LogoPhly, boy, phly
the weblog and site of Matthew Weier O'Phinney

Thursday, August 28. 2008

Using dijit.Editor with Zend Framework

We're getting ready to release Zend Framework 1.6.0. However, one important Dijit had to be omitted from the release as I was not able to get it working in time: dijit.Editor.

This dijit is important as it provides an out-of-the-box WYSIWYG editor that you can use with your forms. Unfortunately, actually using it with forms is pretty tricky -- Dojo actually ends up storing content outside the form, which means you need to create a handler that pulls the content into a hidden element when saving.

I have created an implementation, however, that you can start using now, and I'm posting it below. It includes both a view helper for displaying it, as well as a form element for use with Zend_Form.

The View Helper looks like this:


<?php
/** Zend_Dojo_View_Helper_Textarea */
require_once 'Zend/Dojo/View/Helper/Textarea.php';

/**
 * dijit.Editor view helper
 *
 * @uses       Zend_Dojo_View_Helper_Textarea
 * @category   My
 * @package    My_View
 * @subpackage Helper
 * @license    New BSD {@link http://framework.zend.com/license/new-bsd}
 * @version    $Id: $
 */

class My_View_Helper_Editor extends Zend_Dojo_View_Helper_Textarea
{
    /**
     * @param string Dijit type
     */

    protected $_dijit = 'dijit.Editor';

    /**
     * @param string Dojo module
     */

    protected $_module = 'dijit.Editor';

    /**
     * dijit.Editor
     *
     * @param  string $id
     * @param  string $value
     * @param  array $params
     * @param  array $attribs
     * @return string
     */

    public function editor($id, $value = null, $params = array(), $attribs = array())
    {
        $hiddenName = $textareaName = $id;

        $hiddenAttribs = array(
            'id'    => $hiddenName,
            'name'  => $hiddenName,
            'value' => $value,
            'type'  => 'hidden',
        );

        if (array_key_exists('id', $attribs)) {
            $hiddenAttribs['id'] = $attribs['id'];
            $attribs['id'] .= 'Editor';
            $id = $attribs['id'];
        }

        if (']' == $textareaName[strlen($textareaName) - 1]) {
            $textareaName = rtrim($textareaName, ']');
            $textareaName .= 'Editor]';
        }

        $this->_createGetParentFormFunction();
        $this->_createEditorOnSubmit($hiddenAttribs['id'], $id);

        $html = '<input' . $this->_htmlAttribs($hiddenAttribs) . $this->getClosingBracket()
              . $this->textarea($textareaName, $value, $params, $attribs);
        return $html;
    }

    /**
     * Create JS function for retrieving parent form
     *
     * @return void
     */

    protected function _createGetParentFormFunction()
    {
        $function =<<<EOJ
if (zend == undefined) {
    var zend = {};
}
zend.findParentForm = function(elementNode) {
    while (elementNode.nodeName.toLowerCase() != 'form') {
        elementNode = elementNode.parentNode;
    }
    return elementNode;
};
EOJ;

        $this->dojo->addJavascript($function);
    }

    /**
     * Create onSubmit binding for element
     *
     * @param  string $hiddenId
     * @param  string $editorId
     * @return void
     */

    protected function _createEditorOnSubmit($hiddenId, $editorId)
    {
        $this->dojo->onLoadCaptureStart();
        echo <<<EOJ
function() {
    var form = zend.findParentForm(dojo.byId('$hiddenId'));
    dojo.connect(form, 'onsubmit', function () {
        dojo.byId('$hiddenId').value = dijit.byId('$editorId').getValue(false);
    });
}
EOJ;
        $this->dojo->onLoadCaptureEnd();
    }
}
 

There's a lot of code in there, but the important bits are the last two methods, which allow finding the parent form of the Editor dijit, and then tying the form onsubmit event to an action that sets a hidden value to the provided Editor content.

The form element is much easier:


<?php
/** Zend_Dojo_Form_Element_Dijit */
require_once 'Zend/Dojo/Form/Element/Dijit.php';

/**
 * dijit.Editor
 *
 * @uses       Zend_Dojo_Form_Element_Dijit
 * @category   My
 * @package    My_Form
 * @subpackage Element
 * @license    New BSD {@link http://framework.zend.com/license/new-bsd}
 * @version    $Id: $
 */

class My_Form_Element_Editor extends Zend_Dojo_Form_Element_Dijit
{
    /**
     * @var string View helper
     */

    public $helper = 'Editor';
}
 

Honestly, that's it. Since the view helper does the heavy lifting of display, all the element needs to do is to indicate which helper to use.

Putting it all together in a form, you'll need to do the following:


$view->addHelperPath('My/View/Helper/', 'My_View_Helper');
$form->addPrefixPath('My_Form_Element', 'My/Form/Element');

$form->addElement('Editor', 'content');
 

The helper prefix path is probably best added in your bootstrap; the form prefix path should be added early in your form class's init() method, or passed in via configuration.

You should see this element shipped in ZF's standard library likely in ZF 1.6.1.

Update: Jasone E. noted that the view helper was missing a $_module declaration of "dijit.Editor" -- this has been added.

Posted by Matthew Weier O'Phinney in PHP at 11:50 | Comments (25) | Trackbacks (0)
Defined tags for this entry: dojo, php, zend framework
Related entries by tags:
Zend Framework 1.7.0 Released
Vimgrep and Vim Project
Pastebin app updates
ZendCon08 Wrapup
Setting up your Zend_Test test suites

Trackbacks
Trackback specific URI for this entry

No Trackbacks

Comments
Display comments as (Linear | Threaded)

Thanks again for all of your efforts. This is extremely helpful.
#1 Matthew Lurz on 2008-08-28 17:22 (Reply)
great work! but, only can't use one editor per time right?.. I mean, if your form have two editors..
Maybe I can modify a little code.. and get the perfect result. Thanks
#1.1 jean-claude adams (Link) on 2008-09-15 19:23 (Reply)
I've actually committed code for Editor support into the ZF trunk; the version in ZF trunk is more robust and should allow multiple editor widgets per page.
#1.1.1 Matthew Weier O'Phinney (Link) on 2008-09-15 20:15 (Reply)
I've been playing around with this and can't seem to get the anonymous function in dojo.connect to fire. I just inserted an alert to test.
#2 Matthew Lurz on 2008-08-30 08:39 (Reply)
It appears that a dijit is necessary as the first argument to dojo.connect. At least if I get the dijit explicitly, e.g. form = dijit.byId('form_id');, then dojo.connect works as expected. Also, this character - Â - seems to be prepended each time the form is submitted. Any idea as to what might cause this?
#3 Matthew Lurz on 2008-08-30 09:14 (Reply)
Hello, thanks for making this work, are there any tutorials on how to implement this in Zend Framework ?
I'm a dojo noob with a lot of questions:
- Which javascripts should be included for the dijit.Editor only dojo.js or more ?
- If I include a My_Form_Element_Editor why isn't there 'dojoType="dijit.Editor' in my source code ?
#4 Dries G on 2008-09-04 12:14 (Reply)
Yes -- just dojo.js is necessary; the view helper ensures the other necessary modules are loaded. The reason the dojoType="dijit.Editor" text is not in your HTML source is because ZF creates dijits programmatically by default.

As for tutorials, I did a webinar yesterday; it will be posted at http://www.zend.com/webinars later today or tomorrow. Also keep an eye on my blog for further ones in the future.
#4.1 Matthew Weier O'Phinney (Link) on 2008-09-04 12:28 (Reply)
Thanks for the reply, I will check the webinar as soon as it's on the site thanks!
In the meantime, I've been reading the Zend Framework 1.6 Reference manual and I've noticed I should enable dojo in a custom form by setting

// Dojo-enable the form:
Zend_Dojo::enableForm($this);

this into the code, ... I did this, include dojo.js and added the My_Form_Element_Editor to my page, but only a textarea and corresponding hidden input field appears, with no markup icons...any idea what I did wrong ?

Thanks !
#4.1.1 Dries G on 2008-09-05 04:30 (Reply)
Well, first off, that means it's doing most of it correctly -- if you're seeing the markup, that's half the battle.

So, my guess is that you didn't render the dojo view helper in your layout -- make sure you do that: should be somewhere in the section of your layout script.
#4.1.1.1 Matthew Weier O'Phinney (Link) on 2008-09-05 06:34 (Reply)
Problem solved, I have had a look at the source code from this website: http://wellhost.com/dojoedit.html , my problem was I had the following code in my page:



if I changed the parseOnLoad option to true the markup items were showing, ... still figuring out why etc.
thanks for the help !
#4.1.1.1.1 Dries G on 2008-09-06 08:04 (Reply)
Just to let you know that I've spent some hours trying to let the plugin loader find the editor class, the solution was to change the setting of the prefix path to:

$this->addPrefixPath('My_Form_Element', 'My/Form/Element','element');

I really don't understand why...
#4.1.1.1.2 Dries G on 2008-09-07 04:30 (Reply)
Thanks for this great work.
I tried to integrate this editor several times but without results. each time I validates my form, I do not get the expected result from the editor and I think the problem comes from the function which return the ParentForm

I changed the function by adding this line:
return elementNode.domNode;

and it works fine .

Thanks for sharing and sorry for my poor english
Regards Adil :-)
#5 Adil on 2008-09-06 01:57 (Reply)
Thanks for this great work.

I've been trying to use the dijit editor but although it is displayed correctly on the browser it is not passing its value to the hidden field when the form is submited.

I can see the dojo.connect function at the source code but it seems that the textarea value is empty and therefore passing an empty value to the hidden field. When I print the "$_POST" I see both the hidden field and the textarea with null values. Maybe the textarea is not getting the iframe content?

Regards

Marcell
#6 Marcell on 2008-09-09 16:55 (Reply)
I have the same question,how to deal that?
#6.1 Anonymous on 2008-09-17 12:23 (Reply)
try to use this function :

protected function _createGetParentFormFunction()
{
$function =
#6.2 Adil on 2008-09-18 22:36 (Reply)
sorry for my last comment
this is the code you should change.
_createGetParentFormFunction() should return this value

return elementNode.domNode;

it works for me :-)

Adil
#6.3 Adil on 2008-09-18 22:42 (Reply)
Not works for me and the problem is the submit is not hooked. The form is correctly as its id is right. The code inside the function connected, however, is never executed.
#6.4 Piccolo Principe on 2008-09-19 08:30 (Reply)
I see from http://framework.zend.com/svn/framework/standard/tags/release-1.6.1/library/Zend/Dojo/Form/Element/ that Editor form element is not present. When we could get it? I prefer not to add other classes to mantain to "My_" library if they will be present out-of-the-box soon.
#7 Piccolo Principe on 2008-09-17 12:15 (Reply)
Editor is in current trunk, but will not be released until 1.7.0 -- which, fortunately, will happen before the end of this current calendar year.
#7.1 Matthew Weier O'Phinney (Link) on 2008-09-17 12:57 (Reply)
First i like to thank you for sharing the Editor code. I'm sorry to say that i can't get it to work properly (doesn't receive a value in post).
Unfortunately i can't use ZF Trunk because we have a "Production use" - Project. My Idea was, to implement the 1.7 Editor in my 1.6.1 Library. Can you tell me what files i have to copy and change? Do you think that's possible?

Thanks in advance,
Thorsten
#8 Saphir2k on 2008-09-29 06:54 (Reply)
Yes -- grab Zend_Dojo_View_Helper_Dojo, Zend_Dojo_View_Helper_Dijit, Zend_Dojo_View_Helper_Editor, and Zend_Dojo_Form_Element_Editor; those should be sufficient for implementing the functionality. (I made some additions to the base Dojo/Dijit view helpers to accomodate other dijits in the future, which is why those are necessary.)
#8.1 Matthew Weier O'Phinney (Link) on 2008-09-29 08:51 (Reply)
This is great, cheers. How do you add plugins to enable inserting images and links etc?
#9 Will on 2008-10-03 01:14 (Reply)
OK, Ive worked some of it out

I guess you add the element like this:

$contentbox=new Zend_Dojo_Form_Element_Editor('content');
$contentbox->addPlugin('LinkDialog');
$this->addElement($contentbox);

which works fine without the add plugin call but with it you get a 'Cannot find plugin LinkDialog' error in Editor.xd.js (ln12)

According to
http://docs.dojocampus.org/dijit/Editor#id6
we need to be dojo.require("dijit._editor.plugins.LinkDialog");

and then do plugins="['bold','italic','|','createLink']"

in the markup to get a link dialog plugin.

What can i be doing wrong?
#10 Will on 2008-10-03 02:46 (Reply)
This is good feedback; I've added an item to our issue tracker to automatically create the dojo.require statements: http://framework.zend.com/issues/browse/ZF-4461
#10.1 Matthew Weier O'Phinney (Link) on 2008-10-03 07:28 (Reply)
Thanks!
Obviously i ended up using
$this->dojo()->requireModule ('dijit._editor.plugins.LinkDialog');

last friday to get the link dialog working, it adds the module but removes all the default ones, so you have to add all the toolbar elements you want yourself.

eg
$plugs= array('createLink','bold','redo','cut','copy','paste','selectAll','bold','italic','underline','strikethrough','subscript','superscript','removeFormat');
$contentbox->addPlugins($plugs);

Unfortunatly, I don't think there is a image selector plugin for dojo yet. which is a big hole in functionality for us.
#11 Will on 2008-10-06 18:11 (Reply)

Add Comment

Standard emoticons like :-) and ;-) are converted to images.
E-Mail addresses will not be displayed and will only be used for E-Mail notifications

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

 
 
  • Home
  • Resume
  • Blog
  • Phly PEAR Channel
  • Contact Me
  • About this site

ZCE

Zend Education Advisory Board Member

Add to Technorati Favorites

Calendar

Back November '08 Forward
Mon Tue Wed Thu Fri Sat Sun
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

Quicksearch

Links

  • PHLY - PHp LibrarY
  • Paul M. Jones
  • Mike Naberezny
  • Shahar Evron
  • Planet PHP
  • Zend Where I now work
  • Garden.org Where I once worked

Archives

November 2008
October 2008
September 2008
Recent...
Older...

Categories

XML Linux
XML Personal
XML Aikido
XML Family
XML Programming
XML Dojo
XML Perl
XML PHP

All categories

Syndicate This Blog

XML RSS 0.91 feed
XML RSS 1.0 feed
XML RSS 2.0 feed
ATOM/XML ATOM 0.3 feed
ATOM/XML ATOM 1.0 feed
XML RSS 2.0 Comments

Show tagged entries

xml best practices
xml books
xml conferences
xml dojo
xml dpc08
xml file_fortune
xml linux
xml mvc
xml oop
xml pear
xml personal
xml php
xml phpworks08
xml programming
xml ubuntu
xml vim
xml webinar
xml zendcon
xml zendcon08
xml zend framework
© 2004 - present, Matthew Weier O'Phinney
matthew-web <at> weierophinney.net