Jul/0923
Zend Framework: The Dijit Editor
Introduction
In one of my current projects, AircraftConnection.com, I decided to use the dijit.Editor WYSIWYG editor in my user’s forms. I ran into a few problems and could not find much documentation on the topic.
- I wanted the label, description, and field in a different order.
- I wanted the data entered into the editor to actually be passed to the server when the form was submitted.
- I wanted to pre-populate the form with data the user had previously entered.
I was able to find a few posts related to posting the data to the server via a hidden field but these mostly did so via Ajax, which is fine. It just didn’t suit my needs. I adopted and manipulated their methods to work in the way I wanted.
Prerequisites
- A web server with PHP installed
- The Zend Framework
- Dojo and Dijit Javascript libraries
In this post I make the assumption that you already have the above installed as well as your ZF project created with the Javascript libraries included.
Getting Started
The application we are going to build will be very simple. We will have a single controller, IndexController, with two actions, indexAction and editAction. We will use the editAction to edit the content that is displayed in the index action. The editAction is where we will display the form with the dijit.Editor.
So, in reality, the only work we are going to do will be in the IndexController::editAction() method. This will handle displaying the form as well as processing the data posted to the server.
Creating the Form Elements
The first thing in my list was that I wanted to display the label, description, and field in a different order. The default is label, field, description, which really doesn’t make all that much sense. So, the first thing we need to do is create our own Element class and extend the dijit.Editor class. We need to override the loadDefaultDecorators() method.
Editor.php
class Blog_Element_Editor extends Zend_Dojo_Form_Element_Editor { public function loadDefaultDecorators() { if($this->loadDefaultDecoratorsIsDisabled()) { return; } $decorators = $this->getDecorators(); if(empty($decorators)) { $this->addDecorator('DijitElement') ->addDecorator('Description', array( 'tag' => 'p', 'class' => 'description', 'placement' => Zend_Form_Decorator_Abstract::PREPEND)) ->addDecorator('HtmlTag', array( 'tag' => 'dd', 'id' => $this->getName() . '_element')) ->addDecorator('Label', array( 'tag' => 'dt', 'escape' => false)); } } }
Basically all we are doing here is changing the value of “placement” for our description to be prepend instead of append. One item to not is the use of “DijitElement” instead of the normal “ViewHelper” since we extending a Dijit element. Now we can create our form. The form will consist of a single editor and a submit button.
Creating the Form
As stated, we are going to create a form and add one of the Editor elements we just created as well as a submit button. We will do this by extending Zend_Form.
EditForm.php
class Blog_Form_EditForm extends Zend_Form { public function init() { Zend_Dojo::enableForm($this); } public function __construct($options=null) { parent::__construct($options); $this->setName('editForm'); $this->setMethod('post'); $this->addElement(new Blog_Element_Editor( 'editor', array( 'label' => 'Edit Page:', 'description'=> 'This form allows you to edit the index page.', //'plugins' => array('undo', '|', 'bold', 'italic'), //<- you can choose your plugins here 'dojoType' => 'dijit.Editor' ))); $this->addElement('submit', 'submit', array( 'ignore' => true, 'label' => 'continue' )); } }
And the form is done. If you haven’t already, create your editAction function and the edit view.
The Edit View
At this point the view is very simple. We will add some Javacsript to it in just a bit.
edit.phtml
echo $this->form; if($this->dojo()->isEnabled()) { $this->dojo()->setLocalPath('/scripts/Dojo/dojo/dojo.js') ->addStyleSheetModule('dijit.themes.tundra'); echo $this->dojo(); }
Here we are checking to see if dojo is enabled, which we did enable via our form in the init() function. We also set the path to the dojo.js file (change this to wherever this file exists in your project relative to the public directory) and also select a stylesheet to use for the editor. Be sure to echo out the form prior to checking to see if dojo is enabled or it will fail. Now on to the controller.
IndexController.php
class IndexController extends Zend_Controller_Action { private $logger; public function init() { $this->logger = Zend_Registry::get('logger'); } /** * The default action - show the home page */ public function indexAction() { // TODO Auto-generated IndexController::indexAction() action } public function editAction() { $form = new Blog_Form_EditForm(); $this->view->form = $form; } }
All we are doing here is creating an instance of our form, assigning it to the view, and displaying the page. If you bring up your browser and view http://localhost/index/edit/ you will be able to see the form with all of it’s fancy tools.
Populating the Editor
The next thing we need to do is populate the editor with the data we want to edit. In this example we are going to pull the contents of our index page into the editor and save the edited content back to the file. The first thing we need to do is read the content from the file. Let’s update our editAction() function to the following.
IndexController.php
public function editAction() { $form = new Blog_Form_EditForm(); $this->view->form = $form; // get the contents of the index file $file = APPLICATION_PATH . '/views/scripts/index/index.phtml'; $contents = trim(file_get_contents($file, FILE_TEXT)); // remove all line breaks because they will cause problems with the Javascript $contents = str_replace("\r\n", "", $contents); // pass the file contents to our view $this->view->fileContents = $contents; }
Our view is now aware of the contents of the index.phtml file but it is still not available to our editor yet. Here is where a little Javascript trickery happens. Essentially what we are going to do is populate a Javascript variable with the contents of our file. We will then use some Javascript to populate the editor. Since the dijit editor is not a textarea but is actually an iframe we will need to get the body of the iframe and add the contents via dijit’s setValue() function. Let’s go back to the edit.phtml file.
edit.phtml
-- script tag -- var fileContents = '<?php echo $this->fileContents ?>'; -- end script tag -- <?php echo $this->form; if($this->dojo()->isEnabled()) { $this->dojo()->setLocalPath('/scripts/Dojo/dojo/dojo.js') ->addStyleSheetModule('dijit.themes.tundra'); $this->dojo(); } ?> -- script tag -- dojo.addOnLoad(function() { dijit.byId('editor-Editor').setValue(fileContents); } -- end script tag --
Now you can reload the page in your browser and you should see the contents of your index.phtml file there. If you have Firebug, or a similar tool, you can walk through the DOM and take a look at how dijit creates the editor. Notice that there is a hidden field with the name “editor” which just happens to be the name of the form element we created. Dijit creates this hidden field for us to use to pass the contents of the form back to the server.
Now our data is being passed back to the server. We need to update our editAction() function to handle the post data and update the file.
IndexController.php
public function editAction() { $form = new Blog_Form_EditForm(); $this->view-form = $form; // the file we are editing $file = APPLICATION_PATH . '/views/scripts/index/index.phtml'; // check to see if the form has been submitted $request = $this->getRequest(); if($request->isPost()) { $editorContents = $request->getParam('editor'); file_put_contents($file, $editorContents); // send the user to the index page $this->_helper->redirector('index', 'index'); } else { // form has not been submitted $contents = trim(file_get_contents($file, FILE_TEXT)); // remove all line breaks because they will cause problems with the Javascript $contents = str_replace("\r\n", "", $contents); $this->view->fileContents = $contents; } }
After you submit the form you will be redirected to your newly updated index page. There you have it. The dijit.Editor in action and we achieved the three goals listed at the beginning. It took me some experimenting to get it working so I hope this helps someone out there!
Conclusion
You can extend the Zend_Dojo_Form_Element_* or Zend_Form_Element_* classes to alter the order of your decorators, add new ones, or override functionality. Inheritance in action!
Getting the editor to do what you want takes a little Javascript magic but the functionality and usability it adds is well worth it. Some users still seem to be pleasantly surprised by having this functionality but it is starting to become common place and in the near future all of our textareas will be replaced by WYSIWYG editors.
Jul/090
The New Blog!
I decided to go ahead and give WordPress a try. I haven’t really used it other than helping a friend install it on their web server. My old blog definitely needed an update and since I don’t really have the time to re-write the software I went with WordPress. So far I am very impressed. I wish I would have done it earlier.
I have been very busy lately and it does not seem to be coming to an end any time soon. The projects I am currently working on are TheWeddingVendor.com, OurWeddingCircle.com, SoutheastReglazing.com, and AircraftConnection.com.
AircraftConnection.com is a rather large project which I decided to write using the Zend Framework. I will be blogging about my experiences with the Zend Framework over the next couple weeks as I work on the site. Be sure to come back and check it out.