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-making-ajax-requests-yui
Packt
10 Jan 2011
5 min read
Save for later

Making Ajax Requests with YUI

Packt
10 Jan 2011
5 min read
In this Ajax tutorial, you will learn the YUI way of making Asynchronous JavaScript and XML (AJAX) requests. Although, all modern browsers support sending asynchronous requests to the server, not all browsers work the same way. Additionally, you are not required to return XML; your AJAX requests may return JSON, text, or some other format if you prefer. The Connection component provides a simple, cross-browser safe way to send and retrieve information from the server. How to make your first AJAX request This recipe will show you how to make a simple AJAX request using YUI. Getting ready To use the Connection component, you must include the YUI object, the Event component, and the core of the Connection component: <script src="pathToBuild/yahoo/yahoo-min.js" type="text/javascript"></script> <script src="pathToBuild/event/event-min.js" type="text/javascript"></script> <script src="pathToBuild/connection/connection_core-min.js" type="text/javascript"></script> If you plan on using the form serialization example, or other advanced features, you will need to include the whole component, instead of only the core features: <script src="pathToBuild/connection/connection-min.js" type="text/javascript"></script> How to do it... Make an asynchronous GET request: var url = "/myUrl.php?param1=asdf&param2=1234"; var myCallback = { success: function(o) {/* success handler code */}, failure: function(o) {/* failure handler code */}, /* ... */ }; var transaction = YAHOO.util.Connect.asyncRequest('GET', url, myCallback); Make an asynchronous POST request: var url = "/myUrl.php"; var params = "param1=asdf&param2=1234"; var myCallback = { success: function(o) {/* success handler code */}, failure: function(o) {/* failure handler code */}, /* ... */ }; var transaction = YAHOO.util.Connect.asyncRequest( 'POST', url, myCallback, params); Make an asynchronous POST request using a form element to generate the post data: var url = "/myUrl.php"; var myCallback = { success: function(o) {/* success handler code */}, failure: function(o) {/* failure handler code */}, /* ... */ }; YAHOO.util.Connect.setForm('myFormEelementId'); var transaction = YAHOO.util.Connect.asyncRequest('POST', url, myCallback); How it works... All modern browsers have supported AJAX natively since the early 2000. However, IE implemented a proprietary version using the ActiveXObject object , while other browsers implemented the standard compliant XMLHttpRequest (XHR) object . Each object has its own implementation and quirks, which YUI silently handles for you. Both objects make an HTTP request to the provided URL, passing any parameters you specified. The server should handle AJAX requests like any normal URL request. When making a GET request , the parameters should be added to the URL directly (as in the example above). When making a POST request, the parameters should be a serialized form string (&key=value pairs) and provided as the fourth argument. Connection Manager also allows you to provide the parameters for a GET request as the fourth argument, if you prefer. Using the setForm function attaches a form element for serialization with the next call to the asyncRequest function . The element must be a form element or it will throw an exception. YUI polls the browser XHR object until a response is detected, then it examines the response code and the response data to see if it is valid. If it is valid, the success event fires, and if it is not, the failure event fires. YUI wraps the XHR response with its own connection object, thereby masking browser variations, and passes the wrapper object as the first argument of all the AJAX callback functions. There's more... Beside POST and GET, you may also use PUT, HEAD, and DELETE requests, but these may not be supported by all browsers or servers. It is possible to send synchronous request through the native XHR objects, however Connection Manager does not support this. The asyncRequest function returns an object known as the transaction object . This is the same object that YUI uses internally to manage the XHR request. It has the following properties: See also Exploring the callback object properties recipe, to learn what properties you can set on the callback object. Exploring the response object recipe, to learn what properties are available on the YUI object passed into your callback functions. Exploring the callback object properties The third argument you can provide to the asyncRequest function defines your callback functions and other related response/request properties. This recipe explains what those properties are and how to use them. How to do it... The properties available on the callback object are: var callback = { argument: {/* ... */}, abort: function(o) {/* ... */}, cache: false, failure: function(o) {/* ... */}, scope: {/* ... */}, success: function(o) {/* ... */}, timeout: 10000, // 10 seconds upload: function(o) {/* ... */}, }; How it works... The various callback functions attached to the connection object use the CustomEvent.FLAT callback function signature. This way the response object is the first argument of the callback functions. Each of the callback functions is subscribed to the appropriate custom event by the asyncRequest function. When the Connection Manager component detects the corresponding event conditions, it fires the related custom event. The upload callback function is special because an iframe is used to make this request. Consequently, YUI cannot reasonably discern success or failure, nor can it determine the HTTP headers. This callback will be executed both when an upload is successful and when it fails, instead of the success and failure callback functions. The argument property is stored on the response object and passed through to the callback functions. You can set the argument to anything that evaluates as true. When the cache property is true, YUI maps the responses to the URLs, so if the same URL is requested a second time, Connection Manager can simply execute the proper callback function immediately. The timeout property uses the native browser setTimeout function to call the abort function when the timeout expires. The timeout is cleared when an AJAX response is detected for a transaction. See also Exploring the response object properties recipe, to learn what properties are available on the YUI object passed into your callback functions. Using event callback functions recipe, to learn common practices for handling failure and success callback functions.
Read more
  • 0
  • 0
  • 4018

article-image-django-javascript-integration-jquery-place-editing-using-ajax
Packt
07 Jan 2011
8 min read
Save for later

Django JavaScript Integration: jQuery In-place Editing Using Ajax

Packt
07 Jan 2011
8 min read
Django JavaScript Integration: AJAX and jQuery Develop AJAX applications using Django and jQuery Learn how Django + jQuery = AJAX Integrate your AJAX application with Django on the server side and jQuery on the client side Learn how to handle AJAX requests with jQuery Compare the pros and cons of client-side search with JavaScript and initializing a search on the server side via AJAX Handle login and authentication via Django-based AJAX This will allow us to create a results page as shown: When someone clicks OK, the data is saved on the server, and also shown on the page. Let's get started on how this works. Including a plugin We include a jQuery plugin on a page by including jQuery, then including the plugin (or plugins, if we have more than one). In our base.html, we update: {% block footer_javascript_site %} <script language="JavaScript" type="text/javascript" src="/static/js/jquery.js"></script> <script language="JavaScript" type="text/javascript" src="/static/js/jquery-ui.js"></script> <script language="JavaScript" type="text/javascript" src="/static/js/jquery.jeditable.js"></script> {% endblock footer_javascript_site %} This is followed by the footer_javascript_section and footer_javascript_page blocks. This means that if we don't want the plugin ,which is the last inclusion, to be downloaded for each page, we could put it in overridden section and page blocks. This would render as including the plugin after jQuery. How to make pages more responsive We would also note that the setup, with three JavaScript downloads, is appropriate for development purposes but not for deployment. In terms of YSlow client-side performance optimization, the recommended best practice is to have one HTML/XHTML hit, one CSS hit at the top, and one JavaScript hit at the bottom. One of the basic principles of client-side optimization, discussed by Steve Souders (see http://developer.yahoo.com/yslow/) is,since HTTP requests slow the page down, the recommended best practice is to have one (preferably minifed) CSS inclusion at the top of the page, and then one (preferably minifed) JavaScript inclusion at the bottom of each page. Each HTTP request beyond this makes things slower, so combining CSS and/or JavaScript requests into a single concatenated file is low-hanging fruit to improve how quick and responsive your web pages appear to users. For deployment, we should minify and combine the JavaScript. As we are developing, we also have JavaScript included in templates and rendered into the delivered XHTML; this may be appropriate for development purposes. For deployment though, as much shared functionality as possible should be factored out into an included JavaScript fle. For content that can be delivered statically, such as CSS, JavaScript, and even non-dynamic images, setting far-future Expires/Cache-Control headers is desirable. (One practice is to never change the content of a published URL for the kind of content that has a far-future expiration set, and then if it needs updating, instead of changing the content at the same location, leave the content where it is, publish at a new location possibly including a version number, and reference the new location.) A template handling the client-side requirements Here's the template. Its view will render it with an entity and other information. At present it extends the base directly; it is desirable in many cases to have the templates that are rendered extend section templates, which in turn extend the base. In our simple application, we have two templates which are directly rendered to web pages. One is the page that handles both search and search results—and the other, the page that handles a profile, from the following template: {% extends "base.html" %} We include honorifics before the name, and post-nominals after. At this point we do not do anything to make it editable. {% extends "base.html" %} Following earlier discussion, we include honorifcs before the name, and post-nominals after. At this point we do not do anything to make it editable. {% block head_title %} {{ entity.honorifics }} {{ entity.name }} {{ entity.post_nominals }} {% endblock head_title %} {% block body_main %} There is one important point about Django and the title block. The Django developers do not fnd it acceptable to write a templating engine that produces errors in production if someone attempts to access an undefned value (by typos, for instance). As a result of this design decision, if you attempt to access an undefned value, the templating engine will silently insert an empty string and move on. This means that it is safe to include a value that may or may not exist, although there are ways to test if a value exists and is nonempty, and display another default value in that case. We will see how to do this soon. Let's move on to the main block, defned by the last line of code. Once we are in the main block, we have an h1 which is almost identical to the title block, but this time it is marked up to support editing in place. Let us look at the honorifics span; the name and post_nominals spans work the same way: <h1> <span id="Entity_honorifics_{{ entity.id }}" class="edit"> {% if entity.honorifics %} {{ entity.honorifics }} {% else %} Click to edit. {% endif %} </span> The class edit is used to give all $(".edit") items some basic special treatment with Jeditable; there is nothing magical about the class name, which could have been replaced by user-may-change-this or something else. edit merely happens to be a good name choice, like almost any good variable/function/object name. We create a naming convention in the span's HTML ID which will enable the server side to know which—of a long and possibly open-ended number of things we could intend to change—is the one we want. In a nutshell, the convention is modelname_feldname_instanceID. The frst token is the model name, and is everything up to the first underscore. (Even if we were only interested in one model now, it is more future proof to design so that we can accommodate changes that introduce more models.) The last token is the instance ID, an integer. The middle token, which may contain underscores (for example post_nominals in the following code), is the feld name. There is no specifc requirement to follow a naming convention, but it allows us to specify an HTML ID that the server-side view can parse for information about which feld on which instance of which model is being edited. We also provide a default value, in this case Click to edit, intended not only to serve as a placeholder, but to give users a sense on how this information can be updated. We might also observe that here and in the following code, we do not presently have checks against race conditions in place. So nothing here or in the following code will stop users from overwriting each others' changes. This may be taken as a challenge to refne and extend the solution to either prevent race conditions or mitigate their damage. <span id="Entity_name_{{ entity.id }}" class="edit"> {% if entity.name %} {{ entity.name }} {% else %} Click to edit. {% endif %} </span> <span id="Entity_post_nominals_{{ entity.id }}" class="edit"> {% if entity.post_nominals %} {{ entity.post_nominals }} {% else %} Click to edit. {% endif %} </span> </h1> This approach is an excellent frst approach but in practice is an h1 with three slots that say Click to edit on a profle, creating needless confusion. We move to a simplifed: <span id="Entity_name_{{ entity.id }}" class="edit"> {% if entity.name %} {{ entity.name }}jQuery In-place Editing Using Ajax {% else %} Click to edit. {% endif %} </span> <span id="Entity_post_nominals_{{ entity.id }}" class="edit"> {% if entity.post_nominals %} {{ entity.post_nominals }} {% else %} Click to edit. {% endif %} </span> </h1> Taken together, the three statements form the heading in this screenshot: If we click on the name (for instance) it becomes: The image is presently a placeholder; this should be expanded to allow an image to be uploaded if the user clicks on the picture (implementing consistent-feeling behavior whether or not we do so via the same plugin). We also need the view and urlpattern on the backend: <h1 class="edit" id="Entity_name_{{ entity.id }}"> {{ entity.name }} </h1>
Read more
  • 0
  • 0
  • 7151

article-image-moodle-cims-installing-and-using-bulk-course-upload-tool
Packt
07 Jan 2011
7 min read
Save for later

Moodle CIMS: Installing and Using the Bulk Course Upload Tool

Packt
07 Jan 2011
7 min read
Moodle as a Curriculum and Information Management System Use Moodle to manage and organize your administrative duties; monitor attendance records, manage student enrolment, record exam results, and much more Transform your Moodle site into a system that will allow you to manage information such as monitoring attendance records, managing the number of students enrolled in a particular course, and inter-department communication Create courses for all subjects in no time with the Bulk Course Creation tool Create accounts for hundreds of users swiftly and enroll them in courses at the same time using a CSV file. Part of Packt's Beginner's Guide series: Readers are walked through each task as they read the book with the end result being a sample CIMS Moodle site Using the Bulk Course Upload tool Rather than creating course categories and then courses one at a time and assigning teachers to each course after the course is created, we can streamline the process through the use of the Bulk Course Upload tool. This tool allows you to organize all the information required to create your courses in a CSV (Comma Separated Values) file that is then uploaded into the creation tool and used to create all of your courses at once. Due to its design, the Bulk Course Upload tool only works with MySQL databases. Our MAMP package uses a MySQL database as do the LAMP packages. If your Moodle site is running on a database of a different variety you will not be able to use this tool. Time for action – installing the Bulk Course Upload tool Now that we have our teacher's accounts created, we are ready to use the Bulk Course Creation tool to create all of our courses. First we need to install the tool as an add-on admin report into our Moodle site. To install this tool, do the following: Go to the Modules and plugins area of www.moodle.org. Search for Bulk Course Upload tool. Click on Download latest version to download the tool to your computer. If this does not download the package to your hard drive and instead takes you to a forum in the Using Moodle course on Moodle.org, download the package that was posted in that forum on Sunday, 11 May 2008. Expand the package, contained within, and find the uploadcourse.php file. Place the uploadcourse.php file in your admin directory located inside your main Moodle directory. When logged in as admin, enter the following address in your browser address bar: http://localhost:8888/moodle19/admin/uploadcourse.php. (If you are not using a MAMP package, the first part of the address will of course be different.) You will then see the Upload Course tool explanation screen that looks like the following screenshot: The screen, shown in the previous screenshot, lists the thirty-nine different fields that can be included in a CSV file when creating courses in bulk via this tool. Most of the fields here control settings that are modified in individual courses by clicking on the Settings link found in the Administration block of each course. The following is an explanation of the fields with notes about which ones are especially useful when setting up Moodle as a CIMS: category: You will definitely want to specify categories in order to organize your courses. The best way to organize courses and categories here is such that the organization coincides with the organization of your curriculum as displayed in school documentation and student handbooks. If you already have categories in your Moodle site, make sure that you spell the categories exactly as they appear on your site, including capitalization. A mistake will result in the creation of a new category. This field should start with a forward slash followed by the category name with each subcategory also being followed by a forward slash (for example, /Listening/Advanced). cost: If students must pay to enroll in your courses, via the PayPal plugin, you may enter the cost here. You must have the PayPal plugin activated on your site, which can be done by accessing it via the Site Administration block by clicking on Courses and then Enrolments. Additionally, as this book goes to print, the ability to enter a field in the file used by the Bulk Course tool that allows you to set the enrolment plugin, is not yet available. Therefore, if you enter a cost value for a course, it will not be shown until the enrolment plugin for the course is changed manually by navigating to the course and editing the course through the Settings link found in the course Administration block. Check Moodle.org frequently for updates to the Bulk Course Upload tool as the feature should be added soon. enrolperiod: This controls the amount of time a student is enrolled in a course. The value must be entered in seconds so, for example, if you had a course that ran for one month and students were to be unenrolled after that period, you would set this value to 2,592,000 (60 seconds X 60 minutes per hour X 24 hours per day X 30 = 2,592,000). enrollable: This simply controls whether the course is enrollable or not. Entering a 0 will render the course unenrollable and a 1 will set the course to allow enrollments. enrolstartdate and enrolenddate: If you wish to set an enrollment period, you should enter the dates (start and end dates) in these two fields. The dates can be entered in the month/day/year format (for example, 8/1/10). expirynotify: Enter a 1 here to have e-mails sent to the teacher when a student is going to be unenrolled from a course. Enter a 0 to prevent e-mails from being sent when a student is going to be unenrolled. This setting is only functional when the enrolperiod value is set. expirythreshold: Enter the number of days in advance you want e-mails notifying of student unenrollment sent. The explanation file included calls for a value between 10 and 30 days but this value can actually be set to between 1 and 30 days. This setting is only functional when the enrolperiod value and expirynotify and/or notifystudents (see below) is/are set. format: This field controls the format of the course. As of Moodle 1.9.8+ there are six format options included in the standard package. The options are lams, scorm, social, topics, weeks, and weeks CSS, and any of these values can be entered in this field. fullname: This is the full name of the course you are creating (for example, History 101). groupmode: Set this to 0 for no groups, 1 for separate groups, and 2 for visible groups. groupmodeforce: Set this to 1 to force group mode at the course level and 0 to allow group mode to be set in each individual activity. guest: Use a 0 to prevent guests from accessing this course, a 1 to allow uests in the course, and a 2 to allow only guests who have the key into the course. idnumber: You can enter a course ID number using this field. This number is only used for administrative purposes and is not visible to students. This is a very useful field for institutions that use identification numbers for courses and can provide a link for connecting the courses within Moodle to other systems. If your institution uses any such numbering system it is recommended that you enter the appropriate numbers here. lang: This is the language setting for the course. Leaving this field blank will result in the Do not force language setting, which can be seen from the Settings menu accessed from within each individual course. Doing so will allow users to toggle between languages that have been installed in the site. To specify a language, and thus force the display of the course using this language, enter the language as it is displayed within the Moodle lang directory (for example, English = en_utf8). maxbytes: This field allows you to set the maximum size of individual files that are uploaded to the course. Leaving this blank will result in the course being created with the site wide maximum file upload size setting. Values must be entered in bytes (for example, 1 MB = 1,048,576 bytes). Refer to an online conversion site such as www.onlineconversion.com to help you determine the value you want to enter here. metacourse: If the course you are creating is a meta course, enter a 1, otherwise enter a 0 or leave the field blank.
Read more
  • 0
  • 0
  • 5355

article-image-building-moodle-cims-foundation-creating-categories-and-courses
Packt
07 Jan 2011
8 min read
Save for later

Building the Moodle CIMS Foundation: Creating Categories and Courses

Packt
07 Jan 2011
8 min read
  Moodle as a Curriculum and Information Management System   Use Moodle to manage and organize your administrative duties; monitor attendance records, manage student enrolment, record exam results, and much more Transform your Moodle site into a system that will allow you to manage information such as monitoring attendance records, managing the number of students enrolled for a particular course, and inter-department communication Create courses for all subjects in no time with the Bulk Course Creation tool Create accounts for hundreds of users swiftly and enroll them in courses at the same time using a CSV file. Part of Packt's Beginner's Guide series: Readers are walked through each task as they read through the book with the end result being a sample CIMS Moodle site         Read more about this book       (For more resources on Moodle, see here.) Course categories Categorization is an innate human behavior that allows us to perceive and understand the environment that surrounds us. Moodle designers must have recognized our tendency to categorize, because Moodle contains a flexible categorization system that allows for the creation of categories in which you may house additional categories and courses. Any educational program that offers courses of various varieties will invariably be using a categorization system like this for grouping courses into specific categories. A language program, for example, might group courses into skill-specific categories such as those of listening, speaking, reading, and writing. A larger entity, such as a college, would likely group courses into content-specific categories such as literature, sciences, speech communications, and the like, with additional subcategories used inside each of those main categories. No matter what the categorization system, Moodle is well-equipped to accommodate via its intuitive user-friendly course category creation interface. Manual creation of course categories We will quickly walk through the manual creation of a simple categorization system in the next few pages. It should be noted however, that course categories can be created automatically via the use of the Bulk Course Upload tool that will be introduced later in the next article. While the automated creation process is certainly a more efficient one, it is a good idea to understand how to create, edit, and adjust categories manually as the need to make adjustments may arise after categories have been created automatically, and at that point, the only practical method may be via the manual process. Using the language program sample as an example, we will set up a categorization system that uses the traditional language skills (listening, speaking, reading, and writing) as the highest level in the categorization system with subcategories for levels. In our example, our program will have four levels: Advanced, Intermediate, Beginner, and Basic, so we will set up each skill category such that it contains subcategories that coincide with the four levels. Time for action – manually creating course categories Let's get started by first taking a look at the courses and categories that exist in the default installation of our MAMP package. We'll proceed by manually creating the categories and subcategories we need for our language program example. Log in to your Moodle site as admin, or as a user with administrative permissions, and click on the All courses link found at the bottom of the Course categories block from your front page. An alternative method for accessing the Course category window is to simply type the word 'course' into your browser at the end of your website address from the front page of your Moodle site. This will direct your browser to the default file, index.php, located in the course directory (for example, for the XAMPP package, it will look like this http://localhost/moodle19/course). The following screenshot is of a default MAMP installation. For Windows XAMPP installations, no courses or categories will exist. You will see the two default courses that are created in the MAMP package and no category. As shown in the following screenshot, the full name of the course will appear on the left side of the screen with a small icon of a person, below it. The icon, shown with an arrow pointing to it in the following screenshot, signifies that the course is set to allow guest users to access it. On the right side of the screen is the course summary. Click on the Turn editing on button from the All courses screen, shown in the previous screenshot, to reveal the course category as shown in the next screenshot. This editing screen displays the categories and the number of courses contained in each category. The category was not listed in the course view window in the previous screenshot because there is currently only one category. With editing on, now click on the Add new category button and, on the subsequent screen, type in the desired category title. For this example, we are going to enter the four skills mentioned previously. Also, as we want these to be our four main categories, we will set the Parent category to Top. Enter a category description and click on the Create category button to finish the process. The following screenshot shows our setup prior to creating the category: After clicking on the Create category button, the screen that you will see next will be an editing screen that will allow you to edit from within the Listening category you just created. As a result, you will not see the Add new category button. Instead, you will see an Add a sub-category button. Click on this button to access the screen that allows you to create a new category. After doing so, you will simply need to change the Parent category to Top. Repeat this process until you have created all of your top-level categories. After you have created all categories, turn the editing feature off and click on the Course categories breadcrumb link, found at the top-left of the screen, to see the result. It will look like the following screenshot: If you wish to change the order in which the categories appear, you can turn editing back on and use the up and down arrows to move categories. In the following screenshot, which is the same screen as the previous one, with editing turned on, we have moved the Miscellaneous category to the bottom and rearranged the main categories into a different order. Next, we will create the four level categories using the same process explained for the main categories. The only difference is that we will create each of the four levels inside the main categories by designating the main category as the Parent category. From the editing screen shown in the previous screenshot, click on one of the categories and then on the subsequent Add a sub-category button, as shown in the following screenshot. Creating the category in this fashion will result in the parent category being automatically set to the main category to which you are adding the sub-category. In the same fashion as earlier when we created multiple categories in succession however, after adding the first sub-category, if you click on Add a sub-category again, you will need to then adjust the Parent category. If you do not do so, you will be effectively burying sub-categories within sub-categories. The alternative is to click on the Course categories pull-down menu prior to clicking on Add a sub-category. Create all four levels, Advanced, Intermediate, Beginner, and Basic, using this process, for each of the four skills (Listening, Reading, Speaking, and Writing). When you have finished adding all of the subcategories to the main categories and have returned to the main Course Categories window, your screen should look like the following screenshot: What just happened? You have just created a simple categorization system with four main skills (Listening, Speaking, Reading, and Writing). Next you created four subcategories—levels, inside each of the main categories (Advanced, Intermediate, Beginner, and Basic). As you followed the example used here or maybe created an even more intricate categorization scheme, you may have felt that the process was a bit time consuming and required quite a few mouse clicks. As mentioned in the beginning of this explanation, creating categories via the Bulk Course Upload tool is much more efficient and recommended when possible. There will be times however, when you need to create new categories after courses have already been made or to edit or rearrange categories. On these occasions, you may find it necessary to use the manual procedure so it is a good idea to be familiar with the process.
Read more
  • 0
  • 0
  • 1676

article-image-drupal-intranets-open-atrium-creating-dashboard
Packt
05 Jan 2011
7 min read
Save for later

Drupal Intranets with Open Atrium: Creating Dashboard

Packt
05 Jan 2011
7 min read
Drupal Intranets with Open Atrium Discover an intranet solution for your organization with Open Atrium Unlock the features of Open Atrium to set up an intranet to improve communication and workflow Explore the many features of Open Atrium and how you can utilize them in your intranet Learn how to support, maintain, and administer your intranet A how-to guide written for non-developers to learn how to set up and use Open Atrium   Main dashboard The main dashboard provides an interface for managing and monitoring our Open Atrium installation. This dashboard provides a central place to monitor what's going on across our departments. It will also be used as the central gateway for most of our administrative tasks. From this screen we can add groups, invite users, and customize group dashboards. Each individual who logs in also has the main dashboard and can quickly glance at the overall activity for their company. The dashboard is laid out initially by default in a two column layout. The left side of the screen contains the Main Content section and the right side of the screen contains a Sidebar. In a default installation of Open Atrium, there will be a welcome video in the Main Content area on the left. The first thing that you will notice when you log in is that there is a quick video that you can play on your main dashboard screen. This video provides a quick overview of Open Atrium for our users, and a review of the options you have for working with the dashboard. In the following screenshot, you will see the main dashboard and how the two separate content areas are divided, with a specific section marked that we will discuss later in the article: Each dashboard can be customized to either a two-column or split layout, as shown in the preceding screenshot, or a three-column layout. Under the Modifying Layout section of this article, we will cover how to change the overall layout. As you can see in the preceding image, the dashboard is divided into three distinct sections. There is the header area which includes the Navigation tabs for creating content, modifying settings, and searching the site. Under the header area, we have the main content and sidebar areas. These areas are made up of blocks of content from the site. These blocks can bring forward and include different items depending on how we customize our site. For example, in the left column we could choose to display Recent Activity and Blog Posts, while the right column could show Upcoming Events and a Calendar. Any of the features that we find throughout Open Atrium can be brought forward to a dashboard page. The beauty of this setup is that each group can customize their own. In the next section of this article, we will cover group dashboards in more detail. However, the same basic concepts will apply to all the dashboards. After our users are comfortable with using Open Atrium, we may decide that we no longer need to show the tutorial video on the main dashboard. This video can be easily removed by clicking on the Customizing the dashboard link just above the Recent Activity block or by clicking on the Customize dashboard link on the top right in the header section. Click on the customizing the dashboard link and we will see a dashboard widget on the screen. This will be the main interface for configuring layout and content on our dashboard. Now, hover over the video and on the top right you will see two icons. The first icon that looks like a plus sign (+) indicates that the content can be dragged. We can click on this icon when hovering over a section of content and move that content to another column or below another section of content on our dashboard. The X indicates that we can remove that item from our dashboard. Hovering over any piece of content when you are customizing the dashboard should reveal these two icons. The two icons are highlighted in the following screenshot with a square box drawn around them: To remove the welcome video, we click on the red X and then click on Save changes and the video tutorial will be removed from the dashboard. Group dashboard The group dashboard works the same as the main dashboard. The only difference is that the group dashboard exposes content for the individual departments or groups that are setup on our site. For example, a site could have a separate group for the Human Resources, Accounting, and Management departments. Each of these groups can create a group dashboard that can be customized by any of the administrators for a particular group. The following screenshot shows how the Human Resources department has customized their group dashboard:   In the preceding screenshot, we can see how the HR department customized their dashboard. In the left column they have added a Projects and a Blog section. The Projects section links to specific projects within the site, and the Blog section links to the detailed blog entries. There is also a customized block in the right column where the HR department has added the Upcoming events, a Mini calendar, and a Recent activity block. The Projects section is a block that is provided by the system and exposes content from the Case tracker or Todo sections of the HR website. The Upcoming events section is a customized block that highlights future events entered through the calendar feature. To demonstrate how each department can have a different dashboard, the following screenshot shows the dashboard for the Accounting department: The Accounting dashboard has been configured to show a custom block as the first item in the left column, and below that a listing of Upcoming events. In the right column, the Accounting administrator has added a block which brings forward the Latest cases of all the latest cases, exposing the most recent issues entered into the tracking system. It is also worth noting that the Accounting department has a completely different color scheme from the Human Resources department. The color scheme can be changed by clicking on Settings | Group Settings | Features. We can scroll down to the bottom of the screen and click on BACKGROUND to either enter a hexadecimal color for our main color or pick a color from the color wheel as displayed in the following screenshot: Spaces Spaces is a Drupal API module that allows sitewide configurable options to be overridden by individual spaces. The spaces API is included with our Open Atrium installation and provides the foundation for creating group and user configurable dashboards. Users can then customize their space and set settings that are only applied to their space. This shows the extreme power and flexibility of Open Atrium by allowing users to apply customizations without affecting any of the other areas of Open Atrium. Users can use the functionality provided by spaces to create an individualized home page. Group spaces Group spaces provide an area for each group or department to arrange content in a contextual manner that makes sense for each group. In the preceding examples, the content that is important to the accounting department is not necessarily important to the human resources department. Administrators of each department can take advantage of Open Atrium's complete flexibility to arrange content in a way that works for them. The URLs in the example that we have been looking at are listed as follows: Human Resources: http://acme.alphageekdev.com/hr. Accounting: http://acme.alphageekdev.com/acct Each URL is composed of the site URL, that is, http://acme.alphageekdev.com/ and then the short name that we provided for our group space, hr and acct. User spaces User spaces work in the same way that the group dashboard and spaces work. Each user of the system can customize their dashboard any way that they see appropriate. The following screenshot shows an example of the user's dashboard for the admin account: In the preceding screenshot, we have drawn a box around two areas. These two areas represent two different group spaces showing on the user's dashboard page. This shows how content can be brought forward to various dashboards to show only what is important to a particular user.
Read more
  • 0
  • 0
  • 3258

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

FAQs on Mahara 1.2 ePortfolios

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

Drupal FAQs

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

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

Enhancing your Site with PHP and jQuery

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

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

Getting Started with Ext GWT

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

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

Working with XML Documents in PHP jQuery

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

Moodle 1.9 Testing and Assessment: Advanced Options in Quiz

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

article-image-moodle-19-testing-and-assessment-multiple-choice-quizzes
Packt
22 Dec 2010
7 min read
Save for later

Moodle 1.9 Testing and Assessment: Multiple Choice Quizzes

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

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

Introduction to Developing Facebook Applications

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

Working with JSON in PHP jQuery

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

Packt
16 Dec 2010
15 min read
Save for later

Page Management – Part Two in CMS

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