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 - Web Development

1797 Articles
article-image-faqs-mahara-12-eportfolios
Packt
04 Jan 2011
7 min read
Save for later

FAQs on Mahara 1.2 ePortfolios

Packt
04 Jan 2011
7 min read
Mahara 1.2 E-Portfolios: Beginner's Guide Create and host educational and professional e-portfolios and personalized learning communities Create, customize, and maintain an impressive personal digital portfolio with a simple point-and-click interface Set customized access to share your text files, images, and videos with your family, friends, and others Create online learning communities and social networks through groups, blogs, and forums A step-by-step approach that takes you through examples with ample screenshots and clear explanations Q: What will you need to install Mahara? A: Before you can install Mahara, you will need to have access to a Linux server. It may be that you run Linux on a laptop or desktop at home or that your company or institution has its own Linux servers, in which case, great! If not, there are many hosting services available on the Internet, which will enable you to access a Linux server and therefore run Mahara. It is important that you get a server to which you have root access. It is also important that you set your server up with the following features: Database: Mahara must have a database to work. The databases supported are PostgreSQL Version 8.1 or later and MySQL Version 5.0.25 or later. The Mahara developers recommend that you use PostgreSQL, if possible, but for most installations, MySQL will work just as well. PHP: Mahara requires PHP Version 5.1.3 or later. Web Server: The preferred web server is Apache. PHP extensions: Compulsory Extensions: GD, JSON, cURL, libxml, SimpleXML, Session, pgSQL or Mysqli, EXIF, OpenSSL or XML-RCP (for networking support) Optional Extension: Imagick Q: Can Mahara be installed on Windows? A: At the moment, the Mahara developers offer no support for running Mahara on Windows Servers. It is designed to primarily work with Linux, Apache, PHP, and open source SQL databases. Q: What are Views in Mahara? How are they different from Blogs? A: They are one of the stand-out features of Mahara and we think you are really going to enjoy learning to use them. Views, like blogs, are an excellent tool for reflection. The difference between the two is that a blog is very text orientated with a user reflecting on a topic in writing (with usually an odd image or video to supplement the text), but Views allow you to express your ideas in more of a "web page" type format using lots of different blocks. Also, Views are flexible; you can very easily add and remove whichever blocks you want. Q: What are some of the things you can do with Views in Mahara? A: Let's think about some of the things you can do with Views in Mahara: You could present all of your ideas related to one of the topics in a qualification you are taking. This could be for your own reference or you may choose to share access to this View with your tutor or classmates. You could use a View to take notes on all of the thoughts, ideas, links, and so on, that you gather while you are attending a conference (if you have a wireless connection). You can then share the View with your colleagues after the event to show them what you have learned. You could use a View to explore and express your thoughts on a particular aspect of your social or family life, such as a family holiday. This is likely to be private, and something you would only share with other members of your family. You could use a View as a tutor to present all of the important materials your learners need to read, watch, listen to, and think about in preparation for a particular topic they are going to study with you. Lots of lecturers prefer to use Mahara to present their work instead of doing so in a Virtual Learning Environment such as Moodle. This may be partly because the lecturer's name (and avatar) will continue to be associated with the work presented in the Mahara View even after they retire or move on to another academic institution. You could use a View to present an ongoing progress report on a project you are doing at work. You might make a blog post an element of this View as well as make important files related to your project available for sharing. Q: What is a secret URL? A: It is used if you would like to give some people who aren't already members of the Mahara site access to your View. The URL is simply a link to the View, which you can set up as a hyperlink in another web page, in a blog, or e-mail so that others can open it. The URL that is created is difficult to guess so that the general public can't see your View. Rather than use it as a hyperlink, you could just send the whole link to the people you would like to give access to the View by pasting it into an e-mail, for example. Q: When can the View feedback be useful? A: This might be useful in the following situations: You might have asked a peer for feedback on some work you are doing on a particular course in exchange for feedback you can give on their work. A tutor may have added your View to their Watchlist. You may then get some informal feedback from your tutor on your work before you submit it for formal assessment. You could be using the feedback functionality as a communication vehicle. You may raise a topic for discussion with your workmates, for example, and get them to answer the core question(s) posed in your View by using the feedback option. You may have used a View to share highlights of a recent holiday experience with your friends in Mahara. They could then use the feedback option to tell you how jealous they are of your rich experiences or at least of your suntan! Q: How can the Mahara partners help you? A: Mahara partners can help you with hosting, theming, training, coding, tweaking, extending, bug-fixing, problem-resolving, implementation consultancies, and, well, just about anything to do with Mahara, if you ask them nicely enough. All Mahara partners are excellent support agencies and, if you ARE really keen on using Mahara, you really should give one of the partners a shout. Q: What are the steps to join the Mahara Community? A: The steps to join the Mahara Community are as follows: Go and register: The very first thing that anyone will do on your Mahara site is log in. Head on over to http://mahara.org and click the option to Register, a small link, which you will find in the pale blue Login butt on in the top right-hand part of the screen. Once you've registered you can log in. Respond to your e-mail: You will need to confirm your registration by clicking the link that has been sent to your e-mail address. Once you have done this, you will find yourself at http://mahara.org, which is itself a Mahara site. Let's find some people!: Click on the Community tab, and then on the Members tab. Now let's see if you can find the authors! Can you see the Query box? Type in my name Derrin and see if you can find me? Let's look at some views: Now you've found me, click on my name and why not click on one of my views? Here's another example of Mahara in action. Join a forum: Click on the Community tab again, and now on the Forums tab. Can you see the Support forum? Its description is Need help using or installing Mahara? Ask your questions here. That's going to be useful to you, I bet! Why not subscribe to this forum by clicking on the Subscribe button. You will now be e-mailed with all the updates to this forum. Maybe there are other forums you might want to subscribe to. If you just want to browse a forum, just click on the name of the forum and you will be taken to a list of the posts. Have a look at the Mahara partners: Click on the Partners tab.
Read more
  • 0
  • 0
  • 1256

article-image-drupal-faqs
Packt
30 Dec 2010
5 min read
Save for later

Drupal FAQs

Packt
30 Dec 2010
5 min read
  Drupal 7 First Look Learn the new features of Drupal 7, how they work and how they will impact you Get to grips with all of the new features in Drupal 7 Upgrade your Drupal 6 site, themes, and modules to Drupal 7 Explore the new Drupal 7 administration interface and map your Drupal 6 administration interface to the new Drupal 7 structure Complete coverage of the DBTNG database layer with usage examples and all API changes for both Themes and Modules Also includes an Appendix that introduces the beta release for Drupal 7. It is not a part of the book (print or e-book) but only available for free download Appendix         Read more about this book       Q: What is Drupal?A: Drupal is an Open Source Content Management System used for building dynamic websites.   Q: Why should I use Drupal and not any other CMS?A: By building on relevant standards and open source technologies, Drupal supports and enhances the potential of the Internet as a medium where diverse and geographically separated individuals and groups can collectively produce, discuss, and share information and ideas. With a central interest in and focus on communities and collaboration, Drupal's flexibility allows the collaborative production of online information systems and communities.   Q: What are the minimum requirements for Drupal 7?A: Drupal 7 requires PHP 5.2.0 or later to run the Drupal code. You will also need one of the following databases to run Drupal 7: MySQL version 5.0 or later PostgreSQL 8.3 or later SQLite 3.4.2 or later   Q: Where can one download Drupal 7 from?A: Head on over to http://drupal.org/project/drupal and click on the Drupal version number you wish to download—in this case it is Drupal 7. Click on Download and then save it to your C: drive or your My Documents folder (or wherever you want).   Q: What's new in Drupal 7?A: There are several key functionalities that made it to Drupal 7. Some of them are as follows: New administration toolbar and overlay administration: After installing Drupal 7 you will notice the new administration toolbar (shown in the following screenshot) that appears on all pages if you have the permission to administer the site: (Move the mouse over the image to enlarge it.) The toolbar groups commonly used tasks together making it easier for new administrators to learn how to configure Drupal and making it quicker for experienced administrators to get to commonly-used functionality. New Field API: The Field API allows site administrators to add additional attributes to a node type. It also supports translatable fields to allow for multi-lingual sites. Added context information to messages during translation: Drupal 7 adds an optional context for the translation to allow developers and themers to make translatable strings less ambiguous. Built-in automated cron functionality: Drupal 7 includes a new cron system that does not rely on running cron from the Unix cron system. The mechanism used is similar to the one used by poormanscron except that it runs from an AJAX request rather than delaying the response time of the page triggering cron. Added a new plugin manager: The plugin manager allows automatic updates of your Drupal installation. Seven theme for administration: A common complaint of Drupal administrators in previous versions was the look of the administration interface and that it could be difficult to tell when you were in the administration interface, since it used the same theme as regular content by default. To fix this, Drupal 7 has added a new administration theme called the Seven theme that is enabled by default. jQuery UI to core: jQuery UI (http://jqueryui.com) is a powerful JavaScript library that includes common controls like calendars, progress bars, tabs, sliders, and more. It also includes functionality to allow drag and drop, resizing, sorting, selection, and more. New Stark theme: The new Stark theme that is designed to make it easier to learn how to build a custom theme. Rewritten database layer (DBTNG): The biggest change in Drupal 7, at least for developers, is the new database layer, also called DBTNG (short for Database Layer: The Next Generation). DBTNG is a big change for developers since it changes how modules interact with the database. Queue API for long-running tasks: Drupal 7 adds a Queue API to manage long-running tasks. In general, any task that takes more than 30 seconds to a minute would be an excellent candidate for the Queue API. New test framework: Drupal 7 adds a comprehensive test framework called testing that allows developers and site administrators to run tests against an existing Drupal installation to ensure that it is behaving properly.   Q: How has the installation process improved in Drupal 7?A: Drupal 7 has a new installation routine. It is designed to make it easier for new Drupal users to set up Drupal. The new installation offers two types of install—the regular installation and a minimal installation.   The Minimal installation is similar to previous versions. The new Standard installation automatically enables commonly-used functionality during the installation to save time after setup.   Q: How has the interface for creating content and new content types improved in Drupal 7?A: Improved interface for creating content: A big, but welcome, change for editors is the redesigned and updated interface to create and edit content. A sample of the interface is shown in the following screenshot:   The redesigned screen makes it easier to quickly navigate to specific sections within the content. Improved interface for creating new content types: The interface for creating content types has been redesigned to keep all of the options in a smaller space so navigation is easier and all information can be quickly accessed.
Read more
  • 0
  • 0
  • 1500

article-image-enhancing-your-site-php-and-jquery
Packt
29 Dec 2010
12 min read
Save for later

Enhancing your Site with PHP and jQuery

Packt
29 Dec 2010
12 min read
  PHP jQuery Cookbook Over 60 simple but highly effective recipes to create interactive web applications using PHP with jQuery Create rich and interactive web applications with PHP and jQuery Debug and execute jQuery code on a live site Design interactive forms and menus Another title in the Packt Cookbook range, which will help you get to grips with PHP as well as jQuery         Read more about this book       (For more resources on this subject, see here.) Introduction In this article, we will look at some advanced techniques that can be used to enhance the functionality of web applications. We will create a few examples where we will search for images the from Flickr and videos from YouTube using their respective APIs. We will parse a RSS feed XML using jQuery and learn to create an endless scrolling page like Google reader or the new interface of Twitter. Besides this, you will also learn to create a jQuery plugin, which you can use independently in your applications. Sending cross-domain requests using server proxy Browsers do not allow scripts to send cross-domain requests due to security reasons. This means a script at domain http://www.abc.com cannot send AJAX requests to http://www.xyz.com. This recipe will show how you can overcome this limitation by using a PHP script on the server side. We will create an example that will search Flickr for images. Flickr will return a JSON, which will be parsed by jQuery and images will be displayed on the page. The following screenshot shows a JSON response from Flickr: Getting ready Create a directory for this article and name it as Article9. In this directory, create a folder named Recipe1. Also get an API key from Flickr by signing up at http://www.flickr.com/services/api/keys/. How to do it... Create a file inside the Recipe1 folder and name it as index.html. Write the HTML code to create a form with three fields: tag, number of images, and image size. Also create an ul element inside which the results will be displayed. <html> <head> <title>Flickr Image Search</title> <style type="text/css"> body { font-family:"Trebuchet MS",verdana,arial;width:900px; } fieldset { width:333px; } ul{ margin:0;padding:0;list-style:none; } li{ padding:5px; } span{ display:block;float:left;width:150px; } #results li{ float:left; } .error{ font-weight:bold; color:#ff0000; } </style> </head> <body> <form id="searchForm"> <fieldset> <legend>Search Criteria</legend> <ul> <li> <span>Tag</span> <input type="text" name="tag" id="tag"/> </li> <li> <span>Number of images</span> <select name="numImages" id="numImages"> <option value="20">20</option> <option value="30">30</option> <option value="40">40</option> <option value="50">50</option> </select> </li> <li> <span>Select a size</span> <select id="size"> <option value="s">Small</option> <option value="t">Thumbnail</option> <option value="-">Medium</option> <option value="b">Large</option> <option value="o">Original</option> </select> </li> <li> <input type="button" value="Search" id="search"/> </li> </ul> </fieldset> </form> <ul id="results"> </ul> </body> </html> The following screenshot shows the form created: Include the jquery.js file. Then, enter the jQuery code that will send the AJAX request to a PHP file search.php. Values of form elements will be posted with an AJAX request. A callback function showImages is also defined that actually reads the JSON response and displays the images on the page. <script type="text/javascript" src="../jquery.js"></script> <script type="text/javascript"> $(document).ready(function() { $('#search').click(function() { if($.trim($('#tag').val()) == '') { $('#results').html('<li class="error">Please provide search criteria</li>'); return; } $.post( 'search.php', $('#searchForm').serialize(), showImages, 'json' ); }); function showImages(response) { if(response['stat'] == 'ok') { var photos = response.photos.photo; var str= ''; $.each(photos, function(index,value) { var farmId = value.farm; var serverId = value.server; var id = value.id; var secret = value.secret; var size = $('#size').val(); var title = value.title; var imageUrl = 'http://farm' + farmId + '.static.flickr.com/' + serverId + '/' + id + '_' + secret + '_' + size + '.jpg'; str+= '<li>'; str+= '<img src="' + imageUrl + '" alt="' + title + '" />'; str+= '</li>'; }); $('#results').html(str); } else { $('#results').html('<li class="error">an error occured</li>'); } } }); </script> Create another file named search.php. The PHP code in this file will contact the Flickr API with specified search criteria. Flickr will return a JSON that will be sent back to the browser where jQuery will display it on the page. <?php define('API_KEY', 'your-API-key-here'); $url = 'http://api.flickr.com/services/rest/?method=flickr. photos.search'; $url.= '&api_key='.API_KEY; $url.= '&tags='.$_POST['tag']; $url.= '&per_page='.$_POST['numImages']; $url.= '&format=json'; $url.= '&nojsoncallback=1'; header('Content-Type:text/json;'); echo file_get_contents($url); ?> Now, run the index.html file in your browser, enter a tag to search in the form, and select the number of images to be retrieved and image size. Click on the Search button. A few seconds later you will see the images from Flickr displayed on the page: <html> <head> <title>Youtube Video Search</title> <style type="text/css"> body { font-family:"Trebuchet MS",verdana,arial;width:900px; } fieldset { width:333px; } ul{ margin:0;padding:0;list-style:none; } li{ padding:5px; } span{ display:block;float:left;width:150px; } #results ul li{ float:left; background-color:#483D8B; color:#fff;margin:5px; width:120px; } .error{ font-weight:bold; color:#ff0000; } img{ border:0} </style> </head> <body> <form id="searchForm"> <fieldset> <legend>Search Criteria</legend> <ul> <li> <span>Enter query</span> <input type="text" id="query"/> </li> <li> <input type="button" value="Search" id="search"/> </li> </ul> </fieldset> </form> <div id="results"> </div> </body> </html> How it works... On clicking the Search button, form values are sent to the PHP file search.php. Now, we have to contact Flickr and search for images. Flickr API provides several methods for accessing images. We will use the method flickr.photos.search to search by tag name. Along with method name we will have to send the following parameters in the URL: api_key: An API key is mandatory. You can get one from: http://www.flickr.com/services/api/keys/. tags: The tags to search for. These can be comma-separated. This value will be the value of textbox tag. per_page: Number of images in a page. This can be a maximum of 99. Its value will be the value of select box numImages. format: It can be JSON, XML, and so on. For this example, we will use JSON. nojsoncallback: Its value will be set to 1 if we don't want Flickr to wrap the JSON in a function wrapper. Once the URL is complete we can contact Flickr to get results. To get the results' we will use the PHP function file_get_contents, which will get the results JSON from the specified URL. This JSON will be echoed to the browser. jQuery will receive the JSON in callback function showImages. This function first checks the status of the response. If the response is OK, we get the photo elements from the response and we can iterate over them using jQuery's $.each method. To display an image, we will have to get its URL first, which will be created by combining different values of the photo object. According to Flickr API specification, an image URL can be constructed in the following manner: http://farm{farm-id}.static.flickr.com/{server-id}/{id}_{secret}_[size].jpg So we get the farmId, serverId, id, and secret from the photo element. The size can be one of the following: s (small square) t (thumbnail) - (medium) b (large) o (original image) We have already selected the image size from the select box in the form. By combining all these values, we now have the Flickr image URL. We wrap it in a li element and repeat the process for all images. Finally, we insert the constructed images into the results li. Making cross-domain requests with jQuery The previous recipe demonstrated the use of a PHP file as a proxy for querying cross-domain URLs. This recipe will show the use of JSONP to query cross-domain URLs from jQuery itself. We will create an example that will search for the videos from YouTube and will display them in a list. Clicking on a video thumbnail will open a new window that will take the user to the YouTube website to show that video. The following screenshot shows a sample JSON response from YouTube: Getting ready Create a folder named Recipe2 inside the Article9 directory. How to do it... Create a file inside the Recipe2 folder and name it as index.html. Write the HTML code to create a form with a single field query and a DIV with results ID inside which the search results will be displayed. <script type="text/javascript" src="../jquery.js"></script> <script type="text/javascript"> $(document).ready(function() { $('#search').click(function() { var query = $.trim($('#query').val()); if(query == '') { $('#results').html('<li class="error">Please enter a query.</li>'); return; } $.get( 'http://gdata.youtube.com/feeds/api/videos?q=' + query + '&alt=json-in-script', {}, showVideoList, 'jsonp' ); }); }); function showVideoList(response) { var totalResults = response['feed']['openSearch$totalResults']['$t']; if(parseInt(totalResults,10) > 0) { var entries = response.feed.entry; var str = '<ul>'; for(var i=1; i< entries.length; i++) { var value = entries[i]; var title = value['title']['$t']; var mediaGroup = value['media$group']; var videoURL = mediaGroup['media$player'][0]['url']; var thumbnail = mediaGroup['media$thumbnail'][0]['url']; var thumbnailWidth = mediaGroup['media$thumbnail'][0]['width']; var thumbnailHeight = mediaGroup['media$thumbnail'][0]['height']; var numComments = value['gd$comments']['gd$feedLink']['countHint']; var rating = parseFloat(value['gd$rating']['average']).toFixed(2); str+= '<li>'; str+= '<a href="' + videoURL + '" target="_blank">'; str+= '<img src="'+thumbNail+'" width="'+thumbNailWidth+'" height="'+thumbNailWidth+'" title="' + title + '" />'; str+= '</a>'; str+= '<hr>'; str+= '<p style="width: 120px; font-size: 12px;">Comments: ' + numComments + ''; str+= '<br/>'; str+= 'Rating: ' + rating; str+= '</p>'; str+= '</li>'; } str+= '</ul>'; $('#results').html(str); } else { $('#results').html('<li class="error">No results.</li>'); } } </script> Include the jquery.js file before closing the &ltbody> tag. Now, write the jQuery code that will take the search query from the textbox and will try to retrieve the results from YouTube. A callback function called showVideoList will get the response and will create a list of videos from the response. http://gdata.youtube.com/feeds/api/videos?q=' + query + '&alt=json-in-script All done, and we are now ready to search YouTube. Run the index.html file in your browser and enter a search query. Click on the Search button and you will see a list of videos with a number of comments and a rating for each video. How it works... script tags are an exception to cross-browser origin policy. We can take advantage of this by requesting the URL from the src attribute of a script tag and by wrapping the raw response in a callback function. In this way the response becomes JavaScript code instead of data. This code can now be executed on the browser. The URL for YouTube video search is as follows: http://gdata.youtube.com/feeds/api/videos?q=' + query + '&alt=json-in-script Parameter q is the query that we entered in the textbox and alt is the type of response we want. Since we are using JSONP instead of JSON, the value for alt is defined as json-in-script as per YouTube API specification. On getting the response, the callback function showVideoList executes. It checks whether any results are available or not. If none are found, an error message is displayed. Otherwise, we get all the entry elements and iterate over them using a for loop. For each video entry, we get the videoURL, thumbnail, thumbnailWidth, thumbnailHeight, numComments, and rating. Then we create the HTML from these variables with a list item for each video. For each video an anchor is created with href set to videoURL. The video thumbnail is put inside the anchor and a p tag is created where we display the number of comments and rating for a particular video. After the HTML has been created, it is inserted in the DIV with ID results. There's more... About JSONP You can read more about JSONP at the following websites: http://remysharp.com/2007/10/08/what-is-jsonp/ http://en.wikipedia.org/wiki/JSON#JSONP
Read more
  • 0
  • 0
  • 2004
Visually different images

article-image-getting-started-ext-gwt
Packt
28 Dec 2010
8 min read
Save for later

Getting Started with Ext GWT

Packt
28 Dec 2010
8 min read
  Ext GWT 2.0: Beginner's Guide Take the user experience of your website to a new level with Ext GWT Explore the full range of features of the Ext GWT library through practical, step-by-step examples Discover how to combine simple building blocks into powerful components Create powerful Rich Internet Applications with features normally only found in desktop applications Learn how to structure applications using MVC for maximum reliability and maintainability      What is GWT missing? GWT is a toolkit as opposed to a full development framework, and for most projects, it forms the part of a solution rather than the whole solution. Out-of-the-box GWT comes with only a basic set of widgets and lacks a framework to enable the developers to structure larger applications. Fortunately, GWT is both open and extensible and as a result, a range of complementary projects have grown up around it. Ext GWT is one of those projects. What does Ext GWT offer? Ext GWT sets out to build upon the strengths of GWT by enabling the developers to give their users an experience more akin to that of a desktop application. Ext GWT provides the GWT developer with a comprehensive component library similar to that used when developing for desktop environments. In addition to being a component library, powerful features for working with local and remote data are provided. It also features a model view controller framework, which can be used to structure larger applications. How is Ext GWT licensed? Licensing is always an important consideration when choosing technology to use in a project. At the time of writing, Ext GWT is offered with a dual license. The first license is an open source license compatible with the GNU GPL license v3. If you wish to use this license, you do not have to pay a fee for using Ext GWT, but in return you have to make your source code available under an open source license. This means you have to contribute all the source code of your project to the open source community and give everyone the right to modify or redistribute it. If you cannot meet the obligations of the open source license, for example, you are producing a commercial product or simply do not want to share your source code, you have to purchase a commercial license for Ext GWT. It is a good idea to check the current licensing requirements on the Sencha website, http://www.sencha.com, and take that into account when planning your project. Alternatives to Ext GWT Ext GWT is one of the many products produced by the company Sencha. Sencha was previously named Ext JS and started off developing a JavaScript library by the same name. Ext GWT is closely related to the Ext JS product in terms of functionality. Both Ext GWT and Ext JS also share the same look and feel as well as a similar API structure. However, Ext GWT is a native GWT implementation, written almost entirely in Java rather than a wrapper, the JavaScript-based Ext JS. GWT-Ext Before Ext GWT, there was GWT-Ext: http://code.google.com/p/gwt-ext/. This library was developed by Sanjiv Jeevan as a GWT wrapper around an earlier, 2.0.2 version of Ext JS. Being based on Ext JS, it has a very similar look and feel to Ext GWT. However, after the license of Ext JS changed from LGPL to GPL in 2008, active development came to an end. Apart from no longer being developed or supported, developing with GWT-Ext is more difficult than with Ext GWT. This is because the library is a wrapper around JavaScript and the Java debugger cannot help when there is a problem in the JavaScript code. Manual debugging is required. Smart GWT When development of GWT-Ext came to an end, Sanjiv Jeevan started a new project named Smart GWT: http://www.smartclient.com/smartgwt/. This is a LGPL framework that wraps the Smart Client JavaScript library in a similar way that GWT-Ext wraps Ext JS. Smart GWT has the advantage that it is still being actively developed. Being LGPL-licensed, it also can be used commercially without the need to pay the license fee that is required for Ext GWT. Smart GWT still has the debugging problems of GWT-Ext and the components are often regarded not as visually pleasing as Ext GWT. This could be down to personal taste of course. Vaadin Vaadin, http://vaadin.com, is a third alternative to Ext GWT. Vaadin is a server-side framework that uses a set of precompiled GWT components. Although you can write your own components if required, Vaadin is really designed so that you can build applications by combining the ready-made components. In Vaadin the browser client is just a dumb view of the server components and any user interaction is sent to the server for processing much like traditional Java web frameworks. This can be slow depending on the speed of the connection between the client and the server. The main disadvantage of Vaadin is the dependency on the server. GWT or Ext GWT's JavaScript can run in a browser without needing to communicate with a server. This is not possible in Vaadin. Ext GWT or GXT? To avoid confusion with GWT-Ext and to make it easier to write, Ext GWT is commonly abbreviated to GXT. We will use GXT synonymously with Ext GWT throughout the rest of this article. Working with GXT: A different type of web development If you are a web developer coming to GXT or GWT for the first time, it is very important to realize that working with this toolset is not like traditional web development. In traditional web development, most of the work is done on the server and the part the browser plays is li?? le more than a view-making request and receiving responses. When using GWT, especially GXT, at times it is easier if you suspend your web development thinking and think more like a desktop-rich client developer. Java Swing developers, for example, may find themselves at home. How GXT fits into GWT GXT is simply a library that plugs into any GWT project. If we have an existing GWT project setup, all we need to do to use it is: Download the GXT SDK from the Sencha website Add the library to the project and reference it in the GWT configuration Copy a set of resource files to the project If you haven't got a GWT project setup, don't worry. We will now work through getting GXT running from the beginning. Downloading what you need Before we can start working with GXT, we first need to download the toolkit and set up our development environment. Here is the list of what you need to download for running the examples.     Recommended Notes Download from Sun JDK 6 The Java development kit http://java.sun.com/javase/downloads/widget/jdk6.jsp Eclipse IDE for Java EE Developers 3.6 The Eclipse IDE for Java developers, which also includes some useful web development tools http://www.eclipse.org/downloads/ Ext GWT 2.2.0 SDK for GWT 2.0 The GXT SDK itself http://www.sencha.com/products/gwt/download.php Google supplies a useful plugin that integrates GWT into Eclipse. However, there is no reason that you cannot use an alternative development environment, if you prefer. Eclipse setup There are different versions of Eclipse, and although Eclipse for Java EE developers is not strictly required, it contains some useful tools for editing web-specific files such as CSS. These tools will be useful for GXT development, so it is strongly recommended. We will not cover the details of installing Eclipse here, as this is covered more than adequately on the Eclipse website. For that reason, we make the assumption that you already have a fresh installation of Eclipse ready to go. GWT setup You may have noticed that GWT is not included in the list of downloads. This is because since version 2.0.0, GWT has been available within an Eclipse plugin, which we will now set up. Time for action – setting up GWT In Eclipse, select Help Install New Software|. The installation dialog will appear. Click on the Add button to add a new site. Enter the name and location in the respective fields, as shown in the following screenshot, and click on the OK button. Move the mouse over the image to enlarge it. Select Google Plugin for Eclipse from the plugin section and Google Web Toolkit SDK from the SDKs section. Click on Next. The following dialog will appear. Click on Next to proceed. Click on the radio button to accept the license. Click on Finish. Eclipse will now download the Google Web Toolkit and configure the plugin. Restart when prompted. On restarting, if GWT and the Google Eclipse Plugin are installed successfully, you will notice the following three new icons in your toolbar. What just happened? You have now set up GWT in your Eclipse IDE. You are now ready to create GWT applications. However, before we can create GXT applications, there is a bit more work to do.
Read more
  • 0
  • 0
  • 8170

article-image-moodle-19-testing-and-assessment-advanced-options-quiz
Packt
23 Dec 2010
7 min read
Save for later

Moodle 1.9 Testing and Assessment: Advanced Options in Quiz

Packt
23 Dec 2010
7 min read
  Moodle 1.9 Testing and Assessment Develop and evaluate quizzes and tests using Moodle modules Create and evaluate interesting and interactive tests using a variety of Moodle modules Create simple vocabulary or flash card tests and complex tests by setting up a Lesson module Motivate your students to excel through feedback and by keeping their grades online A well-structured practical guide packed with illustrative examples and screenshots           Read more about this book       (For more resources on Moodle 1.9, see here.) Adding images to multiple-choice questions You are not going to always want simple text-based questions or answers. One common type of question that instructors frequently use is the image-based question. This item incorporates an image into the question. These questions are easy to create and can offer new dimensions for questions, as well as make the questions and test much more interesting to students. You can add images to any question or any field that allows you to use the rich-text editor, but we are going to use a single-answer, multiple choice question. We will follow the same basic steps as before. Step 1 We need to create a new multiple-choice question. When we are editing the question, we need to add the question name. We then need to add the question text. The question text we will be using for ours will be Which holiday is this girl celebrating? Step 2 We now go to the toolbar and click on the Insert Image icon. It is the icon that looks like a framed picture of a mountain, located two places to the left of the smiley face icon. Once we click on this icon, a pop-up menu will appear, as shown in the next screenshot: Here we have a few options in regards to how to use images and how they will be displayed in the question. Image URL & Alternate text If we use this option, we are able to take images directly from the Internet and use them for our tests. To use it we first need to have the address where the image is found. We are not looking for the address of the site here, but just the image. If you simply link to the web page, it will not work. To get just the image address, click on the image and you should get a menu with one of the options being View Image. Select View Image and you will be taken to a different page with only that image. This is the address you want to use. Once you have the image address, you copy and paste it to the Image URL text area.With the image address entered, we need to give the image a title in the Alternate text area. You can use anything you'd like here, but I tend to use the image name itself if it describes the image. If not, I create a short descriptive text of the image, something like "Girl celebrating Halloween". After you have entered text in both the Image URL and the Alternate text, click on the OK button and the image will be added to your question. It is important to note that if the website you pulled the image from removes it or changes its location, it will not be available for the question. It is therefore advisable to download the image, so that it will always be available to you. When you have finished adding responses and saving the question, you will see something like the following screenshot: Source: Image: Tina Phillips / FreeDigitalPhotos.net Now, looking back at the options available in the Insert image pop-up, you see three formatting options directly under the Image URL and Alternate text box where we were just working. They are called: Layout, Spacing, and Size. Layout In this fieldset, we are given ways to alter the Alignment and the Border thickness. Note that the image may be displayed differently on different browsers, although the CSS of the theme you are using will usually provide the appropriate margins and padding Alignment There are several options available here that show how the text and the image will be displayed. The full list is shown in the next screenshot: Most of these options are self-explanatory: Left will place the image to the left of the text, Right will place the image to the right of the text, and so on. However, there are a few possibly new terms. Texttop, Baseline, and Absbottom are HTML terms that many people might be unsure of. Texttop simply means that the very top of the tallest text (for example, l, b) will be aligned with the top of the image. This function works same as Top with some browsers. Baseline means that the imaginary line that all letters sit on will be aligned with the bottom of the image. In most browsers today, this functions the same as Bottom. Absbottom means that the letters that go below the baseline are aligned with the bottom of the image (for example, g, j). The top option, Not Set will place the image wherever the cursor is, without any special guide as to how it should be displayed. Border thickness The image you put into the question should look identical to the image you chose to use. If you are placing this image inside of text, or the edges are indistinct, or you simply want to frame it, use Border Thickness By placing a number in the Border thickness box, we will create a black border around the image. A small number will give a narrow border and a bigger number will give a thicker one. Here are three images showing the difference in borders. The first is set with a border of 0, the second has a border of 5, and the third with 10. You will notice that the image size itself is the same, but the border causes the viewable area of the image to compress Source: Images courtesy of: freeimages.co.uk Spacing There are two spacing options available, Horizontal and Vertical. The larger the number entered, the more space there is between the text and the images. Horizontal This setting allows you to set the horizontal distance between the image and the text surrounding it. This option can be useful if you need to have the image set apart from the text in the question or explanation. Vertical This setting is like the horizontal setting. It allows you to set the vertical distance between text and the image. This option can be useful if you need to have set distances between the text or have multiple images in a list with text surrounding them. Size The two options here are Width and Height. These two settings allow you to alter the size of the image; smaller numbers will make the image smaller and probably easier to work with. Note that the actual images are not resized. For the best result, first resize the images on your computer to the size you want them to be. Width This setting allows you to alter the width of the image. Altering this setting without altering the height will produce narrow or wide images, depending on whether you adjust the value up or down. Height This setting allows you to alter the height of the image. This option functions just like Width, and will allow you to produce images that are vertically stretched or shrunk. File Browser In this space, you will see any images that have been uploaded to the course. As you can see in the previous screenshot, it is empty, which tells us that there aren't pictures available in the course yet. If you look below File Browser, you will see four options for images uploaded to the course. You can Delete, Move, Zip, or Rename any images that have already been uploaded into the course. Preview This is where you can view any images that have been added to the course. This feature can be useful if you have a lot of images and tend to forget which images are which.
Read more
  • 0
  • 0
  • 1032

article-image-working-xml-documents-php-jquery
Packt
23 Dec 2010
8 min read
Save for later

Working with XML Documents in PHP jQuery

Packt
23 Dec 2010
8 min read
PHP jQuery Cookbook Over 60 simple but highly effective recipes to create interactive web applications using PHP with jQuery Create rich and interactive web applications with PHP and jQuery Debug and execute jQuery code on a live site Design interactive forms and menus Another title in the Packt Cookbook range, which will help you get to grips with PHP as well as jQuery Introduction Extensible Markup Language—also known as XML—is a structure for representation of data in human readable format. Contrary to its name, it's actually not a language but a markup which focuses on data and its structure. XML is a lot like HTML in syntax except that where HTML is used for presentation of data, XML is used for storing and data interchange. Moreover, all the tags in an XML are user-defined and can be formatted according to one's will. But an XML must follow the specification recommended by W3C. With a large increase in distributed applications over the internet, XML is the most widely used method of data interchange between applications. Web services use XML to carry and exchange data between applications. Since XML is platform-independent and is stored in string format, applications using different server-side technologies can communicate with each other using XML. Consider the following XML document: From the above document, we can infer that it is a list of websites containing data about the name, URL, and some information about each website. PHP has several classes and functions available for working with XML documents. You can read, write, modify, and query documents easily using these functions. In this article, we will discuss SimpleXML functions and DOMDocument class of PHP for manipulating XML documents. You will learn how to read and modify XML files, using SimpleXML as well as DOM API. We will also explore the XPath method, which makes traversing documents a lot easier. Note that an XML must be well-formed and valid before we can do anything with it. There are many rules that define well-formedness of XML out of which a few are given below: An XML document must have a single root element.   There cannot be special characters like <, >, and soon.   Each XML tag must have a corresponding closing tag.   Tags are case sensitive To know more about validity of an XML, you can refer to this link: http://en.wikipedia.org/wiki/XML#Schemas_and_validation For most of the recipes in this article, we will use an already created XML file. Create a new file, save it as common.xml in the Article3 directory. Put the following contents in this file. <?xml version="1.0"?> <books> <book index="1"> <name year="1892">The Adventures of Sherlock Holmes</name> <story> <title>A Scandal in Bohemia</title> <quote>You see, but you do not observe. The distinction is clear.</quote> </story> <story> <title>The Red-headed League</title> <quote>It is quite a three pipe problem, and I beg that you won't speak to me for fifty minutes.</quote> </story> <story> <title>The Man with the Twisted Lip</title> <quote>It is, of course, a trifle, but there is nothing so important as trifles.</quote> </story> </book> <book index="2"> <name year="1927">The Case-book of Sherlock Holmes</name> <story> <title>The Adventure of the Three Gables</title> <quote>I am not the law, but I represent justice so far as my feeble powers go.</quote> </story> <story> <title>The Problem of Thor Bridge</title> <quote>We must look for consistency. Where there is a want of it we must suspect deception.</quote> </story> <story> <title>The Adventure of Shoscombe Old Place</title> <quote>Dogs don't make mistakes.</quote> </story> </book> <book index="3"> <name year="1893">The Memoirs of Sherlock Holmes</name> <story> <title>The Yellow Face</title> <quote>Any truth is better than indefinite doubt.</quote> </story> <story> <title>The Stockbroker's Clerk</title> <quote>Results without causes are much more impressive. </quote> </story> <story> <title>The Final Problem</title> <quote>If I were assured of your eventual destruction I would, in the interests of the public, cheerfully accept my own.</quote> </story> </book> </books> Loading XML from files and strings using SimpleXML True to its name, SimpleXML functions provide an easy way to access data from XML documents. XML files or strings can be converted into objects, and data can be read from them. We will see how to load an XML from a file or string using SimpleXML functions. You will also learn how to handle errors in XML documents. Getting ready Create a new directory named Article3. This article will contain sub-folders for each recipe. So, create another folder named Recipe1 inside it. How to do it... Create a file named index.php in Recipe1 folder. In this file, write the PHP code that will try to load the common.xml file. On loading it successfully, it will display a list of book names. We have also used the libxml functions that will detect any error and will show its detailed description on the screen. <?php libxml_use_internal_errors(true); $objXML = simplexml_load_file('../common.xml'); if (!$objXML) { $errors = libxml_get_errors(); foreach($errors as $error) { echo $error->message,'<br/>'; } } else { foreach($objXML->book as $book) { echo $book->name.'<br/>'; } } ?> Open your browser and point it to the index.php file. Because we have already validated the XML file, you will see the following output on the screen: The Adventures of Sherlock Holmes The Case-book of Sherlock Holmes The Memoirs of Sherlock Holmes Let us corrupt the XML file now. For this, open the common.xml file and delete any node name. Save this file and reload index.php on your browser. You will see a detailed error description on your screen: How it works... In the first line, passing a true value to the libxml_use_internal_errors function will suppress any XML errors and will allow us to handle errors from the code itself. The second line tries to load the specified XML using the simplexml_load_file function. If the XML is loaded successfully, it is converted into a SimpleXMLElement object otherwise a false value is returned. We then check for the return value. If it is false, we use the libxml_get_errors() function to get all the errors in the form of an array. This array contains objects of type LibXMLError. Each of these objects has several properties. In the previous code, we iterated over the errors array and echoed the message property of each object which contains a detailed error message. If there are no errors in XML, we get a SimpleXMLElement object which has all the XML data loaded in it. There's more... Parameters for simplexml_load_file More parameters are available for the simplexml_load_file method, which are as follows: filename: This is the first parameter that is mandatory. It can be a path to a local XML file or a URL. class_name: You can extend the SimpleXMLElement class. In that case, you can specify that class name here and it will return the object of that class. This parameter is optional. options: This third parameter allows you to specify libxml parameters for more control over how the XML is handled while loading. This is also optional. simplexml_load_string Similar to simplexml_load_file is simplexml_load_string, which also creates a SimpleXMLElement on successful execution. If a valid XML string is passed to it we get a SimpleXMLElement object or a false value otherwise. $objXML = simplexml_load_string('<?xml version="1.0"?><book><name> Myfavourite book</name></book>'); The above code will return a SimpleXMLElement object with data loaded from the XML string. The second and third parameters of this function are same as that of simplexml_load_file. Using SimpleXMLElement to create an object You can also use the constructor of the SimpleXMLElement class to create a new object. $objXML = new SimpleXMLElement('<?xml version="1.0"?><book><name> Myfavourite book</name></book>'); More info about SimpleXML and libxml You can read about SimpleXML in more detail on the PHP site at http://php.net/manual/en/book.simplexml.php and about libxml at http://php.net/manual/en/book.libxml.php.
Read more
  • 0
  • 0
  • 2721
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 €14.99/month. Cancel anytime
article-image-moodle-19-testing-and-assessment-multiple-choice-quizzes
Packt
22 Dec 2010
7 min read
Save for later

Moodle 1.9 Testing and Assessment: Multiple Choice Quizzes

Packt
22 Dec 2010
7 min read
  Moodle 1.9 Testing and Assessment Develop and evaluate quizzes and tests using Moodle modules Create and evaluate interesting and interactive tests using a variety of Moodle modules Create simple vocabulary or flash card tests and complex tests by setting up a Lesson module Motivate your students to excel through feedback and by keeping their grades online A well-structured practical guide packed with illustrative examples and screenshots        Getting started We need to get to the Question bank and Question Editing pages. One quick way to do this is through the Course Admin Menu. There is a link titled Questions, which will bring you to the correct place. The first thing we need to do is name the quiz. We are going to call this one Multiple Choice Quiz. For the introduction, we are just going to write the purpose of this quiz to teach you a few things about this item type. Once we click on the Save and Display button, we will see the Question bank. Notice the questions from the True/False quiz? They are there because the category they are associated with is Course. If I want to get rid of them so that they don't interfere with anything new I am doing, I have a few options. Categories and contexts There are four default categories: System, Miscellaneous, Course, and Activity. The categories act like folders or directories, allowing the questions to be accessed at different levels or hierarchies. They are set up in what are known as contexts. Each context has its own question hierarchies, with the highest context being the Core System, moving down to Course Category, Course, and Activity. What this means is that you can select the context in which you can share your questions. By selecting the System option from the menu, any questions that have been created at this level will be available in all courses and for any quiz you have created on the site. Miscellaneous/Course Category The next level below System to store questions is Miscellaneous, like the Course Category. This category is where all the courses you are enrolled in are found. The questions placed in this context are available to all courses and activities in the Course Category. Course This is where questions directly related to the course the quiz is being made for are stored. Course is the default, and most Moodle users find this is a good place for their questions. Placing the items here allows you to create items specific to the course, based on exactly what was covered. It will also only use the questions developed in the course to draw on for random questions. You can also make a subcategory for questions you'd like to draw from. As long as questions are in one category, they can end up in a quiz that randomly draws questions from that category. Creating subcategories for different units in the course makes it easy to keep track of exactly which questions were used. It also helps in organization and administration of courses The drawback is that the questions are only able to be used in the course. So, looking at the previous graph, the Question bank in Course B would not be able to use anything from Course A. This does not mean we can't ever use them again; we will just need to export them to wherever we want to use them. We'll look at this activity later. Activity Creating items in the quiz Activity itself is also possible. This means that questions being created will only be available for the specific test being made. The benefit to this is that you are assured that the questions are not available anywhere else, so, for example, if you want your test's questions to be completely isolated and unable to be used as random items in other formative or summative tests, this area would be a good place to place all the items. The only real drawback is that the questions you spent all that time working on are limited to a single activity, a single exam. I don't have the space here to go into how to use categories and contexts, but it isn't too hard to figure out. For a detailed and complete overview of how to create and use categories or contexts, check out these links http://docs.moodle.org/en/ Question_categories/ and http://docs.moodle.org/en/Question_contexts Multiple Choice item creation page Since composing Multiple Choice items is nearly the same as creating True/False questions, we are going to be working on a few of them now. Once we have the hang of making them, we will look at a few options that we didn't use in the previous test and see how they work. Returning to the Question bank, I go to the Create New Question drop-down and select Multiple Choice. Make sure you have the appropriate category selected. When the Adding a Multiple Choice question page opens, you will notice that it looks very similar to the True/False question page. That's because it is. There are a few new options available here, but the page looks basically the same. In the top section of the page, General, all the same information from True/False, such as item name and description are there. There are also three new options directly under the General feedback> text area. One or multiple answers This drop-down option has only two choices. It enables us to either accept only a single response or more than one answer as a response. The two options in the drop-down menu are called One answer only and Multiple answers allowed. Shuffle the choices This option takes the possible responses and randomly orders them. This is useful for reducing cheating, and also allows each student to be given a slightly different version of the test. This option will shuffle only if the Shuffle options for the quiz and the question are both turned on. The default is to shuffle or not based on the settings for the quiz module the Moodle administrator has set. These defaults can be overridden in the Quiz settings or here. Number the choices This section allows you to decide on how you want to mark the responses. You have four options: lowercase letters, uppercase letters, numbers, or nothing. From here, we scroll down the page and we will see that we are offered five sections, called Choice 1, Choice 2, and others for entering the answers. These choices can be seen in the next screenshot: Here, we can enter our potential answers, the grade students will get for choosing the particular potential answer, and some feedback based on their response. Under the five answer sections, you have the option to create more choices using a button titled Blanks for 3 More Choices. Clicking on this button will create Choices 6 to 8. There is no way to get rid of Choices, but it is possible to have fewer responses. If we only want to have three responses available, then all we need to do is fill in the three choices we want. At the bottom of the page, we see the three feedback boxes: one is for correct responses, one for partially correct responses, and the final one for incorrect responses. As for choices, these can be filled or left empty.
Read more
  • 0
  • 0
  • 1726

article-image-working-json-php-jquery
Packt
20 Dec 2010
5 min read
Save for later

Working with JSON in PHP jQuery

Packt
20 Dec 2010
5 min read
  PHP jQuery Cookbook Over 60 simple but highly effective recipes to create interactive web applications using PHP with jQuery Create rich and interactive web applications with PHP and jQuery Debug and execute jQuery code on a live site Design interactive forms and menus Another title in the Packt Cookbook range, which will help you get to grips with PHP as well as jQuery         Read more about this book       In this article, by Vijay Joshi, author of PHP jQuery Cookbook, we will cover: Creating JSON in PHP Reading JSON in PHP Catching JSON parsing errors Accessing data from a JSON in jQuery (For more resources on this subject, see here.) Introduction Recently, JSON (JavaScript Object Notation) has become a very popular data interchange format with more and more developers opting for it over XML. Even many web services nowadays provide JSON as the default output format. JSON is a text format that is programming-language independent and is a native data form of JavaScript. It is lighter and faster than XML because it needs less markup compared to XML. Because JSON is the native data form of JavaScript, it can be used on the client side in an AJAX application more easily than XML. A JSON object starts with { and ends with }. According to the JSON specification, the following types are allowed in JSON: Object: An object is a collection of key-value pairs enclosed between { and } and separated by a comma. The key and the value themselves are separated using a colon (:). Think of objects as associative arrays or hash tables. Keys are simple strings and values can be an array, string, number, boolean, or null. Array: Like other languages, an array is an ordered pair of data. For representing an array, values are comma separated and enclosed between [ and ]. String: A string must be enclosed in double quotes The last type is a number A JSON can be as simple as: { "name":"Superman", "address": "anywhere"} An example using an array is as follows: { "name": "Superman", "phoneNumbers": ["8010367150", "9898989898", "1234567890" ]} A more complex example that demonstrates the use of objects, arrays, and values is as follows:   { "people": [ { "name": "Vijay Joshi", "age": 28, "isAdult": true }, { "name": "Charles Simms", "age": 13, "isAdult": false } ]} An important point to note: { 'name': 'Superman', 'address': 'anywhere'} Above is a valid JavaScript object but not a valid JSON. JSON requires that the name and value must be enclosed in double quotes; single quotes are not allowed. Another important thing is to remember the proper charset of data. Remember that JSON expects the data to be UTF-8 whereas PHP adheres to ISO-8859-1 encoding by default. Also note that JSON is not a JavaScript; it is basically a specification or a subset derived from JavaScript. Now that we are familiar with JSON, let us proceed towards the recipes where we will learn how we can use JSON along with PHP and jQuery. Create a new folder and name it as Chapter 4. We will put all the recipes of this article together in this folder. Also put the jquery.js file inside this folder. To be able to use PHP's built-in JSON functions, you should have PHP version 5.2 or higher installed. Creating JSON in PHP This recipe will explain how JSON can be created from PHP arrays and objects Getting ready Create a new folder inside the Chapter4 directory and name it as Recipe1. How to do it... Create a file and save it by the name index.php in the Recipe1 folder. Write the PHP code that creates a JSON string from an array. <?php $travelDetails = array( 'origin' => 'Delhi', 'destination' => 'London', 'passengers' => array ( array('name' => 'Mr. Perry Mason', 'type' => 'Adult', 'age'=> 28), array('name' => 'Miss Irene Adler', 'type' => 'Adult', 'age'=> 28) ), 'travelDate' => '17-Dec-2010' ); echo json_encode($travelDetails);?> Run the file in your browser. It will show a JSON string as output on screen. After indenting the result will look like the following: { "origin":"Delhi","destination":"London","passengers":[ { "name":"Mr. Perry Mason", "type":"Adult", "age":28 }, { "name":"Miss Irene Adler", "type":"Adult", "age":28 }],"travelDate":"17-Dec-2010"} How it works... PHP provides the function json_encode() to create JSON strings from objects and arrays. This function accepts two parameters. First is the value to be encoded and the second parameter includes options that control how certain special characters are encoded. This parameter is optional. In the previous code we created a somewhat complex associative array that contains travel information of two passengers. Passing this array to json_encode() creates a JSON string. There's more... Predefined constants Any of the following constants can be passed as a second parameter to json_encode(). JSON_HEX_TAG: Converts < and > to u003C and u003E JSON_HEX_AMP: Converts &s to u0026 JSON_HEX_APOS: Converts ' to u0027 JSON_HEX_QUOT: Converts " to u0022 JSON_FORCE_OBJECT: Forces the return value in JSON string to be an object instead of an array These constants require PHP version 5.3 or higher.
Read more
  • 0
  • 0
  • 7474

article-image-introduction-developing-facebook-applications
Packt
20 Dec 2010
6 min read
Save for later

Introduction to Developing Facebook Applications

Packt
20 Dec 2010
6 min read
  Facebook Graph API Development with Flash Build social Flash applications fully integrated with the Facebook Graph API Build your own interactive applications and games that integrate with Facebook Add social features to your AS3 projects without having to build a new social network from scratch Learn how to retrieve information from Facebook's database A hands-on guide with step-by-step instructions and clear explanation that encourages experimentation and play         Read more about this book       So let's get on with it... What's so great about Facebook? Seems like everyone's on Facebook these days—people are on it to socialize; businesses are on it to try to attract those people's attention. But the same is true for other older social networks such as LinkedIn, Friendster, and MySpace. Facebook's reach goes far beyond these; my small town's high street car park proudly displays a "Like Us On Facebook" sign. More and more Flash games and Rich Internet Applications (RIAs) are allowing users to log in using their Facebook account—it's a safe assumption that most users will have one. Companies are asking freelancers for deeper Facebook integration in their projects. It's practically a buzzword. But why the big fuss? It's popular Facebook benefits from the snowball effect: it's big, so it gets bigger. People sign up because most of their friends are already on it, which is generally not the case for, say, Twitter. Businesses sign up because they can reach so many people. It's a virtuous circle. There's a low barrier to entry, too; it's not just for techies, or even people who are "pretty good with computers;" even old people and luddites use Facebook. In February 2010, the technology blog ReadWriteWeb published an article called "Facebook Wants to Be Your One True Login," about Facebook's attempts to become the de facto login system throughout the Web. Within minutes, the comments filled up with posts from confused Facebook users: (Source: http://www.readwriteweb.com/archives/facebook_wants_to_be_your_one_true_login.php.) Evidently, the ReadWriteWeb article had temporarily become the top search result for Facebook Login, leading hundreds of Facebook users, equating Google or Bing with the Internet, to believe that this blog post was actually a redesigned Facebook.com. The comment form, fittingly, had a Sign in with Facebook button that could be used instead of manually typing in a name and e-mail address to sign a comment—and of course, the Facebook users misinterpreted this as the new Log in button. And yet… all of those people manage to use Facebook, keenly enough to throw a fit when it apparently became impossible to use. It's not just a site for geeks and students; it has serious mass market appeal. Even "The Social Network"—a movie based on the creation of Facebook—held this level of appeal: it opened at #1 and remained there for its second weekend. Numbers According to Facebook's statistics page (http://www.facebook.com/press/info.php?statistics), over 500 million people log in to Facebook in any given month (as of November 2010). For perspective, the population of the entire world is just under 7,000 million. Twitter is estimated to have 95 million monthly active users (according to the eMarketer.com September 2010 report), as is MySpace. FarmVille, the biggest game based on the Facebook platform, has over 50 million: more than half the population of either competing social network. FarmVille has been reported to be hugely profitable, with some outsider reports claiming that its parent company, Zynga, has generated twice as much profit as Facebook itself (though take this with a grain of salt). Now, of course, not every Facebook game or application can be that successful, and FarmVille does benefit from the same snowball effect as Facebook itself, making it hard to compete with—but that almost doesn't matter; these numbers validate Facebook as a platform on which a money-making business can be built. It's everywhere As the aforementioned ReadWriteWeb article explained, Facebook has become a standard login across many websites. Why add yet another username/password combination to your browser's list (or your memory) if you can replace them all with one Facebook login? This isn't restricted to posting blog comments. UK TV broadcaster, Channel 4, allows viewers to access their entire TV lineup on demand, with no need to sign up for a specific Channel 4 account: Again, Facebook benefits from that snowball effect: as more sites enable a Facebook login, it becomes more of a standard, and yet more sites decide to add a Facebook login in order to keep up with everyone else. Besides login capabilities, many sites also allow users to share their content via Facebook. Another UK TV broadcaster, the BBC, lets users post links for their recommended TV programs straight to Facebook: Blogs—or, indeed, many websites with articles—allow readers to Like a post, publishing this fact on Facebook and on the site itself: So half a billion people use the Facebook website every month, and at the same time, Facebook spreads further and further across the Internet—and even beyond. "Facebook Messages" stores user's entire conversational histories, across e-mail, SMS, chat, and Facebook itself; "Facebook Places" lets users check into a physical location, letting friends know that they're there. No other network has this reach. It's interesting to develop for With all this expansion, it's difficult for a developer to keep up with the Facebook platform. And sometimes there are bugs, and undocumented areas, and periods of downtime, all of which can make development harder still. But the underlying system—the Graph API, introduced in April 2010—is fascinating. The previous API had become bloated and cumbersome over its four years; the Graph API feels well-designed with plenty of room for expansion. Have a go hero – get on Facebook If you're not on Facebook already, sign up now (for free) at http://facebook.com. You'll need an account in order to develop applications that use it. Spend some time getting used to it: Set up a personal profile. Post messages to your friends on their Walls. See what all the FarmVille fuss is about at http://apps.facebook.com/onthefarm. Check in to a location using Facebook Places. Log in to some blogs using your Facebook account. Share some YouTube videos on your own Wall from the YouTube website. "Like" something. Go native!
Read more
  • 0
  • 0
  • 3490

article-image-creating-skeleton-apps-coily-spring-python
Packt
16 Dec 2010
3 min read
Save for later

Creating Skeleton Apps with Coily in Spring Python

Packt
16 Dec 2010
3 min read
  Spring Python 1.1 Create powerful and versatile Spring Python applications using pragmatic libraries and useful abstractions   Maximize the use of Spring features in Python and develop impressive Spring Python applications Explore the versatility of Spring Python by integrating it with frameworks, libraries, and tools Discover the non-intrusive Spring way of wiring together Python components Packed with hands-on-examples, case studies, and clear explanations for better understanding          Read more about this book       (For more resources on this subject, see here.) Plugin approach of Coily coily is a Python script designed from the beginning to provide a plugin based platform for building Spring Python apps. Another important feature is version control of the plugins. Developers should not have to worry about installing an out-of-date plugin that was designed for an older version of Spring Python. coily allows different users on a system to have different sets of plugins installed. It also requires no administrative privileges to install a plugin. Key functions of coily coily is included in the standard installation of Spring Python. To see the available commands, just ask for help. The following table elaborates these commands. Required parts of a plugin A coily plugin closely resembles a Python package with some slight tweaks. This doesn't mean that a plugin is meant to be installed as a Python package. It is only a description of the folder structure. Let's look at the layout of the gen-cherrypy-app plugin as an example. Some parts of this layout are required, and other parts are not. The top folder is the name of the plugin. A plugin requires a __init__.py file inside the top directory. __init__.py must include a __description__ variable. This description is shown when we run the coily --help command. __init__.py must include a command function, which is either a create or apply function. create is used when the plugin needs one argument from the user. apply is used when no argument is needed from the user. Let's look at how gen-cherrypy-app meets each of these requirements. We can already see from the diagram that the top level folder has the same name as our plugin. Inside __init__.py, we can see the following help message defined. __description__ = "plugin to create skeleton CherryPy applications" gen-cherrypy-app is used to create a skeleton application. It needs the user to supply the name of the application it will create. Again, looking inside __init__.py, the following method signature can be found. def create(plugin_path, name) plugin_path is an argument provided to gen-cherrypy-app by coily, which points at the base directory of gen-cherrypy-app. This argument is also provided for plug-ins that use the apply command function. name is the name of the application provided by the user.
Read more
  • 0
  • 0
  • 1136
article-image-oracle-apex-plug-ins
Packt
16 Dec 2010
6 min read
Save for later

Oracle APEX Plug-ins

Packt
16 Dec 2010
6 min read
Oracle APEX 4.0 Cookbook Over 80 great recipes to develop and deploy fast, secure, and modern web applications with Oracle Application Express 4.0 Create feature-rich web applications in APEX 4.0 Integrate third-party applications like Google Maps into APEX by using web services Enhance APEX applications by using stylesheets, Plug-ins, Dynamic Actions, AJAX, JavaScript, BI Publisher, and jQuery Hands-on examples to make the most out of the possibilities that APEX has to offer Part of Packt's Cookbook series: Each recipe is a carefully organized sequence of instructions to complete the task as efficiently as possible   Introduction In APEX 4.0, Oracle introduced the plug-in. A plug-in is an extension to the existing functionality of APEX. The idea behind plug-ins is to make life easier for developers. Plug-ins are reusable and can be exported and imported. In this way, it is possible to create functionality which is available to all APEX developers. It is also possible to install and use them without having knowledge of what is inside the plug-in. APEX is actually a program that converts your settings from the APEX builder to HTML and JavaScript. For example, if you created a text item in the APEX builder, APEX converts this to the following code (simplified): <input type="text" id="P12_NAME" name="P12_NAME" value="your name"> When you create an item type plug-in, you actually take over this conversion task of APEX and you generate the HTML and JavaScript code yourself by using PL/SQL procedures. That offers a lot of flexibility because now you can make this code generic so that it can be used for more items. The same goes for region type plug-ins. A region is a container for forms, reports, and such. The region can be a div or a HTML table. By creating a region type plug-in, you create a region yourself with the possibility to add more functionality to the region. There are four types of plug-in: Item type plug-ins Region type plug-ins Dynamic action plug-ins Process type plug-ins In this article, we will discuss all four types of plug-in. Creating an item type plug-in In an item type plug-in you create an item with the possibility of extending its functionality. To demonstrate this, we will make a text field with a tooltip. This functionality is already available in APEX 4.0 by adding the following code to the HTML form element attributes text field in the Element section of the text field: onmouseover="toolTip_enable(event,this,'A tooltip')" But you have to do this for every item that should contain a tooltip. This can be made more easy by creating an item type plug-in with a built-in tooltip. And if you create an item of type plug-in, you will be asked to enter some text for the tooltip. Getting ready For this recipe, you can use an existing page with a region where you can put some text items on. How to do it... Go to Shared Components | User Interface | Plug-ins. Click on the Create button. In the name section, enter a name in the name text field. In this case, we enter tooltip. In the internal name text field, enter an internal name. It is advised to use your company's domain address reversed to ensure the name is unique when you decide to share this plug-in. So, for example, you can use com.packtpub.apex.tooltip. In the source section, enter the following code to the PL/SQL code textarea: function render_simple_tooltip ( p_item in apex_plugin.t_page_item , p_plugin in apex_plugin.t_plugin , p_value in varchar2 , p_is_readonly in boolean , p_is_printer_friendly in boolean ) return apex_plugin.t_page_item_render_result is l_result apex_plugin.t_page_item_render_result; begin if apex_application.g_debug then apex_plugin_util.debug_page_item ( p_plugin => p_plugin , p_page_item => p_item , p_value => p_value , p_is_readonly => p_is_readonly , p_is_printer_friendly => p_is_printer_friendly); end if; -- sys.htp.p('<input type="text" id="'||p_item.name||'" name="'||p_item.name||'" class="text_field" onmouseover="toolTip_enable(event,this,'||''''||p_item.attribute_01||''''||')">'); -- return l_result; end render_simple_tooltip; This function uses the sys.htp.p function to put a text item on the screen. On the text item, the onmouseover event calls the function tooltip_enable(). This function is an APEX function and can be used to put a tooltip on an item. The arguments of the function are mandatory. The function starts with the option to show debug information. This can be very useful when you have created a plug-in and it doesn't work. After the debug information the htp.p function puts the text item on the screen, including the call to tooltip_enable. You can also see that the call to tooltip_enable uses p_item.attribute_01. This is a parameter that you can use to pass a value to the plug-in. That is the following step in this recipe. The function ends with the return of l_result. This variable is of type apex_plugin.t_page_item_render_result. For the other types of plug-in there are also dedicated return types, for example, t_region_render_result. Click on the Create button. The next step is to define the parameter (attribute) for this plug-in. In the Custom Attributes section, click the Add Attribute button. In the name section, enter a name in the label text field, for example tooltip. Ensure that the attribute text field contains the value 1. In the settings section, set the type to text. Click on the Create button. In the callbacks section, enter render_simple_tooltip into the render function name text field. Click on the Apply changes button. The plug-in is ready now. The next step is to create an item of type tooltip plug-in. Go to a page with a region where you want to use an item with a tooltip. In the items section, click on the add icon to create a new item. Select Plug-ins. Now you will get a list of available plug-ins. Select the one we just created, tooltip. Click on Next. In the item name text field, enter a name for the item, for example tt_item. In the region select list, select the region you want to put the item in. Click Next. In the next step, you will get a new option. It's the attribute you created with the plug-in. Enter the tooltip text here. Click Next. In the last step, leave everything as it is and click the Create item button. You are ready now. Run the page. When you move your mouse pointer over the new item, you will see the tooltip.
Read more
  • 0
  • 0
  • 4557

Packt
16 Dec 2010
15 min read
Save for later

Page Management – Part Two in CMS

Packt
16 Dec 2010
15 min read
  CMS Design Using PHP and jQuery Build and improve your in-house PHP CMS by enhancing it with jQuery Create a completely functional and a professional looking CMS Add a modular architecture to your CMS and create template-driven web designs Use jQuery plugins to enhance the "feel" of your CMS A step-by-step explanatory tutorial to get your hands dirty in building your own CMS         Read more about this book       (For more resources on this subject, see here.) Dates Dates are annoying. The scheme I prefer is to enter dates the same way MySQL accepts them—yyyy-mm-dd hh:mm:ss. From left to right, each subsequent element is smaller than the previous. It's logical, and can be sorted sensibly using a simple numeric sorter. Unfortunately, most people don't read or write dates in that format. They'd prefer something like 08/07/06. Dates in that format do not make sense. Is it the 8th day of the 7th month of 2006, or the 7th day of the 8th month of 2006, or even the 6th day of the 7th month of 2008? Date formats are different all around the world. Therefore, you cannot trust human administrators to enter the dates manually. A very quick solution is to use the jQuery UI's datepicker plugin. Temporarily (we'll remove it in a minute) add the highlighted lines to /ww.admin/pages/pages.js: other_GET_params:currentpageid }); $('.date-human').datepicker({ 'dateFormat':'yy-mm-dd' });}); When the date field is clicked, this appears: It's a great calendar, but there's still a flaw: Before you click on the date field, and even after you select the date, the field is still in yyyy-mm-dd format. While MySQL will thank you for entering the date in a sane format, you will have people asking you why the date is not shown in a humanly readable way. We can't simply change the date format to accept something more reasonable such as "May 23rd, 2010", because we would then need to ensure that we can understand this on the server-side, which might take more work than we really want to do. So we need to do something else. The datepicker plugin has an option which lets you update two fields at the same time. This is the solution—we will display a dummy field which is humanly readable, and when that's clicked, the calendar will appear and you will be able to choose a date, which will then be set in the human-readable field and in the real form field. Don't forget to remove that temporary code from /ww.admin/pages/pages.js. Because this is a very useful feature, which we will use throughout the admin area whenever a date is needed, we will add a global JavaScript file which will run on all pages. Edit /ww.admin/header.php and add the following highlighted line: <script src="/j/jquery.remoteselectoptions /jquery.remoteselectoptions.js"></script><script src="/ww.admin/j/admin.js"></script><link rel="stylesheet" href="http://ajax.googleapis.com /ajax/libs/jqueryui/1.8.0/themes/south-street /jquery-ui.css" type="text/css" /> And then we'll create the /ww.admin/j/ directory and a file named /ww.admin/j/admin.js: function convert_date_to_human_readable(){ var $this=$(this); var id='date-input-'+Math.random().toString() .replace(/\./,''); var dparts=$this.val().split(/-/); $this .datepicker({ dateFormat:'yy-mm-dd', modal:true, altField:'#'+id, altFormat:'DD, d MM, yy', onSelect:function(dateText,inst){ this.value=dateText; } }); var $wrapper=$this.wrap( '<div style="position:relative" />'); var $input=$('<input id="'+id+'" class="date-human-readable" value="'+date_m2h($this.val())+'" />'); $input.insertAfter($this); $this.css({ 'position':'absolute', 'opacity':0 }); $this .datepicker( 'setDate', new Date(dparts[0],dparts[1]-1,dparts[2]) );}$(function(){ $('input.date-human').each(convert_date_to_human_readable);}); This takes the computer-readable date input and creates a copy of it, but in a human-readable format. The original date input box is then made invisible and laid across the new one. When it is clicked, the date is updated on both of them, but only the human-readable one is shown. Much better. Easy for a human to read, and also usable by the server. Saving the page We created the form, and except for making the body textarea more user-friendly, it's just about finished. Let's do that now. When you click on the Insert Page Details button (or Update Page Details, if an ID was provided), the form data is posted to the server. We need to perform these actions before the page menu is displayed, so it is up-to-date. Edit /ww.admin/pages.php, and add the following highlighted lines before the load menu section: echo '<h1>Pages</h1>';// { perform any actionsif(isset($_REQUEST['action'])){ if($_REQUEST['action']=='Update Page Details' || $_REQUEST['action']=='Insert Page Details'){ require 'pages/action.edit.php'; } else if($_REQUEST['action']=='delete'){ 'pages/action.delete.php'; }}// }// { load menu If an action parameter is sent to the server, then the server will use this block to decide whether you want to edit or delete the page. We'll handle deletes later in the article. Notice that we are handling inserts and updates with the same file, action.edit.php—in the database, there is almost no difference between the two when using MySQL. So, let's create that file now. We'll do it a bit at a time, like how we did the form, as it's a bit long. Create /ww.admin/pages/action.edit.php with this code: <?phpfunction pages_setup_name($id,$pid){ $name=trim($_REQUEST['name']); if(dbOne('select id from pages where name="'.addslashes($name).'" and parent='.$pid.' and id!='.$id,'id')){ $i=2; while(dbOne('select id from pages where name="'.addslashes($name.$i).'" and parent='.$pid.' and id!='.$id,'id'))$i++; echo '<em>A page named "'.htmlspecialchars($name).'" already exists. Page name amended to "' .htmlspecialchars($name.$i).'".</em>'; $name=$name.$i; } return $name;} The first piece is a function which tests the submitted page name. If that name is the same as another page which has the same parent, then a number is added to the end and a message is shown explaining this. Here's an example, creating a page named "Home" in the top level (we already have a page named "Home"): Next we'll create a function for testing the inputted special variable. Add this to the same file: function pages_setup_specials($id=0){ $special=0; $specials=isset($_REQUEST['special']) ?$_REQUEST['special']:array(); foreach($specials as $a=>$b) $special+=pow(2,$a); $homes=dbOne("SELECT COUNT(id) AS ids FROM pages WHERE (special&1) AND id!=$id",'ids'); if($special&1){ // there can be only one homepage if($homes!=0){ dbQuery("UPDATE pages SET special=special-1 WHERE special&1"); } } else{ if($homes==0){ $special+=1; echo '<em>This page has been marked as the site\'s Home Page, because there must always be one.</em>'; } } return $special;} In this function, we build up the special variable, which is a bit field. A bit field is a number which uses binary math to combine a few "yes/no" answers into one single value. It's good for saving space and fields in the database.Each value has a value assigned to it which is a power of two. The interesting thing to note about powers of two is that in binary, they're always represented as a 1 with some 0s after it. For example, 1 is represented as 00000001, 2 is 00000010, 4 is 00000100, and so on.When you have a bit field such as 00000011 (each number here is a bit), it's easy to see that this is composed of the values 1 and 2 combined, which are 20 and 21 respectively.The & operator lets us check quickly if a certain bit is turned on (is 1) or not. For example, 00010011 & 16 is true, and 00010011 & 32 is false, because the 16 bit is on and the 32 bit is off. In the database, we set a bit for the homepage, which we say has a value of 1. In the previous function, we need to make sure that after inserting or updating a page, there is always exactly one homepage. The only other one we've set so far is "does not appear in navigation menu", which we've given the value 2. If we added a third bit flag ("is a 404 handler", for example), it would have the value 4, then 8, and so on. Okay—now we will set up our variables. Add this to the same file: // { set up common variables$id =(int)$_REQUEST['id'];$pid =(int)$_REQUEST['parent'];$keywords =$_REQUEST['keywords'];$description =$_REQUEST['description'];$associated_date =$_REQUEST['associated_date'];$title =$_REQUEST['title'];$name =pages_setup_name($id,$pid);$body =$_REQUEST['body'];$special =pages_setup_specials($id);if(isset($_REQUEST['page_vars'])) $vars =json_encode($_REQUEST['page_vars']);else $vars='[]';// } Then we will add the main body of the page update SQL to the same file: // { create SQL$q='edate=now(),type="'.addslashes($_REQUEST['type']).'", associated_date="'.addslashes($associated_date).'", keywords="'.addslashes($keywords).'", description="'.addslashes($description).'", name="'.addslashes($name).'", title="'.addslashes($title).'", body="'.addslashes($body).'",parent='.$pid.', special='.$special.',vars="'.addslashes($vars).'"';// } This is SQL which is common to both creating and updating a page. Finally we run the actual query and perform the action. Add this to the same file: // { run the queryif($_REQUEST['action']=='Update Page Details'){ $q="update pages set $q where id=$id"; dbQuery($q);}else{ $q="insert into pages set cdate=now(),$q"; dbQuery($q); $_REQUEST['id']=dbLastInsertId();}// }echo '<em>Page Saved</em>'; In the first case, we simply run an update. In the second, we run an insert, adding the creation date to the query, and then setting $_REQUEST['id'] to the ID of the entry that we just created. Creating new top-level pages If you've been trying all this, you'll have noticed that you can create a top-level page simply by clicking on the admin area's Pages link in the top menu, and then you're shown an empty Insert Page Details form. If you've been trying all this, you'll have noticed that you can create a top-level page simply by clicking on the admin area's Pages link in the top menu, and then you're shown an empty Insert Page Details form. It makes sense, though, to also have it available from the pagelist on the left-hand side. So, let's make that add main page button useful. If you remember, we created a pages_add_main_page function in the menu.js file, just as a placeholder until we got everything else done. Open up that file now, /ww.admin/pages/menu.js, and replace that function with the following two new functions: function pages_add_main_page(){ pages_new(0);}function pages_new(p){ $('<form id="newpage_dialog" action="/ww.admin/pages.php" method="post"> <input type="hidden" name="action" value="Insert Page Details" /> <input type="hidden" name="special[1]" value="1" /> <input type="hidden" name="parent" value="'+p+'" /> <table> <tr><th>Name</th><td><input name="name" /></td></tr> <tr><th>Page Type</th><td><select name="type"> <option value="0">normal</option> </select></td></tr> <tr><th>Associated Date</th><td> <input name="associated_date" class="date-human" id="newpage_date" /></td></tr> </table> </form>') .dialog({ modal:true, buttons:{ 'Create Page': function() { $('#newpage_dialog').submit(); }, 'Cancel': function() { $(this).dialog('destroy'); $(this).remove(); } } }); $('#newpage_date').each(convert_date_to_human_readable); return false;} When the add main page button is clicked, a dialog box is created asking some basic information about the page to create: We include a few hidden inputs. action: To tell the server this is an Insert Page Details action. special: When Create Page is clicked, the page will be saved in the database, but we should hide it initially so that front-end readers don't see a half-finished page. So, the special[1] flag is set (21 == 2, which is the value for hiding a page). parent: Note that this is a variable. We can use the same dialog to create sub-pages. When the dialog has been created, the date input box is converted to human-readable. Creating new sub-pages We will add sub-pages by using context menus on the page list. Note that we have a message saying right-click for options under the list. First, add this function to the /ww.admin/pages/menu.js file: function pages_add_subpage(node,tree){ var p=node[0].id.replace(/.*_/,''); pages_new(p);} We will now need to activate the context menu. This is done by adding a contextmenu plugin to the jstree plugin . Luckily, it comes with the download, so you've already installed it. Add it to the page by editing /ww.admin/pages/menu.php and add this highlighted line: <script src="/j/jquery.jstree/jquery.tree.js"></script><script src= "/j/jquery.jstree/plugins/jquery.tree.contextmenu.js"></script><script src="/ww.admin/pages/menu.js"></script> And now, we edit the .tree() call in /ww.admin/menu.js to tell it what to do: $('#pages-wrapper').tree({ callback:{// SKIPPED FOR BREVITY - DO NOT DELETE THESE LINES }, plugins:{ 'contextmenu':{ 'items':{ 'create' : { 'label' : "Create Page", 'icon' : "create", 'visible' : function (NODE, TREE_OBJ) { if(NODE.length != 1) return 0; return TREE_OBJ.check("creatable", NODE); }, 'action':pages_add_subpage, 'separator_after' : true }, 'rename':false, 'remove':false } } }}); By default, the contextmenu has three links: create, rename, and remove. You need to turn off any you're not currently using by setting them to false. Now if you right-click on any page name in the pagelist, you will have a choice to create a sub-page under it. Deleting pages We will add deletions in the same way, using the context menu. Edit the same file, and this time in the contextmenu code, replace the remove: false line with these: 'remove' : { 'label' : "Delete Page", 'icon' : "remove", 'visible' : function (NODE, TREE_OBJ) { if(NODE.length != 1) return 0; return TREE_OBJ.check("deletable", NODE); }, 'action':pages_delete, 'separator_after' : true} And add the pages_delete function to the same file: function pages_delete(node,tree){ if(!confirm( "Are you sure you want to delete this page?"))return; $.getJSON('/ww.admin/pages/delete.php?id=' +node[0].id.replace(/.*_/,''),function(){ document.location=document.location.toString(); }); } One thing to always keep in mind is whenever creating any code that deletes something in your CMS, you must ask the administrator if he/she is sure, just to make sure it wasn't an accidental click. If the administrator confirms that the click was intentional, then it's not your fault if something important was deleted. So, the pages_delete function first checks for this, and then calls the server to remove the file. The page is then refreshed because this may significantly change the page list tree, as we'll see now. Create the /ww.admin/pages/delete.php file: <?phprequire '../admin_libs.php';$id=(int)$_REQUEST['id'];if(!$id)exit;$r=dbRow("SELECT COUNT(id) AS pagecount FROM pages");if($r['pagecount']<2){ die('cannot delete - there must always be one page');}else{ $pid=dbOne("select parent from pages where id=$id",'parent'); dbQuery("delete from pages where id=$id"); dbQuery("update pages set parent=$pid where parent=$id");}echo 1; First, we ensure that there is always at least one page in the database. If deleting this page would empty the table, then we refuse to do it. There is no need to add an alert explaining this, as it should be clear to anyone that deleting the last remaining page in a website leaves the website with no content at all. Simply refusing the deletion should be enough. Next, we delete the page. Finally, any pages which were contained within that page (pages which had this one as their parent), are moved up in the tree so they are contained in the deleted page's old parent. For example, if you had a page, page1>page2>page3 (where > indicates the hierarchy), and you removed page2, then page3 would then be in the position page1>page3. This can cause a large difference in the treestructure if there were quite a few pages contained under the deleted one, so the page needs to be refreshed.
Read more
  • 0
  • 0
  • 887

article-image-getting-started-magento-development
Packt
15 Dec 2010
8 min read
Save for later

Getting Started with Magento Development

Packt
15 Dec 2010
8 min read
Magento is an open-source eCommerce stack with smart features such as layered navigation, auto-complete search, multiple language support, multiple stores, smart browsing, RSS product feeds, tagging and reviewing products, reviewing search terms, reviewing customer tags, poll manager, currency exchange rates, Google sitemap integration, abandoned shopping cart report, catalog-wide product comparisons, product wish lists, and even zooming the product image. It was created by Varien, based on the top notch MVC framework—Zend Framework, on March 31, 2008. As with other MVC applications, Magento keeps the display logic separated from the application's business logic. A dedicated team works on updating Magento regularly. Magento Developer is a very hands-on role for both a novice and experienced software engineer who is interested in achieving high impact in a fast-paced development environment with an ambitious mission. Magento gives a very handy way to deal with its features faster than any other alternatives, whether you know a little or a lot about PHP programming. Let's see how these things happen. We will make our development platform ready to cook some mouth-watering recipes for Magento in this article. If you are a newbie, this is the right place to start. If you are a pro, this is still the right place to start as we have tried to follow some best practices for Magento development that you might not be aware of. Let's get our hands dirty with Magento Development! Good luck! Preparing the platform with a virtual host Magento is built on the de facto PHP framework—Zend Framework. We need to set up our development environment properly to get most out of it. In this recipe, we will set up a Fully Qualifed Domain Name (FQDN) and a virtual host. We could use the domain as http://localhost/magento or something like this, but in that case accessing the admin panel might be cumbersome. In most cases, you have to access through the local IP address. Using a FQDN, you don't have to worry about it. A FQDN will make the debugging process much easier also. Getting Ready We need to have the following things installed before kicking off the setup of a virtual host a.k.a. vhost: Apache2 PHP5 MySQL server 5.0 If we want to install the previously mentioned tools from Ubuntu Linux CLI, we can easily do that by running the following commands. We will be using Linux commands based on Ubuntu. The following command is a basic Apache installation command: sudo aptitude install apache2 apache2.2-common apache2-mpm-prefork apache2-utils libexpat1 ssl-cert The following command is a basic PHP5 installation command: sudo aptitude install libapache2-mod-php5 php5 php5-common php5-curl php5-dev php5-gd php5-imagick php5-mcrypt php5-memcache php5-mhash php5- mysql php5-pspell php5-snmp php5-sqlite php5-xmlrpc php5-xsl Enter the following command to begin with a simple MySQL installation: sudo aptitude install mysql-server mysql-client libmysqlclient15-dev Note that we have installed the development libs and headers with the libmysqlclient15-dev package. You can leave that out but it has been found that they are useful in many situations. Alternately, we can use an all-in-one package, such as the XAMPP, to get all the aforementioned tools in one click. The XAMPP package can be downloaded from http://www.apachefriends.org/en/xampp.html. How to do it... To test the domain without creating a DNS zone and record(s) on some Internet nameserver(s), let's modify the /etc/hosts file on our local computer to include some entries mapping the magento.local.com, and so on to the local machine's public IP address (in most cases, 127.0.0.1). Open the /etc/hosts file with any text editor or run the following command in terminal: sudo nano /etc/hosts Add the following line as a similar entry in /etc/hosts file: 127.0.0.1 magento.local.com The location of the host file depends on the OS loaded. If it's a Windows OS it should be c:windowssystem32driversetchosts. Now let's create the layout for our domain. Open terminal and change your location to the WEBROOT directory by running the following command: cd /var/www/ If you are using XAMPP, it would be c:xampphtdocs. Now for our domain, we want to host/create a folder with a standard set of subfolders: mkdir -p magento.local.com/{public,private,log,cgi-bin,backup} Let's create an index.html file for our domain: sudo nano /var/www/magento.local.com/public/index.html It's time to put some content in our index file: <html> <head> <title>Welcome to magento.local.com</title> </head> <body> <h1>Welcome to magento.local.com</h1> </body> </html> We've set up the basics and now we're ready to add our own virtual hosts, so that we can start to serve our domain. Let's go ahead and create the vhost file for magento.local.com: sudo nano /etc/apache2/sites-available/magento.local.com The contents should look like this: # Place any notes or comments you have here # It will make any customization easier to understand in the weeks to come # domain: magento.local.com # public: /var/www/magento.local.com/public <VirtualHost *:80> # Admin email, Server Name (domain name) and any aliases ServerAdmin [email protected] ServerName magento.local.com # Index file and Document Root (where the public files are located) DirectoryIndex index.php index.html DocumentRoot /var/www/magento.local.com/public # Custom log file locations LogLevel warn ErrorLog /var/www/magento.local.com/log/error.log CustomLog /var/www/magento.local.com/log/access.log combined </VirtualHost> Now we have the site available, we need to enable it: sudo a2ensite magento.local.com It seems like good advice to reload the apache: sudo /etc/init.d/apache2 reload With such changes made, we can now navigate to our site in a web browser on our local computer, as seen in the following screenshot: Tada! We now have the contents of public/index.html being shown. How it works... The Getting ready recipe describes the installation process of Apache, PHP, and MySQL from Linux command line. If you have already installed those, you can skip it and start confguring the layout and vhost directly. The Magento source files will be put in the public directory. Other directories represent as their name suggest. Usually in production server, we don't have to write the domain name manually as we wrote here, as the DNS zone is there. The rest of this recipe is the same as the production server. The virtual host contents has some inline comments starting with # to describe the purpose. Setting up a Subversion/SVN A Subversion is a popular version control system initiated in 2000 by CollabNet Inc. Its goal is to be a mostly-compatible successor to the widely used Concurrent Versions System (CVS). Getting Ready If you are a Windows user, please download the TortoiseSVN client from here: http://tortoisesvn.tigris.org/ and if you are a Linux user, fre up your terminal. How to do it... Execute the following command in the terminal to install Subversion: sudo apt-get install subversion Make sure you have an active Internet connection as aptitude will install the package from Ubuntu repository. If you are using windows and intended to use TortoiseSVN you may get a Windows binary from http://tortoisesvn.tigris.org. After downloading the TortoiseSVN installer file, double-click on the TortoiseSVN installer file and follow the on screen instructions. Now let's add a new group called Subversion to our system and add current username to Subversion group. sudo addgroup subversion sudo adduser <your_username_here> subversion If you don't a have a clue about your current username, issue the command whoami in your terminal. Once the Subversion installation is completed, let's create our repository for Magento project. Now issue the following command in the terminal: sudo mkdir /home/svn cd /home/svn sudo mkdir magento sudo chown -R www-data:subversion magento sudo chmod -R g+rws magento Now initiate an SVN repository with the following command: sudo svnadmin create /home/svn/magento In the case of TortoiseSVN, open the folder where you want to put your Magento repository and right-click and find create repository here... from the context menu TortoiseSVN. Enter a name for your repository, in this case the repository name would be magento. It's time to change your current working directory in terminal to: cd /var/www/magento.local.com We will checkout the Magento project by issuing the following command in the terminal: svn co file:///home/svn/magento public How it works... When we execute any apt-get command, the aptitude will take care of the installation process. The aptitude will look for the package from Ubuntu central repository—and download it if necessary—and perform the necessary tasks. After completion of the installation process, we've created a new group named subversion and added the username to the newly created group subversion. Then we've created a directory under /home/location to hold all repositories. After that, we've created a new repository for our Magento project named magento. Finally, we've checked out the repository in our site location in the public directory.
Read more
  • 0
  • 0
  • 1867
article-image-creating-your-first-module-drupal-7-module-development
Packt
14 Dec 2010
15 min read
Save for later

Using Drupal 7 for Module Development

Packt
14 Dec 2010
15 min read
  Drupal 7 Module Development Create your own Drupal 7 modules from scratch Specifically written for Drupal 7 development Write your own Drupal modules, themes, and libraries Discover the powerful new tools introduced in Drupal 7 Learn the programming secrets of six experienced Drupal developers Get practical with this book's project-based format         Read more about this book       The focus of this article by Matt Butcher, author of Drupal 7 Module Development, is module creation. We are going to begin coding in this article. Here are some of the important topics that we will cover in this article: Starting a new module Creating .info files to provide Drupal with module information Creating .module files to store Drupal code Adding new blocks using the Block Subsystem Using common Drupal functions Formatting code according to the Drupal coding standards (For more resources on this subject, see here.) Our goal: a module with a block In this article we are going to build a simple module. The module will use the Block Subsystem to add a new custom block. The block that we add will simply display a list of all of the currently enabled modules on our Drupal installation. We are going to divide this task of building a new module into the three parts: Create a new module folder and module files Work with the Block Subsystem Write automated tests using the SimpleTest framework included in Drupal We are going to proceed in that order for the sake of simplicity. One might object that, following agile development processes, we ought to begin by writing our tests. This approach is called Test-driven Development (TDD), and is a justly popular methodology. Agile software development is a particular methodology designed to help teams of developers effectively and efficiently build software. While Drupal itself has not been developed using an agile process, it does facilitate many of the agile practices. To learn more about agile, visit http://agilemanifesto.org/ However, our goal here is not to exemplify a particular methodology, but to discover how to write modules. It is easier to learn module development by first writing the module, and then learn how to write unit tests. It is easier for two reasons: SimpleTest (in spite of its name) is the least simple part of this article. It will have double the code-weight of our actual module. We will need to become acquainted with the APIs we are going to use in development before we attempt to write tests that assume knowledge of those APIs. In regular module development, though, you may certainly choose to follow the TDD approach of writing tests first, and then writing the module. Let's now move on to the first step of creating a new module. Creating a new module Creating Drupal modules is easy. How easy? Easy enough that over 5,000 modules have been developed, and many Drupal developers are even PHP novices! In fact, the code in this article is an illustration of how easy module coding can be. We are going to create our first module with only one directory and two small files. Module names It goes without saying that building a new module requires naming the module. However, there is one minor ambiguity that ought to be cleared up at the outset, a Drupal module has two names: A human-readable name: This name is designed to be read by humans, and should be one or a couple of words long. The words should be capitalized and separated by spaces. For example, one of the most popular Drupal modules has the human-readable name Views. A less-popular (but perhaps more creatively named) Drupal 6 module has the human-readable name Eldorado Superfly. A machine-readable name: This name is used internally by Drupal. It can be composed of lower-case and upper-case letters, digits, and the underscore character (using upper-case letters in machine names is frowned upon, though). No other characters are allowed. The machine names of the above two modules are views and eldorado_superfly, respectively. By convention, the two names ought to be as similar as possible. Spaces should be replaced by underscores. Upper-case letters should generally be changed to lower-case. Because of the convention of similar naming, the two names can usually be used interchangeably, and most of the time it is not necessary to specifically declare which of the two names we are referring to. In cases where the difference needs to be made (as in the next section), the authors will be careful to make it. Where does our module go? One of the less intuitive aspects of Drupal development is the filesystem layout. Where do we put a new module? The obvious answer would be to put it in the /modules directory alongside all of the core modules. As obvious as this may seem, the /modules folder is not the right place for your modules. In fact, you should never change anything in that directory. It is reserved for core Drupal modules only, and will be overwritten during upgrades. The second, far less obvious place to put modules is in /sites/all/modules. This is the location where all unmodified add-on modules ought to go, and tools like Drush ( a Drupal command line tool) will download modules to this directory. In some sense, it is okay to put modules here. They will not be automatically overwritten during core upgrades. However, as of this writing, /sites/all/modules is not the recommended place to put custom modules unless you are running a multi-site configuration and the custom module needs to be accessible on all sites. The current recommendation is to put custom modules in the /sites/default/modules directory, which does not exist by default. This has a few advantages. One is that standard add-on modules are stored elsewhere, and this separation makes it easier for us to find our own code without sorting through clutter. There are other benefits (such as the loading order of module directories), but none will have a direct impact on us. We will always be putting our custom modules in /sites/default/modules. This follows Drupal best practices, and also makes it easy to find our modules as opposed to all of the other add-on modules. The one disadvantage of storing all custom modules in /sites/default/modules appears only under a specific set of circumstances. If you have Drupal configured to serve multiple sites off of one single instance, then the /sites/default folder is only used for the default site. What this means, in practice, is that modules stored there will not be loaded at all for other sites. In such cases, it is generally advised to move your custom modules into /sites/all/modules/custom. Other module directories Drupal does look in a few other places for modules. However, those places are reserved for special purposes. Creating the module directory Now that we know that our modules should go in /sites/default/modules, we can create a new module there. Modules can be organized in a variety of ways, but the best practice is to create a module directory in /sites/default/modules, and then place at least two files inside the directory: a .info (pronounced "dot-info") file and a .module ("dot-module") file. The directory should be named with the machine-readable name of the module. Similarly, both the .info and .module files should use the machine-readable name. We are going to name our first module with the machine-readable name first, since it is our first module. Thus, we will create a new directory, /sites/default/modules/first, and then create a first.info file and a first.module file: Those are the only files we will need for our module. For permissions, make sure that your webserver can read both the .info and .module files. It should not be able to write to either file, though. In some sense, the only file absolutely necessary for a module is the .info file located at a proper place in the system. However, since the .info file simply provides information about the module, no interesting module can be built with just this file. Next, we will write the contents of the .info file. Writing the .info file The purpose of the .info file is to provide Drupal with information about a module—information such as the human-readable name, what other modules this module requires, and what code files this module provides. A .info file is a plain text file in a format similar to the standard INI configuration file. A directive in the .info file is composed of a name, and equal sign, and a value: name = value By Drupal's coding conventions, there should always be one space on each side of the equals sign. Some directives use an array-like syntax to declare that one name has multiple values. The array-like format looks like this: name[] = value1 name[] = value2 Note that there is no blank space between the opening square bracket and the closing square bracket. If a value spans more than one line, it should be enclosed in quotation marks. Any line that begins with a ; (semi-colon) is treated as a comment, and is ignored by the Drupal INI parser. Drupal does not support INI-style section headers such as those found in the php.ini file. To begin, let's take a look at a complete first.info file for our first module: ;$Id$ name = First description = A first module. package = Drupal 7 Development core = 7.x files[] = first.module ;dependencies[] = autoload ;php = 5.2 This ten-line file is about as complex as a module's .info file ever gets. The first line is a standard. Every .info file should begin with ;$Id$. What is this? It is the placeholder for the version control system to store information about the file. When the file is checked into Drupal's CVS repository, the line will be automatically expanded to something like this: ;$Id: first.info,v 1.1 2009/03/18 20:27:12 mbutcher Exp $ This information indicates when the file was last checked into CVS, and who checked it in. CVS is going away, and so is $Id$. While Drupal has been developed in CVS from the early days through Drupal 7, it is now being migrated to a Git repository. Git does not use $Id$, so it is likely that between the release of Drupal 7 and the release of Drupal 8, $Id$ tags will be removed. You will see all PHP and .info files beginning with the $Id$ marker. Once Drupal uses Git, those tags may go away. The next couple of lines of interest in first.info are these: name = First description = A first module. package = Drupal 7 Development The first two are required in every .info file. The name directive is used to declare what the module's human-readable name is. The description provides a one or two-sentence description of what this module provides or is used for. Among other places, this information is displayed on the module configuration section of the administration interface in Modules. In the screenshot, the values of the name and description fields are displayed in their respective columns. The third item, package, identifies which family (package) of modules this module is related to. Core modules, for example, all have the package Core. In the screenshot above, you can see the grouping package Core in the upper-left corner. Our module will be grouped under the package Drupal 7 Development to represent its relationship. As you may notice, package names are written as human-readable values. When choosing a human-readable module name, remember to adhere to the specifications mentioned earlier in this section. The next directive is the core directive: core = 7.x. This simply declares which main-line version of Drupal is required by the module. All Drupal 7 modules will have the line core = 7.x. Along with the core version, a .info file can also specify what version of PHP it requires. By default, Drupal 7 requires Drupal 5.1 or newer. However, if one were to use, say, closures (a feature introduced in PHP 5.3), then the following line would need to be added: php = 5.3 Next, every .info file must declare which files in the module contain PHP functions, classes, or interfaces. This is done using the files[] directive. Our small initial module will only have one file, first.module. So we need only one files[] directive. files[] = first.module More complex files will often have several files[] directives, each declaring a separate PHP source code file. JavaScript, CSS, image files, and PHP files (like templates) that do not contain functions that the module needs to know about needn't be included in files[] directives. The point of the directive is simply to indicate to Drupal that these files should be examined by Drupal. One directive that we will not use for this module, but which plays a very important role is the dependencies[] directive. This is used to list the other modules that must be installed and active for this module to function correctly. Drupal will not allow a module to be enabled unless its dependencies have been satisfied. Drupal does not contain a directive to indicate that another module is recommended or is optional. It is the task of the developer to appropriately document this fact and make it known. There is currently no recommended best practice to provide such information. Now we have created our first.info file. As soon as Drupal reads this file, the module will appear on our Modules page. In the screenshot, notice that the module appears in the DRUPAL 7 DEVELOPMENT package, and has the NAME and DESCRIPTION as assigned in the .info file. With our .info file completed, we can now move on and code our .module file. Modules checked into Drupal's version control system will automatically have a version directive added to the .info file. This should typically not be altered. Creating a module file The .module file is a PHP file that conventionally contains all of the major hook implementations for a module. We will gain some practical knowledge of them. A hook implementation is a function that follows a certain naming pattern in order to indicate to Drupal that it should be used as a callback for a particular event in the Drupal system. For Object-oriented programmers, it may be helpful to think of a hook as similar to the Observer design pattern. When Drupal encounters an event for which there is a hook (and there are hundreds of such events), Drupal will look through all of the modules for matching hook implementations. It will then execute each hook implementation, one after another. Once all hook implementations have been executed, Drupal will continue its processing. In the past, all Drupal hook implementations had to reside in the .module file. Drupal 7's requirements are more lenient, but in most moderately sized modules, it is still preferable to store most hook implementations in the .module file. There are cases where hook implementations belong in other files. In such cases, the reasons for organizing the module in such a way will be explained. To begin, we will create a simple .module file that contains a single hook implementation – one that provides help information. <?php // $Id$ /** * @file * A module exemplifying Drupal coding practices and APIs. * * This module provides a block that lists all of the * installed modules. It illustrates coding standards, * practices, and API use for Drupal 7. */ /** * Implements hook_help(). */ function first_help($path, $arg) { if ($path == 'admin/help#first') { return t('A demonstration module.'); } } Before we get to the code itself, we will talk about a few stylistic items. To begin, notice that this file, like the .info file, contains an $Id$ marker that CVS will replace when the file is checked in. All PHP files should have this marker following a double-slash-style comment: // $Id$. Next, the preceding code illustrates a few of the important coding standards for Drupal. Source code standards Drupal has a thorough and strictly enforced set of coding standards. All core code adheres to these standards. Most add-on modules do, too. (Those that don't generally receive bug reports for not conforming.) Before you begin coding, it is a good idea to familiarize yourself with the standards as documented here: http://drupal.org/coding-standards. The Coder module can evaluate your code and alert you to any infringement upon the coding standards. We will adhere to the Drupal coding standards. In many cases, we will explain the standards as we go along. Still, the definitive source for standards is the URL listed above, not our code here. We will not re-iterate the coding standards. The details can be found online. However, several prominent standards deserve immediate mention. I will just mention them here, and we will see examples in action as we work through the code. Indenting: All PHP and JavaScript files use two spaces to indent. Tabs are never used for code formatting. The <?php ?> processor instruction: Files that are completely PHP should begin with <?php, but should omit the closing ?>. This is done for several reasons, most notably to prevent the inclusion of whitespace from breaking HTTP headers. Comments: Drupal uses Doxygen-style (/** */) doc-blocks to comment functions, classes, interfaces, constants, files, and globals. All other comments should use the double-slash (//) comment. The pound sign (#) should not be used for commenting. Spaces around operators: Most operators should have a whitespace character on each side. Spacing in control structures: Control structures should have spaces after the name and before the curly brace. The bodies of all control structures should be surrounded by curly braces, and even that of if statements with one-line bodies. Functions: Functions should be named in lowercase letters using underscores to separate words. Later we will see how class method names differ from this. Variables: Variable names should be in all lowercase letters using underscores to separate words. Member variables in objects are named differently. As we work through examples, we will see these and other standards in action. As we work through examples, we will see these and other standards in action.
Read more
  • 0
  • 0
  • 5707

article-image-drupal-7-module-development-drupals-theme-layer
Packt
14 Dec 2010
16 min read
Save for later

Drupal 7 Module Development: Drupal's Theme Layer

Packt
14 Dec 2010
16 min read
  Drupal 7 Module Development Create your own Drupal 7 modules from scratch Specifically written for Drupal 7 development Write your own Drupal modules, themes, and libraries Discover the powerful new tools introduced in Drupal 7 Learn the programming secrets of six experienced Drupal developers Get practical with this book's project-based format Business logic versus presentation logic So what would be the best way to get our data and functionality marked up? Do we simply wrap each piece of data in HTML and return the whole as a giant string? Like the following example: return '<div class="wrapper">' . $data . '</div>'; Fortunately, we don't. Like all other well-designed applications, Drupal separates its business logic from its presentation logic. Traditionally, the primary motivations for this separation of concerns are as follows: To make the code easier to maintain. To make it possible to easily swap out one layer's implementation without having to re-write the other layers. As we shall see, Drupal takes the "swap-ability" aspect to the extreme. As we mentioned in the introduction of this article, the default theme selected on the Appearance page is the most obvious part of the theme layer. Also, you might think that the theme is responsible for applying the HTML and CSS for the website. However, there are thousands of contributed modules on drupal.org. Should the theme be responsible for marking up all of those modules' data? Obviously not. Since a module is most intimately familiar with its own data and functionality, it's the module's responsibility to provide the default theme implementation. As long as the module uses the theme system properly, a theme will be able to override any HTML and CSS by hot-swapping its own implementation for the module's implementation. After the data has been retrieved and manipulated in the heart of your module (the business logic), it will need to provide the default theme implementation. Sometimes a particular theme will need to override your implementation in order for it to achieve a specifc design goal; if the theme provides its own implementation, Drupal will use the theme implementation instead of the module's default implementation. $variables = array('items' => $list, 'type' => 'ol'); $content = theme('item_list', $variables); By calling the theme() function, we are delegating the responsibility of determining and using the proper theme implementation. We're saying: "Hey, theme()! I want to markup my data as an item_list. Can you do that for me? I don't need to know the details. kthxbye." Our module just needs to decide which theme hook it wants to use to markup its data. Should the data be displayed in an unordered list, a table, or a wordle? Hook crazy? In addition to API hooks, Drupal also has theme hooks. A theme hook is simply the name of a particular way to markup some data. For example, passing data to the item_list theme hook will result in different markup then passing data to the links theme hook. However, while normally every module's hook function will be called when Drupal invokes an API hook, only one theme hook implementation will be invoked when Drupal invokes a theme hook. There are actually two different ways you can make an implementation (which we will discuss later), but for now we'll only talk about the simplest method for module developers—theme functions. When you call theme(), it will look for a default theme function named theme_HOOKNAME and for an optional theme override function called THEMENAME_HOOKNAME. If you dig into Drupal's internals, you'll fnd a theme_item_list() inside includes.inc or theme.inc. This is Drupal's default theme implementation for an item_list. If our active theme was Bartik, and if Bartik implemented a theme override called bartik_item_list(), then theme() would use the Bartik theme's implementation instead of the default one. The preceding fgure shows one piece of data as it passes through a module and a theme. However, in order for you to understand the full power of Drupal's theme layer, you also need to understand how the entire page is built. However, since all of the active theme's modifcations occur after any module modifcations, from a module developer's perspective, all of this theme inheritance is transparent. Since modules don't need to know anything about the structure o the theme and its ancestry, we'll simply talk about "the theme" in this book. Just be aware that the actual theme may be more complex. Base themes and sub-themes If you've previously read anything about Drupal theming, you've probably heard about base themes and sub-themes. Any theme can declare a parent theme in its .info file using the base theme key and it will inherit all the hook implementations from its parent theme (and its parent's parent theme, and so on). Data granularity One of the things that makes Drupal theming so powerful is its granularity. Each piece of content is handled separately as it's passed through the theming system. Each bit of data is themed individually, then combined into ever-larger chunks. At each step in the aggregation process, it's themed again. The following illustration will make this clearer: As you can see in the preceding illustration, for a typical blog post, each comment is pulled from the database and sent through the theme system to get HTML markup added to it. Then all the comments are aggregated together into a "comment wrapper" where additional markup and, usually, a "new comment" form is added. Then the single group of comments is passed to the node theming where it is combined with other pieces of the blog post's content. This process of theming bits of content, aggregation, and theming again is repeated until we've built the entire HTML page ready to be sent to a web browser. There are two advantages to this granular system. First, since each module is responsible for theming its own data, it can either create a very specialized theme hook for its data or it can re-use an existing theme hook. Re-using a theme hook ensures a consistent set of markup for similar data structures while still allowing customized CSS classes (Most theme hooks allow custom classes to be passed as parameters.) For example, the list of links after a node (read more, add new comment, and so on) re-uses the links theme hook, and the links after each comment use the same links theme hook. The second advantage is for the theme developer. Having a fine-grained theming system means that a theme, if it chooses to, can literally rewrite all of the markup for its own design purposes. As module developers we need to be keenly aware of the themer's desire to have granular theming overrides.   Theme engines Some themes require alternate theme engines. Theme engines can provide alternate template syntax, naming standards, and helper functions. Several theme engines are available for download at http://drupal.org/project/theme+engines. However, we won't be discussing any theme engines except for Drupal's default theme engine, PHPTemplate. The PHPTemplate theme engine has been the default theme since Drupal 4.7, has been continuously improved with each version, and has proven its worth again and again. Over 99% of themes available for download on drupal.org use the default PHPTemplate theme engine. Two ways to theme So now that we have a good understanding of higher level concepts, let's get down to the nitty-gritty of theme implementations. There are actually two different ways to implement a theme hook: Theme functions: pass data to a PHP function to wrap it in markup Templates: pass data to a template which is a PHP file mixed with markup and PHP print statements Let's look at each of these in turn. Theme functions For a module developer, the easiest type of implementation to understand is a theme function. Theme functions just need to follow a few simple rules in order for them to work properly. First, the name of the theme function follows the pattern: theme_[theme hook name] Since the theme hook name is used directly in the theme function's name, theme hook names have the same constraints on naming as regular PHP function names; the only valid characters in theme hook names are alphanumeric characters and underscores. So if a module has created an example_format theme hook, it would implement it with theme function named theme_example_format(). Second, the theme function will only have a single parameter, as follows: function theme_THEME_HOOK_NAME($variables) {…} The theme function variables are an associative array containing the pieces of data we wish to markup and any options we want to pass to the function. It may seem extremely odd not to use multiple parameters and PHP's ability to specify default values for each parameter. In fact, previous versions of Drupal did use multiple parameters. We'll see why Drupal now only uses one parameter in just a moment when we talk about preprocess functions. For an example of a $variables array, let's look at how the DocBlock of the theme_item_list() function defnes it: Items: An array of items to be displayed in the list. If an item is a string, then it is used as is. If an item is an array, then the data element of the array is used as the contents of the list item. If an item is an array with a "children" element, those children are displayed in a nested list. All other elements are treated as attributes of the list item element. Title: The title of the list. Type: The type of list to return (e.g. ul,ol). Attributes: The attributes applied to the list element. The items and title keys hold the actual data, and the type and attributes keys are options that specify how to build the item list. Third, the theme function should return a string that contains the rendered representation of the data. This is usually a string of HTML, but some theme hooks return other types of themed markup. For example, theme_syslog_format returns a simple string with pipe-separated data values for use in a *NIX syslog error log. That's it! As you can see, theme functions have very simple requirements and in every other way are standard PHP functions. The major difference between most functions and theme functions is that you should never call theme functions directly. It may be tempting to take your data and call theme_item_list($vars) directly, but you should instead call theme("item_list", $vars). This method of calling theme functions indirectly ensures that themes are able to override any module's default theme function (or template). It also allows the theme() function to work additional magic, including allowing other modules to alter the theme function's variables before they are used. Preprocess functions Now we're starting to see the real flexibility of the theme system. Preprocess functions allow one module to alter the variables used by another module when it calls a theme hook. So if some code passes data to theme() for a particular theme hook, preprocess functions will be called to alter the data before the actual theme hook implementation is called. The following steps are carried out: Code calls theme('hook_name', $variables). theme() calls preprocess functions for hook_name. Preprocess functions modify variables. theme() calls actual implementation for hook_name with modifed variables. All preprocess functions take the form of: [module]_preprocess_[theme hook name](&$variables) So if the foo module wants to alter the variables for the item_list theme hook, it could define the function as follows: function foo_preprocess_item_list(&$variables) { // Add a class to the list wrapper. $variables['attributes']['class'][] = 'foo-list'; } Notice that the $variables parameter is defned with an ampersand in front of it. That's PHP notation to pass the parameter by reference. Instead of getting a copy of the variables, the foo_preprocess_item_list() function will get access to the actual $variables which is later passed to the theme function implementation. So any modifications that the preprocess function makes to the $variables parameter will be preserved when those variables are passed to the theme function. That's the reason our example foo_preprocess_item_list() function doesn't return anything; its work is done directly on the original $variables. This is extremely handy for module developers as it allows all sorts of integration with other modules. Since the variables parameter is a mix of data and options, modules can alter both the raw data and change the way data will be rendered. This can be as simple as one module needing a special class for use in its JavaScript code and adding that class to another module's themed content by appending to the $variables['attributes']['class'] array, or can be more complex interactions like the i18n module translating the language used in blocks. Imagine we've built a retro module that integrates GeoCities and we want to replace all links to a user's profle page with a link to the user's GeoCities homepage. We can do that relatively easily with a preprocess function. First let's look at the following theme_username function's documentation: /** * Format a username. * * @param $variables * An associative array containing: * - account: The user object to format. * - name: The user's name, sanitized. * - extra: Additional text to append to the user's name, sanitized. * - link_path: The path or URL of the user's profile page, home * page, or other desired page to link to for more information * about the user. * - link_options: An array of options to pass to the l() function's * $options parameter if linking the user's name to the user's * page. * - attributes_array: An array of attributes to pass to the * drupal_attributes() function if not linking to the user's page. */ Quite conveniently, theme_username() has a handy $link_path variable that we want to alter to achieve our old-school giggles. Assuming that we've used some other business logic with the user module's hooks to load our GeoCities URL into the user's account (the "hard" part), replacing the link to the user's profle page can be accomplished with the following simple preprocess function: /** * Implements awesomeness with hook_preprocess_username(). */ function retro_preprocess_username(&$variables) { $variables['link_path'] = $variables['account']->geocities_url; } That's it! We don't have to override the user module's theme implementation; we just modify its parameters. Theme overrides While module developers usually don't have to worry about whether a theme overrides a particular theme function or not, it's still important to understand how this mechanism works. Drupal theme is normally composed of CSS, images, JavaScripts, template files (discussed shortly), a .info file, and a template.php file. The template.php file is analogous to a module's .module file. It contains all of the PHP functions for the theme and is automatically loaded when the theme is initialized. If a theme wants to override a particular theme function, it needs to copy the theme function from its original location and paste it into its template.php file. Then it needs to change the function's prefix from theme to its own name and finally, it needs to start making the desired changes to the function. For example, if the Bartik theme wants to override the theme_menu_local_tasks() function in order to add some markup around the page's tabs, it would copy the entire function from includes/menu.inc, paste it into Bartik's template.php, and rename it to bartik_menu_local_tasks(). Fortunately, when a theme overrides a default theme function, a module's preprocess functions continue to work as normal. Themes also have the ability to create preprocess functions. If the Bartik theme decides to format a user's name in "last name, frst name" format, it can implement a bartik_preprocess_username() function. Fortunately, a theme's preprocess functions do not override a module's preprocess functions. All preprocess functions are run; frst any module's preprocess functions and then the theme's preprocess function. Template files While theme functions might be the easiest for module developers to understand, template files are the easiest for themes to grasp. When a theme hook is implemented with template files, they are used instead of theme functions. However, from a module developer's standpoint, there is actually a remarkable amount of similarity between template files and theme functions. First, let's take a closer look at template files. Templates are files primarily containing HTML but with some PHP statements mixed in using the template's variables. Instead of declaring a theme_hook_name() function, a module would instead create a hook-name.tpl.php file. The following are the contents of a typical template file, typical-hook.tpl.php: <div class="<?php print $classes; ?>"<?php print $attributes; ?>> <?php if ($title): ?> <h2<?php print $title_attributes; ?>> <?php print $title; ?> </h2> <?php endif;?> <div class="submitted"> <?php print t('By !author @time ago', array( '@time' => $time, '!author' => $author, )); ?> </div> <div class="content"<?php print $content_attributes; ?>> <?php // We hide the links now so that we can render them later. hide($content['links']); print render($content); ?> </div> <?php print render($content['links']); ?> </div> The preceding example shows the full gamut of the things that you are likely see in a template file. They are as follows: Printing a variable containing a string? Printing a translatable string using t() Conditional if/else/endif statement Delaying rendering on part of a render element with hide() Printing a render element All of the PHP in a template should be limited to printing out variables. This limited amount of PHP makes it much easier for non-programmers to learn how to use template fles compared to theme functions. However, for module developers, the template implementation is still very similar to the theme function implementation; the handful of differences are relatively minor. As with theme function implementations, our module would still need to invoke the theme hook using theme(). $variables = array('typical' => $typical_object); $output = theme('typical_hook', $variables); The theme() function would discover that the typical_hook theme hook was implemented as a template and render the corresponding typical-hook.tpl.php file. The only valid characters in theme hook names are alphanumeric characters and underscores. This is true of all theme hooks, regardless of whether they are implemented as a theme function or as a template file. However, when theme() looks for template implementations, it will automatically convert any underscores in the theme hook name into hyphens while searching for the template file. For example, calling theme('user_picture', $variables) will result in the template file named user-picture.tpl.php being rendered. Also, just like theme functions, other modules can modify the variables using preprocess functions. In template fles the focus is on printing out variables in various places in the markup. So for template fles, the preprocess function takes on a more important role. The only difference between a theme function's preprocess functions and a template file's are the number and type of preprocess functions.
Read more
  • 0
  • 0
  • 3073