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-features-raphaeljs
Packt
12 Sep 2013
16 min read
Save for later

Features of RaphaelJS

Packt
12 Sep 2013
16 min read
(For more resources related to this topic, see here.) Creating a Raphael element Creating a Raphael element is very easy. To make it better, there are predefined methods to create basic geometrical shapes. Basic shape There are three basic shapes in RaphaelJS, namely circle, ellipse, and rectangle. Rectangle We can create a rectangle using the rect() method. This method takes four required parameters and a fifth optional parameter, border-radius. The border-radius parameter will make the rectangle rounded (rounded corners) by the number of pixels specified. The syntax for this method is: paper.rect(X,Y,Width,Height,border-radius(optional)); A normal rectangle can be created using the following code snippet: // creating a raphael paper in 'paperDiv' var paper = Raphael ("paperDiv", 650,400); // creating a rectangle with the rect() method. The four required parameters are X,Y,Width & Height var rect = paper.rect(35,25,170,100).attr({ "fill":"#17A9C6", //filling with background color "stroke":"#2A6570", // border color of the rectangle "stroke-width":2 // the width of the border }); The output for the preceding code snippet is shown in the following screenshot: Plain rectangle Rounded rectangle The following code will create a basic rectangle with rounded corners: // creating a raphael paper in 'paperDiv' var paper = Raphael ("paperDiv", 650,400); //The fifth parameter will make the rectangle rounded by the number of pixels specified – A rectangle with rounded corners var rect = paper.rect(35,25,170,100,20).attr({ "fill":"#17A9C6",//background color of the rectangle "stroke":"#2A6570",//border color of the rectangle "stroke-width":2 // width of the border }); //in the preceding code 20(highlighted) is the border-radius of the rectangle. The output for the preceding code snippet is a rectangle with rounded corners, as shown in the following screenshot: Rectangle with rounded corners We can create other basic shapes in the same way. Let's create an ellipse with our magic wand. Ellipse An ellipse is created using the ellipse() method and it takes four required parameters, namely x,y, horizontal radius, and vertical radius. The horizontal radius will be the width of the ellipse divided by two and the vertical radius will be the height of the ellipse divided by two. The syntax for creating an ellipse is: paper.ellipse(X,Y,rX,rY); //rX is the horizontal radius & rY is the vertical radius of the ellipse Let's consider the following example for creating an ellipse: // creating a raphael paperin 'paperDiv' var paper = Raphael ("paperDiv", 650,400); //The ellipse() method takes four required parameters: X,Y, horizontal radius & vertical Radius var ellipse = paper.ellipse(195,125,170,100).attr({ "fill":"#17A9C6", // background color of the ellipse "stroke":"#2A6570", // ellipse's border color "stroke-width":2 // border width }); The preceding code will create an ellipse of width 170 x 2 and height 100 x 2. An ellipse created using the ellipse() method is shown in the following screenshot: An Ellipse Complex shapes It's pretty easy to create basic shapes, but what about complex shapes such as stars, octagons, or any other shape which isn't a circle, rectangle, or an ellipse. It's time for the next step of Raphael wizardry. Complex shapes are created using the path() method which has only one parameter called pathString. Though the path string may look like a long genetic sequence with alphanumeric characters, it's actually very simple to read, understand, and draw with. Before we get into path drawing, it's essential that we know how it's interpreted and the simple logic behind those complex shapes. Imagine that you are drawing on a piece of paper with a pencil. To draw something, you will place the pencil at a point in the paper and begin to draw a line or a curve and then move the pencil to another point on the paper and start drawing a line or curve again. After several such cycles, you will have a masterpiece—at least, you will call it a masterpiece. Raphael uses a similar method to draw and it does so with a path string. A typical path string may look like this: M0,0L26,0L13,18L0,0. Let's zoom into this path string a bit. The first letter says M followed by 0,0. That's right genius, you've guessed it correctly. It says move to 0,0 position, the next letter L is line to 26,0. RaphaelJS will move to 0,0 and from there draw a line to 26,0. This is how the path string is understood by RaphaelJS and paths are drawn using these simple notations. Here is a comprehensive list of commands and their respective meanings: Command Meaning expansion Attributes M move to (x, y) Z close path (none) L line to (x, y) H horizontal line to x V vertical line to y C curve to (x1, y1, x2, y2, x, y) S smooth curve to (x2, y2, x, y) Q quadratic Bézier curve to (x1, y1, x, y) T smooth quadratic Bézier curve to (x, y) A elliptical arc (rx, ry, x axis-rotation, large-arc-flag, sweep-flag, x, y) R Catmull-Rom-curve to* x1, y1 (x y) The uppercase commands are absolute (M20, 20); they are calculated from the 0,0 position of the drawing area (paper). The lowercase commands are relative (m20, 20); they are calculated from the last point where the pen left off. There are so many commands, which might feel like too much to take in—don't worry; there is no need to remember every command and its format. Because we'll be using vector graphics editors to extract paths, it's essential that you understand the meaning of each and every command so that when someone asks you "hey genius, what does this mean?", you shouldn't be standing there clueless pretending to have not heard it. The syntax for the path() method is as follows: paper.path("pathString"); Let's consider the following example: // creating a raphael paper in 'paperDiv' var paper = Raphael ("paperDiv", 350,200); // Creating a shape using the path() method and a path string var tri = paper.path("M0,0L26,0L13,18L0,0").attr({ "fill":"#17A9C6", // filling the background color "stroke":"#2A6570", // the color of the border "stroke-width":2 // the size of the border }); All these commands ("M0,0L26,0L13,18L0,0") use uppercase letters. They are therefore absolute values. The output for the previous example is shown in the following screenshot: A triangle shape drawn using the path string Extracting and using paths from an editor Well, a triangle may be an easy shape to put into a path string. How about a complex shape such as a star? It's not that easy to guess and manually find the points. It's also impossible to create a fairly more complex shape like a simple flower or a 2D logo. Here in this section, we'll see a simple but effective method of drawing complex shapes with minimal fuss and sharp accuracy. Vector graphics editors The vector graphics editors are meant for creating complex shapes with ease and they have some powerful tools in their disposal to help us draw. For this example, we'll create a star shape using an open source editor called Inkscape, and then extract those paths and use Raphael to get out the shape! It is as simple as it sounds, and it can be done in four simple steps. Step 1 – Creating the shape in the vector editor Let's create some star shapes in Inkscape using the built-in shapes tool. Star shapes created using the built-in shapes tool Step 2 – Saving the shape as SVG The paths used by SVG and RaphaelJS are similar. The trick is to use the paths generated by the vector graphics editor in RaphaelJS. For this purpose, the shape must be saved as an SVG file. Saving the shape as an SVG file Step 3 – Copying the SVG path string The next step is to copy the path from SVG and paste it into Raphael's path() method. SVG is a markup language, and therefore it's nested in tags. The SVG path can be found in the <path> and </path> tags. After locating the path tag, look for the d attribute. This will contain a long path sequence. You've now hit the bullseye. The path string is highlighted Step 4 – Using the copied path as a Raphael path string After copying the path string from SVG, paste it into Raphael's path() method. var newpath=paper.path("copied path string from SVG").attr({ "fill":"#5DDEF4", "stroke":"#2A6570", "stroke-width":2 }); That's it! We have created a complex shape in RaphaelJS with absolute simplicity. Using this technique, we can only extract the path, not the styles. So the background color, shadow, or any other style in the SVG won't apply. We need to add our own styles to the path objects using the attr() method. A screenshot depicting the complex shapes created in RaphaelJS using the path string copied from an SVG file is shown here: Complex shapes created in RaphaelJS using path string Creating text Text can be created using the text() method. Raphael gives us a way to add a battery of styles to the text object, right from changing colors to animating physical properties like position and size. The text() method takes three required parameters, namely, x,y, and the text string. The syntax for the text() method is as follows: paper.text(X,Y,"Raphael JS Text"); // the text method with X,Y coordinates and the text string Let's consider the following example: // creating a raphael paper in 'paperDiv' var paper = Raphael ("paperDiv", 650,400); // creating text var text = paper.text(40,55,"Raphael Text").attr({ "fill":"#17A9C6", // font-color "font-size":75, // font size in pixels //text-anchor indicates the starting position of the text relative to the X, Y position.It can be "start", "middle" or "end" default is "middle" "text-anchor":"start", "font-family":"century gothic" // font family of the text }); I am pretty sure that the text-anchor property is a bit heavy to munch. Well, there is a saying that a picture is worth a thousand words. The following diagram clearly explains the text-anchor property and its usage. A brief explanation of text-anchor property A screenshot of the text rendered using the text() method is as follows: Rendering text using the text() method Manipulating the style of the element The attr() method not only adds styles to an element, but it also modifies an existing style of an element. The following example explains the attr() method: rect.attr('fill','#ddd'); // This will update the background color of the rectangle to gray Transforming an element RaphaelJS not only creates elements, but it also allows the manipulating or transforming of any element and its properties dynamically. Manipulating a shape By the end of this section, you would know how to transform a shape. There might be many scenarios wherein you might need to modify a shape dynamically. For example, when the user mouse-overs a circle, you might want to scale up that circle just to give a visual feedback to the user. Shapes can be manipulated in RaphaelJS using the transform() method. Transformation is done through the transform() method, and it is similar to the path() method where we add the path string to the method. transform() works in the same way, but instead of the path string, it's the transformation string. There is only a moderate difference between a transformation string and a path string. There are four commands in the transformation string: T Translate S Scale R Rotate in degrees M Matrix The fourth command, M, is of little importance and let's keep it out of the way, to avoid confusion. The transformation string might look similar to a path string. In reality, they are different, not entirely but significantly, sharing little in common. The M in a path string means move to , whereas the same in a transformation string means Matrix . The path string is not to be confused with a transformation string. As with the path string, the uppercase letters are for absolute transformations and the lowercase for relative transformation. If the transformation string reads r90T100,0, then the element will rotate 90 degrees and move 100 px in the x axis (left). If the same reads r90t100,0, then the element will rotate 90 degrees and since the translation is relative, it will actually move vertically down 100px, as the rotation has tilted its axis. I am sure the previous point will confuse most, so let me break it up. Imagine a rectangle with a head and now this head is at the right side of the rectangle. For the time being, let's forget about absolute and relative transformation; our objective is to: Rotate the rectangle by 90 degrees. Move the rectangle 100px on the x axis (that is, 100px to the right). It's critical to understand that the elements' original values don't change when we translate it, meaning its x and y values will remain the same, no matter how we rotate or move the element. Now our first requirement is to rotate the rectangle by 90 degrees. The code for that would be rect.transform("r90") where r stands for rotation—fantastic, the rectangle is rotated by 90 degrees. Now pay attention to the next important step. We also need the rectangle to move 100px in the x axis and so we update our previous code to rect.transform("r90t100,0"), where t stands for translation. What happens next is interesting—the translation is done through a lowercase t, which means it's relative. One thing about relative translations is that they take into account any previous transformation applied to the element, whereas absolute translations simply reset any previous transformations before applying their own. Remember the head of the rectangle on the right side? Well, the rectangle's x axis falls on the right side. So when we say, move 100px on the x axis, it is supposed to move 100px towards its right side, that is, in the direction where its head is pointing. Since we have rotated the rectangle by 90 degrees, its head is no longer on the right side but is facing the bottom. So when we apply the relative translation, the rectangle will still move 100px to its x axis, but the x axis is now pointing down because of the rotation. That's why the rectangle will move 100px down when you expect it to move to the right. What happens when we apply absolute translation is something that is entirely different from the previous one. When we again update our code for absolute translation to rect.transform("r90T100,0"), the axis of the rectangle is not taken into consideration. However, the axis of the paper is used, as absolute transformations don't take previous transformations into account, and they simply reset them before applying their own. Therefore, the rectangle will move 100px to the right after rotating 90 degrees, as intended. Absolute transformations will ignore all the previous transformations on that element, but relative transformations won't. Getting a grip on this simple logic will save you a lot of frustration in the future while developing as well as while debugging. The following is a screenshot depicting relative translation: Using relative translation The following is a screenshot depicting absolute translation: Using absolute translation Notice the gap on top of the rotated rectangle; it's moved 100px on the one with relative translation and there is no such gap on top of the rectangle with absolute translation. By default, the transform method will append to any transformation already applied to the element. To reset all transformations, use element.transform(""). Adding an empty string to the transform method will reset all the previous transformations on that element. It's also important to note that the element's original x,y position will not change when translated. The element will merely assume a temporary position but its original position will remain unchanged. Therefore after translation, if we call for the element's position programmatically, we will get the original x,y, not the translated one, just so we don't jump from our seats and call RaphaelJS dull! The following is an example of scaling and rotating a triangle: //creating a Triangle using the path string var tri = paper.path("M0,0L104,0L52,72L0,0").attr({ "fill":"#17A9C6", "stroke":"#2A6570", "stroke-width":2 }); //transforming the triangle. tri.animate({ "transform":"r90t100,0,s1.5" },1000); //the transformation string should be read as rotating the element by 90 degrees, translating it to 100px in the X-axis and scaling up by 1.5 times The following screenshot depicts the output of the preceding code: Scaling and rotating a triangle The triangle is transformed using relative translation (t). Now you know the reason why the triangle has moved down rather than moving to its right. Animating a shape What good is a magic wand if it can't animate inanimate objects! RaphaelJS can animate as smooth as butter almost any property from color, opacity, width, height, and so on with little fuss. Animation is done through the animate() method. This method takes two required parameters, namely final values and milliseconds, and two optional parameters, easing and callback. The syntax for the animate() method is as follows: Element.animate({ Animation properties in key value pairs },time,easing,callback_function); Easing is that special effect with which the animation is done, for example, if the easing is bounce, the animation will appear like a bouncing ball. The following are the several easing options available in RaphaelJS: linear < or easeIn or ease-in > or easeOut or ease-out <> or easeInOut or ease-in-out backIn or back-in backOut or back-out elastic bounce Callbacks are functions that will execute when the animation is complete, allowing us to perform some tasks after the animation. Let's consider the example of animating the width and height of a rectangle: // creating a raphael paper in 'paperDiv' var paper = Raphael ("paperDiv", 650,400); rect.animate({ "width":200, // final width "height":200 // final height },300,"bounce',function(){ // something to do when the animation is complete – this callback function is optional // Print 'Animation complete' when the animation is complete $("#animation_status").html("Animation complete") }) The following screenshot shows a rectangle before animation: Rectangle before animation A screenshot demonstrating the use of a callback function when the animation is complete is as follows. The text Animation complete will appear in the browser after completing the animation. Use of a callback function The following code animates the background color and opacity of a rectangle: rect.animate({ "fill":"#ddd", // final color, "fill-opacity":0.7 },300,"easeIn",function(){ // something to do when the animation is complete – this call back function is optional // Alerts done when the animation is complete alert("done"); }) Here the rectangle is animated from blue to gray and with an opacity from 1 to 0.7 over a duration of 300 milliseconds. Opacity in RaphaelJS is the same as in CSS, where 1 is opaque and 0 is transparent.
Read more
  • 0
  • 0
  • 4563

article-image-php-5-social-networking-integrating-media-profile-posts
Packt
22 Oct 2010
13 min read
Save for later

PHP 5 Social Networking: Integrating Media in Profile Posts

Packt
22 Oct 2010
13 min read
Since different status types will use different status tables, we should use a left join to connect the tables, so we can keep just a single query to look up the statuses. It also pulls in the extra information when it is required. Let's get started with extending our profiles and the status stream! Changes to the view Since all of the media types we are going to support require at least one additional database field in a table that extends the statuses table, we are going to need to display any additional fields on the post status form. The standard type of status doesn't require additional fields, and new media types that we haven't discussed, which we may wish to support in the future, may require more than one additional field. To support a varying number of additional fields depending on the type, we could use some JavaScript (in this case, we will use the jQuery framework) to change the form depending on the context of the status. Beneath the main status box, we can add radio buttons for each of the status types, and depending on the one the user selects, the JavaScript can show or hide the additional fields, making the form more relevant. Template Our update status template needs a few changes: We need to set the enctype on the form, so that we can upload files (for posting images) We need radio buttons for the new types of statuses We need additional fields for those statuses The changes are highlighted in the following code segment: <p>Tell your network what you are up to</p> <form action="profile/statuses/{profile_user_id}" method="post" enctype="multipart/form-data"> <textarea id="status" name="status"></textarea> <br /> <input type="radio" name="status_type" id="status_checker_update" class="status_checker" value="update" />Update <input type="radio" name="status_type" id="status_checker_video" class="status_checker" value="video" />Video <input type="radio" name="status_type" id="status_checker_image" class="status_checker" value="image" />Image <input type="radio" name="status_type" id="status_checker_link" class="status_checker" value="link" />Link <br /> <div class="video_input extra_field"> <label for="video_url" class="">YouTube URL</label> <input type="text" id="" name="video_url" class="" /><br /> </div> <div class="image_input extra_field"> <label for="image_file" class="">Upload image</label> <input type="file" id="" name="image_file" class="" /><br /> </div> <div class="link_input extra_field"> <label for="link_url" class="">Link</label> <input type="text" id="" name="link_url" class="" /><br /> <label for="link_description" class="">Description</label> <input type="text" id="" name="link_description" class="" /><br /> </div> <input type="submit" id="updatestatus" name="updatestatus" value="Update" /> </form> These changes also need to be made to the post template, for posting on another user's profile. jQuery to enhance the user experience For accessibility purposes, we need this form to function regardless of whether the user has JavaScript enabled on their browser. To that end, we should use JavaScript to hide the unused form elements. So, even if the user has JavaScript disabled, they can still use all aspects of the form. We can then use JavaScript to enhance the user experience, toggling which aspects of the form are hidden or shown. <script type="text/javascript"> $(function() { First, we hide all of the extended status fields. $('.extra_field').hide(); $("input[name='status_type']").change(function(){ When the user changes the type of status, we hide all of the extended fields. $('.extra_field').hide(); We then show the fields directly related to the status type they have chosen. $('.'+ $("input[name='status_type']:checked").val() + '_input').show(); }); }); </script> View in action If we now take a look at our status updates page for our profile, we have some radio buttons that we can use to toggle elements of the form. Images To process images as a new status type, we will need a new database table and a new model to extend from the main status model. We will also need some new views, and to change the profile and status stream controllers (though we will make those changes after adding the three new status types). Database table The database table for images simply needs two fields:     Field Type Description ID Integer, Primary key To relate to the main statuses table Image Varchar The image filename These two fields will be connected to the statuses table via a left join, to bring in the image filename for statuses that are images. Model The model needs to extend our statuses model, providing setters for any new fields, call the parent constructor, call the parent setTypeReference method to inform that it is an image, call the parent save method to save the status, and then insert a new record into the image status table with the image information. Class, variable, and constructor Firstly, we define the class as an extension of the status class. We then define a variable for the image, and construct the object. The constructor calls the parent setTypeReference method to ensure it generates the correct type ID for an image, and then calls the parent constructor so it too has reference to the registry object. This file is saved as /models/imagestatus.php. <?php /** * Image status object * extends the base status object */ class Imagestatus extends status { private $image; /** * Constructor * @param Registry $registry * @param int $id * @return void */ public function __construct( Registry $registry, $id = 0 ) { $this->registry = $registry; parent::setTypeReference('image'); parent::__construct( $this->registry, $id ); } To call a method from an object's parent class, we use the parent keyword, followed by the scope resolution operator, followed by the method we wish to call. Processing the image upload When dealing with image uploads, resizing, and saving, there are different PHP functions that should be used depending on the type of the image. To make this easier and to provide a centralized place for dealing with image uploads and other image-related tasks, we should create a library file (lib/images/imagemanager. class.php) to make this easier. Let's discuss what an image manager library file should do to make our lives easier: Process uploading of an image from $_POST data Verify the type of file and the file extension Process images from the file system so that we can modify them Display an image to the browser Resize an image Rescale an image by resizing either the x or y co-ordinate, and scaling the other co-ordinate proportionally Get image information such as size and name Save the changes to the image The following is the code required to perform the above-mentioned tasks: <?php /** * Image manager class * @author Michael Peacock */ class Imagemanager { /** * Type of the image */ private $type = ''; /** * Extensions that the user can upload */ private $uploadExtentions = array( 'png', 'jpg', 'jpeg', 'gif' ); /** * Mime types of files the user can upload */ private $uploadTypes = array( 'image/gif', 'image/jpg', 'image/jpeg', 'image/pjpeg', 'image/png' ); /** * The image itself */ private $image; /** * The image name */ private $name; public function __construct(){} We need a method to load a local image, so that we can work with images saved on the servers file system. /** * Load image from local file system * @param String $filepath * @return void */ public function loadFromFile( $filepath ) { Based on the path to the image, we can get information on the image including the type of image (getimagesize gives us an array of information on the image; the second element in the array is the type). $info = getimagesize( $filepath ); $this->type = $info[2]; We can then compare the image type to various PHP constants, and depending on the image type (JPEG, GIF, or PNG) we use the appropriate imagecreatefrom function. if( $this->type == IMAGETYPE_JPEG ) { $this->image = imagecreatefromjpeg($filepath); } elseif( $this->type == IMAGETYPE_GIF ) { $this->image = imagecreatefromgif($filepath); } elseif( $this->type == IMAGETYPE_PNG ) { $this->image = imagecreatefrompng($filepath); } } We require a couple of getter methods to return the height or width of the image. /** * Get the image width * @return int */ public function getWidth() { return imagesx($this->image); } /** * Get the height of the image * @return int */ public function getHeight() { return imagesy($this->image); } We use a simple resize method that resizes the image to the dimensions we request. /** * Resize the image * @param int $x width * @param int $y height * @return void */ public function resize( $x, $y ) { $new = imagecreatetruecolor($x, $y); imagecopyresampled($new, $this->image, 0, 0, 0, 0, $x, $y, $this->getWidth(), $this->getHeight()); $this->image = $new; } Here we use a scaling function that takes a height parameter to resize to and scales the width accordingly. /** * Resize the image, scaling the width, based on a new height * @param int $height * @return void */ public function resizeScaleWidth( $height ) { $width = $this->getWidth() * ( $height / $this->getHeight() ); $this->resize( $width, $height ); } Similar to the above method, this method takes a width parameter, resizes the width, and rescales the height based on the width. /** * Resize the image, scaling the height, based on a new width * @param int $width * @return void */ public function resizeScaleHeight( $width ) { $height = $this->getHeight() * ( $width / $this->getWidth() ); $this->resize( $width, $height ); } The following is another scaling function, this time to rescale the image to a percentage of its current size: /** * Scale an image * @param int $percentage * @return void */ public function scale( $percentage ) { $width = $this->getWidth() * $percentage / 100; $height = $this->getheight() * $percentage / 100; $this->resize( $width, $height ); } To output the image to the browser from PHP, we need to check the type of the image, set the appropriate header based off the type, and then use the appropriate image function to render the image. After calling this method, we need to call exit() to ensure the image is displayed correctly. /** * Display the image to the browser - called before output is sent, exit() should be called straight after. * @return void */ public function display() { if( $this->type == IMAGETYPE_JPEG ) { $type = 'image/jpeg'; } elseif( $this->type == IMAGETYPE_GIF ) { $type = 'image/gif'; } elseif( $this->type == IMAGETYPE_PNG ) { $type = 'image/png'; } header('Content-Type: ' . $type ); if( $this->type == IMAGETYPE_JPEG ) { imagejpeg( $this->image ); } elseif( $this->type == IMAGETYPE_GIF ) { imagegif( $this->image ); } elseif( $this->type == IMAGETYPE_PNG ) { imagepng( $this->image ); } } To load an image from $_POST data, we need to know the post field the image is being sent through, the directory we wish to place the image in, and any additional prefix we may wish to add to the image's name (to prevent conflicts with images with the same name). /** * Load image from postdata * @param String $postfield the field the image was uploaded via * @param String $moveto the location for the upload * @param String $name_prefix a prefix for the filename * @return boolean */ public function loadFromPost( $postfield, $moveto, $name_prefix='' ) { Before doing anything, we should check that the file requested is actually a file that has been uploaded (and that this isn't a malicious user trying to access other files). if( is_uploaded_file( $_FILES[ $postfield ]['tmp_name'] ) ) { $i = strrpos( $_FILES[ $postfield ]['name'], '.'); if (! $i ) { //'no extention'; return false; } else { We then check that the extension of the file is in our allowed extensions array. $l = strlen( $_FILES[ $postfield ]['name'] ) - $i; $ext = strtolower ( substr( $_FILES[ $postfield ]['name'], $i+1, $l ) ); if( in_array( $ext, $this->uploadExtentions ) ) { Next, we check if the file type is an allowed file type. if( in_array( $_FILES[ $postfield ]['type'], $this->uploadTypes ) ) { Then, we move the file, as it has already been uploaded to our server's temp folder, to our own uploads directory and load it into our image manager class for any further processing we wish to make. $name = str_replace( ' ', '', $_FILES[ $postfield ]['name'] ); $this->name = $name_prefix . $name; $path = $moveto . $name_prefix.$name; move_uploaded_file( $_FILES[ $postfield ]['tmp_name'] , $path ); $this->loadFromFile( $path ); return true; } else { // 'invalid type'; return false; } } else { // 'invalid extention'; return false; } } } else { // 'not uploaded file'; return false; } } The following getter method is used to return the name of the image we are working with: /** * Get the image name * @return String */ public function getName() { return $this->name; } Finally, we have our save method, which again must detect the type of image, to work out which function to use. /** * Save changes to an image e.g. after resize * @param String $location location of image * @param String $type type of the image * @param int $quality image quality /100 * @return void */ public function save( $location, $type='', $quality=100 ) { $type = ( $type == '' ) ? $this->type : $type; if( $type == IMAGETYPE_JPEG ) { imagejpeg( $this->image, $location, $quality); } elseif( $type == IMAGETYPE_GIF ) { imagegif( $this->image, $location ); } elseif( $type == IMAGETYPE_PNG ) { imagepng( $this->image, $location ); } } } ?> Using the image manager library to process the file upload Now that we have a simple, centralized way of processing file uploads and resizing them, we can process the image the user is trying to upload as their extended status. /** * Process an image upload and set the image * @param String $postfield the $_POST field the image was uploaded through * @return boolean */ public function processImage( $postfield ) { require_once( FRAMEWORK_PATH . 'lib/images/imagemanager.class.php' ); $im = new Imagemanager(); $prefix = time() . '_'; if( $im->loadFromPost( $postfield, $this->registry- >getSetting('upload_path') . 'statusimages/', $prefix ) ) { $im->resizeScaleWidth( 150 ); $im->save( $this->registry->getSetting('upload_path') . 'statusimages/' . $im->getName() ); $this->image = $im->getName(); return true; } else { return false; } } Saving the status This leaves us with the final method for saving the status. This calls the parent object's save method to create the record in the statuses table. Then it gets the ID, and inserts a new record into the images table with this ID as the ID. /** * Save the image status * @return void */ public function save() { // save the parent object and thus the status table parent::save(); // grab the newly inserted status ID $id = $this->getID(); // insert into the images status table, using the same ID $extended = array(); $extended['id'] = $id; $extended['image'] = $this->image; $this->registry->getObject('db')->insertRecords( 'statuses_images', $extended ); } } ?>
Read more
  • 0
  • 0
  • 4552

article-image-reporting
Packt
19 Dec 2013
4 min read
Save for later

Reporting

Packt
19 Dec 2013
4 min read
(For more resources related to this topic, see here.) Creating a pie chart First, we made the component test CT for display purposes, but now let's create the CT to make it run. We will use the Direct function, so let's prepare that as well. In reality we've done this already. Duplicate a different app.html and change the JavaScript file like we have done before. Please see the source file for the code: 03_making_a_pie_chart/ct/dashboard/pie_app.html. Implementing the Direct function Next, prepare the Direct function to read the data. First, it's the config.php file that defines the API. Let's gather them together and implement the four graphs (source file: 04_implement_direct_function/php/config.php). .... 'MyAppDashBoard'=>array( 'methods'=>array( 'getPieData'=>array( 'len'=>0 ), 'getBarData'=>array( 'len'=>0 ), 'getLineData'=>array( 'len'=>0 ), 'getRadarData'=>array( 'len'=>0 ) ) .... Next, let's create the following methods to acquire data for the various charts: getPieData getBarData getLineData getRadarData First, implement the getPieData method for the pie chart. We'll implement the Direct method to get the data for the pie chart. Please see the actual content for the source code (source file: 04_implement_direct_function/php/classes/ MyAppDashBoard.php ). This is acquiring valid quotation and bill data items. With the data to be sent back to the client, set the array in items and set up the various names and data in a key array. You will now combine the definitions in the next model. Preparing the store for the pie chart Charts need a store, so let's define the store and model (source file: 05_prepare_the_store_for_the_pie_chart/app/model/ Pie.js). We'll create the MyApp.model.Pie class that has the name and data fields. Connect this with the data you set with the return value of the Direct function. If you increased the number of fields inside the model you just defined, make sure to amend the return field values, otherwise it won't be applied to the chart, so be careful. We'll use the model we made in the previous step and implement the store (source file: 05_prepare_the_store_for_the_pie_chart/app/model/ Pie.js). Ext.define('MyApp.store.Pie', { extend: 'Ext.data.Store', storeId: 'DashboardPie', model: 'MyApp.model.Pie', proxy: { type: 'direct', directFn: 'MyAppDashboard.getPieData', reader: { type: 'json', root: 'items' } } }) Then, define the store using the model we made and set up the Direct function we made earlier in the proxy. Creating the View We have now prepared the presentation data. Now, let's quickly create the view to display it (source file: 06_making_the_view/app/view/dashboard/Pie.js). Ext.define('MyApp.view.dashboard.Pie', { extend: 'Ext.panel.Panel', alias : 'widget.myapp-dashboard-pie', title: 'Pie Chart', layout: 'fit', requires: [ 'Ext.chart.Chart', 'MyApp.store.Pie' ], initComponent: function() { var me = this, store; store = Ext.create('MyApp.store.Pie'); Ext.apply(me, { items: [{ xtype: 'chart', store: store, series: [{ type: 'pie', field: 'data', showInLegend: true, label: { field: 'name', display: 'rotate', contrast: true, font: '18px Arial' } }] }] }); me.callParent(arguments); } }); Implementing the controller With the previous code, data is not being read by the store and nothing is being displayed. In the same way that reading was performed with onShow, let's implement the controller (source file: 06_making_the_view/app/controller/DashBoard.js): Ext.define('MyApp.controller.dashboard.DashBoard', { extend: 'MyApp.controller.Abstract', screenName: 'dashboard', init: function() { var me = this; me.control({ 'myapp-dashboard': { 'myapp-show': me.onShow, 'myapp-hide': me.onHide } }); }, onShow: function(p) { p.down('myapp-dashboard-pie chart').store.load(); }, onHide: function() { } }); With the charts we create from now on, as we create them it would be good to add the reading process to onShow. Let's take a look at our pie chart which appears as follows: Summary You must agree this is starting to look like an application! The dashboard is the first screen you see right after logging in. Charts are extremely effective in order to visually check a large and complicated amount of data. If you keep adding panels as and when you feel it's needed, you'll increase its practicability. This sample will become a customizable base for you to use in future projects. Resources for Article: Further resources on this subject: So, what is Ext JS? [Article] Buttons, Menus, and Toolbars in Ext JS [Article] Displaying Data with Grids in Ext JS [Article]
Read more
  • 0
  • 0
  • 4550

article-image-ibm-lotus-domino-adding-style-form-and-page-elements
Packt
29 Mar 2011
6 min read
Save for later

IBM Lotus Domino: Adding Style to Form and Page Elements

Packt
29 Mar 2011
6 min read
  IBM Lotus Domino: Classic Web Application Development Techniques A step-by-step guide for web application development and quick tips to enhance applications using Lotus Domino Most of the CSS rules you write for an application relate to design elements on forms and pages. Suggestions and examples in this section just scratch the surface of CSS possibilities. Browse the Web for additional ideas. Here we focus on the mechanics of how elements are styled, rather than on specific recommendations about what looks good, which is largely a matter of taste. Use color effectively Use pleasing, complementary colors. If your organization requires a specific set of colors, then, of course, find out what that palette is and conform to it as much as possible. Color tastes change over the years, primary colors dominating at times and lighter pastels in vogue at others. Here are a few generalities to consider: Use white or very light colors for backgrounds Use stronger colors such as dark red to make important elements stand out Use no more than three or four colors on a form Use black or dark gray text on a light background for lengthy text passages If you have paid little attention to the matter of color in your applications, do some web work on the subject. Once you select a color scheme, provide some samples to your customers for their opinions and suggestions. Style text Typography is a complex topic with a rich history and strong opinions. For web application design purposes, consider using web-safe fonts which are likely to be available on most or all personal computers. If you use a font that is not available to a browser, then text is rendered with a default font. Fonts with serifs are usually considered easier to read on paper, and less so as web page text. Experiment with the following fonts: Bookman Old Style Cambria Garamond Georgia Times New Roman Common fonts without serifs (sans serif) are considered easier to read on the Web. Some examples include: Arial Calibri Helvetica MS Sans Serif Tahoma Trebuchet MS Verdana Mono-spaced fonts are useful when you want text to line up—columns of numbers in a table, perhaps: Courier New Courier Establish a common font style with CSS rules applied to the body type selector or to a main division using a type selector, a class selector, or an ID selector: body { color: #555555; font-family: Verdana; font-size: 8pt; } Style headings and labels If headings and labels are bracketed with HTML heading tags (for example, <h1> or <h2gt;), they can be styled with type selectors: h1 { color: Blue; font-family: Arial; font-size: 18pt; font-weight: bold; } If headings and labels are bracketed with <span> tags, use CSS classes: <span class="highlight1">October News</span> Underline links in text but not in menus When browsers and the Web first appeared in the early 1990's, hyperlinks were a novelty. To distinguish a link from normal text, the convention developed to underscore the text containing the link, and often the link text was colored blue. There is no magic associated with underscoring and making text blue—it was just the convention adopted at the time. Today links in text passages are usually distinguished from adjacent text with color, weight or underscoring. In a menu, however, each item is understood to be a hotspot link. Underscores and blue text are not required. So if you feel like underscoring a link, do so if the link appears within some text, but don't underscore links in menus. At the same time, refrain from highlighting important text with underscoring, which implies that that text is a hyperlink. Use another highlighting technique; italics, bold, or an alternate color work well for this purpose. Style fields Fields can be styled with CSS either with the Style attribute in Field Properties or with CSS rules. The key to understanding how CSS rules can be applied to fields is to understand that fields are translated to the Web using <input> tags. Here is how a simple text field translates into HTML: <input name="FirstName" value=""> Here is how a radio button field translates: <input name="%%Surrogate_Gender" type="hidden" value="1"> <label><input type="radio" name="Gender" value="M">M</label><br> <label><input type="radio" name="Gender" value="F">F</label><br> CSS rules can be defined for the <input> tag, an ID, or a class. For example, assume that a CSS class named requiredtext is defined. If that class name is entered in the Class attribute of Field Properties, the resulting HTML might look like this: <input name="FirstName" value="" class="requiredtext"> CSS style rules coded for the requiredtext class are applied to the field. Highlight required fields Required fields are validated, most likely with JavaScript code, so that complete and good data is saved into the database when a document is submitted. If entered values fail validation, the user is presented with a message of some sort that identifies the problem and requests correction. Web forms typically identify which fields are required. Any of several techniques can be used. Required field labels can be styled with a more prominent color or a special marker such as an asterisk or a checkmark can be positioned near the field. Required fields also can be co-located and set apart using the <fieldset> and <legend> tags. If a field value fails validation, it is common practice to provide an error message and then to set the focus into the field; the cursor is positioned in the field to facilitate an immediate correction. As the cursor can be difficult to spot on a busy form, it is also possible to change the background color of the incorrect field as a way of drawing the user's attention to the field. In this illustration, the background color of the field has been changed to yellow: Implementing this technique requires writing a small JavaScript function that changes the background color of the field, and then calling that function when field validation fails.
Read more
  • 0
  • 0
  • 4550

article-image-aspnet-social-networks-making-friends-part-1
Packt
28 Oct 2009
19 min read
Save for later

ASP.NET Social Networks—Making Friends (Part 1)

Packt
28 Oct 2009
19 min read
Problem There are many aspects to building relationships in any community—real or virtual. First and foremost is initiating contact with the people whom you will eventually call your friends. We will do this in a few ways. First, we will provide a way for our users to search the site for friends who are also members. Second, we will create a form that allows you to enter your friends' email IDs and invite them directly. Third, we will create a form that allows you to import all of your contacts from Outlook. All of these methods of inviting a friend into the system would of course generate an email invite. The user would have the ability to then follow the link into the system and either sign up or log in to accept the request. The preceding screenshot shows a sample email that the user would receive in their inbox. And following is the message that would be seen: Once the user has clicked on the link in their email, he/she will be taken to a page displaying the request. Once we have a way for our users to attach friends to their profile, we need to start integrating the concept of friends into the fabric of our site. We will need a way for our users to view all of their friends. We will also need a way for our users to remove the relationships (for those users who are no longer friends!). Then we will need to add friends to our user's public profile. While this is a good first pass at integrating the concept of friends into our site, there are a couple more steps for true integration. We need to add friend request and friend confirm alerts. We also need to modify the alert system so that when users modify their profile, change their avatar, or any other alert that is triggered by users of our system, all of their friends are notified on The Filter. Once this is done we have one final topic to cover—which sort of fits in the realm of friends—the concept of Status Updates. This is a form of a micro blog. It allows users to post something about: What they are currently doing Where they are or What they are thinking about This is then added to their profile and sent out to their friends' filters. The box in the preceding screenshot is where the user can enter his/herStatus Updates. Each of these updates will also be shown on the updates view and in their filter views. This really helps to keep The Filter busy and helps people feel involved with their friends. Design Now let's talk about the design of these features. Friends This article is an attempt to throw light on the infrastructure needs and more heavily focused on the UI side for creating and managing relationships. That being said, there is always some form of groundwork that has to be in place prior to adding new features. In this case we need to add the concept of a friend prior to having the ability to create friendships. This concept is a relatively simple one as it is really only defining a relationship between two accounts. We have the account that requested the relationship and the account that accepted the relationship. This allows an account to be linked to as many other accounts as they wish. Finding friends Like in life, it is very difficult to create friends without first locating and meeting people. For that reason the various ways to locate and invite someone to be your friend is our first topic. Searching for a friend The easiest way to locate friends who might be interested in the same site that you are is to search through the existing user base. For that reason we will need to create a simple keyword search box that is accessible from any page on the site. This search feature should take a look at several fields of data pertaining to an account and return all possible users. From the search results page we should be able to initiate a friend request. Inviting a friend The next best thing to locating friends who are already members of the site is to invite people who you know out of the site. The quickest way to implement this is to allow a user to manually enter an email address or many email addresses, type a message, and then submit. This would be implemented with a simple form that generates a quick email to the recipient list. In the body of the email will be a link that allows the recipients to come in to our site. Importing friends from external sources An obvious extension of the last topic is to somehow automate the importing process of contacts from an email management tool. We will create a toolset that allows the user to export their contacts from Outlook and import them via a web form. The user should then be able to select the contacts that they want to invite. Sending an invitation With all the three of the above methods we will end up sending out an invitation email. We could simply send out an email with a link to the site. However, we need to maintain: Who has been invited Who initiated the invitation and When this occurred Then in the email, rather than just invite people in, we want to assign the user a key so that we can easily identify them on their way in. We will use a system-generated GUID to do this. In the case of inviting an existing user, we will allow him/her to log in to acknowledge the new friendship. In the case of a non-member user who was invited, we will allow him/her to create a new account. In both cases we will populate the invitation with the invited user's Account ID so that we have some history about the relationship. Adding friend alerts to the filter Once we have the framework in place for inviting and accepting friendship requests, we need to extend our existing system with alerts. These alerts should show up on existing user's Filters to show that they sent an invitation. We should also have alerts showing that a user has been invited. Once a user has accepted a friendship we should also have an alert. Interacting with your friends Now let's discuss some of the features that we need to interact with our friends. Viewing your friends Friends are only good if a user can interact with them. The first stop along this train of thought is to provide a page that allows a user to see all the friends he/she has. This is a jumping off point for a user to view the profile of friends. Also, as the concept of a user's profile grows, more data can be shown about each friend in an at-a-glance format. In addition to an all Friends page, we can add friends' views to a user's public profile so that other users can see the relationships. Managing your friends Now that we can see into all the relationships, we can finally provide the users with the ability to remove a relationship. In our initial pass this will be a permanent deletion of the relationship. Following your friends Now, we can extend the alert system so that when alerts are generated for a common user, such as updating their profile information, uploading a new photo, or any other user specific task, all the user's friends are automatically notified via their Filter. Providing status updates to your friends Somewhat related to friend-oriented relationships and The Filter is the concept of micro blogs. We need to add a way for a user to send a quick blurb about what they are doing, what they are thinking, and so on. This would also show up on the Filters of all the user's friends. This feature creates a lot of dynamic content on an end user's homepage, which keeps things interesting. Solution Now let's take a look at our solution. Implementing the database Let's look at the tables that are needed to support these new features. The Friends Table As the concept of friends is our base discussion for this article, we will immediately dive in and start creating the tables around this subject. As you have seen previously this is very straightforward table structure that simply links one account to the other. Friend Invitations This table is responsible for keeping track of who has been invited to the site, by whom, and when. It also holds the key (GUID) that is sent to the friends so that they can get back into the system under the appropriate invitation. Once a friend has accepted the relationship, their AccountID is stored here too, so that we can see how relationships were created in the past. Status Updates Status Updates allow a user to tell their friends what they are doing at that time. This is a micro blog so to speak. A micro blog allows a user to write small blurbs about anything. Examples of this are Twitter and Yammer. For more information take a look here: http://en.wikipedia.org/wiki/Micro-blogging The table needed for this is also simple. It tracks who said what, what was said, and when. Creating the Relationships Here are the relationships that we need for the tables we just discussed: Friends and Accounts via the owning account Friends and Accounts via the friends account FriendInvitations and Accounts StatusUpdates and Accounts Setting up the data access layer Let's extend the data access layer now to handle these new tables. Open your Fisharoo.dbml file and drag in these three new tables. We are not allowing LINQ to manage these relationships for us. So go ahead and remove the relationships from the surrounding tables. Once you hit Save we should have three new classes to work with! Building repositories As always, with these new tables will come new repositories. The following repositories will be created: FriendRepository FriendInvitationRepository StatusUpdateRepository In addition to the creation of the above repositories, we will also need to modify the AccountRepository. FriendRepository Most of our repositories will always follow the same design. They provide a way to get at one record, many records by a parent ID, save a record, and delete a record. This repository differs slightly from the norm when it is time to retrieve a list of friends in that it has two sides of the relationship to look at—on one side where it is the owning Account of the Friend relationship and on the other side where the relationship is owned by another account. Here is that method: public List<Friend> GetFriendsByAccountID(Int32 AccountID){ List<Friend> result = new List<Friend>(); using(FisharooDataContext dc = conn.GetContext()) { //Get my friends direct relationship IEnumerable<Friend> friends = (from f in dc.Friends where f.AccountID == AccountID && f.MyFriendsAccountID AccountID select f).Distinct(); result = friends.ToList(); //Getmy friends indirect relationship var friends2 = (from f in dc.Friends where f.MyFriendsAccountID == AccountID && f.AccountID != AccountID select new { FriendID = f.FriendID, AccountID = f.MyFriendsAccountID, MyFriendsAccountID = f.AccountID, CreateDate = f.CreateDate, Timestamp = f.Timestamp }).Distinct(); foreach (object o in friends2) { Friend friend = o as Friend; if(friend != null) result.Add(friend); } } return result;} This method queries for all friends that are owned by this account. It then queries for the reverse relationship where this account is owned by another account. Then it adds the second query to the first and returns that result. Here is the method that gets the Accounts of our Friends: public List<Account> GetFriendsAccountsByAccountID(Int32 AccountID){ List<Friend> friends = GetFriendsByAccountID(AccountID); List<int> accountIDs = new List<int>(); foreach (Friend friend in friends) { accountIDs.Add(friend.MyFriendsAccountID); } List<Account> result = new List<Account>(); using(FisharooDataContext dc = conn.GetContext()) { IEnumerable<Account> accounts = from a in dc.Accounts where accountIDs.Contains(a.AccountID) select a; result = accounts.ToList(); } return result;} This method first gathers all the friends (via the first method we discussed) and then queries for all the related accounts. It then returns the result. FriendInvitationRepository Like the other repositories this one has the standard methods. In addition to those we also need to be able to retrieve an invitation by GUID or the invitation key that was sent to the friend. public FriendInvitation GetFriendInvitationByGUID(Guid guid){ FriendInvitation friendInvitation; using(FisharooDataContext dc = conn.GetContext()) { friendInvitation = dc.FriendInvitations.Where(fi => fi.GUID == guid).FirstOrDefault(); } return friendInvitation;} This is a very straightforward query matching the GUID values. In addition to the above method we will also need a way for invitations to be cleaned up. For this reason we will also have a method named CleanUpFriendInvitations(). public void CleanUpFriendInvitationsForThisEmail(FriendInvitation friendInvitation){ using (FisharooDataContext dc = conn.GetContext()) { IEnumerable<FriendInvitation> friendInvitations = from fi in dc.FriendInvitations where fi.Email == friendInvitation.Email && fi.BecameAccountID == 0 && fi.AccountID == friendInvitation.AccountID select fi; foreach (FriendInvitation invitation in friendInvitations) { dc.FriendInvitations.DeleteOnSubmit(invitation); } dc.SubmitChanges(); }} This method is responsible for clearing out any invitations in the system that are sent from account A to account B and have not been activated (account B never did anything with the invite). Rather than checking if the invitation already exists when it is created, we will allow them to be created time and again (checking each invite during the import process of 500 contacts could really slow things down!). When account B finally accepts one of the invitations all of the others will be cleared. Also, in case account B never does anything with the invites, we will need a database process that periodically cleans out old invitations. StatusUpdateRepository Other than the norm, this repository has a method that gets topN StatusUpdates for use on the profile page. public List<StatusUpdate> GetTopNStatusUpdatesByAccountID(Int32 AccountID, Int32 Number){ List<StatusUpdate> result = new List<StatusUpdate>(); using (FisharooDataContext dc = conn.GetContext()) { IEnumerable<StatusUpdate> statusUpdates = (from su in dc.StatusUpdates where su.AccountID == AccountID orderby su.CreateDate descending select su).Take(Number); result = statusUpdates.ToList(); } return result;} This is done with a standard query with the addition of the Take() method, which translates into a TOP statement in the resulting SQL. AccountRepository With the addition of our search capabilities we will require a new method in our AccountRepository. This method will be the key for searching accounts. public List<Account> SearchAccounts(string SearchText){ List<Account> result = new List<Account>(); using (FisharooDataContext dc = conn.GetContext()) { IEnumerable<Account> accounts = from a in dc.Accounts where(a.FirstName + " " + a.LastName).Contains(SearchText) || a.Email.Contains(SearchText) || a.Username.Contains(SearchText) select a; result = accounts.ToList(); } return result;} This method currently searches through a user's first name, last name, email address, and username. This could of course be extended to their profile data and many other data points (all in good time!). Implementing the services/application layer Now that we have the repositories in place, we can begin to create the services that sit on top of those repositories. We will be creating the following services: FriendService In addition to that we will also be extending these services: AlertService PrivacyService FriendService The FriendService currently has a couple of duties. We will need it to tell us whether or not a user is a Friend, so that we can extend the PrivacyService to consider friends (recall that we currently only understand public and private settings!). In addition to that we need our FriendService to be able to handle creating Friends from a FriendInvitation. public bool IsFriend(Account account, Account accountBeingViewed){ if(account == null) return false; if(accountBeingViewed == null) return false; if(account.AccountID == accountBeingViewed.AccountID) return true; else { Friend friend = _friendRepository.GetFriendsByAccountID (accountBeingViewed.AccountID). Where(f => f.MyFriendsAccountID == account.AccountID).FirstOrDefault(); if(friend != null) return true; } return false;} This method needs to know who is making the request as well as who it is making the request about. It then verifies that both accounts are not null so that we can use them down the road and returns false if either of them are null. We then check to see if the user that is doing the viewing is the same user as is being viewed. If so we can safely return true. Then comes the fun part—currently we are using the GetFriendsByAccountID method found in the FriendRepository. We iterate through that list to see if our friend is there in the list or not. If we locate it, we return true. Otherwise the whole method has failed to locate a result and returns false. Keep in mind that this way of doing things could quickly become a major performance issue. If you are checking security around several data points frequently in the same page, this is a large query and moves a lot of data around. If someone had 500 friends this would not be acceptable. As our goal is for people to have lots of friends, we generally would not want to follow this way. Your best bet then is to create a LINQ query in the FriendsRepository to handle this logic directly only returning true or false. Now comes our CreateFriendFromFriendInvitation method, which as the name suggests, creates a friend from a friend invitation! public void CreateFriendFromFriendInvitation(Guid InvitationKey, Account InvitationTo){ //update friend invitation request FriendInvitation friendInvitation = _friendInvitationRepository. GetFriendInvitationByGUID(InvitationKey); friendInvitation.BecameAccountID = InvitationTo.AccountID; _friendInvitationRepository.SaveFriendInvitation(friendInvitation); _friendInvitationRepository.CleanUpFriendInvitationsForThisEmail(frie ndInvitation); //create friendship Friend friend = new Friend(); friend.AccountID = friendInvitation.AccountID; friend.MyFriendsAccountID = InvitationTo.AccountID; _friendRepository.SaveFriend(friend); Account InvitationFrom = _accountRepository.GetAccountByID (friendInvitation.AccountID); _alertService.AddFriendAddedAlert(InvitationFrom, InvitationTo); //TODO: MESSAGING - Add message to inbox regarding new friendship!} This method expects the InvitationKey (in the form of a system generated GUID) and the Account that is wishing to create the relationship. It then gets the FriendInvitation and updates the BecameAccountID property of the new friend. We then make a call to flush any other friend invites between these two users. Once we have everything cleaned up, we add a new alert to the system letting the account that initiated this invitation know that the invitation was accepted. AlertService The alert service is essentially a wrapper to post an alert to the user's profile on The Filter. Go through the following methods. They do not need much explanation! public void AddStatusUpdateAlert(StatusUpdate statusUpdate){ alert = new Alert(); alert.CreateDate = DateTime.Now; alert.AccountID = _userSession.CurrentUser.AccountID; alert.AlertTypeID = (int)AlertType.AlertTypes.StatusUpdate; alertMessage = "<div class="AlertHeader">" + GetProfileImage(_userSession.CurrentUser.AccountID) + GetProfileUrl(_userSession.CurrentUser.Username) + " " + statusUpdate.Status + "</div>"; alert.Message = alertMessage; SaveAlert(alert); SendAlertToFriends(alert);}public void AddFriendRequestAlert(Account FriendRequestFrom, Account FriendRequestTo, Guid requestGuid, string Message){ alert = new Alert(); alert.CreateDate = DateTime.Now; alert.AccountID = FriendRequestTo.AccountID; alertMessage = "<div class="AlertHeader">" + GetProfileImage(FriendRequestFrom.AccountID) + GetProfileUrl(FriendRequestFrom.Username) + " would like to be friends!</div>"; alertMessage += "<div class="AlertRow">"; alertMessage += FriendRequestFrom.FirstName + " " + FriendRequestFrom.LastName + " would like to be friends with you! Click this link to add this user as a friend: "; alertMessage += "<a href="" + _configuration.RootURL + "Friends/ConfirmFriendshipRequest.aspx?InvitationKey=" + requestGuid.ToString() + "">" + _configuration.RootURL + "Friends/ConfirmFriendshipRequest.aspx?InvitationKey=" + requestGuid.ToString() + "</a><HR>" + Message + "</div>"; alert.Message = alertMessage; alert.AlertTypeID = (int) AlertType.AlertTypes.FriendRequest; SaveAlert(alert);}public void AddFriendAddedAlert(Account FriendRequestFrom, Account FriendRequestTo){ alert = new Alert(); alert.CreateDate = DateTime.Now; alert.AccountID = FriendRequestFrom.AccountID; alertMessage = "<div class="AlertHeader">" + GetProfileImage(FriendRequestTo.AccountID) + GetProfileUrl(FriendRequestTo.Username) + " is now your friend!</div>"; alertMessage += "<div class="AlertRow">" + GetSendMessageUrl(FriendRequestTo.AccountID) + "</div>"; alert.Message = alertMessage; alert.AlertTypeID = (int)AlertType.AlertTypes.FriendAdded; SaveAlert(alert); alert = new Alert(); alert.CreateDate = DateTime.Now; alert.AccountID = FriendRequestTo.AccountID; alertMessage = "<div class="AlertHeader">" + GetProfileImage(FriendRequestFrom.AccountID) + GetProfileUrl(FriendRequestFrom.Username) + " is now your friend!</div>"; alertMessage += "<div class="AlertRow">" + GetSendMessageUrl(FriendRequestFrom.AccountID) + "</div>"; alert.Message = alertMessage; alert.AlertTypeID = (int)AlertType.AlertTypes.FriendAdded; SaveAlert(alert); alert = new Alert(); alert.CreateDate = DateTime.Now; alert.AlertTypeID = (int) AlertType.AlertTypes.FriendAdded; alertMessage = "<div class="AlertHeader">" + GetProfileUrl(FriendRequestFrom.Username) + " and " + GetProfileUrl(FriendRequestTo.Username) + " are now friends!</div>"; alert.Message = alertMessage; alert.AccountID = FriendRequestFrom.AccountID; SendAlertToFriends(alert); alert.AccountID = FriendRequestTo.AccountID; SendAlertToFriends(alert);} PrivacyService Now that we have a method to check if two people are friends or not, we can finally extend our PrivacyService to account for friends. Up to this point we are only interrogating whether something is marked as private or public. Friends is marked false by default! public bool ShouldShow(Int32 PrivacyFlagTypeID, Account AccountBeingViewed, Account Account, List<PrivacyFlag> Flags){ bool result; bool isFriend = _friendService.IsFriend(Account,AccountBeingViewed); //flag marked as private test if(Flags.Where(f => f.PrivacyFlagTypeID == PrivacyFlagTypeID && f.VisibilityLevelID == (int)VisibilityLevel.VisibilityLevels.Private) .FirstOrDefault() != null) result = false; //flag marked as friends only test else if (Flags.Where(f => f.PrivacyFlagTypeID == PrivacyFlagTypeID && f.VisibilityLevelID == (int)VisibilityLevel.VisibilityLevels.Friends) .FirstOrDefault() != null && isFriend) result = true; else if (Flags.Where(f => f.PrivacyFlagTypeID == PrivacyFlagTypeID && f.VisibilityLevelID == (int)VisibilityLevel.VisibilityLevels.Public) .FirstOrDefault() != null) result = true; else result = false; return result;} Summary The article started with the thought process of how we can apply the concept of Friends to our community site. We tried to figure out what we need to do to implement the concept, we then finalized our requirements, and finally we began implementing the features. In the next part of this article we will continue with the implementation process.  
Read more
  • 0
  • 0
  • 4549

article-image-working-flexible-content-elements-typo3-templates
Packt
19 Nov 2010
17 min read
Save for later

Working with Flexible Content Elements in TYPO3 Templates

Packt
19 Nov 2010
17 min read
  TYPO3 Templates Create and modify templates with TypoScript and TemplaVoila Build dynamic and powerful TYPO3 templates using TypoScript, TemplaVoila, and other core technologies. Customize dynamic menus, logos, and headers using tricks you won’t find in the official documentation. Build content elements and template extensions to overhaul and improve TYPO3’s default back-end editing experience. Follow along with the step-by-step instructions to build a site from scratch using all the lessons in the book in a practical example.        Introducing flexible content elements I just said flexible content elements are like mini-templates, but they are actually a little more sophisticated than that. TYPO3 templates, traditionally, are just used to design the pages of your website. Well, flexible content elements are there as a way to create our own specialized types of content elements. Flexible content elements give us most of the power that we've had in the main TemplaVoila templates; the workflow and structure is almost exactly the same. We still have a data structure and a mapped object for each template, and we can still create backend layouts and preview images to help our editors. So, we already have all the raw skills we need to start creating them, but we just need a few examples of where we would want them. Creating a flexible content element really is just like creating a new content type for our sites utilizing the power of TemplaVoila. Once created, they can be embedded into any templates or even other FCEs. We can use references to link them across separate pages. We can copy them around between TYPO3 installations easily. We can even update the main template object or data structure of an FCE and watch our changes reach to every instance of that content element in our page tree. The best examples of this are going to be some of the ones we're about to build: a contact section, a div to wrap around other content elements, a multi-column element, and a custom product layout. Creating our first flexible content element The first FCE we're going to create is going to be simple enough to show us the basic workflow, but it's also a pretty handy trick so that we can add our contact information onto multiple pages using consistent formatting across our site. We're going to create a new flexible content element for our contact information using microformats (http://microformats.org/) so that Google and some browsers can read our address, phone number, and email address easier. Normally, this would require a lot of extra work to place it on multiple pages, but we can create an FCE that our editors can add to any page just like a normal content element. Building the content element Of course, the first thing that we should do is create an HTML file that we can use for our mapping. FCEs are normally mapped to a part of a complete HTML template, while page templates are mapped to the whole file. For our example, we will create one universal HTML file to hold all of our flexible content element HTML snippets called template_fce_snippets.html in the fileadmin/templates/ directory. At this point, we can create our HTML that the FCE will be based on. Like we said before, we are going to use microformats so that our contact information can be read by software more easily. To use microformats, we are just going to add some specific class names to the span and div tags around our information. If you would like to see more information about microformats, I recommend going to http://microformats.org/. For now, we can add this code into our template_fce_snippets.html file: <!DOCTYPE HTML> <html> <head> <meta charset="utf-8" /> </head> <body> <div id="contact_info_section"> <h3 id="contact_info_title">Contact Us</h3> <div class="vcard"> <div class="fn org">Example.com</div> <div class="adr"> <div class="street-address">1214 Rebekah Ave. </div> <span class="locality">Dallas</span>, <span class="region">TX</span> <span class="postal-code">75154</span> <span class="country-name">USA</span> </div> <div class="tel">(212) 555-1212</div> <a class="email" href="mailto:jeremy@example.com">jeremy@example.com</a> </div> </div> </body> </html> We are ready to start creating the TemplaVoila structures now, so we can go to the TemplaVoila Control Center in the backend of our installation now. We can create a new data structure by going to the Template Files tab in the control center. To create a new template object and data structure simultaneously based on our new HTML file, we need to click on the Create... link for our template file, fileadmin/templates/template_fce_snippets.html. Now we need to choose the root data element. Go ahead and choose the main div tag (circled in the following screenshot). We need to make sure we set the mapping mode to OUTER (Include tag). Due to an oddity in TemplaVoila, outer mapping is the only way to make sure that we actually keep the contact_info_section class after mapping. It may be counter-intuitive, but TemplaVoila treats root elements exactly the opposite of all other elements in its implementation of outer and inner mapping modes. Click on Set to start creating our data structure. Now that we have set the root, we can add our own fields to the FCE data structure. All of our contact information can be static, so we will just create a field for the header. Like the page templates, we will create a new field by filling the in name, field_header, at the bottom of the page as shown in following screenshot, and click on Add. Now we can fill in the form for our new field. We will set the Title to Header, and we can set the Sample Data as [Header goes here]. As we are using this as a header, we can choose Header field as our Element Preset. After we have filled out the form as shown in the following screenshot, we can click on Add to save our settings. Map the header field to the h3 tag in our HTML template and click on Set to save the mapping. We've finished creating our small content element, so we can click on the Save as button in our builder screen and save our progress. We are creating a new data structure, so we will need to fill out the CREATE Data Structure/ Template Object portion of the TemplaVoila save screen. We will give our new element an easy title, Contact Information. We also need to make sure we choose Content Element from the Template Type drop down because we are creating an FCE instead of a page template this time. Our screen should look something like shown in the following screenshot before we click on the CREATE DS / TO button: Testing our new content element We can add our element to any page the same way we've been adding text or graphic elements in the past through the Page view. Go to the main page in the backend of TYPO3 and click on the new element button (circled in the following screenshot). Added to the choices of standard or extension-based elements, we can see our own flexible content element, Contact Information [Template], listed. Go ahead and choose it to add it to the page. The next screen we see is the content editing screen where we can fill in the header for our new element: Finally, we can save our new content element and see the output on the frontend (highlighted in the following screenshot): Creating a flexible HTML wrapper As a website grows, we sometimes run into times where we would like to assign a special style to a content element or group of content elements, but there is no easy way to do this in TYPO3 without creating a new page template. All we really want to do is wrap a div tag around the group of elements we are styling with a CSS class to give them any style we need from our own stylesheets. For example, we might want to highlight a group of content elements with a color background or border. We will create a flexible content element to output a div tag with a blank class attribute that can contain normal page content elements. The FCE will have a field for the class, so our editors can fill in whatever class they need to use later. We're also keeping control over the options that editors have. They are still restricted to using CSS classes, as opposed to arbitrary style attributes, so we have not given them too much freedom. Building the content element First, we can create our HTML to which the FCE will be mapped. All we need is a div tag with a blank class attribute, so we can just add our snippet to the bottom of /fileadmin/templates/template_fce_snippets.html. We will also add some HTML comments around our new snippet so that we can always identify it in the HTML file: <!-- BEGIN HTML Wrapper --> <div class=""></div> <!-- END HTML Wrapper --> Now, we go back to the TemplaVoila module in the backend. From the Template Files tab in the TemplaVoila Control Center, click on Create... next to the file fileadmin/templates/template_fce_snippets.html label. Go ahead and choose our new div tag between the HTML comments (circled in the following screenshot) and click on Set to start creating our data structure. Again, choose OUTER (Include tag) as our mapping mode. The first field we need to create is the wrapper field for the content element. We have already set the div tag as the root element, but we still need to create a separate field to handle content elements or we won't be able to add content into our new FCE in the Page view. Like before, we can create a field by filling in the new field text area with a new name, field_wrapper, and clicking on the Add button. Now we can create the field with the following values just like we did when we added fields to our main templates. Like our page templates, we are going to use the Page-Content Elements preset because it allows us to place other content elements inside our new field: Field: field_wrapper Element Title: Wrapper Sample Data: [Content goes here] Element Preset: Page-Content Elements Once we have created and saved our new field, we can map it to the div tag by clicking on the Map button. We can use inner mapping this time because we want to keep the tag and this is not the ROOT field. The next field we need to create is the class field so that we can edit the class from the page module. Instead of an element, we are creating an attribute. To create the new field, fill in the name, field_class, at the bottom of our page and click on Add. Choose Attribute from the drop down on the left side and fill out the field values: Title: Class Sample Data: [Class field] Element Preset: Plain input field After we have created the new class attribute and saved it, we can map it to the class attribute in our div tag. If we click on the Map button for the class field, we see that we can only choose the div tag to map to; this is okay. If the div tag is grayed out or disabled, we probably need to check that the root element was set with OUTER mapping. After we click on the div tag, we are presented with a slightly different mapping screen than we have seen before. Up until now, we have been mapping tags instead of attributes, so our choice has been INNER or OUTER mode. When mapping attributes, this drop down will show any blank attributes that exist within the HTML template for that tag. If we wanted to set a relation attribute, for example, the HTML just needs to have rel="" present in the tag with or without a value. For now, we can choose ATTRIBUTE "class" (= ) from the drop down and click on the Set button to continue. We've created all of the fields we need for this small content element, so we can click on the Save as button to save our progress. We will give our new element an easy title, HTML Wrapper. We also need to make sure we choose Content Element from the Template Type drop down again. Testing our new content element We now have a data structure and template object created as a flexible content element and mapped, so we are ready to test. We can test with almost any class from our stylesheet, but we'll make it easy by adding a new class style to the bottom of our style.css file with a color background, rounded corners, and a slight shadow to highlight content: .alert { background-color: #BBCCDD; padding: 10px; -webkit-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px; box-shadow: 2px 2px 5px #888; -webkit-box-shadow: 2px 2px 5px #888; -moz-box-shadow: 2px 2px 5px #888; } As an example, we can highlight a couple of bullet lists on the Bulletlist page that the TemplaVoila wizard created. Go to the Bulletlist page in the backend of TYPO3 and choose to add a new element like we did for the Contact Information FCE. This time, choose HTML Wrapper [Template] for our new element. The next screen we see is the editing screen, and we can see that the titles we gave our data structure fields are showing up along with the different form elements we just declared. We can add elements to the wrapper here, but it's easier in the page module. Instead, we'll just set the Class field to alert to match our stylesheet, and save our new element. Finally, in the page module, we can drag elements into our new content element, and our new div tag with a class we have set in the settings will wrap around them. We can drag two of our bullet lists into the FCE: If we look at our edited page on the frontend, we can see the new CSS styling applied immediately: Creating a multi-column layout element As helpful as a wrapping div tag can be, we should start getting a little bigger with our goals. One thing that we run into all the time in the real world of site development is the need to have multi-column elements. With the rise of grid-based design and content-heavy sites, it's getting more popular to start adding two columns into the main content area under a single column article or something similar. Unfortunately, there are a lot of variations on this idea of mixing and nesting multi-column layouts, and it's not always possible or smart to create a template for every possible variation in a limited amount of time. You can easily waste all your time creating templates with a two-column element over a three-column element over a two-column element over a single-column element. I know that sounded confusing, and that's the problem. Instead, we can create a handful of useful multi-column flexible content elements that our editors can use anywhere they need to and in any order they need to. They can even nest them inside of each other if we do this right. Right now, we're going to make a quick FCE with two columns that take up roughly half of the current content area. We're just going to start by adding some basic styling to our main stylesheet, fileadmin/templates/style.css: .multi_column_element { display: inline-block; width: 100%; } #nested_column_1 { float: left; clear: left; } #nested_column_2 { float: right; clear: right; } .half { width: 49%; } As you can see above, we are using inline-block as the display setting for the entire element. If we don't set that, then the elements below it can creep up when we start using floats. For more information on CSS values like inline-block, I recommend the tutorials from w3schools.com (http://www.w3schools.com/css/). In addition, our style floats the first column, nested_column_1, to the left and clears anything to its left. The second column, nested_column_2, floats to the right and clears anything to the right of it. If we assign the class half to both columns, then they will both take up a little under 50% of the total width with a little whitespace in the middle. After we've modified the CSS, we need to update our HTML file. Once again, we'll add our new HTML code with identifying comments into our HTML template, /fileadmin/templates/template_fce_snippets.html. Go ahead and add some basic code to the main FCE HTML file to create two divs for columns: <!-- BEGIN 1/2 + 1/2 Element --><div class="multi_column_element"> <div class="nested_column half" id="nested_column_1">Column 1</div> <div class="nested_column half" id="nested_column_2">Column 2</div> </div> <!-- END 1/2 + 1/2 Element --> Now we're going to follow most of the same steps from the previous examples starting with the creation of a new data structure: From the Template Files tab in the TemplaVoila Control Center, click on Create... next to the file fileadmin/templates/template_fce_snippets.html label. Choose the main div tag that wraps around the entire HTML template as the root field. Again, we need to make sure we set the mapping mode to OUTER (Include tag). Create a new field for the first column named field_column_1. As the float is set completely in CSS, we will not refer to the columns as left or right columns here. This means we could swap the columns in CSS or assign different identifiers in the HTML without breaking our data structure. Go ahead and create our new field with these values: Field: field_column_1 Element Title: Column 1 Sample Data: [Column #1 goes here] Element Preset: Page-Content Elements Save the first field and map field_column_1 to the div tag with the ID nested_column_1. Make sure that you select inner mapping so that the classes and identifiers are left in the div tag. Create a new field for the second column with almost the same values as the first column: Field: field_column_2 Element Title: Column 2 Sample Data: [Column #2 goes here] Element Preset: Page-Content Elements Save the second column field and map it to the div tag with the ID nested_column_2 in the HTML. Click on the Save as button to save our new data structure and template object. Set the title as something memorable, Two-Column Element, before choosing Content Element as the Template Type and clicking CREATE DS / TO. As easy as that, we've just created another FCE. We can test this one on the main page of our test site by creating a new content element with our new FCE, Two-Column Element, and dragging our current blocks into either side: With two even columns, our front page should look something like this:
Read more
  • 0
  • 0
  • 4531
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-creating-your-first-web-page-using-expressionengine-part-1
Packt
14 Oct 2009
8 min read
Save for later

Creating Your First Web Page Using ExpressionEngine: Part 1

Packt
14 Oct 2009
8 min read
Toast for Sale! To demonstrate the power of ExpressionEngine, we are going to use a fictitious business as an example throughout this article. Our website is in the business of selling toast (heated bread with melted butter) online. With this example, we will be able to explore many of the nuances of building a complete website with ExpressionEngine. Though unlikely that we would really want to sell toast over the internet, the concepts of our example should be transferable to any website. In this article, we want to introduce the world to our business, so we are going to create a 'News from the President' webpage. This will allow the President of our company to communicate to customers and investors the latest goings-on in his business. Inside the Control Panel When you first log into the control panel, there are lots of options. Let us take a quick tour of the control panel. First, we will need to log into ExpressionEngine. If you are using XAMPP to follow along with this article, go to http://localhost/admin.php or http://localhost/system/index.php to log in. It is assumed that you are using XAMPP with http://localhost/ addresses. If you are following along on an actual website, substitute http://localhost/ for your website domain (for example, http://www.example.com/). It is required to move the login page to the root of our website to mask the location of our system directory The first page we see is the CP Home. We can return to this page anytime by selecting CP Home from the menu at the top-right of the screen, above the main menu. In the left column, we have EllisLab News Feed. Below, we have Most Recent Weblog Entries as well as any Recent Comments or trackbacks visitors may have left. In our case, our site is brand new, so there will be no recent comments or trackbacks, and only 1 recent weblog entry (Getting Started with ExpressionEngine). Clicking on the link will take you directly to that entry. On the right, there is a Bulletin Board (a way for you to pass messages to other members of your control panel), the Site Statistics and a Notepad (we can write anything here, and it will be available every time we log-in). Across the top is the main menu bar, and at the top-right are links to your website (My Site), this page (CP Home), the ExpressionEngine user-guide (User Guide), and to log-out (Log-out). The Publish and Edit links in the main menu bar are where you can create new entries and edit existing entries. The Templates link is where we can create new templates and edit existing templates. We will spend most of our time in these sections. The Communicate tab is where we can manage bulk-emails to our website members. At this time we do not have any members to email (other than ourselves), but as our site grows larger, this feature can be a useful communication/marketing tool. Be careful to avoid sending unsolicited bulk emails (or spam) using this feature. In many countries, there are laws governing what can or cannot be done. In the United States, commercial emails must meet very specific guidelines set by the Federal Trade Commission (http://www.ftc.gov/spam/). The Modules tab is where we can manage all the modules that come with ExpressionEngine, as well as optional third-party modules that we may wish to install. We can download additional modules from http://expressionengine.com/downloads/addons/category/modules/. The My Account tab is where we can edit our login preferences, including our username and password. We can also edit the look and feel of the control panel home page from this screen, as well as send private messages to other members. Much of this page is irrelevant when we are the only member of the site (as we are right now). The Admin tab is where most of the configuration of ExpressionEngine takes place, and we will spend a lot of time here. By default, most of the ExpressionEngine settings are already properly set, but feel free to browse and explore all the options that are available. Full documentation on each of the options is available at http://expressionengine.com/docs/cp/admin/index.html. This concludes our brief tour of ExpressionEngine. Now we are going to delve into one of the most important parts of the control panel—templates. Templates and URLs The basic concept in ExpressionEngine is that of a template. Go to any ExpressionEngine-powered website and you will undoubtedly be looking at a template. Templates are what the outside world sees. At its most basic, a template in ExpressionEngine is a HTML (or CSS or JavaScript) file. If we wanted to, we could use a template exactly like a HTML file, without any problems. We could create an entire website without ever using any other part of ExpressionEngine. However, we can take templates a lot further than that. By using ExpressionEngine tags inside our templates, we can take advantage of all the features of ExpressionEngine and combine it with all the flexibility that HTML and CSS offers in terms of layout and design. We are not limited to pre-defined 'cookie-cutter' templates that have been carefully adapted to work with ExpressionEngine. This is why ExpressionEngine is very popular with website designers. On the flip side, this is also why there is such a learning curve with ExpressionEngine. There is no point-and-click interface to change the look and feel of your website; you have to have some experience with HTML to get the most out of it. Let us take a closer look at templates and how they relate to URLs: If you are not already logged in, log into ExpressionEngine at either http://localhost/admin.php or http://www.example.com/admin.php. Click on the Templates button on the top of the screen. Templates are stored in groups. There is no 'right' way to group templates—some sites have all their templates in a single group and other sites have lots of template groups. We are going to create a new template group for each section of our website. ExpressionEngine does come pre-installed with two template groups: the site template group and the search template group. As a new user, it is best not to delete these template groups in case you want to refer to them later. In the next screen we can give our template group a name; let us use toast. There is an option to Duplicate an Existing Template Group which copies all the templates from one template group into our new template group. This can be useful if we are creating one template group that will work very similarly to the one that we already created, but as this is our first template group, we are going to start from scratch. Checking the box Make the index template in this group your site's home page? means that visitors will see the toast website in place of the ExpressionEngine example site. If you are using the XAMPP test server, go ahead and check this box. Hit Submit to create the template group. We will be returned to the Template Management screen. A message will appear saying Template Group Created, and the new template will appear in the box of groups on the left-hand side. Left-click on the New Template group in the Choose Group box on the left-hand side. Each template group comes with an initial template, called index. Remembering that a template is like an HTML file, a template group is like a directory on our server. The index template is the equivalent of the index.html file—when a visitor visits our template group, the index template is displayed first. For that reason, the index template cannot be renamed or deleted. Let us edit the index template to see what it does. Click on the word index. A template is essentially just text (although it usually contains HTML, CSS, or ExpressionEngine code). When we first create a template, there is no text, and therefore all we see is an empty white box. Let us write something in the box to demonstrate how templates are seen by visitors. Type in a sentence and click Update and Finished. Just like HTML files and directories, templates and template groups relate directly to the URL that visitors see. In the URL http://www.example.com/index.php/toast/index, the index.php is what distinguishes this as an ExpressionEngine page. Then comes the template group name, in our case called toast. Finally, we have the template name, in this case index. Go to the previous URL (with or without the index.php as appropriate, for example, http://www.example.com/toast/index or http://localhost/toast/index) and the template we just edited should appear. Now try typing the template group without specifying which template to load. The index template is always returned. What happens if we do not specify the template group, and just go to our base domain (http://localhost/ or http://www.example.com/)? In this case, the toast template of the default template group is returned. The default template group is indicated on the templates screen with an * before the template group name and underneath the list of template groups.
Read more
  • 0
  • 0
  • 4529

article-image-working-binding-data-and-ui-elements-silverlight-4
Packt
10 May 2010
6 min read
Save for later

Working with Binding data and UI elements in Silverlight 4

Packt
10 May 2010
6 min read
Binding data to another UI element Sometimes, the value of the property of an element is directly dependent on the value of the property of another element. In this case, you can create a binding in XAML called an element binding or element-to-element binding . This binding links both values. If needed, the data can flow bidirectionally. In the banking application, we can add a loan calculator that allows the user to select an amount and the number of years in which they intend to pay the loan back to the bank, including (of course) a lot of interest. Getting ready To follow this recipe, you can either continue with your solution from the previous recipe or use the provided solution that can be found in the Chapter02/SilverlightBanking_ Element_Binding_Starter folder in the code bundle that is available on the Packt website. The finished application for this recipe can be found in the Chapter02/SilverlightBanking_Element_Binding_Completed folder. How to do it... To build the loan calculator, we'll use Slider controls. Each Slider is bound to a TextBlock using an element-to-element binding to display the actual value. Let's take a look at the steps we need to follow to create this binding: We will build the loan calculator as a separate screen in the application. Add a new child window called LoanCalculation.xaml. To do so, right-click on the Silverlight project in the Solution Explorer, select Add | New Item..., and choose Silverlight Child Window under Visual C#. Within MainPage.xaml, add a Click event on the LoanCalculationButton as shown in the following code: <Button x_Name="LoanCalculationButton" Click="LoanCalculationButton_Click" /> In the code-behind's event handler for this Click event, we can trigger the display of this new screen with the following code: private void LoanCalculationButton_Click(object sender, RoutedEventArgs e) { LoanCalculation loanCalculation = new LoanCalculation(); loanCalculation.Show(); } The UI of the LoanCalculation.xaml is quite simple—it contains two Slider controls. Each Slider control has set values for its Minimum and Maximum values (not all UI code is included here; the complete listing can be found in the finished sample code) as shown in the following code: <Slider x_Name="AmountSlider" Minimum="10000" Maximum="1000000" SmallChange="10000" LargeChange="10000" Width="300" > </Slider> <Slider x_Name="YearSlider" Minimum="5" Maximum="30" SmallChange="1" LargeChange="1" Width="300" UseLayoutRounding="True"> </Slider> As dragging a Slider does not give us proper knowledge of where we are exactly between the two values, we add two TextBlock controls. We want the TextBlock controls to show the current value of the Slider control, even while dragging. This can be done by specifying an element-to-element binding as shown in the following code: <TextBlock x_Name="AmountTextBlock" Text="{Binding ElementName=AmountSlider, Path=Value}"> </TextBlock> <TextBlock x_Name="MonthTextBlock" Text="{Binding ElementName=YearSlider, Path=Value}"> </TextBlock> Add a Button that will perform the actual calculation called CalculateButton and a TextBlock called PaybackTextBlock to show the results. This can be done using the following code: <Button x_Name="CalculateButton" Content="Calculate" Click="CalculateButton_Click"> </Button> <TextBlock x_Name="PaybackTextBlock"></TextBlock> The code for the actual calculation that is executed when the Calculate button is clicked uses the actual value for either the Slider or the TextBlock. This is shown in the following code: private double percentage = 0.0345; private void CalculateButton_Click(object sender, RoutedEventArgs e) { double requestedAmount = AmountSlider.Value; int requestedYears = (int)YearSlider.Value; for (int i = 0; i < requestedYears; i++) { requestedAmount += requestedAmount * percentage; } double monthlyPayback = requestedAmount / (requestedYears * 12); PaybackTextBlock.Text = "€" + Math.Round(monthlyPayback, 2); } Having carried out the previous steps, we now have successfully linked the value of the Slider controls and the text of the TextBlock controls. The following screenshot shows the LoanCalculation.xaml screen as it is included in the finished sample code containing some extra markup: How it works... An element binding links two properties of two controls directly from XAML. It allows creating a Binding where the source object is another control. For this to work, we need to create a Binding and specify the source control using the ElementName property. This is shown in the following code: <TextBlock Text="{Binding ElementName=YearSlider, Path=Value}" > </TextBlock> Element bindings were added in Silverlight 3. Silverlight 2 did not support this type of binding. There's more... An element binding can also work in both directions, that is, from source to target and vice versa. This can be achieved by specifying the Mode property on the Binding and setting it to TwoWay. The following is the code for this. In this code, we replaced the TextBlock by a TextBox. When entering a value in the latter, the Slider will adjust its position: <TextBox x_Name="AmountTextBlock" Text="{Binding ElementName=AmountSlider, Path=Value, Mode=TwoWay}" > </TextBox> Element bindings without bindings Achieving the same effect in Silverlight 2—which does not support this feature—is also possible, but only through the use of an event handler as shown in the following code. Element bindings eliminate this need: private void AmountSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { AmountSlider.Value = Math.Round(e.NewValue); AmountTextBlock.Text = AmountSlider.Value.ToString(); } See also Element-to-element bindings can be easily extended to use converters. For more information on TwoWay bindings, take a look at the Using the different modes of data binding to allow persisting data recipe in this article. Binding collections to UI elements Often, you'll want to display lists of data in your application such as a list of shopping items, a list of users, a list of bank accounts, and so on. Such a list typically contains a bunch of items of a certain type that have the same properties and need to be displayed in the same fashion. We can use data binding to easily bind a collection to a Silverlight control (such as a ListBox or DataGrid) and use the same data binding possibilities to defi ne how every item in the collection should be bound. This recipe will show you how to achieve this. Getting ready For this recipe, you can fi nd the starter solution in the Chapter02/SilverlightBanking_ Binding_Collections_Starter folder and the completed solution in the Chapter02/SilverlightBanking_Binding_Collections_Completed folder in the code bundle that is available on the Packt website.
Read more
  • 0
  • 0
  • 4518

article-image-handling-authentication
Packt
13 Dec 2013
9 min read
Save for later

Handling Authentication

Packt
13 Dec 2013
9 min read
(for more resources related to this topic, see here.) Understanding Authentication methods In a world where security on the Internet is such a big issue, the need for great authentication methods is something that cannot be missed. Therefore, Zend Framework 2 provides a range of authentication methods that suits everyone's needs. Getting ready To make full use of this, I recommend a working Zend Framework 2 skeleton application to be set up. How to do it… The following is a list of authentication methods—or as they are called adapters—that are readily available in Zend Framework 2. We will provide a small overview of the adapter, and instructions on how you can use it. The DbTable adapter Constructing a DbTable adapter is pretty easy, if we take a look at the following constructor: public function __construct( // The ZendDbAdapterAdapter DbAdapter $zendDb, // The table table name to query on $tableName = null, // The column that serves as 'username' $identityColumn = null, // The column that serves as 'password' $credentialColumn = null, // Any optional treatment of the password before // checking, such as MD5(?), SHA1(?), etcetera $credentialTreatment = null ); The HTTP adapter After constructing the object we need to define the FileResolver to make sure there are actually user details parsed in. Depending on what we configured in the accept_schemes option, the FileResolver can either be set as a BasicResolver, a DigestResolver, or both. Let's take a quick look at how to set a FileResolver as a DigestResolver or BasicResolver (we do this in the /module/Application/src/Application/Controller/IndexController.php file): <?php namespace Application; // Use the FileResolver, and also the Http // authentication adapter. use ZendAuthenticationAdapterHttpFileResolver; use ZendAuthenticationAdapterHttp; use ZendMvcControllerAbstractActionController; class IndexController extends AbstractActionController { public function indexAction() { // Create a new FileResolver and read in our file to use // in the Basic authentication $basicResolver = new FileResolver(); $basicResolver->setFile( '/some/file/with/credentials.txt' ); // Now create a FileResolver to read in our Digest file $digestResolver = new FileResolver(); $digestResolver->setFile( '/some/other/file/with/credentials.txt' ); // Options doesn't really matter at this point, we can // fill them in to anything we like $adapter = new Http($options); // Now set our DigestResolver/BasicResolver, depending // on our $options set $adapter->setBasicResolver($basicResolver); $adapter->setDigestResolver($digestResolver); } } How it works… After two short examples, let's take a look at the other adapters available. The DbTable adapter Let's begin with probably the most used adapter of them all, the DbTable adapter. This adapter connects to a database and pulls the requested username/password combination from a table and, if all went well, it will return to you an identity, which is nothing more than the record that matched the username details. To instantiate the adapter, it requires a ZendDbAdapterAdapter in its constructor to connect with the database with the user details; there are also a couple of other options that can be set. Let's take a look at the definition of the constructor: The second (tableName) option speaks for itself as it is just the table name, which we need to use to get our users, the third and the fourth (identityColumn, credentialColumn) options are logical and they represent the username and password (or what we use) columns in our table. The last option, the credentialTreatment option, however, might not make a lot of sense. The credentialTreatment tells the adapter to treat the credentialColumn with a function before trying to query it. Examples of this could be to use the MD5 (?) function, PASSWORD (?), or SHA1 (?) function, if it was a MySQL database, but obviously this can differ per database as well. To give a small example on how the SQL can look like (the actual adapter builds this query up differently) with and without a credential treatment, take a look at the following examples: With credential treatment: SELECT * FROM `users` WHERE `username` = 'some_user' AND `password` = MD5('some_password'); Without credential treatment: SELECT * FROM `users` WHERE `username` = 'some_user' AND `password` = 'some_password'; When defining the treatment we should always include a question mark for where the password needs to come, for example, MD5 (?) would create MD5 ('some_password'), but without the question mark it would not insert the password. Lastly, instead of giving the options through the constructor, we can also use the setter methods for the properties: setTableName(), setIdentityColumn(), setCredentialColumn(), and setCredentialTreatment(). The HTTP adapter The HTTP authentication adapter is an adapter that we have probably all come across at least once in our Internet lives. We can recognize the authentication when we go to a website and there is a pop up showing where we can fill in our usernames and passwords to continue. This form of authentication is very basic, but still very effective in certain implementations, and therefore, a part of Zend Framework 2. There is only one big massive but to this authentication, and that is that it can (when using the basic authentication) send the username and password clear text through the browser (ouch!). There is however a solution to this problem and that is to use the Digest authentication, which is also supported by this adapter. If we take a look at the constructor of this adapter, we would see the following code line: public function __construct(array $config); The constructor accepts a load of keys in its config parameter, which are as follows: accept_schemes: This refers to what we want to accept authentication wise; this can be basic, digest, or basic digest. realm: This is a description of the realm we are in, for example Member's area. This is for the user only and is only to describe what the user is logging in for. digest_domains: These are URLs for which this authentication is working for. So if a user logs in with his details on any of the URLs defined, they will work. The URLs should be defined in a space-separated (weird, right?) list, for example /members/area /members/login. nonce_timeout: This will set the number of seconds the nonce (the hash users login with when we are using Digest authentication) is valid. Note, however, that nonce tracking and stale support are not implemented in Version 2.2 yet, which means it will authenticate again every time the nonce times out. use_opaque: This is either true or false (by default is true) and tells our adapter to send the opaque header to the client. The opaque header is a string sent by the server, which needs to be returned back on authentication. This does not work sometimes on Microsoft Internet Explorer browsers though, as they seem to ignore that header. Ideally the opaque header is an ever-changing string, to reduce predictability, but ZF 2 doesn't randomize the string and always returns the same hash. algorithm: This includes the algorithm to use for the authentication, it needs to be a supported algorithm that is defined in the supportedAlgos property. At the moment there is only MD5 though. proxy_auth: This boolean (by default is false) tells us if the authentication used is a proxy Authentication or not. It should be noted that there is a slight difference in files when using either Digest or Basic. Although both files have the same layout, they cannot be used interchangeably as the Digest requires the credentials to be MD5 hashed, while the Basic requires the credentials to be plain text. There should also always be a new line after every credential, meaning that the last line in the credential file should be empty. The layout of a credential file is as follows: username:realm:credentials For example: some_user:My Awesome Realm:clear text password Instead of a FileResolver, one can also use the ApacheResolver which can be used to read out htpasswd generated files, which comes in handy when there is already such a file in place. The Digest adapter The Digest adapter is basically the Http adapter without any Basic authentication. As the idea behind it is the same as the Http adapter, we will just go on and talk about the constructor, as that is a bit different in implementation: public function __construct($filename = null, $realm = null, $identity = null, $credential = null); As we can see the following options can be set when constructing the object: filename: This is the direct filename of the file to use with the Digest credentials, so no need to use a FileResolver with this one. realm: This identifies to the user what he/she is logging on to, for example My Awesome Realm or The Dragonborn's lair. As we are immediately trying to log on when constructing this, it does need to correspond with the credential file. identity: This is the username we are trying to log on with, and again it needs to resemble a user that is defined in the credential file to work. credential: This is the Digest password we try to log on with, and this again needs to match the password exactly like the one in the credential file. We can then, for example, just run $digestAdapter->getIdentity() to find out if we are successfully authenticated or not, resulting in NULL if we are not, and resulting in the identity column value if we are. The LDAP adapter Using the LDAP authentication is obviously a little more difficult to explain, so we will not go in to that full as that would take quite a while. What we will do is show the constructor of the LDAP adapter and explain its various options. However, if we want to know more about setting up an LDAP connection, we should take a look at the documentation of ZF2, as it is explained in there very well: public function __construct(array $options = array(), $identity = null, $credential = null); The options parameter in the construct refers to an array of configuration options that are compatible with the ZendLdapLdap configuration. There are literally dozens of options that can be set here so we advice to go and look at the LDAP documentation of ZF2 to know more about that. The next two parameters identity and credential are respectively the username and password again, so that explains itself really. Once you have set up the connection with the LDAP there isn't much left to do but to get the identity and see whether we were successfully validated or not. About Authentication Authentication in Zend Framework 2 works through specific adapters, which are always an implementation of the ZendAuthenticationAdapterAdapterInterface and thus, always provides the methods defined in there. However, the methods of Authentication are all different, and strong knowledge of the methods displayed previously is always a requirement. Some work through the browser, like the Http and Digest adapter, and others just require us to create a whole implementation like the LDAP and the DbTable adapter.
Read more
  • 0
  • 0
  • 4516

article-image-using-phpstorm-team
Packt
26 Dec 2014
11 min read
Save for later

Using PhpStorm in a Team

Packt
26 Dec 2014
11 min read
In this article by Mukund Chaudhary and Ankur Kumar, authors of the book PhpStorm Cookbook, we will cover the following recipes: Getting a VCS server Creating a VCS repository Connecting PhpStorm to a VCS repository Storing a PhpStorm project in a VCS repository (For more resources related to this topic, see here.) Getting a VCS server The first action that you have to undertake is to decide which version of VCS you are going to use. There are a number of systems available, such as Git and Subversion (commonly known as SVN). It is free and open source software that you can download and install on your development server. There is another system named concurrent versions system (CVS). Both are meant to provide a code versioning service to you. SVN is newer and supposedly faster than CVS. Since SVN is the newer system and in order to provide information to you on the latest matters, this text will concentrate on the features of Subversion only. Getting ready So, finally that moment has arrived when you will start off working in a team by getting a VCS system for you and your team. The installation of SVN on the development system can be done in two ways: easy and difficult. The difficult step can be skipped without consideration because that is for the developers who want to contribute to the Subversion system. Since you are dealing with PhpStorm, you need to remember the easier way because you have a lot more to do. How to do it... The installation step is very easy. There is this aptitude utility available with Debian-based systems, and there is the Yum utility available with Red Hat-based systems. Perform the following steps: You just need to issue the command apt-get install subversion. The operating system's package manager will do the remaining work for you. In a very short time, after flooding the command-line console with messages, you will have the Subversion system installed. To check whether the installation was successful, you need to issue the command whereis svn. If there is a message, it means that you installed Subversion successfully. If you do not want to bear the load of installing Subversion on your development system, you can use commercial third-party servers. But that is more of a layman's approach to solving problems, and no PhpStorm cookbook author will recommend that you do that. You are a software engineer; you should not let go easily. How it works... When you install the version control system, you actually install a server that provides the version control service to a version control client. The subversion control service listens for incoming connections from remote clients on port number 3690 by default. There's more... If you want to install the older companion, CVS, you can do that in a similar way, as shown in the following steps: You need to download the archive for the CVS server software. You need to unpack it from the archive using your favorite unpacking software. You can move it to another convenient location since you will not need to disturb this folder in the future. You then need to move into the directory, and there will start your compilation process. You need to do #. /configure to create the make targets. Having made the target, you need to enter #make install to complete the installation procedure. Due to it being older software, you might have to compile from the source code as the only alternative. Creating a VCS repository More often than not, a PHP programmer is expected to know some system concepts because it is often required to change settings for the PHP interpreter. The changes could be in the form of, say, changing the execution time or adding/removing modules, and so on. In order to start working in a team, you are going to get your hands dirty with system actions. Getting ready You will have to create a new repository on the development server so that PhpStorm can act as a client and get connected. Here, it is important to note the difference between an SVN client and an SVN server—an SVN client can be any of these: a standalone client or an embedded client such as an IDE. The SVN server, on the other hand, is a single item. It is a continuously running process on a server of your choice. How to do it... You need to be careful while performing this activity as a single mistake can ruin your efforts. Perform the following steps: There is a command svnadmin that you need to know. Using this command, you can create a new directory on the server that will contain the code base in it. Again, you should be careful when selecting a directory on the server as it will appear in your SVN URL for the rest part of your life. The command should be executed as: svnadmin create /path/to/your/repo/ Having created a new repository on the server, you need to make certain settings for the server. This is just a normal phenomenon because every server requires a configuration. The SVN server configuration is located under /path/to/your/repo/conf/ with the name svnserve.conf. Inside the file, you need to make three changes. You need to add these lines at the bottom of the file: anon-access = none auth-access = write password-db = passwd There has to be a password file to authorize a list of users who will be allowed to use the repository. The password file in this case will be named passwd (the default filename). The contents in the file will be a number of lines, each containing a username and the corresponding password in the form of username = password. Since these files are scanned by the server according to a particular algorithm, you don't have the freedom to leave deliberate spaces in the file—there will be error messages displayed in those cases. Having made the appropriate settings, you can now make the SVN service run so that an SVN client can access it. You need to issue the command svnserve -d to do that. It is always good practice to keep checking whether what you do is correct. To validate proper installation, you need to issue the command svn ls svn://user@host/path/to/subversion/repo/. The output will be as shown in the following screenshot:   How it works... The svnadmin command is used to perform admin tasks on the Subversion server. The create option creates a new folder on the server that acts as the repository for access from Subversion clients. The configuration file is created by default at the time of server installation. The contents that are added to the file are actually the configuration directives that control the behavior of the Subversion server. Thus, the settings mentioned prevent anonymous access and restrict the write operations to certain users whose access details are mentioned in a file. The command svnserve is again a command that needs to be run on the server side and which starts the instance of the server. The -d switch mentions that the server should be run as a daemon (system process). This also means that your server will continue running until you manually stop it or the entire system goes down. Again, you can skip this section if you have opted for a third-party version control service provider. Connecting PhpStorm to a VCS repository The real utility of software is when you use it. So, having installed the version control system, you need to be prepared to use it. Getting ready With SVN being client-server software, having installed the server, you now need a client. Again, you will have difficulty searching for a good SVN client. Don't worry; the client has been factory-provided to you inside PhpStorm. The PhpStorm SVN client provides you with features that accelerate your development task by providing you detailed information about the changes made to the code. So, go ahead and connect PhpStorm to the Subversion repository you created. How to do it... In order to connect PhpStorm to the Subversion repository, you need to activate the Subversion view. It is available at View | Tool Windows | Svn Repositories. Perform the following steps to activate the Subversion view: 1. Having activated the Subversion view, you now need to add the repository location to PhpStorm. To do that, you need to use the + symbol in the top-left corner in the view you have opened, as shown in the following screenshot: Upon selecting the Add option, there is a question asked by PhpStorm about the location of the repository. You need to provide the full location of the repository. Once you provide the location, you will be able to see the repository in the same Subversion view in which you have pressed the Add button. Here, you should always keep in mind the correct protocol to use. This depends on the way you installed the Subversion system on the development machine. If you used the default installation by installing from the installer utility (apt-get or aptitude), you need to specify svn://. If you have configured SVN to be accessible via SSH, you need to specify svn+ssh://. If you have explicitly configured SVN to be used with the Apache web server, you need to specify http://. If you configured SVN with Apache over the secure protocol, you need to specify https://. Storing a PhpStorm project in a VCS repository Here comes the actual start of the teamwork. Even if you and your other team members have connected to the repository, what advantage does it serve? What is the purpose solved by merely connecting to the version control repository? Correct. The actual thing is the code that you work on. It is the code that earns you your bread. Getting ready You should now store a project in the Subversion repository so that the other team members can work and add more features to your code. It is time to add a project to version control. It is not that you need to start a new project from scratch to add to the repository. Any project, any work that you have done and you wish to have the team work on now can be added to the repository. Since the most relevant project in the current context is the cooking project, you can try adding that. There you go. How to do it... In order to add a project to the repository, perform the following steps: You need to use the menu item provided at VCS | Import into version control | Share project (subversion). PhpStorm will ask you a question, as shown in the following screenshot: Select the correct hierarchy to define the share target—the correct location where your project will be saved. If you wish to create the tags and branches in the code base, you need to select the checkbox for the same. It is good practice to provide comments to the commits that you make. The reason behind this is apparent when you sit down to create a release document. It also makes the change more understandable for the other team members. PhpStorm then asks you the format you want the working copy to be in. This is related to the version of the version control software. You just need to smile and select the latest version number and proceed, as shown in the following screenshot:   Having done that, PhpStorm will now ask you to enter your credentials. You need to enter the same credentials that you saved in the configuration file (see the Creating a VCS repository recipe) or the credentials that your service provider gave you. You can ask PhpStorm to save the credentials for you, as shown in the following screenshot:   How it works... Here it is worth understanding what is going on behind the curtains. When you do any Subversion related task in PhpStorm, there is an inbuilt SVN client that executes the commands for you. Thus, when you add a project to version control, the code is given a version number. This makes the version system remember the state of the code base. In other words, when you add the code base to version control, you add a checkpoint that you can revisit at any point in future for the time the code base is under the same version control system. Interesting phenomenon, isn't it? There's more... If you have installed the version control software yourself and if you did not make the setting to store the password in encrypted text, PhpStorm will provide you a warning about it, as shown in the following screenshot: Summary We got to know about version control systems, step-by-step process to create a VCS repository, and connecting PhpStorm to a VCS repository. Resources for Article:  Further resources on this subject: FuelPHP [article] A look into the high-level programming operations for the PHP language [article] PHP Web 2.0 Mashup Projects: Your Own Video Jukebox: Part 1 [article]
Read more
  • 0
  • 0
  • 4515
article-image-drag-and-drop-yui-part-1
Packt
30 Nov 2009
7 min read
Save for later

Drag-and-Drop with the YUI: Part-1

Packt
30 Nov 2009
7 min read
Dynamic Drag-and-Drop without the Hassle Like most of the other library components, when creating your own drag-and-drop elements, there are a range of different options available to you that allow you to tailor those objects to your requirements. These properties, like those of most other library components, can be set using an object literal supplied with the constructor, but in most cases even this is not required. The most challenging aspects of any drag-and-drop scenario in your web applications are going to center around the design of your specific implementation rather than in getting drag-and-drop to work in the first place. This utility is yet another example of the huge benefits the YUI can provide in reducing the amount of coding and troubleshooting that you need to concern yourself with. The Different Components of Drag-and-Drop In addition to the configurable properties used in your object literal, you also have several constructors that can be used to enable drag-and-drop. The first constructor YAHOO.util.DD allows for drag-and-drop at its most basic level. The supplied element will be transformed into an object that can be dragged around the page. The mechanics of drag-and-drop result in a burden of fairly high processing. The library has to keep track of the mouse pointer whilst it is moving, the draggable object needs to be repositioned, and different events are almost continually firing while the drag is taking place. In order to minimize the amount of information that needs to be processed, especially when the draggable object is fairly large, you can make use of a proxy element that will track across the page with the mouse pointer. When the proxy element reaches its final destination, it disappears and is replaced by the actual element. If a proxy element is required, we can use the YAHOO.util.DDProxy constructor instead of the basic constructor. As the proxy element is just an empty <div>, it's much easier to track and can even be shared between different drag objects on the page, reducing the overall processing that's required. Personally I think the default appearance of the proxy element is perfectly adequate, however you can also create your own custom elements to use as a proxy. The figure below shows the default proxy-element appearance: Design Considerations When working with DragDrop implementations, it is useful to consider the following aspects of the design: Can any part of the drag object be clicked on to initiate the drag, or should a drag handle be defined? Can the object be dropped on to any part of the page or should a specific drop target be defined? Should anything occur whilst the object is being dragged? Should anything occur when the item is dropped on a non-valid target? Should anything occur when the object is dropped on to a valid target? Events Events are an integral aspect of many DragDrop situations. Sometimes, however, being able to move something around the screen is the only behavior that's required, but generally you'll want something to happen either while the object is being dragged, or when it is dropped. The YAHOO.util.DragDrop utility provides a series of custom events which allow you to hook into and respond to events such as startDrag, endDrag, onDrag, onDragDrop, and onInvalidDrop. Valid targets also expose events of their own including onDragEnter, onDragOut, and onDragOver. We will be looking at a number of these events during the example that follows. Allowing Your Visitors to Drag-and-Drop The Drag-and-Drop utility uses tried and tested DHTML techniques, as well as some innovative new features, to allow you to easily create objects that can be dragged and then dropped. All that you need to do to make an element on your page dragable is to create a new instance of the YAHOO.util.DD class and feed in the id or element reference of the element that drag is to be enabled for. DragDrop Classes The base class of the Drag-and-Drop utility is YAHOO.util. DragDrop, but you'll use one of its extending subclasses, like YAHOO.util.DD, most of the time. This subclass inherits all of the properties and methods of the base class and even adds a few of its own, so it's more than capable of handling most of your drag-and-drop requirements. The YAHOO.util.DD class also has its own subclasses to deal with additional drag-and-drop requirements for different situations. The subclasses are YAHOO.util.DDProxy and YAHOO.widget.SliderThumb. As you can see, the Drag-and-Drop utility provides some of the basic functionality of another of the controls found in the YUI, the Slider Control (which we will look at in more detail towards the end of this article). Let's examine the DDProxy class, as that is relevant specifically to the Drag-and-Drop utility. Creating a proxy object that tracks with the cursor when a drag object is being dragged instead of allowing the actual drag object to track can prevent problems that arise with large drag objects not tracking properly or obscuring other content on the page. The proxy object is a small, empty object that represents the drag object and shows only its borders. The proxy object is created on the mouseDown event of the drag object and the actual drag object does not move to its new position until the mouseUp event is fired. Using a proxy object is both visually appealing and better overall for all but the simplest of implementations performance wise. The Constructor The constructor for an instance of the DragDrop object can also take a second or third argument when you are instantiating objects for dragging. The second argument, which is optional, specifies the group to which the element being dragged belongs. This refers to interaction groups—the object being dragged can only interact with and fire events with other elements in its interaction group. The third argument, which is also optional, can be used to supply a configuration object, the members of which hold additional optional configuration properties that can easily be accessed and set. Every object instantiated with the drag-and-drop constructor is a member of one or more interaction group(s), even if the second argument is not passed. When the argument is not supplied, the object will simply belong to the 'default' group instead. There is no limit as to how many groups an object can belong to. The API provides just two methods that relate to group access. .addToGroup() is used to add the object to more than one group, so the first group membership is defined with the constructor and subsequent groups with the .addToGroup() method. To remove an object from a group, just call the .removeFromGroup() method. Target Practice There is no doubt that drag-and-drop adds a hands-on, fun element to surfing the net that is way more engaging than simple point-and-click scenarios, and there are many serious applications of this behavior too. But dragging is only half of the action; without assigned drop targets, the usefulness of being able to drag elements on the page around at leisure is almost wasted. Drop targets have a class of their own in the Drag-and-Drop utility. Which extends the YAHOO.util.DragDrop base class to cater for the creation of drag elements that aren't actually dragable and this is the defining attribute of a drop target. The constructor is exactly the same as for the DD and Proxy classes with regard to the arguments passed, but YAHOO.util.DDTarget is used instead. The Target class has no methods or properties of its own, but it inherits all of the same methods and properties as the other two classes, including all of the events.
Read more
  • 0
  • 0
  • 4507

article-image-drupal-web-services-twitter-and-drupal
Packt
26 Nov 2010
10 min read
Save for later

Drupal Web Services: Twitter and Drupal

Packt
26 Nov 2010
10 min read
Drupal Web Services Integrate social and multimedia Web services and applications with your Drupal Web site. Explore different Web services and how they integrate with the Drupal CMS. Reuse the applications without coding them again using the Web services protocols on your Drupal site. Configure your Drupal site to consume various web services by using contributed Drupal modules for each specific task or application. Drive the content from your Drupal site to Facebook, Twitter and LinkedIn using effective Drupal Web services An easy to follow guide that opens up a method of easily sharing data and content resources between applications and machines that are running different platforms and architecture. Introduction Twitter is a popular and widely used micro-blogging application and website. You can sign up for a Twitter account and post tiny snippet-based blog entries, 140 characters or less, to your Twitter home page. You can log in to your Twitter account and post your 140 character entry into the What's happening? text area box and then click on the Tweet button to publish it. The tweet will appear on your account's home page—your default Twitter home page—and it will be shared on the main Twitter home pages of your followers. To send a tweet to another user, you can use the hash tag in front of their username in your post. So, for example, if I was going to send myself a tweet, I would add this in my text area box before adding my post: #jamesweblabs. For more on the history and functionality of Twitter, check out the Wikipedia entry at: http://en.wikipedia.org/wiki/Twitter. Twitter also has a detailed Help and support documentation section on its main site at http://support.twitter.com/.   You may want to integrate Twitter with your Drupal site, to do things such as posting all of your most recent tweets into a Drupal block that will appear on your home page. You also may want to run this block automatically via a web service integration so that the block updates automatically whenever you post a new tweet to your Twitter account. Drupal and Twitter can easily integrate through these web services by using contributed modules. In this article, we're going to install, configure, and use the Twitter module so that we can integrate our Twitter account with our Drupal user account; we can also post tweets to the sidebar block on our site. With the Twitter module, we'll also expose some of its fields to the Views module and be able to create more powerful and dynamic listings of Twitter-based content. We'll also look at other contributed modules including Tweet. The Twitter API The Twitter API and service integration with Drupal uses the REST (Representational State Transfer) API protocol and a Streaming API protocol. Twitter does state in its API documentation that the service does not offer unlimited usage. Twitter does impose limits on the number of requests and updates made to its service API. The REST service is HTTP-based and uses GET and POST requests. GET is used to retrieve data so, in our case, this will be used when our Drupal site tries to receive the latest Tweet posted to your Twitter account. POST requests are used when you submit, update, or delete node data that you have sent over to Twitter and posted as a Tweet using the Twitter module. Using REST as the protocol, the API does support various formats for data transfer including XML, JSON, RSS, and Atom. For more details on the Twitter API and how to use it, see the Twitter API documentation for developers at: http://dev.twitter.com/pages/every_developer. The Twitter module The Twitter module is available via its Drupal project page at http://drupal.org/project/twitter. The module allows for integration with Twitter's API web service. It allows you to integrate your Twitter account with your Drupal user account; post Tweets to a block in Drupal; and allows your Drupal users to post to their Twitter account using Drupal node content. Drupal Views also integrates with the module and you can create your own customized Views-based listings of Twitter content. The module gives you a default block called User Tweets and also a user profile page titled user's tweets. We'll set both of these up in the examples that follow. Integrating the Twitter module with Drupal Download the 6.x-3.0-beta2 version of the Twitter module. This is the Other release version, not the recommended release. The reason we're going to install the Other release version is that recently Twitter changed their web service API to use authentication provided by the OAuth protocol. This change happened recently, in September 2010, when Twitter redesigned their website and made other security improvements and enhancements to their API. In order to support OAuth in the integration, you need to make sure to use the 3.0-beta2 version of the Twitter module. You can download it from: http://drupal.org/project/twitter It's listed under the Other releases heading: Once downloaded, upload this Twitter module folder to your /sites/all/modules location on your web server. You also need to download the OAuth module and add that to your /sites/all/modules. OAuth is required by the Twitter module, so you must install it. The OAuth module is available at: http://drupal.org/project/oauth. Again, with this module, you need to make sure to use the other release (earlier version) of 6.x-2.02. This 2.x version is the version that works with the Twitter 3.0-beta2 module. Make sure you have the correct versions of both of these modules before uploading to your site. This is very important. If the module versions are not the ones mentioned here, you may run into errors or other issues with functionality. So, make sure to install these exact versions. Go ahead and upload both of these modules to your /sites/all/modules. Once uploaded, browse to your modules admin page and look for the OAuth and Twitter module suites under the Other modules fieldset. For OAuth, you're looking for the Oauth and the OAuth Client Test modules. Enable the OAuth module as shown in the following screenshot: Then, scroll down and look for the Twitter, Twitter actions, Twitter Post, and Twitter Signin modules. Enable all four of these modules: Save your module configuration. Registering your website with Twitter Now that we've installed the necessary modules on our Drupal site, we need to set up the Twitter side of our functionality. In order to integrate the Twitter module with the Twitter web service, you need to create two Twitter-related items. The first is a Twitter account. If you do not already have a Twitter account, you can go to twitter.com and sign up for a brand new Twitter account. Go to: https://twitter.com/ Click on the Sign Up button and then proceed through the account sign-up steps. Setting up a Twitter application Now, we need to configure a new Twitter developer application. Once you have a Twitter account, log in to your Twitter account and then go to the twitter.com/apps URL to sign up for a new developer's application on Twitter. Make sure you are signed into your Twitter account already when you go to the apps URL. Launch the apps URL from: https://twitter.com/apps This page will show you any applications you have configured in Twitter. For our site, we're going to set up a brand new application, so, click on the Register a new application hyperlink: Clicking on that link will load a Register an Application form as shown in the following screenshot. Let's fill that out with the following info: Application Name Description of application Application Website (this is the URL of your website) Organization Name Website address (again this is the URL/home domain of your website) Scroll down on the form and then complete the form by adding and completing the following fields: Application Type—make sure to select Browser here Callback URL—this is the callback URL that the Drupal Twitter module provides The Callback URL is information that is provided by your Twitter module settings inside your Drupal site. To locate the correct Callback URL to add to the application sign-up form, go to your Twitter setup configuration settings in your Drupal site by browsing to: Site configuration | Twitter setup (admin/settings/twitter). On this page, you will see the Callback URL noted at the top of the OAuth Settings fieldset. You should see something similar to this: Go back to your Twitter application sign-up form and add this Callback URL. Now, make sure the Default Access type is set to Read & Write. Finally, make sure to check the Yes, Use Twitter for login. This will allow you to authenticate your posts to your Twitter account username and password when you try to post Drupal content to your Twitter account. So, make sure that box is checked. Your app form should now look like this: Complete the reCAPTCHA field at the bottom of the form and then click on the Save button. Twitter will load a page confirming your application is successfully configured and show you your application details. This includes your Consumer key, Consumer secret, Request token URL, Access Token URL, and Authorize URL. For integration with our Drupal site, we're going to need the Consumer key and secret. Leave this app details confirmation page open and then open up your Drupal site in another browser tab. Configuring the Twitter module once you have your app setup With your Drupal site open, go back to your Twitter module configuration form in your Drupal site at the following path: admin/settings/twitter. Here, you want to copy and paste your Twitter Consumer key and secret code into the respective fields for OAuth Consumer key and OAuth Consumer secret. Also, make sure to check the box next to Import Twitter Statuses. This will allow for your Drupal site to request posts from your Twitter account and add links to these tweets on your user account page, and also in a User Tweets block in one of your site's regions. This is what allows for the total cross-pollination and integration of your Drupal site with your Twitter account. It's very powerful and flexible for running the Twitter import functionality on your site. Finally, set the Delete old statuses drop down to 1 week. This will keep your Tweets block up to date on your Drupal site and show only updated and recent tweets. Let's go ahead and do that. You should have a screen that looks like this: Go ahead and Save configuration. Now, let's check and tweak some of the other Twitter module settings before we test our posts. Click on the Post link at the top of your Twitter setup page. On this page, you can specify what content types and respective Drupal content you want to announce and post to your Twitter account. Let's make sure we check the boxes next to the Blog entry, Page, and Story types. Of course, you can enable all of your content types if you need to, but for this example, we'll just post our new blog entries over to our Twitter account. The Default format string field shows you the format of the link that will be posted over to your Twitter account announcing your new Drupal content. So, when you post a node to your Drupal site using the blog type, the post will appear on your Twitter account in the following format as a hyperlink back to your post on Drupal: New post: !title !tinyurl This will show the Drupal node title, !title, value along with a tinyurl formatted hyperlink back to your Drupal post. So, for example, the resulting post on Twitter will look like this: ·New post: Testing post to Twitter http://tinyurl.com/33jnclx — 1 hour 53 min ago Your Post screen should now look like this: Save your Post page configuration.
Read more
  • 0
  • 0
  • 4503

article-image-forms-and-views
Packt
13 Jan 2016
12 min read
Save for later

Forms and Views

Packt
13 Jan 2016
12 min read
In this article by Aidas Bendoraitis, author of the book Web Development with Django Cookbook - Second Edition we will cover the following topics: Passing HttpRequest to the form Utilizing the save method of the form (For more resources related to this topic, see here.) Introduction When the database structure is defined in the models, we need some views to let the users enter data or show the data to the people. In this chapter, we will focus on the views managing forms, the list views, and views generating an alternative output than HTML. For the simplest examples, we will leave the creation of URL rules and templates up to you. Passing HttpRequest to the form The first argument of every Django view is the HttpRequest object that is usually named request. It contains metadata about the request. For example, current language code, current user, current cookies, and current session. By default, the forms that are used in the views accept the GET or POST parameters, files, initial data, and other parameters; however, not the HttpRequest object. In some cases, it is useful to additionally pass HttpRequest to the form, especially when you want to filter out the choices of form fields using the request data or handle saving something such as the current user or IP in the form. In this recipe, we will see an example of a form where a person can choose a user and write a message for them. We will pass the HttpRequest object to the form in order to exclude the current user from the recipient choices; we don't want anybody to write a message to themselves. Getting ready Let's create a new app called email_messages and put it in INSTALLED_APPS in the settings. This app will have no models, just forms and views. How to do it... To complete this recipe, execute the following steps: Add a new forms.py file with the message form containing two fields: the recipient selection and message text. Also, this form will have an initialization method, which will accept the request object and then, modify QuerySet for the recipient's selection field: # email_messages/forms.py # -*- coding: UTF-8 -*- from __future__ import unicode_literals from django import forms from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User class MessageForm(forms.Form): recipient = forms.ModelChoiceField( label=_("Recipient"), queryset=User.objects.all(), required=True, ) message = forms.CharField( label=_("Message"), widget=forms.Textarea, required=True, ) def __init__(self, request, *args, **kwargs): super(MessageForm, self).__init__(*args, **kwargs) self.request = request self.fields["recipient"].queryset = self.fields["recipient"].queryset. exclude(pk=request.user.pk) Then, create views.py with the message_to_user() view in order to handle the form. As you can see, the request object is passed as the first parameter to the form, as follows: # email_messages/views.py # -*- coding: UTF-8 -*- from __future__ import unicode_literals from django.contrib.auth.decorators import login_required from django.shortcuts import render, redirect from .forms import MessageForm @login_required def message_to_user(request): if request.method == "POST": form = MessageForm(request, data=request.POST) if form.is_valid(): # do something with the form return redirect("message_to_user_done") else: form = MessageForm(request) return render(request, "email_messages/message_to_user.html", {"form": form} ) How it works... In the initialization method, we have the self variable that represents the instance of the form itself, we also have the newly added request variable, and then we have the rest of the positional arguments (*args) and named arguments (**kwargs). We call the super() initialization method passing all the positional and named arguments to it so that the form is properly initiated. We will then assign the request variable to a new request attribute of the form for later access in other methods of the form. Then, we modify the queryset attribute of the recipient's selection field, excluding the current user from the request. In the view, we will pass the HttpRequest object as the first argument in both situations: when the form is posted as well as when it is loaded for the first time. See also The Utilizing the save method of the form recipe Utilizing the save method of the form To make your views clean and simple, it is good practice to move the handling of the form data to the form itself whenever possible and makes sense. The common practice is to have a save() method that will save the data, perform search, or do some other smart actions. We will extend the form that is defined in the previous recipe with the save() method, which will send an e-mail to the selected recipient. Getting ready We will build upon the example that is defined in the Passing HttpRequest to the form recipe. How to do it... To complete this recipe, execute the following two steps: From Django, import the function in order to send an e-mail. Then, add the save() method to MessageForm. It will try to send an e-mail to the selected recipient and will fail quietly if any errors occur: # email_messages/forms.py # -*- coding: UTF-8 -*- from __future__ import unicode_literals from django import forms from django.utils.translation import ugettext, ugettext_lazy as _ from django.core.mail import send_mail from django.contrib.auth.models import User class MessageForm(forms.Form): recipient = forms.ModelChoiceField( label=_("Recipient"), queryset=User.objects.all(), required=True, ) message = forms.CharField( label=_("Message"), widget=forms.Textarea, required=True, ) def __init__(self, request, *args, **kwargs): super(MessageForm, self).__init__(*args, **kwargs) self.request = request self.fields["recipient"].queryset = self.fields["recipient"].queryset. exclude(pk=request.user.pk) def save(self): cleaned_data = self.cleaned_data send_mail( subject=ugettext("A message from %s") % self.request.user, message=cleaned_data["message"], from_email=self.request.user.email, recipient_list=[ cleaned_data["recipient"].email ], fail_silently=True, ) Then, call the save() method from the form in the view if the posted data is valid: # email_messages/views.py # -*- coding: UTF-8 -*- from __future__ import unicode_literals from django.contrib.auth.decorators import login_required from django.shortcuts import render, redirect from .forms import MessageForm @login_required def message_to_user(request): if request.method == "POST": form = MessageForm(request, data=request.POST) if form.is_valid(): form.save() return redirect("message_to_user_done") else: form = MessageForm(request) return render(request, "email_messages/message_to_user.html", {"form": form} ) How it works... Let's take a look at the form. The save() method uses the cleaned data from the form to read the recipient's e-mail address and the message. The sender of the e-mail is the current user from the request. If the e-mail cannot be sent due to an incorrect mail server configuration or another reason, it will fail silently; that is, no error will be raised. Now, let's look at the view. When the posted form is valid, the save() method of the form will be called and the user will be redirected to the success page. See also The Passing HttpRequest to the form recipe Uploading images In this recipe, we will take a look at the easiest way to handle image uploads. You will see an example of an app, where the visitors can upload images with inspirational quotes. Getting ready Make sure to have Pillow or PIL installed in your virtual environment or globally. Then, let's create a quotes app and put it in INSTALLED_APPS in the settings. Then, we will add an InspirationalQuote model with three fields: the author, quote text, and picture, as follows: # quotes/models.py # -*- coding: UTF-8 -*- from __future__ import unicode_literals import os from django.db import models from django.utils.timezone import now as timezone_now from django.utils.translation import ugettext_lazy as _ from django.utils.encoding import python_2_unicode_compatible def upload_to(instance, filename): now = timezone_now() filename_base, filename_ext = os.path.splitext(filename) return "quotes/%s%s" % ( now.strftime("%Y/%m/%Y%m%d%H%M%S"), filename_ext.lower(), ) @python_2_unicode_compatible class InspirationalQuote(models.Model): author = models.CharField(_("Author"), max_length=200) quote = models.TextField(_("Quote")) picture = models.ImageField(_("Picture"), upload_to=upload_to, blank=True, null=True, ) class Meta: verbose_name = _("Inspirational Quote") verbose_name_plural = _("Inspirational Quotes") def __str__(self): return self.quote In addition, we created an upload_to function, which sets the path of the uploaded picture to be something similar to quotes/2015/04/20150424140000.png. As you can see, we use the date timestamp as the filename to ensure its uniqueness. We pass this function to the picture image field. How to do it... Execute these steps to complete the recipe: Create the forms.py file and put a simple model form there: # quotes/forms.py # -*- coding: UTF-8 -*- from __future__ import unicode_literals from django import forms from .models import InspirationalQuote class InspirationalQuoteForm(forms.ModelForm): class Meta: model = InspirationalQuote fields = ["author", "quote", "picture", "language"] In the views.py file, put a view that handles the form. Don't forget to pass the FILES dictionary-like object to the form. When the form is valid, trigger the save() method as follows: # quotes/views.py # -*- coding: UTF-8 -*- from __future__ import unicode_literals from django.shortcuts import redirect from django.shortcuts import render from .forms import InspirationalQuoteForm def add_quote(request): if request.method == "POST": form = InspirationalQuoteForm( data=request.POST, files=request.FILES, ) if form.is_valid(): quote = form.save() return redirect("add_quote_done") else: form = InspirationalQuoteForm() return render(request, "quotes/change_quote.html", {"form": form} ) Lastly, create a template for the view in templates/quotes/change_quote.html. It is very important to set the enctype attribute to multipart/form-data for the HTML form, otherwise the file upload won't work: {# templates/quotes/change_quote.html #} {% extends "base.html" %} {% load i18n %} {% block content %} <form method="post" action="" enctype="multipart/form-data"> {% csrf_token %} {{ form.as_p }} <button type="submit">{% trans "Save" %}</button> </form> {% endblock %} How it works... Django model forms are forms that are created from models. They provide all the fields from the model so you don't need to define them again. In the preceding example, we created a model form for the InspirationalQuote model. When we save the form, the form knows how to save each field in the database as well as upload the files and save them in the media directory. There's more As a bonus, we will see an example of how to generate a thumbnail out of the uploaded image. Using this technique, you could also generate several other specific versions of the image, such as the list version, mobile version, and desktop computer version. We will add three methods to the InspirationalQuote model (quotes/models.py). They are save(), create_thumbnail(), and get_thumbnail_picture_url(). When the model is being saved, we will trigger the creation of the thumbnail. When we need to show the thumbnail in a template, we can get its URL using {{ quote.get_thumbnail_picture_url }}. The method definitions are as follows: # quotes/models.py # … from PIL import Image from django.conf import settings from django.core.files.storage import default_storage as storage THUMBNAIL_SIZE = getattr( settings, "QUOTES_THUMBNAIL_SIZE", (50, 50) ) class InspirationalQuote(models.Model): # ... def save(self, *args, **kwargs): super(InspirationalQuote, self).save(*args, **kwargs) # generate thumbnail picture version self.create_thumbnail() def create_thumbnail(self): if not self.picture: return "" file_path = self.picture.name filename_base, filename_ext = os.path.splitext(file_path) thumbnail_file_path = "%s_thumbnail.jpg" % filename_base if storage.exists(thumbnail_file_path): # if thumbnail version exists, return its url path return "exists" try: # resize the original image and # return URL path of the thumbnail version f = storage.open(file_path, 'r') image = Image.open(f) width, height = image.size if width > height: delta = width - height left = int(delta/2) upper = 0 right = height + left lower = height else: delta = height - width left = 0 upper = int(delta/2) right = width lower = width + upper image = image.crop((left, upper, right, lower)) image = image.resize(THUMBNAIL_SIZE, Image.ANTIALIAS) f_mob = storage.open(thumbnail_file_path, "w") image.save(f_mob, "JPEG") f_mob.close() return "success" except: return "error" def get_thumbnail_picture_url(self): if not self.picture: return "" file_path = self.picture.name filename_base, filename_ext = os.path.splitext(file_path) thumbnail_file_path = "%s_thumbnail.jpg" % filename_base if storage.exists(thumbnail_file_path): # if thumbnail version exists, return its URL path return storage.url(thumbnail_file_path) # return original as a fallback return self.picture.url In the preceding methods, we are using the file storage API instead of directly juggling the filesystem, as we could then exchange the default storage with Amazon S3 buckets or other storage services and the methods will still work. How does the creating the thumbnail work? If we had the original file saved as quotes/2014/04/20140424140000.png, we are checking whether the quotes/2014/04/20140424140000_thumbnail.jpg file doesn't exist and, in that case, we are opening the original image, cropping it from the center, resizing it to 50 x 50 pixels, and saving it to the storage. The get_thumbnail_picture_url() method checks whether the thumbnail version exists in the storage and returns its URL. If the thumbnail version does not exist, the URL of the original image is returned as a fallback. Summary In this article, we learned about passing an HttpRequest to the form and utilizing the save method of the form. You can find various book on Django on our website: Learning Website Development with Django (https://www.packtpub.com/web-development/learning-website-development-django) Instant Django 1.5 Application Development Starter (https://www.packtpub.com/web-development/instant-django-15-application-development-starter) Django Essentials (https://www.packtpub.com/web-development/django-essentials) Resources for Article: Further resources on this subject: So, what is Django?[article] Code Style in Django[article] Django JavaScript Integration: jQuery In-place Editing Using Ajax[article]
Read more
  • 0
  • 0
  • 4497
article-image-jquery-ui-accordion-widget-part-1
Packt
16 Oct 2009
9 min read
Save for later

jQuery UI Accordion Widget - Part 1

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

article-image-vaadin-and-its-context
Packt
25 Sep 2013
24 min read
Save for later

Vaadin and its Context

Packt
25 Sep 2013
24 min read
(For more resources related to this topic, see here.) Developing Java applications and more specifically, developing Java web applications should be fun. Instead, most projects are a mess of sweat and toil, pressure and delays, costs and cost cutting. Web development has lost its appeal. Yet, among the many frameworks available, there is one in particular that draws our attention because of its ease of use and its original stance. It has been around since the past decade and has begun to grow in importance. The name of this framework is Vaadin. The goal of this article is to see, step-by-step, how to develop web applications with Vaadin. Vaadin is the Finnish word for a female reindeer (as well as a Finnish goddess). This piece of information will do marvels to your social life as you are now one of the few people on Earth who know this (outside Finland). Before diving right into Vaadin, it is important to understand what led to its creation. Readers who already have this information (or who don't care) should go directly to Environment Setup. Rich applications Vaadin is often referred to as a Rich Internet Application (RIA) framework. Before explaining why, we need to first define some terms which will help us describe the framework. In particular, we will have a look at application tiers, the different kind of clients, and their history. Application tiers Some software run locally, that is, on the client machine and some run remotely, such as on a server machine. Some applications also run on both the client and the server. For example, when requesting an article from a website, we interact with a browser on the client side but the order itself is passed on a server in the form of a request. Traditionally, all applications can be logically separated into tiers, each having different responsibilities as follows: Presentation : The presentation tier is responsible for displaying the end-user information and interaction. It is the realm of the user interface. Business Logic : The logic tier is responsible for controlling the application logic and functionality. It is also known as the application tier, or the middle tier as it is the glue between the other two surrounding tiers, thus leading to the term middleware. Data : The data tier is responsible for storing and retrieving data. This backend may be a file system. In most cases, it is a database, whether relational, flat, or even an object-oriented one. This categorization not only naturally corresponds to specialized features, but also allows you to physically separate your system into different parts, so that you can change a tier with reduced impact on adjacent tiers and no impact on non-adjacent tiers. Tier migration In the histor yof computers and computer software, these three tiers have moved back and forth between the server and the client. Mainframes When computers were mainframes, all tiers were handled by the server. Mainframes stored data, processed it, and were also responsible for the layout of the presentation. Clients were dumb terminals, suited only for displaying characters on the screen and accepting the user input. Client server Not many companies could afford the acquisition of a mainframe (and many still cannot). Yet, those same companies could not do without computers at all, because the growing complexity of business processes needed automation. This development in personal computers led to a decrease in their cost. With the need to share data between them, the network traffic rose. This period in history saw the rise of the personal computer, as well as the Client server term, as there was now a true client. The presentation and logic tier moved locally, while shared databases were remotely accessible, as shown in the following diagram: Thin clients Big companies migrating from mainframes to client-server architectures thought that deploying software on ten client machines on the same site was relatively easy and could be done in a few hours. However, they quickly became aware of the fact that with the number of machines growing in a multi-site business, it could quickly become a nightmare. Enterprises also found that it was not only the development phase that had to be managed like a project, but also the installation phase. When upgrading either the client or the server, you most likely found that the installation time was high, which in turn led to downtime and that led to additional business costs. Around 1991, Sir Tim Berners-Leeinvented the Hyper Text Markup Language, better known as HTML. Some time after that, people changed its original use, which was to navigate between documents, to make HTML-based web applications. This solved the deployment problem as the logic tier was run on a single-server node (or a cluster), and each client connected to this server. A deployment could be done in a matter of minutes, at worst overnight, which was a huge improvement. The presentation layer was still hosted on the client, with the browser responsible for displaying the user interface and handling user interaction. This new approach brought new terms, which are as follows: The old client-server architecture was now referred to as fat client . The new architecture was coined as thin client, as shown in the following diagram: Limitations of the thin-client applications approach Unfortunately, this evolution was made for financial reasons and did not take into account some very important drawbacks of the thin client. Poor choice of controls HTML does not support many controls, and what is available is not on par with fat-client technologies. Consider, for example, the list box: in any fat client, choices displayed to the user can be filtered according to what is typed in the control. In legacy HTML, there's no such feature and all lines are displayed in all cases. Even with HTML5, which is supposed to add this feature, it is sadly not implemented in all browsers. This is a usability disaster if you need to display the list of countries (more than 200 entries!). As such, ergonomics of true thin clients have nothing to do with their fat-client ancestors. Many unrelated technologies Developers of fat-client applications have to learn only two languages: SQL and the technology's language, such as Visual Basic, Java, and so on. Web developers, on the contrary, have to learn an entire stack of technologies, both on the client side and on the server side. On the client side, the following are the requirements: First, of course, is HTML. It is the basis of all web applications, and although some do not consider it a programming language per se, every web developer must learn it so that they can create content to be displayed by browsers. In order to apply some common styling to your application, one will probably have to learn the Cascading Style Sheets ( CSS) technology. CSS is available in three main versions, each version being more or less supported by browser version combinations (see Browser compatibility). Most of the time, it is nice to have some interactivity on the client side, like pop-up windows or others. In this case, we will need a scripting technology such as ECMAScript. ECMAScript is the specification of which JavaScript is an implementation (along with ActionScript ). It is standardized by the ECMA organization. See http://www.ecma-international.org/publications/standards/Ecma-262.htm for more information on the subject. Finally, one will probably need to update the structure of the HTML page, a healthy dose of knowledge of the Document Object Model (DOM) is necessary. As a side note, consider that HTML, CSS, and DOM are W3C specifications while ECMAScript is an ECMA standard. From a Java point-of-view and on the server side, the following are the requirements: As servlets are the most common form of request-response user interactions in Java EE, every web developer worth his salt has to know both the Servlet specification and the Servlet API. Moreover, most web applications tend to enforce the Model-View-Controller paradigm. As such, the Java EE specification enforces the use of servlets for controllers and JavaServer Pages (JSP ) for views. As JSP are intended to be templates, developers who create JSP have an additional syntax to learn, even though they offer the same features as servlets. JSP accept scriptlets, that is, Java code snippets, but good coding practices tend to frown upon this, however, as Java code can contain any feature, including some that should not be part of views—for example, the database access code. Therefore, a completely new technology stack is proposed in order to limit code included in JSP: the tag libraries. These tag libraries also have a specification and API, and that is another stack to learn. However, these are a few of the standard requirements that you should know in order to develop web applications in Java. Most of the time, in order to boost developer productivity, one has to use frameworks. These frameworks are available in most of the previously cited technologies. Some of them are supported by Oracle, such as Java Server Faces, others are open source, such as Struts. JavaEE 6 seems to favor replacement of JSP and Servlet by Java Server Faces(JSF). Although JSF aims to provide a component-based MVC framework, it is plagued by a relative complexity regarding its components lifecycle. Having to know so much has negative effects, a few are as follows: On the technical side, as web developers have to manage so many different technologies, web development is more complex than fat-client development, potentially leading to more bugs On the human resources side, different meant either different profiles were required or more resources, either way it added to the complexity of human resource management On the project management side, increased complexity caused lengthier projects: developing a web application was potentially taking longer than developing a fat-client application All of these factors tend to make the thin-client development cost much more than fat-client, albeit the deployment cost was close to zero. Browser compatibility The Web has standards, most of them upheld by the World Wide Web Consortium. Browsers more or less implement these standards, depending on the vendor and the version. The ACID test, in version 3, is a test for browser compatibility with web standards. Fortunately, most browsers pass the test with 100 percent success, which was not the case two years ago. Some browsers even make the standards evolve, such as Microsoft which implemented the XmlHttpRequest objectin Internet Explorer and thus formed the basis for Ajax. One should be aware of the combination of the platform, browser, and version. As some browsers cannot be installed with different versions on the same platform, testing can quickly become a mess (which can fortunately be mitigated with virtual machines and custom tools like http://browsershots.org). Applications should be developed with browser combinations in mind, and then tested on it, in order to ensure application compatibility. For intranet applications, the number of supported browsers is normally limited. For Internet applications, however, most common combinations must be supported in order to increase availability. If this wasn't enough, then the same browser in the same version may run differently on different operating systems. In all cases, each combination has an exponential impact on the application's complexity, and therefore, on cost. Page flow paradigm Fat-client applications manage windows. Most of the time, there's a main window. Actions are mainly performed in this main window, even if sometimes managed windows or pop-up windows are used. As web applications are browser-based and use HTML over HTTP, things are managed differently. In this case, the presentation unit is not the window but the page. This is a big difference that entails a performance problem: indeed, each time the user clicks on a submit button, the request is sent to the server, processed by it, and the HTML response is sent back to the client. For example, when a client submits a complex registration form, the entire page is recreated on the server side and sent back to the browser even if there is a minor validation error, even though the required changes to the registration form would have been minimal. Beyond the limits Over the last few years, users have been applying some pressure in order to have user interfaces that offer the same richness as good old fat-client applications. IT managers, however, are unwilling to go back to the old deploy-as-a-project routine and its associated costs and complexity. They push towards the same deployment process as thin-client applications. It is no surprise that there are different solutions in order to solve this dilemma. What are rich clients? All the following solutions are globally called rich clients, even if the approach differs. They have something in common though: all of them want to retain the ease of deployment of the thin client and solve some or all of the problems mentioned previously. Rich clients fulfill the fourth quadrant of the following schema, which is like a dream come true, as shown in the following diagram: Some rich client approaches The following solutions are strategies that deserve the rich client label. Ajax Ajax was one of the first successful rich-client solutions. The term means Asynchronous JavaScript with XML. In effect, this browser technology enables sending asynchronous requests, meaning there is no need to reload the full page. Developers can provide client scripts implementing custom callbacks: those are executed when a response is sent from the server. Most of the time, such scripts use data provided in the response payload to dynamically update relevant part of the page DOM. Ajax addresses the richness of controls and the page flow paradigm. Unfortunately: It aggravates browser-compatibility problems as Ajax is not handled in the same way by all browsers. It has problems unrelated directly to the technologies, which are as follows: Either one learns all the necessary technologies to do Ajax on its own, that is, JavaScript, Document Object Model, and JSON/XML, to communicate with the server and write all common features such as error handling from scratch. Alternatively, one uses an Ajax framework, and thus, one has to learn another technology stack. Richness through a plugin The oldest way to bring richness to the user's experience is to execute the code on the client side and more specifically, as a plugin in the browser. Sun—now Oracle—proposed the applet technology, whereas Microsoft proposed ActiveX. The latest technology using this strategy is Flash. All three were failures due to technical problems, including performance lags, security holes, and plain-client incompatibility or just plain rejection by the market. There is an interesting way to revive the applet with the Apache Pivot project, as shown in the following screenshot (http://pivot.apache.org/), but it hasn't made a huge impact yet; A more recent and successful attempt at executing code on the client side through a plugin is through Adobe's Flex. A similar path was taken by Microsoft's Silverlight technology. Flex is a technology where static views are described in XML and dynamic behavior in ActionScript. Both are transformed at compile time in Flash format. Unfortunately, Apple refused to have anything to do with the Flash plugin on iOS platforms. This move, coupled with the growing rise of HTML5, resulted in Adobe donating Flex to the Apache foundation. Also, Microsoft officially renounced plugin technology and shifted Silverlight development to HTML5. Deploying and updating fat-client from the web The most direct way toward rich-client applications is to deploy (and update) a fat-client application from the web. Java Web Start Java Web Start (JWS), available at http://download.oracle.com/javase/1.5.0/docs/guide/javaws/, is a proprietary technology invented by Sun. It uses a deployment descriptor in Java Network Launching Protocol (JNLP) that takes the place of the manifest inside a JAR file and supplements it. For example, it describes the main class to launch the classpath, and also additional information such as the minimum Java version, icons to display on the user desktop, and so on. This descriptor file is used by the javaws executable, which is bundled in the Java Runtime Environment. It is the javaws executable's responsibility to read the JNLP file and do the right thing according to it. In particular, when launched, javaws will download the updated JAR. The detailed process goes something like the following: The user clicks on a JNLP file. The JNLP file is downloaded on the user machine, and interpreted by the local javaws application. The file references JARs that javaws can download. Once downloaded, JWS reassembles the different parts, create the classpath, and launch the main class described in the JNLP. JWS correctly tackles all problems posed by the thin-client approach. Yet it never reaches critical mass for a number of reasons: First time installations are time-consuming because typically lots of megabytes need to be transferred over the wire before the users can even start using the app. This is a mere annoyance for intranet applications, but a complete no go for Internet apps. Some persistent bugs weren't fixed across major versions. Finally, the lack of commercial commitment by Sun was the last straw. A good example of a successful JWS application is JDiskReport (http://www.jgoodies.com/download/jdiskreport/jdiskreport.jnlp), a disk space analysis tool by Karsten Lentzsch , which is available on the Web for free. Update sites Updating software through update sites is a path taken by both Integrated Development Environment ( IDE ) leaders, NetBeans and Eclipse. In short, once the software is initially installed, updates and new features can be downloaded from the application itself. Both IDEs also propose an API to build applications. This approach also handles all problems posed by the thin-client approach. However, like JWS, there's no strong trend to build applications based on these IDEs. This can probably be attributed to both IDEs using the OSGI standard whose goal is to address some of Java's shortcomings but at the price of complexity. Google Web Toolkit Google Web Toolkit (GWT) is the framework used by Google to create some of its own applications. Its point of view is very unique among the technologies presented here. It lets you develop in Java, and then the GWT compiler transforms your code to JavaScript, which in turn manipulates the DOM tree to update HTML. It's GWT's responsibility to handle browser compatibility. This approach also solves the other problems of the pure thin-client approach. Yet, GWT does not shield developers from all the dirty details. In particular, the developer still has to write part of the code handling server-client communication and he has to take care of the segregation between Java server-code which will be compiled into byte code and Java client-code which will be compiled into JavaScript. Also, note that the compilation process may be slow, even though there are a number of optimization features available during development. Finally, developers need a good understanding of the DOM, as well as the JavaScript/DOM event model. Why Vaadin? Vaadin is a solution evolved from a decade of problem-solving approach, provided by a Finnish company named Vaadin Ltd, formerly IT Mill. Therefore, having so many solutions available, could question the use of Vaadin instead of Flex or GWT? Let's first have a look at the state of the market for web application frameworks in Java, then detail what makes Vaadin so unique in this market. State of the market Despite all the cons of the thin-client approach, an important share of applications developed today uses this paradigm, most of the time with a touch of Ajax augmentation. Unfortunately, there is no clear leader for web applications. Some reasons include the following: Most developers know how to develop plain old web applications, with enough Ajax added in order to make them usable by users. GWT, although new and original, is still complex and needs seasoned developers in order to be effective. From a Technical Lead or an IT Manager's point of view, this is a very fragmented market where it is hard to choose a solution that will meet users' requirements, as well as offering guarantees to be maintained in the years to come. Importance of Vaadin Vaadin is a unique framework in the current ecosystem; its differentiating features include the following: There is no need to learn different technology stacks, as the coding is solely in Java. The only thing to know beside Java is Vaadin's own API, which is easy to learn. This means: The UI code is fully object-oriented There's no spaghetti JavaScript to maintain It is executed on the server side Furthermore, the IDE's full power is in our hands with refactoring and code completion. No plugin to install on the client's browser, ensuring all users that browse our application will be able to use it as-is. As Vaadin uses GWT under the hood, it supports all browsers that the version of GWT also supports. Therefore, we can develop a Vaadin application without paying attention to the browsers and let GWT handle the differences. Our users will interact with our application in the same way, whether they use an outdated version (such as Firefox 3.5), or a niche browser (like Opera). Moreover, Vaadin uses an abstraction over GWT so that the API is easier to use for developers. Also, note that Vaadin Ltd (the company) is part of GWT steering committee, which is a good sign for the future. Finally, Vaadin conforms to standards such as HTML and CSS, making the technology future proof. For example, many applications created with Vaadin run seamlessly on mobile devices although they were not initially designed to do so. Vaadin integration In today's environment, integration features of a framework are very important, as normally every enterprise has rules about which framework is to be used in some context. Vaadin is about the presentation layer and runs on any servlet container capable environment. Integrated frameworks There are three integration levels possible which are as follows: Level 1 : out-of-the-box or available through an add-on, no effort required save reading the documentation Level 2 : more or less documented Level 3 : possible with effort The following are examples of such frameworks and tools with their respective integration estimated effort: Level 1 : Java Persistence API ( JPA ): JPA is the Java EE 5 standard for all things related to persistence. An add-on exists that lets us wire existing components to a JPA backend. Other persistence add-ons are available in the Vaadin directory, such as a container for Hibernate, one of the leading persistence frameworks available in the Java ecosystem. A bunch of widget add-ons, such as tree tables, popup buttons, contextual menus, and many more. Level 2 : Spring is a framework which is based on Inversion of Control ( IoC ) that is the de facto standard for Dependency Injection. Spring can easily be integrated with Vaadin, and different strategies are available for this. Context Dependency Injection ( CDI ): CDI is an attempt at making IoC a standard on the Java EE platform. Whatever can be done with Spring can be done with CDI. Any GWT extensions such as Ext-GWT or Smart GWT can easily be integrated in Vaadin, as Vaadin is built upon GWT's own widgets. Level 3 : We can use another entirely new framework and languages and integrate them with Vaadin, as long as they run on the JVM: Apache iBatis, MongoDB, OSGi, Groovy, Scala, anything you can dream of! Integration platforms Vaadin provides an out-of-the-box integration with an important third-party platform: Liferay is an open source enterprise portal backed by Liferay Inc. Vaadin provides a specialized portlet that enables us to develop Vaadin applications as portlets that can be run on Liferay. Also, there is a widgetset management portlet provided by Vaadin, which deploys nicely into Liferay's Control Panel. Using Vaadin in the real world If you embrace Vaadin, then chances are that you will want to go beyond toying with the Vaadin framework and develop real-world applications. Concerns about using a new technology Although it is okay to use the latest technology for a personal or academic project, projects that have business objectives should just run and not be riddled with problems from third-party products. In particular, most managers may be wary when confronted by anew product (or even a new version), and developers should be too. The following are some of the reasons to choose Vaadin: Product is of highest quality : The Vaadin team has done rigorous testing throughout their automated build process. Currently, it consists of more than 8,000 unit tests. Moreover, in order to guarantee full compatibility between versions, many (many!) tests execute pixel-level regression testing. Support : Commercial : Although completely committed to open source, Vaadin Limited offer commercial support for their product. Check their Pro Account offering. User forums : A Vaadin user forum is available. Anyone registered can post questions and see them answered by a member of the team or of the community. Note that Vaadin registration is free, as well as hassle-free: you will just be sent the newsletter once a month (and you can opt-out, of course). Retro-compatibility: API : The server-side API is very stable, version after version, and has survived major client-engines rewrite. Some part of the API has been changed from v6 to v7, but it is still very easy to migrate. Architecture : Vaadin's architecture favors abstraction and is at the root of it all. Full-blown documentation available : Product documentation : Vaadin's site provides three levels of documentation regarding Vaadin: a five-minute tutorial, a one-hour tutorial, and the famed article of Vaadin . Tutorials API documentation : The Javadocs are available online; there is no need to build the project locally. Course/webinar offerings : Vaadin Ltd currently provides four different courses, which tackles all the needed skills for a developer to be proficient in the framework. Huge community around the product : There is a community gathering, which is ever growing and actively using the product. There are plenty of blogs and articles online on Vaadin. Furthermore, there are already many enterprises using Vaadin for their applications. Available competent resources : There are more and more people learning Vaadin. Moreover, if no developer is available, the framework can be learned in a few days. Integration with existing product/platforms : Vaadin is built to be easily integrated with other products and platforms. The artile of Vaadin describes how to integrate with Liferay and Google App Engine. Others already use Vaadin Upon reading this, managers and developers alike should realize Vaadin is mature and is used on real-world applications around the world. If you still have any doubts, then you should check http://vaadin.com/who-is-using-vaadin and be assured that big businesses trusted Vaadin before you, and benefited from its advantages as well. Summary In this article, we saw the migration of application tiers in the software architecture between the client and the server. We saw that each step resolved the problems in the previous architecture: Client-server used the power of personal computers in order to decrease mainframe costs Thin-clients resolved the deployment costs and delays Thin-clients have numerous drawbacks. For the user, a lack of usability due to poor choice of controls, browser compatibility issues, and the navigation based on page flow; for the developer, many technologies to know. As we are at the crossroad, there is no clear winner in all the solutions available: some only address a few of the problems, some aggravate them. Vaadin is an original solution that tries to resolve many problems at once: It provides rich controls It uses GWT under the cover that addresses most browser compatibility issues It has abstractions over the request response model, so that the model used is application-based and not page based The developer only needs to know one programming language: Java, and Vaadin generates all HTML, JavaScript, and CSS code for you Now we can go on and create our first Vaadin application! Resources for Article : Further resources on this subject: Vaadin Portlets in Liferay User Interface Development [Article] Creating a Basic Vaadin Project [Article] Vaadin – Using Input Components and Forms [Article]
Read more
  • 0
  • 0
  • 4495
Modal Close icon
Modal Close icon