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-working-javascript-drupal-6-part-1
Packt
15 Oct 2009
11 min read
Save for later

Working with JavaScript in Drupal 6: Part 1

Packt
15 Oct 2009
11 min read
How Drupal handles JavaScript How is JavaScript typically used? Mostly, it is used to provide additional functionality to a web page, which is usually delivered to a web browser as an HTML document. The browser receives the HTML from the server and then begins the process of displaying the page. During this parsing and rendering process, the browser may request additional resources from the server such as images, CSS, or Flash. It then incorporates these elements into the document displayed to the user. In this process, there are two ways that JavaScript code can be sent from the server to the browser. First, the code can be placed directly inside the HTML. This is done by inserting code inside the <script> and </script> tags: <script type="text/javascript">alert('hello world');</script> This is called including the script inline. Second, the code can be loaded separately from the rest of the HTML. Again, this is usually done using the <script> and </script> tags. However, instead of putting the code between the tags, we use the src attribute to instruct the browser to retrieve an additional document from the server. <script type="text/javascript" src="some/script.js"></script> In this example, src="some/script.js" points the browser to an additional script file stored on the same server as the HTML document in which this script tag is embedded. So, if the HTML is located at http://example.com/index.html, the browser will request the script file using the URL http://example.com/some/script.js. The </script> tag is required When XML was first standardized, it introduced a shorthand notation for writing tags that have no content. Instead of writing <p></p>, one could simply write <p/>. While this notation is supported by all modern mainstream browsers, it cannot be used for <script></script> tags. Some browsers do not recognize <script/> and expect that any <script> tag will be accompanied by a closing </script> tag even if there is no content between the tags. If we were developing static HTML files, we would simply write HTML pages that include <script></script> tags anytime we needed to add some JavaScript to the page. But we're using Drupal, not static HTML, and the process for adding JavaScript in this environment is done differently. Where Drupal JavaScript comes from? As with most web content management systems, Drupal generates HTML dynamically. This is done through interactions between the Drupal core, modules, and the theme system. A single request might involve several different modules. Each module is responsible for providing information for a specific portion of the resulting page. The theme system is used to transform that information from PHP data structures into HTML fragments, and then compose a full HTML document. But this raises some interesting questions: What part of Drupal should be responsible for deciding what JavaScript is needed for a page? And where will this JavaScript come from? In some cases, it makes sense for the Drupal core to handle JavaScript. It could automatically include JavaScript in cases where scripts are clearly needed. JavaScript can also be used to modify the look and feel of a site. In that case, the script is really functioning as a component of a theme. It would be best to include the script as a part of a theme. JavaScript can also provide functional improvements, especially when used with AJAX and related technologies. These features can be used to make more powerful modules. In that case, it makes sense to include the script as a part of a module. So which one is the best: modules, themes, or core? Rather than deciding on your behalf, Drupal developers have made it possible to incorporate JavaScript into all three: The Drupal core handles including the core JavaScript support as needed. The Drupal and jQuery libraries are included automatically when necessary. When theme developers needs to add some JavaScript, they can do so within the theme. There is no need to tamper with the core, or to accompany a theme with a module. Finally, module developers can add JavaScript directly to a module. In this way, modules can provide advanced JavaScript functionality without requiring modification of the theme. In this article we will add scripts to themes and modules. As we get started, we will begin with a theme. Module or theme? How do you decide whether your script ought to go in a theme or in a module? Here's a basic guideline. If the script provides functionality specific to the layout details of a theme, it should be included in a theme. If the script provides general behavior that should work regardless of the theme, then it should be included in a module. Sometimes it is hard to determine when a script belongs to a theme and when it should to be placed in a module. In fact, the script we create here will be one such a case. We are going to create a script that provides a printer-friendly version of a page's main content. Once we have the script, we will attach it to a theme. Of course, if we want to provide this functionality across themes, we might instead create a module to house the script. We will start out simply with a JavaScript-enabled theme. Project overview: printer-friendly page content The JavaScript that we will write creates a pop-up printer-friendly window, and automatically launches the print dialog. This is usually launched from File | Print in your browser's menu. Once we write the script, we will incorporate it into a theme, and add a special printing feature to the page(s) displayed with that theme. As we walk through this process, we will also create our first theme. (Technically, it will be a subtheme derived from the Bluemarine theme.) By the end of this project, you should know how to create Drupal-friendly JavaScript files. You will also know how to create themes and add scripts to them. The first step in the process is to write the JavaScript. The printer script Our script will fetch the main content of a page and then open a new window, populating that window's document with the main content of the page. From there, it will open the browser's print dialog, prompting the user to print the document. Since this is our first script, we will keep it simple. The code will be very basic, employing the sort of classical procedural JavaScript that web developers have been using since the mid-1990's. But don't expect this to be the norm. To minimize clutter and maximize the reusability of our code, we will store this new script in its own script file. The file will be named printer_tool.js: // $Id$/*** Add printer-friendly tool to page.*/var PrinterTool = {};PrinterTool.windowSettings = 'toolbar=no,location=no,' +'status=no,menu=no,scrollbars=yes,width=650,height=400';/*** Open a printer-friendly page and prompt for printing.* @param tagID* The ID of the tag that contains the material that should* be printed.*/PrinterTool.print = function (tagID) {var target = document.getElementById(tagID);var title = document.title;if(!target || target.childNodes.length === 0) {alert("Nothing to Print");return;}var content = target.innerHTML;var text = '<html><head><title>' +title +'</title><body>' +content +'</body></html>';printerWindow = window.open('', '', PrinterTool.windowSettings);printerWindow.document.open();printerWindow.document.write(text);printerWindow.document.close();printerWindow.print();}; First, let's talk about some of the structural aspects of the code. Drupal coding standards In general, well-formatted code is considered a mark of professionalism. In an open source project such as Drupal, where many people are likely to view and contribute to the code, enforced coding standards can make reading and understanding what the code does easier. When contributing code to the Drupal project, developers adhere to a Drupal coding standard (http://drupal.org/coding-standards). Add-on modules and themes are expected to abide by these rules. It is advised that you follow the Drupal standards even in code that you do no anticipate submitting to the Drupal project. Along with keeping your code stylistically similar to Drupal's, it will also help you develop good coding habits for those occasions when you do contribute something to the community. For the most part, the official Drupal coding standards are focused on the PHP code. But many of these rules are readily applicable to JavaScript as well. Here are a few important standards: Every file should have a comment near the top that has the contents $Id$. This is a placeholder for the version control system to insert version information. Drupal uses CVS (Concurrent Versioning System) for source code versioning. Each time a file is checked into CVS, it will replace $Id$ with information about the current version of the software. To learn more about CVS, visit http://www.nongnu.org/cvs/. Indenting should be done with two spaces (and no tabs). This keeps the code compact, but still clear. Comments should be used wherever necessary. Doxygen-style documentation blocks (/** ... */) should be used to comment files and functions. Any complex or potentially confusing code should be commented with // or /* ... */. Comments should be written in sentences with punctuation. Control structure keywords (if, else, for, switch, and so on) should appear at the beginning of a line, and be followed by a single space (if (), not if()). Here's an example: if (a) {// Put code here.}else if (b) {// Put code here.}else {// Put code here.} Operators (+, =, *, &&, ||, and so on) should have a single space on each side, for example: 1 + 2. The exception to this rule is the member operator (.), which is used to access a property of an object. There should be no spaces surrounding these. Example: window.document (never window . document). Stylistic differences between PHP and JavaScript Not all PHP coding standards apply to JavaScript. PHP variables and function names are declared in all lower case with underscores (_) to separate words. JavaScript typically follows different conventions. JavaScript variables and functions are named using camel case (sometimes called StudlyCaps). For a variable or function, the first word is all lower case. Any subsequent words in the variable or function name are capitalized. Underscores are not used to separate words. Here are some examples: var myNewVariable = "Hello World";function helloWorld() { alert(myNewVariable);} While this convention is employed throughout the Drupal JavaScript code, there is currently no hard-and-fast set of JavaScript-specific coding conventions. The working draft, which covers most of the important recommendations, can be found at http://drupal.org/node/260140. Here is a summary of the more important (and widely followed) conventions: Variables should always be declared with the var keyword. This can go a long way towards making the scope of variables explicit. JavaScript has a particularly broad notion of scope. Functions inherit the scope of their parent context, which means a parent's variables are available to the children. Using var makes it easier to visually identify the scoping of a variable. It also helps to avoid ambiguous cases which may lead to hard-to-diagnose bugs or issues. Statements should always end with a semicolon (;). This includes statements that assign functions, for example, myFunction = function() {};. Our print function, defined earlier, exhibits this behavior. Why do we require trailing semicolons? In JavaScript, placing semicolons at the end of statements is considered optional. Without semicolons, the script interpreter is responsible for determining where the statement ends. It usually uses line endings to help determine this. However, explicitly using semicolons can be helpful. For example, JavaScript can be compressed by removing whitespace and line endings. For this to work, every line must end with a semicolon. When an anonymous function is declared, there should be a space between  the function and the parentheses, for example, function () {}, not function() {}. This preserves the whitespace that would be there in in a non-anonymous function declaration (function myFunction() {}). There are other conventions, many of which you will see here. But the ones mentioned here cover the most frequently needed. With coding standards behind us, let's take a look at the beginning of the printer_tool.js file.
Read more
  • 0
  • 0
  • 6280

article-image-google-earth-google-maps-and-your-photos-tutorial-part-ii
Packt
17 Mar 2010
19 min read
Save for later

Google Earth, Google Maps and Your Photos: a Tutorial Part II

Packt
17 Mar 2010
19 min read
Part 2: Google Maps Section 1: Introduction to Part 2 When approaching any sufficiently high-level computing topic, it is often true that we need to be familiar with a broad range of underlying and related concepts to establish the foundation necessary to learn the new material. Virtually every technology not only borrows from, but also builds on others. Furthermore, it is often the case with programming projects that the bulk of the work comes at the beginning and involves carefully thinking through the problem, devising a solution, and building those parts of the project that we need to write before we can get to the code we want to write. In the first part of the tutorial we wrote a Perl script which allows us to generate valid KML files from collections of geotagged photos. Using our new tool, we generated a number of files containing all of the data (about our photos) that we'll use to populate our Google Maps. We also looked at the structure of KML, and covered a number of other important topics, which are key to understanding the material presented here. If you have not read part 1, do take the time at least to glance through it to confirm for yourself that you won't have trouble following along with this discussion. Now we turn our attention to Google Maps. After this short introduction we'll handle the tutorial in 3 parts. Part 1: This section discusses the document-object-model (DOM), which is a formal methodology for negotiating XML files, like the KML files we created in part 1. Part 2: Next we'll look at XHTML and the XHTML file we'll use to display our Google Map. As you'll see, the file included with the project is no more than a shell, but it does suffice to allow us to present our map. Furthermore, it affords us an opportunity to talk about integrating XHTML, Javacript, and the Google Maps API. There are a few important things we'll need to understand. Working with a simple page will help us avoid complicating the issues unnecessarily and will make it easy for you to relocate the map to a page of your own (maybe as part of a weblog for example) with a minimum amount of fuss. Part 3: Finally, we'll look at Javascript and the Google Maps API. Before we get to all of that, there are a couple of preliminary topics to talk about: XML We've already looked at XML, describing it as an open, extensible markup language. We've said that XML is a metalanguage which allows us to define other languages with specific syntactic structures and vocabularies tailored to discrete problem domains. Furthermore we've said that KML is one such XML-based language, engineered to address the problem of describing geographical data and the positioning of geographical placemarks and other features to display on a map, among other applications. XHTML We haven't yet talked about XHTML which is a reimplementation of HTML as a standard, XML-based format. HTML (Hypertext Markup Language) has served as the preeminent language for authoring documents on the World Wide Web since the web's inception in the late 1980s and early 1990s. HTML is the markup language1; which makes hypertext2; linking between documents on the web possible and defines the set of tags, i.e. elements and attributes, that indicate the structure of a document using plain-text codes included alongside the content itself. Just as the web was not the first hypertext system3, HTML was not the first markup language, though both have become extremely important. Without delving too deeply into the primordial history of markup, HTML is a descendant of SGML (Standard Generalized Markup Language) which is itself an offspring of GML (Generalized Markup Language). The Wikipedia entry for GML offers this description of the language: GML frees document creators from specific document formatting concerns such as font specification, line spacing, and page layout required by Script. SCRIPT was an early text formatting language developed by IBM, and a precursor to modern page description languages like Postscript and LaTeX, that describe the structure and appearance of documents. Not surprisingly the goal of GML is echoed in the intent of HTML, though the two are far removed from each other. Berners-Lee; considered HTML to be an application of SGML from the very beginning, but with a clear emphasis on simplicity and winnowing down much of the overhead that had always characterized formal markup languages. In the early days, the web had to struggle for acceptance. The birth of the web is a story of humble beginnings4. The significance of the web was by no means a forgone conclusion and early adoption required that the markup syntax of the web be as accessible as possible. After all, more stodgy languages already existed. The simplicity of HTML certainly contributed to the success of the web (among many other factors), but it also meant that the standard was lacking in key areas. As the web gained wider appeal there was a tendency to take advantage of the early permissiveness of the standard. Developers of mainstream web browsers exacerbated the problem significantly by tolerating noncompliant documents and encouraging the use of proprietary tags in defiance of efforts on the part of standards organizations to reign in the syntax of the language. In the short term, this was a confusing situation for everyone and led to incompatibilities and erratic behavior among an ever increasing multitude of documents on the web and the various web browsers available, which differed in their support for, and interpretation of, what were in essence emerging 'dialects' of HTML. These web browsers differed not only from one another, but also frequently from one version to the next of the same application. There was a real need to establish stability in the language. Lack of dependable syntax meant that the job of building a parser capable of adequately adhering to the standards, and at the same time accommodating various abuses of the standard, had become an exercise in futility. Unlike HTML, XHTML must strictly adhere to the XML standard, which means that any compliant XML parser can negotiate properly formatted documents with relative ease. This reliability paves the way for a more efficient and sophisticated web, resulting in not only more consistent rendering of content, but the development of software that is able to differentiate and act on content based on context, and relationships among data. This is one of the primary advantages of XML, as has already been discussed, and this is a key advantage of XHTML as well. Long term, Berners-Lee, who currently serves as the director of the World Wide Web Consortium (W3C); and a senior researcher at MIT's Computer Science and Artificial Intelligence Laboratory (CSAIL), continues to actively pursue the vision of a Semantic Web. That is, a web that can be mined as a rich repository of data by intelligent software agents, which not only present information, perform basic pattern matching, and the like, but are capable of analysing information (in a truer sense—keep this or get rid of it?). From the W3C's Semantic Web Roadmap we have this brief introduction to the concept: The Web was designed as an information space, with the goal that it should be useful not only for human-human communication, but also that machines would be able to participate and help. One of the major obstacles to this has been the fact that most information on the Web is designed for human consumption, and even if it was derived from a database with well defined meanings (in at least some terms) for its columns, that the structure of the data is not evident to a robot browsing the web. Leaving aside the artificial intelligence problem of training machines to behave like people, the Semantic Web approach instead develops languages for expressing information in a machine processable form. Whether this vision accurately predicts the future of the web remains to be seen. At the moment the Semantic Web is a veritable stew of protocols, frameworks, concepts, extensions, namespaces, vocabularies, schema, ontologies, and other components. It is the subject of much debate, virtually all of it far beyond the scope of this tutorial. But this 'brave new web' is not purely academic. The increased emphasis on standards-compliant markup has resulted in developers of web browsers and content creation tools steering their apps toward the standards. This in turn motivates authors to produce compliant documents. In fact the Strict variations of XHTML do not allow for deviation from the standards. Two immediate benefits of this work, whether or not it ultimately leads to some future web, are (1) more consistent document rendering across platforms among mainstream web browsers, (2) and the emergence of the Document Object Model (DOM). We'll look at the DOM shortly. Section 2: Object Models and the DOM An object model is a collection of objects and the typically hierarchical, often complex, relationships among them, where the most generic definition of an object is simply a 'thing'. Object models are all around us and are not limited to programming or the broader topic of computing for that matter. If, for example, you were to describe a car in terms of its object model: You might start by talking about the chassis, or base frame, and then go on to describe the body of the car, its wheels, axles, exhaust system, the drivetrain, etc.; everything that is directly attached to the frame. For each of these you could describe various attributes and elements of that object; for e.g. the body material is an attribute of the body object. The elements may in fact be other objects that collectively comprise those objects within which they are contained. The body of the car contains the engine compartment, passenger compartment, and trunk elements. The engine compartment includes the engine which is itself a collection of smaller objects. The passenger compartment can be described as the collection of front and rear compartment objects, where the front compartment object includes at least a driver side compartment with a steering wheel, instrument panel, etc. These objects have their own attributes and elements perhaps consisting of other objects each of which is an object itself, with a more specific function than the objects in which they are contained. If you've ever put together a toy model of a car you may remember seeing an exploded schematic diagram of the completed model which clearly shows all of the objects from the largest container elements to the smallest ties, screws and other fasteners that hold all of the pieces together. This is a nice way to visualize the object model of the toy car. Of course the object model I have described is only an informal example. It may be fair to dispute the model I've sketched here. As long as you have a better general understanding of what an object model is then this example has served its purpose. Object models are very common within the realms of computer technology, information technology, programming languages, and formal notation. The Document Object Model The Document Object Model (DOM); is a standard object model for describing, accessing and manipulating HTML documents and XML-based formats. The often quoted description of the DOM from the W3C's site dedicated to the specification is: The Document Object Model is a platform- and language-neutral interface that will allow programs and scripts to dynamically access and update the content, structure and style of documents. The document can be further processed and the results of that processing can be incorporated back into the presented page. Remember that XHTML is a special case of XML (i.e. it is an XML based format) and essentially no more than a formalization of HTML. Because it is an XML based format the XML DOM applies. Furthermore, because XHTML describes a single format with a number of required structural elements and only a limited collection of allowable elements and attributes, the HTML DOM has a number of unique objects and methods for acting on those objects that are not available in the more generic XML DOM. Having said that, I want to emphasize the the two are more alike than the are different. Technically we will look at the XML DOM here but nearly everything discussed is applicable to the HTML DOM as well. Though there are differences, some of which we'll encounter later in this tutorial, as an introduction it is appropriate to limit ourselves to fundamental concepts, which the two share in common. We need both. We'll rely on the XML DOM to parse the KML files we generated in part one of the tutorial to populate our Google Map, and the HTML DOM to add the map to our webpage. By the time we've completed this part of the tutorial hopefully you will appreciate just how integral the DOM is for modern web design and development, though we'll only have skimmed the surface of it. The concept of the DOM is actually quite easily understood. It will seem intuitive to anyone who has ever dealt with tree structures (from filesystem hierarchies to family trees). Even if you haven't had any experience with this sort of data structure, you should anticipate being able to pick it up quickly. Under the Document Object Model individual components of the structure are referred to as nodes. Elements, attributes and the text contained within elements are all nodes. The DOM represents an XML document as an inverted tree with a root node at the top. As far as the structure of an actual XML document is concerned, the root is the element that contains all others. In every structure all other nodes are contained within a document node. In the KML files we've generated the Document element is the root element. Every other node is a descendent of Document. We can express the reciprocal relationship by stating that Document is an ancestor of every element other than itself. Relationships among nodes of the document are described in familial terms. Direct descendants are called child nodes or simply children of the their immediate ancestor, referred to as a parent. In our KML files, is the only child of . (It would be just as correct to say that is the parent node of .) Note that there could be more than one Folder node. We could use additional folders to group Placemarks (a) by year, with one folder per year, (b) by event, with each folder dedicated to a single event, or (3) by image gallery so that each folder corresponds  to a discrete image gallery, or maybe some combination of these and other criteria. Furthermore, we can have more than one type of child node under a single parent. For example Placemark is the parent node of , , and in our files. These nodes can all be described as siblings, because they all have the same parent. Also, notice that is a child of , and a grandchild (not a child) of Placemark. We can make a couple of other useful observations about this structure: Every node other than the root has exactly one parent. Parents may have any number of children including zero, though a node without any children won't be referred to as a parent. (A node with no children is called a leaf.) Implicitly there are other familial relationships among nodes. For example, elements with parents that are siblings could be thought of as 'cousins' I suppose, but it is unusual to see these relationships named or otherwise acknowledged. There is one important subtlety. Text is always stored in a text node and never directly in some other element node. For example, the description elements in our KML files contain either plain text or html descriptions of associated Placemarks. This text is not contained directly in the description node. Instead the description node contains unseen text node which contains the descriptive text. So the text is a grandchild of the description node, and a child of a text node, which is the direct descendent of description. Make sure that you understand this before continuing. Because of the inherent structure of XML, we can unambiguously navigate a document without knowing anything else about it, except that it validates. We can move around the tree without being able to name the nodes before we begin. Starting at the root document node, we can traverse that node's children, move laterally among siblings, travel more deeply from parent to child, and then work our way back up the tree negotiating parent relationships. We haven't yet described how we move among siblings. The DOM allows us to treat siblings as a list of nodes, and take advantage of the relationships that exist among elements in any list. Specifically, we can refer to the first (firstChild) and last (lastChild) nodes to position ourselves in the list. Once we are at some location in the list, we can refer to the previous (previousSibling) and next (nextSibling) nodes to navigate among siblings. Programmatically we can use the DOM to treat siblings in a XML data structure as we would any other list. For example, we can loop through sibling nodes working on each node in turn. Keep in mind that we are using generic terminology, not referring to specific node names and we are relying only on the structure of XML which we know must be dependable if the document adheres to the standard. This will work well for our KML files, and it is certainly not limited to KML. There are primarily two techniques we can use to find and manipulate elements in our XML structure using the DOM. Node PropertiesFirstly, we can take advantage of relationships among element nodes as we have been discussing.A number of node properties, some of which have already been mentioned, allow us to move between nodes in the structure. These include: firstChild,lastChild,previousSibling,nextSibling,parentNode If we look at a fragment of KML, similar to the KML files generated in part 1 of the tutorial, starting at the Placemark element... <Placemark>     <name>value</name>     <Snippet maxLines="1">         value     </Snippet>     <description><![CDATA[         value         ]]></description>     <Point>         <coordinates>value</coordinates>     </Point> </Placemark> ...we see a number of these properties: is the firstChild of is the lastChild of The nextSibling of is The previousSibling of is is the parentNode of , , , and getElementsByTagName()Secondly, we can use the method getElementsByTagName() to find any element regardless of the document structure.For example, using the syntax... getElementsByTagName("name") ...we can retrieve all elements as a nodeList from the document which are descendants of the element we are using when we call the method. The following Javascript statement returns a list of all elements in the document and stores that list at the variable list_of_nodes. var list_of_nodes = getElementsByTagName("name"); What is a node list? A node list (NodeList) is an object representing an ordered list of nodes, where each node represents an element in the XML document. The order of the NodeList is the same as the order of the elements in the document. Elements at the top of the document appear first in the list, and the first element returned, i.e. the first position in the list, is numbered 0. Keep in mind that the list includes all <name> elements. If you look at the KML files we've generated you may notice that both <folder> and <placemark> elements contain <name&gt. We need to be aware that getElementsByTagName("name") will return all of these if we are starting at the document root. We can differentiate between these <name> elements in a number of different ways. For example we can insist that the node is a child of a Placemark node to exclude <name> elements that are the children of <folder> elements. We need to be able to refer to various properties of these nodes if we are going to act on them in any reasonable way. The XML DOM exposes several useful node properties incl: nodeName, nodeValue, and nodeType. nodeName: is (quite obviously) the name of the node. What might be less obvious is precisely how the DOM defines nodeName. The tag name is always the name of an element, e.g. 'Placemark' is the name of the <Placemark> elements The attribute name is the nodeName of an attribute, e.g. the name of the maxLines attribute of <Snippet> is 'maxLines' The name of any text node is always the string '#text'. e.g., the plain text or html that we're using as our Placemark descriptions are each contained in a text node, as has already been discussed, and the name of this text node is '#text', and not the name of the element which surrounds the value in the XML document The nodeName of the root document node is always the literal string '#document'. nodeValue: is what you might expect. The value of text nodes is text itself. So the text node of one of our Placemark elements is all of the plain-text or html within the description tags. Again, as far as the DOM is concerned the text is actually contained within a text node which is a child of a description node The value of an attribute node is simply the attribute value. e.g. maxLines="1" has a nodeValue of 1 nodeValue is not defined for the document node and all element nodes. nodeType: is certainly not something you could guess. A specific value is assigned to each of the available types (categories) of nodes. The following is an incomplete list of common node types. Element, type 1 Attribute, type 2 Text, type 3 Comment, type 8 Document, type 9 As I have already said, we will take advantage of the DOM to parse our KML files and populate our Google Maps. Many of the ideas we've seen here will seem much more concrete when we put them to use. Still, this has been a very brief look at an interesting topic that is especially important to web developers and designers. I would recommend that you pick up a book that does a good job of describing the document object model if you are planning on doing any significant amount of that kind of work. This need not be an intimidating topic, though I have found that the majority of books and articles do an inadequate job with it. If you are only interested in following along with this tutorial then this brief treatment of the DOM, the comments in the included source files, and the javascript code itself should be sufficient for you to complete the project.
Read more
  • 0
  • 0
  • 6270

article-image-alice-3-making-simple-animations-actors
Packt
29 Apr 2011
9 min read
Save for later

Alice 3: Making Simple Animations with Actors

Packt
29 Apr 2011
9 min read
Alice 3 provides an extensive gallery with hundreds of customizable 3D models that you can easily incorporate as actors. This article provides many tasks that will allow us to start making simple animations with many actors in the 3D environment provided by Alice. We will search for models of specific animals in the diverse galleries. We will locate and orient the actors in the 3D space. We will give some simple orders to the actors to create simple animations. Browsing galleries to search for a specific class In this recipe, we will create a new project and set a simple scene. Then we will browse the different packages included in Alice to search for a specific class. We will visualize the thumbnail icons that represent each package and class. Getting ready We have to be working on a project in order to be able to browse the galleries. Therefore, we will create a new project and set a simple scene. Follow these steps: Select File New...| in the main menu to start a new project. A dialog box will display the six predefined templates with their thumbnail previews in the Templates tab. Select GrassyProject.a3p as the desired template for the new project and click on OK. Alice will display a grassy ground with a light blue sky. Click on Edit Scene, at the lower-right corner of the scene preview. Alice will show a bigger preview of the scene and will display the Model Gallery at the bottom. Go to the Model Gallery and select Generic Alice Models Environments | Skies|. Use the horizontal scroll bar to find the ForestSky class. Click on the ForestSky thumbnail. Leave the default name, forestSky, for the new instance and click OK to add it to the existing scene. The scene preview will replace the light blue sky with a violet one. Many trees will appear at the horizon, as shown in the next screenshot: (Move the mouse over the image to enlarge it.) How to do it... Follow these steps to browse the different packages included in Alice to search for a specific class: Make sure that Alice is displaying the scene editor. If you see the Edit Code label at the lower-right corner of the big preview of the scene, it means that Alice is displaying the scene editor. If you see the Edit Scene label at the lower-right corner of a small scene preview, you should click on this label to switch to the scene editor. You will see the Model Gallery displayed at the bottom of the window. The initial view of the Model Gallery shows the following three packages located in the gallery root folder, as shown in the following screenshot: Looking Glass Characters: This package includes many characters that perform realistic animations for the characters. For example, you can make a person walk with a simple call to a procedure. Looking Glass Scenery: This package includes different kinds of scenery elements. Generic Alice Models: This package includes models that provide the basic and generic procedures. For example, you can move a person with a simple procedure call, but there isn't a procedure to make the person walk. If you don't see the previously shown screenshot with the three packages, it means that you are browsing a subfolder of gallery and you need to go back to the gallery root folder. Click on the gallery button and Alice will display the thumbnails for the three packages. If you don't see the three packages, you should check your Alice installation. Click on the search entire gallery textbox, located at the right-hand side of the gallery button. Enter rab in the search entire gallery textbox. Alice will query for the classes and packages that contain the rab string and will display the thumbnails for the following classes, as shown in the next screenshot: Rabbit Scarab WhiteRabbit Parabola Now you know that you have two different rabbits, Rabbit and WhiteRabbit. You can select your favorite rabbit and then add it as an actor in the scene. Select File Save as...| and give a name to the project, for example, MyForest. Then, you can use this new scene as a template for your next Alice project. How it works... Alice organizes its gallery in packages with hierarchical folders. The previously mentioned three packages are located in the gallery root folder. We can browse each package by clicking on its thumbnail. Each time we click on a thumbnail, the related sub-folder will open and Alice will display the thumbnails for the new sub-folders and the classes. The thumbnail that represents a folder, known as a package, displays a folder icon at the upper-left corner and includes the preview of some of the classes that it includes. The next screenshot shows the thumbnails for three packages, amusementpark, animals, and beach. These packages are sub-folders of the Generic Alice Models package: The thumbnails for classes don't include the previously mentioned folder icon and they show a different background color. The next screenshot shows the thumbnails for three classes, Bird1, BirdBaby, and BlueBird: The names for packages included within one of the three main packages use lowercase names, such as, aquarium, bedroom, and circus. The names for classes always start with an uppercase letter, such as, Monitor and Room. When a class name needs more than one word, it doesn't use spaces to separate them but it mixes lowercase with uppercase to mark the difference between words, such as, CatClock and OldBed. The main packages contain hundreds of classes organized in dozens of folders. Therefore, we might spend hours browsing the galleries to find an appropriate rabbit for our scene. We took advantage of Alice query features to search the entire gallery for all the classes that contain a string. This way, we could find a simple rabbit, Rabbit, and a dressed rabbit, WhiteRabbit. There's more... While you type characters in the search entire gallery textbox, Alice will query all the packages and will display the results in real-time. You will notice that Alice changes the results displayed as you are editing the textbox. The results for your search will include both packages and classes that contain the entered string. For example, follow these steps: Click on the search entire gallery textbox, located at the right-hand side of the gallery button. Enter bug in the search entire gallery text box. Alice will query for the classes and packages that contain the bug string and will display two thumbnails. One thumbnail is the bugs package and the other thumbnail is the Ladybug class, as shown in the following screenshot: If you think that Ladybug isn't the appropriate bug you want as an actor, you can click on the thumbnail for the bugs package and you will find many other bugs. When you click on the thumbnail, the text you entered in the search entire gallery textbox will disappear because there is no filter being applied to the gallery and you are browsing the contents of the gallery Generic Alice Models | animals | bugs| package. You can add a Beetle or a Catepillar, as shown in the following screenshot: Creating a new instance from a class in a gallery In this task, we will add a new actor to an existing scene. We will drag and drop a thumbnail of a class from the gallery and then we will learn how Alice adds a new instance to the scene. Getting ready We want to add a new actor to an existing scene. Therefore, we will use an existing project that has a simple scene. Open an existing project based on one of the six predefined Alice templates. You can open the MyForest project saved in the Browsing galleries to search for a specific class recipe in this article. Select Starting Camera View in the drop-down list located at the top of the big scene preview. How to do it... Follow these steps to add a new instance of the WhiteRabbit class: Search for the WhiteRabbit class in the gallery. You can browse gallery Generic Alice Models | animals| or enter rab in the search entire gallery textbox to visualize the WhiteRabbit thumbnail. Drag the WhiteRabbit thumbnail from the gallery to the big scene preview. A bounding box that represents the 3D model in the 3D space will appear, as shown in the next screenshot: Keep the mouse button down and move the mouse to locate the bounding box in the desired initial position for the new element. Once you have located the element in the desired position, release the mouse button and the Declare Property dialog box will appear. Leave the default name, whiteRabbit, for the new instance and click on OK to add it to the existing scene. The scene preview will perform an animation when Alice adds the new instance and then it will go back to the starting camera view to show how the new element appears on the scene. The next screenshot shows the new dressed white rabbit added to the scene, as seen by the starting camera: Select File Save as...| from Alice's main menu and give a new name to the project. Then, you can make changes to the project according to your needs. How it works... When we dropped the thumbnail for the WhiteRabbit class, the Declare Property dialog box provided information about what Alice was going to do, as shown in the following screenshot: Alice defines a new class, MyWhiteRabbit, that extends WhiteRabbit. MyWhiteRabbit is a new value type for the project, a subclass of WhiteRabbit. The name for the new property that represents the new instance of MyWhiteRabbit is whiteRabbit. This means that you can access this new actor with the whiteRabbit name and that this property is available for scene. Because the starting camera view is looking at the horizon, we see the rabbit looking at the camera in the scene preview. If you select TOP in the in the drop-down list located at the top of the big scene preview, you will see the rabbit on the grassy ground and how the camera is looking at the rabbit. The next screenshot shows the scene seen from the top and you can see the camera with a circle around it: There's more... When you run the project, Alice shows a new window with the rendered scene, as seen by the previously shown camera, the starting camera. The default window size is very small. You can resize the Run window and Alice will use the new size to render the scene with a higher resolution. The next time you run the project, Alice will use the new size, as shown in the next screenshot that displays the dressed white rabbit with a forest in the background:
Read more
  • 0
  • 0
  • 6263

article-image-using-chronoforms-add-more-features-your-joomla-form
Packt
31 Aug 2010
11 min read
Save for later

Using ChronoForms to add More Features to your Joomla! Form

Packt
31 Aug 2010
11 min read
(For more resources on ChronoForms, see here.) Showing a YouTube video This is the "not really a form" recipe in this article, it just opens a little door to some of the other, more unexpected, capabilities of ChronoForms. For the most part Joomla! protects the content you can display on your pages; it's easy to show HTML + CSS formatted content, more difficult to show PHP and JavaScript. There are many modules, plug-ins and extensions that can help with this but if you have ChronoForms installed then it may be able to help. ChronoForms is designed to show pages that use HTML, CSS, PHP, and JavaScript working together. Most often the pages created are forms but nothing actually requires that any form inputs are included so we can add any code that we like. ChronoForms will wrap our code inside <form>. . .</form> tags which means that we can't embed a form (why would we want to?), but otherwise most things are possible.   Getting ready You will need the ID of the YouTube video that you want to display. We're going to use a video from a conference at Ashridge Business School, but any video will work in essentially the same way. This recipe was developed for this particular video to force display of the HD version. At that time HD was a new option on YouTube and was not readily accessible as it is now. How to do it... Find the video you want on YouTube and look for the links boxes in the right hand column. Here we've clicked on the "customize" icon—the little gear wheel—to open up the options menu. When you've set the options you want copy the code from the Embed box. Here is the code from this video with some added line breaks for clarity: <object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/2Ok1SFnMS4E&hl=en_GB&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/2Ok1SFnMS4E&hl=en_GB&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object> To create a good looking page, we are going to add some HTML before and after this snippet: <h3>Video Postcards from the Edge</h3><div>The video of the 2008 AMOC Conference</div><div style='margin:6px; padding:0px; border:6px solid silver;width:425px;'><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/2Ok1SFnMS4E&hl =en&fs=1&ap=%2526fmt%3D18"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/2Ok1SFnMS4E&hl=en&fs =1&ap=%2526fmt%3D18" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object></div><div>Some more text . . .</div> If you look closely, you'll see that there is also a new parameter in the URL—&ap=%2526fmt%3D18—which is there to force the HD version of the video to be used. Paste this code into the Form HTML box of a new form, save, and publish it. Of course, it would be entirely possible to embed the video and to add form inputs in the same page, maybe to ask for comments or reviews. How it works... Very simply ChronoForms allows you to embed scripts into the page HTML that are not permitted in standard Joomla! articles. Adding a barcode to a form e-mail Sometimes it's important to add a unique identifier to the form response, for example travel or event tickets. In this recipe we will look at generating a "random" identifier and adding it to the form e-mail as a scannable barcode. Getting ready We're going to need a simple form. Our newsletter form will be perfect although we'll be adding to the code in the Form HTML box. We'll need a simple function to create the "random identifier" which we will see shortly. Lastly we"ll need code to generate a barcode. Rather than taking time reinventing this particular wheel, we're going to use a PHP program created by Charles J Scheffold and made available for use or download from http://www.sid6581.net/cs/php-scripts/barcode/. How to do it... First, grab a copy of the barcode.php file from sid6581.net. We'll need to make this file accessible to our form. So let's create a new folder inside the ChronoForms front-end folder. You'll probably need to use an FTP client to do this, or install the "exTplorer" Joomla! extension which will allow you to create folders from within the Joomla! Site Admin interface. Browse to [root]/components/com_chronocontact and create a new includes folder Copy the standard Joomla! index.html file from the com_chronocontact folder into the new folder Upload the barcode.php file into the new includes folder Now, we are going to add the function to create a "random" identifier to the Form HTML. This is a small function that creates an alphanumeric string when it is called. <?phpif ( !$mainframe->isSite() ) { return; }/* function to generate a random alpha-numeric code using a specified pattern * * @param $pattern string * @return string */function generateIdent($pattern='AA9999A'){ $alpha = array("A","B","C","D","E","F","G","H", "J","K","L","M","N","P","Q","R","S","T","U","V","W", "X","Y","Z"); $digit = array("1","2","3","4","5","6","7","8","9"); $return = ""; $pattern_array = str_split($pattern, 1); foreach ( $pattern_array as $v ) { if ( is_numeric($v) ) { $return .= $digit[array_rand($digit)]; } elseif ( in_array(strtoupper($v), $alpha) ) { $return .= $alpha[array_rand($alpha)]; } else { $return .= " "; } } return $return;}?> We call this function using generateIdent() or generateIdent('pattern') where the pattern is a string of As and 9s that defines the shape of the ident we want. The default is AA9999A, giving idents like KX4629G. This will be perfectly fine for our example here. We also want to add the ident into the form and we'll use a hidden field to do that, but to make it visible we'll also display the value. <?php$ident = generateIdent();echo "<div>Ident is $ident</div>";?><input type='hidden' name='ident' id='ident' value='<?php echo $ident; ?>' /> In day to day use we probably wouldn't generate the ident until after the form is submitted. There is often no useful value in displaying it on the form and essentially the same code will work in the OnSubmit boxes. However, here it makes the process clearer to generate it in the form HTML. We can add both these code snippets to our form just before the submit button element. Then apply or save the form and view it in your browser. The layout may not be very elegant but the Ident is there. Refresh the browser a few times to be sure that it is different each time. It's simpler and tempting to use serial numbers to identify records. If you are saving data in a table then these are generated for you as record IDs. It does create some problems though; in particular, it can make it very easy to guess what other IDs are valid and if, as we often do, we include the ID in a URL it may well be possible to guess what other URLs will be valid. Using a random string like this makes that kind of security breach more difficult and less likely. We said though that we'd generate a barcode, so let's develop this form one more step and show the barcode in the form. If you look at the code in barcode.php, it shows a list of parameters and says what we can use. For example: <img src="barcode.php?barcode=123456&width=320&height=200"> We need to modify this a little to link to the new folder for the file and to add our generated ident value: <img src="/components/com_chronocontact/includes/barcode.php?barcode=<? php echo $ident;?>&width=320&height=8"> This code can go in place of the "echo" line we used to display the ident value: <?php$ident = generateIdent();echo "<img src='".JURI::base()."components/com_chronocontact/includes/barcode.php?barcode=".$ident."&width=320&height=80' />";?> Apply or save the form and view it in your browser. There we have it—a bar code in our form showing the random ident that we have created. If you don't see any graphic and the code appears to be correct then you may not have the PHP GD graphics library installed. Check on the AntiSpam tab for any of your forms and you will see a GD Info box. The GD library is now included in the vast majority of PHP installations. If you don't have it then check with your ISP to see if the library can be enabled. Now that's actually not of much use except to show that it works, you can't scan a bar code off the screen. Where we want it is in our Email template. The code to add to the template is: <div>Your code: {ident}</div><img src="<?php echo JURI::base().'components/com_chronocontact/ includes/'; ?>barcode.php?barcode={ident}&width=280&height=100" /> As this includes some PHP, we can't add it using the Rich Text Editor. First we need to go to the Email Setup | Properties box and set Use Template Editor to No, apply the Properties, then apply the form and go to the Email Template tab. To avoid an "oddity" in the current release of ChronoForms it may be necessary to comment out the generateIdent() function code block in the Form HTML, while you create an Email Setup. Just put /* & */ before and after the block if you get a blank page or see a PHP Error message about re-declaring the function. Now click on the Email Template tab and paste the code at the end of the textarea. Submit the form to test. We now have a printable e-mail complete with a barcode showing our random ident. How it works... In this recipe we did a couple of things. We added some more complex PHP to the Form HTML that we had before and we imported a PHP script found on the internet and successfully used that in combination with ChronoForms. There are many hundreds of useful scripts available for almost any conceivable function. Not all are of good quality and not all will work in this way but, with a little work, a surprising number will function perfectly well. There's more... We said earlier that it might be better to generate the ident after the form is submitted. Here's the code to use in the OnSubmit Before code box to get the same result in the e-mail: <?phpif ( ! $mainframe->isSite() ) { return; }JRequest::setVar('ident', generateIdent());/* function to generate a random alpha-numeric code using a specified pattern * * @param $pattern string * @return string */function generateIdent($pattern='AA9999A'){ $alpha = array("A","B","C","D","E","F","G","H", "J","K","L","M","N","P","Q","R","S","T","U","V","W", "X","Y","Z"); $digit = array("1","2","3","4","5","6","7","8","9"); $return = ""; $pattern_array = str_split($pattern, 1); foreach ( $pattern_array as $v ) { if ( is_numeric($v) ) { $return .= $digit[array_rand($digit)]; } elseif ( in_array(strtoupper($v), $alpha) ) { $return .= $alpha[array_rand($alpha)]; } else { $return .= " "; } } return $return;}?> If you use this, then you can remove all of the additional code from the Form HTML box leaving just the basic HTML generated by the Form Wizard. The Email template code remains as we created it previously.
Read more
  • 0
  • 0
  • 6253

article-image-blog-cms
Packt
12 Oct 2009
10 min read
Save for later

Blog CMS

Packt
12 Oct 2009
10 min read
Let's get started right away. The first question-do I need a self-hosted or service-based CMS? Blogs have taken the Internet by storm. They started like simple diaries and have grown to be full-fledged CMSs now. If you want to start a blog, you have the following two options: Sign up with a hosted blog service such as WordPress.com, Typepad.com, Blogger.com, or any other similar services available Set up blogging software, such as WordPress, Movable Type, ExpressionEngine, and so on, on your own server If you are a casual blogger, signing up with a hosted service is a suitable choice. But if you want full control of your blog, setting up your own system is the best option. It's not very difficult—you could do it within five minutes. We will cover only self-hosted solutions for this article. But you can easily apply this knowledge to a blog service. Top blogging CMSs  WordPress (www.WordPress.org) is the most popular self-hosted blogging software. Hundreds of thousands of sites run on WordPress, and tens of millions of people see WordPress-driven content every day. The following images are of the PlayStation ( http://blog.us.playstation.com/ ) and the People ( http://offtherack.people.com/ ) blog sites, which use WordPress: Movable Type (www.movabletype.org) is another longtime favorite. It's very easy to use and has a strong fan following. There are many contenders after the top two blogging CMSs. All general-purpose CMSs have a blogging component. Many old blog software applications are no longer actively maintained. There are new entrants on the scene that focus on niches, such as photo blogging. Let us cover the top choices We can't cover all of the blog software in this article. So, we will only cover WordPress at length. We will talk about Movable Type and ExpressionEngine briefly. At the end, we will touch upon other blogging software. What we are interested in is to find out answers to the following questions: What sort of a site is that CMS good for? How easy is it to build a site? How easy is it to edit content? What's its plug-in/template support like? How extensible/customizable is it? What are the interesting or high-profile examples of that CMS? Taking WordPress for a test drive Let's try creating a site structure, adding and editing content, applying design templates, and making a few customizations with WordPress to see how it performs. Time for action-managing content with WordPress Log in to the administration panel of your WordPress installation. Click on the New Post link in the top bar. This opens the Add New Post page.Enter a title for your first blog post where your cursor is blinking. We will enter definition of the word Yoga for our Yoga Site. Start writing your text in the large text entry box. It's a WYSIWYG editor. You can use buttons in the toolbar to format text, insert links, and so on. Let's insert an image into our post. Click on the first icon next to Upload/Insert. When you move your mouse over it, you will see Add an Image in the tooltip. Click on that icon. Upload a file from your computer. Once a file is uploaded, you can enter additional parameters for this image. This includes Title, Caption, Alignment, a link to open when an image is clicked, and so on. Here's how your screen may look at this stage. Click on Insert into Post to add this image to your post. Complete writing the blog entry. If you want to add tags (keywords) to this post, you can do that from the Tagssection at right. WordPress will autocomplete long tags and will create newones as you Add them. We have not yet created any categories for our blog. Navigate to the Categories section below Tags. Click on the + Add New Category link. Enter Background as your category name and Add it. Any new categories youadd are selected automatically. Notice that you can post a blog entry in multiplecategories at once. There are a few other options too. There are the settings for Discussion. We want to allow both comments and trackbacks, so keep both options checked. Scroll up and click on the Publish button on the right to make this post live. Click on View Post at the top left to see how your site looks at the moment. What just happened? We published a new blog post with WordPress! This was the first time we used WordPress, but we could accomplish everything we needed to post this entry just from one screen. This is an important thing. Many CMSs require that you set up categories and images separately. This means you have to know the system before you can use it! WordPress allows you to learn about the system while using it. All sections in the Add New Postpage are well-labeled. There are sufficient descriptions, and what is not needed is hidden by default. Our title automatically became a search engine friendly permalink for this post. We could format our text with a simple WYSIWYG editor. It was packed with features—spell check, full screen editing, and further formatting options via Kitchen Sink. The editor allowed advanced editing by switching to the HTML mode. Adding an image was very easy. Upload, set options, and insert. We could select a previously uploaded image from the gallery, too. We could enter keyword tags for a post quickly. Selecting a category and adding new categories was simple. We created a new category on the Add New Post page itself. WordPress is intelligent enough to understand that if we added a new category on a post page, we would want to use it for that post. So, it was selected automatically. Advance options were available, but were hidden by default. We could publish the post right away, or at a later date. WordPress could also keep history of all the revisions we make to a post, could preview the post, and would auto-save it frequently. WordPress looks easy and powerful so far. Let us look at how we can harness it further. Surviving blog jargon and benefitting from itBlogs have their own terminology. You may not have heard of trackbacks, pingbacks, tags, or permalinks. You can learn more about these terms from http://en.wikipedia.org/wiki/List_of_blogging_terms and http://www.dailyblogtips.com/the-bloggers-glossary/. Similarly, there are excellent features that blogs have—comments, aggregating content from other sources, ability to get updates via RSS feeds, and so on. I recommend you to go through these glossaries to learn more about blogs. Extending WordPress Managing content with WordPress seems easy. We want to see how easy is it to customize its design and extend its features. Let's begin with the action. Time for action-customizing the design Find some themes you like. You can browse through theme galleries at http://WordPress.org/extend/themes/ or Google WordPress themes. There are thousands of free and paid themes available for WordPress. Download some themes that you like. Unzip each theme's ZIP file. Each theme should create a new folder for itself. Upload all these folders to the wp-content/themes folder on your server. In WordPress, go to Admin  Appearance|. You should see new themes you uploaded in the Available Themes section. The page also lists the WordPress Classic andDefault themes. We have three new themes showing up. Click on one of the themes to see a live preview. This is how it will look. Review all themes. Activate the one you like the most by clicking on the Activate link at the top right in the preview window. We liked oriental and activated it. Our site now shows up just like the live preview. What just happened? We installed a new design theme for our WordPress blog. We downloaded three themes from the Web, unzipped them, and uploaded them to our WordPress themes folder. The themes showed up in WordPress admin. Clicking on a theme showed a live preview. This made our decision easy. We activated the theme we liked. That's how easy it was to change the design of our blog! If you recall, installing a new design was similar in Joomla!, except that Joomla! allowed us to upload a ZIP file using its administration interface itself. The tricky part in giving a new design to your site was shortlisting and selecting a design, not setting it up. Customizing the theme Consider the following theme editor in WordPress If you want to further customize your theme, you can do that. In fact, you have full control over how your site looks with WordPress. You can use Appearance | Editor to change individual theme files. We recommend making template customizations on a local installation of WordPress first.Once you get everything done according to your choice, you can upload the changed files to the theme's folder and activate it. WordPress widgets Widgets are content blocks that can be used in a theme. Search, RSS feeds, Blog Post Archives, Tag Cloud, and Recent Posts are some of the built-in widgets available in WordPress. You can turn them on or off independently, determine their position in the sidebar, and also change their settings. Go to the Appearance | Widgets page to take over the control of WordPress widgets. Add unlimited power with plug-ins Our Yoga Site needs a lot more than just the core content management. How can we achieve that with WordPress? And will it be wise to use WordPress for our Yoga Site? The WordPress plug-in architecture is solid. You will find hundreds of high-quality plug-ins from photo galleries to e-commerce. But remember that the core of WordPress is a blog engine, which chronologically displays content under set categories. It encourages sharing and contribution. Theoretically, you can customize WordPress to any need you have. But we recommend you to evaluate the most important features for your site and then decide whether you want to use WordPress as a base, or something else. I use WordPress for my blog and have a range of plug-ins installed. WordPress is painless, and it allows me to focus on the core goal of my blog—sharing knowledge. Take a look at the list of plug-ins on my blog at www.mehtanirav.com. You may have noticed a few plug-ins to handle comments and spam. Why would you need that? Well, because you will end up spending all your time removing spam comments from your system if you don't have them activated. Comment spam is a real pain with all blogs. Spammers have written spam-bots (automatic software) that keep posting junk comments on your blog. If you don't protect comment submission, your blog will soon be flooded with advertisements of pills you don't want to take and a lot of other things you don't want your visitors to attend to. Comment protection plug-ins are the first you should install. I use Akismet with Simple Math. Simple Math poses a simple mathematical question to the comment writer. A human can easily answer that. This takes care of most of the spam comments. Comments that pass through this test need to pass through Akismet. Askimet is an excellent spam-protection plug-in from the WordPress team. These two plug-ins kill almost 99.99% of spam comments on my blog. Once I am left with legitimate comments, I can go to WordPress's Admin | Comments, and Approve, Unapprove, Delete, or Mark as Spam all comments. The Edit Comments screen looks like the following screenshot:| WordPress is a superb choice for creating a blog. It can be used as a general-purpose CMS as well. We have covered most of the day-to-day operations with WordPress so far. Here are some additional resources for you.
Read more
  • 0
  • 1
  • 6214

article-image-getting-started-spring-python
Packt
10 Dec 2010
12 min read
Save for later

Getting started with Spring Python

Packt
10 Dec 2010
12 min read
Spring Python for Python developers You have already picked one of the most popular and technically powerful dynamic languages to develop software, Python. Spring Python makes it even easier to solve common problems encountered by Python developers every day. Exploring Spring Python's non-invasive nature Spring Python has a non-invasive nature, which means it is easy to adopt the parts that meet your needs, without rewriting huge blocks of code. For example, Pyro (http://pyro.sourceforge.net) is a 3rd party library that provides an easy way to make remote procedure calls. In order to demonstrate the Spring way of non-invasiveness, let's code a simple service, publish it as a web service using Pyro's API, and then publish it using Spring Python's wrapper around Pyro. This will show the difference in how Spring Python simplifies API access for us, and how it makes the 3rd party library easier to use without as much rework to our own code. First, let's write a simple service that parses out the parameters from a web request string: class ParamParser(object): def parse_web_parms(self, parm): return [tuple(p.split("=")) for p in parm.split("&")] Now we can write a simple, functional piece of code that uses our service in order to have a working version. parser = ParamParser() parser.parse_web_parms("pages=5&article=Spring_Python") This is just instantiating the ParamParser and accessing the function. To make this a useful internet service, it needs to be instantiated on a central server and should be configured to listen for calls from clients. The next step is to advertise it as a web service using the API of Pyro. This will make it reachable by multiple Pyro clients. To do this, we define a daemon which will host our service on port 9000 and initialize it. daemon = Pyro.core.Daemon(host="localhost", port="9000") Pyro.core.initServer() Next, we create a Pyro object instance to act as proxy to our service as well as an instance of our ParamParser. We configure the proxy to delegate all method calls to our service. pyro_proxy = Pyro.core.ObjBase() parser = ParamParser() pyro_proxy.delegateTo(parser) Finally, we register the pyro_proxy object with the daemon, and startup a listen-dispatch loop so that it's ready to handle requests: daemon.connect(pyro_proxy, "mywebservice") daemon.requestLoop(True) When we run this server code, an instance of our ParamParser will be created and advertised at PYROLOC://localhost:9000/mywebservice. To make this service complete, we need to create a Pyro client that will call into our service. The proxy seamlessly transfers Python objects over the wire using the Pyro library, in this case the tuple of request parameters. url_base = "PYROLOC://localhost:9000" client_proxy = Pyro.core.getProxyForURI( url_base + "/mywebservice") print client_proxy.parse_web_parms( "pages=5&article=Spring_Python") The Pyro library is easy to use. One key factor is how our ParamParser never gets tightly coupled to the Pyro machinery used to serve it to remote clients. However, it's very invasive. What if we had already developed a simple application on a single machine with lots of methods making use of our utility? In order to convert our application into a client-server application, we would have to rewrite it to use the Pyro client proxy pattern everywhere that it was called. If we miss any instances, we will have bugs that need to be cleaned up. If we had written automated tests, they would also have to be rewritten as well. Converting a simple, one-machine application into a multi-node application can quickly generate a lot of work. That is where Spring Python comes in. It provides a different way of creating objects which makes it easy for us to replace a local object with a remoting mechanism such as Pyro. Let's utilize Spring Python's container to create our parser and also to serve it up with Pyro. from springpython.config import PythonConfig from springpython.config import Object from springpython.remoting.pyro import PyroServiceExporter from springpython.remoting.pyro import PyroProxyFactory class WebServiceContainer(PythonConfig): def __init__(self): super(WebServiceContainer, self).__init__() @Object(lazy_init=True) def my_web_server(self): return PyroServiceExporter(service=ParamParser(), service_name="mywebservice", service_port=9000) @Object(lazy_init=True) def my_web_client(self): myService = PyroProxyFactory() myService.service_url="PYROLOC://localhost:9000/mywebservice" return myService With this container definition, it is easy to write both a server application as well as a client application. To spin up one instance of our Pyro server, we use the following code: from springpython.context import ApplicationContext container = ApplicationContext(WebServiceContainer()) container.get_object("my_web_server") The client application looks very similar. from springpython.context import ApplicationContext container = ApplicationContext(WebServiceContainer()) myService = container.get_object("my_web_client") myService.parse_web_parms("pages=5&article=Spring_Python") The Spring Python container works by containing all the definitions for creating key objects. We create an instance of the container, ask it for a specific object, and then use it. This easily looks like just as much (if not more) code than using the Pyro API directly. So why is it considered less invasive? Looking at the last block of code, we can see that we are no longer creating the parser or the Pyro proxy. Instead, we are relying on the container to create it for us. The Spring Python container decouples the creation of our parser, whether its for a local application, or if it uses Pyro to join them remotely. The server application doesn't know that it is being exported as a Pyro service, because all that information is stored in the WebServiceContainer. Any changes made to the container definition aren't seen by the server application code. The same can be said for the client. By putting creation of the client inside the container, we don't have to know whether we are getting an instance of our service or a proxy. This means that additional changes can be made inside the definition of the container of Spring Python, without impacting our client and server apps. This makes it easy to split the server and client calls into separate scripts to be run in separate instances of Python or on separate nodes in our enterprise. This demonstrates how it is possible to mix in remoting to our existing application. By using this pattern of delegating creation of key objects to the container, it is easy to start with simple object creation, and then layer on useful services such as remoting. Later in this book, we will also see how this makes it easy to add other services like transactions and security. Due to Spring Python's open ended design, we can easily create new services and add them on without having to alter the original framework. Adding in some useful templates In addition to the non-invasive ability to mix in services, Spring Python has several utilities that ease the usage of low level APIs through a template pattern. The template pattern involves capturing a logical flow of steps. What occurs at each step is customizable by the developer, while still maintaining the same overall sequence. One example where a template would be useful is for writing a SQL query. Coding SQL queries by hand using Python's database API (http://www.python.org/dev/peps/pep-0249) is very tedious. We must properly handle errors and harvest the results. The extra code involved with connecting things together and handling issues is commonly referred to as plumbing code. Let's look at the following code to see how Python's database API functions. The more plumbing code we have to maintain, the higher the cost. Having an application with dozens or hundreds of queries can become unwieldy, even cost prohibitive to maintain. Using Python's database API, we only have to write the following code once for setup. ### One time setup import MySQLdb conn = MySQLdb.connection(username="me", password"secret", hostname="localhost", db="springpython") Now let's use Python's database API to perform a single query. ### Repeated for every query cursor = conn.cursor() results = [] try: cursor.execute("""select title, air_date, episode_number, writer from tv_shows where name = %s""", ("Monty Python",)) for row in cursor.fetchall(): tvShow = TvShow(title=row[0], airDate=row[1], episodeNumber=row[2], writer=row[3]) results.append(tvShow) finally: try: cursor.close() except Exception: pass conn.close() return results   The specialized code we wrote to look up TV shows is contained in the execute statement and also the part that creates an instance of TvShow. The rest is just plumbing code needed to handle errors, manage the database cursor, and iterate over the results.   This may not look like much, but have you ever developed an application with just one SQL query? We could have dozens or even hundreds of queries, and having to repeatedly code these steps can become overwhelming. Spring Python's DatabaseTemplate lets us just inject the query string and and a row mapper to reduce the total amount of code that we need to write. We need a slightly different setup than before. """One time setup""" from springpython.database.core import * from springpython.database.factory import * connectionFactory = MySQLConnectionFactory(username="me", password="secret", hostname="localhost", db="springpython") We also need to define a mapping to generate our TvShow objects. class TvShowMapper(RowMapper): def map_row(self, row, metadata=None): return TvShow(title=row[0], airDate=row[1], episodeNumber=row[2], writer=row[3]) With all this setup, we can now create an instance of DatabaseTemplate and use it to execute the same query with a much lower footprint. dt = DatabaseTemplate(connectionFactory) """Repeated for each query""" results = dt.query("""select title, air_date, episode_number, writer from tv_shows where name = %s""", ("Monty Python",), TvShowMapper()) This example shows how we can replace 19 lines of code with a single statement using Spring Python's template solution. Object Relational Mappers (ORMs) have sprung up in response to the low level nature of ANSI SQL's protocol. Many applications have simple object persistence requirements and many of us would prefer working on code, and not database design. By having a tool to help do the schema management work, these ORMs have been a great productivity boost. But they are not necessarily the answer for every use case. Some queries are very complex and involve looking up information spread between many tables, or involve making complex calculations and involve decoding specific values. Also, many legacy systems are denormalized and don't fit the paradigm that ORMs were originally designed to handle. The complexity of these queries can require working around, or even against, the ORM-based solutions, making them not worth the effort. To alleviate the frustration of working with SQL, Spring Python's DatabaseTemplate greatly simplifies writing SQL, while giving you complete freedom in mapping the results into objects, dictionaries, and tuples. DatabaseTemplate can easily augment your application, whether or not you are already using an ORM. That way, simple object persistence can be managed with ORM, while complex queries can be handed over to Spring Python's DatabaseTemplate, resulting in a nice blend of productive, functional code. Other templates, such as TransactionTemplate, relieve you of the burden of dealing with the low level idioms needed to code transactions that makes them challenging to incorporate correctly. Later in this book, we will learn how easy it is to add transactions to our code both programmatically and declaratively. Applying the services you need and abstracting away low level APIs is a key part of the Spring way and lets us focus our time and effort on our customer's business requirements instead of our own technical ones. By using the various components we just looked at, it isn't too hard to develop a simple Pyro service that serves up TV shows from a relational database. from springpython.database.factory import * from springpython.config import * from springpython.remoting.pyro import * class TvShowMapper(RowMapper): def map_row(self, row, metadata=None): return (title=row[0], airDate=row[1], episodeNumber=row[2], writer=row[3]) class TvShowService(object): def __init__(self): self.connFactory = MySQLConnectionFactory(username="me", password="secret", hostname="localhost", db="springpython") self.dt = DatabaseTemplate(connFactory) def get_tv_shows(self): return dt.query("""select title, air_date, episode_number, writer from tv_shows where name = %s""", ("Monty Python",), TvShowMapper()) class TvShowContainer(PythonConfig): def __init__(self): super(TvShowContainer, self).__init__() @Object(lazy_init=True) def web_server(self): return PyroServiceExporter(service=TvShowService(), service_name="tvshows", service_port=9000) @Object(lazy_init=True) def web_client(self): myService = PyroProxyFactory() myService.service_url="PYROLOC://localhost:9000/tvshows" return myService if __name__ == "__main__": container = ApplicationContext(TvShowContainer()) container.get_object("web_server") By querying the database for TV shows and serving it up through Pyro, this block of code demonstrates how easy it is to use these powerful modules without mixing them together. It is much easier to maintain software over time when things are kept simple and separated. We just took a quick walk through SQL and Pyro and examined their low level APIs. Many low level APIs require a certain sequence of steps to properly utilize them. We just looked at a SQL query. The need for templates also exists with database transactions and LDAP calls. By capturing the flow of the API in a Spring Python template and allowing you to insert your custom code, you can get out of writing plumbing code and instead work on your application's business logic.
Read more
  • 0
  • 0
  • 6210
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-transformations-using-mapreduce
Packt
05 Feb 2015
19 min read
Save for later

Transformations Using Map/Reduce

Packt
05 Feb 2015
19 min read
In this article written by Adam Boduch, author of the book Lo-Dash Essentials, we'll be looking at all the interesting things we can do with Lo-Dash and the map/reduce programming model. We'll start off with the basics, getting our feet wet with some basic mappings and basic reductions. As we progress through the article, we'll start introducing more advanced techniques to think in terms of map/reduce with Lo-Dash. The goal, once you've reached the end of this article, is to have a solid understanding of the Lo-Dash functions available that aid in mapping and reducing collections. Additionally, you'll start to notice how disparate Lo-Dash functions work together in the map/reduce domain. Ready? (For more resources related to this topic, see here.) Plucking values Consider that as your informal introduction to mapping because that's essentially what it's doing. It's taking an input collection and mapping it to a new collection, plucking only the properties we're interested in. This is shown in the following example: var collection = [ { name: 'Virginia', age: 45 }, { name: 'Debra', age: 34 }, { name: 'Jerry', age: 55 }, { name: 'Earl', age: 29 } ]; _.pluck(collection, 'age'); // → [ 45, 34, 55, 29 ] This is about as simple a mapping operation as you'll find. In fact, you can do the same thing with map(): var collection = [ { name: 'Michele', age: 58 }, { name: 'Lynda', age: 23 }, { name: 'William', age: 35 }, { name: 'Thomas', age: 41 } ]; _.map(collection, 'name'); // → // [ // "Michele", // "Lynda", // "William", // "Thomas" // ] As you'd expect, the output here is exactly the same as it would be with pluck(). In fact, pluck() is actually using the map() function under the hood. The callback passed to map() is constructed using property(), which just returns the specified property value. The map() function falls back to this plucking behavior when a string instead of a function is passed to it. With that brief introduction to the nature of mapping, let's dig a little deeper and see what's possible in mapping collections. Mapping collections In this section, we'll explore mapping collections. Mapping one collection to another ranges from composing really simple—as we saw in the preceding section—to sophisticated callbacks. These callbacks that map each item in the collection can include or exclude properties and can calculate new values. Besides, we can apply functions to these items. We'll also address the issue of filtering collections and how this can be done in conjunction with mapping. Including and excluding properties When applied to an object, the pick() function generates a new object containing only the specified properties. The opposite of this function, omit(), generates an object with every property except those specified. Since these functions work fine for individual object instances, why not use them in a collection? You can use both of these functions to shed properties from collections by mapping them to new ones, as shown in the following code: var collection = [ { first: 'Ryan', last: 'Coleman', age: 23 }, { first: 'Ann', last: 'Sutton', age: 31 }, { first: 'Van', last: 'Holloway', age: 44 }, { first: 'Francis', last: 'Higgins', age: 38 } ]; _.map(collection, function(item) { return _.pick(item, [ 'first', 'last' ]); }); // → // [ // { first: "Ryan", last: "Coleman" }, // { first: "Ann", last: "Sutton" }, // { first: "Van", last: "Holloway" }, // { first: "Francis", last: "Higgins" } // ] Here, we're creating a new collection using the map() function. The callback function supplied to map() is applied to each item in the collection. The item argument is the original item from the collection. The callback is expected to return the mapped version of that item and this version could be anything, including the original item itself. Be careful when manipulating the original item in map() callbacks. If the item is an object and it's referenced elsewhere in your application, it could have unintended consequences. We're returning a new object as the mapped item in the preceding code. This is done using the pick() function. We only care about the first and the last properties. Our newly mapped collection looks identical to the original, except that no item has an age property. This newly mapped collection is seen in the following code: var collection = [ { first: 'Clinton', last: 'Park', age: 19 }, { first: 'Dana', last: 'Hines', age: 36 }, { first: 'Pete', last: 'Ross', age: 31 }, { first: 'Annie', last: 'Cross', age: 48 } ]; _.map(collection, function(item) { return _.omit(item, 'first'); }); // → // [ // { last: "Park", age: 19 }, // { last: "Hines", age: 36 }, // { last: "Ross", age: 31 }, // { last: "Cross", age: 48 } // ] The preceding code follows the same approach as the pick() code. The only difference is that we're excluding the first property from the newly created collection. You'll also notice that we're passing a string containing a single property name instead of an array of property names. In addition to passing strings or arrays as the argument to pick() or omit(), we can pass in a function callback. This is suitable when it's not very clear which objects in a collection should have which properties. Using a callback like this inside a map() callback lets us perform detailed comparisons and transformations on collections while using very little code: function invalidAge(value, key) { return key === 'age' && value < 40; } var collection = [ { first: 'Kim', last: 'Lawson', age: 40 }, { first: 'Marcia', last: 'Butler', age: 31 }, { first: 'Shawna', last: 'Hamilton', age: 39 }, { first: 'Leon', last: 'Johnston', age: 67 } ]; _.map(collection, function(item) { return _.omit(item, invalidAge); }); // → // [ // { first: "Kim", last: "Lawson", age: 40 }, // { first: "Marcia", last: "Butler" }, // { first: "Shawna", last: "Hamilton" }, // { first: "Leon", last: "Johnston", age: 67 } // ] The new collection generated by this code excludes the age property for items where the age value is less than 40. The callback supplied to omit() is applied to each key-value pair in the object. This code is a good illustration of the conciseness achievable with Lo-Dash. There's a lot of iterative code running here and there is no for or while statement in sight. Performing calculations It's time now to turn our attention to performing calculations in our map() callbacks. This entails looking at the item and, based on its current state, computing a new value that will be ultimately mapped to the new collection. This could mean extending the original item's properties or replacing one with a newly computed value. Whichever the case, it's a lot easier to map these computations than to write your own logic that applies these functions to every item in your collection. This is explained using the following example: var collection = [ { name: 'Valerie', jqueryYears: 4, cssYears: 3 }, { name: 'Alonzo', jqueryYears: 1, cssYears: 5 }, { name: 'Claire', jqueryYears: 3, cssYears: 1 }, { name: 'Duane', jqueryYears: 2, cssYears: 0 } ]; _.map(collection, function(item) { return _.extend({ experience: item.jqueryYears + item.cssYears, specialty: item.jqueryYears >= item.cssYears ? 'jQuery' : 'CSS' }, item); }); // → // [ // { // experience": 7, // specialty": "jQuery", // name": "Valerie", // jqueryYears": 4, // cssYears: 3 // }, // { // experience: 6, // specialty: "CSS", // name: "Alonzo", // jqueryYears: 1, // cssYears: 5 // }, // { // experience: 4, // specialty: "jQuery", // name: "Claire", // jqueryYears: 3, // cssYears: 1 // }, // { // experience: 2, // specialty: "jQuery", // name: "Duane", // jqueryYears: 2, // cssYears: 0 // } // ] Here, we're mapping each item in the original collection to an extended version of it. Particularly, we're computing two new values for each item—experience and speciality. The experience property is simply the sum of the jqueryYears and cssYears properties. The speciality property is computed based on the larger value of the jqueryYears and cssYears properties. Earlier, I mentioned the need to be careful when modifying items in map() callbacks. In general, it's a bad idea. It's helpful to try and remember that map() is used to generate new collections, not to modify existing collections. Here's an illustration of the horrific consequences of not being careful: var app = {}, collection = [ { name: 'Cameron', supervisor: false }, { name: 'Lindsey', supervisor: true }, { name: 'Kenneth', supervisor: false }, { name: 'Caroline', supervisor: true } ]; app.supervisor = _.find(collection, { supervisor: true }); _.map(collection, function(item) { return _.extend(item, { supervisor: false }); }); console.log(app.supervisor); // → { name: "Lindsey", supervisor: false } The destructive nature of this callback is not obvious at all and next to impossible for programmers to track down and diagnose. Its nature is essentially resetting the supervisor attribute for each item. If these items are used anywhere else in the application, the supervisor property value will be clobbered whenever this map job is executed. If you need to reset values like this, ensure that the change is mapped to the new value and not made to the original. Mapping also works with primitive values as the item. Often, we'll have an array of primitive values that we'd like transformed into an alternative representation. For example, let's say you have an array of sizes, expressed in bytes. You can map those arrays to a new collection with those sizes expressed as human-readable values, using the following code: function bytes(b) { var units = [ 'B', 'K', 'M', 'G', 'T', 'P' ], target = 0; while (b >= 1024) { b = b / 1024; target++; } return (b % 1 === 0 ? b : b.toFixed(1)) + units[target] + (target === 0 ? '' : 'B'); } var collection = [ 1024, 1048576, 345198, 120120120 ]; _.map(collection, bytes); // → [ "1KB", "1MB", "337.1KB", "114.6MB" ] The bytes() function takes a numerical argument, which is the number of bytes to be formatted. This is the starting unit. We just keep incrementing the target unit until we have something that is less than 1024. For example, the last item in our collection maps to '114.6MB'. The bytes() function can be passed directly to map() since it's expecting values in our collection as they are. Calling functions We don't always have to write our own callback functions for map(). Wherever it makes sense, we're free to leverage Lo-Dash functions to map our collection items. For example, let's say we have a collection and we'd like to know the size of each item. There's a size() Lo-Dash function we can use as our map() callback, as follows: var collection = [ [ 1, 2 ], [ 1, 2, 3 ], { first: 1, second: 2 }, { first: 1, second: 2, third: 3 } ]; _.map(collection, _.size); // → [ 2, 3, 2, 3 ] This code has the added benefit that the size() function returns consistent results, no matter what kind of argument is passed to it. In fact, any function that takes a single argument and returns a new value based on that argument is a valid candidate for a map() callback. For instance, we could also map the minimum and maximum value of each item: var source = _.range(1000), collection = [ _.sample(source, 50), _.sample(source, 100), _.sample(source, 150) ]; _.map(collection, _.min); // → [ 20, 21, 1 ] _.map(collection, _.max); // → [ 931, 985, 991 ] What if we want to map each item of our collection to a sorted version? Since we do not sort the collection itself, we don't care about the item positions within the collection, but the items themselves, if they're arrays, for instance. Let's see what happens with the following code: var collection = [ [ 'Evan', 'Veronica', 'Dana' ], [ 'Lila', 'Ronald', 'Dwayne' ], [ 'Ivan', 'Alfred', 'Doug' ], [ 'Penny', 'Lynne', 'Andy' ] ]; _.map(collection, _.compose(_.first, function(item) { return _.sortBy(item); })); // → [ "Dana", "Dwayne", "Alfred", "Andy" ] This code uses the compose() function to construct a map() callback. The first function returns the sorted version of the item by passing it to sortBy(). The first() item of this sorted list is then returned as the mapped item. The end result is a new collection containing the alphabetically first item from each array in our collection, with three lines of code. This is not bad. Filtering and mapping Filtering and mapping are two closely related collection operations. Filtering extracts only those collection items that are of particular interest in a given context. Mapping transforms collections to produce new collections. But what if you only want to map a certain subset of your collection? Then it would make sense to chain together the filtering and mapping operations, right? Here's an example of what that might look like: var collection = [ { name: 'Karl', enabled: true }, { name: 'Sophie', enabled: true }, { name: 'Jerald', enabled: false }, { name: 'Angie', enabled: false } ]; _.compose( _.partialRight(_.map, 'name'), _.partialRight(_.filter, 'enabled') )(collection); // → [ "Karl", "Sophie" ] This map is executed using compose() to build a function that is called right away, with our collection as the argument. The function is composed of two partials. We're using partialRight() on both arguments because we want the collection supplied as the leftmost argument in both cases. The first partial function is filter(). We're partially applying the enabled argument. So this function will filter our collection before it's passed to map(). This brings us to our next partial in the function composition. The result of filtering the collection is passed to map(), which has the name argument partially applied. The end result is a collection with enabled name strings. The important thing to note about the preceding code is that the filtering operation takes place before the map() function is run. We could have stored the filtered collection in an intermediate variable instead of streamlining with compose(). Regardless of flavor, it's important that the items in your mapped collection correspond to the items in the source collection. It's conceivable to filter out the items in the map() callback by not returning anything, but this is ill-advised as it doesn't map well, both figuratively and literally. Mapping objects The previous section focused on collections and how to map them. But wait, objects are collections too, right? That is indeed correct, but it's worth differentiating between the more traditional collections, arrays, and plain objects. The main reason is that there are implications with ordering and keys when performing map/reduce. At the end of the day, arrays and objects serve different use cases with map/reduce, and this article tries to acknowledge these differences. Now we'll start looking at some techniques Lo-Dash programmers employ when working with objects and mapping them to collections. There are a number of factors to consider such as the keys within an object and calling methods on objects. We'll take a look at the relationship between key-value pairs and how they can be used in a mapping context. Working with keys We can use the keys of a given object in interesting ways to map the object to a new collection. For example, we can use the keys() function to extract the keys of an object and map them to values other than the property value, as shown in the following example: var object = { first: 'Ronald', last: 'Walters', employer: 'Packt' }; _.map(_.sortBy(_.keys(object)), function(item) { return object[item]; }); // → [ "Packt", "Ronald", "Walters" ] The preceding code builds an array of property values from object. It does so using map(), which is actually mapping the keys() array of object. These keys are sorted using sortBy(). So Packt is the first element of the resulting array because employer is alphabetically first in the object keys. Sometimes, it's desirable to perform lookups in other objects and map those values to a target object. For example, not all APIs return everything you need for a given page, packaged in a neat little object. You have to do joins and build the data you need. This is shown in the following code: var users = {}, preferences = {}; _.each(_.range(100), function() { var id = _.uniqueId('user-'); users[id] = { type: 'user' }; preferences[id] = { emailme: !!(_.random()) }; }); _.map(users, function(value, key) { return _.extend({ id: key }, preferences[key]); }); // → // [ // { id: "user-1", emailme: true }, // { id: "user-2", emailme: false }, // ... // ] This example builds two objects, users and preferences. In the case of each object, the keys are user identifiers that we're generating with uniqueId(). The user objects just have some dummy attribute in them, while the preferences objects have an emailme attribute, set to a random Boolean value. Now let's say we need quick access to this preference for all users in the users object. As you can see, it's straightforward to implement using map() on the users object. The callback function returns a new object with the user ID. We extend this object with the preference for that particular user by looking at them by key. Calling methods Objects aren't limited to storing primitive strings and numbers. Properties can store functions as their values, or methods, as they're commonly referred. However, depending on the context where you're using your object, methods aren't always callable, especially if you have little or no control over the context where your objects are used. One technique that's helpful in situations such as these is mapping the result of calling these methods and using this result in the context in question. Let's see how this can be done with the following code: var object = { first: 'Roxanne', last: 'Elliot', name: function() { return this.first + ' ' + this.last; }, age: 38, retirement: 65, working: function() { return this.retirement - this.age; } }; _.map(object, function(value, key) { var item = {}; item[key] = _.isFunction(value) ? object[key]() : value return item; }); // → // [ // { first: "Roxanne" }, // { last: "Elliot" }, // { name: "Roxanne Elliot" }, // { age: 38 }, // { retirement: 65 }, // { working: 27 } // ] _.map(object, function(value, key) { var item = {}; item[key] = _.result(object, key); return item; }); // → // [ // { first: "Roxanne" }, // { last: "Elliot" }, // { name: "Roxanne Elliot" }, // { age: 38 }, // { retirement: 65 }, // { working: 27 } // ] Here, we have an object with both primitive property values and methods that use these properties. Now we'd like to map the results of calling those methods and we will experiment with two different approaches. The first approach uses the isFunction() function to determine whether the property value is callable or not. If it is, we call it and return that value. The second approach is a little easier to implement and achieves the same outcome. The result() function is applied to the object using the current key. This tests whether we're working with a function or not, so our code doesn't have to. In the first approach to mapping method invocations, you might have noticed that we're calling the method using object[key]() instead of value(). The former retains the context as the object variable, but the latter loses the context, since it is invoked as a plain function without any object. So when you're writing mapping callbacks that call methods and not getting the expected results, make sure the method's context is intact. Perhaps, you have an object but you're not sure which properties are methods. You can use functions() to figure this out and then map the results of calling each method to an array, as shown in the following code: var object = { firstName: 'Fredrick', lastName: 'Townsend', first: function() { return this.firstName; }, last: function() { return this.lastName; } }; var methods = _.map(_.functions(object), function(item) { return [ _.bindKey(object, item) ]; }); _.invoke(methods, 0); // → [ "Fredrick", "Townsend" ] The object variable has two methods, first() and last(). Assuming we didn't know about these methods, we can find them using functions(). Here, we're building a methods array using map(). The input is an array containing the names of all the methods of the given object. The value we're returning is interesting. It's a single-value array; you'll see why in a moment. The value of this array is a function built by passing the object and the name of the method to bindKey(). This function, when invoked, will always use object as its context. Lastly, we use invoke() to invoke each method in our methods array, building a new result array. Recall that our map() callback returned an array. This was a simple hack to make invoke() work, since it's a convenient way to call methods. It generally expects a key as the second argument, but a numerical index works just as well, since they're both looked up as same. Mapping key-value pairs Just because you're working with an object doesn't mean it's ideal, or even necessary. That's what map() is for—mapping what you're given to what you need. For instance, the property values are sometimes all that matter for what you're doing, and you can dispense with the keys entirely. For that, we have the values() function and we feed the values to map(): var object = { first: 'Lindsay', last: 'Castillo', age: 51 }; _.map(_.filter(_.values(object), _.isString), function(item) { return '<strong>' + item + '</strong>'; }); // → [ "<strong>Lindsay</strong>", "<strong>Castillo</strong>" ] All we want from the object variable here is a list of property values, which are strings, so that we can format them. In other words, the fact that the keys are first, last, and age is irrelevant. So first, we call values() to build an array of values. Next, we pass that array to filter(), removing anything that's not a string. We then pass the output of this to map, where we're able to map the string using <strong/> tags. The opposite might also be true—the value is completely meaningless without its key. If that's the case, it may be fitting to map key-value pairs to a new collection, as shown in the following example: function capitalize(s) { return s.charAt(0).toUpperCase() + s.slice(1); } function format(label, value) { return '<label>' + capitalize(label) + ':</label>' + '<strong>' + value + '</strong>'; } var object = { first: 'Julian', last: 'Ramos', age: 43 }; _.map(_.pairs(object), function(pair) { return format.apply(undefined, pair); }); // → // [ // "<label>First:</label><strong>Julian</strong>", // "<label>Last:</label><strong>Ramos</strong>", // "<label>Age:</label><strong>43</strong>" // ] We're passing the result of running our object through the pairs() function to map(). The argument passed to our map callback function is an array, the first element being the key and the second being the value. It so happens that the format() function expects a key and a value to format the given string, so we're able to use format.apply() to call the function, passing it the pair array. This approach is just a matter of taste. There's no need to call pairs() before map(). We could just as easily have called format directly. But sometimes, this approach is preferred, and the reasons, not least of which is the style of the programmer, are wide and varied. Summary This article introduced you to the map/reduce programming model and how Lo-Dash tools help realize it in your application. First, we examined mapping collections, including how to choose which properties get included and how to perform calculations. We then moved on to mapping objects. Keys can have an important role in how objects get mapped to new objects and collections. There are also methods and functions to consider when mapping. Resources for Article: Further resources on this subject: The First Step [article] Recursive directives [article] AngularJS Project [article]
Read more
  • 0
  • 0
  • 6209

article-image-play-framework-binding-and-validating-objects-and-rendering-json-output
Packt
03 Aug 2011
4 min read
Save for later

Play Framework: Binding and Validating Objects and Rendering JSON Output

Packt
03 Aug 2011
4 min read
Binding and validating objects using custom binders Read the Play documentation about binding and validating objects. As validation is extremely important in any application, it basically has to fulfill several tasks. First, it should not allow the user to enter wrong data. After a user has filled a form, he should get a positive or negative feedback, irrespective of whether the entered content was valid or not. The same goes for storing data. Before storing data you should make sure that storing it does not pose any future problems as now the model and the view layer should make sure that only valid data is stored or shown in the application. The perfect place to put such a validation is the controller. As a HTTP request basically is composed of a list of keys and values, the web framework needs to have a certain logic to create real objects out of this argument to make sure the application developer does not have to do this tedious task. You can find the source code of this example in the chapter2/binder directory. How to do it... Create or reuse a class you want created from an item as shown in the following code snippet: public class OrderItem { @Required public String itemId; public Boolean hazardous; public Boolean bulk; public Boolean toxic; public Integer piecesIncluded; public String toString() { return MessageFormat.format("{0}/{1}/{2}/{3}/{4}", itemId, piecesIncluded, bulk, toxic, hazardous); } } Create an appropriate form snippet for the index.xml template: #{form @Application.createOrder()} <input type="text" name="item" /><br /> <input type="submit" value="Create Order"> #{/form} Create the controller: public static void createOrder(@Valid OrderItem item) { if (validation.hasErrors()) { render("@index"); } renderText(item.toString()); } Create the type binder doing this magic: @Global public class OrderItemBinder implements TypeBinder<OrderItem> { @Override public Object bind(String name, Annotation[] annotations, String value, Class actualClass) throws Exception { OrderItem item = new OrderItem(); List<String> identifier = Arrays.asList(value.split("-", 3)); if (identifier.size() >= 3) { item.piecesIncluded = Integer.parseInt(identifier.get(2)); } if (identifier.size() >= 2) { int c = Integer.parseInt(identifier.get(1)); item.bulk = (c & 4) == 4; item.hazardous = (c & 2) == 2; item.toxic = (c & 1) == 1; } if (identifier.size() >= 1) { item.itemId = identifier.get(0); } return item; } } How it works... With the exception of the binder definition all of the preceding code has been seen earlier. By working with the Play samples you already got to know how to handle objects as arguments in controllers. This specific example creates a complete object out of a simple String. By naming the string in the form value (<input …name="item" />) the same as the controller argument name (createOrder(@Valid OrderItem item)) and using the controller argument class type in the OrderItemBinder definition (OrderItemBinder implements TypeBinder<OrderItem>), the mapping is done. The binder splits the string by a hyphen, uses the first value for item ID, the last for piìesIncluded, and checks certain bits in order to set some Boolean properties. By using curl you can verify the behavior very easily as shown: curl -v -X POST --data "item=Foo-3-5" localhost:9000/order Foo/5/false/true/true Here Foo resembles the item ID, 5 is the piecesIncluded property, and 3 is the argument means that the first two bits are set and so the hazardous and toxic properties are set, while bulk is not. There's more... The TypeBinder feature has been introduced in Play 1.1 and is documented at http://www.playframework.org/documentation/1.2/controllers#custombinding. Using type binders on objects Currently, it is only possible to create objects out of one single string with a TypeBinder. If you want to create one object out of several submitted form values you will have to create your own plugin for this as workaround. You can check more about this at: http://groups.google.com/group/play-framework/browse_thread/thread/62e7fbeac2c9e42d Be careful with JPA using model classes As soon as you try to use model classes with a type binder you will stumble upon strange behavior, as your objects will always only have null or default values when freshly instanced. The JPA plugin already uses a binding and overwrites every binding you are doing.
Read more
  • 0
  • 0
  • 6207

article-image-programming-php-nuke
Packt
13 Apr 2010
27 min read
Save for later

Programming PHP-Nuke

Packt
13 Apr 2010
27 min read
After a quick look at the file and folder structure of a module, we then begin creating a new module for PHP-Nuke. This module will allow items of content to be submitted for modules that do not support user-submitted content. In this article, we will code functionality for users to submit encyclopedia entries for administrator approval. However, this will not involve making any modifications to the Encyclopedia module, and can be extended to cover other modules as well. What Happens When a Page is Requested? Let's see what happens when a visitor wants to view an article on the site, and the process that PHP-Nuke goes through to construct the page containing this information. Viewing an article means that the visitor will be navigating to a page similar to this: http://localhost/nuke/modules.php?name=News&file=article&sid=1 The page requested by the visitor is modules.php, so let's have a look at that. Note that although there are many PHP files in the PHP-Nuke installation, there are only four files actually requested in the normal course of interaction with the site: index.php modules.php admin.php backend.php The other files in the PHP-Nuke installation are used by these files when required. Where Does PHP-Nuke Get Information From? PHP-Nuke is able to collect information about what module the visitor wants to see, what operation they want to perform, and details of the user from request variables coming from these places: The query string in the URL: The URL of the page holds information that tells PHP-Nuke which module to select, which part of the module to use, what item of content to show, and so on. The query string information is used to select the page from the system that needs to be shown to the visitor. Posted variables: When a user enters information in a form, and submits this back to the server, this information will be available to PHP-Nuke. This posted information is how PHP-Nuke gets input from the user to create items of content, enter terms to search for, and so on. Cookie variables: There is user account information stored in a cookie (and administrator account information if the user has such an account). This is used to identify the user, so they do not have to keep logging on every time they view a page or come to the site. When the user logs out, this information is deleted from the cookie. The information that PHP-Nuke gets from these sources has to be treated very carefully within the system. These sources are the only means through which visitors communicate with the site, and are also the channels through which hacks or attacks might be conducted on the site. The patches we applied in Article 2 while installing the system address precisely this issue, and they make sure that the data PHP-Nuke collects from a visitor is in exactly the right form for working with. Requesting a Page Once the modules.php page is requested, the first step followed is to include the mainfile.php file. This file does the following things: It checks and processes the request variables (namely the input to the application), to avoid possibly harmful tags, or other indicators of some form of SQL injection attack. It creates global variables for each request variable. It sets up a connection to the database. It gets the site configuration such as the site name, site logo, and so on, from the database. The mainfile.php file also contains a number of core functions such as checking if the user is logged in or is an administrator, choosing the blocks to display, and filtering text, among others. These will be used at different points in the creation of the page. After this file has been included, the next thing to happen in modules.php is that PHP-Nuke gets the requested module from the $name global variable, which corresponds to the name query string variable (as in modules.php?name=News), and checks if this module is active. If the module isn't active, and the visitor isn't an administrator, a 'Module Not Active' message is displayed, and the page output is done. If the module is active, then PHP-Nuke checks if the visitor has rights to access this module. PHP-Nuke checks to see if the access is restricted to a particular user group, and if so, is the user a member of that group? PHP-Nuke also checks if the module is for subscribers only, and if so, is the user a subscriber to the site? If the visitor doesn't have the right permissions to view the module, then a 'No Access' message is displayed, and the page output is done. If the module selected by the visitor is active, and they do have permission to view it, then PHP-Nuke can get on with passing control to that module. Control is passed to the selected module by attempting to include the index.php file in the folder of the selected module. However, if there is a file variable in the query string, then the file with that name is included instead. If these files can't be found, a 'Module Cannot Be Found' error is displayed to the visitor. Thus if the user requests a page like modules.php?name=News&file=article&sid=1, the article.php file in the News folder will be included by PHP-Nuke. If the user requests a page like modules.php?name=News&sid=1, then the index.php file in the News folder will be included. Attempting to request a page like modules.php?name=News&file=nosuchfile returns a page with a 'No such page' message, since there is no file called nosuchfile.php in the News folder. The 'No such page' message is generated by PHP-Nuke, since it's in control of the process. If the user has selected an active module for which they have view permission, and are requesting a page that is part of the module, then control passes to the module, and it's up to that module to do its work and create the page. We'll see how this works later in the article, but for now, our overview of how PHP-Nuke gets the page creation underway is complete. Seeing how PHP-Nuke works isn't particularly exciting, what is more exciting is seeing how we can extend the power of PHP-Nuke by creating new blocks and modules. Along the way, we'll see most of the components required for 'programming' with PHP-Nuke, and you'll get a good idea of how to go about your own development projects. Creating a Block Our development efforts begin with creating a File block. A File block is a PHP script that is stored in the blocks folder. It must have a filename of the form block-NAME.php, where NAME will be used by PHP-Nuke as the title for the block. The filename should not contain any spaces. The goal of a block is simple. It just has to create one variable, $content, that holds the content of the block. After that, the PHP-Nuke core will bring the theme into play to take care of displaying the block. The block we will create is a better version of the Dinosaur of the Day static HTML block we created in Article 4. The block will display the name of the Dinosaur of the Day, and a thumbnail image of the lucky lizard. However, on the next day, a different dinosaur will be chosen, and the block display will be updated. This is how the block works: We will create a database table to hold the date, the title of the dinosaur for that day, and a link to the thumbnail image of that dinosaur. We will create a text data file that will contain the name of a dinosaur and a link to its thumbnail image on each line. The data in this file will be the dinosaur pool from which the dinosaur of the day is chosen at random. When the block code is executed, it will look in the database table to see if there is any information for the current date. If there is, it will retrieve it and build the block output. If there is no information for the current date, the data from the text file will be loaded in. One of the entries in that file will be selected at random, and that data will be inserted into the database. This will become the Dinosaur of the Day. That data will then be used to create the block output. We will use the text file to hold the 'Dinosaur of the Day' candidates rather than a database table so that we do not have to create a separate administration feature to add these details. To add more dinosaurs to the list, we simply upload a new version of the text file. Make sure that you copy the dinosaur thumbnails from the code download into the imagesdinosaurstnails folder of your PHP-Nuke installation root. Time For Action—Creating the Database Table Open up phpMyAdmin in your web browser, and select the nuke database from the drop-down list in the left-hand panel. Click on the SQL tab, and enter the following code into the textbox, then click on Go. CREATE TABLE dinop_dinoportal_dotd (id INT( 10 ) NOT NULL AUTO_INCREMENT ,day VARCHAR( 16 ) NOT NULL ,title VARCHAR( 128 ) NOT NULL ,image VARCHAR( 250 ) NOT NULL ,PRIMARY KEY ( 'id' )) TYPE = MYISAM ; What Just Happened? We just created our database table. There is only one table needed, with a simple design. There are four fields in the table. The id field will hold an auto-incrementing unique numerical value and the other fields will hold the current date, the title of the dinosaur, and the link to the image of the dinosaur. Time For Action—Creating the Text File Open up your text editor, and enter the following: Tyrannosaurus Rex,images/dinosaurs/tnails/tyro.gifStegosaurus,images/dinosaurs/tnails/stego.gifTriceratops,images/dinosaurs/tnails/triceratops.gif Save this file as dotd_list.txt in the blocks folder. What Just Happened? The dotd_list.txt file will be the data source for choosing a new Dinosaur of the Day image. You will notice that we are storing the data here in the form 'name of the dinosaur', 'path to the image', so it will be easy to extract the information when we need it. Time For Action—Creating the Block Code Open up your text editor, and enter the following code into a blank file: <?phpif ( !defined('BLOCK_FILE') ){ Header("Location: ../index.php"); die();}global $prefix, $db;$today = date('d-m-Y');$sql = "SELECT * from ".$prefix."_dinoportal_dotd WHERE day='$today'";$result = $db->sql_query($sql);$content = "";$dino_title = "";$image = ""; $numrows = $db->sql_numrows($result); if ($numrows) { $row = $db->sql_fetchrow($result); $dino_title = $row['title']; $image = $row['image']; } else { $filename = "blocks/dotd_list.txt"; $possibles =@ file($filename); if ($possibles) { $choice = rand(1, count($possibles)); $imp = explode("," , $possibles[$choice-1]); $dino_title = $imp[0]; $image = $imp[1]; $sql = "INSERT INTO ".$prefix."_dinoportal_dotd(day,title,image) VALUES ('$today', '$dino_title', '$image')"; $result = $db->sql_query($sql); } $choice = rand(1, count($possibles)); $imp = explode("," , $possibles[$choice-1]); $dino_title = $imp[0]; $image = $imp[1]; }if ($dino_title){ $content = "Today's dinosaur is:<br><center><b>$dino_title</b><center><br>"; $content .= "<center><img src="$image" alt="$dino_title"></center><br>";}?> Save this file as block-DinosaurOfTheDay.php in the blocks folder of your PHP-Nuke installation. What Just Happened? We just entered the code for the Dinosaur of the Day block, and we'll step through it now. This first part of the code stops this file being requested directly by a visitor— the BLOCK_FILE constant is defined in mainfile.php, and without that constant being defined, the visitor would be redirected back to the homepage of the site. Block files are never requested directly by the visitor, they are included by PHP-Nuke. These first few lines of code are found in every block file: if ( !defined('BLOCK_FILE') ){ Header("Location: ../index.php"); die();} Now we can get started. First, we set ourselves to access some of the global variables of the application, and we will have our first look at the objects to access data from the database. The only global variables we need here are the ones for data access—$prefix, which holds the value of the database tables prefix, and $db, which is used to actually perform database operations. global $prefix, $db; Next, we grab today's date, formatted as digits like this 24-05-2005. $today = date('d-m-Y'); Now we set up the SQL statement to retrieve the information corresponding to this date from the database: $sql = "SELECT * from ".$prefix."_dinoportal_dotd WHERE day='$today'"; Now we execute the SQL statement: $result = $db->sql_query($sql); It is possible that there is no data corresponding to today's date, so we check the number of rows returned from this last query. If there are zero rows, there will be no information. $numrows = $db->sql_numrows($result); If there are some rows returned, we can start creating the block output. We use the sql_fetchrow() method to retrieve a row of data from the result of the query. This row is returned as an array, and we set some variables from the array. We'll only grab one row. If for some reason, there is more than one entry for today's date, we simply ignore the others. if ($numrows){ $row = $db->sql_fetchrow($result); $dino_title = $row['title']; $image = $row['image'];} Now we move on to the situation where there is no information for today's date, and we have to create it. The first thing we do is to read the contents of the dotd_list.txt file into an array—there will be one entry in the array for each line in the text file. However, we have to consider what will happen if there is some kind of problem reading the file. else{ $filename = "blocks/dotd_list.txt"; Note that the path to the file for the dodt_list.txt file is blocksdotd_list.txt. This may seem strange, since both this file and the block file are in the same blocks folder. However, PHP will be looking for this file from the executing script, which will be one of index.php, modules.php, or admin.php, all of which are outside the blocks folder. Thus we need to add the blocks folder in the path to the dotd_list.txt file. Now we try to grab the file itself: $possibles =@ file($filename); The file function opens the named file, and reads the input into an array called $possibles. The use of the @ character here will suppress any error messages—if there is a problem opening or reading the file, no untidy error messages will be displayed to the user, and execution can continue. Of course, if there is a problem reading the file then there will be a problem with $possibles. So we check this next—if there has been some problem reading the file then $possibles will be false: if ($possibles){ If there is something stored in $possibles, then this check will be passed, and we can proceed to choose one element from it at random. We choose a random number, between 1 and the number of lines in the text file. $choice = rand(1, count($possibles)); All we have to do now is choose that element from the array (we have to subtract one from the random number because the first element of the array is 0, rather than 1), and then split up that line to get at the title and the path to the image. $imp = explode("," , $possibles[$choice-1]);$dino_title = $imp[0];$image = $imp[1]; We split the line using the explode() function. The explode() function converts a string to an array by splitting it at certain characters. We will split the string at the ',' character, and we get an array with two entries. The first entry is the name of the dinosaur; the second is the path of the image. Now we have the details of our Dinosaur of the Day, we can add it to the database using an INSERT SQL statement. $sql = "INSERT INTO ".$prefix."_dinoportal_dotd(day,title,image) VALUES ('$today', '$dino_title', '$image')"; $result = $db->sql_query($sql); }} At this point, we should have a Dinosaur of the Day, one way or another, and so we can finalize the block output. However, we check the value of the $dino_title variable just in case there has been some problem either retrieving data or creating the new Dinosaur of the Day. If there has been a problem with either of these, there will be no value for the $dino_title variable, and if so, this code will ensure that the block content will remain empty, rather than producing some useless output. if ($dino_title){ $content = "Today's dinosaur is:<br><center><b>$dino_title</b><center><br>"; $content .= "<center><img src="$image" alt="$dino_title"></center><br>";} That's it, our block is complete! The key points of this block were the initial few lines that stopped the file from being requested directly, and this was also our first encounter with the data access code. Another thing to note from this example is the effort we made to ensure that the block output was only created if everything went smoothly. We suppressed errors when trying to read in a file, we checked that the reading of a file had actually given us some data, and then we didn't create any output if there was a problem with dino_title variable, which would be an indicator of some problem. All this means that if there is a problem, the visitor will not be confronted with lots of error messages, which could disturb the visitor and lead to a poor impression of your site, or even break the layout of the page, or reveal some information about your code that could be used against you. All that remains now is to set up this File block using the steps we saw in Article 4, and we are away! Data Access in PHP-Nuke In the code for creating the block we had a couple of lines with data access functions: $result = $db->sql_query($sql);$numrows = $db->sql_numrows($result);$row = $db->sql_fetchrow($result); PHP-Nuke uses a 'data abstraction layer', which means that you call functions against an object, which translates them into specific calls against the database of your choice. Generally, MySQL is the database used with PHP-Nuke, but you could choose another database server to power your site. A more pertinent advantage is that you don't need to use database-specific functions to access data in PHP-Nuke; you only need to learn about the functions of the data access object (You will still need to know some SQL to create queries that will be executed on the database). The code for the data access object is found in the file dbmysql.php. In fact, the db folder contains code for different types of database server, but this file is the one selected by default by PHP-Nuke for working with the MySQL database server. The data access object is a genuine object, that is, it's an instance of a class, sql_db in this case. Classes are one of the basics of object-oriented programming, but other than this instance PHP-Nuke does not make much use of object-oriented programming. A discussion of object-oriented programming in PHP is beyond the scope of this article series, and it won't particularly help here since PHP-Nuke makes so little use of it. All that we need to know is how to access the methods (functions) of the data access object. Object-oriented programming is covered in more detail in any book on PHP programming, and you can read an article about it at http://www.devarticles.com/c/a/PHP/Object-Oriented-Programming-in-PHP/. The data-access object provides a number of methods that you can use to execute a query, retrieve a row of data, check the number of rows returned by the query, or get the last inserted auto-increment field. Working with the object follows a similar process to the standard way of working with data in PHP using functions like mysql_query() or mysql_fetch_field(). To access data in PHP-Nuke, you will need two global variables, $prefix and $db. The $prefix variable holds the table prefix of the database tables, and this needs to be used in your SQL queries. The $db variable is the data access object itself. In our block example, we had these lines to create a SQL query and then execute it: $sql = "SELECT * from ".$prefix."_dinoportal_dotd WHERE day='$today'";$result = $db->sql_query($sql); Note the $db->sql_query() syntax. This syntax is used in PHP to call a method on an object, in this case the sql_query() method of the $db object. The sql_query() method executes an SQL query as its name suggests. You provide a string with the query that's to be executed as a parameter. Following the execution of a query, you can retrieve a row using the sql_fetchrow() method: $row = $db->sql_fetchrow($result); This method returns an array, and you can refer to the fields in the data using $row['fieldname'], as we do in the block example to get the title and image fields: $dino_title = $row['title'];$image = $row['image']; If you want to insert or update data, you need to create the relevant SQL query and then use the sql_query() function to do it: $sql = "INSERT INTO ".$prefix."_dinoportal_dotd(day,title,image) VALUES ('$today', '$dino_title', '$image')";$result = $db->sql_query($sql); This is only a small selection of the methods of the data access object. Another interesting one is the sql_nextid() method, which you can use after an INSERT statement to get the value of the last auto-increment field created. However, these are the methods that you will see the most of as you look around the code in PHP-Nuke. Module File and Folder Structure Before we get started creating a new module, let's have a look at the file structure of a typical module. A module is simply a collection of files (usually only PHP files) contained in a folder that goes in the modules folder in the root of the PHP-Nuke installation. The name of the folder is the name that PHP-Nuke will recognize the module by. However, we can't just place the files into the module folder in any order. There is an organization of files, subfolder names, and filenames that modules need to follow in order to function properly with PHP-Nuke. The image below shows the contents of the News module folder: We have already seen how PHP-Nuke switches between files in the module folder based on the value of the file query string variable. If there is no value for this variable, the index.php file of the module is used. Files that sit inside the module folder are the 'front-end' files, which will be used during a standard user's visit to the module. The code for the administration part of a module resides in the admin folder within the module folder. In earlier versions of PHP-Nuke (before 7.5), the administration code for any module would have to go into the admin folder (the one in the root of the PHP-Nuke installation), and would be mixed with the 'core' administration code. The decision to have a module's administration code contained within the module folder itself means that the module is much more self-contained, keeps people away from the core code itself, and generally makes the module easier to set up, install, and maintain. We'll see more about what is found in the admin folder when we create the administration area of our new module later in this article. We saw in Article 4 that the Language block allows you to change PHP-Nuke's user interface language. This ability to switch languages is something that has made PHP-Nuke so popular all around the world. This multi-language support is achieved by module developers avoiding coding any 'localizable' text into the module output. Localizable text is text that needs to be translated if a different interface language is selected. Instead of coding the text, PHP constants are used, with the values of the constants defined in a language file. The language files are found in the language folder of the module, and there is a separate language file for each language, each with a filename of the form lang-LANGUAGE.php. All PHP-Nuke needs to do is select the correct file based on the desired language. Creating a User Submissions Module Writing a new module allows you to extend PHP-Nuke to get it to do exactly what you want it to do. What we will do here is to create a general-purpose module that will allow users to submit content for modules that do not support user-submitted material. We'll call it UserSubmissions. It will work in the way the Submit News module works for stories: The user will submit the material through a form. The administrator will be notified of the new submission by email. The administrator will be able to see a list of the submitted material in the administration area, and can edit, delete, or approve the material to go into the database. The point of this module is that it does not touch the modules for which it allows the submission of content; everything will happen in the UserSubmissions module. In this article, we will only code in functionality for users to submit encyclopedia entries. It is straightforward to extend this to allow submissions for the Content module, or questions for the FAQ module. Conceptually what the module does is to: Present a form to the user similar to the one the administrator would use for entering an encyclopedia entry. Take the user's input and store it in a 'general' way in a single database table. After the administrator checks the input, the data is then stored in the encyclopedia's database tables using the same kind of code that the Encyclopedia module uses. We will see exactly what the 'general' way we store the data in is later. Basically, the module will take all the parts of the encyclopedia entry—the title, the text, the encyclopedia ID—and put them all together into one bundle, which can then be easily retrieved and broken out to form the individual pieces of data for the administrator to view, approve, or delete. Rather than presenting the development as a series of steps for you to follow, we will break the code up into various tasks, and then examine each piece of code or activity. You can type in the code as it is presented, although it is probably easiest to grab the example code for this module from the code download, and refer to it as we go. Module Development Steps The steps that we will follow to create the module are these: Create the module folder Create the database tables Code the front end (visitor view) of the module Adapt the code for multi-language support Set up module administration Code the administration area Rather unusually, we're going to start by coding the front end of the site. The reason this is unusual is that modules typically display some kind of data (that is what all the modules we have encountered in the article series do), and you would first need to enter this data into the database. This data is usually entered by the administrator, through the administration interface. With some example data in place, the front end of the site will be able to display it. It will be difficult to test the front end if it is supposed to display data and there is no data to display! This module does not require any existing data in the database to work. In fact, the data is entered by a standard visitor, and the administrator only has to look at this data, and edit or delete it. There is no facility in the administrator part of the module for the administrator to add new data into the module, which would rather defeat the point of this module! Thus we can start on the front end of the module quite happily. Let's start off with creating the module folder. Creating the Module Folder Create a new folder in the modules folder called UserSubmissions. This will be our module folder. Within this folder, create two new folders called admin and language. The admin folder will contain our administration code, and the language folder will contain the user interface language files. We create another folder, inside the admin folder, also called language. This folder will hold the language files for the module's administration interface. That's the first step out of the way, so let's move on to the database tables. Creating the Database Tables The module has only one database table. The table will be called <prefix>_usersubmissions. You can follow the same steps in phpMyAdmin as we did earlier for creating the block database table to create this table: CREATE TABLE dinop_usersubmissions ( id int(11) NOT NULL auto_increment, data text NOT NULL, parent_id int(11) NOT NULL default '0', type varchar(36) NOT NULL default '1', user_id int(11) NOT NULL default '0', date timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, title varchar(255) NOT NULL default '', user_name varchar(250) NOT NULL default '', PRIMARY KEY (id)) COMMENT='Table for holding user submitted content' ; Each row in this table will represent a single item of submitted content. The row will be identified by its id field. With only one table, you may be wondering how this module is going to be able to hold data from different modules. The answer is that the submitted data will be bundled up into a single object, then 'serialized' and stored in the data field. When the data is needed for viewing, it will be unbundled, and 'unserialized' back into a form that can be worked with. The 'title' of the submission will be stored in the title field. The type of module that we are storing data for will be held in the type field of the row. The details of the submitter will be stored in the user_id and user_name fields. We actually only use the user_name field in this version of the module, but we store both for future use. The date the item is submitted is held in the field called date. This field is a MySQL TIMESTAMP, and whenever a row is inserted, the current date and time will be inserted into the field automatically by the database, so we will not need to record the date and time ourselves. The final field is parent_id. Recall how an encyclopedia entry belongs to an Encyclopedia; a content page belongs to a Content category; a FAQ question belongs to a particular category, and so on. For each of these types of content, you needed to provide a 'parent' object that the content would belong to. That is where our parent_id field comes in. The ID of the parent object will be stored in this field. For an encyclopedia entry, this will be the ID of the chosen Encyclopedia.
Read more
  • 0
  • 0
  • 6188

article-image-data-manipulation-silverlight-4-data-grid
Packt
26 Apr 2010
9 min read
Save for later

Data Manipulation in Silverlight 4 Data Grid

Packt
26 Apr 2010
9 min read
Displaying data in a customized DataGrid Displaying data is probably the most straightforward task we can ask the DataGrid to do for us. In this recipe, we'll create a collection of data and hand it over to the DataGrid for display. While the DataGrid may seem to have a rather fixed layout, there are many options available on this control that we can use to customize it. In this recipe, we'll focus on getting the data to show up in the DataGrid and customize it to our likings. Getting ready In this recipe, we'll start from an empty Silverlight application. The finished solution for this recipe can be found in the Chapter04/Datagrid_Displaying_Data_Completed folder in the code bundle that is available on the Packt website. How to do it... We'll create a collection of Book objects and display this collection in a DataGrid. However,we want to customize the DataGrid. More specifically, we want to make the DataGridfixed. In other words, we don't want the user to make any changes to the bound data or move the columns around. Also, we want to change the visual representation of the DataGrid by changing the background color of the rows. We also want the vertical column separators to be hidden and the horizontal ones to get a different color. Finally, we'll hook into the LoadingRow event, which will give us access to the values that are bound to a row and based on that value, the LoadingRow event will allow us to make changes to the visual appearance of the row. To create this DataGrid, you'll need to carry out the following steps: Start a new Silverlight solution called DatagridDisplayingData in Visual Studio. We'll start by creating the Book class. Add a new class to the Silverlight project in the solution and name this class as Book. Note that this class uses two enumerations—one for the Category and the other for the Language. These can be found in the sample code. The following is the code for the Book class: public class Book { public string Title { get; set; } public string Author { get; set; } public int PageCount { get; set; } public DateTime PurchaseDate { get; set; } public Category Category { get; set; } public string Publisher { get; set; } public Languages Language { get; set; } public string ImageName { get; set; } public bool AlreadyRead { get; set; } } In the code-behind of the generated MainPage.xaml file, we need to create a generic list of Book instances (List) and load data into this collection.This is shown in the following code: private List<Book> bookCollection; public MainPage() { InitializeComponent(); LoadBooks(); } private void LoadBooks() { bookCollection = new List<Book>(); Book b1 = new Book(); b1.Title = "Book AAA"; b1.Author = "Author AAA"; b1.Language = Languages.English; b1.PageCount = 350; b1.Publisher = "Publisher BBB"; b1.PurchaseDate = new DateTime(2009, 3, 10); b1.ImageName = "AAA.png"; b1.AlreadyRead = true; b1.Category = Category.Computing; bookCollection.Add(b1); ... } Next, we'll add a DataGrid to the MainPage.xaml file. For now, we won't add any extra properties on the DataGrid. It's advisable to add it to the page by dragging it from the toolbox, so that Visual Studio adds the correct references to the required assemblies in the project, as well as adds the namespace mapping in the XAML code. Remove the AutoGenerateColumns="False" for now so that we'll see all the properties of the Book class appear in the DataGrid. The following line of code shows a default DataGrid with its name set to BookDataGrid: <sdk:DataGrid x_Name="BookDataGrid"></sdk:DataGrid> Currently, no data is bound to the DataGrid. To make the DataGrid show the book collection, we set the ItemsSource property from the code-behind in the constructor. This is shown in the following code: public MainPage() { InitializeComponent(); LoadBooks(); BookDataGrid.ItemsSource = bookCollection; } Running the code now shows a default DataGrid that generates a column for each public property of the Book type. This happens because the AutoGenerateColumns property is True by default. Let's continue by making the DataGrid look the way we want it to look. By default, the DataGrid is user-editable, so we may want to change this feature. Setting the IsReadOnly property to True will make it impossible for a user to edit the data in the control. We can lock the display even further by setting both the CanUserResizeColumns and the CanUserReorderColumns properties to False. This will prohibit the user from resizing and reordering the columns inside the DataGrid, which are enabled by default. This is shown in the following code: <sdk:DataGrid x_Name="BookDataGrid" AutoGenerateColumns="True" CanUserReorderColumns="False" CanUserResizeColumns="False" IsReadOnly="True"> </sdk:DataGrid> The DataGrid also offers quite an impressive list of properties that we can use to change its appearance. By adding the following code, we specify alternating the background colors (the RowBackground and AlternatingRowBackground properties), column widths (the ColumnWidth property), and row heights (the RowHeight property). We also specify how the gridlines should be displayed (the GridLinesVisibility and HorizontalGridLinesBrushs properties). Finally, we specify that we also want a row header to be added (the HeadersVisibility property ). <sdk:DataGrid x_Name="BookDataGrid" AutoGenerateColumns="True" CanUserReorderColumns="False" CanUserResizeColumns="False" RowBackground="#999999" AlternatingRowBackground="#CCCCCC" ColumnWidth="90" RowHeight="30" GridLinesVisibility="Horizontal" HeadersVisibility="All" HorizontalGridLinesBrush="Blue"> </sdk:DataGrid> We can also get a hook into the loading of the rows. For this, the LoadingRow event has to be used. This event is triggered when each row gets loaded. Using this event, we can get access to a row and change its properties based on custom code. In the following code, we are specifying that if the book is a thriller, we want the row to have a red background: private void BookDataGrid_LoadingRow(object sender, DataGridRowEventArgs e) { Book loadedBook = e.Row.DataContext as Book; if (loadedBook.Category == Category.Thriller) { e.Row.Background = new SolidColorBrush(Colors.Red); //It's a thriller! e.Row.Height = 40; } else { e.Row.Background = null; } } After completing these steps, we have the DataGrid that we wanted. It displays the data (including headers), fixes the columns and makes it impossible for the user to edit the data. Also, the color of the rows and alternating rows is changed, the vertical grid lines are hidden, and a different color is applied to the horizontal grid lines. Using the LoadingRow event, we have checked whether the book being added is of the "Thriller" category, and if so, a red color is applied as the background color for the row. The result can be seen in the following screenshot: How it works... The DataGrid allows us to display the data easily, while still offering us many customization options to format the control as needed. The DataGrid is defined in the System.Windows.Controls namespace, which is located in the System.Windows.Controls.Data assembly. By default, this assembly is not referenced while creating a new Silverlight application. Therefore, the following extra references are added while dragging the control from the toolbox for the first time: System.ComponentModel.DataAnnotations System.Windows.Controls.Data System.Windows.Controls.Data.Input System.Windows.Data While compiling the application, the corresponding assemblies are added to the XAP file (as can be seen in the following screenshot, which shows the contents of the XAP file). These assemblies need to be added because while installing the Silverlight plugin, they aren't installed as a part of the CLR. This is done in order to keep the plugin size small. However, when we use them in our application, they are embedded as part of the application. This results in an increase of the download size of the XAP file. In most circumstances, this is not a problem. However, if the file size is an important requirement, then it is essential to keep an eye on this. Also, Visual Studio will include the following namespace mapping into the XAML file: From then on, we can use the control as shown in the following line of code: <sdk:DataGrid x_Name="BookDataGrid"> </sdk:DataGrid> Once the control is added on the page, we can use it in a data binding scenario. To do so, we can point the ItemsSource property to any IEnumerable implementation. Each row in the DataGrid will correspond to an object in the collection. When AutoGenerateColumns is set to True (the default), the DataGrid uses a refl ection on the type of objects bound to it. For each public property it encounters, it generates a corresponding column. Out of the box, the DataGrid includes a text column, a checkbox column, and a template column. For all the types that can't be displayed, it uses the ToString method and a text column. If we want the DataGrid to feature automatic synchronization, the collection should implement the INotifyCollectionChanged interface. If changes to the objects are to be refl ected in the DataGrid, then the objects in the collection should themselves implement the INotifyPropertyChanged interface. There's more While loading large amounts of data into the DataGrid, the performance will still be very good. This is the result of the DataGrid implementing UI virtualization, which is enabled by default. Let's assume that the DataGrid is bound to a collection of 1,000,000 items (whether or not this is useful is another question). Loading all of these items into memory would be a time-consuming task as well as a big performance hit. Due to UI virtualization, the control loads only the rows it's currently displaying. (It will actually load a few more to improve the scrolling experience.) While scrolling, a small lag appears when the control is loading the new items. Since Silverlight 3, the ListBox also features UI virtualization. Inserting, updating, and deleting data in a DataGrid The DataGrid is an outstanding control to use while working with large amounts of data at the same time. Through its Excel-like interface, not only can we easily view the data, but also add new records or update and delete existing ones. In this recipe, we'll take a look at how to build a DataGrid that supports all of the above actions on a collection of items. Getting ready This recipe builds on the code that was created in the previous recipe. To follow along with this recipe, you can keep using your code or use the starter solution located in the Chapter04/Datagrid_Editing_Data_Starter folder in the code bundle available on the Packt website. The finished solution for this recipe can be found in the Chapter04/Datagrid_Editing_Data_Completed folder.
Read more
  • 0
  • 0
  • 6188
article-image-creating-web-templates-inkscape
Packt
04 Nov 2010
9 min read
Save for later

How to create web templates in Inkscape

Packt
04 Nov 2010
9 min read
Blogs and storefronts have some different elements when designing, however, they also have "pages" within them that use standard items, those that repeat over time. Blogs have posts that all have (at least): headings/titles content in the body options to comment Storefronts have some of the following: lists of items to purchase prices descriptions ratings/comments checkouts or shopping baskets And since these items are common on a number of the website pages, it can use templates for the design. You can create a site based on a template. Here are two quick examples based on each type of site. Designing for blogs Some common parts of many blog site are: the blog header or banner, a sidebar with recent posts (or archives), about section, recent posts, blog roll and/or links section, a main content section that will contain all of the blog posts, then links to their relevant comments, and a footer of the site. Of course you can get as fancy as you would like here, or as simple, but let's design a site based on these simple sections. Here's how it's done: Open Inkscape, and create a new document. From the file menu, select File, New, and Desktop_800x600. When open, create a new layer (Shift + Ctrl + N) and call it Basic Layout. Use the Rectangle Tool to draw rectangles for each of your layout areas in your blog design. For now, use different shades of gray for each area so you can easily distinguish between them at a glance. To change the fill color of a particular rectangle, left click the rectangle and choose a gray shade for the rectangle. Or drag the gray shade from the color palette onto the rectangle. Use sharp edged (not rounded) rectangles. If you need to change to sharp, click the Make Corners Sharp button in the Tool Controls Bar. Make sure your rectangle shapes do not have an outline or stroke. Use the Shift + Left click keypad shortcut to open the Stroke dialog and choose No Color (the icon with an X) to delete the stroke. Position the rectangles so there are no white spaces in-between them. From the main menu choose Object and then Align and Distribute. In the Remove Overlapssection, click the icon. This makes sure that the bounding boxes around each object don't over lap each other and place the objects tangent to each other. Use the Tool Controls Bar W (width): number fi eld to apply a setting of 800.0 px so the Header fills the entire width of the web page. Continue using the steps described to add rectangles for all areas shown below in the rough layout of the blog page we'll be creating. Once all of your areas are blocked out on the canvas, we'll need to convert the current rectangles into guides so we can use the guides when creating our web page layout graphics. We can easily keep the Basic Layout Export layer intact; we need to copy all of the rectangles in this layer. On the main menu, select Edit and then Select All (or use the keyboard shortcut keys Ctrl + A). Then select Edit and Duplicate (or use the keyboard shortcut Ctrl + D) to duplicate all of the elements in this layer. Now you are ready to convert these current shapes into guides. First, select all the rectangles in the top (duplicate) layout. Do this by clicking a rectangle and then holding the Shift key on your keypad. Then click/select the next rectangle. When you have all rectangles selected, from the main menu select Object and then Object to Guide. Your duplicate rectangles will be removed from the canvas and replaced with blue guides. To better see the guides, turn off the grid (from the main menu choose View and Grid) and hide the basic layout layer (click the eye icon). Create a new layer (Shift + Ctrl + N) called Background. Use the rectangle tool to draw a background that fills the entire canvas. Use the control bar, to set the width to 800 and the height to 600. Use the Color Palette to choose a fi ll color of white. In the Status bar, right-click the Stroke setting and select Remove Stroke. Create a new layer (Shift + Ctrl + N) called Header. Click the Create and Edit tool and enter the header title as shown in the following screenshot. Remember to use the control bar to adjust the font type and size. Then, still using the Create and Edit tool, type the sub-title as shown below and, again use the control bar to adjust the font type and size. Create a new layer (Shift + Ctrl + N) called Navigation. Now we need to import the icons that we have created. From the main menu, select File and then Import. Select the SVG file for the icon and then place it on the canvas. Repeat this until you have all five icons on the canvas. Use the rectangle tool to draw the horizontal bars below the title and then below the navigation icons. Use the Color Palette to choose a fill color for the rectangles. For our example, we're using a turquoise color. Select both rectangles, and then in the Status bar, right-click the Stroke setting and select Remove Stroke. With the rectangles still selected open the Align and Distribute dialog (Shift + Ctrl + A) and click the Center on Vertical Axis button. Select all of the icons and then open the Align and Distribute dialog (Shift + Ctrl + A) and click the Distribute Centers Equidistantly Horizontally button. Next we will create the sidebar content. Most of this will be the links to help with navigating to previous posts or static content—content that doesn't change. Create a new layer (Shift + Ctrl + N) called Sidebar. Import a photograph (File and then Import). Place it on the upper left side of the page. Use your guides to place it appropriately on the page. Select the Create and Edit tool, and drag it across your canvas in the area you want to add a block of text to create a textbox. Then start typing placeholder text for an author bio. Use the control bar to adjust font styles and sizes. Again use the guides for left alignment placement. Continue to use the Create and Edit to create any Headings and other text content on the left sidebar. Note that Inkscape does not support bullets or numbers. So any "bullets" will need to be created manually with dashes (-) or importing graphics. Your blog web page should look similar to the following screenshot: Now it is time to create the look of the content portion of the site—where the blog posts will appear. Create a new layer (Shift + Ctrl + N) called Blog Post. Just like with the sidebar text, use the Create and Edit text tool to create text and use the control bar to adjust fonts and sizes. Start with a heading. Then with the Create and Edit text tool selected, drag it across the screen to create a textbox. Add in dummy text or write some placeholder blog post. Again, use the control bar to adjust font and size of the text. Select the heading and the blog post text and align it within your guides. Or use the Align and Distribute dialog (Shift + Ctrl + A) to align items on the page correctly. Now it is time to create the comment, permalink and share this link text. Create a new layer (Shift + Ctrl + N) called Blog Post Footer. Again select the Create and Edit text tool, and type: comment | 0 comments | permalink | share this post. Use the control bar to adjust font and size as needed. Then use the color palette to change the text to red. If desired, use the rectangle tool to draw the horizontal bars to show a break between blog posts. Use the color palette to choose a fill color for the rectangles. For our example, we're using turquoise color. You can save the file, or add additional post examples. Use Steps 37 – 44 to do a second blog post. Your page should now look something like the following example: There will likely also be a sub-page of this content that will show an individual blog post. We can design that page, based on how we want it to look here. Finally, for this page, let's add blog footer with some copyright information to see a completed blog design. Create a new layer (Shift + Ctrl + N) called Footer. Select the horizontal bar under the navigation icon. From the main menu select Edit and then Duplicate. Select the duplicate rectangle and use the guides to place it at the footer area of your web page. Select the Create and Edit text tool and type a copyright attribution statement. In the following example we entered: © 2010 Jane Somebody | All rights reserved. Select both the rectangle in the footer and the copyright text and open the Align and Distribute dialog (Shift + Ctrl + A). Click the Center on Vertical Axis button to center the footer content. As stated in Step 46, there will also likely be a "sub-page" used in a blog to show each individual post as it's unique web address (if you want to link to the one blog post instead of the dynamic stream posts). Here's what this page would look like: As you can see, it looks very much like the main blog page, just without any posts before it, or after it. And in this case, we display the comments on this post directly instead of just making it a link. To modify the existing web page file to match the previous image, you would: Open the existing file in Inkscape. From the main menu select File and then Save a Copy. Give this a new file name. Delete any sample blog posts below the first one. Use the Create and Edit text tool to create the comments, headings, and text. Re-align all text appropriately with guides and the Align and Distribute dialog (Shift + Ctrl + A). Save the file again to save your work.
Read more
  • 0
  • 0
  • 6178

article-image-static-data-management
Packt
25 Feb 2015
29 min read
Save for later

Static Data Management

Packt
25 Feb 2015
29 min read
In this article by Loiane Groner, author of the book Mastering Ext JS, Second Edition, we will start implementing the application's core features, starting with static data management. What exactly is this? Every application has information that is not directly related to the core business, but this information is used by the core business logic somehow. There are two types of data in every application: static data and dynamic data. For example, the types of categories, languages, cities, and countries can exist independently of the core business and can be used by the core business information as well; this is what we call static data because it does not change very often. And there is the dynamic data, which is the information that changes in the application, what we call core business data. Clients, orders, and sales would be examples of dynamic or core business data. We can treat this static information as though they are independent MySQL tables (since we are using MySQL as the database server), and we can perform all the actions we can do on a MySQL table. (For more resources related to this topic, see here.) Creating a Model As usual, we are going to start by creating the Models. First, let's list the tables we will be working with and their columns: Actor: actor_id, first_name, last_name, last_update Category: category_id, name, last_update Language: language_id, name, last_update City: city_id, city, country_id, last_update Country: country_id, country, last_update We could create one Model for each of these entities with no problem at all; however, we want to reuse as much code as possible. Take another look at the list of tables and their columns. Notice that all tables have one column in common—the last_update column. All the previous tables have the last_update column in common. That being said, we can create a super model that contains this field. When we implement the actor and category models, we can extend the super Model, in which case we do not need to declare the column. Don't you think? Abstract Model In OOP, there is a concept called inheritance, which is a way to reuse the code of existing objects. Ext JS uses an OOP approach, so we can apply the same concept in Ext JS applications. If you take a look back at the code we already implemented, you will notice that we are already applying inheritance in most of our classes (with the exception of the util package), but we are creating classes that inherit from Ext JS classes. Now, we will start creating our own super classes. As all the models that we will be working with have the last_update column in common (if you take a look, all the Sakila tables have this column), we can create a super Model with this field. So, we will create a new file under app/model/staticData named Base.js: Ext.define('Packt.model.staticData.Base', {     extend: 'Packt.model.Base', //#1       fields: [         {             name: 'last_update',             type: 'date',             dateFormat: 'Y-m-j H:i:s'         }     ] }); This Model has only one column, that is, last_update. On the tables, the last_update column has the type timestamp, so the type of the field needs to be date, and we will also apply date format: 'Y-m-j H:i:s', which is years, months, days, hours, minutes, and seconds, following the same format as we have in the database (2006-02-15 04:34:33). When we can create each Model representing the tables, we will not need to declare the last_update field again. Look again at the code at line #1. We are not extending the default Ext.data.Model class, but another Base class (security.Base). Adapting the Base Model schema Create a file named Base.js inside the app/model folder with the following content in it: Ext.define('Packt.model.Base', {     extend: 'Ext.data.Model',       requires: [         'Packt.util.Util'     ],       schema: {         namespace: 'Packt.model', //#1         urlPrefix: 'php',         proxy: {             type: 'ajax',             api :{                 read : '{prefix}/{entityName:lowercase}/list.php',                 create:                     '{prefix}/{entityName:lowercase}/create.php',                 update:                     '{prefix}/{entityName:lowercase}/update.php',                 destroy:                     '{prefix}/{entityName:lowercase}/destroy.php'             },             reader: {                 type: 'json',                 rootProperty: 'data'             },             writer: {                 type: 'json',                 writeAllFields: true,                 encode: true,                 rootProperty: 'data',                 allowSingle: false             },             listeners: {                 exception: function(proxy, response, operation){               Packt.util.Util.showErrorMsg(response.responseText);                 }             }         }     } }); Instead of using Packt.model.security, we are going to use only Packt.model. The Packt.model.security.Base class will look simpler now as follows: Ext.define('Packt.model.security.Base', {     extend: 'Packt.model.Base',       idProperty: 'id',       fields: [         { name: 'id', type: 'int' }     ] }); It is very similar to the staticData.Base Model we are creating for this article. The difference is in the field that is common for the staticData package (last_update) and security package (id). Having a single schema for the application now means entityName of the Models will be created based on their name after 'Packt.model'. This means that the User and Group models we created will have entityName security.User, and security.Group respectively. However, we do not want to break the code we have implemented already, and for this reason we want the User and Group Model classes to have the entity name as User and Group. We can do this by adding entityName: 'User' to the User Model and entityName: 'Group' to the Group Model. We will do the same for the specific models we will be creating next. Having a super Base Model for all models within the application means our models will follow a pattern. The proxy template is also common for all models, and this means our server-side code will also follow a pattern. This is good to organize the application and for future maintenance. Specific models Now we can create all the models representing each table. Let's start with the Actor Model. We will create a new class named Packt.model.staticData.Actor; therefore, we need to create a new file name Actor.js under app/model/staticData, as follows: Ext.define('Packt.model.staticData.Actor', {     extend: 'Packt.model.staticData.Base', //#1       entityName: 'Actor', //#2       idProperty: 'actor_id', //#3       fields: [         { name: 'actor_id' },         { name: 'first_name'},         { name: 'last_name'}     ] }); There are three important things we need to note in the preceding code: This Model is extending (#1) from the Packt.model.staticData.Base class, which extends from the Packt.model.Base class, which in turn extends from the Ext.data.Model class. This means this Model inherits all the attributes and behavior from the classes Packt.model.staticData.Base, Packt.model.Base, and Ext.data.Model. As we created a super Model with the schema Packt.model, the default entityName created for this Model would be staticData.Actor. We are using entityName to help the proxy compile the url template with entityName. To make our life easier we are going to overwrite entityName as well (#2). The third point is idProperty (#3). By default, idProperty has the value "id". This means that when we declare a Model with a field named "id", Ext JS already knows that this is the unique field of this Model. When it is different from "id", we need to specify it using the idProperty configuration. As all Sakila tables do not have a unique field called "id"—it is always the name of the entity + "_id"—we will need to declare this configuration in all models. Now we can do the same for the other models. We need to create four more classes: Packt.model.staticData.Category Packt.model.staticData.Language Packt.model.staticData.City Packt.model.staticData.Country At the end, we will have six Model classes (one super Model and five specific models) created inside the app/model/staticData package. If we create a UML-class diagram for the Model classes, we will have the following diagram: The Actor, Category, Language, City, and Country Models extend the Packt.model.staticData Base Model, which extends from Packt.model.Base, which in turn extends the Ext.data.Model class. Creating a Store The next step is to create the storesfor each Model. As we did with the Model, we will try to create a generic Storeas well (in this article, will create a generic code for all screens, so creating a super Model, Store, and View is part of the capability). Although the common configurations are not in the Store, but in the Proxy(which we declared inside the schema in the Packt.model.Base class), having a super Store class can help us to listen to events that are common for all the static data stores. We will create a super Store named Packt.store.staticData.Base. As we need a Store for each Model, we will create the following stores: Packt.store.staticData.Actors Packt.store.staticData.Categories Packt.store.staticData.Languages Packt.store.staticData.Cities Packt.store.staticData.Countries At the end of this topic, we will have created all the previous classes. If we create a UML diagram for them, we will have something like the following diagram: All the Store classes extend from the Base Store. Now that we know what we need to create, let's get our hands dirty! Abstract Store The first class we need to create is the Packt.store.staticData.Base class. Inside this class, we will only declare autoLoad as true so that all the subclasses of this Store can be loaded when the application launches: Ext.define('Packt.store.staticData.Base', {     extend: 'Ext.data.Store',       autoLoad: true }); All the specific stores that we will create will extend this Store. Creating a super Store like this can feel pointless; however, we do not know that during future maintenance, we will need to add some common Store configuration. As we will use MVC for this module, another reason is that inside the Controller, we can also listen to Store events (available since Ext JS 4.2). If we want to listen to the same event of a set of stores and we execute exactly the same method, having a super Store will save us some lines of code. Specific Store Our next step is to implement the Actors, Categories, Languages, Cities, and Countries stores. So let's start with the Actors Store: Ext.define('Packt.store.staticData.Actors', {     extend: 'Packt.store.staticData.Base', //#1       model: 'Packt.model.staticData.Actor' //#2 }); After the definition of the Store, we need to extend from the Ext JS Store class. As we are using a super Store, we can extend directly from the super Store (#1), which means extending from the Packt.store.staticData.Base class. Next, we need to declare the fields or the model that this Store is going to represent. In our case, we always declare the Model (#2). Using a model inside the Store is good for reuse purposes. The fields configuration is recommended just in case we need to create a very specific Store with specific data that we are not planning to reuse throughout the application, as in a chart or a report. For the other stores, the only thing that is going to be different is the name of the Store and the Model. However, if you need the code to compare with yours or simply want to get the complete source code, you can download the code bundle from this book or get it at https://github.com/loiane/masteringextjs. Creating an abstract GridPanel for reuse Now is the time to implement the views. We have to implement five views: one to perform the CRUD operations for Actor, one for Category, one for Language, one for City, and one for Country. The following screenshot represents the final result we want to achieve after implementing the Actors screen: And the following screenshot represents the final result we want to achieve after implementing the Categories screen: Did you notice anything similar between these two screens? Let's take a look again: The top toolbar is the same (1); there is a Live Search capability (2); there is a filter plugin (4), and the Last Update and widget columns are also common (3). Going a little bit further, both GridPanels can be edited using a cell editor(similar to MS Excel capabilities, where you can edit a single cell by clicking on it). The only things different between these two screens are the columns that are specific to each screen (5). Does this mean we can reuse a good part of the code if we use inheritance by creating a super GridPanel with all these common capabilities? Yes! So this is what we are going to do. So let's create a new class named Packt.view.staticData.BaseGrid, as follows: Ext.define('Packt.view.staticData.BaseGrid', {     extend: 'Ext.ux.LiveSearchGridPanel', //#1     xtype: 'staticdatagrid',       requires: [         'Packt.util.Glyphs' //#2     ],       columnLines: true,    //#3     viewConfig: {         stripeRows: true //#4     },       //more code here });    We will extend the Ext.ux.LiveSearchGridPanel class instead of Ext.grid.Panel. The Ext.ux.LiveSearchGridPanel class already extends the Ext.grid.Panel class and also adds the Live Search toolbar (2). The LiveSearchGridPanel class is a plugin that is distributed with the Ext JS SDK. So, we do not need to worry about adding it manually to our project (you will learn how to add third-party plugins to the project later in this book). As we will also add a toolbar with the Add, Save Changes, Cancel Changes buttons, we need to require the util.Glyphs class we created (#2). The configurations #3 and #4 show the border of each cell of the grid and to alternate between a white background and a light gray background. Likewise, any other component that is responsible for displaying information in Ext JS, such as the "Panel" piece is only the shell. The View is responsible for displaying the columns in a GridPanel. We can customize it using the viewConfig (#4). The next step is to create an initComponent method. To initComponent or not? While browsing other developers' code, we might see some using the initComponent when declaring an Ext JS class and some who do not (as we have done until now). So what is the difference between using it and not using it? When declaring an Ext JS class, we usually configure it according to the application needs. They might become either a parent class for other classes or not. If they become a parent class, some of the configurations will be overridden, while some will not. Usually, we declare the ones that we expect to override in the class as configurations. We declare inside the initComponent method the ones we do not want to be overridden. As there are a few configurations we do not want to be overridden, we will declare them inside the initComponent, as follows: initComponent: function() {     var me = this;       me.selModel = {         selType: 'cellmodel' //#5     };       me.plugins = [         {             ptype: 'cellediting',  //#6             clicksToEdit: 1,             pluginId: 'cellplugin'         },         {             ptype: 'gridfilters'  //#7         }     ];       //docked items       //columns       me.callParent(arguments); //#8 } We can define how the user can select information from the GridPanel: the default configuration is the Selection RowModel class. As we want the user to be able to edit cell by cell, we will use the Selection CellModel class (#5) and also the CellEditing plugin (#6), which is part of the Ext JS SDK. For the CellEditing plugin, we configure the cell to be available to edit when the user clicks on the cell (if we need the user to double-click, we can change to clicksToEdit: 2). To help us later in the Controller, we also assign an ID to this plugin. To be able to filter the information (the Live Search will only highlight the matching records), we will use the Filters plugin (#7). The Filters plugin is also part of the Ext JS SDK. The callParent method (#8) will call initConfig from the superclass Ext.ux.LiveSearchGridPanel passing the arguments we defined. It is a common mistake to forget to include the callParent call when overriding the initComponent method. If the component does not work, make sure you are calling the callParent method! Next, we are going to declare dockedItems. As all GridPanels will have the same toolbar, we can declare dockedItems in the super class we are creating, as follows: me.dockedItems = [     {         xtype: 'toolbar',         dock: 'top',         itemId: 'topToolbar', //#9         items: [             {                 xtype: 'button',                 itemId: 'add', //#10                 text: 'Add',                 glyph: Packt.util.Glyphs.getGlyph('add')             },             {                 xtype: 'tbseparator'             },             {                 xtype: 'button',                 itemId: 'save',                 text: 'Save Changes',                 glyph: Packt.util.Glyphs.getGlyph('saveAll')             },             {                 xtype: 'button',                 itemId: 'cancel',                 text: 'Cancel Changes',                 glyph: Packt.util.Glyphs.getGlyph('cancel')             },             {                 xtype: 'tbseparator'             },             {                 xtype: 'button',                 itemId: 'clearFilter',                 text: 'Clear Filters',                 glyph: Packt.util.Glyphs.getGlyph('clearFilter')             }         ]     } ]; We will have Add, Save Changes, Cancel Changes, and Clear Filters buttons. Note that the toolbar (#9) and each of the buttons (#10) has itemId declared. As we are going to use the MVC approach in this example, we will declare a Controller. The itemId configuration has a responsibility similar to the reference that we declare when working with a ViewController. We will discuss the importance of itemId more when we declare the Controller. When declaring buttons inside a toolbar, we can omit the xtype: 'button' configuration since the button is the default component for toolbars. Inside the Glyphs class, we need to add the following attributes inside its config: saveAll: 'xf0c7', clearFilter: 'xf0b0' And finally, we will add the two columns that are common for all the screens (Last Update column and Widget Column delete (#13)) along with the columns already declared in each specific GridPanel: me.columns = Ext.Array.merge( //#11     me.columns,               //#12     [{         xtype    : 'datecolumn',         text     : 'Last Update',         width    : 150,         dataIndex: 'last_update',         format: 'Y-m-j H:i:s',         filter: true     },     {         xtype: 'widgetcolumn', //#13         width: 45,         sortable: false,       //#14         menuDisabled: true,    //#15         itemId: 'delete',         widget: {             xtype: 'button',   //#16             glyph: Packt.util.Glyphs.getGlyph('destroy'),             tooltip: 'Delete',             scope: me,                //#17             handler: function(btn) {  //#18                 me.fireEvent('widgetclick', me, btn);             }         }     }] ); In the preceding code we merge (#11) me.columns (#12) with two other columns and assign this value to me.columns again. We want all child grids to have these two columns plus the specific columns for each child grid. If the columns configuration from the BaseGrid class were outside initConfig, then when a child class declared its own columns configuration the value would be overridden. If we declare the columns configuration inside initComponent, a child class would not be able to add its own columns configuration, so we need to merge these two configurations (the columns from the child class #12 with the two columns we want each child class to have). For the delete button, we are going to use a Widget Column (#13) (introduced in Ext JS 5). Until Ext JS 4, the only way to have a button inside a Grid Column was using an Action Column. We are going to use a button (#16) to represent a Widget Column. Because it is a Widget Column, there is no reason to make this column sortable (#14), and we can also disable its menu (#15). Specific GridPanels for each table Our last stop before we implement the Controller is the specific GridPanels. We have already created the super GridPanel that contains most of the capabilities that we need. Now we just need to declare the specific configurations for each GridPanel. We will create five GridPanels that will extend from the Packt.view.staticData.BaseGrid class, as follows: Packt.view.staticData.Actors Packt.view.staticData.Categories Packt.view.staticData.Languages Packt.view.staticData.Cities Packt.view.staticData.Countries Let's start with the Actors GridPanel, as follows: Ext.define('Packt.view.staticData.Actors', {     extend: 'Packt.view.staticData.BaseGrid',     xtype: 'actorsgrid',        //#1       store: 'staticData.Actors', //#2       columns: [         {             text: 'Actor Id',             width: 100,             dataIndex: 'actor_id',             filter: {                 type: 'numeric'   //#3             }         },         {             text: 'First Name',             flex: 1,             dataIndex: 'first_name',             editor: {                 allowBlank: false, //#4                 maxLength: 45      //#5             },             filter: {                 type: 'string'     //#6             }         },         {             text: 'Last Name',             width: 200,             dataIndex: 'last_name',             editor: {                 allowBlank: false, //#7                 maxLength: 45      //#8             },             filter: {                 type: 'string'     //#9             }         }     ] }); Each specific class has its own xtype (#1). We also need to execute an UPDATE query in the database to update the menu table with the new xtypes we are creating: UPDATE `sakila`.`menu` SET `className`='actorsgrid' WHERE `id`='5'; UPDATE `sakila`.`menu` SET `className`='categoriesgrid' WHERE `id`='6'; UPDATE `sakila`.`menu` SET `className`='languagesgrid' WHERE `id`='7'; UPDATE `sakila`.`menu` SET `className`='citiesgrid' WHERE `id`='8'; UPDATE `sakila`.`menu` SET `className`='countriesgrid' WHERE `id`='9'; The first declaration that is specific to the Actors GridPanel is the Store (#2). We are going to use the Actors Store. Because the Actors Store is inside the staticData folder (store/staticData), we also need to pass the name of the subfolder; otherwise, Ext JS will think that this Store file is inside the app/store folder, which is not true. Then we need to declare the columns specific to the Actors GridPanel (we do not need to declare the Last Update and the Delete Action Column because they are already in the super GridPanel). What you need to pay attention to now are the editor and filter configurations for each column. The editor is for editing (cellediting plugin). We will only apply this configuration to the columns we want the user to be able to edit, and the filter (filters plugin) is the configuration that we will apply to the columns we want the user to be able to filter information from. For example, for the id column, we do not want the user to be able to edit it as it is a sequence provided by the MySQL database auto increment, so we will not apply the editor configuration to it. However, the user can filter the information based on the ID, so we will apply the filter configuration (#3). We want the user to be able to edit the other two columns: first_name and last_name, so we will add the editor configuration. We can perform client validations as we can do on a field of a form too. For example, we want both fields to be mandatory (#4 and #7) and the maximum number of characters the user can enter is 45 (#5 and #8). And at last, as both columns are rendering text values (string), we will also apply filter (#6 and #9). For other filter types, please refer to the Ext JS documentation as shown in the following screenshot. The documentation provides an example and more configuration options that we can use: And that is it! The super GridPanel will provide all the other capabilities. Summary In this article, we covered how to implement screens that look very similar to the MySQL Table Editor. The most important concept we covered in this article is implementing abstract classes, using the inheritance concept from OOP. We are used to using these concepts on server-side languages, such as PHP, Java, .NET, and so on. This article demonstrated that it is also important to use these concepts on the Ext JS side; this way, we can reuse a lot of code and also implement generic code that provides the same capability for more than one screen. We created a Base Model and Store. We used GridPanel and Live Search grid and filter plugin for the GridPanel as well. You learned how to perform CRUD operations using the Store capabilities. Resources for Article: Further resources on this subject: So, What Is EXT JS? [article] The Login Page Using EXT JS [article] Improving Code Quality [article]
Read more
  • 0
  • 0
  • 6168

article-image-handling-sessions-and-users
Packt
30 Aug 2013
4 min read
Save for later

Handling sessions and users

Packt
30 Aug 2013
4 min read
(For more resources related to this topic, see here.) Getting ready We will work from the app.py file from the sched directory and the models.py file. How to do it... Flask provides a session object, which behaves like a Python dictionary, and persists automatically across requests. You can, in your Flask application code: from flask import session# ... in a request ...session['spam'] = 'eggs'# ... in another request ...spam = session.get('spam') # 'eggs' Flask-Login provides a simple means to track a user in Flask's session. Update requirements.txt: FlaskFlask-LoginFlask-ScriptFlask-SQLAlchemyWTForms Then: $ pip install -r requirements.txt We can then load Flask-Login into sched's request handling, in app.py: from flask.ext.login import LoginManager, current_userfrom flask.ext.login import login_user, logout_userfrom sched.models import User# Use Flask-Login to track current user in Flask's session.login_manager = LoginManager()login_manager.setup_app(app)login_manager.login_view = 'login'@login_manager.user_loaderdef load_user(user_id):"""Flask-Login hook to load a User instance from ID."""return db.session.query(User).get(user_id) Flask-Login requires four methods on the User object, inside class User in models.py: def get_id(self):return str(self.id)def is_active(self):return Truedef is_anonymous(self):return Falsedef is_authenticated(self):return True Flask-Login provides a UserMixin (flask.ext.login.UserMixin) if you prefer to use its default implementation. We then provide routes to log the user in when authenticated and log out. In app.py: @app.route('/login/', methods=['GET', 'POST']) def login(): if current_user.is_authenticated(): return redirect(url_for('appointment_list')) form = LoginForm(request.form) error = None if request.method == 'POST' and form.validate(): email = form.username.data.lower().strip() password = form.password.data.lower().strip() user, authenticated = User.authenticate(db.session.query, email, password) if authenticated: login_user(user) return redirect(url_for('appointment_list')) else: error = 'Incorrect username or password.' return render_template('user/login.html', form=form, error=error) @app.route('/logout/') def logout(): logout_user() return redirect(url_for('login')) We then decorate every view function that requires a valid user, in app.py: from flask.ext.login import login_required@app.route('/appointments/')@login_requireddef appointment_list():# ... How it works... On login_user, Flask-Login gets the user object's ID from User.get_id and stores it in Flask's session. Flask-Login then sets a before_request handler to load the user instance into the current_user object, using the load_user hook we provide. The logout_user function then removes the relevant bits from the session. If no user is logged in, then current_user will provide an anonymous user object which results in current_user.is_anonymous() returning True and current_user. is_authenticated() returning False, which allows application and template code to base logic on whether the user is valid. (Flask-Login puts current_user into all template contexts.) You can use User.is_active to make user accounts invalid without actually deleting them, by returning False as appropriate. View functions decorated with login_required will redirect the user to the login view if the current user is not authenticated, without calling the decorated function. There's more... Flask's session supports display of messages and protection against request forgery. Flashing messages When you want to display a simple message to indicate a successful operation or a failure quickly, you can use Flask's flash messaging, which loads the message into the session until it is retrieved. In application code, inside request handling code: from flask import flashflash('Sucessfully did that thing.', 'success') In template code, where you can use the 'success' category for conditional display: {% for cat, m in get_flashed_messages(with_categories=true) %}<div class="alert">{{ m }}</div>{% endfor %} Cross-site request forgery protection Malicious web code will attempt to forge data-altering requests for other web services. To protect against forgery, you can load a randomized token into the session and into the HTML form, and reject the request when the two do not match. This is provided in the Flask-SeaSurf extension, pythonhosted.org/Flask-SeaSurf/ or the Flask-WTF extension (which integrates WTForms), pythonhosted.org/Flask-ETF/. Summary This article explained how to keep users logged in for on-going requests after authentication. It shed light on how Flask provides a session object, which behaves like a Python dictionary, and persists automatically across requests. It also spoke about coding in Flask application. We got acquainted with flashing messages and cross-site request forgery protection. Resources for Article: Further resources on this subject: Python Testing: Installing the Robot Framework [Article] Getting Started with Spring Python [Article] Creating Skeleton Apps with Coily in Spring Python [Article]
Read more
  • 0
  • 0
  • 6165
article-image-getting-started-impressive-presentations
Packt
25 Mar 2013
8 min read
Save for later

Getting Started with Impressive Presentations

Packt
25 Mar 2013
8 min read
(For more resources related to this topic, see here.) What is impress.js? impress.js is a presentation framework build upon the powerful CSS3 transformations and transitions on modern web browsers. Bartek Szopka is the creator of this amazing framework. According to the creator, the idea came to him while he was playing with CSS transformations. Prezi.com was the source that got him inspired. On w3.org we have the following mentioned about CSS transforms: CSS transforms allows elements styled with CSS to be transformed in twodimensional or three-dimensional space For more information on CSS transformations for those who are interested, visit http://www.w3.org/TR/css3-transforms/. Creating presentations with impress.js is not a difficult task once you get used to the basics of the framework. Slides in impress.js presentations are called steps and they go beyond the conventional presentation style. We can have multiple steps visible at the same time with different dimensions and effects. impress.js step designs are built upon HTML. This means we can create unlimited effects and the only limitation is your imagination. Built-in features impress.js comes with advanced support for most CSS transformations. We can combine these features to provide more advanced visualizations in modern browsers. These features are as follows: Positioning: Elements can be placed in certain areas of the browser window enabling us to move between slides. Scaling: Elements can be scaled up or scaled down to show an overview or a detailed view of elements. Rotating: Elements can be rotated across any given axis. Working on 3D space: Presentations are not limited to 2D space. All the previously mentioned effects can be applied to 3D space with the z axis. Beyond presentations with impress.js This framework was created to build online presentations with awesome effects with the power of CSS and JavaScript. Bartek, who is the creator of this framework, mentions that it has been used for various different purposes expanding the original intention. Here are some of the most common usages of the impress.js framework: Creating presentations Portfolios Sliders Single page websites List of demos containing various types of impress.js presentations can be found at https://github.com/bartaz/impress.js/wiki/Examples-and-demos. Why is it important? You must be wondering why we need to care about such a framework when we have quality presentation programs such as PowerPoint. The most important thing we need to look at is the license for impress.js. Since it is licensed under MIT and GPL we can even change the source codes to customize the framework according to our needs. Also most of the modern browsers support CSS transformations, allowing you to use impress.js, eliminating the platform dependency of presentation programs. Both desktop-based presentations and online presentations are equally good at presenting information to the audience, but online presentations with impress.js provide a slight advantage over desktop-based presentations in terms of usability. The following are some of the drawbacks of desktop program generated presentations, compared to impress.js presentations: Desktop presentations require a presentation creation software or presentation viewer. Therefore, it's difficult to get the same output in different operating systems. Desktop presentations use standard slide-based techniques with a common template, while impress.js presentation slides can be designed in a wide range of ways. Modifications are difficult in desktop-based presentations since it requires presentation creation software. impress.js presentations can be changed instantly by modifying the HTML content with a simple text editor. Creating presentations is not just about filling our slides with a lot of information and animations. It is a creative process that needs to be planned carefully. Best practices will tell us that we should keep the slides as simple as possible with very limited information and, letting presenter do the detailed explanations. Let's see how we can use impress.js to work with some well-known presentation design guidelines. Presentation outline The audience does not have any idea about the things you are going to present prior to the start of the presentation. If your presentation is not up to standard, the audience will wonder how many boring slides are to come and what the contents are going to be. Hence, it's better to provide a preliminary slide with the outline of your presentation. A limited number of slides and their proper placement will allow us to create a perfect outline of the presentation. Steps in impress.js presentations are placed in 3D space and each slide is positioned relatively. Generally, we will not have an idea about how slides are placed when the presentation is on screen. You can zoom in on the steps by using the scaling feature of impress.js. In this way, we can create additional steps containing the overview of the presentation by using scaling features. Using bullet points People prefer to read the most important points articles rather than huge chunks of text . It's wise to put these brief points on the slides and let the details come through your presenting skills. Since impress.js slides are created with HTML, you can easily use bullet points and various types of designs for them using CSS. You can also create each point as a separate step allowing you to use different styles for each point. Animations We cannot keep the audience interested just by scrolling down the presentation slides . Presentations need to be interactive and animations are great for getting the attention of the audience. Generally, we use animations for slide transitions. Even though presentation tools provide advanced animations, it's our responsibility to choose the animations wisely. impress.js provides animation effects for moving, rotating, and scaling step transitions. We have to make sure it is used with purpose. Explaining the life cycle of a product or project is an excellent scenario for using rotation animations. So choose the type of animation that suits your presentation contents and topic. Using themes Most people like to make the design of their presentation as cool as possible. Sometimes they get carried away and choose from the best themes available in the presentation tool. Themes provided by tools are predefined and designed to suit general purposes. Your presentation might be unique and choosing an existing theme can ruin the uniqueness. The best practice is to create your own themes for your presentations. impress.js does not come with built-in themes. Hence there is no other option than to create a new theme from scratch. impress.js steps are different to each other unlike standard presentations, so you have the freedom to create a theme or design for each of the steps just by using some simple HTML and CSS code. Apart from the previous points, we can use typography, images, and videos to create better designs for impress.js presentations. We have covered the background and the importance for impress.js. Now we can move on to creating real presentations using the framework throughout the next few sections. Downloading and configuring impress.js You can obtain a copy of the impress.js library by downloading from the github page at https://github.com/bartaz/impress.js/. The downloaded .zip file contains an example demo and necessary styles in addition to the impress.js file. Extract the .zip file on to your hard drive and load the index.html on the browser to see impress.js in action. The folder structure of the downloaded .zip file is as given in the following screenshot: Configuring impress.js is something you should be able to do quite easily. I'll walk you through the configuration process. First we have to include the impress.js file in the HTML file. It is recommended you load this file as late as possible in your document. Create a basic HTML using the following code: <!doctype html> <html lang="en"> <head> <title>impress.js </title> </head> <body> <script src = "js/impress.js"></script> </body> </html> We have linked the impress.js file just before the closing body tag to make sure it is loaded after all the elements in our document. Then we need to initialize the impress library to make the presentations work. We can place the following code after the impress.js file to initialize any existing presentation in the document which is compatible with the impress library: <script>impress(). init();</script> Since we have done the setup of the impress.js library, we can now create our impressive presentation. Summary In this article we looked at the background of the impress.js framework and how it was created. Then we talked about the importance of impress.js in creating web-based presentations and various types of usage beyond presentations. Finally we obtained a copy of the framework from the official github page and completed the setup. Resources for Article : Further resources on this subject: 3D Animation Techniques with XNA Game Studio 4.0 [Article] Enhancing Your Math Teaching using Moodle 1.9: Part 1 [Article] Your First Page with PHP-Nuke [Article]
Read more
  • 0
  • 0
  • 6153

article-image-menus-toolbars-and-buttons-ext-js-32
Packt
13 Oct 2010
8 min read
Save for later

Menus, Toolbars, and Buttons in Ext JS 3.2

Packt
13 Oct 2010
8 min read
  Learning Ext JS 3.2 Build dynamic, desktop-style user interfaces for your data-driven web applications using Ext JS Learn to build consistent, attractive web interfaces with the framework components Integrate your existing data and web services with Ext JS data support Enhance your JavaScript skills by using Ext's DOM and AJAX helpers Extend Ext JS through custom components An interactive tutorial packed with loads of example code and illustrative screenshots         What's on the menu? We will begin by introducing the Menu class which will be used in all following examples. We are going to demonstrate usage of the Menu class as both a static component within a page, and as a popup. Both menus will be configured with the same options by using a technique where we define a variable called menuItems to reference an array which specifies the menu's items, and use it in both cases. The Menu class inherits from Container, so any menu options are child Components specified in the items config. It also inherits the usual Component config options such as renderTo, and the width option. The static menu will be rendered to the document body, and in order for it to be rendered as a visible, static element in the document, we configure it with floating: false. So the configuration we end up with is as follows: new Ext.menu.Menu({ renderTo: document.body, width: 150, floating: false, items: menuItems }); The popup menu needs no extra configuring aside from its items. We do need to decide when and where to display it. In this case we will add a contextmenu (right click) event listener to the document, and show the menu at the mouse event's position: var contextMenu = new Ext.menu.Menu({ items: menuItems }); Ext.getDoc().on({ contextmenu: function(eventObj) { contextMenu.showAt(eventObj.getXY()); }, stopEvent: true }); When we run this example, the static menu will be visible. When we right click on the document, the result should be the two menus shown below. Notice how only the second, popup menu has a shadow to indicate that it floats above the document. The menu's items The menuItems variable references an array which should be familiar by now. Just like the items config of a FormPanel, it's a list of child Components or config objects. In a menu, a config object with no xtype creates a MenuItem Component. The MenuItem class accepts the following config options in addition to those it inherits: icon: The URL of an image to display as an icon iconCls: A CSS class name which allows a stylesheet to specify a background image to use as an icon text: The text to display handler: A function to call when the item is clicked menu: A Menu object, or Menu configuration object or an array of menu items to display as a submenu when the item is clicked Because a menu inherits from Container, it can accept other Components as child items. If some complex, menu option dependent input is required, a menu may be configured with a panel as a child item. The menu config of "Menu Option 2" we're creating next contains a FormPanel as its sole child item: { text: 'Menu Option 2', iconCls: 'flag-green', menu: { plain: true, items: { xtype: 'form', border: false, bodyStyle: 'background:transparent;padding:5px', labelWidth: 70, width: 300, defaults: { anchor: '100%' }, items: [{ xtype: 'combo', editable: false, fieldLabel: 'Select', triggerAction: 'all', store: [ [0, 'One or...'], [1 ,'The other']], value: 0, getListParent: function() { return this.el.up('div.x-menu'); } }, { xtype: 'textfield', fieldLabel: 'Title' }], fbar: [{ text: 'Submit' }] } } } The configurations in the above object will mostly be familiar by now. There is one extra config we use for the menu which contains the FormPanel. plain: Specify as true so that the menu does not have to show the incised line for separating icons from text The panel within the menu has the following configs: border: Specify as false to produce a panel with no borders. bodyStyle: A CSS style string to apply to the document body. We want to make it transparent to allow the menu to show, and we apply padding. The ComboBox must render its dropdown list to the menu's element so that clicking on the list does not trigger the menu to hide: GetListParent: This is a function which a ComboBox may be configured with. It must return the HTML element to render the dropdown list into. By default a ComboBox renders its dropdown into the document. We call the up function of the Ext.Element class to find the ancestor node of the combo's element which is a DIV which has the CSS class "x-menu". The FormPanel as a child of a menu will display like this: A toolbar for every occasion An Ext JS Panel, and every Ext JS Component which inherits from the Panel class (This includes Window, TreePanel, and GridPanel) can be configured to render and manage a toolbar docked above, or below the panel's body—or both if really necessary. These are referred to as the top and bottom toolbars, or tbar and bbar for short. Panels and subclasses thereof may also be configured with a footer bar which renders buttons right at the bottom of the panel—below any bottom toolbar. The Toolbar class is also an Ext JS Component in its own way, and may when necessary be used on its own, or as a child Component of any Container. Our second example renders a toolbar standalone into the body of the document. We will use all the main button types to illustrate their usage before moving on to add handlers to react to user interaction. The toolbar will contain the following child components: A basic button A button configured with a menu which is displayed when the button is clicked A SplitButton which will display a menu only when its arrow glyph is clicked A CycleButton which on click, cycles between three different options A pair of mutually exclusive toggle buttons of which only one may be in a "pressed" state at once Ext.onReady(function(){ new Ext.Toolbar({ renderTo: Ext.getBody(), items: [{ xtype: 'button', text: 'Button' },{ xtype: 'button', text: 'Menu Button', menu: [{ text: 'Better' },{ text: 'Good' },{ text: 'Best' }] },{ xtype: 'splitbutton', text: 'Split Button', menu: [{ text: 'Item One' },{ text: 'Item Two' },{ text: 'Item Three' }] }, { xtype: 'cycle', showText: true, minWidth: 100, prependText: 'Quality: ', items: [{ text: 'High', checked: true }, { text: 'Medium' }, { text: 'Low' }] }, { text: 'Horizontal', toggleGroup: 'orientation-selector' }, { text: 'Vertical', toggleGroup: 'orientation-selector' }] }); }); As usual, everything is inside our onReady event handler. The items config holds our toolbar's entire child Components—I say child Components and not buttons because as we now know, the toolbar can accept many different types of Ext JS Components including entire forms or just form fields—which we will be implementing later on in this article. The result of the above code looks like this: The default xtype for each element in the items config is button. We can leave out the xtype config element if button is the type we want, but I like to include it just for clarity. Button configuration In addition to inherited config options, a button accepts the following configurations which we will be using in the following examples for this article: icon: The URL of an image to display as an icon iconCls: A CSS class name which allows a stylesheet to specify a background image to use as an icon text: The text to display handler: A function to call when the button is clicked menu: A Menu object, or Menu configuration object, or an array of menu items to display as a submenu when the button is clicked enableToggle: Specify as true to make a single button toggleable between pressed and unpressed state toggleGroup: A mnemonic string identifying a group of buttons of which only one may be in a "pressed" state at one time toggleHandler: A function to be called when a button's "pressed" state is changed A basic button Creating a button is fairly straightforward; the main config option is the text that is displayed on the button. We can also add an icon to be used alongside the text if we want to. A handler function is called when the button is clicked. Here is the most basic configuration of a button: { xtype: 'button', text: 'Button', handler: functionReference } The following screenshot shows what happens when the mouse is hovered over the Button button: Button with a menu A button may be configured to act as a trigger for showing a dropdown menu. If configured with a menu option, clicking the button displays a menu below the button. The alignment of the menu is configurable, but defaults to being shown below the button. Each option within the menu may itself be configured with a menu option allowing a familiar cascading menu system to be built very easily. The following is a config for a button which displays a dropdown menu upon click: { xtype: 'button', text: 'Button', menu: [{ text: 'Better' },{ text: 'Good' },{ text: 'Best' }] } The following screenshot shows what happens when the Menu Button is clicked on, and the mouse is hovered over the Best option:
Read more
  • 0
  • 0
  • 6148
Modal Close icon
Modal Close icon