Completed
Push — master ( 6e5918...2d50a5 )
by Andreas
13:56
created

midcom_helper_head::print_jsonload()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2.5

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 5
ccs 2
cts 4
cp 0.5
crap 2.5
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package midcom.helper
4
 * @author CONTENT CONTROL http://www.contentcontrol-berlin.de/
5
 * @copyright CONTENT CONTROL http://www.contentcontrol-berlin.de/
6
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License
7
 */
8
9
/**
10
 * Helper functions for managing HTML head
11
 *
12
 * @package midcom.helper
13
 */
14
class midcom_helper_head
15
{
16
    /**
17
     * Array with all JavaScript declarations for the page's head.
18
     *
19
     * @var array
20
     */
21
    private $_jshead = [];
22
23
    /**
24
     * Array with all JavaScript file inclusions.
25
     *
26
     * @var array
27
     */
28
    private $_jsfiles = [];
29
30
    /**
31
     * Array with all prepend JavaScript declarations for the page's head.
32
     *
33
     * @var array
34
     */
35
    private $_prepend_jshead = [];
36
37
    /**
38
     * Boolean showing if jQuery is enabled
39
     *
40
     * @var boolean
41
     */
42
    private $_jquery_enabled = false;
43
44
    private $_jquery_init_scripts = '';
45
46
    /**
47
     * Array with all JQuery state scripts for the page's head.
48
     *
49
     * @var array
50
     */
51
    private $_jquery_states = [];
52
53
    /**
54
     * Array with all linked URLs for HEAD.
55
     *
56
     * @var Array
57
     */
58
    private $_linkhrefs = [];
59
60
    /**
61
     * Array with all methods for the BODY's onload event.
62
     *
63
     * @var Array
64
     */
65
    private $_jsonload = [];
66
67
    /**
68
     * string with all metatags to go into the page head.
69
     *
70
     * @var string
71
     */
72
    private $_meta_head = '';
73
74
    /**
75
     * string with all object tags to go into a page's head.
76
     *
77
     * @var string
78
     */
79
    private $_object_head = '';
80
81
    /**
82
     * String with all css styles to go into a page's head.
83
     *
84
     * @var string
85
     */
86
    private $_style_head = '';
87
88
    /**
89
     * Array with all link elements to be included in a page's head.
90
     *
91
     * @var array
92
     */
93
    private $_link_head = [];
94
95
    /**
96
     * Sets the page title for the current context.
97
     *
98
     * This can be retrieved by accessing the component context key
99
     * MIDCOM_CONTEXT_PAGETITLE.
100
     *
101
     * @param string $string    The title to set.
102
     */
103 133
    public function set_pagetitle($string)
104
    {
105 133
        midcom_core_context::get()->set_key(MIDCOM_CONTEXT_PAGETITLE, $string);
106 133
    }
107
108
    /**
109
     * Register JavaScript File for referring in the page.
110
     *
111
     * This allows MidCOM components to register JavaScript code
112
     * during page processing. The site style code can then query this queued-up code
113
     * at anytime it likes. The queue-up SHOULD be done during the code-init phase,
114
     * while the print_head_elements output SHOULD be included in the HTML HEAD area and
115
     * the HTTP onload attribute returned by print_jsonload SHOULD be included in the
116
     * BODY-tag. Note, that these suggestions are not enforced, if you want a JScript
117
     * clean site, just omit the print calls and you should be fine in almost all
118
     * cases.
119
     *
120
     * The sequence of the add_jsfile and add_jscript commands is kept stable.
121
     *
122
     * @param string $url    The URL to the file to-be referenced.
123
     * @param boolean $prepend Whether to add the JS include to beginning of includes
124
     * @see add_jscript()
125
     * @see add_jsonload()
126
     * @see print_head_elements()
127
     * @see print_jsonload()
128
     */
129 341
    public function add_jsfile($url, $prepend = false)
130
    {
131
        // Adds a URL for a <script type="text/javascript" src="tinymce.js"></script>
132
        // like call. $url is inserted into src. Duplicates are omitted.
133 341
        if (!in_array($url, $this->_jsfiles)) {
134 30
            $this->_jsfiles[] = $url;
135 30
            $js_call = ['url' => $url];
136 30
            if ($prepend) {
137
                // Add the javascript include to the beginning, not the end of array
138
                array_unshift($this->_jshead, $js_call);
139
            } else {
140 30
                $this->_jshead[] = $js_call;
141
            }
142
        }
143 341
    }
144
145
    /**
146
     * Register JavaScript Code for output directly in the page.
147
     *
148
     * This allows components to register JavaScript code
149
     * during page processing. The site style can then query this queued-up code
150
     * at anytime it likes. The queue-up SHOULD be done during the code-init phase,
151
     * while the print_head_elements output SHOULD be included in the HTML HEAD area and
152
     * the HTTP onload attribute returned by print_jsonload SHOULD be included in the
153
     * BODY-tag. Note, that these suggestions are not enforced
154
     *
155
     * The sequence of the add_jsfile and add_jscript commands is kept stable.
156
     *
157
     * @param string $script    The code to be included directly in the page.
158
     * @see add_jsfile()
159
     * @see add_jsonload()
160
     * @see print_head_elements()
161
     * @see print_jsonload()
162
     */
163 19
    public function add_jscript($script, $defer = '', $prepend = false)
164
    {
165 19
        $js_call = ['content' => trim($script), 'defer' => $defer];
166 19
        if ($prepend) {
167
            $this->_prepend_jshead[] = $js_call;
168
        } else {
169 19
            $this->_jshead[] = $js_call;
170
        }
171 19
    }
172
173
    /**
174
     * Register JavaScript snippets to jQuery states.
175
     *
176
     * This allows components to register JavaScript code to the jQuery states.
177
     * Possible ready states: document.ready
178
     *
179
     * @param string $script    The code to be included in the state.
180
     * @param string $state    The state where to include the code to. Defaults to document.ready
181
     * @see print_jquery_statuses()
182
     */
183 3
    public function add_jquery_state_script($script, $state = 'document.ready')
184
    {
185 3
        $js_call = "\n" . trim($script) . "\n";
186
187 3
        if (!isset($this->_jquery_states[$state])) {
188 1
            $this->_jquery_states[$state] = $js_call;
189
        } else {
190 2
            $this->_jquery_states[$state] .= $js_call;
191
        }
192 3
    }
193
194
    /**
195
     * Register some object tags to be added to the head element.
196
     *
197
     * This allows components to register object tags to be placed in the
198
     * head section of the page.
199
     *
200
     * @param  string $script    The input between the <object></object> tags.
201
     * @param  array  $attributes Array of attribute=> value pairs to be placed in the tag.
202
     * @see print_head_elements()
203
     */
204
    public function add_object_head($script, $attributes = null)
205
    {
206
        $this->_object_head .= '<object' . $this->_get_attribute_string($attributes) . '>' . $script . "</object>\n";
207
    }
208
209
    /**
210
     *  Register a metatag to be added to the head element.
211
     *  This allows components to register metatags to be placed in the
212
     *  head section of the page.
213
     *
214
     *  @param  array  $attributes Array of attribute => value pairs to be placed in the tag.
215
     *  @see print_head_elements()
216
     */
217
    public function add_meta_head($attributes = null)
218
    {
219
        $this->_meta_head .= '<meta' . $this->_get_attribute_string($attributes) . ' />' . "\n";
220
    }
221
222
    /**
223
     * Register a styleblock / style link  to be added to the head element.
224
     * This allows components to register extra CSS sheets they wants to include.
225
     * in the head section of the page.
226
     *
227
     * @param  string $script    The input between the <style></style> tags.
228
     * @param  array  $attributes Array of attribute=> value pairs to be placed in the tag.
229
     * @see print_head_elements()
230
     */
231
    public function add_style_head($script, $attributes = null)
232
    {
233
        $this->_style_head .= '<style type="text/css"' . $this->_get_attribute_string($attributes) . '>' . $script . "</style>\n";
234
    }
235
236 7
    private function _get_attribute_string($attributes)
237
    {
238 7
        $string = '';
239 7
        if (null === $attributes) {
240
            return $string;
241
        }
242 7
        foreach ($attributes as $key => $val) {
243 7
            $string .= ' ' . $key . '="' . htmlspecialchars($val, ENT_COMPAT) . '"';
244
        }
245 7
        return $string;
246
    }
247
248
    /**
249
     * Register a link element to be placed in the page head.
250
     *
251
     * This allows components to register extra CSS links.
252
     * Example to use this to include a CSS link:
253
     * <code>
254
     * $attributes = array ('rel' => 'stylesheet',
255
     *                      'type' => 'text/css',
256
     *                      'href' => '/style.css'
257
     *                      );
258
     * midcom::get()->head->add_link_head($attributes);
259
     * </code>
260
     *
261
     * Each URL will only be added once. When trying to add the same URL a second time,
262
     * it will be moved to the end of the stack, so that CSS overrides behave as the developer
263
     * intended
264
     *
265
     * @param  array $attributes Array of attribute => value pairs to be placed in the tag.
266
     * @see print_head_elements()
267
     */
268 342
    public function add_link_head(array $attributes)
269
    {
270 342
        if (!array_key_exists('href', $attributes)) {
271
            return false;
272
        }
273
274
        // Register each URL only once
275 342
        if (($key = array_search($attributes['href'], $this->_linkhrefs)) !== false) {
276 342
            if (end($this->_linkhrefs) != $attributes['href']) {
277 342
                unset($this->_linkhrefs[$key]);
278 342
                $this->_linkhrefs[] = $attributes['href'];
279 342
                reset($this->_linkhrefs);
280
            }
281 342
            return false;
282
        }
283
284 36
        $this->_linkhrefs[] = $attributes['href'];
285 36
        $this->_link_head[$attributes['href']] = $attributes;
286 36
    }
287
288
    /**
289
     * Convenience shortcut for adding CSS files
290
     *
291
     * @param string $url The stylesheet URL
292
     * @param string $media The media type(s) for the stylesheet, if any
293
     */
294 342
    public function add_stylesheet($url, $media = false)
295
    {
296
        $attributes = [
297 342
            'rel'  => 'stylesheet',
298 342
            'type' => 'text/css',
299 342
            'href' => $url,
300
        ];
301 342
        if ($media) {
302 12
            $attributes['media'] = $media;
303
        }
304 342
        $this->add_link_head($attributes);
305 342
    }
306
307
    /**
308
     * Register a JavaScript method for the body onload event
309
     *
310
     * This allows components to register JavaScript code
311
     * during page processing. The site style can then query this queued-up code
312
     * at anytime it likes. The queue-up SHOULD be done during the code-init phase,
313
     * while the print_head_elements output SHOULD be included in the HTML HEAD area and
314
     * the HTTP onload attribute returned by print_jsonload SHOULD be included in the
315
     * BODY-tag. Note that these suggestions are not enforced.
316
     *
317
     * @param string $method    The name of the method to be called on page startup, including parameters but excluding the ';'.
318
     * @see add_jsfile()
319
     * @see add_jscript()
320
     * @see print_head_elements()
321
     * @see print_jsonload()
322
     */
323
    public function add_jsonload($method)
324
    {
325
        // Adds a method name for <body onload=".."> The string must not end with a ;, it is added automagically
326
        $this->_jsonload[] = $method;
327
    }
328
329
    /**
330
     * Echo the registered javascript code.
331
     *
332
     * This allows components to register JavaScript code
333
     * during page processing. The site style code can then query this queued-up code
334
     * at anytime it likes. The queue-up SHOULD be done during the code-init phase,
335
     * while the print_head_elements output SHOULD be included in the HTML HEAD area and
336
     * the HTTP onload attribute returned by print_jsonload SHOULD be included in the
337
     * BODY-tag. Note, that these suggestions are not enforced
338
     *
339
     * The sequence of the add_jsfile and add_jscript commands is kept stable.
340
     *
341
     * This is usually called during the BODY region of your style:
342
     *
343
     * <code>
344
     * <html>
345
     *     <body <?php midcom::get()->head->print_jsonload();?>>
346
     *            <!-- your actual body -->
347
     *     </body>
348
     * </html>
349
     * </code>
350
     *
351
     * @see add_jsfile()
352
     * @see add_jscript()
353
     * @see add_jsonload()
354
     * @see print_head_elements()
355
     */
356 5
    public function print_jsonload()
357
    {
358 5
        if (!empty($this->_jsonload)) {
359
            $calls = implode("; ", $this->_jsonload);
360
            echo " onload=\"$calls\" ";
361
        }
362 5
    }
363
364
    /**
365
     * Echo the _head elements added.
366
     * This function echos the elements added by the add_(style|meta|link|object)_head
367
     * methods.
368
     *
369
     * Place the method within the <head> section of your page.
370
     *
371
     * This allows components to register HEAD elements
372
     * during page processing. The site style can then query this queued-up code
373
     * at anytime it likes. The queue-up SHOULD be done during the code-init phase,
374
     * while the print_head_elements output SHOULD be included in the HTML HEAD area and
375
     * the HTTP onload attribute returned by print_jsonload SHOULD be included in the
376
     * BODY tag. Note that these suggestions are not enforced
377
     *
378
     * @see add_link_head()
379
     * @see add_object_head()
380
     * @see add_style_head()
381
     * @see add_meta_head()
382
     * @see add_jsfile()
383
     * @see add_jscript()
384
     */
385 7
    public function print_head_elements()
386
    {
387 7
        echo $this->_meta_head;
388 7
        foreach ($this->_linkhrefs as $url) {
389 7
            $attributes = $this->_link_head[$url];
390 7
            $is_conditional = false;
391
392 7
            if (array_key_exists('condition', $attributes)) {
393
                echo "<!--[if {$attributes['condition']}]>\n";
394
                $is_conditional = true;
395
                unset($attributes['condition']);
396
            }
397
398 7
            echo "<link" . $this->_get_attribute_string($attributes) . " />\n";
399
400 7
            if ($is_conditional) {
401 7
                echo "<![endif]-->\n";
402
            }
403
        }
404
405 7
        echo $this->_object_head;
406 7
        echo $this->_style_head;
407
408 7
        if ($this->_jquery_enabled) {
409 7
            echo $this->_jquery_init_scripts;
410
        }
411
412 7
        if (!empty($this->_prepend_jshead)) {
413
            array_map([$this, '_print_js'], $this->_prepend_jshead);
414
        }
415
416 7
        array_map([$this, '_print_js'], $this->_jshead);
417 7
        $this->print_jquery_statuses();
418 7
    }
419
420 7
    private function _print_js(array $js_call)
421
    {
422 7
        if (array_key_exists('url', $js_call)) {
423 7
            echo '<script type="text/javascript" src="' . $js_call['url'] . "\"></script>\n";
424
        } else {
425 3
            echo '<script type="text/javascript"' . $js_call['defer'] . ">\n";
426 3
            echo  $js_call['content'] . "\n";
427 3
            echo "</script>\n";
428
        }
429 7
    }
430
431 5
    public function get_jshead_elements()
432
    {
433 5
        return $this->_prepend_jshead + $this->_jshead;
434
    }
435
436
    public function get_link_head()
437
    {
438
        return $this->_link_head;
439
    }
440
441
    /**
442
     * Init jQuery
443
     *
444
     * This method adds jQuery support to the page
445
     */
446 341
    public function enable_jquery($version = null)
447
    {
448 341
        if ($this->_jquery_enabled) {
449 341
            return;
450
        }
451
452 1
        if (!$version) {
453 1
            $version = midcom::get()->config->get('jquery_version');
454
        }
455
456 1
        $this->_jquery_init_scripts .= "\n";
457
458 1
        if (midcom::get()->config->get('jquery_load_from_google')) {
459
            // Use Google's hosted jQuery version
460
            $this->_jquery_init_scripts .= "<script src=\"http://www.google.com/jsapi\"></script>\n";
461
            $this->_jquery_init_scripts .= "<script>\n";
462
            $this->_jquery_init_scripts .= "    google.load('jquery', '{$version}');\n";
463
            $this->_jquery_init_scripts .= "</script>\n";
464
        } else {
465 1
            $url = MIDCOM_STATIC_URL . "/jQuery/jquery-{$version}.js";
466 1
            if (midcom::get()->config->get('jquery_version_oldie')) {
467 1
                $oldie_url = MIDCOM_STATIC_URL . '/jQuery/jquery-' . midcom::get()->config->get('jquery_version_oldie') . '.js';
468 1
                $this->_jquery_init_scripts .= "<!--[if lt IE 9]>\n";
469 1
                $this->_jquery_init_scripts .= "<script type=\"text/javascript\" src=\"{$oldie_url}\"></script>\n";
470 1
                $this->_jquery_init_scripts .= "<![endif]-->\n";
471 1
                $this->_jquery_init_scripts .= "<!--[if gte IE 9]><!-->\n";
472 1
                $this->_jquery_init_scripts .= "<script type=\"text/javascript\" src=\"{$url}\"></script>\n";
473 1
                $this->_jquery_init_scripts .= "<!--<![endif]-->\n";
474
            } else {
475
                $this->_jquery_init_scripts .= "<script type=\"text/javascript\" src=\"{$url}\"></script>\n";
476
            }
477
        }
478
479 1
        if (!defined('MIDCOM_JQUERY_UI_URL')) {
480 1
            define('MIDCOM_JQUERY_UI_URL', MIDCOM_STATIC_URL . "/jQuery/jquery-ui-" . midcom::get()->config->get('jquery_ui_version'));
481
        }
482
483 1
        $script  = "var MIDCOM_STATIC_URL = '" . MIDCOM_STATIC_URL . "';\n";
484 1
        $script .= "var MIDCOM_PAGE_PREFIX = '" . midcom_connection::get_url('self') . "';\n";
485
486 1
        $this->_jquery_init_scripts .= "<script type=\"text/javascript\">\n";
487 1
        $this->_jquery_init_scripts .= trim($script) . "\n";
488 1
        $this->_jquery_init_scripts .= "</script>\n";
489
490 1
        $this->_jquery_enabled = true;
491 1
    }
492
493
    /**
494
     * Echo the jquery statuses
495
     *
496
     * This function echos the scripts added by the add_jquery_state_script method.
497
     *
498
     * This method is called from print_head_elements method.
499
     *
500
     * @see add_jquery_state_script()
501
     * @see print_head_elements()
502
     */
503 7
    public function print_jquery_statuses()
504
    {
505 7
        if (empty($this->_jquery_states)) {
506 7
            return;
507
        }
508
509
        echo '<script type="text/javascript">' . "\n";
510
511
        foreach ($this->_jquery_states as $status => $scripts) {
512
            list($status_target, $status_method) = explode('.', $status);
513
            echo "\njQuery({$status_target}).{$status_method}(function() {\n";
514
            echo $scripts;
515
            echo "\n" . '});' . "\n";
516
        }
517
518
        echo '</script>' . "\n";
519
    }
520
521
    /**
522
     * Add jquery ui components
523
     *
524
     * core and widget are loaded automatically. Also loads jquery.ui theme,
525
     * either the configured theme one or a hardcoded default (base theme)
526
     *
527
     * @param array $components The components that should be loaded
528
     */
529 341
    public function enable_jquery_ui(array $components = [])
530
    {
531 341
        $this->enable_jquery();
532 341
        $this->add_jsfile(MIDCOM_JQUERY_UI_URL . '/core.min.js');
533
534 341
        foreach ($components as $component) {
535 341
            $path = $component;
536 341
            if (strpos($component, 'effect') === 0) {
537 2
                if ($component !== 'effect') {
538 2
                    $path = 'effects/' . $component;
539
                }
540
            } else {
541 341
                $path = 'widgets/' . $component;
542
            }
543
544 341
            $this->add_jsfile(MIDCOM_JQUERY_UI_URL . '/' . $path . '.min.js');
545
546 341
            if ($component == 'datepicker') {
547 45
                $lang = midcom::get()->i18n->get_current_language();
548
                /*
549
                 * The calendar doesn't have all lang files and some are named differently
550
                 * Since a missing lang file causes the calendar to break, let's make extra sure
551
                 * that this won't happen
552
                 */
553 45
                if (!file_exists(MIDCOM_STATIC_ROOT . "/jQuery/jquery-ui-" . midcom::get()->config->get('jquery_ui_version') . "/i18n/datepicker-{$lang}.min.js")) {
554 45
                    $lang = midcom::get()->i18n->get_fallback_language();
555 45
                    if (!file_exists(MIDCOM_STATIC_ROOT . "/jQuery/jquery-ui-" . midcom::get()->config->get('jquery_ui_version') . "/i18n/datepicker-{$lang}.min.js")) {
556 45
                        $lang = null;
557
                    }
558
                }
559
560 45
                if ($lang) {
561 341
                    $this->add_jsfile(MIDCOM_JQUERY_UI_URL . "/i18n/datepicker-{$lang}.min.js");
562
                }
563
            }
564
        }
565
566 341
        $this->add_stylesheet(MIDCOM_STATIC_URL . '/jQuery/jquery-ui-1.12.icon-font.min.css');
567 341
        if (midcom::get()->config->get('jquery_ui_theme')) {
568
            $this->add_stylesheet(midcom::get()->config->get('jquery_ui_theme'));
569
        } else {
570 341
            $this->add_stylesheet(MIDCOM_JQUERY_UI_URL . '/themes/base/jquery-ui.min.css');
571
        }
572 341
    }
573
}
574