To use the WYSIWG editor in your code, you use the \IPS\Helpers\Form\Editor class within the Form Helper.
Editors automatically have the ability to support attachments, and the administrator can customize the editor to make certain features available in some areas and not others. Because of this, using an Editor is slightly more complicated than most other form types.
Creating an EditorLocations extension
You are required to create an EditorLocations extension within your application which is mostly used to provide callbacks to locate attachments uploaded to that editor.
To get started, create an EditorLocations extension file through the developer center for your application. A skeleton file will be created in the applications/app/extensions/core/EditorLocations folder with example code. You will need to provide code for the attachmentPermissionCheck() and attachmentLookup() methods.
For example, if you are using this editor for an ACP setting, the value of which will be displayed on a certain page which is visible to all members who have access to the application, the code might look something like this:
<?php namespace IPS\app\extensions\core\EditorLocations; class _Key { /** * Permission check for attachments * * @param \IPS\Member $member The member * @param int|null $id1 Primary ID * @param int|null $id2 Secondary ID * @param string|null $id3 Arbitrary data * @return bool */ public function attachmentPermissionCheck( $member, $id1, $id2, $id3 ) { return $member->canAccessModule( \IPS\Application\Module::get( 'app', 'module' ) ); } /** * Attachment lookup * * @param int|null $id1 Primary ID * @param int|null $id2 Secondary ID * @param string|null $id3 Arbitrary data * @return \IPS\Http\Url|\IPS\Content|\IPS\Node\Model * @throws \LogicException */ public function attachmentLookup( $id1, $id2, $id3 ) { return \IPS\Http\Url::internal( 'app=app&module=module&controller=controller', 'front' ); } }
Or if you are using this editor for the description for Content Items that members create, the code might look something like:
<?php namespace IPS\app\extensions\core\EditorLocations; class _Key { /** * Permission check for attachments * * @param \IPS\Member $member The member * @param int|null $id1 Primary ID * @param int|null $id2 Secondary ID * @param string|null $id3 Arbitrary data * @return bool */ public function attachmentPermissionCheck( $member, $id1, $id2, $id3 ) { try { return \IPS\app\Thing::load( $id1 )->canView( $member ); } catch ( \OutOfRangeException $e ) { return FALSE; } } /** * Attachment lookup * * @param int|null $id1 Primary ID * @param int|null $id2 Secondary ID * @param string|null $id3 Arbitrary data * @return \IPS\Http\Url|\IPS\Content|\IPS\Node\Model * @throws \LogicException */ public function attachmentLookup( $id1, $id2, $id3 ) { return \IPS\app\Thing::load( $id1 )->url(); } }
However the appropriate code to use will depend on the nature of how the content created by your editor will be used.
Note that you do not have to (and shouldn't) create a separate extension for every single editor. It is common practice for example, to use one extension for every setting field within your application. The $id parameters allow you to know specifically what piece of content is referenced, as explained below.
You must also create a language string which identifies your editor with the key editor__<app>_<Key>. This is used to display to the admin when they are configuring which buttons show up in which areas. For example, in the core application, the key editor__core_Contact is defined as "Contact Form".
Creating the form element
When creating the element you must provide an $options parameter specifying the extension you just created, along with some additional information:
- autoSaveKey is a string which identifies this editor's purpose. For example, if the editor is for replying to a topic with ID 5, you could use "topic-reply-5". Make sure you pass the same key every time, but a different key for different editors.
- attachIds are discussed below. Can contain up to 3 elements, and the first 2 must be numeric, but the last can be a string
For example, the code to create your element will look something like:
$form->add( new \IPS\Helpers\Form\Editor( 'my_editor', NULL, TRUE, array( 'app' => 'app', 'key' => 'Key', 'autoSaveKey' => 'my-editor-field', 'attachIds' => array( ... ) ) );
Claiming attachments
Generally speaking, there are two types of content: values which always exist (like settings) and content which is created and deleted. Attachments are handled differently for each:
Values which always exist
Pass an identifier to the attachIds parameter. For example, you might do:
'attachIds' => array( 1 )
And then in your extension you will look at $id 1 and know that 1 is for this instance of the editor. Then you would use different numbers for other editors using the same extension.
Even if there is only one editor using this extension, you must provide a value for attachIds. The system will then automatically handle claiming attachments.
Content which is created and deleted
When displaying the editor on the "create" screen you will pass NULL for attachIds (because of course at this point you don't know what ID you will save it with). Then, in the code for your form which handles creating the content, after you have created the content and therefore have an ID for it, you call this code:
\IPS\File::claimAttachments( $autoSaveKey, $id1, $id2, $id3 );
$autoSaveKey is the same value you used for the autoSaveKey parameter when creating the editor. Each of the $id fields are optional but you must provide at least one. They are what will be passed to the method in your extension.
When displaying the editor on the "edit" screen, you pass the ID values to attachIds and do not call claimAttachments.
For example:
$editing = NULL; if ( \IPS\Request::i()->id ) { try { $editing = \IPS\app\Thing::load( \IPS\Request::i()->id ); } catch ( \OutOfRangeException $e ) { \IPS\Output::i()->error( ... ); } } $form = new \IPS\Helpers\Form; $form->add( new \IPS\Helpers\Form\Editor( 'my_editor', NULL, TRUE, array( 'app' => 'app', 'key' => 'Key', 'autoSaveKey' => !$editing ? 'creating-thing' : "editing-thing-{$editing->id}", 'attachIds' => $editing ? array( $editing->id ) : NULL ) ) ); if ( $values = $form->values() ) { if ( !$editing ) { $item = new \IPS\app\Thing; $item->content = $values['my_editor']; $item->save(); \IPS\File::claimAttachments( 'creating-thing', $item->id ); } else { $editing->content = $values['my_editor']; $editing->save(); } }
Displaying the contents of an Editor field
The value is automatically parsed including replacing profanity and other settings configured by the administrator, and sanitized of any security concerns. You can safely store the display value and display it without any further parsing.
If you simply output the value of the editor in your template, you would notice that entities are double-escaped. This is because by default, the IPS4 template system escapes all output to prevent XSS vulnerabilities. In the case of editor content, however, you can safely use the unescaped version of the content because the form helper will have already taken care of sanitization for you. Therefore, to use editor content in a template, you would use this:
{$val|raw}
The |raw modifier disables automatic escaping for this variable by the template system.
Report Document