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

How-To Tutorials - Web Development

1802 Articles
article-image-uploading-videos-and-sound-files-your-posts-using-apache-roller-40
Packt
30 Dec 2009
6 min read
Save for later

Uploading Videos and Sound Files on Your Posts Using Apache Roller 4.0

Packt
30 Dec 2009
6 min read
Using videos in your posts It's time to learn how to insert video files in your posts. You can just insert one as an HTML link, but who does that anymore? It's a good way to drive your prospective readers away! In today's world, you need to offer your spectators the easiest, quickest, and most attractive way to see what you have to offer. My job is to show you how to do that with your Roller weblog, so let's get to it! Time for action – uploading and inserting videos on your posts In this exercise, I'll show you how to upload a video file to your blog server and then insert it into a post using Apache Roller: Open your web browser and log into Roller. The New Entry page will appear. Click on the File Uploads link from the Create & Edit tab. Scroll down the File Uploads page until you locate the Manage Uploaded Files section. Type video in the New Directory field and click on the Create button, as shown in the following screenshot:  Roller will show the following success message: Scroll down the page again until you locate the video folder in the Manage Uploaded Files section, and click on it: Roller will take you to the same File Uploads page, but this time you'll be inside the video directory. Now click on the first Browse... button of the Upload files for use in weblog main section. On the File Upload dialog, go to the folder where you downloaded the support files for this article, and double-click on the FirstFrame.png image to select it. The name of this file will show up on the first textbox of the File Uploads page. Now click on the second Browse... button and double-click on the showvbox.mp4 file, so that its name appears in the second textbox of the File Uploads page. Repeat the process with the third Browse... button and the showvbox_controller.swf file. Your File Uploads page must look like the following screenshot: Click on the Upload button to upload the three files to the video directory in your blog server. Roller will return the following success page: Don't forget to write down the three URLs from the previous Roller message; you'll need them when inserting the video into an entry (post). Click on the New Entry link from the Create & Edit tab to go to the New Entry page and create a new post for your blog. Type Ubuntu Linux Virtual Machine Inside a Windows XP PC in the Title field, select Open Source in the Category field, type virtualbox windows xp linux ubuntu in the Tags field. In the Content field, and type Here's a sample video of my Ubuntu Linux Virtual Machine, running inside a Windows XP PC with VirtualBox: as shown in the following screenshot:   Click on the Toggle HTML Source button from the HTML editor and write the following code below the text you typed in step 8 (the text in bold must correspond to the URLs from step 7's screenshot): <object height="498" width="640" id="csSWF" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/ cabs/flash/swflash.cab#version=9,0,115,0"><param name="src" value="http://localhost/roller/main/ resource/video/showvbox_controller.swf" /><param name="bgcolor" value="#1a1a1a" /><param name="quality" value="best" /><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="true" /><param name="scale" value="showall" /><param name="flashVars" value="autostart=false" /><embed height="498" width="640" name="csSWF" src="http://localhost/roller/main/resource/ video/showvbox_controller.swf" bgcolor="#1a1a1a" quality="best" allowscriptaccess="always" allowfullscreen="true" scale="showall" flashvars="autostart=false&amp; thumb=http://localhost/roller/main/resource/ video/FirstFrame.png&amp; thumbscale=45&amp;color=0x000000,0x000000" pluginspage="http://www.macromedia.com/ shockwave/download/ index.cgi?P1_Prod_Version=ShockwaveFlash"/></object> Click on the Save as Draft button, to save a draft of your post. Then scroll down the page and click on the Full Preview button, to see how your post will look in your blog before publishing it. The preview will open in a new tab in your web browser:       Click on the play button and the video will begin to playback. When finished, close the preview tab and click on the Post to Weblog button to publish your new post. You can logout from Roller now. What just happened? The previous exercise showed you how to upload a video to your blog server and insert it in a post. As you can see, videos are a little more complicated than plain images. In this case, we used the following files: FirstFrame.png: This is the thumbnail image that shows up before the video begins to playback showvbox.mp4: The video file showvbox_controller.swf: The controller that plays back theshowvbox.mp4 file      The video was produced with Camtasia Studio, an excellent screen recording software application from TechSmith (http://www.techsmith.com). If you want to practice with your own videos, you can download a 30-day free trial version of Camtasia Studio from the following URL: http://www.techsmith.com/download/camtasiatrial.asp. What would happen if you wanted to embed a video from your camera or cell phone? Well, you can embed it directly in your blog, but the best thing to do is use a software application such as Camtasia Studio to create the .swf controller and the HTML code to embed into your post automatically. Then you just need to change the .swf controller and thumbnail URLs, as you did in step 9 of the previous exercise. You can use the same embed code to insert a different video in your blog; just be sure to change the URL in bold text. You could also upload your video to YouTube instead of uploading it into Roller, as we'll see later in this article.
Read more
  • 0
  • 0
  • 5004

article-image-tips-and-tricks-ibm-filenet-p8-content-manager
Packt
24 Feb 2011
11 min read
Save for later

Tips and Tricks on IBM FileNet P8 Content Manager

Packt
24 Feb 2011
11 min read
Getting Started with IBM FileNet P8 Content Manager Install, customize, and administer the powerful FileNet Enterprise Content Management platform Quickly get up to speed on all significant features and the major components of IBM FileNet P8 Content Manager Provides technical details that are valuable both for beginners and experienced Content Management professionals alike, without repeating product reference documentation Gives a big picture description of Enterprise Content Management and related IT areas to set the context for Content Manager Written by an IBM employee, Bill Carpenter, who has extensive experience in Content Manager product development, this book gives practical tips and notes with a step-by-step approach to design real Enterprise Content Management solutions to solve your business needs   Installation care If you are using a virtual server image with snapshot capability, it’s a good idea to use snapshots. In fact, we recommend that after each of the major installation steps. If something goes wrong in a later step, you can recover back to the snapshot point to save yourself the trouble of starting over. WAS Bootstrap Hostname In a development environment, the domain name might not resolve in your DNS. In that case, enter the IP address for that server instead. Populating Tivoli Directory Server (TDS) We could use the TDS Realms interface to construct our users and groups. If you use TDS in your enterprise, that’s a good way to go. It offers several user interface niceties for directory administration, and it also offers partial referential integrity for the entries. Directory concepts and notation Directory concepts and notation can seem pretty odd. Most people don’t encounter them every day. There is a lot of material available on the web to explain both the concepts and the notation. Here is one example that is clearly written and oriented toward directory novices: http://www.skills-1st.co.uk/papers/ldapschema-design-feb-2005/index.html. Close up all of the nodes before you exit FEM FEM remembers the state of the tree view from session to session. When you start FEM the next time, it will try to open the nodes you had open when you exited. That will often mean something of a delay as it reads extensive data for each open Object Store node. You might find it a useful habit to close up all of the nodes before you exit FEM. Using topology levels A set of configuration data, if used, is used as the complete configuration. That is, the configuration objects at different topology levels are not blended to create an "effective configuration". Trace logging Although similar technologies are used to provide trace logging in the CE server and the client APIs, the configuration mechanisms are completely separate. The panels in FEM control only tracing within the CE server and do not apply to any client tracing. If you find that performance still drags or that the trace log file continues to grow even after you have disabled trace logging in the Domain configuration, it could be that trace logging is still configured at a more specific level. That's very easy to overlook, especially in more complex deployments or where CM administration duties are shared. Collaborative checkout Even with a collaborative checkout, the subsequent checkin is still subject to access checks, so you can still have fine-grained control over that. In fact, because you can use fine-grained security to limit who can do a checkin, you might as well make the Object Store default be Collaborative unless you have some specific use case that demands Exclusive. Cancel the creation of the class Although the final step in the Create a Class Wizard will still let you cancel the creation of the class, any property templates and choice lists you created along the way will already have been created in the Object Store. If you wish to completely undo your work, you will have to delete them manually. FEM query interface A historical quirk of the FEM query interface is that the SELECT list must begin with the This property. That is not a general requirement of CE SQL. Running the CSE installer If you are running the CSE installer and eventually the CSE itself on the same machine as the CE, you might be tempted to use localhost as the CSE server host. From the CE point of view, that would be technically correct. However, exploiting little tricks like that is a bad habit to get into. It certainly won't work in any environment where you install the CSE separately from the CE or have multiple CSE servers installed. We suggest you use a proper host name. Be sure to get the server name correct since the installer and the Verity software will sprinkle it liberally throughout several configuration files. If it is not correct by default, which is one of the hazards of using dynamic IP addresses, correct it now. CBR Locale field uni stands for Unicode and is generally the best choice for mixed languages support. If you think you don't need mixed-languages support, there's a pretty good chance you are mistaken, even if all of your users have the same locale settings in their environments. In any case, if you are tempted to use a different CBR locale, you should first read the K2 locale customization guide, since it's a reasonably complicated topic. Process Service does not start If the Process Service does not start, check to make sure that the Windows service named Process Engine Services Manager is started. If not, start it manually and make sure it is marked it for automatic startup. Configure two WAS profiles When trying to duplicate configuration aspects of one WAS profile into another WAS profile, we could theoretically have the WAS consoles open simultaneously in separate browser windows, which would facilitate side-by-side comparisons. In practice, this is likely to confuse the browser cookies holding the session information and drive you slightly crazy. If you have two different browsers installed, for example Firefox and Internet Explorer, you can open one WAS console in each. Disk space used by XT Disk space used by XT may exceed your expectations. We recommend having at least 2 gigabytes of disk space available when doing an XT installation. A lot of that can be recovered after XT is deployed into the application server. Object deletion Deleted objects are really, permanently deleted by the CE server. There is no undo or recycle bin or similar mechanism unless an application implements one. Notional locking & Cooperative locking Don't confuse the notional locking that comes via checkout with the unrelated feature of cooperative locking. Cooperative locking is an explicit mechanism for applications to mark a Document, Folder, or Custom Object as being locked. As the name implies, this only matters for applications which check for and honor cooperative locks. The CE will not prevent any update operation—other than locking operations themselves—just because there is a cooperative lock on the object. Synchronous or asynchronous subscription As a terminology convenience, events or event handlers are sometimes referred to as being synchronous or asynchronous. This is not technically correct because the designation is always made on the subscription object. An event can have either kind of subscription, and an event handler can be invoked both ways. Synchronous subscription event handlers The CE does not always throw an exception if the event handler for a synchronous subscription updates the triggering object. This has allowed many developers to ignore the rule that such updates are not allowed, assuming it is merely a best practice. Nonetheless, it has always been the rule that synchronous subscription event handlers are not allowed to do that. Even if it works in a particular instance, it may fail at random times that escape detection in testing. Don't fall into this trap! AddOn in the P8 Domain If you don't happen to be a perfect person, you might have to iterate a few times during the creation and testing of your AddOn until you get things exactly the way you want them. For the sake of mere mechanical efficiency, we usually do this kind of work using a virtual machine image that includes a snapshot capability. We make a snapshot just before creating the AddOn in the P8 Domain. Then we do the testing. If we need to iterate, it's pretty fast to roll back to the snapshot point. "anonymous access" complaints from the CE When an application server sees a Subject that it doesn't trust, since there is no trust relationship with the sending application server, it will often simply discard the Subject or strip vital information out of it. Hence the complaints from the CE that you are trying to do "anonymous access" often mean that there is something wrong with your trust relationship setup. Unknown ACE An "unknown" Access Control Entry (ACE) in an Access Control List (ACL) comes about because ACEs sometimes get orphaned. The user or group mentioned in the ACE gets deleted from the directory, but the ACE still exists in the CE repository. These ACEs will never match any calling user and so will never figure into any access control calculation. Application developers have to be aware of this kind of ACE when programmatically displaying or modifying the ACL. The unknown ACEs should be silently filtered out and not displayed to end users. (FEM displays unknown ACEs, but it is an administrator tool.) If updates are made to the ACL, the unknown ACEs definitely must be filtered out. Otherwise, the CE will throw an exception because it cannot resolve the user or group in the directory. Virtualization Several years ago, CM product documentation said that virtual machine technology was supported, but that you might have to reproduce any problems directly on physical hardware if you needed support. That's no longer the case, and virtualization is supported as a first-class citizen. For your own purposes, you will probably want to evaluate whether there are any significant performance costs to the virtualization technology you have chosen. The safest way to evaluate that is under similar configuration and load as that of your intended production environment. File Storage Area Folders used internally within a File Storage Area for content have no relationship to the folders used for filing objects within an Object Store. On reflection, this should be obvious, since you can store content for unfiled documents. Whereas the folders in an Object Store are an organizing technique for objects, the folders in a File Storage Area are used to avoid overwhelming the native filesystem with too many files in a single directory (which can impact performance). Sticky sessions All API interactions with the CE are stateless. In other words, except for load balancing, it doesn't matter which CE server is used for any particular API request. Requests are treated independently, and the CE does not maintain any session state on behalf of the application. On the other hand, some CM web applications do need to be configured for sticky sessions. A sticky session means that incoming requests (usually from a web browser) must return to the same copy of the application for subsequent requests. Disaster Recovery (DR) There is technology available for near real time replication for DR. It can be tempting to think of your DR site as your data backup, or at least eliminating the need for traditional backups. It seems too good to be true since all of your updates are almost instantaneously copied to another datacenter. The trap is that the replication can't tell desirable updates from mistakes. If you have to recover some of your data because of an operational mistake (for example, if you drop the tables in an Object Store database), the DR copy will reflect the same mistake. You should still do traditional backups even if you have a replicated DR site. Further resources on this subject: IBM FileNet P8 Content Manager: Administrative Tools and Tasks [Article] IBM FileNet P8 Content Manager: Exploring Object Store-level Items [Article] IBM FileNet P8 Content Manager: End User Tools and Tasks [Article]
Read more
  • 0
  • 0
  • 4991

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
  • 4990

article-image-recursive-directives
Packt
22 Dec 2014
13 min read
Save for later

Recursive directives

Packt
22 Dec 2014
13 min read
In this article by Matt Frisbie, the author of AngularJS Web Application Development Cookbook, we will see recursive directives. The power of directives can also be effectively applied when consuming data in a more unwieldy format. Consider the case in which you have a JavaScript object that exists in some sort of recursive tree structure. The view that you will generate for this object will also reflect its recursive nature and will have nested HTML elements that match the underlying data structure. (For more resources related to this topic, see here.) Recursive directives In this article by Matt Frisbie, the author of AngularJS Web Application Development Cookbook, we will see recursive directives. The power of directives can also be effectively applied when consuming data in a more unwieldy format. Consider the case in which you have a JavaScript object that exists in some sort of recursive tree structure. The view that you will generate for this object will also reflect its recursive nature and will have nested HTML elements that match the underlying data structure. Getting ready Suppose you had a recursive data object in your controller as follows: (app.js)   angular.module('myApp', []) .controller('MainCtrl', function($scope) { $scope.data = {    text: 'Primates',    items: [      {        text: 'Anthropoidea',        items: [          {            text: 'New World Anthropoids'          },          {            text: 'Old World Anthropoids',            items: [              {                text: 'Apes',                items: [                 {                    text: 'Lesser Apes'                  },                  {                    text: 'Greater Apes'                  }                ]              },              {                text: 'Monkeys'              }            ]          }        ]      },      {        text: 'Prosimii'      }    ] }; }); How to do it… As you might imagine, iteratively constructing a view or only partially using directives to accomplish this will become extremely messy very quickly. Instead, it would be better if you were able to create a directive that would seamlessly break apart the data recursively, and define and render the sub-HTML fragments cleanly. By cleverly using directives and the $compile service, this exact directive functionality is possible. The ideal directive in this scenario will be able to handle the recursive object without any additional parameters or outside assistance in parsing and rendering the object. So, in the main view, your directive will look something like this: <recursive value="nestedObject"></recursive> The directive is accepting an isolate scope = binding to the parent scope object, which will remain structurally identical as the directive descends through the recursive object. The $compile service You will need to inject the $compile service in order to make the recursive directive work. The reason for this is that each level of the directive can instantiate directives inside it and convert them from an uncompiled template to real DOM material. The angular.element() method The angular.element() method can be thought of as the jQuery $() equivalent. It accepts a string template or DOM fragment and returns a jqLite object that can be modified, inserted, or compiled for your purposes. If the jQuery library is present when the application is initialized, AngularJS will use that instead of jqLite. If you use the AngularJS template cache, retrieved templates will already exist as if you had called the angular.element() method on the template text. The $templateCache Inside a directive, it's possible to create a template using angular.element() and a string of HTML similar to an underscore.js template. However, it's completely unnecessary and quite unwieldy to use compared to AngularJS templates. When you declare a template and register it with AngularJS, it can be accessed through the injected $templateCache, which acts as a key-value store for your templates. The recursive template is as follows: <script type="text/ng-template" id="recursive.html"> <span>{{ val.text }}</span> <button ng-click="delSubtree()">delete</button> <ul ng-if="isParent" style="margin-left:30px">    <li ng-repeat="item in val.items">      <tree val="item" parent-data="val.items"></tree>    </li> </ul> </script> The <span> and <button> elements are present at each instance of a node, and they present the data at that node as well as an interface to the click event (which we will define in a moment) that will destroy it and all its children. Following these, the conditional <ul> element renders only if the isParent flag is set in the scope, and it repeats through the items array, recursing the child data and creating new instances of the directive. Here, you can see the full template definition of the directive: <tree val="item" parent-data="val.items"></tree> Not only does the directive take a val attribute for the local node data, but you can also see its parent-data attribute, which is the point of scope indirection that allows the tree structure. To make more sense of this, examine the following directive code: (app.js)   .directive('tree', function($compile, $templateCache) { return {    restrict: 'E',    scope: {      val: '=',      parentData: '='    },    link: function(scope, el, attrs) {      scope.isParent = angular.isArray(scope.val.items)      scope.delSubtree = function() {        if(scope.parentData) {            scope.parentData.splice(            scope.parentData.indexOf(scope.val),            1          );        }        scope.val={};      }        el.replaceWith(        $compile(          $templateCache.get('recursive.html')        )(scope)      );      } }; }); With all of this, if you provide the recursive directive with the data object provided at the beginning of this article, it will result in the following (presented here without the auto-added AngularJS comments and directives): (index.html – uncompiled)   <div ng-app="myApp"> <div ng-controller="MainCtrl">    <tree val="data"></tree> </div>    <script type="text/ng-template" id="recursive.html">    <span>{{ val.text }}</span>    <button ng-click="deleteSubtree()">delete</button>    <ul ng-if="isParent" style="margin-left:30px">      <li ng-repeat="item in val.items">        <tree val="item" parent-data="val.items"></tree>      </li>    </ul> </script> </div> The recursive nature of the directive templates enables nesting, and when compiled using the recursive data object located in the wrapping controller, it will compile into the following HTML: (index.html - compiled)   <div ng-controller="MainController"> <span>Primates</span> <button ng-click="delSubtree()">delete</button> <ul ng-if="isParent" style="margin-left:30px">    <li ng-repeat="item in val.items">      <span>Anthropoidea</span>      <button ng-click="delSubtree()">delete</button>      <ul ng-if="isParent" style="margin-left:30px">        <li ng-repeat="item in val.items">          <span>New World Anthropoids</span>          <button ng-click="delSubtree()">delete</button>        </li>        <li ng-repeat="item in val.items">          <span>Old World Anthropoids</span>          <button ng-click="delSubtree()">delete</button>          <ul ng-if="isParent" style="margin-left:30px">            <li ng-repeat="item in val.items">              <span>Apes</span>              <button ng-click="delSubtree()">delete</button>              <ul ng-if="isParent" style="margin-left:30px">                <li ng-repeat="item in val.items">                  <span>Lesser Apes</span>                  <button ng-click="delSubtree()">delete</button>                </li>                <li ng-repeat="item in val.items">                  <span>Greater Apes</span>                  <button ng-click="delSubtree()">delete</button>                </li>              </ul>            </li>            <li ng-repeat="item in val.items">              <span>Monkeys</span>              <button ng-click="delSubtree()">delete</button>            </li>          </ul>         </li>      </ul>    </li>    <li ng-repeat="item in val.items">      <span>Prosimii</span>      <button ng-click="delSubtree()">delete</button>    </li> </ul> </div> JSFiddle: http://jsfiddle.net/msfrisbie/ka46yx4u/ How it works… The definition of the isolate scope through the nested directives described in the previous section allows all or part of the recursive objects to be bound through parentData to the appropriate directive instance, all the while maintaining the nested connectedness afforded by the directive hierarchy. When a parent node is deleted, the lower directives are still bound to the data object and the removal propagates through cleanly. The meatiest and most important part of this directive is, of course, the link function. Here, the link function determines whether the node has any children (which simply checks for the existence of an array in the local data node) and declares the deleting method, which simply removes the relevant portion from the recursive object and cleans up the local node. Up until this point, there haven't been any recursive calls, and there shouldn't need to be. If your directive is constructed correctly, AngularJS data binding and inherent template management will take care of the template cleanup for you. This, of course, leads into the final line of the link function, which is broken up here for readability: el.replaceWith( $compile(    $templateCache.get('recursive.html') )(scope) ); Recall that in a link function, the second parameter is the jqLite-wrapped DOM object that the directive is linking—here, the <tree> element. This exposes to you a subset of jQuery object methods, including replaceWith(), which you will use here. The top-level instance of the directive will be replaced by the recursively-defined template, and this will carry down through the tree. At this point, you should have an idea of how the recursive structure is coming together. The element parameter needs to be replaced with a recursively-compiled template, and for this, you will employ the $compile service. This service accepts a template as a parameter and returns a function that you will invoke with the current scope inside the directive's link function. The template is retrieved from $templateCache by the recursive.html key, and then it's compiled. When the compiler reaches the nested <tree> directive, the recursive directive is realized all the way down through the data in the recursive object. Summary This article demonstrates the power of constructing a directive to convert a complex data object into a large DOM object. Relevant portions can be broken into individual templates, handled with distributed directive logic, and combined together in an elegant fashion to maximize modularity and reusability. Resources for Article:  Further resources on this subject: Working with Live Data and AngularJS [article] Angular Zen [article] AngularJS Project [article]
Read more
  • 0
  • 0
  • 4959

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

Views, URLs, and Generic Views in Django 1.0

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

article-image-agile-yii-11-and-php5-trackstar-application
Packt
05 Aug 2010
13 min read
Save for later

Agile with Yii 1.1 and PHP5: The TrackStar Application

Packt
05 Aug 2010
13 min read
(For more resources on Agile, see here.) Introducing TrackStar TrackStar is a Software Development Life Cycle (SDLC) issue management application. Its main goal is to help keep track of all the many issues that arise throughout the course of building software applications. It is a user-based application that allows the creation of user accounts and grants access to the application features, once a user has been authenticated and authorized. It allows a user to add and manage projects. Projects can have users associated with them (typically the team members working on the project) as well as issues. The project issues will be things such as development tasks and application bugs. The issues can be assigned to members of the project and will have a status such as not yet started, started, and finished. This way, the tracking tool can give an accurate depiction of projects with regard to what has been accomplished, what is currently in progress, and what is yet to be started. Creating user stories Simple user stories are a great way to identify the required features of your application. User stories, in their simplest form, state what a user can do with a piece of software. They should start simple, and grow in complexity as you dive into more and more of the details around each feature. Our goal here is to begin with just enough complexity to allow us to get started. If needed, we'll add more detail and complexity later. We briefly touched on the three main entities that play a large role in this application: users, projects, and issues. These are our primary domain objects, and are extremely important items in this application. So, let's start with them. Users TrackStar is a user-based web application. There will be two high-level user types: Anonymous Authenticated An anonymous user is any user of the application that has not been authenticated through the login process. Anonymous users will only have access to register for a new account or to log in. All other functionality will be restricted to authenticated users. An authenticated user is any user that has provided valid authentication credentials through the login process. In other words, authenticated users are logged-in users. They will have access to the main features of the application such as creating and managing projects, and project issues. Projects Managing the project is the primary purpose of the TrackStar application. A project represents a general, high-level goal to be achieved by one or more users of the application. The project is typically broken down into more granular tasks (or issues) that represent the smaller steps that need to be taken to achieve the overall goal. As an example, let's take what we are going to be doing throughout this book, that is, building a project and issue tracking management application. Unfortunately, we can't use our yet-to-be-created application as a tool to help us track its own development. However, if we were using a similar tool to help track what we are building, we might create a project called Build The TrackStar Project/Issue Management Tool. This project would be broken down into more granular project issues such as 'Create the login screen' or 'Design database schema for issues', and so on. Authenticated users can create new projects. The creator of the project within an account has a special role within that project, called the project owner. Project owners have the ability to edit and delete these projects as well as add new members to the project. Other users associated with the project—besides the project owner—are referred to simply as project members. They have the ability to add new issues, as well as edit existing ones. Issues Project issues can be classified into one of the following three categories: Features: Items that represent real features to be added to the application. For example, 'Implement the login functionality' Tasks: Items that represent work that needs to be done, but is not an actual feature of the software. For example, 'Set up the build and integration server' Bugs: Items that represent application behaviors that are not working as expected. For example, 'The account registration form does not validate the format of input e-mail addresses' Issues can have one of the following three statuses: Not yet started Started Finished Project members can add new issues to a project, as well as edit and delete them. They can assign issues to themselves or other project members. For now, this is enough information on these three main entities. We could go into a lot more detail about what exactly account registration entails' and how exactly one adds a new task to a project', but we have outlined enough specifications to begin on these basic features. We'll nail down the more granular details as we proceed with the implementation. However, before we start, we should jot down some basic navigation and application workflow. This will help everyone to better understand the general layout and flow of the application we are building. Navigation and page flow It is always good to outline the main pages within an application, and how they fit together. This will help us quickly identify some needed Yii controllers, actions and views as well as help to set everyone's expectations as to what we'll be building towards at the onset of our development. The following figure shows the basic idea of the application flow from logging in, through the project details listing: When users first come to the application, they must log in to authenticate themselves before accessing any functionality. Once successfully logged-in, they will be presented with a list of his current projects along with the option to create a new project. Choosing a specific project will take them to the project details page. The project details page will present a list of the issues by type. There will also be the option to add a new issue as well as edit any of the listed issues. This is all pretty basic functionality, but the figure gives us a little more information on how the application is stitched together and allows us to better identify our needed models, views, and controllers. It also allows something visual to be shared with others so that everyone involved has the same 'picture' of what we are working towards. In my experience, almost everyone prefers pictures over written specifications when first thinking through a new application. Defining a data scheme We still need to think a little more about the data we will be working with as we begin to build toward these specifications. If we pick out all the main nouns from our system, we may end up with a pretty good list of domain objects and, by extension of using Active Record, the data we want to model. Our previously outlined user stories seem to dictate the following: A User A Project An Issue Based on this and the other details provided in the user stories and application workflow diagram, a first attempt at the needed data is shown in the following figure. This is a basic object model that outlines our primary data entities, their respective attributes, and some of the relationships between them. The 1..* on either side of the line between the Project and User objects represents a many-to-many relationship between them. A user can be associated with one or more projects, and a project has one or more users. Similarly we have represented the fact that a project can have zero or more issues associated with it, whereas an issue belongs to just one specific project. Also, a user can be the owner of (or requester of) many issues, but an issue has just one owner (and also just one requester). We have kept the attributes as simple as possible at this state. A User is going to need a username and a password in order to get past the login screen. The Project has only a name Issues have the most associated information based on what we currently know about them. As discussed briefly in the user stories above, they will have a type attribute to distinguish the general category (bug, feature, or task). They will also have a status attribute to indicate the progress of the issue being worked on. A user in the system will initially create the issue, this is the requester. Once a user in the system has been assigned to work on the issue, they will be the owner of the issue. We have also defined the description attribute to allow for some descriptive text of the issue to be entered. Notice that we have not explicitly talked about schemas or databases yet. The fact is, until we think through what is really needed from a data perspective, we won't know the right tool to use to house this data. Would flat files on the filesystem work just as well as a relational database? Do we need a persistent data at all?   The answers to these questions are not needed in this early planning state. It is better to focus more on the features that we want and the type of data needed to support these features. We can turn to the explicit technology implementation details after we have had a chance to discuss these ideas with other project stakeholders to ensure we are on the right track. Other project stakeholders include anyone and everyone involved in this development project. This can include the client, if building an application for someone else, as well as other development team members, product/project managers, and so on. It is always a good idea to get some feedback from "the team" to help validate the approach and any assumptions being made. However, before we dive right into building our application, we need to cover our development approach. We will be employing some specific development methodologies and principles, and it makes sense to go over these prior to getting started with coding. Defining our development methodology We will be employing an agile inspired process of iterative and incremental development as we build this application. 'Agile' is certainly a loaded term in modern software development and can have varied meanings among developers. Our process will focus on the aspects of an agile methodology that embrace transparent and open collaboration, constant feedback loops, and a strong ability to respond quickly to changing requirements. We will work incrementally in that we won't wait until every detail of the application has been specified before we start coding. Once the details of a particular feature have been finalized, we can begin work on implementing that feature, even though other features or application details are still in the design/planning stage. The process surrounding this feature implementation will follow an iterative model. We will do some initial iteration planning, engage in analysis and design, write the code to try out these ideas, test the code, and gather feedback. We then repeat this cycle of design->code->test->evaluation, until everyone is happy. Once everyone is happy, we can deploy the application with the new feature, and then start gathering the specifications on the next feature(s) to be implemented in the next iteration. Automated software testing Gathering feedback is of fundamental importance to agile development. Feedback from the users of the application and other project stakeholders, feedback from the development team members, and feedback directly from the software itself. Developing software in a manner that will allow it to tell you when something is broken can turn the fear associated with integrating and deploying applications into boredom. The method by which you empower your software with this feedback mechanism is writing unit and functional tests, and then executing them repeatedly and often. Unit and functional testing Unit tests are written to provide the developer with verification that the code is doing the right things. Functional tests are written to provide the developer, as well as other project stakeholders, that the application, as a whole, is doing things the right way. Unit tests Unit tests are tests that focus on the smallest units within a software application. In an object-oriented application, (such as a Yii web application) the smallest units are the public methods that make up the interfaces to classes. Unit tests should focus on one single class, and not require other classes or objects to run. Their purpose is to validate that a single unit of code is working as expected. Functional tests Functional tests focus on testing the end-to-end feature functionality of the application. These tests exist at a higher level than the unit tests and typically do require multiple classes or objects to run. Their purpose is to validate that a given feature of the application is working as expected. Benefits of testing There are many benefits to writing unit and functional tests. For one, they are a great way to provide documentation. Unit tests can quickly tell the exact story of why a block of code exists. Similarly, functional tests document what features are implemented within an application. If you stay diligent in writing these tests, then the documentation continues to evolve naturally as the application evolves. They are also invaluable as a feedback mechanism to constantly reassure the developer and other project stakeholders that the code and application is working as expected. You run your tests every time you make changes to the code and get immediate feedback on whether or not something you altered inadvertently changed the behavior of the system. You then address these issues immediately. This really increases the confidence that developers have in the application's behavior and translates to fewer bugs and more successful projects. This immediate feedback also helps to facilitate change and improving the design of the code base. A developer is more likely to make improvements to existing code if a suite of tests are in place to immediately provide feedback as to whether the changes made altered the application behavior. The confidence provided by a suite of unit and functional tests allows developers to write better software, release a more stable application, and ship quality products. Test-driven development Test-driven development (TDD) is a software development methodology that helps to create an environment of comfort and confidence by ensuring your test suite grows organically with your application, and is always up-to-date. It does this by stipulating that you begin your coding by first writing a test for the code you are about to write. The following steps sum up the process: Begin by writing a test that will quickly fail. Run the test to ensure it does, indeed, fail. Quickly add just enough code to the class you are testing to get the test to pass. Run the test again to ensure it does, indeed, pass. Refactor the code to remove any repetitive logic or improve any corners cut while you were just trying to get the test to pass. These steps are then repeated throughout the entire development process. Even with the best intentions, if you wait to write your tests until after the code is completed, you probably won't. Writing your tests first and injecting the test writing process directly into the coding process will ensure the best test coverage. This depth of coverage will help minimize the stress and fear that can accompany complex software applications and build confidence by constantly providing positive feedback as additions and changes are made. In order to embrace a TDD process, we need to understand how to test within a Yii application.
Read more
  • 0
  • 0
  • 4935
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
article-image-text-and-appearance-bindings-and-form-field-bindings
Packt
25 May 2015
14 min read
Save for later

Text and appearance bindings and form field bindings

Packt
25 May 2015
14 min read
In this article by Andrey Akinshin, the author of Getting Started with Knockout.js for .Net Developers, we will look at the various binding offered by Knockout.js. Knockout.js provides you with a huge number of useful HTML data bindings to control the text and its appearance. In this section, we take a brief look at the most common bindings: The text binding The html binding The css binding The style binding The attr binding The visible binding (For more resources related to this topic, see here.) The text binding The text binding is one of the most useful bindings. It allows us to bind text of an element (for example, span) to a property of the ViewModel. Let's create an example in which a person has a single firstName property. The Model will be as follows: var person = { firstName: "John" }; The ViewModel will be as follows: var PersonViewModel = function() { var self = this; self.firstName = ko.observable(person.firstName); }; The View will be as follows: The first name is <span data-bind="text: firstName"></span>. It is really a very simple example. The Model (the person object) has only the firstName property with the initial value John. In the ViewModel, we created the firstName property, which is represented by ko.observable. The View contains a span element with a single data binding; the text property of span binds to the firstName property of the ViewModel. In this example, any changes to personViewModel.firstName will entail an automatic update of text in the span element. If we run the example, we will see a single text line: The first name is John. Let's upgrade our example by adding the age property for the person. In the View, we will print young person for age less than 18 or adult person for age greater than or equal to 18 (PersonalPage-Binding-Text2.html): The Model will be as follows: var person = { firstName: "John", age: 30 }; The ViewModel will be as follows: var personViewModel = function() { var self = this; self.firstName = ko.observable(person.firstName); self.age = ko.observable(person.age); }; The View will be as follows: <span data-bind="text: firstName"></span> is <span data- bind="text: age() >= 18 ? 'adult' : 'young'"></span>   person. This example uses an expression binding in the View. The second span element binds its text property to a JavaScript expression. In this case, we will see the text John is adult person because we set age to 30 in the Model. Note that it is bad practice to write expressions such as age() >= 18 directly inside the binding value. The best way is to define the so-called computed observable property that contains a boolean expression and uses the name of the defined property instead of the expression. We will discuss this method later. The html binding In some cases, we may want to use HTML tags inside our data binding. However, if we include HTML tags in the text binding, tags will be shown in the raw form. We should use the html binding to render tags, as shown in the following example: The Model will be as follows: var person = { about: "John's favorite site is <a     href='http://www.packtpub.com'>PacktPub</a>." }; The ViewModel will be as follows: var PersonViewModel = function() { var self = this; self.about = ko.observable(person.about); }; The View will be as follows: <span data-bind="html: about"></span> Thanks to the html binding, the about message will be displayed correctly and the <a> tag will be transformed into a hyperlink. When you try to display a link with the text binding, the HTML will be encoded, so the user will see not a link but special characters. The css binding The html binding is a good way to include HTML tags in the binding value, but it is a bad practice for its styling. Instead of this, we should use the css binding for this aim. Let's consider the following example: The Model will be as follows: var person = { favoriteColor: "red" }; The ViewModel will be as follows: var PersonViewModel = function() { var self = this; self.favoriteColor = ko.observable(person.favoriteColor); }; The View will be as follows: <style type="text/css"> .redStyle {    color: red; } .greenStyle {    color: green; } </style> <div data-bind="css: { redStyle: favoriteColor() == 'red',   greenStyle: favoriteColor() == 'green' }"> John's favorite color is <span data-bind="text:   favoriteColor"></span>. </div> In the View, there are two CSS classes: redStyle and greenStyle. In the Model, we use favoriteColor to define the favorite color of our person. The expression binding for the div element applies the redStyle CSS style for red color and greenStyle for green color. It uses the favoriteColor observable property as a function to get its value. When favoriteColor is not an observable, the data binding will just be favoriteColor== 'red'. Of course, when favoriteColor changes, the DOM will not be updated because it won't be notified. The style binding In some cases, we do not have access to CSS, but we still need to change the style of the View. For example, CSS files are placed in an application theme and we may not have enough rights to modify it. The style binding helps us in such a case: The Model will be as follows: var person = { favoriteColor: "red" }; The ViewModel will be as follows: var PersonViewModel = function() { var self = this; self.favoriteColor = ko.observable(person.favoriteColor); }; The View will be as follows: <div data-bind="style: { color: favoriteColor() }"> John's favorite color is <span data-bind="text:   favoriteColor"></span>. </div> This example is analogous to the previous one, with the only difference being that we use the style binding instead of the css binding. The attr binding The attr binding is also a good way to work with DOM elements. It allows us to set the value of any attributes of elements. Let's look at the following example: The Model will be as follows: var person = { favoriteUrl: "http://www.packtpub.com" }; The ViewModel will be as follows: var PersonViewModel = function() { var self = this; self.favoriteUrl = ko.observable(person.favoriteUrl); }; The View will be as follows: John's favorite site is <a data-bind="attr: { href: favoriteUrl()   }">PacktPub</a>. The href attribute of the <a> element binds to the favoriteUrl property of the ViewModel via the attr binding. The visible binding The visible binding allows us to show or hide some elements according to the ViewModel. Let's consider an example with a div element, which is shown depending on a conditional binding: The Model will be as follows: var person = { favoriteSite: "PacktPub" }; The ViewModel will be as follows: var PersonViewModel = function() { var self = this; self.favoriteSite = ko.observable(person.favoriteSite); }; The View will be as follows: <div data-bind="visible: favoriteSite().length > 0"> John's favorite site is <span data-bind="text:   favoriteSite"></span>. </div> In this example, the div element with information about John's favorite site will be shown only if the information was defined. Form fields bindings Forms are important parts of many web applications. In this section, we will learn about a number of data bindings to work with the form fields: The value binding The click binding The submit binding The event binding The checked binding The enable binging The disable binding The options binding The selectedOptions binding The value binding Very often, forms use the input, select and textarea elements to enter text. Knockout.js allows work with such text via the value binding, as shown in the following example: The Model will be as follows: var person = { firstName: "John" }; The ViewModel will be as follows: var PersonViewModel = function() { var self = this; self.firstName = ko.observable(person.firstName); }; The View will be as follows: <form> The first name is <input type="text" data-bind="value:     firstName" />. </form> The value property of the text input element binds to the firstName property of the ViewModel. The click binding We can add some function as an event handler for the onclick event with the click binding. Let's consider the following example: The Model will be as follows: var person = { age: 30 }; The ViewModel will be as follows: var personViewModel = function() { var self = this; self.age = ko.observable(person.age); self.growOld = function() {    var previousAge = self.age();    self.age(previousAge + 1); } }; The View will be as follows: <div> John's age is <span data-bind="text: age"></span>. <button data-bind="click: growOld">Grow old</button> </div> We have the Grow old button in the View. The click property of this button binds to the growOld function of the ViewModel. This function increases the age of the person by one year. Because the age property is an observable, the text in the span element will automatically be updated to 31. The submit binding Typically, the submit event is the last operation when working with a form. Knockout.js supports the submit binding to add the corresponding event handler. Of course, you can also use the click binding for the "submit" button, but that is a different thing because there are alternative ways to submit the form. For example, a user can use the Enter key while typing into a textbox. Let's update the previous example with the submit binding: The Model will be as follows: var person = { age: 30 }; The ViewModel will be as follows: var PersonViewModel = function() { var self = this; self.age = ko.observable(person.age); self.growOld = function() {    var previousAge = self.age();    self.age(previousAge + 1); } }; The View will be as follows: <div> John's age is <span data-bind="text: age"></span>. <form data-bind="submit: growOld">    <button type="submit">Grow old</button> </form> </div> The only new thing is moving the link to the growOld function to the submit binding of the form. The event binding The event binding also helps us interact with the user. This binding allows us to add an event handler to an element, events such as keypress, mouseover, or mouseout. In the following example, we use this binding to control the visibility of a div element according to the mouse position: The Model will be as follows: var person = { }; The ViewModel will be as follows: var PersonViewModel = function() { var self = this; self.aboutEnabled = ko.observable(false); self.showAbout = function() {    self.aboutEnabled(true); }; self.hideAbout = function() {    self.aboutEnabled(false); } }; The View will be as follows: <div> <div data-bind="event: { mouseover: showAbout, mouseout:     hideAbout }">    Mouse over to view the information about John. </div> <div data-bind="visible: aboutEnabled">    John's favorite site is <a       href='http://www.packtpub.com'>PacktPub</a>. </div> </div> In this example, the Model is empty because the web page doesn't have a state outside of the runtime context. The single property aboutEnabled makes sense only to run an application. In such a case, we can omit the corresponding property in the Model and work only with the ViewModel. In particular, we will work with a single ViewModel property aboutEnabled, which defines the visibility of div. There are two event bindings: mouseover and mouseout. They link the mouse behavior to the value of aboutEnabled with the help of the showAbout and hideAbout ViewModel functions. The checked binding Many forms contain checkboxes (<input type="checkbox" />). We can work with its value with the help of the checked binding, as shown in the following example: The Model will be as follows: var person = { isMarried: false }; The ViewModel will be as follows: var personViewModel = function() { var self = this; self.isMarried = ko.observable(person.isMarried); }; The View is as follows: <form> <input type="checkbox" data-bind="checked: isMarried" /> Is married </form> The View contains the Is married checkbox. Its checked property binds to the Boolean isMarried property of the ViewModel. The enable and disable binding A good usability practice suggests setting the enable property of some elements (such as input, select, and textarea) according to a form state. Knockout.js provides us with the enable binding for this purpose. Let's consider the following example: The Model is as follows: var person = { isMarried: false, wife: "" }; The ViewModel will be as follows: var PersonViewModel = function() { var self = this; self.isMarried = ko.observable(person.isMarried); self.wife = ko.observable(person.wife); }; The View will be as follows: <form> <p>    <input type="checkbox" data-bind="checked: isMarried" />    Is married </p> <p>    Wife's name:    <input type="text" data-bind="value: wife, enable: isMarried" /> </p> </form> The View contains the checkbox from the previous example. Only in the case of a married person can we write the name of his wife. This behavior is provided by the enable binding of the text input element. The disable binding works in exactly the opposite way. It allows you to avoid negative expression bindings in some cases. The options binding If the Model contains some collections, then we need a select element to display it. The options binding allows us to link such an element to the data, as shown in the following example: The Model is as follows: var person = { children: ["Jonnie", "Jane", "Richard", "Mary"] }; The ViewModel will be as follows: var PersonViewModel = function() { var self = this; self.children = person.children; }; The View will be as follows: <form> <select multiple="multiple" data-bind="options:     children"></select> </form> In the preceding example, the Model contains the children array. The View represents this array with the help of multiple select elements. Note that, in this example, children is a non-observable array. Therefore, changes to ViewModel in this case do not affect the View. The code is shown only for demonstration of the options binding. The selectedOptions binding In addition to the options binding, we can use the selectedOptions binding to work with selected items in the select element. Let's look at the following example: The Model will be as follows: var person = { children: ["Jonnie", "Jane", "Richard", "Mary"], selectedChildren: ["Jonnie", "Mary"] }; The ViewModel will be as follows: var PersonViewModel = function() { var self = this; self.children = person.children; self.selectedChildren = person.selectedChildren }; The View will be as follows: <form> <select multiple="multiple" data-bind="options: children,     selectedOptions: selectedChildren"></select> </form> The selectedChildren property of the ViewModel defines a set of selected items in the select element. Note that, as shown in the previous example, selectedChildren is a non-observable array; the preceding code only shows the use of the selectedOptions binding. In a real-world application, most of the time, the value of the selectedChildren binding will be an observable array. Summary In this article, we have looked at examples that illustrate the use of bindings for various purposes. Resources for Article: Further resources on this subject: So, what is Ext JS? [article] Introducing a feature of IntroJs [article] Top features of KnockoutJS [article]
Read more
  • 0
  • 0
  • 4931

article-image-joomla-15-top-extensions-using-languages
Packt
28 Oct 2010
5 min read
Save for later

Joomla! 1.5 Top Extensions for Using Languages

Packt
28 Oct 2010
5 min read
  Joomla! 1.5 Top Extensions Cookbook Over 80 great recipes for taking control of Joomla! Extensions Set up and use the best extensions available for Joomla! Covers extensions for just about every use of Joomla! Packed with recipes to help you get the most of the Joomla! extensions Part of Packt's Cookbook series: Each recipe is a carefully organized sequence of instructions to complete the task as efficiently as possible        Introduction One of the greatest features of Joomla! is that you can build a multilingual website. The Joomla! interface can be displayed in many languages. You can simply download the translation pack for the required language and install that to Joomla!. If you don't have a translation pack for your desired language, you can translate it by editing language files directly or by using the translation manager component. The translation manager component allows you to visually translate your site's interface into any language, right from the Joomla! administration area. After completing the translation, you can pack the translation and share it with others, so that they can install the translation in other Joomla! sites. Besides translating the Joomla! interface, you can translate a site's contents into your desired language. The GTranslate component allows you to translate your site's content into 55 languages using Google's translation service. Adding a language to your site Joomla! can build a multilingual site. A site interface can be in multiple languages, using different locales. In this recipe, you will learn how to add an additional language to a Joomla! site. Getting ready... Joomla! translations are available in major languages. First, decide which language you want to add to your site. For example, we want to add French to a Joomla! website. A French translation for Joomla! 1.5 is available to download at the Joomla! Extensions Directory, http://extensions.joomla.org/extensions/languages/translations-for-joomla. Download this extension from http://joomlacode.org/gf/project/french/frs/, and install it from the Extensions | Install/Uninstall screen. How to do it... After installation, follow the steps as shown: From the Joomla! administration panel, click on Extensions | Language Manager. This will show the Language Manager screen, listing the installed languages for the site: Note that the default language for the site is marked with a yellow star in the Default column. To make the newly-installed language, French (Fr), the default language for your site, select the language and click on the Default button in the toolbar. Preview the site's frontend and you will find the site's interface (not content) in French. For example, the Login Form module will look like the following screenshot: For changing the language of the administration panel, in the Language Manager screen click on Administrator, select a language from the list, and set that as the default language for the administrator backend. See also... Adding a translation will only show the Joomla! interfaces in that language. The content of the site is not translated or displayed in the selected language. Also note that we still don't have a mechanism to select our desired language. All of these things can be done using the Joom!Fish extension, which is discussed in the recipe Manually Translating Your Joomla! Site's Content into Your Desired Language. Translating language files for your site Joomla!'s translations are available in most major languages. However, you may like to change the translations and have your own translation in your desired language. In that case, Joomla! provides a mechanism to translate the Joomla! interface language. In this recipe, you will learn how to translate language files for your site from the administration backend. Getting ready... Translation Manager is a popular extension that can help you translate the site's language files right from the administration backend, without opening a text editor. Download this extension from http://joomlacode.org/gf/project/joomla_1_5_tr1/frs/ and install it from the Extensions | Install/Uninstall screen. How to do it... After installation, follow the steps as shown: From the Joomla! administration panel, click on Components | Translation Manager. This will show the Translation Manager screen, listing all of the installed languages for the site and the administration backend. < For changing any language translation, select that language, for example Site [en-GB] English(United Kingdom), and click on the View Files button. This will show the language files for that language. Now select a file, such as, com_banners, and click on the Edit button. This shows the string editing screen for the com_banners.ini file. Change the strings accordingly, and click on the Save button in the toolbar. For adding a new language, click on New in the Translation Manager screen. This will show the Create New Language screen: In the Language Details section, configure the following: Client: Select who will be the client for this translation—Administrator, Installation, or Site. If you want to translate for the administrator interface, select Administrator. We want to translate the site's frontend, therefore we select Site. Language ISO tag: Type the ISO tag for the language. For example, if we want to translate it into Bengali, type ISO code bn-BD. Name: Type language name, that is Bangla. Description: Type a short description for the translation. Legacy Name: Type the traditional name of the language, for example, bn for bn-BD. Language Locales: Type the locale code for the language. Windows Code page: Specify the code page for the language. The default is iso-8859-1. For the Bangla language it will be utf-8. PDF Font: Specify the font family to be used for displaying the PDF in that language. Right-to-Left: Specify Yes if the language is to be read from right to left (for example, Arabic). In the Author Details section, provide the translator's name (probably your name), e-mail address, website URL, version number for the translation, creation date, the copyright holder's name, and URL to the license document. When done, click on the Save button in the toolbar. This saves the language definition and you will see the language name on the Translation Manager screen:
Read more
  • 0
  • 0
  • 4925

article-image-customizing-kubrik-wordpress
Packt
19 Apr 2010
5 min read
Save for later

Customizing Kubrik with Wordpress

Packt
19 Apr 2010
5 min read
Getting ready The first step is to make a list of the changes that you want to make. Here's what we've come up with: Increase width to 980px Increase font sizes in sidebar Use a graphic header We've picked 980px as our target width because this size is optimized for a 1024 screen resolution and works well in a grid layout. Several CSS adjustments will be necessary to realize this modification, as well as using an image editing program (we will be using Photoshop). How to do it... To increase the page width, the first step is to determine which entries in the CSS stylesheet are controlling the width. Using Firebug to inspect the page (as seen below), we find that the selector #page has a value of 760px for the width property. And #header has a width of 758px (less because there is a 1px left margin). The .narrowcolumn selector gives the main content column a width of 450px. And #sidebar has a width of 190px. Finally, #footer has a width of 760px. So, we will increase #page and #footer to 980px. #header we will increase to 978px. Let's apply all of the additional 220px width to .narrowcolumn. Taking note of the existing 45px left margin, our new value for the width property will be 700px. That means #sidebar width will remain at 190px, but the margin-left will need to be increased from 545px to 765px. Click on Appearance | Editor. In the right-hand column, below the Templates heading, click on style.css. Scroll past the section that says /* Begin Typography & Colors */, until you get to the section that says /* Begin Structure */. Make the following changes to the stylesheet (style.css), commenting as appropriate to document your changes. #page { background-color: white; margin: 20px auto; padding: 0; width: 980px; /* increased from 760px */ border: 1px solid #959596; }#header { background-color: #73a0c5; margin: 0 0 0 1px; padding: 0; height: 200px; width: 978px; /* increased from 758px */ }.narrowcolumn { float: left; padding: 0 0 20px 45px; margin: 0px 0 0; width: 700px; /* increased from 450px */ }#sidebar {margin-left:765px; /* increaseed from 545px */padding:20px 0 10px;width:190px;}#footer { padding: 0; margin: 0 auto; width: 980px; /* increased from 760px */ clear: both; } Adjustments via Photoshop We'll also need to use an image editing program to modify the three background images that create the rounded corners: kubrikbg-ltr.jpg, kubrickheader.jpg, and kubrickfooter.jpg. In this example, we modify kubrik-ltr.jpg (the background image for #page), a 760px image. Open up the image in Photoshop, select all, copy, create a new document (with a white or transparent background), and paste (Ctrl-A, Ctrl-C, Ctrl-N, Ctrl-V). Increase the canvas size (Image | Canvas Size) to 980px, keeping the image centered on the left-hand side by clicking on the left-pointing arrow. Select one half of the image with the Rectangular Marquee Tool, cut and paste. Use the Move Tool to drag the new layer to the right-hand side of the canvas. In this case, it does not matter if you can see the transparent background or if your selection was exactly one half the image. Since the middle of the image is simply a white background, we are really only concerned with the borders on the left and right. The following screenshot shows the background image cut in half and moved over: Save for Web and Devices, exporting as a jpg. Then, replace the existing kubrikbgltr.jpg with your modified version via FTP. The steps are similar for both kubrickheader.jpg and kubrickfooter.jpg. Increase the canvas size and copy/paste from the existing image to increase the image size without stretching or distortion. The only difference is that you need to copy and paste different parts of the image in order to preserve the background gradient and/or top and bottom borders. In order to complete our theme customization, the width of .widecolumn will need to be increased from 450px to 700px (and the 150px margin should be converted to a 45px margin, the same as .narrowcolumn). Also, the kubrikwide.jpg background image will need to be modified with an image editing program to increase the size from 760px to 980px. Then, the individual post view will look as good as the homepage. By following the same steps as above, you should now be prepared to make this final customization yourself. Our next goal is to increase the sizes of the sidebar fonts. Firebug helps us to pinpoint the relevant CSS. #sidebar h2 has a font-size of 1.2em (around line 123 of style.css). Let's change this to 1.75em. #sidebar has font-size of 1em. Let's increase this to 1.25em. To use a graphic in the header, open up kubrickheader.jpg in a new Photoshop document. Use the magic wand tool to select and delete the blue gradient with rounded corners. Now, use the rounded rectangle tool to insert your own custom header area. You can apply another gradient, if desired. We choose to apply a bevel and emboss texture to our grey rectangle. Then, to paste in some photos, decreasing their opacity to 50%. In a short time, we've been able to modify Kubrik by re-writing CSS and using an image-editing program. This is the most basic technique for theme modification. Here is the result:
Read more
  • 0
  • 0
  • 4924

article-image-why-meteor-rocks
Packt
08 Jul 2015
23 min read
Save for later

Why Meteor Rocks!

Packt
08 Jul 2015
23 min read
In this article by Isaac Strack, the author of the book, Getting Started with Meteor.js JavaScript Framework - Second Edition, has discussed some really amazing features of Meteor that has contributed a lot to the success of Meteor. Meteor is a disruptive (in a good way!) technology. It enables a new type of web application that is faster, easier to build, and takes advantage of modern techniques, such as Full Stack Reactivity, Latency Compensation, and Data On The Wire. (For more resources related to this topic, see here.) This article explains how web applications have changed over time, why that matters, and how Meteor specifically enables modern web apps through the above-mentioned techniques. By the end of this article, you will have learned: What a modern web application is What Data On The Wire means and how it's different How Latency Compensation can improve your app experience Templates and Reactivity—programming the reactive way! Modern web applications Our world is changing. With continual advancements in displays, computing, and storage capacities, things that weren't even possible a few years ago are now not only possible but are critical to the success of a good application. The Web in particular has undergone significant change. The origin of the web app (client/server) From the beginning, web servers and clients have mimicked the dumb terminal approach to computing where a server with significantly more processing power than a client will perform operations on data (writing records to a database, math calculations, text searches, and so on), transform the data and render it (turn a database record into HTML and so on), and then serve the result to the client, where it is displayed for the user. In other words, the server does all the work, and the client acts as more of a display, or a dumb terminal. This design pattern for this is called…wait for it…the client/server design pattern. The diagrammatic representation of the client-server architecture is shown in the following diagram: This design pattern, borrowed from the dumb terminals and mainframes of the 60s and 70s, was the beginning of the Web as we know it and has continued to be the design pattern that we think of when we think of the Internet. The rise of the machines (MVC) Before the Web (and ever since), desktops were able to run a program such as a spreadsheet or a word processor without needing to talk to a server. This type of application could do everything it needed to, right there on the big and beefy desktop machine. During the early 90s, desktop computers got even more beefy. At the same time, the Web was coming alive, and people started having the idea that a hybrid between the beefy desktop application (a fat app) and the connected client/server application (a thin app) would produce the best of both worlds. This kind of hybrid app—quite the opposite of a dumb terminal—was called a smart app. Many business-oriented smart apps were created, but the easiest examples can be found in computer games. Massively Multiplayer Online games (MMOs), first-person shooters, and real-time strategies are smart apps where information (the data model) is passed between machines through a server. The client in this case does a lot more than just display the information. It performs most of the processing (or acts as a controller) and transforms the data into something to be displayed (the view). This design pattern is simple but very effective. It's called the Model View Controller (MVC) pattern. The model is essentially the data for an application. In the context of a smart app, the model is provided by a server. The client makes requests to the server for data and stores that data as the model. Once the client has a model, it performs actions/logic on that data and then prepares it to be displayed on the screen. This part of the application (talking to the server, modifying the data model, and preparing data for display) is called the controller. The controller sends commands to the view, which displays the information. The view also reports back to the controller when something happens on the screen (a button click, for example). The controller receives the feedback, performs the logic, and updates the model. Lather, rinse, repeat! Since web browsers were built to be "dumb clients", the idea of using a browser as a smart app back then was out of question. Instead, smart apps were built on frameworks such as Microsoft .NET, Java, or Macromedia (now Adobe) Flash. As long as you had the framework installed, you could visit a web page to download/run a smart app. Sometimes, you could run the app inside the browser, and sometimes, you would download it first, but either way, you were running a new type of web app where the client application could talk to the server and share the processing workload. The browser grows up Beginning in the early 2000s, a new twist on the MVC pattern started to emerge. Developers started to realize that, for connected/enterprise "smart apps", there was actually a nested MVC pattern. The server code (controller) was performing business logic against the database (model) through the use of business objects and then sending processed/rendered data to the client application (a "view"). The client was receiving this data from the server and treating it as its own personal "model". The client would then act as a proper controller, perform logic, and send the information to the view to be displayed on the screen. So, the "view" for the server MVC was the "model" for the client MVC. As browser technologies (HTML and JavaScript) matured, it became possible to create smart apps that used the Nested MVC design pattern directly inside an HTML web page. This pattern makes it possible to run a full-sized application using only JavaScript. There is no longer any need to download multiple frameworks or separate apps. You can now get the same functionality from visiting a URL as you could previously by buying a packaged product. A giant Meteor appears! Meteor takes modern web apps to the next level. It enhances and builds upon the nested MVC design pattern by implementing three key features: Data On The Wire through the Distributed Data Protocol (DDP) Latency Compensation with Mini Databases Full Stack Reactivity with Blaze and Tracker Let's walk through these concepts to see why they're valuable, and then, we'll apply them to our Lending Library application. Data On The Wire The concept of Data On The Wire is very simple and in tune with the nested MVC pattern; instead of having a server process everything, render content, and then send HTML across the wire, why not just send the data across the wire and let the client decide what to do with it? This concept is implemented in Meteor using the Distributed Data Protocol, or DDP. DDP has a JSON-based syntax and sends messages similar to the REST protocol. Additions, deletions, and changes are all sent across the wire and handled by the receiving service/client/device. Since DDP uses WebSockets rather than HTTP, the data can be pushed whenever changes occur. But the true beauty of DDP lies in the generic nature of the communication. It doesn't matter what kind of system sends or receives data over DDP—it can be a server, a web service, or a client app—they all use the same protocol to communicate. This means that none of the systems know (or care) whether the other systems are clients or servers. With the exception of the browser, any system can be a server, and without exception, any server can act as a client. All the traffic looks the same and can be treated in a similar manner. In other words, the traditional concept of having a single server for a single client goes away. You can hook multiple servers together, each serving a discreet purpose, or you can have a client connect to multiple servers, interacting with each one differently. Think about what you can do with a system like that: Imagine multiple systems all coming together to create, for example, a health monitoring system. Some systems are built with C++, some with Arduino, some with…well, we don't really care. They all speak DDP. They send and receive data on the wire and decide individually what to do with that data. Suddenly, very difficult and complex problems become much easier to solve. DDP has been implemented in pretty much every major programming language, allowing you true freedom to architect an enterprise application. Latency Compensation Meteor employs a very clever technique called Mini Databases. A mini database is a "lite" version of a normal database that lives in the memory on the client side. Instead of the client sending requests to a server, it can make changes directly to the mini database on the client. This mini database then automatically syncs with the server (using DDP of course), which has the actual database. Out of the box, Meteor uses MongoDB and Minimongo: When the client notices a change, it first executes that change against the client-side Minimongo instance. The client then goes on its merry way and lets the Minimongo handlers communicate with the server over DDP. If the server accepts the change, it then sends out a "changed" message to all connected clients, including the one that made the change. If the server rejects the change, or if a newer change has come in from a different client, the Minimongo instance on the client is corrected, and any affected UI elements are updated as a result. All of this doesn't seem very groundbreaking, but here's the thing—it's all asynchronous, and it's done using DDP. This means that the client doesn't have to wait until it gets a response back from the server. It can immediately update the UI based on what is in the Minimongo instance. What if the change was illegal or other changes have come in from the server? This is not a problem as the client is updated as soon as it gets word from the server. Now, what if you have a slow internet connection or your connection goes down temporarily? In a normal client/server environment, you couldn't make any changes, or the screen would take a while to refresh while the client waits for permission from the server. However, Meteor compensates for this. Since the changes are immediately sent to Minimongo, the UI gets updated immediately. So, if your connection is down, it won't cause a problem: All the changes you make are reflected in your UI, based on the data in Minimongo. When your connection comes back, all the queued changes are sent to the server, and the server will send authorized changes to the client. Basically, Meteor lets the client take things on faith. If there's a problem, the data coming in from the server will fix it, but for the most part, the changes you make will be ratified and broadcast by the server immediately. Coding this type of behavior in Meteor is crazy easy (although you can make it more complex and therefore more controlled if you like): lists = new Mongo.Collection("lists"); This one line declares that there is a lists data model. Both the client and server will have a version of it, but they treat their versions differently. The client will subscribe to changes announced by the server and update its model accordingly. The server will publish changes, listen to change requests from the client, and update its model (its master copy) based on these change requests. Wow, one line of code that does all that! Of course, there is more to it, but that's beyond the scope of this article, so we'll move on. To better understand Meteor data synchronization, see the Publish and subscribe section of the meteor documentation at http://docs.meteor.com/#/full/meteor_publish. Full Stack Reactivity Reactivity is integral to every part of Meteor. On the client side, Meteor has the Blaze library, which uses HTML templates and JavaScript helpers to detect changes and render the data in your UI. Whenever there is a change, the helpers re-run themselves and add, delete, and change UI elements, as appropriate, based on the structure found in the templates. These functions that re-run themselves are called reactive computations. On both the client and the server, Meteor also offers reactive computations without having to use a UI. Called the Tracker library, these helpers also detect any data changes and rerun themselves accordingly. Because both the client and the server are JavaScript-based, you can use the Tracker library anywhere. This is defined as isomorphic or full stack reactivity because you're using the same language (and in some cases the same code!) on both the client and the server. Re-running functions on data changes has a really amazing benefit for you, the programmer: you get to write code declaratively, and Meteor takes care of the reactive part automatically. Just tell Meteor how you want the data displayed, and Meteor will manage any and all data changes. This declarative style is usually accomplished through the use of templates. Templates work their magic through the use of view data bindings. Without getting too deep, a view data binding is a shared piece of data that will be displayed differently if the data changes. Let's look at a very simple data binding—one for which you don't technically need Meteor—to illustrate the point. Let's perform the following set of steps to understand the concept in detail: In LendLib.html, you will see an HTML-based template expression: <div id="categories-container">      {{> categories}}   </div> This expression is a placeholder for an HTML template that is found just below it: <template name="categories">    <h2 class="title">my stuff</h2>.. So, {{> categories}} is basically saying, "put whatever is in the template categories right here." And the HTML template with the matching name is providing that. If you want to see how data changes will affect the display, change the h2 tag to an h4 tag and save the change: <template name="categories">    <h4 class="title">my stuff</h4> You'll see the effect in your browser. (my stuff will become itsy bitsy.) That's view data binding at work. Change the h4 tag back to an h2 tag and save the change, unless you like the change. No judgment here...okay, maybe a little bit of judgment. It's ugly, and tiny, and hard to read. Seriously, you should change it back before someone sees it and makes fun of you! Alright, now that we know what a view data binding is, let's see how Meteor uses it. Inside the categories template in LendLib.html, you'll find even more templates: <template name="categories"> <h4 class="title">my stuff</h4> <div id="categories" class="btn-group">    {{#each lists}}      <div class="category btn btn-primary">        {{Category}}      </div>    {{/each}} </div> </template> Meteor uses a template language called Spacebars to provide instructions inside templates. These instructions are called expressions, and they let us do things like add HTML for every record in a collection, insert the values of properties, and control layouts with conditional statements. The first Spacebars expression is part of a pair and is a for-each statement. {{#each lists}} tells the interpreter to perform the action below it (in this case, it tells it to make a new div element) for each item in the lists collection. lists is the piece of data, and {{#each lists}} is the placeholder. Now, inside the {{#each lists}} expression, there is one more Spacebars expression: {{Category}} Since the expression is found inside the #each expression, it is considered a property. That is to say that {{Category}} is the same as saying this.Category, where this is the current item in the for-each loop. So, the placeholder is saying, "add the value of the Category property for the current record." Now, if we look in LendLib.js, we will see the reactive values (called reactive contexts) behind the templates: lists : function () { return lists.find(... Here, Meteor is declaring a template helper named lists. The helper, lists, is found inside the template helpers belonging to categories. The lists helper happens to be a function that returns all the data in the lists collection, which we defined previously. Remember this line? lists = new Mongo.Collection("lists"); This lists collection is returned by the above-mentioned helper. When there is a change to the lists collection, the helper gets updated and the template's placeholder is changed as well. Let's see this in action. On your web page pointing to http://localhost:3000, open the browser console and enter the following line: > lists.insert({Category:"Games"}); This will update the lists data collection. The template will see this change and update the HTML code/placeholder. Each of the placeholders will run one additional time for the new entry in lists, and you'll see the following screen: When the lists collection was updated, the Template.categories.lists helper detected the change and reran itself (recomputed). This changed the contents of the code meant to be displayed in the {{> categories}} placeholder. Since the contents were changed, the affected part of the template was re-run. Now, take a minute here and think about how little we had to do to get this reactive computation to run: we simply created a template, instructing Blaze how we want the lists data collection to be displayed, and we put in a placeholder. This is simple, declarative programming at its finest! Let's create some templates We'll now see a real-life example of reactive computations and work on our Lending Library at the same time. Adding categories through the console has been a fun exercise, but it's not a long-term solution. Let's make it so that we can do that on the page instead as follows: Open LendLib.html and add a new button just before the {{#each lists}} expression: <div id="categories" class="btn-group"> <div class="category btn btn-primary" id="btnNewCat">    <span class="glyphicon glyphicon-plus"></span> </div> {{#each lists}} This will add a plus button on the page, as follows: Now, we want to change the button into a text field when we click on it. So let's build that functionality by using the reactive pattern. We will make it based on the value of a variable in the template. Add the following {{#if…else}} conditionals around our new button: <div id="categories" class="btn-group"> {{#if new_cat}} {{else}}    <div class="category btn btn-primary" id="btnNewCat">      <span class="glyphicon glyphicon-plus"></span>    </div> {{/if}} {{#each lists}} The first line, {{#if new_cat}}, checks to see whether new_cat is true or false. If it's false, the {{else}} section is triggered, and it means that we haven't yet indicated that we want to add a new category, so we should be displaying the button with the plus sign. In this case, since we haven't defined it yet, new_cat will always be false, and so the display won't change. Now, let's add the HTML code to display when we want to add a new category: {{#if new_cat}} <div class="category form-group" id="newCat">      <input type="text" id="add-category" class="form-control" value="" />    </div> {{else}} ... {{/if}} There's the smallest bit of CSS we need to take care of as well. Open ~/Documents/Meteor/LendLib/LendLib.css and add the following declaration: #newCat { max-width: 250px; } Okay, so now we've added an input field, which will show up when new_cat is true. The input field won't show up unless it is set to true; so, for now, it's hidden. So, how do we make new_cat equal to true? Save your changes if you haven't already done so, and open LendLib.js. First, we'll declare a Session variable, just below our Meteor.isClient check function, at the top of the file: if (Meteor.isClient) { // We are declaring the 'adding_category' flag Session.set('adding_category', false); Now, we'll declare the new template helper new_cat, which will be a function returning the value of adding_category. We need to place the new helper in the Template.categories.helpers() method, just below the declaration for lists: Template.categories.helpers({ lists: function () {    ... }, new_cat: function(){    //returns true if adding_category has been assigned    //a value of true    return Session.equals('adding_category',true); } }); Note the comma (,) on the line above new_cat. It's important that you add that comma, or your code will not execute. Save these changes, and you'll see that nothing has changed. Ta-da! In reality, this is exactly as it should be because we haven't done anything to change the value of adding_category yet. Let's do this now: First, we'll declare our click event handler, which will change the value in our Session variable. To do this, add the following highlighted code just below the Template.categories.helpers() block: Template.categories.helpers({ ... }); Template.categories.events({ 'click #btnNewCat': function (e, t) {    Session.set('adding_category', true);    Tracker.flush();    focusText(t.find("#add-category")); } }); Now, let's take a look at the following line of code: Template.categories.events({ This line declares that events will be found in the category template. Now, let's take a look at the next line: 'click #btnNewCat': function (e, t) { This tells us that we're looking for a click event on the HTML element with an id="btnNewCat" statement (which we already created in LendLib.html). Session.set('adding_category', true); Tracker.flush(); focusText(t.find("#add-category")); Next, we set the Session variable, adding_category = true, flush the DOM (to clear up anything wonky), and then set the focus onto the input box with the id="add-category" expression. There is one last thing to do, and that is to quickly add the focusText(). helper function. To do this, just before the closing tag for the if (Meteor.isClient) function, add the following code: /////Generic Helper Functions///// //this function puts our cursor where it needs to be. function focusText(i) { i.focus(); i.select(); }; } //<------closing bracket for if(Meteor.isClient){} Now, when you save the changes and click on the plus button, you will see the input box: Fancy! However, it's still not useful, and we want to pause for a second and reflect on what just happened; we created a conditional template in the HTML page that will either show an input box or a plus button, depending on the value of a variable. This variable is a reactive variable, called a reactive context. This means that if we change the value of the variable (like we do with the click event handler), then the view automatically updates because the new_cat helpers function (a reactive computation) will rerun. Congratulations, you've just used Meteor's reactive programming model! To really bring this home, let's add a change to the lists collection (which is also a reactive context, remember?) and figure out a way to hide the input field when we're done. First, we need to add a listener for the keyup event. Or, to put it another way, we want to listen when the user types something in the box and hits Enter. When this happens, we want to add a category based on what the user typed. To do this, let's first declare the event handler. Just after the click handler for #btnNewCat, let's add another event handler: 'click #btnNewCat': function (e, t) {    ... }, 'keyup #add-category': function (e,t){    if (e.which === 13)    {      var catVal = String(e.target.value || "");      if (catVal)      {        lists.insert({Category:catVal});        Session.set('adding_category', false);      }    } } We add a "," character at the end of the first click handler, and then add the keyup event handler. Now, let's check each of the lines in the preceding code: This line checks to see whether we hit the Enter/Return key. if (e.which === 13) This line of code checks to see whether the input field has any value in it: var catVal = String(e.target.value || ""); if (catVal) If it does, we want to add an entry to the lists collection: lists.insert({Category:catVal}); Then, we want to hide the input box, which we can do by simply modifying the value of adding_category: Session.set('adding_category', false); There is one more thing to add and then we'll be done. When we click away from the input box, we want to hide it and bring back the plus button. We already know how to do this reactively, so let's add a quick function that changes the value of adding_category. To do this, add one more comma after the keyup event handler and insert the following event handler: 'keyup #add-category': function (e,t){ ... }, 'focusout #add-category': function(e,t){    Session.set('adding_category',false); } Save your changes, and let's see this in action! In your web browser on http://localhost:3000, click on the plus sign, add the word Clothes, and hit Enter. Your screen should now resemble the following screenshot: Feel free to add more categories if you like. Also, experiment by clicking on the plus button, typing something in, and then clicking away from the input field. Summary In this article, you learned about the history of web applications and saw how we've moved from a traditional client/server model to a nested MVC design pattern. You learned what smart apps are, and you also saw how Meteor has taken smart apps to the next level with Data On The Wire, Latency Compensation, and Full Stack Reactivity. You saw how Meteor uses templates and helpers to automatically update content, using reactive variables and reactive computations. Lastly, you added more functionality to the Lending Library. You made a button and an input field to add categories, and you did it all using reactive programming rather than directly editing the HTML code. Resources for Article: Further resources on this subject: Building the next generation Web with Meteor [article] Quick start - creating your first application [article] Meteor.js JavaScript Framework: Why Meteor Rocks! [article]
Read more
  • 0
  • 0
  • 4916
article-image-blogger-improving-your-blog-google-analytics-and-search-engine-optimization
Packt
22 Oct 2009
7 min read
Save for later

Blogger: Improving Your Blog with Google Analytics and Search Engine Optimization

Packt
22 Oct 2009
7 min read
If you've ever wondered how people find your website or how to generate more traffic, then this article tells you more about your visitors. Knowing where they come from, what posts they like, how long they stay, and other site metrics are all valuable information to have as a blogger. You would expect to pay for such a deep look into the underbelly of your blog, but Google wants to give it to you for free. Why for free? The better your site does, the more likely you are to pay for AdWords or use other Google tools. The Google Analytics online statistics application is a delicious carrot to encourage content rich sites and better ad revenue for everyone involved. You also want people to find your blog when they perform a search about your topic. The painful truth is that search engines have to find your blog first before it will show up in their results. There are thousands of new blogs being created everyday. If you want people to be able to find your blog in the increasingly crowded blogosphere, optimizing your blog for search engines will improve the odds. Improving Your Blog with Google Analytics Analytics gives you an overwhelming amount of data to use for measuring the success of your sites, and ads. Once you've had time to analyze that data, you will want to take action to improve the performance of your blog, and ads. We'll now look at how Analytics can help you make decisions about the design, and content of your site. Analyzing Navigation The Navigation section of the Content Overview report reveals how your visitors actually navigate your blog. Visitors move around a site in ways we can't predict. Seeing how they actually navigate a site and where they entered the site are powerful tools we can use to diagnose where we need to improve our blog. Exploring the Navigation Summary The Navigation Summary shows you the path people take through your site, including how they get there and where they go. We can see from the following graphical representation that our visitors entered the site through the main page of the blog most of the time. After reaching that page, over half the time, they went to other pages within the site. Entrance Paths We can see the path, the visitors take to enter our blog using the Entrance Paths report. It will show us from where they entered our site, which pages they looked at, and the last page they viewed before exiting. Visitors don't always enter by the main page of a site, especially if they find the site using search engines or trackbacks. The following screenshot displays a typical entrance path. The visitor comes to the site home page, and then goes to the full page of one of the posts. It looks like our visitors are highly attracted to the recipe posts. Georgia may want to feature more posts about recipes that tie in with her available inventory. Optimizing your Landing Page The Landing Page reports tell you where your visitors are coming from, and if they have used keywords to find you. You have a choice between viewing the source visitors used to get to your blog, or the keywords. Knowing the sources will give you guidance on the areas you should focus your marketing or advertising efforts on. Examining Entrance Sources You can quickly see how visitors are finding your site, whether through a direct link, or a search engine, locally from Blogger, or from social networking applications such as Twitter.com. In the Entrance Sources graph shown in the following screenshot, we can see that the largest among the number of people are coming to the blog using a direct link. Blogger is also responsible for a large share of our visitors, which is over 37%. There is even a visitor drawn to the blog from Twitter.com, where Georgia has an account. Discovering Entrance Keywords When visitors arrive at your site using keywords, the words they use will show up on the report. If they are using words in a pattern that do not match your site content, you may see a high bounce rate. You can use this report to redesign your landing page to better represent the purpose of your site by the words, and phrases that you use. Interpreting Click Patterns When visitors visit your site they show their attraction to links, and interactive content by clicking on them. Click Patterns are the representation of all those mouse clicks over a set time period. Using the Site Overlay reporting feature, you can visually see the mouse clicks represented in a graphical pattern. Much like collared pins stuck on a wall chart they will quickly reveal to you, which areas of your site visitors clicked on the most, and which links they avoided. Understanding Site Overlay Site Overlay shows the number of clicks for your site by laying them transparently in a graphical format on top of your site. Details with the number of clicks, and goal tracking information pop up in a little box when you hover over a click graphic with your mouse. At the top of the screen are options that control the display of the Site Overlay. Clicking the Hide Overlay link will hide the overlay from view. The Displaying drop-down list lets you choose how to view mouse Clicks on the page, or goals. The date range is the last item displayed. The graphical bars shown on top of the page content indicate where visitors clicked, and how many of them did so. You can quickly see what areas of the page interest your visitors the most. Based on the page clicks you see, you will have an idea of the content, and advertising that is most interesting to your visitors. Yes, Site Overlay will show the content areas of the page the visitors clicked on, and the advertisement areas. It will also help you see which links are tied to goals, and whether they are enticing your visitors to click. Optimizing Your Blog for Search Engines We are going to take our earlier checklists and use them as guides on where to make changes to our blog. When the changes are complete, the blog will be more attractive to search engines and visitors. We will start with changes we can make "On-site", and then progress to ways we can improve search engine results with "Off-site" improvements. Optimizing On-site The most crucial improvements we identified earlier were around the blog settings, template, and content. We will start with the easiest fixes, then dive into the template to correct validation issues. Let's begin with the settings in our Blogger blog. Seeding the Blog Title and Description with Keywords When you created your blog, did you take a moment to think about what words potential visitors were likely to type in when searching for your blog? Using keywords in the title and description of your blog gives potential visitors a preview and explanation of the topics they can expect to encounter in your blog. This information is what will also display in search results when potential visitors perform a search. Updating the Blog Title and Description It's never too late to seed your blog title and description with keywords. We will edit the blog title and description to optimize them for search engines. Login to your blog and navigate to Settings | Basic. We are going to replace the current title text with a phrase that more closely fits the blog. Type Organic Fruit for All into the Title field. Now, we are going to change the description of the blog. Type Organic Fruit Recipes, seasonal tips, and guides to healthy living into the description field. Scroll down to the bottom of the screen and click the Save Settings button. Y ou can enter up to 500 characters of descriptive text. What Just Happened? When we changed the title and description of our blog in the Basic Settings section, Blogger saved the changes and updated the template information as well. Now, when search engines crawl our blog, they will see richer descriptions of our blog in the blog title and blog description. The next optimization task is to verify that search engines can index our blog.
Read more
  • 0
  • 0
  • 4913

article-image-zen-gift-education
Packt
23 Oct 2009
4 min read
Save for later

Zen Gift of Education

Packt
23 Oct 2009
4 min read
Zen Gift of Education Many distributions have special releases around Christmas and New Year. I was planning to look at some of these this month like last year's Ubuntu Christmas Edition. But instead I found a release that's useful enough to maintain all year around. ZenEdu is a Live distribution that packs a whole bunch of educational tools on top of the Slackware-based light-weight and zippy Zenwalk Linux. As per Zenwalk's Wiki, ZenEdu was initiated by a user on the distro's French forum last year in December. That time the distro contained mostly French-only educational programs. This year, several members of the Zenwalk Linux community decided to release an international edition of ZenEdu. The distro is a goldmine of open source educational software and also packs a detailed user manual, which shows the developers' serious approach to do things properly. The educational apps included in the distro cover a broad range of subjects. The ZenEdu ISO is about 700 MB and includes apps that'll help users with subjects like Astronomy, Mathematics, and Chemistry. Since learning is the core idea behind the distro, it goes beyond traditional curriculum subjects and also packs tools that'll teach students the basics of programming and music. Some of the tools I particularly like are Stellarium - the popular 3D planetarium, Stardict - a multi-language dictionary, ghemical - a comprehensive computational chemistry package, Little Wizard that introduces the basics of programming to young students, and Maxima, for the manipulation of symbolic and numerical expressions, including differentiation, integration, ordinary differential equations, systems of linear equations, etc. If you want to learn music, train your ears with Solfege, and use TuxGuitar to edit and play guitar tablatures. What sets ZenEdu apart from other educational distros is that it bundles other productivity tools as well. This includes general-purpose applications like the IceWeasel web browser, IceDove email client, Pidgin for instant messaging, Kompozer for authoring web pages, and OpenOffice.org for word processing. Furthermore, the distro packs several other apps, which according to the developers, were chosen based on their usefulness to students while keeping in mind the things that might interest them. This includes a simple program to manage personal tasks and todo lists, a drawing program, a comic book viewer, a video editor, and a program to create a wide array of 3D content. However, there are dozens of free software educational tools that aren't included in this CD due to size considerations. But that's no problem. Since ZenEdu is based on Zenwalk, it too can be expanded with drag-and-drop modules. To create a new customize ZenEdu Live CD, browse and download the modules of educational apps you want and use the remastering application, isomaster to add them to your customized ZenEdu Live CD! The highlight of this distro though is the iTALC tool for teachers. iTALC, which stands for Intelligent Teaching And Learning with Computers, is a powerful cross-platform didactical tool that lets teachers view and control other computers in their network. Using iTALC teachers can see what's going on in computer labs and take snapshots, remote-control computers to support and help students, run a demo on all students' computers in real-time, send text-messages to students, cycle power and rebooting computers remotely, etc. ZenEdu has a special 'teacher' account pre-configured to run iTALC. Once logged in from that user, you can start iTALC and navigate through its interface, first adding student computers, and then controlling or monitoring them. ZenEdu's wiki page advices that if you'll be using the program regularly, you should save the 'teacher' account's iTALC directory (/home/teacher/.italc/) inside zenlive/rootcopy of the Live CD via isomaster. This will load the iTALC configuration the next time you boot the remastered Live CD. If you'll be using iTALC regularly you'd be well off installing ZenEdu on to your hard disk. Unfortunately, ZenEdu isn't installable. It's only a Live CD, and at best can be installed onto a USB Flash stick for portability. Most of the specialized distros I've played with, tend to be too specialized. They do what they are supposed to, but nothing more. ZenEdu is different in that, in a single CD, the developers have managed to squeeze a good number of educational apps as well as everyday tools. I hope members of the Zenwalk community, actively develop and maintain ZenEdu.   Some more articles by Mayank Sharma: Meet the Distro guy Making a Complete yet Small Linux Distribution
Read more
  • 0
  • 0
  • 4908

article-image-object-oriented-javascript-backbone-classes
Packt
03 Jun 2015
9 min read
Save for later

Object-Oriented JavaScript with Backbone Classes

Packt
03 Jun 2015
9 min read
In this Article by Jeremy Walker, author of the book Backbone.js Essentials, we will explore the following topics: The differences between JavaScript's class system and the class systems of traditional object-oriented languages How new, this, and prototype enable JavaScript's class system Extend, Backbone's much easier mechanism for creating subclasses (For more resources related to this topic, see here.) JavaScript's class system Programmers who use JavaScript can use classes to encapsulate units of logic in the same way as programmers of other languages. However, unlike those languages, JavaScript relies on a less popular form of inheritance known as prototype-based inheritance. Since Backbone classes are, at their core, just JavaScript classes, they too rely on the prototype system and can be subclassed in the same way as any other JavaScript class. For instance, let's say you wanted to create your own Book subclass of the Backbone Model class with additional logic that Model doesn't have, such as book-related properties and methods. Here's how you can create such a class using only JavaScript's native object-oriented capabilities: // Define Book's Initializervar Book = function() {// define Book's default propertiesthis.currentPage = 1;this.totalPages = 1;}// Define book's parent classBook.prototype = new Backbone.Model();// Define a method of BookBook.prototype.turnPage = function() {this.currentPage += 1;return this.currentPage;} If you've never worked with prototypes in JavaScript, the preceding code may look a little intimidating. Fortunately, Backbone provides a much easier and easier to read mechanism for creating subclasses. However, since that system is built on top of JavaScript's native system, it's important to first understand how the native system works. This understanding will be helpful later when you want to do more complex class-related tasks, such as calling a method defined on a parent class. The new keyword The new keyword is a relatively simple but extremely useful part of JavaScript's class system. The first thing that you need to understand about new is that it doesn't create objects in the same way as other languages. In JavaScript, every variable is either a function, object, or primitive, which means that when we refer to a class, what we're really referring to is a specially designed initialization function. Creating this class-like function is as simple as defining a function that modifies this and then using the new keyword to call that function. Normally, when you call a function, its this is obvious. For instance, when you call the turnPage method of a book object, the this method inside turnPage will be set to this book object, as shown here: var simpleBook = {currentPage: 3, pages: 60};simpleBook.turnPage = function() {this.currentPage += 1;return this.currentPage;}simpleBook.turnPage(); // == 4 Calling a function that isn't attached to an object (in other words, a function that is not a method) results in this being set to the global scope. In a web browser, this means the window object: var testGlobalThis = function() {alert(this);}testGlobalThis(); // alerts window When we use the new keyword before calling an initialization function, three things happen (well, actually four, but we'll wait to explain the fourth one until we explain prototypes): JavaScript creates a brand new object ({})for us JavaScript sets the this method inside the initialization function to the newly created object After the function finishes, JavaScript ignores the normal return value and instead returns the object that was created As you can see, although the new keyword is simple, it's nevertheless important because it allows you to treat initialization functions as if they really are actual classes. At the same time, it does so without violating the JavaScript principle that all variables must either be a function, object, or primitive. Prototypal inheritance That's all well and good, but if JavaScript has no true concept of classes, how can we create subclasses? As it turns out, every object in JavaScript has two special properties to solve this problem: prototype and __proto__ (hidden). These two properties are, perhaps, the most commonly misunderstood aspects of JavaScript, but once you learn how they work, they are actually quite simple to use. When you call a method on an object or try to retrieve a property JavaScript first checks whether the object has the method or property defined in the object itself. In other words if you define a method such as this one: book.turnPage = function()this.currentPage += 1;}; JavaScript will use that definition first when you call turnPage. In real-world code, however, you will almost never want to put methods directly in your objects for two reasons. First, doing that will result in duplicate copies of those methods, as each instance of your class will have its own separate copy. Second, adding methods in this way requires an extra step, and that step can be easily forgotten when you create new instances. If the object doesn't have a turnPage method defined in it, JavaScript will next check the object's hidden __proto__ property. If this __proto__ object doesn't have a turnPage method, then JavaScript will look at the __proto__ property on the object's __proto__. If that doesn't have the method, JavaScript continues to check the __proto__ of the __proto__ of the __proto__ and keeps checking each successive __proto__ until it has exhausted the chain. This is similar to single-class inheritance in more traditional object-oriented languages, except that instead of going through a class chain, JavaScript instead uses a prototype chain. Just as in an object-oriented language we wind up with only a single copy of each method, but instead of the method being defined on the class itself, it's defined on the class's prototype. In a future version of JavaScript (ES6), it will be possible to work with the __proto__ object directly, but for now, the only way to actually see the __proto__ property is to use your browser's debugging tool (for instance, the Chrome Developer Tools debugger):   This means that you can't use this line of code: book.__proto__.turnPage(); Also, you can't use the following code: book.__proto__ = {turnPage: function() {this.currentPage += 1;}}; But, if you can't manipulate __proto__ directly, how can you take advantage of it? Fortunately, it is possible to manipulate __proto__, but you can only do this indirectly by manipulating prototype. Do you remember I mentioned that the new keyword actually does four things? The fourth thing is that it sets the __proto__ property of the new object it creates to the prototype property of the initialization function. In other words, if you want to add a turnPage method to every new instance of Book that you create, you can assign this turnPage method to the prototype property of the Book initialization function, For example: var Book = function() {};Book.prototype.turnPage = function() {this.currentPage += 1;};var book = new Book();book.turnPage();// this works because book.__proto__ == Book.prototype Since these concepts often cause confusion, let's briefly recap: Every object has a prototype property and a hidden __proto__ property An object's __proto__ property is set to the prototype property of its constructor when it is first created and cannot be changed Whenever JavaScript can't find a property or method on an object, it "checks each step of the __proto__ chain until it finds one or until it runs "out of chain Extending Backbone classes With that explanation out of the way, we can finally get down to the workings of Backbone's subclassing system, which revolves around Backbone's extend method. To use extend, you simply call it from the class that your new subclass will be based on, and extend will return the new subclass. This new subclass will have its __proto__ property set to the prototype property of its parent class, allowing objects created with the new subclass to access all the properties and methods of the parent class. Take an example of the following code snippet: var Book = Backbone.Model.extend();// Book.prototype.__proto__ == Backbone.Model.prototype;var book = new Book();book.destroy(); In the preceding example, the last line works because JavaScript will look up the __proto__ chain, find the Model method destroy, and use it. In other words, all the functionality of our original class has been inherited by our new class. But of course, extend wouldn't be exciting if all it can do is make exact clones of the parent classes, which is why extend takes a properties object as its first argument. Any properties or methods on this object will be added to the new class's prototype. For instance, let's try making our Book class a little more interesting by adding a property and a method: var Book = Backbone.Model.extend({currentPage: 1,turnPage: function() {this.currentPage += 1;}});var book = new Book();book.currentPage; // == 1book.turnPage(); // increments book.currentPage by one The extend method also allows you to create static properties or methods, or in other words, properties or methods that live on the class rather than on objects created from that class. These static properties and methods are passed in as the second classProperties argument to extend. Here's a quick example of how to add a static method to our Book class: var Book = Backbone.Model.extend({}, {areBooksGreat: function() {alert("yes they are!");}});Book.areBooksGreat(); // alerts "yes they are!"var book = new Book();book.areBooksGreat(); // fails because static methods must becalled on a class As you can see, there are several advantages to Backbone's approach to inheritance over the native JavaScript approach. First, the word prototype did not appear even once in any of the previously mentioned code; while you still need to understand how prototype works, you don't have to think about it just to create a class. Another benefit is that the entire class definition is contained within a single extend call, keeping all of the class's parts together visually. Also, when we use extend, the various pieces of logic that make up the class are ordered the same way as in most other programming languages, defining the super class first and then the initializer and properties, instead of the other way around. Summary In this article, we explored how JavaScript's native class system works and how the new, this, and prototype keywords/properties form the basis of it. We also learned how Backbone's extend method makes creating new subclasses much more convenient as well as how to use apply and call to invoke parent methods (or when providing callback functions) to preserve the desired this method. Resources for Article: Further resources on this subject: Testing Backbone.js Application [Article] Building an app using Backbone.js [Article] Organizing Backbone Applications - Structure, Optimize, and Deploy [Article]
Read more
  • 0
  • 0
  • 4865
article-image-oracle-api-management-implementation-12c
Packt
29 Sep 2015
5 min read
Save for later

Oracle API Management Implementation 12c

Packt
29 Sep 2015
5 min read
 This article by Luis Augusto Weir, the author of the book, Oracle API Management 12c Implementation, gives you a gist of what is covered in the book. At present, the digital transformation is essential for any business strategy, regardless of the industry they belong to an organization. (For more resources related to this topic, see here.) The companies who embark on a journey of digital transformation, they become able to create innovative and disruptive solutions; this in order to deliver a user experience much richer, unified, and personalized at lower cost. These organizations are able to address customers dynamically and across a wide variety of channels, such as mobile applications, highly responsive websites, and social networks. Ultimately, companies that develop models aligned digital innovation business, acquire a considerable competitive advantage over those that do not. The main trigger for this transformation is the ability to expose and make available business information and key technological capabilities for this, which often are buried in information systems (EIS) of the organization, or in components integration are only visible internally. In the digital economy, it is highly desirable to realize those assets in a standardized way through APIs, this course, in a controlled, scalable, and secure environment. The lightweight nature and ease of finding/using these APIs greatly facilitates its adoption as the essential mechanism to expose and/or consume various features from a multichannel environment. API Management is the discipline that governs the development cycle of APIs, defining the tools and processes needed to build, publish, and operate, also including management development communities around them. Our recent book, API Management Oracle 12c (Luis Weir, Andrew Bell, Rolando Carrasco, Arturo Viveros), is a very comprehensive and detailed to implement API Management in an organization guide. In this book, he explains the relationship that keeps this discipline with concepts such great detail as SOA Governance and DevOps .The convergence of API Management with SOA and governance of such services is addressed particularly to explain and shape the concept of Application Services Governance (ESG). On the other hand, it highlights the presence of case studies based on real scenarios, with multiple examples to demonstrate the correct definition and implementation of a robust strategy in solving supported Oracle Management API. The book begins by describing a number of key concepts about API Management and contextualizing the complementary disciplines, such as SOA Governance, DevOps, and Enterprise Architecture (EA). This is in order to clear up any confusion about the relationship to these topics. Then, all these concepts are put into practice by defining the case study of an organization with real name, which previously dealt with successfully implementing a service-oriented architecture considering the government of it, and now It is the need/opportunity to extend its technology platform by implementing a strategy of API Management. Throughout the narrative of the case are also described: Business requirements justifying the adoption of API Management The potential impact of the proposed solution on the organization The steps required to design and implement the strategy The definition and implementation of the assessment of maturity (API Readiness) and analysis of gaps in terms of: people, tools, and technology The exercise of evaluation and selection of products, explaining the choice of Oracle as the most appropriate solution The implementation roadmap API Management In later chapters, the various steps are being addressed one by one needed to solve the raised stage, by implementing the following reference architecture for API Management, based on the components of the Oracle solution: Catalog API, API Manager, and API Gateway. In short, the book will enable the reader to acquire a number of advanced knowledge on the following topics: API Management, its definition, concepts, and objectives Differences and similarities between API Management and SOA Governance; where and how these two disciplines converge in the concept of ESG Application Services Governance[d1]  and how to define a framework aimed at ASG Definition and implementation of the assessment of maturity for API Management Criteria for the selection and evaluation tools; Why Oracle API Management Suite? Implementation of Oracle API Catalog (OAC), including OAC harvesting by bootstrapping & ANT scripts and JDev, OAC Console, user creation and management, metadata API, API Discovery, and how to extend the functionality of OAC REX by API. Management APIs and challenges in general API Management Oracle Implementation Manager API (OAPIM), including the creation, publishing, monitoring, subscription, and life cycle management APIs by OAPIM Portal Common scenarios for adoption/implementation of API Management and how to solve them[d2]  Implementation of Oracle API Gateway (OAG), including creation of policies with different filters, OAuth authentication, integration with LDAP, SOAP/REST APIs conversions, and Testing. Defining the deployment topology for Oracle API Management Suite Installing and configuring OAC, OAPIM, and OAG 12c Oracle Management API is designed for the following audience: Enterprise Architects, Solution Architects, Technical Leader and SOA and APIs professionals seeking to know thoroughly and successfully implement the Oracle API Management solution. Summary In this article, we looked at Oracle API Management Implementation 12c in brief. More information on this is provided in the book. Resources for Article: Further resources on this subject: Oracle 12c SQL and PL/SQL New Features[article] Securing Data at Rest in Oracle 11g[article] Getting Started with Oracle Primavera P6 [article]
Read more
  • 0
  • 0
  • 4859

article-image-layout-extnet
Packt
30 Jan 2013
16 min read
Save for later

Layout with Ext.NET

Packt
30 Jan 2013
16 min read
(For more resources related to this topic, see here.) Border layout The Border layout is perhaps one of the more popular layouts. While quite complex at first glance, it is popular because it turns out to be quite flexible to design and to use. It offers common elements often seen in complex web applications, such as an area for header content, footer content, a main content area, plus areas to either side. All are separately scrollable and resizable if needed, among other benefits. In Ext speak, these areas are called Regions, and are given names of North, South, Center, East, and West regions. Only the Center region is mandatory. It is also the one without any given dimensions; it will resize to fit the remaining area after all the other regions have been set. A West or East region must have a width defined, and North or South regions must have a height defined. These can be defined using the Width or Height property (in pixels) or using the Flex property which helps provide ratios. Each region can be any Ext.NET component; a very common option is Panel or a subclass of Panel. There are limits, however: for example, a Window is intended to be floating so cannot be one of the regions. This offers a lot of flexibility and can help avoid nesting too many Panels in order to show other components such as GridPanels or TabPanels, for example. Here is a screenshot showing a simple Border layout being applied to the entire page (that is, the viewport) using a 2-column style layout: We have configured a Border layout with two regions; a West region and a Center region. The Border layout is applied to the whole page (this is an example of using it with Viewport. Here is the code: <%@ Page Language="C#" %> <!DOCTYPE html> <html> <head runat="server"> <title>Border Layout Example</title> </head> <body> <ext:ResourceManager runat="server" Theme="Gray" /> <ext:Viewport runat="server" Layout="border"> <Items> <ext:Panel Region="West" Split="true" Title="West" Width="200" Collapsible="true" /> <ext:Panel Region="Center" Title="Center content" /> </Items> </ext:Viewport> </body> </html> The code has a Viewport configured with a Border layout via the Layout property. Then, into the Items collection two Panels are added, for the West and Center regions. The value of the Layout property is case insensitive and can take variations, such as Border, border, borderlayout, BorderLayout, and so on. As regions of a Border layout we can also configure options such as whether you want split bars, whether Panels are collapsible, and more. Our example uses the following: The West region Panel has been configured to be collapsible (using Collapsible="true"). This creates a small button in the title area which, when clicked, will smoothly animate the collapse of that region (which can then be clicked again to open it). When collapsed, the title area itself can also be clicked which will float the region into appearance, rather than permanently opening it (allowing the user to glimpse at the content and mouse away to close the region). This floating capability can be turned off by using Floatable="false" on the Panel. Split="true" gives a split bar with a collapse button between the regions. This next example shows a more complex Border layout where all regions are used: The markup used for the previous is very similar to the first example, so we will only show the Viewport portion: <ext:Viewport runat="server" Layout="border"> <Items> <ext:Panel Region="North" Split="true" Title="North" Height="75" Collapsible="true" /> <ext:Panel Region="West" Split="true" Title="West" Width="150" Collapsible="true" /> <ext:Panel runat="server" Region="Center" Title="Center content" /> <ext:Panel Region="East" Split="true" Title="East" Width="150" Collapsible="true" /> <ext:Panel Region="South" Split="true" Title="South" Height="75" Collapsible="true" /> </Items> </ext:Viewport> Although each Panel has a title set via the Title property, it is optional. For example, you may want to omit the title from the North region if you want an application header or banner bar, where the title bar could be superfluous. Different ways to create the same components The previous examples were shown using the specific Layout="Border" markup. However, there are a number of ways this can be marked up or written in code. For example, You can code these entirely in markup as we have seen You can create these entirely in code You can use a mixture of markup and code to suit your needs Here are some quick examples: Border layout from code This is the code version of the first two-panel Border layout example: <%@ Page Language="C#" %> <script runat="server"> protected void Page_Load(object sender, EventArgs e) { var viewport = new Viewport { Layout = "border", Items = { new Ext.Net.Panel { Region = Region.West, Title = "West", Width = 200, Collapsible = true, Split = true }, new Ext.Net.Panel { Region = Region.Center, Title = "Center content" } } }; this.Form.Controls.Add(viewport); } </script> <!DOCTYPE html> <html> <head runat="server"> <title>Border Layout Example</title> </head> <body> <form runat="server"> <ext:ResourceManager runat="server" Theme="Gray" /> </form> </body> </html> There are a number of things going on here worth mentioning: The appropriate panels have been added to the Viewport's Items collection Finally, the Viewport is added to the page via the form's Controls Collection If you are used to programming with ASP.NET, you normally add a control to the Controls collection of an ASP.NET control. However, when Ext.NET controls add themselves to each other, it is usually done via the Items collection. This helps create a more optimal initialization script. This also means that only Ext.NET components participate in the layout logic. There is also the Content property in markup (or ContentControls property in code-behind) which can be used to add non-Ext.NET controls or raw HTML, though they will not take part in the layout. It is important to note that configuring Items and Content together should be avoided, especially if a layout is set on the parent container. This is because the parent container will only use the Items collection. Some layouts may hide the Content section altogether or have other undesired results. In general, use only one at a time, not both because the Viewport is the outer-most control; it is added to the Controls collection of the form itself. Another important thing to bear in mind is that the Viewport must be the only top-level visible control. That means it cannot be placed inside a div, for example it must be added directly to the body or to the <form runat="server"> only. In addition, there should not be any sibling controls (except floating widgets, like Window). Mixing markup and code The same 2-panel Border layout can also be mixed in various ways. For example: <%@ Page Language="C#" %> <script runat="server"> protected void Page_Load(object sender, EventArgs e) { this.WestPanel.Title = "West"; this.WestPanel.Split = true; this.WestPanel.Collapsible = true; this.Viewport1.Items.Add(new Ext.Net.Panel { Region = Region.Center, Title = "Center content" }); } </script> <!DOCTYPE html> <html> <head runat="server"> <title>Border Layout Example</title> </head> <body> <ext:ResourceManager runat="server" /> <ext:Viewport ID="Viewport1" runat="server" Layout="Border"> <Items> <ext:Panel ID="WestPanel" runat="server" Region="West" Width="200" /> </Items> </ext:Viewport> </body> </html> In the previous example, the Viewport and the initial part of the West region have been defined in markup. The Center region Panel has been added via code and the rest of the West Panel's properties have been set in code-behind. As with most ASP. NET controls, you can mix and match these as you need. Loading layout items via User Controls A powerful capability that Ext.NET provides is being able to load layout components from User Controls. This is achieved by using the UserControlLoader component. Consider this example: <ext:Viewport runat="server" Layout="Border"> <Items> <ext:UserControlLoader Path="WestPanel.ascx" /> <ext:Panel Region="Center" /> </Items> </ext:Viewport> In this code, we have replaced the West region Panel that was used in earlier examples with a UserControlLoader component and set the Path property to load a user control in the same directory as this page. That user control is very simple for our example: <%@ Control Language="C#" %> <ext:Panel runat="server" Region="West" Split="true" Title="West" Width="200" Collapsible="true" /> In other words, we have simply moved our Panel from our earlier example into a user control and loaded that instead. Though a small example, this demonstrates some useful reuse capability. Also note that although we used the UserControlLoader in this Border layout example, it can be used anywhere else as needed, as it is an Ext.NET component. The containing component does not have to be a Viewport Note also that the containing component does not have to be a Viewport. It can be any other appropriate container, such as another Panel or a Window. Let's do just that: <ext:Window runat="server" Layout="Border" Height="200" Width="400" Border="false"> <Items> <ext:Panel Region="West" Split="true" Title="West" Width="150" Collapsible="true" /> <ext:Panel Region="Center" Title="Center content" /> </Items> </ext:Window> The container has changed from a Viewport to a Window (with dimensions). It will produce this: More than one item with the same region In previous versions of Ext JS and Ext.NET you could only have one component in a given region, for example, only one North region Panel, one West region Panel, and so on. New to Ext.NET 2 is the ability to have more than one item in the same region. This can be very flexible and improve performance slightly. This is because in the past if you wanted the appearance of say multiple West columns, you would need to create nested Border layouts (which is still an option of course). But now, you can simply add two components to a Border layout and give them the same region value. Nested Border layouts are still possible in case the flexibility is needed (and helps make porting from an earlier version easier). First, here is an example using nested Border layouts to achieve three vertical columns: <ext:Window runat="server" Layout="Border" Height="200" Width="400" Border="false"> <Items> <ext:Panel Region="West" Split="true" Title="West" Width="100" Collapsible="true" /> <ext:Panel Region="Center" Layout="Border" Border="false"> <Items> <ext:Panel Region="West" Split="true" Title="Inner West" Width="100" Collapsible="true" /> <ext:Panel Region="Center" Title="Inner Center" /> </Items> </ext:Panel> </Items> </ext:Window> This code will produce the following output: The previous code is only a slight variation of the example preceding it, but has a few notable changes: The Center region Panel has itself been given the layout as Border. This means that although this is a Center region for the window that it is a part of, this Panel is itself another Border layout. The nested Border layout then has two further Panels, an additional West region and an additional Center region. Note, the Title has also been removed from the outer Center region so that when they are rendered, they line up to look like three Panels next to each other. Here is the same example, but without using a nested border Panel and instead, just adding another West region Panel to the containing Window: <ext:Window runat="server" Layout="Border" Height="200" Width="400" Border="false"> <Items> <ext:Panel Region="West" Split="true" Title="West" Width="100" Collapsible="true" /> <ext:Panel Region="West" Split="true" Title="Inner West" Width="100" Collapsible="true" /> <ext:Panel Region="Center" Title="Center content" Border="false" /> </Items> </ext:Window> Regions are not limited to Panels only A common problem with layouts is to start off creating more deeply nested controls than needed and the example earlier shows that it is not always needed. Multiple items with the same region helps to prevent nesting Border Layouts unnecessarily. Another inefficiency typical with the Border layout usage is using too many containing Panels in each region. For example, there may be a Center region Panel which then contains a TabPanel. However, as TabPanel is a subclass of Panel it can be given a region directly, therefore avoiding an unnecessary Panel to contain the TabPanel: <ext:Window runat="server" Layout="Border" Height="200" Width="400" Border="False"> <Items> <ext:Panel Region="West" Split="true" Title="West" Width="100" Collapsible="True" /> <ext:TabPanel Region="Center"> <Items> <ext:Panel Title="First Tab" /> <ext:Panel Title="Second Tab" /> </Items> </ext:TabPanel> </Items> </ext:Window> This code will produce the following output: The differences with the nested Border layout example shown earlier are: The outer Center region has been changed from Panel to TabPanel. TabPanels manage their own items' layout so Layout="Border" is removed. The TabPanel also has Border="false" taken out (so it is true by default). The inner Panels have had their regions, Split, and other border related attributes taken out. This is because they are not inside a nested Border layout now; they are tabs. Other Panels, such as TreePanel or GridPanel, can also be used as we will see. Something that can be fiddly from time to time is knowing which borders to take off and which ones to keep when you have nested layouts and controls like this. There is a logic to it, but sometimes a quick bit of trial and error can also help figure it out! As a programmer this sounds minor and unimportant, but usually you want to prevent the borders becoming too thick, as aesthetically it can be off-putting, whereas just the right amount of borders can help make the application look clean and professional. You can always give components a class via the Cls property and then in CSS you can fine tune the borders (and other styles of course) as you need. Weighted regions Another feature new to Ext.NET 2 is that regions can be given weighting to influence how they are rendered and spaced out. Prior versions would require nested Border layouts to achieve this. To see how this works, consider this example to put a South region only inside the Center Panel: To achieve this output, if we used the old way—the nested Border layouts—we would do something like this: <ext:Window runat="server" Layout="Border" Height="200" Width="400" Border="false"> <Items> <ext:Panel Region="West" Split="true" Title="West" Width="100" Collapsible="true" /> <ext:Panel Region="Center" Layout="Border" Border="false"> <Items> <ext:Panel Region="Center" Title="Center" /> <ext:Panel Region="South" Split="true" Title="South" Height="100" Collapsible="true" /> </Items> </ext:Panel> </Items> </ext:Window> In the preceding code, we make the Center region itself be a Border layout with an inner Center region and a South region. This way the outer West region takes up all the space on the left. If the South region was part of the outer Border layout, then it would span across the entire bottom area of the window. But the same effect can be achieved using weighting. This means you do not need nested Border layouts; the three Panels can all be items of the containing window, which means a few less objects being created on the client: <ext:Window runat="server" Layout="Border" Height="200" Width="400" Border="false"> <Items> <ext:Panel Region="West" Split="true" Title="West" Width="100" Collapsible="true" Weight="10" /> <ext:Panel Region="Center" Title="Center" /> <ext:Panel Region="South" Split="true" Title="South" Height="100" Collapsible="true" /> </Items> </ext:Window> The way region weights work is that the region with the highest weight is assigned space from the border before other regions. If more than one region has the same weight as another, they are assigned space based on their position in the owner's Items collection (that is first come, first served). In the preceding code, we set the Weight property to 10 to the West region only, so it is rendered first and, thus, takes up all the space it can before the other two are rendered. This allows for many flexible options and Ext.NET has an example where you can configure different values to see the effects of different weights: http://examples.ext.net/#/Layout/BorderLayout/Regions_Weights/ As the previous examples show, there are many ways to define the layout, offering you more flexibility, especially if generating from code-behind in a very dynamic way. Knowing that there are so many ways to define the layout, we can now speed up our look at many other types of layouts. Summary This article covered one of the numerous layout options available in Ext.NET, that is, the Border layout, to help you organize your web applications. Resources for Article : Further resources on this subject: Your First ASP.NET MVC Application [Article] Customizing and Extending the ASP.NET MVC Framework [Article] Tips & Tricks for Ext JS 3.x [Article]
Read more
  • 0
  • 0
  • 4842
Modal Close icon
Modal Close icon