Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
64.10% covered (warning)
64.10%
100 / 156
14.29% covered (danger)
14.29%
1 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
Editor_View
64.10% covered (warning)
64.10%
100 / 156
14.29% covered (danger)
14.29%
1 / 7
14.63
0.00% covered (danger)
0.00%
0 / 1
 add_hooks
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 admin_head
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 grunion_media_button
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 mce_external_plugins
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 mce_buttons
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 handle_editor_view_js
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 1
2
 editor_view_js_templates
100.00% covered (success)
100.00%
100 / 100
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2/**
3 * A prototype to allow inline editing / editor views for contact forms.
4 *
5 * Originally developed in: https://github.com/automattic/gm2016-grunion-editor
6 * Authors: Michael Arestad, Andrew Ozz, and George Stephanis
7 *
8 * @package automattic/jetpack-forms
9 */
10
11namespace Automattic\Jetpack\Forms\ContactForm;
12
13use Automattic\Jetpack\Assets;
14
15/**
16 * Grunion editor view class.
17 */
18class Editor_View {
19    /**
20     * Add hooks according to screen.
21     *
22     * @param \WP_Screen $screen Data about current screen.
23     */
24    public static function add_hooks( $screen ) {
25        if ( isset( $screen->base ) && 'post' === $screen->base ) {
26            add_action( 'admin_notices', array( __CLASS__, 'handle_editor_view_js' ) );
27            add_action( 'admin_head', array( __CLASS__, 'admin_head' ) );
28        }
29    }
30
31    /**
32     * Admin header.
33     */
34    public static function admin_head() {
35        add_action( 'media_buttons', array( __CLASS__, 'grunion_media_button' ), 999 );
36    }
37
38    /**
39     * Render the grunion media button.
40     */
41    public static function grunion_media_button() {
42        $title = __( 'Add Contact Form', 'jetpack-forms' );
43        ?>
44
45        <button type="button" id="insert-jetpack-contact-form" class="button" title="<?php echo esc_attr( $title ); ?>" href="javascript:;">
46            <span class="jetpack-contact-form-icon"></span>
47            <?php echo esc_html( $title ); ?>
48        </button>
49
50        <?php
51    }
52
53    /**
54     * Get external plugins.
55     *
56     * @param array $plugin_array - the plugin array.
57     *
58     * @return array
59     */
60    public static function mce_external_plugins( $plugin_array ) {
61        $plugin_array['grunion_form'] = plugins_url( '../../dist/contact-form/js/tinymce-plugin-form-button.js', __FILE__ );
62        return $plugin_array;
63    }
64
65    /**
66     * MCE buttons.
67     *
68     * @param array $buttons - the buttons.
69     *
70     * @return array
71     */
72    public static function mce_buttons( $buttons ) {
73        $size     = count( $buttons );
74        $buttons1 = array_slice( $buttons, 0, $size - 1 );
75        $buttons2 = array_slice( $buttons, $size - 1 );
76        return array_merge(
77            $buttons1,
78            array( 'grunion' ),
79            $buttons2
80        );
81    }
82
83    /**
84     * WordPress Shortcode Editor View JS Code
85     */
86    public static function handle_editor_view_js() {
87        add_action( 'admin_print_footer_scripts', array( __CLASS__, 'editor_view_js_templates' ), 1 );
88        add_filter( 'mce_external_plugins', array( __CLASS__, 'mce_external_plugins' ) );
89        add_filter( 'mce_buttons', array( __CLASS__, 'mce_buttons' ) );
90
91        wp_enqueue_style( 'grunion-editor-ui', plugins_url( '../../dist/contact-form/css/editor-ui.css', __FILE__ ), array(), \JETPACK__VERSION );
92        wp_style_add_data( 'grunion-editor-ui', 'rtl', 'replace' );
93
94        Assets::register_script(
95            'grunion-editor-view',
96            '../../dist/contact-form/js/editor-view.js',
97            __FILE__,
98            array(
99                'enqueue'      => true,
100                'dependencies' => array( 'wp-util', 'jquery', 'quicktags' ),
101                'version'      => \JETPACK__VERSION,
102                'in_footer'    => true,
103            )
104        );
105
106        wp_localize_script(
107            'grunion-editor-view',
108            'grunionEditorView',
109            array(
110                'inline_editing_style'     => plugins_url( '../../dist/contact-form/css/editor-inline-editing-style.css', __FILE__ ),
111                'inline_editing_style_rtl' => plugins_url( '../../dist/contact-form/css/editor-inline-editing-style.rtl.css', __FILE__ ),
112                'dashicons_css_url'        => includes_url( 'css/dashicons.css' ),
113                'default_form'             => '[contact-field label="' . __( 'Name', 'jetpack-forms' ) . '" type="name"  required="true" /]' .
114                                    '[contact-field label="' . __( 'Email', 'jetpack-forms' ) . '" type="email" required="true" /]' .
115                                    '[contact-field label="' . __( 'Website', 'jetpack-forms' ) . '" type="url" /]' .
116                                    '[contact-field label="' . __( 'Message', 'jetpack-forms' ) . '" type="textarea" /]',
117                'labels'                   => array(
118                    'submit_button_text'  => __( 'Submit', 'jetpack-forms' ),
119                    /** This filter is documented in \Automattic\Jetpack\Forms\ContactForm\Contact_Form */
120                    'required_field_text' => apply_filters( 'jetpack_required_field_text', __( '(required)', 'jetpack-forms' ) ),
121                    'edit_close_ays'      => __( 'Are you sure you\'d like to stop editing this form without saving your changes?', 'jetpack-forms' ),
122                    'quicktags_label'     => __( 'contact form', 'jetpack-forms' ),
123                    'tinymce_label'       => __( 'Add contact form', 'jetpack-forms' ),
124                ),
125            )
126        );
127
128        add_editor_style( plugin_dir_url( __FILE__ ) . '../../dist/contact-form/css/editor-style.css' );
129    }
130
131    /**
132     * JS Templates.
133     */
134    public static function editor_view_js_templates() {
135        ?>
136<script type="text/html" id="tmpl-grunion-contact-form">
137    <form class="card jetpack-contact-form-shortcode-preview" action='#' method='post' class='contact-form commentsblock' onsubmit="return false;">
138        {{{ data.body }}}
139        <p class='contact-submit'>
140            <input type='submit' value='{{ data.submit_button_text }}' class='pushbutton-wide'/>
141        </p>
142    </form>
143</script>
144
145<script type="text/html" id="tmpl-grunion-field-email">
146    <div>
147        <label for='{{ data.id }}' class='grunion-field-label email'>{{ data.label }}<# if ( data.required ) print( " <span>" + data.required + "</span>" ) #></label>
148        <input type='email' name='{{ data.id }}' id='{{ data.id }}' value='{{ data.value }}' class='{{ data.class }}' placeholder='{{ data.placeholder }}' />
149    </div>
150</script>
151
152<script type="text/html" id="tmpl-grunion-field-telephone">
153    <div>
154        <label for='{{ data.id }}' class='grunion-field-label telephone'>{{ data.label }}<# if ( data.required ) print( " <span>" + data.required + "</span>" ) #></label>
155        <input type='tel' name='{{ data.id }}' id='{{ data.id }}' value='{{ data.value }}' class='{{ data.class }}' placeholder='{{ data.placeholder }}' />
156    </div>
157</script>
158
159<script type="text/html" id="tmpl-grunion-field-textarea">
160    <div>
161        <label for='contact-form-comment-{{ data.id }}' class='grunion-field-label textarea'>{{ data.label }}<# if ( data.required ) print( " <span>" + data.required + "</span>" ) #></label>
162        <textarea name='{{ data.id }}' id='contact-form-comment-{{ data.id }}' rows='20' class='{{ data.class }}' placeholder='{{ data.placeholder }}'>{{ data.value }}</textarea>
163    </div>
164</script>
165
166<script type="text/html" id="tmpl-grunion-field-radio">
167    <div>
168        <label class='grunion-field-label'>{{ data.label }}<# if ( data.required ) print( " <span>" + data.required + "</span>" ) #></label>
169        <# _.each( data.options, function( option ) { #>
170            <label class='grunion-radio-label radio'>
171                <input type='radio' name='{{ data.id }}' value='{{ option }}' class="{{ data.class }}" <# if ( option === data.value ) print( "checked='checked'" ) #> />
172                <span>{{ option }}</span>
173            </label>
174        <# }); #>
175        <div class='clear-form'></div>
176    </div>
177</script>
178
179<script type="text/html" id="tmpl-grunion-field-checkbox">
180    <div>
181        <label class='grunion-field-label checkbox'>
182            <input type='checkbox' name='{{ data.id }}' value='<?php esc_attr_e( 'Yes', 'jetpack-forms' ); ?>' class="{{ data.class }}" <# if ( data.value ) print( 'checked="checked"' ) #> />
183                <span>{{ data.label }}</span><# if ( data.required ) print( " <span>" + data.required + "</span>" ) #>
184        </label>
185        <div class='clear-form'></div>
186    </div>
187</script>
188
189<script type="text/html" id="tmpl-grunion-field-checkbox-multiple">
190    <div>
191        <label class='grunion-field-label'>{{ data.label }}<# if ( data.required ) print( " <span>" + data.required + "</span>" ) #></label>
192        <# _.each( data.options, function( option ) { #>
193            <label class='grunion-checkbox-multiple-label checkbox-multiple'>
194                <input type='checkbox' name='{{ data.id }}[]' value='{{ option }}' class="{{ data.class }}" <# if ( option === data.value || _.contains( data.value, option ) ) print( "checked='checked'" ) #> />
195                <span>{{ option }}</span>
196            </label>
197        <# }); #>
198        <div class='clear-form'></div>
199    </div>
200</script>
201
202<script type="text/html" id="tmpl-grunion-field-select">
203    <div>
204        <label for='{{ data.id }}' class='grunion-field-label select'>{{ data.label }}<# if ( data.required ) print( " <span>" + data.required + "</span>" ) #></label>
205        <select name='{{ data.id }}' id='{{ data.id }}' class="{{ data.class }}">
206            <# _.each( data.options, function( option ) { #>
207                <option <# if ( option === data.value ) print( "selected='selected'" ) #>>{{ option }}</option>
208            <# }); #>
209        </select>
210    </div>
211</script>
212
213<script type="text/html" id="tmpl-grunion-field-date">
214    <div>
215        <label for='{{ data.id }}' class='grunion-field-label {{ data.type }}'>{{ data.label }}<# if ( data.required ) print( " <span>" + data.required + "</span>" ) #></label>
216        <input type='text' name='{{ data.id }}' id='{{ data.id }}' value='{{ data.value }}' class="{{ data.class }}" />
217    </div>
218</script>
219
220<script type="text/html" id="tmpl-grunion-field-text">
221    <div>
222        <label for='{{ data.id }}' class='grunion-field-label {{ data.type }}'>{{ data.label }}<# if ( data.required ) print( " <span>" + data.required + "</span>" ) #></label>
223        <input type='text' name='{{ data.id }}' id='{{ data.id }}' value='{{ data.value }}' class='{{ data.class }}' placeholder='{{ data.placeholder }}' />
224    </div>
225</script>
226
227<script type="text/html" id="tmpl-grunion-field-url">
228    <div>
229        <label for='{{ data.id }}' class='grunion-field-label {{ data.type }}'>{{ data.label }}<# if ( data.required ) print( " <span>" + data.required + "</span>" ) #></label>
230        <input type='url' name='{{ data.id }}' id='{{ data.id }}' value='{{ data.value }}' class='{{ data.class }}' placeholder='{{ data.placeholder }}' />
231    </div>
232</script>
233
234
235<script type="text/html" id="tmpl-grunion-field-edit">
236    <div class="card is-compact grunion-field-edit grunion-field-{{ data.type }}" aria-label="<?php esc_attr_e( 'Form Field', 'jetpack-forms' ); ?>">
237        <label class="grunion-name">
238            <span><?php esc_html_e( 'Field Label', 'jetpack-forms' ); ?></span>
239            <input type="text" name="label" placeholder="<?php esc_attr_e( 'Label', 'jetpack-forms' ); ?>" value="{{ data.label }}"/>
240        </label>
241
242        <?php
243        $grunion_field_types = array(
244            'text'              => __( 'Text', 'jetpack-forms' ),
245            'name'              => __( 'Name', 'jetpack-forms' ),
246            'email'             => __( 'Email', 'jetpack-forms' ),
247            'url'               => __( 'Website', 'jetpack-forms' ),
248            'textarea'          => __( 'Textarea', 'jetpack-forms' ),
249            'checkbox'          => __( 'Checkbox', 'jetpack-forms' ),
250            'checkbox-multiple' => __( 'Checkbox with Multiple Items', 'jetpack-forms' ),
251            'select'            => __( 'Drop down', 'jetpack-forms' ),
252            'radio'             => __( 'Radio', 'jetpack-forms' ),
253            'date'              => __( 'Date', 'jetpack-forms' ),
254        );
255        ?>
256        <div class="grunion-type-options">
257            <label class="grunion-type">
258                <?php esc_html_e( 'Field Type', 'jetpack-forms' ); ?>
259                <select name="type">
260                    <?php foreach ( $grunion_field_types as $type => $label ) : ?>
261                    <option <# if ( <?php echo wp_json_encode( $type, JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); ?> === data.type ) print( "selected='selected'" ) #> value="<?php echo esc_attr( $type ); ?>">
262                        <?php echo esc_html( $label ); ?>
263                    </option>
264                    <?php endforeach; ?>
265                </select>
266            </label>
267
268            <label class="grunion-required">
269                <input type="checkbox" name="required" value="1" <# if ( data.required ) print( 'checked="checked"' ) #> />
270                <span><?php esc_html_e( 'Required?', 'jetpack-forms' ); ?></span>
271            </label>
272        </div>
273
274        <label class="grunion-options">
275            <?php esc_html_e( 'Options', 'jetpack-forms' ); ?>
276            <ol>
277                <# if ( data.options ) { #>
278                    <# _.each( data.options, function( option ) { #>
279                        <li><input type="text" name="option" value="{{ option }}" /> <a class="delete-option" href="javascript:;"><span class="screen-reader-text"><?php esc_html_e( 'Delete Option', 'jetpack-forms' ); ?></span></a></li>
280                    <# }); #>
281                <# } else { #>
282                    <li><input type="text" name="option" /> <a class="delete-option" href="javascript:;"><span class="screen-reader-text"><?php esc_html_e( 'Delete Option', 'jetpack-forms' ); ?></span></a></li>
283                    <li><input type="text" name="option" /> <a class="delete-option" href="javascript:;"><span class="screen-reader-text"><?php esc_html_e( 'Delete Option', 'jetpack-forms' ); ?></span></a></li>
284                    <li><input type="text" name="option" /> <a class="delete-option" href="javascript:;"><span class="screen-reader-text"><?php esc_html_e( 'Delete Option', 'jetpack-forms' ); ?></span></a></li>
285                <# } #>
286                <li><a class="add-option" href="javascript:;"><?php esc_html_e( 'Add new option...', 'jetpack-forms' ); ?></a></li>
287            </ol>
288        </label>
289
290        <a href="javascript:;" class="delete-field"><span class="screen-reader-text"><?php esc_html_e( 'Delete Field', 'jetpack-forms' ); ?></span></a>
291    </div>
292</script>
293
294<script type="text/html" id="tmpl-grunion-field-edit-option">
295    <li><input type="text" name="option" /> <a class="delete-option" href="javascript:;"><span class="screen-reader-text"><?php esc_html_e( 'Delete Option', 'jetpack-forms' ); ?></span></a></li>
296</script>
297
298<script type="text/html" id="tmpl-grunion-editor-inline">
299            <h1 id="form-settings-header" class="grunion-section-header"><?php esc_html_e( 'Contact form information', 'jetpack-forms' ); ?></h1>
300            <section class="card grunion-form-settings" aria-labelledby="form-settings-header">
301                <label><?php esc_html_e( 'What would you like the subject of the email to be?', 'jetpack-forms' ); ?>
302                    <input type="text" name="subject" value="{{ data.subject }}" />
303                </label>
304                <label><?php esc_html_e( 'Which email address should we send the responses to?', 'jetpack-forms' ); ?>
305                    <input type="text" name="to" value="{{ data.to }}" />
306                </label>
307            </section>
308            <h1 id="form-fields-header" class="grunion-section-header"><?php esc_html_e( 'Contact form fields', 'jetpack-forms' ); ?></h1>
309            <section class="grunion-fields" aria-labelledby="form-fields-header">
310                {{{ data.fields }}}
311            </section>
312            <section class="grunion-controls">
313                <?php submit_button( esc_html__( 'Add Field', 'jetpack-forms' ), 'secondary', 'add-field', false ); ?>
314
315                <div class="grunion-update-controls">
316                    <?php submit_button( esc_html__( 'Cancel', 'jetpack-forms' ), 'delete', 'cancel', false ); ?>
317                    <?php submit_button( esc_html__( 'Update Form', 'jetpack-forms' ), 'primary', 'submit', false ); ?>
318                </div>
319            </section>
320</script>
321
322</div>
323        <?php
324    }
325}