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

How-To Tutorials - CMS & E-Commerce

830 Articles
article-image-installing-and-configuring-joomla-local-and-remote-servers
Packt
27 May 2010
8 min read
Save for later

Installing and Configuring Joomla! on Local and Remote Servers

Packt
27 May 2010
8 min read
Like every other endeavor in life, there are two ways of installing Joomla!—the easy way and the difficult way. In order to do it the difficult way, you will need to set up your server by yourself before you proceed with the installation. You have the choice of environment to use for your new installation: you may install directly to a live server or you can set up a test environment on your local computer. Minimum system requirements A fully-operational web server (preferably Apache) is required to successfully install and use Joomla!. You also need a database (preferably MySQL) and the server-side scripting language PHP, together with specific modules for MySQL, XML, and Zlib functionality, which are activated within PHP amongst others. Following are the minimum versions of these server components that are required: Software Minimum requirement Recommended Latest options Website PHP 4.3.10 4.4.7 5.x.series http://php.net MySQL 3.23.x or above   5.x series http://dev.mysql.com/downloads/mysql/5.0.html Apache 1.3 or above   2.2 series http://httpd.apache.org Installation on a local computer There are a number of ways to set up a test environment on your own local computer. Most time-pressed developers will install and configure directly onto a live server, but there are good reasons for running your application first on a local development server: Developing your application locally allows you to work on it even if you are not connected to the Internet. The experience that you gain from getting your local server running on a simple installation like WampServer for a machine running Windows, or MAMP for a Mac, will make it easier for you to understand server processes and databases. This knowledge will certainly pay off as you get deeper into Joomla!. The Web is constantly scanned and archived by various search engines, and so will everything that you put on the Web. This information will be around for quite a bit of time and you certainly don't want Google to display your inevitable learning mistakes for the world to see. Installation on WampServer WampServer2 enables you to run Apache, MySQL, and PHP on Windows, and is available for free. You can download it from http://www.wampserver.com. The WampServer2 package comes with the following components already configured to work together: Apache 2.2.11 MySQL 5.1.30 PHP 5.2.8 There are similar packages that already include Joomla! (such as DeveloperSide and WDE). However, note that these may not always have the latest secure version of Joomla!. Therefore, it is better to use WampServer2 and load it with the Joomla! version of your choice. WampServer2 is self-installing. Just double-click on the icon after you've unpacked your zipped download and follow the installation instructions. This gets your development environment ready in just a few minutes. Now let the fun begin! Installing Joomla! 1.5 on localhost Installing Joomla! on localhost can be remarkably straightforward: Download the latest stable release of Joomla!, and unzip the discernible Joomla! 1.5 folder. You will need to use a tool such as WinZip for Windows (http://www.winzip.com) to perform this task. Another free alternative to WinZip is IZArc (http://www.izarc.org/). Locate the directory in which WampServer2 is installed on your computer. This will usually be the root of your computer's main directory (usually C:) and in a folder named wamp. Open it, locate the www folder, and copy your Joomla! 1.5 folder into it. Name the Joomla! folder as per your preference. In the unlikely scenario that you will be installing only one Joomla! test site on your local machine, you may—just for the sake of living to a ripe old age—name it Joomla. Navigate to your computer desktop taskbar tray, click on the WampServer icon, and select the Start All Services option (if this has not yet been selected). Then open your browser and navigate to http://localhost. This will display the main WampServer2 interface and you will see your project, Joomla, listed under Your Projects. However, because Joomla! needs a database to run, you must create the database for our project. Click on the phpMyAdmin link. This will display another interface, this time for phpMyAdmin. Enter the name of your new database in the Create new database field. For the simple reason that we shouldn't live a complicated life, we have given this database the same name (Joomla) as our project and our installation folder. We are now ready to install Joomla!. Joomla! has an automated installation script that automatically populates database tables. The installation script will set the base URL, connect Joomla! to the database, and create tables in the database. Navigate to http://localhost/Joomla and start your installation. You will be presented with a step-by-step guide to the installation in the later pages. Page 1: Choose Language This page asks what language you want to use for the installation. We select English as the language of choice. Click on the Next button to continue with your installation. Page 2: Pre-installation Check Checks are made by the installation script on server configuration. If any of these items are not supported (marked as No), then your system does not meet the minimum requirements for the installation of Joomla!, and you should take the appropriate actions in order to correct the errors. Failing to do so could lead to your Joomla! installation not functioning properly. You are not likely to face this problem on your local installation, and if you do, it can be quickly fixed. Page 3: License The License page is just a page of legalese that the developers of Joomla! really think you must read. It tells you the conditions for use of the free software and also spells out liabilities. Primarily, if the Joomla! installation makes your computer to explode or you start acting funny after you are done with the installation, the suppliers of Joomla! will accept no liability. After correcting any host-specific errors and reading the license, you will be directed to the Database Configuration page. Page 4: Database Configuration On the Database Configuration page, you specify the database where Joomla! will store and retrieve data. Select the type of database from the drop-down list. This will generally be mysql. Also, enter the hostname of the database server that Joomla! will be installed on. This may not necessarily be the same as your web server, so check with your hosting provider if you are not sure. In the present case, it will be localhost. Now enter the MySQL username, password, and database name that you wish to use with Joomla!. These must already exist for the database that you are going to use. We have already determined this when we created the data base. Here are the values for our present project: Host Name: localhost Username: root (unless you have changed it) Password: Leave blank (unless you added a password when you set up your database) Database Name: Joomla (or whatever you have called yours) Table Prefix: If you are installing more than one instance of Joomla! in a single database, then give one of them a prefix (such as jos2_), or else the second instance will not install. Otherwise, you may safely ignore this. Click on the Next button to continue. Page 5: FTP Configuration You can safely omit this step and go on to the next page. But if you do decide to carry out this step, do take notice of the following requirements: As explained on this Joomla! installation page, due to file system permission restrictions on Linux and other Unix systems (and PHP Safe Mode restrictions), an FTP layer is used to handle fi le system manipulation and to enable Joomla! installers. You may enter an FTP username and password with access to the Joomla! root directory. This will be the FTP account that handles all of the file system operations when Joomla! requires FTP access to complete a task. However, for security reasons, if the option is available, you are advised to create a separate FTP user account with access to the Joomla! installation only and not to the entire web server. Page 6: Main Configuration This is where you define your site's public identity. The descriptions of the fields are as follows: Site Name: Enter the name of your Joomla! site. Your E-mail: This will be the e-mail address of the website Super Administrator. Admin Password: Enter a new password and then confirm it, in the appropriate fields. Along with the username admin, this will be the password that you will use to login to the Administrator Control Panel at the end of the installation. Install Sample Data: It is strongly recommended that new Joomla! users install the default sample data. To do this, select this option and click on the button, before proceeding to the next stage. Page 7: Finish That's all! Your installation success screen will be displayed. Congratulations, you are now on your way to becoming a Joomla! Guru. Once the installation script has successfully been completed and you have removed the installation folder, you will be directed to the Joomla! Administration login page—if you want to immediately perform administrative functions on your new site. Otherwise, clicking on the Site icon will direct you to the front page of your site showing all of the sample data—if you have loaded it. That is the most of what you need to know about installing Joomla!.
Read more
  • 0
  • 0
  • 2546

article-image-plone-3-themes
Packt
26 May 2010
9 min read
Save for later

Plone 3 Themes

Packt
26 May 2010
9 min read
(For more resources on Plone, see here.) Plone's stock configuration delivers a great deal of concrete functionality: workflow, security, tagging, and more. However, the people whom you need to win over—like your boss and the public—often form their first impressions of your site based solely on visual design. Replacing the out-of-the-box look of Plone with one tailored to your organization is thus a very important task. Changing the overall look of a Plone site requires more than just the web designer's usual toolkit of HTML and CSS. In this article, we provide an introduction to the additional Zope- and Plone-specific techniques you need. We give an overview of Plone's somewhat complicated theming situation, show how to theme a site in a portable, reusable way, and demonstrate practices that strike a balance among ease, speed, and compatibility with future versions of Plone. Theming is a complex topic, and there are entire books on that topic alone, so we also give plenty of outside references in case your needs extend beyond the basic. An overview of Plone theming Plone themes, also known as skins, are visual designs that can be applied to a site, independent of its content. There are two main ways to create a theme: through the web and via the filesystem. Through-the-web versus filesystem One of the great advantages of Zope (and thus Plone) has historically been the customization power available through its web-based interface. Though there are some holes in this functionality with Plone 3 and 4, you can, for the most part, still point and click your way to a working theme. The advantages of this approach are: Immediate feedback. Iterations are simple. As a result, you're encouraged to test often, bugs turn up early, and bugs caught early are bugs solved easily. Explorability. Though the Zope Management Interface, where most theme work takes place, isn't the best-organized or friendliest environment in the world, it at least offers some semblance of navigable structure. You can find a piece of HTML or CSS you want to customize, click a button, and begin editing. There's less need to think abstractly. Accessibility. Through-the-web theming requires no access to the server's filesystem, so it is usable by people without, for example, Unix command-line experience or the ability to restart Zope. The alternative is theming by developing add-on products, which live on the server's filesystem. The advantages of this are: Better tools. Expressing a theme as files and folders lets you use the entire ecosystem of filesystem-based development tools: proper text editors and version control systems, for example. Ease of re-use. Encapsulating a theme as a product means you can easily make use of it on more than one site, copy it from machine to machine, or share it with the world. Completeness. Some customizations can't yet be done through the Web: for example, moving the search box from the top of the page to the bottom by moving its viewlet into a different viewlet manager. In practice, a filesystem product is usually better, with through-the-web styling used to test changes and to make emergency in-production tweaks between Zope restarts. A load of languages Theming involves several special-purpose languages. Here's the rundown: Language Use in Theming HTML The old standby, Hypertext Markup Language defines the semantic structure of every page. Plone's markup sticks admirably to specifying meaning and avoids visual design. For example, its navigation bars are <ul>s, and its portlets (those omnipresent titled sidebars) are actually definition lists (<dl>s) with the title as the term and the content as the definition. Visual styling is applied almost wholly by CSS. CSS Cascading Stylesheets, another standard tool in the web designer's kit, apply a layer of visual design atop HTML. Because Plone's HTML so assiduously avoids visual design, we can change the look of a Plone site substantially without tampering with markup. TAL Most theming can be done with just CSS, but sometimes, like when adding new element to a page, only HTML changes will do. All HTML in Plone is produced by Template Attribute Language (TAL), a simple XML-based language so named because it nestles entirely within the attributes of XML tags. Like other templating languages, TAL is a more readable alternative to littering program code with bits of hard-coded markup. It is good for inserting content into a page skeleton, repeating portions of a page, and doing other simple presentation logic. More complicated logic is best done in Python modules, where you aren't limited to cramped one-liners. A good introduction to TAL is http://docs.zope.org/zope2/zope2book/ZPT.html. METAL The Macro Expansion for TAL (METAL) language helps combine bits of TAL from different templates to create a single page. http://docs.zope.org/zope2/zope2book/ZPT.html#macros is a good introduction. Python The general-purpose language Zope and Plone are written in. We will write almost no Python in this article, but it often does make an appearance in page templates. It has a much more prominent role in Zope 3-style theming than in Zope 2. ZCML Some parts of theming use the Zope 3 component architecture, a scheme for tying plugins and customizations into a large system like Plone. The Zope Component Markup Language (ZCML) is an XML-based language that specifies where to plug these in. For example, we will use ZCML to tie our theme product to a third-party package that drastically simplifies overriding some templates. GenericSetup XML A variety of XML mini-languages, which show up in your product's profiles folder. These are run by GenericSetup, Plone's installation framework, when your theme product is installed or uninstalled. Don't let theming hold you up Theming is complicated and can be time-consuming the first time through. Don't make the common mistake of letting it hold up work on the rest of your site. Indeed, most information-oriented work—audience analysis, the creation and input of content, information architecture decisions, and development of custom content types—can go on without much thought toward the coat of paint that will eventually go over it. (Likewise, you can change the look of your site later without having to redo all your navigation and content.) The few elements to decide on ahead of time are… Navigation. What is your navigation strategy? Should the theme provide space for main or contextual navigation or for a search field? It can help to have your graphic designer join you for the last few minutes of each information architecture discussion to synchronize expectations. Drawing wireframes is another fast way to get everybody on the same page. For an excellent primer on strategies for organizing your site's content, see Peter Morville's Information Architecture for the World Wide Web. CSS styles. The style menu in Plone's built-in editor is commonly customized to suit the semantic needs of the site at hand. Decide early in the design process what styles will be needed: for example, body text, warning messages, sidebars containing supplementary material, and various levels of headings. It's not necessary to settle on a look for these styles—just to enumerate them and establish their CSS class names. After that, theme and content work can progress in parallel. Prepare your development environment Before we get down the business of creating a theme, make sure you have all the tools and settings in place: Run Zope in foreground mode. When developing, always launch Zope using bin/instance fg rather than bin/instance start. At the cost of a little processor power, this greatly speeds development by… Puting Zope into debug mode. This means it will notice certain changes to the product we're developing without needing to be constantly restarted. In Plone 3.3 and above, this automatically turns on the CSS and JavaScript debug modes as well (explained below). Printing error messages, usually hidden in the event.log file, to the terminal. Plone typically makes a lot of noise when it starts up; that can be ignored. But watch for errors, hidden among the innocuous INFO and DEBUG messages, when you exercise the functionality of your product. Turn on CSS debug mode. With Plone 3.3 or above, you can skip this step, as it's implicitly done when you run Zope in foreground mode. In older versions of Plone, go into the ZMI, then to your Plone site, and finally to portal_css. There, turn on Debug/development mode. This will keep Plone from doing its clever caching, merging, and compression of stylesheets while you're developing them, helping ensure that you always see the latest version of your work. Without CSS debug mode, your CSS changes will take effect only when Zope is restarted. Get Firefox, Firebug, and the Web Developer add-on. Firefox is a nice browser, but what really makes it shine is its third-party plugins. Get the latest version, available from http://www.getfirefox.com/, then grab two vital plugins, Firebug (http://getfirebug.com/) and Web Developer (https://addons.mozilla.org/firefox/addon/60). Turn off caching. In Firefox, show the Web Developer Toolbar (View ? Toolbars ? Web Developer Toolbar), then pull down its Disable menu and select Disable Cache. Together with enabling CSS debug mode, this will ensure that you always see your latest CSS changes. Nothing is more frustrating than spending hours chasing a problem, only to track it down to a stale cache. If you use Firefox for casual browsing, you may not wish to disable caching globally and slow down your surfing. In that case, be sure to use Shift+Command+R (on the Mac) or Shift+Ctrl+R (on other platforms) to force your stylesheets to reload when doing theme work. Begin your theme On-disk theme products can be quite verbose, so we employ a program to generate the skeleton of ours. We'll then make a few clean-ups before moving on to making a visual impact. Install paster and ZopeSkel To generate the empty shell of a theme, we'll use a code generation tool called paster. A set of Zope- and Plone-specific code snippets, called ZopeSkel, extends paster to provide a sort of "madlibs for Plone", churning out skeletal products whose blanks we can fill in. Here's how to get a copy of paster up and running: Some installations of Plone come with paster and ZopeSkel; check the bin folder in your buildout. If paster is in there, you're done; skip to the next section. If not, read on. Install easy_install, a simple Python installer, which we can use to install paster and ZopeSkel. Follow the platform-specific instructions on the easy_install download page: http://pypi.python.org/ pypi/setuptools. Use easy_install to install ZopeSkel, which also automatically installs paster. For example: easy_install ZopeSkel
Read more
  • 0
  • 0
  • 1727

article-image-creating-installing-and-tweaking-your-theme-using-plone-3
Packt
26 May 2010
12 min read
Save for later

Creating, Installing and Tweaking your theme using Plone 3

Packt
26 May 2010
12 min read
(For more resources on Plone here.) We will first inspect a few structural changes and install them, and then finally examine the various components and skin layer items that have been changed, one at a time. Where restarting Zope or rerunning your buildout would be required, this will be noted. About the theme This theme and its design are available for personal and professional use to anyone, and can be freely modified. You can (and should) download the files from https://svn.plone.org/svn/collective/plonetheme.guria/trunk using the following command: svn co https://svn.plone.org/svn/collective/plonetheme.guria/trunk plonetheme.guria Note the space between the words trunk and plonetheme.guria. This theme is intended for installation on Plone 3 web sites. The finished theme should look like the following, but we have work to do to make this happen: This theme was created by me, for use by a charity group in India, called Guria (http://www.guriaindia.org), dedicated to ending human trafficking and prostitution. The finished site is currently in development, and is generously hosted free of charge by the talented folks at Six Feet Up (sixfeetup.com). Additionally, most of the code and lessons learned come courtesy of similar themes created by the staff at ONE/Northwest in Seattle, Washington. The design for this theme was created with the assumption that most of the tasks would need to be present in this theme. In fact, the only task not covered here is the creation of a new viewlet manager. Creation of viewlet managers is discussed at http://plone.org/documentation/how-to/adding-portlet-managers and http://plone.org/documentation/manual/theme-reference/elements/viewletmanager/override. Creating a theme product I created a theme product named plonetheme.guria, using the command line syntax paster create –t plone3_theme, while we were located in the src/ directory of our buildout, as seen next: [bash: /opt/mybuildout/src] paster create -t plone3_theme plonetheme.guriaSelected and implied templates: ZopeSkel#basic_namespace A project with a namespace package ZopeSkel#plone A Plone project ZopeSkel#plone3_theme A Theme for Plone 3.0Variables: egg: plonetheme.guria package: plonethemeguria project: plonetheme.guriaEnter namespace_package (Namespace package (like plonetheme)) ['plonetheme']:Enter package (The package contained namespace package (like example)) ['example']: guriaEnter skinname (The skin selection to be added to 'portal_skins' (like 'My Theme')) ['']: Guria Theme for the Plone Theming BookEnter skinbase (Name of the skin selection from which the new one will be copied) ['Plone Default']:Enter empty_styles (Override default public stylesheets with empty ones?) [True]: FalseEnter include_doc (Include in-line documentation in generated code?) [False]:Enter zope2product (Are you creating a Zope 2 Product?) [True]:Enter version (Version) ['0.1']:Enter description (One-line description of the package) ['An installable theme for Plone 3.0']:Enter long_description (Multi-line description (in reST)) ['']:Enter author (Author name) ['Plone Collective']: Veda WilliamsEnter author_email (Author email) ['product-developers@lists. plone.org']: [email protected] keywords (Space-separated keywords/tags) ['web zope plone theme']:Enter url (URL of homepage) ['http://svn.plone.org/svn/collective/']:Enter license_name (License name) ['GPL']:Enter zip_safe (True/False: if the package can be distributed as a .zip file) [False]:Creating template basic_namespaceCreating directory ./plonetheme.guria[snip] You may wish to generate a new Plone theme product yourself, so that you can compare and contrast the differences between the Guria theme and a vanilla Plone theme. Notice that the full name of the theme is plonetheme.guria, and where an item shows as blank, it defaults to the example value in that step. In other words, the namespace package defaults to plonetheme, because there was no reason to change it. The skinname is set to a single lowercase word out of stylistic preference. It's important to also note that you should not use hyphens or spaces in your theme names, as they will not be recognized by your buildout. We've chosen not to override Plone's default stylesheets, and instead, we want to build on top of Plone's default (and excellent!) stylesheets. I prefer this method mostly because the layout needed for Plone's Contents view and other complex structural pieces are already taken care of by Plone's base stylesheets. It's easier than trying to rebuild those from scratch every time, but this is merely a personal preference. Following the creation of the theme, we register the theme product in our buildout.cfg, using the following syntax [buildout] ...develop = src/plonetheme.guria...[instance]eggs = plonetheme.guria...zcml = plonetheme.guria... If we were using the eggtractor egg, there would be no need to add these lines of code to our buildout.cfg; all we would need to do is rebuild our buildout and it would automatically recognize the new egg. eggtractor can be found at http://pypi.python.org/pypi/buildout.eggtractor, and is documented thoroughly. Assuming we are not using eggtractor, we must rebuild our buildout, as we have altered ZCML code and added a new egg: [bash: /opt/mybuildout/src/] ./bin/buildout This would be a good time to check your vanilla theme product into Subversion, so that you can track back to the original version, if needed. However, since this is an existing theme, there is no need to do so. For the purposes of following along, it might be best if you do not yet install the theme. We want to make some changes first. However, we will point out some caveats along the way, in case you installed the theme prematurely. Altering the theme product's structure Several modifications have been made to the theme product's structure to shorten folder names and change the default behavior. Again, this is mostly a personal preference. Let's take a look at these changes and how they were achieved. Renaming the theme In our theme product, you will see a file named profiles.zcml, located at mybuildout/src/plonetheme.guria/plonetheme/guria/profiles.zcml. The code looks like this: <configure i18n_domain="plonetheme.guria"> <genericsetup:registerProfile name="default" title="Guria Theme for the Plone Theming Book" directory="profiles/default" description='Extension profile for the "Guria Theme for the Plone Theming Book" Plone theme.' provides="Products.GenericSetup.interfaces.EXTENSION" /></configure> If you named your theme in a way that was less descriptive, you could alter the title. Naming your theme product properly is important, because you may have different types of products used for a given web site—for example, a policy product for content that might be used in tandem with your theme product. This text is what you see in the portal_quickinstaller at http://localhost:8080/mysite/portal_quickinstaller/manage_installProductsForm, where mysite is the name of your Plone site. You can also see this name if you install your theme product via Site Setup Add-on Products|, found at http://localhost:8080/mysite/prefs_install_products_form. If you change your XML here, and your theme product is already installed, you'll need to start (or restart) your Zope instance, using: [bash: /opt/mybuildout] ./bin/instance fg Shortening folder names Next, we look at the folder structure of our theme product. The standard Plone 3 theme produces folders with names like plonetheme_guria_custom_images, plonetheme_guria_custom_templates, and plonetheme_guria_styles. While there is nothing wrong with keeping this structure, it can be cumbersome to type or tab through (especially when checking items into Subversion). However, you might want to keep the existing folder names to help you distinguish which items of base Plone you modified. This can make migrations easier. If you choose this route, you probably want to create additional folders for non-base-Plone items. I personally prefer the shorter folder names and don't worry too much about the migration issues. In the case of this theme product, I opted to make the folder names shorter. First, I altered the names of the folders in the skins/ folder to guria_images, guria_styles, and guria_templates. Then, in the theme, go to mybuildout/plonetheme.guria/plonetheme/guria/skins.zcml. The code in this file is altered to appear as follows: <configure i18n_domain="plonetheme.guria"> <!-- File System Directory Views registration --> <cmf:registerDirectory name="guria_images"/> <cmf:registerDirectory name="guria_templates"/> <cmf:registerDirectory name="guria_styles"/></configure> One more step is required here. In plonetheme.guria/plonetheme/guria/profiles/default/skins.xml, the code is changed to read as follows: <?xml version="1.0"?><object name="portal_skins" allow_any="False" cookie_persistence="False" default_skin=" Guria Theme for the Plone Theming Book "> <object name="guria_images" meta_type="Filesystem Directory View" directory="plonetheme.guria:skins/guria_images"/> <object name="guria_templates" meta_type="Filesystem Directory View" directory="plonetheme.guria:skins/guria_templates"/> <object name="guria_styles" meta_type="Filesystem Directory View" directory="plonetheme.guria:skins/guria_styles"/> <skin-path name=" Guria Theme for the Plone Theming Book " based- on="Plone Default"> <layer name="guria_images" insert-after="custom"/> <layer name="guria_templates" insert-after="guria_images"/> <layer name="guria_styles" insert-after="guria_templates"/> </skin-path></object> Basically, the steps are the following:   Rename the folders on the filesystem. Modify the skins.zcml file to change the name of the filesystem directory view (what you see in the portal_skins/properties area of the ZMI). Modify the skins.xml file in the profiles/default folder to match. This alters the basic profile of your theme product. If you wanted to add additional folders and filesystem directory views here (a scripts/ folder, for example), you'd just add code by following the conventions given to you in these files and then create additional folders. Making changes to the ZCML file means that you would need to do a restart of your Zope instance. If you installed your theme product before making the changes to the skin layer names, you might want to inspect the skin layers at http://localhost:8080/mysite/ portal_skins/manage_propertiesForm, to make sure that the correct skin layers are listed. You might even need to reimport the "skins tool" step via portal_setup at http://localhost:8080/mysite/portal_setup/manage_importSteps. Make sure you choose the correct profile first by choosing your theme product's name from the drop-down list at the top of the import page. The theme product's name is the same name as you find in your profiles.zcml file. Adjusting how stylesheets and images are used Next, we remove some of the default behavior given to us by the plone3_theme recipe. In a vanilla theme product, folders named images/ and stylesheets/ are inserted into the plonetheme.guria/plonetheme/guria/browser/ directory. Additionally, a file named main.css is included in the stylesheets/ directory. I chose not to place the theme's images or stylesheets in the browser/ directory, as this is generally unnecessary for most themes. Advanced programmers may wish to expose these items to the browser layer, but this is generally a personal choice and carries with it additional consequences. I deleted the folders mentioned above, as well as the i file. Then, I opened the file named configure.zcml, located at plonetheme.guria/plonetheme/guria/browser/, and removed all of the following boilerplate text: <!-- Viewlets registration --> <!-- Zope 3 browser resources --> <!-- Resource directory for images --> <browser:resourceDirectory name="plonetheme.guria.images" directory="images" layer=".interfaces.IThemeSpecific" /> <!-- Resource directory for stylesheets --> <browser:resourceDirectory name="plonetheme.guria.stylesheets" directory="stylesheets" layer=".interfaces.IThemeSpecific" /> I then removed the highlighted code below fromI then removed the highlighted code below from plonetheme.guria/plonetheme/guria/profiles/default/cssregistry.xml:: <stylesheet title="" id="++resource++plonetheme.guria.stylesheets/main.css" media="screen" rel="stylesheet" rendering="import" cacheable="True" compression="safe" cookable="True" enabled="1" expression=""/> And replaced it with the following: <stylesheet title="" id="guria.css" media="screen" rel="stylesheet" rendering="import" cacheable="True" compression="safe" cookable="True" enabled="1" expression=""/> This, in effect, tells our theme product that we will be using a stylesheet named guria.css (or more correctly, guria.css.dtml, as we'll see in a moment). This stylesheet does not yet exist, so we have to create it. I wanted the option of making use of the DTML behavior provided by Plone, so that I could use certain base properties provided to us via the base_properties.props file (also located in our skins/guria_styles/ folder). DTML essentially allows us to use property-sheet variables and apply changes on a more global scale. The easiest way to create this new stylesheet is to go to your mybuildout/buildout-cache/eggs/Plone[some version number]/Products/CMFPlone/skins/plone_styles/ploneCustom.css and copy the contents of that file into a new stylesheet (named guria.css.dtml) in your theme's guria_styles/ folder (located in the skins/ directory at mybuildout/plonetheme.guria/plonetheme/guria/skins/guria_styles). The important bits of code you want are as follows: /* <dtml-with base_properties> (do not remove this :) *//* <dtml-call "REQUEST.set('portal_url', portal_url())"> (not this either :) *//* DELETE THIS LINE AND PUT YOUR CUSTOM STUFF HERE */ /* </dtml-with> */ Again, we would need to restart our Zope at this point, as we have modified our ZCML. If we had already installed our theme product, we'd also have to import our cssregistry.xml file via portal_setup in the ZMI, to capture the new GenericSetup profile settings. However, we have not yet installed the product, so we do not need to worry about this.
Read more
  • 0
  • 0
  • 1365
Visually different images

article-image-building-news-aggregating-site-joomla
Packt
26 May 2010
3 min read
Save for later

Building a News Aggregating Site in Joomla!

Packt
26 May 2010
3 min read
(For more resources on Joomla!, see here.) The completed news aggregation site will look similar to the example shown in the following screenshot: Build Weird Hap'nins Vaughan Pyre is a very ambitious webpreneur. What he really hopes for is a website that is completely self-maintaining, and on which he can place some Google AdSense blocks. Clicks from the visitors to his site will ensure that he makes lots of money. For this, he needs a site where the content updates regularly with fresh content so that visitors will keep coming back to click on some more Google ads. Vaughan's ultimate objective is to create several of these websites. Template The template chosen is Midnight by BuyHTTP, which is a template that fits the theme of this unique website. Extensions This is, surprisingly, a very simple site to build, and much of the requirements can be actually be achieved by using the native News Feeds component. However, the News Feeds component will only list the title links to the external feed items, whereas what Vaughan wants is that the feeds are pulled into the site as articles. Therefore, we will be using an automatic article generator component. There are several of such components on the Joomla! extensions site, but almost all of them are commercial. Vaughan is a skinflint and will not pay to buy any script, so what we are looking for is free component. That is why we have chosen the following: 4RSS—aggregates RSS feeds and creates articles from them JCron Scheduler—used for cron jobs management and scheduling to simulate cron jobs through the Joomla! frontend interface at preset intervals Indeed, were it not for the fact that Vaughan needs the content to automatically be updated, we needn't use any extension other than the 4RSS component. Other extensions The core module that will be used for this site is: Main Menu module—creates the primary navigation functionality for the site pages Sections and categories New sections and categories will need to be created so that incoming article feeds will be correctly routed according to their description. A new section will be created that we will call Feed. Under this section, we shall have three categories—Bad News, More Bad News, and Weird News. Create a new section We intend to create a section that will be named Feed. In order to do this, perform the following steps: Navigate to the Section Manager from the Control Panel, and then click on the New icon at the top right-hand side, in order to create a new section. On the next page, add the name of the section, and then save your changes. Create new categories To create a new category, perform the following steps: Navigate to the Category Manager page from the Control Panel. On the following page, create a new category in the same way as we created the new section. However, remember to set the Section to Feed.
Read more
  • 0
  • 0
  • 2558

article-image-setting-complete-django-e-commerce-store-30-minutes
Packt
21 May 2010
7 min read
Save for later

Setting up a Complete Django E-commerce store in 30 minutes

Packt
21 May 2010
7 min read
In order to demonstrate Django's rapid development potential, we will begin by constructing a simple, but fully-featured, e-commerce store. The goal is to be up and running with a product catalog and products for sale, including a simple payment processing interface, in about half-an-hour. If this seems ambitious, remember that Django offers a lot of built-in shortcuts for the most common web-related development tasks. We will be taking full advantage of these and there will be side discussions of their general use. In addition to building our starter storefront, this article aims to demonstrate some other Django tools and techniques. In this article by Jesse Legg, author of Django 1.2 e-commerce, we will: Create our Django Product model to take advantage of the automatic admin tool Build a flexible but easy to use categorization system, to better organize our catalog of products Utilize Django's generic view framework to expose a quick set of views on our catalog data Finally, create a simple template for selling products through the Google Checkout API (Read more interesting articles on Django 1.2 e-commerce here.) Before we begin, let's take a moment to check our project setup. Our project layout includes two directories: one for files specific to our personal project (settings, URLs, and so on), and the other for our collection of e-commerce Python modules (coleman). This latter location is where the bulk of the code will live. If you have downloaded the source code from the Packt website, the contents of the archive download represents everything in this second location. Designing a product catalog The starting point of our e-commerce application is the product catalog. In the real world, businesses may produce multiple catalogs for mutually exclusive or overlapping subsets of their products. Some examples are: fall and spring catalogs, catalogs based on a genre or sub-category of product such as catalogs for differing kinds of music (for example, rock versus classical), and many other possibilities. In some cases a single catalog may suffice, but allowing for multiple catalogs is a simple enhancement that will add flexibility and robustness to our application. As an example, we will imagine a fictitious food and beverage company, CranStore.com, that specializes in cranberry products: cranberry drinks, food, and desserts. In addition, to promote tourism at their cranberry bog, they sell numerous gift items, including t-shirts, hats, mouse pads, and the like. We will consider this business to illustrate examples as they relate to the online store we are building. We will begin by defining a catalog model called Catalog. The basic model structure will look like this: class Catalog(models.Model): name = models.CharField(max_length=255 slug = models.SlugField(max_length=150) publisher = models.CharField(max_length=300) description = models.TextField() pub_date = models.DateTimeField(default=datetime.now) This is potentially the simplest model we will create. It contains only five, very simple fields. But it is a good starting point for a short discussion about Django model design. Notice that we have not included any relationships to other models here. For example, there is no products ManyToManyField. New Django developers tend to overlook simple design decisions such as the one shown previously, but the ramifications are quite important. The first reason for this design is a purely practical one. Using Django's built-in admin tool can be a pleasure or a burden, depending on the design of your models. If we were to include a products field in the Catalog design, it would be a ManyToManyField represented in the admin as an enormous multiple-select HTML widget. This is practically useless in cases where there could be thousands of possible selections. If, instead, we attach a ForeignKey to Catalog on a Product model (which we will build shortly), we instantly increase the usability of Django's automatic admin tool. Instead of a select-box where we must shift-click to choose multiple products, we have a much simpler HTML drop-down interface with significantly fewer choices. This should ultimately increase the usability of the admin for our users. For example, CranStore.com sells lots of t-shirts during the fall when cranberries are ready to harvest and tourism spikes. They may wish to run a special catalog of touristy products on their website during this time. For the rest of the year, they sell a smaller selection of items online. The developers at CranStore create two catalogs: one is named Fall Collection and the other is called Standard Collection. When creating product information, the marketing team can decide which catalog an individual product belongs to by simply selecting them from the product editing page. This is more intuitive than selecting individual products out of a giant list of all products from the catalog admin page. Secondly, designing the Catalog model this way prevents potential "bloat" from creeping into our models. Imagine that CranStore decides to start printing paper versions of their catalogs and mailing them to a subscriber list. This would be a second potential ManyToManyField on our Catalog model, a field called subscribers. As you can see, this pattern could repeat with each new feature CranStore decides to implement. By keeping models as simple as possible, we prevent all kinds of needless complexity. In addition we also adhere to a basic Django design principle, that of "loose coupling". At the database level, the tables Django generates will be very similar regardless of where our ManyToManyField lives. Usually the only difference will be in the table name. Thus it generally makes more sense to focus on the practical aspects of Django model design. Django's excellent reverse relationship feature also allows a great deal of flexibility when it comes time to using the ORM to access our data. Model design is difficult and planning up-front can pay great dividends later. Ideally, we want to take advantage of the automatic, built-in features that make Django so great. The admin tool is a huge part of this. Anyone who has had to build a CRUD interface by hand so that non-developers can manage content should recognize the power of this feature. In many ways it is Django's "killer app". Creating the product model Finally, let's implement our product model. We will start with a very basic set of fields that represent common and shared properties amongst all the products we're likely to sell. Things like a picture of the item, its name, a short description, and pricing information. class Product(models.Model): name = models.CharField(max_length=300) slug = models.SlugField(max_length=150) description = models.TextField() photo = models.ImageField(upload_to='product_photo', blank=True) manufacturer = models.CharField(max_length=300, blank=True) price_in_dollars = models.DecimalField(max_digits=6, decimal_places=2) Most e-commerce applications will need to capture many additional details about their products. We will add the ability to create arbitrary sets of attributes and add them as details to our products later in this article. For now, let's assume that these six fields are sufficient. A few notes about this model: first, we have used a DecimalField to represent the product's price. Django makes it relatively simple to implement a custom field and such a field may be appropriate here. But for now we'll keep it simple and use a plain and built-in DecimalField to represent currency values. Notice, too, the way we're storing the manufacturer information as a plain CharField. Depending on your application, it may be beneficial to build a Manufacturer model and convert this field to a ForeignKey. Lastly, you may have realized by now that there is no connection to a Catalog model, either by a ForeignKey or ManyToManyField. Earlier we discussed the placement of this field in terms of whether it belonged to the Catalog or in the Product model and decided, for several reasons, that the Product was the better place. We will be adding a ForeignKey to our Product model, but not directly to the Catalog. In order to support categorization of products within a catalog, we will be creating a new model in the next section and using that as the connection point for our products.
Read more
  • 0
  • 0
  • 12509

article-image-creating-custom-content-type-paster-plone-3
Packt
20 May 2010
18 min read
Save for later

Creating a Custom Content Type with Paster in Plone 3

Packt
20 May 2010
18 min read
(Further resources on Plone see here.) we have used a graphic application (ArgoUML) to draw a UML model that was automatically transformed by ArchGenXML into an Archetypes-based content type for Plone. In this article, we'll create a content type product with another tool, paster. It's not a graphic application, but it's as easy to use as writing a few characters. We used paster earlier to create a buildout-based Zope instance and an egg-structured Plone product. Here we'll use it to create a full Archetype product, its schema fields, and even the required tests to make sure everything is working as intended Creating an Archetypes product with paster There are several steps to take with paster to produce a full and useful content type. The first one should be the creation of the structure, meaning the product directory organization. Getting ready The final destination of this product, at least at development stage, is the src folder of our buildout directory. There is where we place our packages source code while we are working on them, until they become eggs (to see how to turn them into eggs read Submitting products to an egg repository). Thus go to your buildout directory and then get inside the src folder: cd ./src Make sure you have the latest ZopeSkel installed. ZopeSkel is the name of a Python package with a collection of skeletons and templates to create commonly used Zope and Plone projects via a paster command. easy_install -U ZopeSkel   How to do it… Create a package for the new add-on product: We are going to create a new package called pox.video. The pox prefix is taken from PloneOpenX (the website we are working on) and will be the namespace of our product. paster create -t archetype Fix the main configure.zcml file to prevent errors: Open the just created configure.zcml file in the pox/video folder and comment the internationalization registration like this: <!-- <i18n:registerTranslations directory="locales" /> --> Update the Zope instance with the new product: To let Zope know that there's new code to be used, let's update our instance buildout.cfg file. In the main [buildout] section, modify the eggs and develop parameters like this: [buildout] ... eggs = ... pox.video ... develop = src/pox.video Automatically add the product in a Plone site: We can install our brand new product automatically during buildout. So add a pox.video line inside the [plonesite] part's products parameter: [plonesite] recipe = collective.recipe.plonesite ... products = ... pox.video Rebuild and relaunch the Zope instance: Build your instance and, if you want to, launch it to check that the pox.video product is installed (not strictly necessary though). ./bin/buildout ./bin/instance fg How it works… So far we have a skeleton product, which is composed basically of boilerplate (we will build on it further). However, it has all the necessary code to be installed, which is important. The paster command of Step 1 in How to do it… creates a package using the archetype available template. When run, it will output some informative text and then a short wizard will be started to select some options. The most important are the first five ones: Option Value Enter project name pox.video Expert mode? Choose whatever option you like. Project Title Video Version 1.0 Description Video content type for PloneOpenX website Add whatever you want to the remaining options (if you chose other than easy mode), or just hit Enter to each one. After selecting the last option, you'll get an output like this (a little longer actually): Creating template basic_namespace Creating directory .pox.video Creating template archetype Recursing into +namespace_package+ Recursing into +package+ Recursing into content Recursing into interfaces Recursing into portlets Recursing into profiles Recursing into tests ... The project you just created has local commands. These can be used from within the product. usage: paster COMMAND Commands: addcontent Adds plone content types to your project For more information: paster help COMMAND The first group of lines tells us something about the created directory structure. We have a pox.video (project name) folder, containing a pox (namespace) folder, which contains a video (package) folder, which in turn contains several sub-packages: content, interfaces, portlets, profiles, and tests. In the following sections, we are going to deal with all of them except portlets, which will be tackled in Creating a portlet package, Customizing a new portlet according to our requirements, and Testing portlets. The second group of lines (after the ellipsis) gives us very important information: we can use particular local commands inside our fresh product. More of this in the next section. Step 2 in the preceding procedure is to tell Zope about the new available package. By adding pox.video in the eggs parameter, we add it in Zope's PYTHONPATH. We also have to add the package's location in the develop parameter. If not, the buildout process would try to fetch it from some of the URLs listed in the find-links parameter. During start up, Zope 2 loads (Five does the job actually) configuration files, usually configure.zcml, for all the products and packages inside the folders that are listed in the [instance] section's products parameter. For other Python packages outside those folders, a ZCML slug is required for the product to be loaded. Fortunately, from Plone 3.3 onwards, the ZCML slug is not needed if packages to be installed use z3c.autoinclude, which automatically detects and includes ZCML files. Although we were not aware of that, when we created the pox.video package with paster, z3c.autoinclude was added as an entry point in the setup.py file. Open it in the main pox.video folder to check it: ... setup(name='pox.video', version=version, description="Video content type for PloneOpenX website", ... entry_points=""" # -*- entry_points -*- [z3c.autoinclude.plugin] target = plone """, ... ) For those packages that don't have this feature, we must explicitly insert a reference to the package in the zcml parameter of the [instance] section like we did in Taking advantage of an enhanced interactive Python debugger with ipdb: [instance] ... # If you want to register ZCML slugs for any packages, # list them here. # e.g. zcml = my.package my.other.package zcml = iw.debug There's more… Do not forget to test your changes (paster changes in fact)! Fortunately, paster creates automatically a tests sub-package and a package-level README.txt file with the first part of a test (logging into our website). Feel free to take a look at it, as it is a very good example of doctest. Nevertheless, it really doesn't test too much for the time being. It will be more productive after adding some features to the product. You may find it really useful to read the content types section from the online Plone Developer Manual at http://plone.org/documentation/manual/developer-manual/archetypes. See Also Submitting products to an egg repository Taking advantage of an enhanced interactive Python debugger with ipdb Adding a content type into a product Adding fields to a content type Adding a custom validator to a content type Creating a portlet egg with paster Customizing a new portlet according to our requirements Testing portlets Adding a content type into a product In Creating an Archetypes product with paster, we were able to create a package shell with all the necessary code to install a product, although it was unproductive. We are now going to add some useful functionality by means of, again, our dear paster. Getting ready When we ran paster in Creating an Archetypes product with paster, we highlighted some of its output, copied below: The project you just created has local commands. These can be used from within the product. Paster local commands are available inside the project folder. So let's move inside it: cd ./src/pox.video How to do it… To add a new content type inside the product, run the following command: paster addcontent contenttype How it works… This will run the addcontent paster command with its contenttype template. After a short wizard asking for some options, it will produce all the code we need. Option Value Enter Video Enter contenttype_description FLV video file Enter folderish False Enter global_allow True Enter allow_discussion True/False, whatever - You'll get an output like this: ... Inserting from README.txt_insert into /pox.video/pox/video/README.txt Recursing into content Recursing into interfaces Recursing into profiles Recursing into default Recursing into types If you need more than just one content type in your product, you can run the paster addcontent contenttype command as many times as you want. There's no need to modify, buildout.cfg file, as we have already made all the required changes. If you didn't make these modifications, please refer to Creating an Archetypes product with paster. Open the interface file in ./src/pox.video/pox/video/interface/video.py: from zope import schema from zope.interface import Interface from pox.video import videoMessageFactory as _ class IVideo(Interface): """Description of the Example Type""" # -*- schema definition goes here -*- Empty interfaces, like this one, are called marker interfaces. Although they provide some information (they can be used to associate a class with some functionality as we will see in Using the ZCA to extend a third party product: Collage), they lack attributes and methods information (that is, their promised functionalities), and consequently and worse, they don't document. Interfaces don't exist in Python. However, Zope 3 has incorporated this concept to let components interact easier. All attributes and methods declarations in interfaces are a contract (not a binding one, though) with the external world. For more information about zope.interface, visit http://wiki.zope.org/Interfaces/FrontPage. The new content type class is in the video.py file located in the ./src/pox.vieo/pox/video/content package. Let's go through it and explain its pieces. """Definition of the Video content type """ from zope.interface import implements, directlyProvides from Products.Archetypes import atapi from Products.ATContentTypes.content import base from Products.ATContentTypes.content import schemata from pox.video import videoMessageFactory as _ from pox.video.interfaces import IVideo from pox.video.config import PROJECTNAME All paster-generated content types inherit from basic ATContentTypes, which is good given the large number of products available for them. Check the Products.ATContentTypes package for plenty of good working examples. VideoSchema = schemata.ATContentTypeSchema.copy() + atapi.Schema(( # -*- Your Archetypes field definitions here ... -*- )) Schemas specify the fields available in content types. In our case, the Video content type is a plain copy of ATContentTypeSchema, which already includes all fields necessary to support Dublin Core convention. Dublin Core is supported thanks to the BaseObject and ExtensibleMetadata modules in the Products.Archetypes package. VideoSchema here is the result of the addition (yes, we can actually add schemas) of two other schemas: the aforementioned ATContentTypeSchema and the new empty one created with the atapi.Schema(()) method, which expects a tuple argument (check the double brackets). Up to ZopeSkel 2.16 (paster's package) the storage of title and description fields are changed to AnnotationStorage. This reduces performance and therefore it would be better to change it by removing these lines letting Archetypes deal with regular AttributeStorage: # Set storage on fields copied from ATContentTypeSchema, # making sure # they work well with the python bridge properties. VideoSchema['title'].storage = atapi. AnnotationStorage() VideoSchema['description'].storage = atapi. AnnotationStorage() here are plans to remove this from ZopeSkel, but there's no release date yet for it. After schema definition, we call finalizeATCTSchema to re-order and move some fields inside our schema according to Plone standard. It's advisable to get familiar with its code in the Products.ATContentTypes.content.schema module: schemata.finalizeATCTSchema(VideoSchema, moveDiscussion=False) Once defined its schema the real class is created. As we said earlier, it inherits from base.ATCTContent; this will be changed for our Video content type. class Video(base.ATCTContent): """FLV video file""" implements(IVideo) meta_type = "Video" schema = VideoSchema title = atapi.ATFieldProperty('title') description = atapi.ATFieldProperty('description') # -*- Your ATSchema to Python Property Bridges Here ... -*- atapi.registerType(Video, PROJECTNAME) The first line in our class body specifies that it implements IVideo interface (interfaces/video.py file). then VideoSchema is associated with the class. ATFieldProperty is required to create ATSchema to Python Property bridges. These are recommended for fields of a schema using AnnotationStorage. If you still have title and description fields storage as AnnotationStorage, you should keep these lines. Otherwise you can safely remove them. And finally, the atapi.registerType() call adds all getters and setters to the Video class. This is Archetypes' magic. You define just a schema and Archetypes will automatically create all methods needed to interact with the class. There's more… We do have some more interesting code now, that's why we should be more careful with it and test it. Again, paster has appended several functional tests in the README.txt file, including the creation (as Manager and Contributor users), modification, and deletion of a Video object. Test the product with the following command: ./bin/instance test -s pox.video We'd like to highlight the block of statements regarding the creation of content as a contributor member: Let's logout and then login as 'contributor', a portal member that has the contributor role assigned. >>> browser.getLink('Log out').click() >>> browser.open(portal_url) >>> browser.getControl(name='__ac_name').value = 'contributor' >>> browser.getControl(name='__ac_password').value = default_password >>> browser.getControl(name='submit').click() This contributor member isn't mentioned anywhere inside the test. Nevertheless the login action doesn't fail. How can that be possible if there's no contributor member included by default in the PloneTestCase base class, like default_user or portal_owner? If we check the base.py file inside the tests sub-package of our product, we'll see that the FunctionalTestCase class has a special afterSetUp method, which is called just before the real test begins and registers the contributor member above. Could we have created the user inside the test? Definitely, because test code is a set of Python statements and we can do whatever we want with them. Is it sensible to perform this kind of set up actions inside the test code? Absolutely not. functional tests should be conceived as black-box tests, from the sheer end-user point of view. This means that code inside a functional test shouldn't assume anything about the underlying environment, but behave as if a regular user were acting through the user interface. Anything we need during testing that shouldn’t be done by the user must be placed outside the test code, as in this example. See also Creating an Archetypes product with paster Working with paster generated test suites Zope Functional testing Using the ZCA to extend a third party product: Collage Changing the base class in paster content types All paster-created (non-folderish) content types inherit from the basic ATCTContent class, which comes with ATContentTypeSchema. However, this is a very basic content type: title, description, and some more metadata fields. On top of this, we intend to upload videos to our website, not just text. ATContentTypes are native to Plone and many community developers had released extensions or plugins for them, such as LinguaPlone. That's why it is prudent to stay close to them. We are now going to change the ATCTContent parent class for ATFile to automatically inherit all the benefits, including the file upload field. How to do it… Open the video.py file inside the content sub-package of your product and make these changes. Be aware of commented lines — they can be just removed, but we wanted to keep them here to remark what's going on. Import the base class and interface to be used: from Products.Archetypes import atapi # from Products.ATContentTypes.content import base from Products.ATContentTypes.content import file from Products.ATContentTypes.interface.file import IATFile from Products.ATContentTypes.content import schemata This way we are importing interface and class of the out-of-the-box File content type. Change original schema: # VideoSchema = schemata.ATContentTypeSchema.copy() + # atapi.Schema(( VideoSchema = file.ATFileSchema.copy() + atapi.Schema(( # -*- Your Archetypes field definitions here ... -*- )) Now, our VideoSchema includes File fields. Change the base class and implemented interface: # class Video(base.ATCTContent): class Video(file.ATFile): """ pox Video """ # implements(IVideo) implements(IATFile,IVideo The last step is to change the parent class of Video so that now it inherits from ATFile instead of just ATCTContent. And then we adjust the interfaces this class now implements. Change the view action URL: Open profiles/default/types/Video.xml file and amend the url_expr attribute in View action by adding /view. <?xml version="1.0"?> <object name="Video" meta_type="Factory-based Type Information with dynamic views" i18n_domain="pox.video" action_id="view" category= "object" condition_expr="" url_expr="string:${object_url}/view" visible="True"> <permission value="View" /> </action> ... </object> Tell Plone to use the new action URL in listings: Add a propertiestool.xml file inside the profiles/default folder with this code: <?xml version="1.0"?> <object name="portal_properties" meta_type= "Plone Properties Tool"> <object name="site_properties" meta_type="Plone Property Sheet"> <property name="typesUseViewActionInListings" type= "lines" purge="False"> <element value="Video"/> </property> </object> </object> Relaunch your instance and reinstall the product. By restarting the Zope instance all of the latest changes will be applied: ./bin/instance fg Go to http://localhost:8080/plone/prefs_install_products_form and reinstall the product. Create a new Video object:Inside your Plone site, click on the Add new... drop-down menu and select the Video option. It should look like this. How it works… Since the first creation of the almost empty product (full of boilerplate, though), in Creating an Archetypes product with paster, we haven't tried to use it, except for the tests we have run. We can now say that it has grown up and it's ready to be seen in action. In Steps 1 to 3 above, we changed some of the basics in paster's original class and its schema to inherit all the benefits of another existing content type: ATFile. If you had tried to create a Video content type before Step 4, after saving, you would have been automatically prompted to download the file you just uploaded. Why's that? The reason is we inherited our class from ATFile, which has a special behavior (like ATImage) regarding its URLs. Files and images uploaded to a Plone site (using regular content types) are downloadable via their natural URL. For example, if you browse to http://yoursite.com/document.pdf, you will be asked to download the file. Alternatively, if you want to open the web page with a download link and metadata, you should use http://yoursite.com/document.pdf/view. That's why we had to change the view URL for our content type in Video.xml (Step 4) for users to be able to open an inline video player (as we plan to). All files included in the profiles folder are used by GenericSetup during installation of the product and are to give some information that Python code doesn't provide, such as whether we'll let users post comments inside the content types (allow_discussion). Plone object listings (including search results) tend to create links to contents without the /view suffix. We must explicitly tell Plone that when listing videos, the suffix should be appended to prevent a download attempt. Fortunately, Plone has foreseen this could have happened. Thus there's no need to modify or override every single list. If the content type name is listed in the special typesUseViewActionInListings property, it will work as expected. Plone object listings (including search results) tend to create links to contents without the /view suffix. We must explicitly tell Plone that when listing videos, the suffix should be appended to prevent a download attempt. Fortunately, Plone has foreseen this could have happened. Thus there's no need to modify or override every single list. If the content type name is listed in the special typesUseViewActionInListings property, it will work as expected. Changes in Step 5 will make the site_properties update its typesUseViewActionInListings property. By including purge="False" in <property /> tag, we prevent other existing values (typically File and Image) in the property from being removed.
Read more
  • 0
  • 0
  • 1515
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 $15.99/month. Cancel anytime
article-image-django-12-e-commerce-generating-pdf-reports-python-using-reportlab
Packt
19 May 2010
6 min read
Save for later

Django 1.2 E-commerce: Generating PDF Reports from Python using ReportLab

Packt
19 May 2010
6 min read
(Read more interesting articles on Django 1.2 e-commerce here.) ReportLab is an open source project available at http://www.reportlab.org. It is a very mature tool and includes binaries for several platforms as well as source code. It also contains extension code written in C, so it's relatively fast. It is possible for ReportLab to insert PNG and GIF image files into PDF output, but in order to do so we must have the Python Imaging Library (PIL) installed. We will not require this functionality in this article, but if you need it for a future project, see the PIL documentation for setup instructions. The starting point in the ReportLab API is drawing to canvas objects. Canvas objects are exactly what they sound like: blank slates that are accessible using various drawing commands that paint graphics, images, and words. This is sometimes referred to as a low-level drawing interface because generating output is often tedious. If we were creating anything beyond basic reporting output, we would likely want to build our own framework or set of routines on top of these low-level drawing functions. Drawing to a canvas object is a lot like working with the old LOGO programming language. It has a cursor that we can move around and draw points from one position to another. Mostly, these drawing functions work with two-dimensional (x, y) coordinates to specify starting and ending positions. This two-dimensional coordinate system in ReportLab is different from the typical system used in many graphics applications. It is the standard Cartesian plane, whose origin (x and y coordinates both equal to 0) begins in the lower-left hand corner instead of the typical upper-right hand corner. This coordinate system is used in most mathematics courses, but computer graphics tools, including HTML and CSS layouts, typically use a different coordinate system, where the origin is in the upper-left. ReportLab's low-level interface also includes functions to render text to a canvas. This includes support for different fonts and colors. The text routines we will see, however, may surprise you with their relative crudeness. For example, word-wrapping and other typesetting operations are not automatically implemented. ReportLab includes a more advanced set of routines called PLATYPUS, which can handle page layout and typography. Most low-level drawing tools do not include this functionality by default (hence the name "low-level"). This low-level drawing interface is called pdfgen and is located in the reportlab.pdfgen module. The ReportLab User's Guide includes extensive information about its use and a separate API reference is also available. The ReportLab canvas object is designed to work directly on files. We can create a new canvas from an existing open file object or by simply passing in a file name. The canvas constructor takes as its first argument the filename or an open file object. For example: from reportlab.pdfgen import canvasc = canvas.Canvas("myreport.pdf") Once we obtained a canvas object, we can access the drawing routines as methods on the instance. To draw some text, we can call the drawString method: c.drawString(250, 250, "Ecommerce in Django") This command moves the cursor to coordinates (250, 250) and draws the string "Ecommerce in Django". In addition to drawing strings, the canvas object includes methods to create rectangles, lines, circles, and other shapes. Because PDF was originally designed for printed output, consideration needs to be made for page size. Page size refers to the size of the PDF document if it were to be output to paper. By default, ReportLab uses the A4 standard, but it supports most popular page sizes, including letter, the typical size used in the US. Various page sizes are defined in reportlab.lib.pagesizes. To change this setting for our canvas object, we pass in the pagesize keyword argument to the canvas constructor. from reportlab.lib.pagesizes import letterc = canvas.Canvas('myreport.pdf', pagesize=letter) Because the units passed to our drawing functions, like rect, will vary according to what page size we're using, we can use ReportLab's units module to precisely control the output of our drawing methods. Units are stored in reportlab.lib.units. We can use the inch unit to draw shapes of a specific size: from reportlab.lib.units import inchc.rect(1*inch, 1*inch, 0.5*inch, 1*inch) The above code fragment draws a rectangle, starting one inch from the bottom and one inch from the left of the page, with sides that are length 0.5 inches and one inch, as shown in the following screenshot: Not particularly impressive is it? As you can see, using the low-level library routines require a lot of work to generate very little results. Using these routines directly is tedious. They are certainly useful and required for some tasks. They can also act as building blocks for your own, more sophisticated routines. Building our own library of routines would still be a lot of work. Fortunately ReportLab includes a built-in high-level interface for creating sophisticated report documents quickly. These routines are called PLATYPUS; we mentioned them earlier when talking about typesetting text, but they can do much more. PLATYPUS is an acronym for "Page Layout and Typography Using Scripts". The PLATYPUS code is located in the reportlab.platypus module. It allows us to create some very sophisticated documents suitable for reporting systems in an e-commerce application. Using PLATYPUS means we don't have to worry about things such as page margins, font sizes, and word-wrapping. The bulk of this heavy lifting is taken care of by the high-level routines. We can, if we wish, access the low-level canvas routines. Instead we can build a document from a template object, defining and adding the elements (such as paragraphs, tables, spacers, and images) to the document container. The following example generates a PDF report listing all the products in our Product inventory: from reportlab.platypus.doctemplate import SimpleDocTemplatefrom reportlab.platypus import Paragraph, Spacerfrom reportlab.lib import sytlesdoc = SimpleDocTemplate("products.pdf")Catalog = []header = Paragraph("Product Inventory", styles['Heading1']) Catalog.append(header)style = styles['Normal']for product in Product.objects.all(): for product in Product.objects.all(): p = Paragraph("%s" % product.name, style) Catalog.append(p) s = Spacer(1, 0.25*inch) Catalog.append(s)doc.build(Catalog) The previous code generates a PDF file called products.pdf that contains a header and a list of our product inventory. The output is displayed in the accompanying screenshot.
Read more
  • 0
  • 0
  • 4290

article-image-using-flowplayer-plone-3
Packt
19 May 2010
5 min read
Save for later

Using Flowplayer in Plone 3

Packt
19 May 2010
5 min read
This article is the third and the final section of this article series. The following articles are the initial parts of the series. Managing Audio Content in Plone 3.3 Audio Enhancements with p4a.ploneaudio in Plone 3.3 (For more resources on Plone, see here.) Including audio into HTML Generally, we have two options to include a sound file on a HTML page: Streaming Non streaming Another option is to simply include a link to the file like this: <a href="example.mp3" type="audio/x-mpeg" title="MP3 audiofile , ... kB">example.mp3 </a> This is the standard way Plone includes files into the visual editor. The advantage of this approach is that virtually everyone is able to access the file in some way. What happens with the file after it has been downloaded depends on the client browser and how it is configured. The shortcoming of this method is that we depend on an external player to listen to the audio. Probably one needs to download the file and start the player manually. Including audio with plugin elements Another option to spread an audio file is to use the embed element or the object element. The former looks like this: <embed src="example.mp3"> The embed element was introduced by Netscape in browser version 2.0. However, it has not yet made it into the HTML standard, and probably will never do so. An alternative element to the Netscape variant is the object element that was introduced by Microsoft. Including an example.mp3 file located in the data folder looks like this: <object type="audio/x-mpeg" data="data/example.mp3" width="200" height="20"> <param name="src" value="data/example.mp3"> <param name="autoplay" value="false"> <param name="autoStart" value="0"> alt : <a href="data/example.mp3">example.mp3</a> </object> Including audio with the embed or the object element assumes that there is a plugin installed on the client side that can play the multimedia format. In most cases, we can't tell what the client is equipped with and want a more robust solution. The third way to include audio into your site is Flash. We still need a plugin on the client side, but Flash is more widespread than audio player plugins. There are a couple of free audio players written in Flash. An older but easy-to-use Flash player is EMFF. A custom view with an embedded audio player What we do now is to write a custom view for the audio-enhanced File content type of Plone. We reuse the mm.enhance product we created in the previous article and add the additional code there. We utilize the p4a.audio.interfaces.IAudioEnhanced interface to register our view on. Let's do so: <browser:page for="p4a.audio.interfaces.IAudioEnhanced" name="my-audioplayer-view" class=".browser.AudioPlayerView" permission="zope2.View" template="player.pt" /> <browser:resourceDirectory directory="thirdparty/emff" name="emff" /> The page is named my-audioplayer-view and has the AudioPlayerView view class in the browser module. Further, we register a thirdparty/emff directory where we can put the Flash resources of the Flash player. Next, we need to create this view class and add the player.pt template. We fill the template with the HTML code we get from the EMFF code generator: Using the EMFF code generator Choose the first option URL to MP3, though it doesn't really matter what you write into the text field. The value is overridden with the name we retrieve from our context object. For the HTML version, you can either choose HTML or XHTML as Plone 3 doesn't output valid XHTML itself. Nevertheless, XHTML might still be the better option, as it is future proof. Selecting XHTML closes the param elements inside of the object element. We can copy this literally into our Zope page template. <object type="application/x-shockwave-flash" data="emff_lila_info.swf" width="200" height="55"> <param name="movie" value="emff_lila_info.swf" /> <param name="bgcolor" value="#00ff00" /> <param name="FlashVars" value="src=example.mp3&amp;autostart=yes" /> </object> The Plone template is a standard one using the main_template. We copy the generated code from the bottom of the codegenerator window and put into the main slot of the template. There are just two changes we make. One is the location of the Flash file, which is registered as a resource, and the other is the audio file itself, which is our context. <html xml_lang="en" lang="en" i18n:domain="p4a.audio" metal:use-macro="context/main_template/macros/master"> <body> <div metal:fill-slot="main"> <object type="application/x-shockwave-flash" data=" ++resource++emff/emff_lila_info.swf" width="200" height="55"> <param name="movie" value="emff_lila_info.swf" /> <param name="bgcolor" value="#ffffff" /> <param name="FlashVars" value="src=example.mp3&amp;autostart=yes" tal:attributes="value string_src=${context/getId}&amp; autostart=yes" /> </object> </div> </body> </html> Next, we download the necessary Flash code from its website. The player is provided as a ZIP package with all sources and stuff included. We need to copy the chosen skin file to the thirdparty/emff directory of our mm.enhance product. In our example we used the emff_lila_info skin.
Read more
  • 0
  • 0
  • 1254

article-image-django-12-e-commerce-data-integration
Packt
19 May 2010
7 min read
Save for later

Django 1.2 E-commerce: Data Integration

Packt
19 May 2010
7 min read
(Read more interesting articles on Django 1.2 e-commerce here.) We will be using a variety of tools, many builtin to Django. These are all relatively stable and mature, but as with all open source technology, new versions could change their usage at any time. Exposing data and APIs One of the biggest elements of the web applications developed in the last decade has been the adoption of so-called Web 2.0 features. These come in a variety of flavors, but one thing that has been persistent amongst them all is a data-centric view of the world. Modern web applications work with data, usually stored in a database, in ways that are more modular and flexible than ever before. As a result, many web-based companies are choosing to share parts of their data with the world in hopes of generating "buzz", or so that interested developers might create a clever "mash-up" (a combination of third-party application software with data exposed via an API or other source). These mash-ups take a variety of forms. Some simply allow external data to be integrated or imported into a desktop or web-based application. For example, loading Amazon's vast product catalog into a niche website on movie reviews. Others actually deploy software written in web-based languages into their own application. This software is usually provided by the service that is exposing their data in the form of a code library or web-accessible API. Larger web services that want to provide users with programmatic access to their data will produce code libraries written in one or more of the popular web-development languages. Increasingly, this includes Python, though not always, and typically also includes PHP, Java, or Perl. Often when an official data library exists in another language, an enterprising developer has ported the code to Python. Increasingly, however, full-on code libraries are eschewed in favor of open, standards-based, web-accessible APIs. These came into existence on the Web in the form of remote procedure call tools. These mapped functions in a local application written in a programming language that supports XML-RPC to functions on a server that exposed a specific, well-documented interface. XML and network transport protocols were used "under the hood" to make the connection and "call" the function. Other similar technologies also achieved a lot of use. For example, many web-services provide Simple Object Access Protocol (SOAP) interface, which is the successor to XML-RPC and built on a very similar foundation. Other standards, sometimes with proprietary implementations, also exist, but many new web-services are now building APIs using REST-style architecture. REST stands for Representational State Transfer and is a lightweight and open technique for transmitting data across the Web in both server-to-server and client-to-server situations. It has become extremely popular in the Web 2.0 and open source world due to its ease of use and its reliance on standard web protocols such as HTTP, though it is not limited to any one particular protocol. A full discussion of REST web services is beyond the scope of this article. Despite their simplicity, there can arise many complicated technical details. Our implementation in this article will focus on a very straightforward, yet powerful design. REST focuses on defining our data as a resource that when used with HTTP can map to a URL. Access to data in this scheme is simply a matter of specifying a URL and, if supported, any look-up, filter, or other operational parameters. A fully featured REST web service that uses the HTTP protocol will attempt to define as many operations as possible using the basic HTTP access methods. These include the usual GET and POST methods, but also PUT and DELETE, which can be used for replacement, updating, or deletion of resources. There is no standard implementation of a REST-based web service and as such the design and use can vary widely from application to application. Still, REST is lightweight enough and relies on a well known set of basic architectures that a developer can learn a new REST-based web service in a very short period of time. This gives it a degree of advantage over competing SOAP or XML-RPC web services. Of course, there are many people who would dispute this claim. For our purposes, however, REST will work very well and we will begin by implementing a REST-based view of our data using Django. Writing our own REST service in Django would be very straightforward, partly because URL mapping schemes are very easy to design in the urls.py file. A very quick and dirty data API could be created using the following super-simple URL patterns: (r'^api/(?P<obj_model>w*)/$', 'project.views.api')(r'^api/(?P<obj_model>w*)/(?P<id>d*)/$', 'project.views.api') And this view: from django.core import serializersdef api(request, obj_model, obj_id=None): model = get_model(obj_model.split(".")) if model is None: raise Http404 if obj_id is not None: results = model.objects.get(id=obj_id) else: results = model.objects.all()json_data = serializers.serialize('json', results)return HttpResponse(json_data, mimetype='application/json')) This approach as it is written above is not recommended, but it shows an example of one of the simplest possible data APIs. The API view returns the full set of model objects requested in JSON form. JSON is a simple, lightweight data format that resembles JavaScript syntax. It is quickly becoming the preferred method of data transfer for web applications. To request a list of all products, for example, we only need to access the following URL path on our site: /api/products.Product/. This uses Django's app.model syntax to refer to the model we want to retrieve. The view uses get_model to obtain a reference to the Product model and then we can work with it as needed. A specific model can be retrieved by including an object ID in the URL path: /api/products.Product/123/ would retrieve the Product whose ID is 123. After obtaining the results data, it must be encoded to JSON format. Django provides serializers for several data formats, including JSON. These are all located in the django.code.serializers module. In our case, we simply pass the results QuerySet to the serialize function, which returns our JSON data. We can limit the fields to be serialized by including a field's keyword argument in the call to serialize: json_data = serializers.serialize('json', results, fields=('name','price')) We can also use the built-in serializers to generate XML. We could modify the above view to include a format flag to allow the generation of JSON or XML: def api(request, obj_model, obj_id=None, format='json'): model = get_model(*obj_model.split()) If model is None: raise Http404 if obj_id is not None: results = model.objects.get(id=obj_id) else: results = model.objects.all()serialized_data = serializers.serialize(format, results)return HttpResponse(serialized_data, mimetype='application/' + format) Format could be passed directly on the URL or better yet, we could define two distinct URL patterns and use Django's keyword dictionary: (r'^api/(?P<obj_model>w*)/$', 'project.views.api'),(r'^api/(?P<obj_model>w*)/xml/$', 'project.views.api',{'format': 'xml'}),(r'^api/(?P<obj_model>w*)/yaml/$', 'project.views.api',{'format': 'yaml'}),(r'^api/(?P<obj_model>w*)/python/$', 'project.views.api',{'format': 'python'}), By default our serializer will generate JSON data, but we've got to provide alternative API URLs that support XML, YAML, and Python formats. These are the four built-in formats supported by Django's serializers module. Note that Django's support for YAML as a serialization format requires installation of the third-party PyYAML module. Building our own API is in some ways both easy and difficult. Clearly we have a good start with the above code, but there are many problems. For example, this is exposing all of our Django model information to the world, including our User objects. This is why we do not recommend this approach. The views could be password protected or require a login (which would make programmatic access from code more difficult) or we could look for another solution.
Read more
  • 0
  • 0
  • 3275

article-image-audio-enhancements-p4aploneaudio-plone-33
Packt
17 May 2010
14 min read
Save for later

Audio Enhancements with p4a.ploneaudio in Plone 3.3

Packt
17 May 2010
14 min read
(For more resources on Plone, see here.) Audio enhancements with p4a.ploneaudio One of the most advanced products to boost the audio features of Plone is p4a.ploneaudio. Like its image sister p4a.ploneimage it doesn't bring a content type on its own, but expands existing ones. As you might have guessed already, the File content type and the folderish ones (Folder, Large Folder, and Collection) are chosen for the enhancement. To install it, add the following code to the buildout of our instance: [buildout]...[instance]...eggs =${buildout:eggs}Plonep4a.ploneaudiozcml =p4a.ploneaudio After running the buildout and restarting the instance, we need to install the product as an add-on product. We find it with the product name Plone4Artists Audio (p4a.ploneaudio). Enhancing files Installing the p4a.ploneaudio product enables the enhancement of the File content type of ATContentTypes. Unlike with the image enhancement, not all files are automatically enhanced with additional audio features. p4a.ploneaudio comes with a MIME type filter. If we upload a file with one of the meta types such as audio/MPEG or application/Ogg, the file will automatically be audio enhanced. All other files (such as ZIP files, EXE files, and so on) stay untouched. Technically speaking, this works via a named adapter. The first thing we see is the modified default view for audio-enhanced files: On the right side we see some technical information about the audio file itself. We find the size, the format (MP3 or Ogg), the bitrate, the frequency, and the length of the track there. As with any other content type, we have the title and the description at the top of the content area. For the audio-enhanced content, the description has changed from a simple text field to a rich text field. We find four buttons after the usual CMS bar (the belowcontenttitle slot) containing the author and the modification date of the file. Each of these buttons retrieves the audio file in a different way: Button Action Description     Play An embedded audio player written in Flash. Clicking on it starts playback immediately.     Pop up Opens a pop-up window with a Flash player playing the audio track. This is useful if someone wants to play the track while continuing to browse the site.     Stream Clicking on the button returns an M3U playlist with the URL of the file. The browser/operating system needs to take care of the handling of the stream. If you have a Mac, the file will be streamed to iTunes.     Download This is the standard behavior of Plone’s File content-type. The file is returned to the client like any other file object. It can be saved or opened with the favorite media player of the operating system.   We find a long list of additional information on the audio track below the player and streaming buttons. This information is the metadata stored with the audio file and is gathered during the enhancing process. It can be changed and written back to the file. Let's take a closer look on the enhancement process. One important step here is marking the content object with two interfaces: One is p4a.subtyper.interfaces.ISubtyped. This interface marks the content as subtyped. The other interface is p4a.audio.interfaces.IAudioEnhanced. This interface describes the type of enhancement, which is audio content in this case. All other views and components available with the enhanced version bind to the p4a.audio.interfaces.IAudioEnhanced interface. Additionally, p4a.ploneaudio tries to extract as much of the metadata information from the file as possible. The title is retrieved from the metadata and changed. Let's see what happens when a file is added in detail: It is possible to write custom audio enhancers if needed. The enhancers are queried as named adapters by the MIME type on the IAudioDataAccessor interface. Enhancing containers With p4a.ploneaudio, we can turn any Plone folder into an audio-enhanced folder by choosing Audio container from the Subtype menu. Two marker interfaces are attached to the container: p4a.subtyper.interfaces.ISubtyped p4a.audio.interfaces.IAudioContainerEnhanced The default view of the container is changed utilizing the IAudioContainerEnhanced interface. The new default view is audio-container.html, which comes with the p4a.ploneaudio product. In the View option we see one box for each track. For each track, the title and the cover artwork is shown. There is also an embedded Flash player to play each track directly. There are some other container views that come with the product as follows: audio-album.html (album view) audiocd-popup.html (pop-up view) cd_playlist.xspf And the default edit view for IAudioContainerEnhaced-marked folders is overridden. The audio-album.html view presents the audio content of the container in a slightly different way. The single tracks are arranged in a table. Two variants of this view are exposed in the Display menu of the container—Album view and Album view with no track numbers. Both these views are more compact than the default audio container view and have the same layout, except that the second one omits the column with the track numbers. As for the other audio container views, there is a player for each track. Moreover, there are two buttons on the top of the page. One is the commonly used RSS icon and the other one is the familiar pop-up player button . By clicking on the RSS icon, we get to the stream (or podcast of the folder). This may not be too interesting for a standard static Folder, but can be for a Collection where the content changes more dynamically. The pop-up player for a folder looks and operates slightly differently as the file standalone variant. It contains all tracks that are part of the audio container as a playlist. Lastly, there is the cd_playlist.xspf view. This view is not exposed via a display or as an action. It provides the audio data as a XSPF stream. The XML Shareable Playlist Format: XSPF The XML Shareable Playlist Format (XSPF) is an XML file format for storing playlists of digital audio. The audio can be located locally or online. Last.fm uses XSPF for providing its playlists. An example playlist looks like this: <?xml version="1.0" encoding="UTF-8"?><playlist version="1" ><trackList><track><location>example.mp3</location><creator>Tom</creator><album>Thriller</album><annotation>A comment</annotation></track><track><location>another.mp3</location><creator>Tom</creator></track></trackList></playlist> There is a list of applications supporting the XSPF format on the XSPF (http://xspf.org/) website. The default XSPF view of p4a.ploneaudio does not include all possible information. It provides the following attributes: location: This is the required location (URL) of the song. image: The album artwork that may be included with each track. annotation: p4a.ploneaudio collects information about the title, artist, album, and year in this field. It is easy to write a custom implementation of an XSPF view. Look at the available fields at the XSPF home page and the XSPF implementation of p4a.audio. We find the template named cd_playlist.xspf.pt in the p4a.audio.browser module. p4a.ploneaudio and the Plone catalog Besides the customized default views and the additional views, p4a.ploneaudio comes with a number of other changes. One very important change is the disclosure of some audio metadata fields to the portal catalog. This allows us to use them in catalog queries in general and smart folders in particular. The following indexes are added: Artist Genre Track Format The Artist attribute is exposed as metadata information in the catalog. Also, the genre and the artist name are added to the full text index SearchableText. The values for the genre field are hardcoded. The ID3 tag genre list is used together with the Winamp extensions. They are stored as a vocabulary. The term titles are resolved for Searchable Text, but not for the index and the Collection field. Accessing audio metadata in Collections To access catalog information in collections, it needs to be exposed to the collections tool. This can either be done by a product or TTW in the Plone configuration panel. p4a.ploneaudio comes with a modification of the fields: Artist (Artist name) Genre (Genre) Format (MIME Types) Let's say we want a collection of all our MP3 files. All we have to do is add a MIME Types criterion to our collection and set audio/mpeg as the value: ATAudio migration If you have an older Plone site (2.5), you probably have ATAudio installed to deal with audio content.ATAudio has features similar to p4a.ploneaudio. This is not surprising as p4a.ploneaudio was derived from ATAudio. The main difference is that ATAudio provides a content type, while p4a.ploneaudio reuses an existing one. If you want to switch from ATAudio to p4a.ploneaudio for one or the other reason, p4a.ploneaudio comes with a migration routine. One reason for switching might be that ATAudio is not actively developed any more and probably doesn't work with recent versions of Plone. For migrating, you need to call migrate-ataudioconfiglet.html and follow the instructions there. The migration view is available only if ATAudio is installed. There is a little bit of a catch-22 situation because p4a.ploneaudio doesn't run on Plone 2.5 and ATAudio doesn't run on Plone 3. This means there is no good starting point for the migration. At least, there is a version of ATAudio that does install in Plone 3 in the collective repository: http://svn.plone.org/svn/collective/ATAudio/tags/0.7- plone3migration/. Extracting metadata with AudioDataAccessors The IAudioDataAccessor interface is used for extracting metadata from binary audio content. If uploading a file, Plone tries to acquire a named adapter for the interface with the MIME type as the key. It has the following layout: class IAudioDataAccessor(interface.Interface):"""Audio implementation accessor (ie MP3, ogg, etc)."""audio_type = schema.TextLine(title=_(u'Audio Type'),required=True,readonly=True)def load(filename):"""Load from filename"""def store(filename):"""Store to filename""" The audio_type field contains a human-readable description of the audio type. In the case of MP3, the Unicode string "MPEG-1 Audio Layer 3" is used. The load and store methods are used for reading/writing the metadata from/to the audio file. The definition for the MP3 adapter looks like this: <adapterfor="p4a.audio.interfaces.IPossibleAudio"factory="._audiodata.MP3AudioDataAccessor"provides="p4a.audio.interfaces.IAudioDataAccessor"name="audio/mpeg"/> The component is registered for the p4a.audio.interfaces.IPossibleAudio interface. All classes marked with this interface are capable of getting converted to an audio-enhanced object. The standard product marks the File content type with this interface. The adapter provides the p4a.audio.interfaces.IAudioDataAccessor interface, which is the marker for the lookup. The name attribute of adapter is the key for the lookup and needs to be set to the MIME type of the audio file that should be processed. Now, the factory does the actual work of loading and storing the metadata from the audio file. p4a.ploneaudio and FLAC For the moment, p4a.ploneaudio only supports MP3 and Ogg Vorbis. This is a reasonable choice. Both formats are streamable and were made for good audio quality with small file sizes. We want to add FLAC support. We use mutagen for metadata extraction. Mutagen is an audio metadata extractor written in Python. It is capable of reading and writing many audio metadata formats including: FLAC M4A Monkey's Audio MP3 Musepack Ogg Vorbis True Audio WavPack OptimFROG Let's remember the flow chart of the audio adding process. We recall that we need a metadata extractor for our FLAC MIME type. First, we need to register a named adapter for this purpose. This is very similar to the MP3 adapter we saw before: <adapterfor="p4a.audio.interfaces.IPossibleAudio"factory=".flac._audiodata.FlacAudioDataAccessor"provides="p4a.audio.interfaces.IAudioDataAccessor"name="application/x-flac"/> The adapter is used for objects implementing the p4a.audio.interfaces.IPossibleAudio interface. The factory does the work of extracting the metadata. The adapter provides the p4a.audio.interfaces.IAudioDataAccessor interface. This is what the adapter is made for and the name is application/x-flac, which is the MIME type of FLAC audio files. Next, we define the metadata accessor: from mutagen.flac import Open as openaudio...from p4a.audio.ogg._audiodata import _safe First, we need some third-party imports. For the metadata extraction, we use the FLAC accessor of the mutagen library. _safe is a helper method. It returns the first element if the given parameter is a list or a tuple, or the element itself. class FlacAudioDataAccessor(object):"""An AudioDataAccessor for FLAC"""implements(IAudioDataAccessor)def __init__(self, context):self._filecontent = context The first lines are the boilerplate part. The adapter class implements the interface the adapter provides. In the constructor, we get the context of the adapter and save it in the _filecontent variable of the instance. @propertydef audio_type(self):return 'FLAC'@propertydef _audio(self):return IAudio(self._filecontent)@propertydef _audio_data(self):annotations = IAnnotations(self._filecontent)return annotations.get(self._audio.ANNO_KEY, None) The audio_type property is just for information purposes and required by the interface. It is displayed in the audio view. The _audio property is a shortcut for accessing the IAudio adapter for the context. The audio_data property is a shortcut for accessing the metadata annotated to the context. def load(self, filename):flacfile = openaudio(filename)self._audio_data['title'] = _safe(flacfile.get('title', ''))self._audio_data['artist'] = _safe(flacfile.get('artist', ''))self._audio_data['album'] = _safe(flacfile.get('album', ''))self._audio_data['year'] = _safe(flacfile.get('date', ''))self._audio_data['idtrack'] = _safe(flacfile.get('tracknumber', ''))self._audio_data['genre'] = _safe(flacfile.get('genre', ''))self._audio_data['comment'] = _safe(flacfile.get('description', ''))self._audio_data['bit_rate'] = long(flacfile.info.bits_per_sample)self._audio_data['length'] = long(flacfile.info.length)self._audio_data['frequency'] = long(flacfile.info.sample_rate) The load method is required by the IAudioDataAccessor interface. It fetches the metadata using the mutagen method from the audio file and stores it as an annotation on the context. def store(self, filename):flacfile = openaudio(filename)flacfile['title'] = self._audio.title or u''flacfile['artist'] = self._audio.artist or u''flacfile['album'] = self._audio.album or u''flacfile['date'] = self._audio.year or u''flacfile['tracknumber'] = self._audio.idtrack or u''flacfile.save() The store method is required by the IAudioDataAccessor interface as well and its purpose is to write the metadata from the context annotation back to the audio file. We have covered the following in this article series: Manipulation of audio content stored as File content in Plone The different formats used for the binary storage of audio data Storing and accessing MP3 audio metadata with the ID3 tag format Managing metadata, formats, and playlists with p4a.ploneaudio in Plone Including a custom embedded audio player in Plone Using the Flowplayer product to include an audio player standalone in rich text and as a portlet >> Continue Reading: Using Flowplayer in Plone 3. Further resources on this subject: Plone 3 Multimedia [book] Using Flowplayer in Plone 3 [article] Audio Enhancements with p4a.ploneaudio in Plone 3.3 [article] Red5: A video-on-demand Flash Server [article]   Plone 3.3 Products Development Cookbook [book] Creating a custom type with paster in plone 3 [article] Improving Plone 3 Product Performance [article]   Plone 3 for Education [book] Calendaring with Plone 3 for Education [article] Showcasing Personnel with Faculty/Staff Directory using Plone 3 [article] Plone 3 Themes [article] Blogs and forums using Plone 3 [article]   Plone 3 Theming [book] Creating, Installing and Tweaking your theme using Plone 3 [article] Skinner's Toolkit for Plone 3 Theming (Part 1) [article] Skinner's Toolkit for Plone 3 Theming (Part 2) [article] Add-on Tools and Theming Tips for Plone 3 [article]   Practical Plone 3: A Beginner's Guide to Building Powerful Websites [book] Find and Install Add-Ons that Expand Plone Functionality [article] Structure the Content on your Plone Site [article] Safely manage different vesions of content with plone [article] Creating New Types of Plone Portlets [article] Show Additional Information to Users and Visitors of Your Plone Site [article]
Read more
  • 0
  • 0
  • 1178
article-image-managing-audio-content-plone-33
Packt
17 May 2010
10 min read
Save for later

Managing Audio Content in Plone 3.3

Packt
17 May 2010
10 min read
(For more resources on Plone, see here.) There are at least four use cases when we think of integrating audio in a web application: We want to provide an audio database with static files for download. We have audio that we want to have streamed to the Internet (for example, as a podcast). We want a audio file/live show streamed to the Internet as an Internet radio service. We want some sound to be played when the site is loaded or shown. In this article series, we will discuss three of the four cases. The streaming support is limited to use case 2. We can stream to one client like a podcast does, but not to many clients at once like an Internet Radio does. We need special software such as Icecast or SHOUTcast for this purpose. Further, we will investigate how we solve use cases 1, 2, and 3 with the Plone CMS and extensions. Technically, these are the topics covered in this article series: Manipulation of audio content stored as File content in Plone The different formats used for the binary storage of audio data Storing and accessing MP3 audio metadata with the ID3 tag format Managing metadata, formats, and playlists with p4a.ploneaudio in Plone Including a custom embedded audio player in Plone Using the Flowplayer product to include an audio player standalone in rich text and as a portlet Previewing the audio element of HTML5 Extracting metadata from a FLAC file using mutagen   Uploading audio files with an unmodified Plone installation The out of the box support of Plone for audio content is limited. What is possible to do is to upload an audio file utilizing the File content type of Plone to the ZODB. A File is nothing more and nothing less than a simple binary file. Plone does not make any difference between a MP3 file and a ZIP, an EXE, or an RPM binary file. When adding File content to Plone, we need to upload a file (of course!). We don't necessarily need to specify a title, as the filename is used if the title is omitted. The filename is always taken for the short name (ID) of the object. This limits the number of files with any specific name to one in a container While uploading a file, Plone tries to recognize the MIME type and the size of the file. This is the smallest subset of information shared by all binary files the content type File was intended for. Normally, detecting the MIME type for standard audio is not a problem if the file extension is correctly set. Clicking on the link in the default view either downloads the file or opens it with the favorite player of your operating system. This behavior depends on the settings made on the target browser and corresponds with the method 1 of our audio use cases. It goes without saying that we can add the default metadata to files and organize them in folders. Like Images, File objects do not have a workflow associated in a default Plone setup. They inherit the read and write permissions from the container they are placed into. Still, we can add an existing workflow to this content type or create a new one via the portal_workflow tool if we want. That's pretty much it. Fortunately, we can utilize some extensions to enhance the Plone audio story greatly. What we will see in this article is as follows: First, we will go over some theoretical ground. We will see what formats are available for storing audio content and which is best for which purpose. Later we will investigate the Plone4Artists extension for Plone's File content type—p4a.ploneaudio. We will talk about metadata especially used for audio content and how to manipulate it. As a concrete example, we will use mutagen to extract metadata from a FLAC file to add FLAC support to p4a.ploneaudio. Finally, we will have a word on streaming audio data through the Web and see how to embed a Flash player into our Plone site. We will see how we can do this programmatically and also with the help of a third-party product called collective.flowplayer. At the very end of the article, we have a small technical preview on HTML5 where a dedicated audio element is available. This element allows us to embed audio directly into our HTML page without the detour with Flash. Accessing audio content in Plone Once we upload a file we want to work with to Plone, we will link it with other content and display it in one way or another. There are several ways of accessing audio data in Plone. It can be accessed in the visual editor by editors, in templates by integrators and in Python code by developers. Kupu access Unlike for images, there is no special option in the visual editor to embed file/audio content into a page. The only way to access an audio file with Kupu is to use an internal link. The file displays as a normal link and is executed when clicked. Executed means (as for the standalone file) saved or opened with the music player of your operating system as is done in the standard view of the File content type. Of course, it is possible to reference external audio files as well. Page template access As there is no special access method in Kupu, there is none in page templates. If we need to access a file there, we can use the absolute_url method of the audio content object. This computes a link we can refer to. So the only way to access a file from another context is to refer to its URL. <a tal_attributes="href audiocontext/absolute_url"tal:content="audiocontext/Title">audio</a> Python script access If we need to access the content of an (audio) file in a Python script, we can get the binary data with the Archetype accessor getFile. >>> binary = context.getFile() This method returns the data wrapped into a Zope OFS.File object. To access the raw data as a string, we need to do the following: >>> rawdata = str(binary.data) Accessing the raw data of an audio file might be useful if we want to do format transformations on the fly or other direct manipulation of the data. Field access If we write our own content type and want to save audio data with an object, we need a file field. This field stores the binary data and takes care of communicating with the browser with adequate view and edit widgets. The file field is defined in the Field module of the Archetype product. Additional to the properties, it exclusively defines that it inherits from the ObjectField base class. The following properties are important. Key Default value type 'file' default ' ' primary False widget FileWidget content_class File default_content_type 'application/octet-stream'   The type property provides a unique name for the field. We usually don't need to change this. The default property defines the default value for this field. It is normally empty. If we want to change it, we need to specify an instance of the content_class property. One field of the schema can be marked as primary. This field can be retrieved by the getPrimaryField accessor. When accessing the content object with FTP, the content of the primary field is transmitted to the client. Like every other field, the file field needs a widget. The standard FileWidget is defined in the Widget module of the Archetypes product. The content_class property declares the instance, where the actual binary data is stored. As standard, the File class from Zope's OFS.Image module is used. This class supports chunk-wise transmission of the data with the publisher. Field can be accessed like any other field by its accessor method. This method is either defined as a property of the field or constructed from its name. If the name were "audio", the accessor would be getAudio. The accessor is generated from the "get" prefix with the capitalized name of the field. Audio formats Before we go on with Plone and see how we can enhance the story of audio processing and manipulate audio data, we will glance at audio formats. We will see how raw audio data is compressed to enable effective audio storage and streaming. We need to have some basic audio know-how about some of the terminology to understand how we can effectively process audio for our own purposes. As with images, there are several formats in which audio content can be stored. We want to learn a bit of theoretical background. This eases the decision of choosing the right format for our use case. An analog acoustic signal can be displayed as a wave: If digitalized, the wave gets approximated by small rectangles below the curve. The more rectangles are used the better is the sound (fidelity) of the digital variant. The width of the rectangles is called the sampling rate. Usual sampling rates include: 44.1 kHz (44,100 samples per second): CD quality 32 kHz: Speech 14.5 kHz: FM radio bandwidth 10 kHz: AM radio Each sample is stored with a fixed number of bits. This value is called the audio bit depth or bit resolution. Finally, there is a third value that we already know from the analog side. It is the channel. We have one channel for mono and two channels for stereo. For the digital variant, this means a doubling of data if stereo is used. So let's do a calculation. Let's assume we have an audio podcast with a length of eight minutes, which we want to stream in stereo CD quality. The sampling rate corresponds with the highest frequency of sound that is stored. For accurate reproduction of the original sound, the sample rate has to be at least twice that ofthe highest frequency sound. Most humans cannot hear frequencies higher than 20 kHz. The corresponding sampling rate to 20 kHz is a sampling rate of 44100 samples. We want to use a bit resolution of 16. This is the standard bit depth for audio CDs. Lastly, we have two channels for stereo: 44100 x 16 x 2 x 60 x 8= 677376000 bits = 84672000 bytes ˜ 80.7 MB This is quite a lot of data for eight minutes of CD-quality sound. We do not want to store so much data and more importantly, we do not want to send so much data over the Internet. So what we do is compress the data. Zipping the data would not give us a big effect because of the binary structure of digital audio data. There are different types of compressions for different types of data. ZIPs are good for text, JPEG is good for images, and MP3 is good for music—but why? Each of these algorithms takes the nature of the data into account. ZIP looks for redundant characters, JPEG unifies similar color areas, and MP3 strips the frequencies humans do not hear from the raw data.
Read more
  • 0
  • 0
  • 1201

article-image-customizing-your-vim-work-area
Packt
14 May 2010
12 min read
Save for later

Customizing Your Vim for work area

Packt
14 May 2010
12 min read
(Read more interesting articles on Hacking Vim 7.2 here.) Work area personalization In this article, we introduce a list of smaller, good-to-know modifications for the editor area in Vim. The idea with these recipes is that they all give you some sort of help or optimization when you use Vim for editing text or code. Adding a more visual cursor Sometimes, you have a lot of syntax coloring in the file you are editing. This can make the task of tracking the cursor really hard. If you could just mark the line the cursor is currently in, then it would be easier to track it. Many have tried to fix this with Vim scripts, but the results have been near useless (mainly due to slowness, which prevented scrolling longer texts at an acceptable speed). Not until version 7 did Vim have a solution for this. But then it came up with not just one, but two possible solutions for cursor tracking. The first one is the cursorline command , which basically marks the entire line with, for example, another background color without breaking the syntax coloring. To turn it on, use the following command: :set cursorline The color it uses is the one defined in the CursorLine color group. You can change this to any color or styling you like, for example: :highlight CursorLine guibg=lightblue ctermbg=lightgray If you are working with a lot of aligned file content (such as tab-separated data), the next solution for cursor tracking comes in handy: :set cursorcolumn This command marks the current column (here the cursor is placed) by coloring the entire column through the entire file, for example. As with the cursor line, you can change the settings for how the cursor column should be marked. The color group to change is named cursorcolumn. Adding both the cursor line and column marking makes the cursor look like a crosshair, thus making it impossible to miss. Even though the cursorline and cursorcolumn functionalities are implemented natively in Vim, it can still give quite a slowdown when scrolling through the file. Adding line numbers Often when compiling and debugging code, you will get error messages stating that the error is in some line. One could, of course, start counting lines from the top to find the line, but Vim has a solution to go directly to some line number. Just execute :XXX where XXX is the line number, and you will be taken to the XXX line. Alternatively, you can go into normal mode (press the Esc key) and then simply use XXXgg or XXXG (again XXX is the line number). Sometimes, however, it is nice to have an indication of the line number right there in the editor, and that's where the following command comes in handy: :set number Now, you get line numbers to the left of each line in the file. By default, the numbers take up four columns of space, three for numbers, and one for spacing. This meansthat the width of the numbers will be the same until you have more than 999 lines. If you get above this number of lines, an extra column will be added and the content will be moved to the right. Of course, you can change the default number of columns used for the line numbers. This can be achieved by changing the following property: :set numberwidth=XXX Replace XXX with the number of columns that you want. Even though it would be nice to make the number of columns higher in order to get more spacing between code and line numbers, this is not achievable with the numberwidth property. This is because the line numbers will be right-aligned within the columns. In the following figure, you can see how line numbers are shown as right-aligne when a higher number of columns are set in numberwidth: You can change the styling of the line numbers and the columns they are in by making changes to the LineNr color group. Spell checking your language We all know it! Even if we are really good spellers, it still happens from time to time that we misspell a word or hit the wrong keys. In the past, you had to run your texts (that you had written in Vim) through some sort of spell checker such as Aspell or Ispell . This was a tiresome process that could only be performed as a final task, unless you wanted to do it over and over again. With version 7 of Vim, this troublesome way of spell checking is over. Now, Vim has got a built-in spell checker with support for more than 50 languages from around the world. The new spell checker marks the wrongly written words as you type them in, so you know right away that there is an error. The command to execute to turn on this helpful spell checker feature is: :set spell This turns on the spell checker with the default language (English). If you don't use English much and would prefer to use another language in the spell checker, then there is no problem changing this. Just add the code of the language you would like to use to the spelllang property . For example: :set spelllang=de Here, the language is set to German (Deutsch) as the spell checker language of choice. The language name can be written in several different formats. American English, for example, can be written as: en_us us American Names can even be an industry-related name such as medical. If Vim does not recognize the language name, Vim will highlight it when you execute the property-setting command. If you change the spelllang setting to a language not already installed, then Vim will ask you if it should try to automatically retrieve it from the Vim homepage. Personally, I tend to work in several different languages in Vim, and I really don't want to tell Vim all the time which language I am using right now. Vim has a solution for this. By appending more language codes to the spelllang property (separated by commas), you can tell Vim to check the spelling in more than one language. :set spelllang=en,da,de,it Vim will then take the languages from the start to the end, and check if the words match any word in one of these languages. If they do, then they are not marked as a spelling error. Of course, this means that you can have a word spelled wrong in the language you are using but spelled correctly in another language, thereby introducing a hidden spelling error. You can find language packages for a lot of languages at the Vim FTP site: ftp://ftp.vim.org/pub/vim/runtime/spell. Spelling errors are marked differently in Vim and Gvim. In regular Vim, the misspelled word is marked with the SpellBad color group (normally, white on red). In Gvim, the misspelled word is marked with a red curvy line underneath the word. This can, of course, be changed by changing the settings of the color group. Whenever you encounter a misspelled word, you can ask Vim to suggest better ways to spell the word. This is simply done by placing the cursor over the word, going into the normal mode (press Esc), and then pressing Z + =. If possible, Vim will give you a list of good guesses for the word you were actually trying to write. In front of each suggestion is a number. Press the number you find in front of the right spelling (of the word you wanted) or press Enter if the word is not there. Often Vim gives you a long list of alternatives for your misspelled word, but unless you have spelled the word completely wrong, chances are that the correct word is within the top five of the alternatives. If this is the case, and you don't want to look through the entire list of alternatives, then you can limit the output with the following command: :set spellsuggest=X Set X to the number of alternative ways of spelling you want Vim to suggest. Adding helpful tool tips In the Modifying tabs recipe, we learned about how to use tool tips to store more information using less space in the tabs in Gvim. To build on top of that same idea with this recipe, we move on and use tool tips in other places in the editor. The editing area is the largest part of Vim. So, why not try to add some extra information to the contents of this area by using tool tips? In Vim, tool tips for the editing area are called balloons and they are only shown when the cursor is hovering over one of the characters. The commands you will need to know in order to use the balloons are: The first command is the one you will use to actually turn on this functionality in Vim. :set ballooneval The second command tells Vim how long it should wait before showing the tool tip/balloon (the delay is in milliseconds and as a default is set to 600). :set balloondelay=400 The last command is the one that actually sets the string that Vim will show in the balloon. :set ballonexpr="textstring" This can either be a static text string or the return of some function. In order to have access to information about the place where you are hovering over a character in the editor, Vim provides access to a list of variables holding such information: abc<space>and abc<enter> Both expand 123abc<space> Will not expand as the abbreviation is part of a word abcd<space> Will not expand because there are letters after the abbreviation abc Will not expand until another special letter is pressed So with these variables in hand, let's look at some examples. Example 1: The first example is based on one from the Vim help system. It shows how to make a simple function that will show the information from all the available variables. function! SimpleBalloon() return 'Cursor is at line/column: ' . v:beval_lnum . '/' . v:beval_col . ' in file ' . bufname(v:beval_bufnr) . '. Word under cursor is: "' . v:beval_text . '"' endfunction set balloonexpr=SimpleBalloon() set balloonevalcode 59 The result will look similar to the following screenshot: Example 2: Let's look at a more advanced example that explores the use of balloons for specific areas in editing. In this example, we will put together a function that gives us great information balloons for two areas at the same time: Misspelled words: The balloon gives ideas for alternative words Folded text: The balloon gives a preview of what's in the fold So, let's take a look at what the function should look for, to detect if the cursor is hovering over either a misspelled word or a fold line (a single line representing multiple lines folded behind it). In order to detect if a word is misspelled, the spell check would need to be turned on: :set spell If it is on, then calling the built-in spell checker function—spellsuggest()—would return alternative words if the hovered word was misspelled. So, to see if a word is misspelled, just check if the spellsuggest() returns anything. There is, however, a small catch. spellsuggest() also returns alternative, similar words if the word is not misspelled. To get around this, another function has to be used on the input word before putting it into the spellsuggest() function . This extra function is the spellbadword(). This basically moves the cursor to the first misspelled word in the sentence that it gets as input, and then returns the word. We just input a single word and if it is not misspelled, then the function cannot return any words. Putting no word into spellsuggest() results in getting nothing back, so we can now check if a word is misspelled or not. It is even simpler to check if a word is in a line, in a fold. You simply have to call the foldclosed()function on the line number of the line over which the cursor is hovering (remember v:beval_lnum ?), and it will return the number of the first line in the current fold; if not in a fold, then it returns -1. In other words, if foldclosed(v:beval_lnum) returns anything but -1 and 0, we are in a fold. Putting all of this detection together and adding functionality to construct the balloon text ends up as the following function: function! FoldSpellBalloon() let foldStart = foldclosed(v:beval_lnum ) let foldEnd = foldclosedend(v:beval_lnum) let lines = [] " Detect if we are in a fold if foldStart < 0 " Detect if we are on a misspelled word let lines = spellsuggest( spellbadword(v:beval_text)[ 0 ], 5, 0 ) else " we are in a fold let numLines = foldEnd - foldStart + 1 " if we have too many lines in fold, show only the first 14 " and the last 14 lines if ( numLines > 31 ) let lines = getline( foldStart, foldStart + 14 ) let lines += [ '-- Snipped ' . ( numLines - 30 ) . ' lines --' ] let lines += getline( foldEnd - 14, foldEnd ) else "less than 30 lines, lets show all of them let lines = getline( foldStart, foldEnd ) endif endif " return result return join( lines, has( "balloon_multiline" ) ? "n" : " " ) endfunction set balloonexpr=FoldSpellBalloon() set ballooneval The result is some really helpful balloons in the editing area of Vim that can improve your work cycle tremendously. The following screenshot shows how the information balloon could look when it is used to preview a folded range of lines from a file: Instead, if the balloon is used on a misspelled word, it will look like the following screenshot: In Production Boosters, you can learn more about how to use folding of lines to boost productivity in Vim.
Read more
  • 0
  • 0
  • 3016

article-image-personalizing-vim
Packt
14 May 2010
12 min read
Save for later

Personalizing Vim

Packt
14 May 2010
12 min read
(Read more interesting articles on Hacking Vim 7.2 here.) Some of these tasks contain more than one recipe because there are different aspects for personalizing Vim for that particular task. It is you, the reader, who decides which recipes (or parts of it) you would like to read and use. Before we start working with Vim, there are some things that you need to know about your Vim installation, such as where to find the configuration files. Where are the configuration files? When working with Vim, you need to know a range of different configuration files. The location of these files is dependent on where you have installed Vim and the operating system that you are using. In general, there are three configuration files that you must know where to find: vimrc gvimrc exrc The vimrc file is the main configuration file for Vim. It exists in two versions—global and personal. The global vimrc file is placed in the folder where all of your Vim system files are installed. You can find out the location of this folder by opening Vim and executing the following command in normal mode: :echo $VIM The examples could be: Linux: /usr/share/vim/vimrc Windows: c:program filesvimvimrc The personal vimrc file is placed in your home directory. The location of the home directory is dependent on your operating system. Vim was originally meant for Unixes, so the personal vimrc file is set to be hidden by adding a dot as the first character in the filename. This normally hides files on Unix, but not on Microsoft Windows. Instead, the vimrc file is prepended with an underscore on these systems. So, examples would be: Linux: /home/kim/.vimrc Windows: c:documents and settingskim_vimrc Whatever you change in the personal vimrc file will overrule any previous setting made in the global vimrc file. This way you can modify the entire configuration without having to ever have access to the global vimrc file. You can find out what Vim considers as the home directory on your system by executing the following command in normal mode: :echo $HOME Another way of finding out exactly which vimrc file you use as your personal file is by executing the following command in the normal mode: :echo $MYVIMRC The vimrc file contains ex (vi predecessor) commands, one on each line, and is the default place to add modifications to the Vim setup. In the rest of the article, this file is just called vimrc. Your vimrc can use other files as an external source for configurations. In the vimrc file, you use the source command like this: source /path/to/external/file Use this to keep the vimrc file clean, and your settings more structured. (Learn more about how to keep your vimrc clean in Appendix B, Vim Configuration Alternatives). The gvimrc file is a configuration file specifically for Gvim. It resembles the vimrc file previously described, and is placed in the same location as a personal version as well as a global version. For example: Linux: /home/kim/.gvimrc and /usr/share/vim/gvimrc Windows: c:documents and settingskim_gvimrc and c:program filesvimgvimrc This file is used for GUI-specific settings that only Gvim will be able to use. In the rest of the article, this file is called gvimrc. The gvimrc file does not replace the vimrc file, but is simply used for configurationsthat only apply to the GUI version of Vim. In other words, there is no need to haveyour configurations duplicated in both the vimrc file and the gvimrc file. The exrc file is a configuration file that is only used for backwards compatibility with the old vi / ex editor. It is placed at the same location (both global and local) as vimrc, and is used the same way. However, it is hardly used anymore except if you want to use Vim in a vi-compatible mode. Changing the fonts In regular Vim, there is not much to do when it comes to changing the font because the font follows one of the terminals. In Gvim, however, you are given the ability to change the font as much as you like. The main command for changing the font in Linux is: :set guifont=Courier 14 Here, Courier can be exchanged with the name of any font that you have, and 14 with any font size you like (size in points—pt). For changing the font in Windows, use the following command: :set guifont=Courier:14 If you are not sure about whether a particular font is available on the computer or not, you can add another font at the end of the command by adding a comma between the two fonts. For example: :set guifont=Courier New 12, Arial 10 If the font name contains a whitespace or a comma, you will need to escape it with a backslash. For example: :set guifont=Courier New 12 This command sets the font to Courier New size 12, but only for this session. If you want to have this font every time you edit a file, the same command has to be added to your gvimrc file (without the : in front of set). In Gvim on Windows, Linux (using GTK+), Mac OS, or Photon, you can get a font selection window shown if you use this command: :set guifont=*. If you tend to use a lot of different fonts depending on what you are currently working with (code, text, logfiles, and so on.), you can set up Vim to use the correct font according to the file type. For example, if you want to set the font to Arial size 12 every time a normal text file (.txt) is opened, this can be achieved by adding the following line to your vimrc file: autocmd BufEnter *.txt set guifont=Arial 12 The window of Gvim will resize itself every time the font is changed. This means, if you use a smaller font, you will also (as a default) have a smaller window. You will notice this right away if you add several different file type commands like the one previously mentioned, and then open some files of different types. Whenever you switch to a buffer with another file type, the font will change, and hence the window size too. You can find more information about changing fonts in the Vim help system under Help | guifont. Changing color scheme Often, when working in a console environment, you only have a black background and white text in the foreground. This is, however, both dull and dark to look at. Some colors would be desirable. As a default, you have the same colors in the console Vim as in the console you opened it from. However, Vim has given its users the opportunity to change the colors it uses. This is mostly done with a color scheme file. These files are usually placed in a directory called colors wherever you have installed Vim. You can easily change the installed color schemes with the command: :colorscheme mycolors Here, mycolors is the name of one of the installed color schemes. If you don't know the names of the installed color schemes, you can place the cursor after writing: :colorscheme Now, you can browse through the names by pressing the Tab key. When you find the color scheme you want, you can press the Enter key to apply it. The color scheme not only applies to the foreground and background color, but also to the way code is highlighted, how errors are marked, and other visual markings in the text. You will find that some color schemes are very alike and only minor things have changed. The reason for this is that the color schemes are user supplied. If some user did not like one of the color settings in a scheme, he or she could just change that single setting and re-release the color scheme under a different name. Play around with the different color schemes and find the one you like. Now, test it in the situations where you would normally use it and see if you still like all the color settings. While learning Basic Vim Scripting, we will get back to how you can change a color scheme to fit your needs perfectly. Personal highlighting In Vim, the feature of highlighting things is called matching. With matching, you can make Vim mark almost any combination of letters, words, numbers, sentences, and lines. You can even select how it should be marked (errors in red, important words in green, and so on). Matching is done with the following command: :match Group /pattern/ The command has two arguments. The first one is the name of the color group that you will use in the highlight. Compared to a color scheme, which affects the entire color setup, a color group is a rather small combination of background (or foreground) colors that you can use for things such as matches. When Vim is started, a wide range of color groups are set to default colors, depending on the color scheme you have selected. To see a complete list of color groups, use the command: :so $VIMRUNTIME/syntax/hitest.vim. The second argument is the actual pattern you want to match. This pattern is a regular expression and can vary from being very simple to extremely complex, depending on what you want to match. A simple example of the match command in use would be: :match ErrorMsg /^Error/ This command looks for the word Error (marked with a ^) at the beginning of all lines. If a match is found, it will be marked with the colors in the ErrorMsg color group (typically white text on red background). If you don't like any of the available color groups, you can always define your own. The command to do this is as follows: :highlight MyGroup ctermbg=red guibg=red gctermfg=yellowguifg=yellow term=bold This command creates a color group called MyGroup with a red background and yellow text, in both the console (Vim) and the GUI (Gvim). You can change the following options according to your preferences: ctermb Background color in console guibg Background color in Gvim ctermf Text color in console guifg Text color in Gvim gui Font formatting in Gvim term Font formatting in console (for example, bold) If you use the name of an existing color group, you will alter that group for the rest of the session. When using the match command, the given pattern will be matched until you perform a new match or execute the following command: :match NONE The match command can only match one pattern at a time, so Vim has provided you with two extra commands to match up to three patterns at a time. The commands are easy to remember because their names resemble those of the match command: :2match:3match You might wonder what all this matching is good for, as it can often seem quite useless. Here are a few examples to show the strength of matching. Example 1: Mark color characters after a certain column In mails, it is a common rule that you do not write lines more than 74 characters (a rule that also applies to some older programming languages such as, Fortran-77). In a case like this, it would be nice if Vim could warn you when you reached this specific number of characters. This can simply be done with the following command: :match ErrorMsg /%>73v.+/ Here, every character after the 73rd character will be marked as an error. This match is a regular expression that when broken down consists of: %> Match after column with the number right after this 73 The column number V Tells that it should work on virtual columns only .+ Match one or more of any character Example 2: Mark tabs not used for indentation in code When coding, it is generally a good rule of thumb to use tabs only to indent code, and not anywhere else. However, for some it can be hard to obey this rule. Now, with the help of a simple match command, this can easily be prevented. The following command will mark any tabs that are not at the beginning of the line (indentation) as an error: :match errorMsg /[^t]zst+/ Now, you can check if you have forgotten the rule and used the Tab key inside the code. Broken down, the match consists of the following parts: [^ Begin a group of characters that should not be matched t The tab character ] End of the character group zs A zero-width match that places the 'matching' at the beginning of the line ignoring any whitespaces t+ One or more tabs in a row This command says: Don't match all the tab characters; match only the ones that are not used at the beginning of the line (ignoring any whitespaces around it). If instead of using tabs you want to use the space character for indentation, you can change the command to: :match errorMsg /[t]/ This command just says: Match all the tab characters. Example 3: Preventing errors caused by IP addresses If you write a lot of IP addresses in your text, sometimes you tend to enter a wrong value in one (such as 123.123.123.256). To prevent this kind of an error, you can add the following match to your vimrc file: match errorMsg /(2[5][6-9]|2[6-9][0-9]|[3-9][0-9][0-9])[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}|[0-9]{1,3}[.](2[5][6-9]|2[6-9][0-9]| [3-9][0-9][0-9])[.][0-9]{1,3}[.][0-9]{1,3}|[0-9]{1,3}[.][0-9]{1,3}[.](2[5] [6-9]|2[6-9][0-9]|[3-9][0-9][0-9])[.][0-9]{1,3}|[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.](2[5][6-9]|2[6-9][0-9]|[3-9][0-9][0-9])/ Even though this seems a bit too complex for solving a small possible error, you have to remember that even if it helps you just once, it is worth adding. If you want to match valid IP addresses, you can use this, which is a much simpler command: match todo /((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).) {3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/
Read more
  • 0
  • 0
  • 5425
article-image-creating-customizing-and-assigning-portlets-automatically-plone-33
Packt
12 May 2010
5 min read
Save for later

Creating, Customizing, and Assigning Portlets Automatically for Plone 3.3

Packt
12 May 2010
5 min read
(For more resources on Plone, see here.) Introduction One of the major changes from Plone 2.5 to Plone 3.0 was the complete refactoring of its portlets engine. In Plone 2.5, left and right side portlets were managed from Zope Management Interface (ZMI) by setting two special properties: left_slots and right_slots. This was not so hard but was cumbersome. Any TALES path expression—ZPT macros typically—could be manually inserted in the above two properties and would be displayed as a bit of HTML to the final user. The major drawback for site managers with the old-style approach was not just the uncomfortable way of setting which portlets to display, but the lack of any configuration options for them. For example, if we wanted to present the latest published news items, we wouldn't have any means of telling how many of them to show, unless the portlet itself were intelligent enough to get that value from some other contextual property. But again, we were still stuck in the ZMI. Fortunately, this has changed enormously in Plone 3.x: Portlets can now be configured and their settings are mantained in ZODB. Portlets are now managed via a user-friendly, Plone-like interface. Just click on the Manage portlets link below each of the portlets columns (see the following screenshot). In the above screen, if we click on the News portlet link, we are presented with a special configuration form to choose the Number of items to display and the Workflow state(s) we want to consider when showing news items. If you have read previous chapters, you might be correctly guessing that Zope 3 components (zope.formlib mainly) are behind the portlets configuration forms. In the next sections, we'll look again at the customer's requirements: Advertisement banners will be located in several areas of every page Advertisement banners may vary according to the section of the website Creating a portlet package Once again, paster comes to the rescue. As in Creating a product package structure and Creating an Archetypes product with paster, we will use the paster command here to create all the necessary boilerplate (and even more) to get a fully working portlet. Getting ready As we are still at the development stage, we should run the following commands in our buildout's src folder: cd ./src How to do it... Run the paster command: We are going to create a new egg called pox.portlet.banner. The pox prefix is from PloneOpenX (the website we are working on) and it will be the namespace of our product. Portlets eggs usually have a nested portlet namespace as in plone.portlet.collection or plone.portlet.static. We have chosen the pox main namespace as in the previous eggs we have created, and the banner suffix corresponds to the portlet name. For more information about eggs and packages names read http://www.martinaspeli.net/articles/the-naming-ofthings-package-names-and-namespaces.If you want to add portlets to an existing package instead of creating a new one, the steps covered in this chapter should tell you all you need to know (the use of paster addcontent portlet local command will be of great help). In your src folder, run the following command: paster create -t plone3_portlet This paster command creates a product using the plone3_portlet template. When run, it will output some informative text, and then a short wizard will be started to select options for the package: Option Value Enter project name pox.portlet.banner Expert Mode? easy Version 1.0 Description Portlet to show banners Portlet Name Banner portlet Portlet Type BannerPortlet After selecting the last option, you'll get an output like this (a little longer actually): Creating directory ./pox.portlet.banner ... Recursing into +namespace_package+ Recursing into +namespace_package2+ Recursing into +package+ Recursing into profiles Creating ./pox.portlet.banner/pox/portlet/banner/profiles/ Recursing into default Creating ./pox.portlet.banner/pox/portlet/banner/profiles/default/ Copying metadata.xml_tmpl to ./pox.portlet.banner/pox/portlet/banner/profiles/default/metadata.xml Copying portlets.xml_tmpl to ./pox.portlet.banner/pox/portlet/banner/profiles/default/portlets.xml This tells us that even the GenericSetup extension profile has also been created by paster. This means that we can install the new Banner portlet product (as entered in the portlet_name option above). Install the product: To tell our Zope instance about the new product, we must update the buildout.cfg file as follows: [buildout]...eggs =... pox.portlet.banner...develop = src/pox.portlet.banner We can automatically install the product during buildout. Add a pox.portlet.banner line inside the products parameter of the [plonesite] part: [plonesite]recipe = collective.recipe.plonesite...products =... pox.portlet.banner Build your instance and, if you want to, launch it to see the new empty Banner portlet: ./bin/buildout./bin/instance fg Check the new portlet: After implementing the changes above, if you click on the Manage portlets link in the site's home page (or anywhere in the Plone site), you will see a new Banner portlet option in the drop-down menu. A new box in the portlet column will then be shown. The Header/Body text/Footer box shown above matches the template definition in the bannerportlet.pt file the way paster created it.
Read more
  • 0
  • 0
  • 1691

article-image-vim-72-formatting-code
Packt
30 Apr 2010
11 min read
Save for later

Vim 7.2 Formatting Code

Packt
30 Apr 2010
11 min read
Formatting code often depends on many different things. Each programming language has its own syntax, and some languages rely on formatting like indentation more than others. In some cases, the programmer is following style guidelines given by an employer so that code can follow the company-wide style. So, how should Vim know how you want your code to be formatted? The short answer is that it shouldn't! But by being flexible, Vim can let you set up exactly how you want your formatting done. However, the fact is that even though formatting differs, most styles of formatting follow the same basic rules. This means that in reality, you only have to change the things that differ. In most cases, the changes can be handled by changing a range of settings in Vim. Among these, there are a few especially worth mentioning: Formatoptions: This setting holds formatting-specific settings (see :help 'fo') Comments: What are comments and how they should be formatted (see :help 'co') (no)expandtab: Convert tabs to spaces (see :help 'expandtab') Softtabstop: How many spaces a single tab is converted to (see :help 'sts') Tabstop: How many spaces a tab looks like (see :help 'ts') With these options, you can set nearly every aspect of how Vim will indent your code, and whether it should use spaces or tabs for indentation. But this is not enough because you still have to tell Vim if it should actually try to do the indentation for you, or if you want to do it manually. It you want Vim to do the indentation for you, you have the choice between four different ways for Vim to do it. In the following sections, we will look at the options you can set to interact with the way Vim indents code. Autoindent Autoindent is the simplest way of getting Vim to indent your code. It simply stays at the same indentation level as the previous line. So, if the current line is indented with four spaces, then the new line you add by pressing Enter will automatically be indented with four spaces too. It is then up to you as to how and when the indentation level needs to change again. This type of indentation is particularly good for languages where the indentation stays the same for several lines in a row. You get autoindent by using :set, autoindent, or :set ai. Smartindent Smartindent is the next step when you want a smarter indent than autoindent. It still gives you the indentation from the previous line, but you don't have to change the indentation level yourself. Smartindent recognizes the most common structures from the C programming language and uses this as a marker for when to add / remove the indentation levels. As many languages are loosely based on the same syntax as C, this will work for those languages as well. You get smart indent by using any of the following commands: :set smartindent :set si Cindent Cindent is often called clever indent or configurable indent because it is more configurable than the previous two indentation methods. You have access to three different setup options: cinkeys This option contains a comma-separated list of keys that Vim should use to change the indentation level. An example could be: :set cinkeys="0{,0},0#,:", which means that it should reindent whenever it hits a {, a } or a # as the first character on the line, or if you use : as the last character on the line (as used in switch constructs in many languages).The default value for cinkeys is "0{, 0}, 0), :, 0#, !^F, o, O, and e". See :help cinkeys for more information on what else you can set in this option. cinoptions This option contains all the special options you can set specifically for cindent. A large range of options can be set in this comma-separated list. An example could be:set cinoptions=">2,{3,}3", which means that we want Vim to add two extra spaces to the normal indent length, and we want to place { and } three spaces as compared to the previous line. So, if we have a normal indent to be four spaces, then the previous example could result in the code looking like this (dot marks represent a space): if( a == b) ...{ ......print "hello"; ...} The default value for cinoptions is this quite long string: ">s,e0,n0,f0,{0,}0,^0,:s,=s,l0,b0,gs,hs,ps,ts,is,+s,c3,C0,/0,(2s,us,U0,w0,W0,m0,j0,)20,*30" . See :help 'cinoptions' for more information on all the options. cinwords This option contains all the special keywords that will make Vim add indentation on the next line. An example could be: :set cinwords="if,else,do,while,for,switch", which is also the default value for this option. See :help 'cinwords' for more information. Indentexpr Indentexpr is the most flexible indent option to use, but also the most complex. When used, indentexpr evaluates an expression to compute the indent of a line. Hence, you have to write an expression that Vim can evaluate. You can activate this option by simply setting it to a specific expression such as: :set indentexpr=MyIndenter() Here, MyIndenter() is a function that computes the indentation for the lines it is executed on. A very simple example could be a function that emulates the autoindent option: function! MyIndenter() " Find previous line and get its indentation let prev_lineno = s:prevnonblank(v:lnum) let ind = indent( prev_lineno ) return indendfunction Adding just a bit more functionality than this, the complexity increases quite fast. Vim comes with a lot of different indent expressions for many programming languages. These can serve as inspiration if you want to write your own indent expression. You can find them in the indent folder in your VIMHOME. You can read more about how to use indentexpr in :help 'indentexpr' and :help 'indent-expression'. Fast code-block formatting After you have configured your code formatting, you might want to update your code to follow these settings. To do so, you simply have to tell Vim that it should reindent every single line in the file from the first line to the last. This can be done with the following Vim command: 1G=G If we split it up, it simply says: 1G: Go to the first line of the file (alternatively you can use gg) =: Equalize lines; in other words, indent according to formatting configuration G: Go to the last line in the file (tells Vim where to end indenting) You could easily map this command to a key in order to make it easily accessible: :nmap <F11> 1G=G:imap <F11> <ESC>1G=Ga The last a is to get back into the insert mode as this was where we originally were. So, now you can just press the F11key in order to reindent the entire buffer correctly. Note that if you have a programmatic error, for example, missing a semicolon at the end of a line in a C program, the file will not be correctly indented from that point on in the buffer. This can sometimes be useful to identify where a scope is not closed correctly (for example, a { not closed with a } ). Sometimes, you might just want to format smaller blocks of code. In those cases, you typically have two options—use the natural scope blocks in the code, or select a block of code in the visual mode and indent it. The last one is simple. Go into the visual mode with, for example,Shift+v and then press = to reindent the lines. When it comes to using code blocks on the other hand, there are several different ways to do it. In Vim, there are multiple ways to select a block of code. So in order to combine a command that indents a code block, we need to look at the different types and the commands to select them: i{ Inner block, which means everything between { and } excluding the brackets. This can also be selected with i} and iB. a{ A block, which means all the code between { and } including the brackets. This can also be selected with a} and aB. i( Inner parenthesis, meaning everything between ( and ) excluding the parentheses. Can also be selected with i) and ib. a( A parentheses, meaning everything between ( and ) including the parenthesis. Can also be selected with a) and ab. i< Inner < > block, meaning everything between < and > excluding the brackets. Can also be selected with i>. a< A < > block, meaning everything between < and > including the brackets. Can also be selected with a>. i[ Inner [ ] block, meaning everything between [ and ] excluding the square brackets. Can also be selected with i]. a[ A [ ] block, meaning everything between [ and ], including the square brackets. This can also be selected with a]. So, we have defined what Vim sees a block of code as; now, we simply have to tell it what to do with the block. In our case, we want to reindent the code. We already know that = can do this. So, an example of a code block reindentation could look like this: =i{ Let's execute the code block reindentation in the following code (| being the place where the cursor is): if( a == b ) { print |"a equals b"; } This would produce the following code (with default C format settings): if( a == b ) { print |"a equals b"; } If, on the other hand, we choose to use a { as the block we are working on, then the resulting code would look like this: if( a == b ) { print "a equals b"; } As you can see in the last piece of code, the =a{ command corrects the indentation of both the brackets and the print line. In some cases where you work in a code block with multiple levels of code blocks, you might want to reindent the current block and maybe the surrounding one. No worries, Vim has a fast way to do this. If, for instance, you want to reindent the current code block and besides that want to reindent the block that surrounds it, you simply have to execute the following command while the cursor is placed in the innermost block: =2i{ This simply tells Vim that you will equalize / reindent two levels of inner blocks counting from the "active" block and out. You can replace the number 2 with any number of levels of code blocks you want to reindent. Of course, you can also swap the inner block command with any of the other block commands, and that way select exactly what you want to reindent. So, this is really all it takes to get your code to indent according to the setup you have. Auto format pasted code The trend among programmers tells us that we tend to reuse parts of our code, or so-called patterns. This could mean that you have to do a lot of copying and pasting of code. Most users of Vim have experienced what is often referred to as the stair effect when pasting code into a file. This effect occurs when Vim tries to indent the code as it inserts it. This often results in each new line to be indented to another level, and you ending up with a stair: code line 1 code line 2 codeline 3 code line 4 ... The normal workaround for this is to go into the paste-mode in Vim, which is done by using: :set paste After pasting your code, you can now go back to your normal insert mode again: :set nopaste But what if there was another workaround? What if Vim could automatically indent the pasted code such that it is indented according to the rest of the code in the file? Vim can do that for you with a simple paste command. p=`] This command simply combines the normal paste command (p) with a command that indents the previously inserted lines (=`]). It actually relies on the fact that when you paste with p (lowercase), the cursor stays on the first character of the pasted text. This is combined with `], which takes you to the last character of the latest inserted text and gives you a motion across the pasted text from the first line to the last. So, all you have to do now is map this command to a key and then use this key whenever you paste a piece of code into your file. Using external formatting tools Even though experienced Vim users often say that Vim can do everything, this is of course not the truth—but is close. For those things that Vim can't do, it is smart enough to be able to use external tools. In the following sections, we will take a look at some of the most used external tools that can be used for formatting your code, and how to use them.
Read more
  • 0
  • 0
  • 7160