Completed
Push — master ( 13c082...8b89bf )
by Thierry
01:50
created

Response::_addCommand()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
nc 4
nop 4
dl 0
loc 34
rs 8.7537
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Response.php - The Jaxon Response
5
 *
6
 * This class collects commands to be sent back to the browser in response to a jaxon request.
7
 * Commands are encoded and packaged in json format.
8
 *
9
 * Common commands include:
10
 * - <Response->assign>: Assign a value to an element's attribute.
11
 * - <Response->append>: Append a value on to an element's attribute.
12
 * - <Response->script>: Execute a portion of javascript code.
13
 * - <Response->call>: Execute an existing javascript function.
14
 * - <Response->alert>: Display an alert dialog to the user.
15
 *
16
 * Elements are identified by the value of the HTML id attribute.
17
 *
18
 * @package jaxon-core
19
 * @author Jared White
20
 * @author J. Max Wilson
21
 * @author Joseph Woolley
22
 * @author Steffen Konerow
23
 * @author Thierry Feuzeu <[email protected]>
24
 * @copyright Copyright (c) 2005-2007 by Jared White & J. Max Wilson
25
 * @copyright Copyright (c) 2008-2010 by Joseph Woolley, Steffen Konerow, Jared White  & J. Max Wilson
26
 * @copyright 2016 Thierry Feuzeu <[email protected]>
27
 * @license https://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
28
 * @link https://github.com/jaxon-php/jaxon-core
29
 */
30
31
namespace Jaxon\Response;
32
33
class Response extends AbstractResponse
34
{
35
    use \Jaxon\Features\Translator;
36
37
    /**
38
     * The commands that will be sent to the browser in the response
39
     *
40
     * @var array
41
     */
42
    private $aCommands = [];
43
44
    /**
45
     * A string, array or integer value to be returned to the caller when using 'synchronous' mode requests.
46
     * See <jaxon->setMode> for details.
47
     *
48
     * @var mixed
49
     */
50
    private $returnValue;
51
52
    /**
53
     * Get the content type, which is always set to 'application/json'
54
     *
55
     * @return string
56
     */
57
    public function getContentType()
58
    {
59
        return 'application/json';
60
    }
61
62
    /**
63
     * Provides access to registered response plugins
64
     *
65
     * Pass the plugin name as the first argument and the plugin object will be returned.
66
     *
67
     * @param string        $sName                The name of the plugin
68
     *
69
     * @return null|\Jaxon\Plugin\Response
70
     */
71
    public function plugin($sName)
72
    {
73
        $xPlugin = jaxon()->di()->getPluginManager()->getResponsePlugin($sName);
74
        if(!$xPlugin)
75
        {
76
            return null;
77
        }
78
        $xPlugin->setResponse($this);
79
        return $xPlugin;
80
    }
81
82
    /**
83
     * Create a JQuery Element with a given selector, and link it to the current response.
84
     *
85
     * This is a shortcut to the JQuery plugin.
86
     *
87
     * @param string        $sSelector            The jQuery selector
88
     * @param string        $sContext             A context associated to the selector
89
     *
90
     * @return Jaxon\Response\Plugin\JQuery\Dom\Element
91
     */
92
    public function jq($sSelector = '', $sContext = '')
93
    {
94
        return $this->plugin('jquery')->element($sSelector, $sContext);
95
    }
96
97
    /**
98
     * Create a JQuery Element with a given selector, and link it to the current response.
99
     *
100
     * This is a shortcut to the JQuery plugin.
101
     *
102
     * @param string        $sSelector            The jQuery selector
103
     * @param string        $sContext             A context associated to the selector
104
     *
105
     * @return Jaxon\Response\Plugin\JQuery\Dom\Element
106
     */
107
    public function jQuery($sSelector = '', $sContext = '')
108
    {
109
        return $this->jq($sSelector, $sContext);
110
    }
111
112
    /**
113
     * Magic PHP function
114
     *
115
     * Used to permit plugins to be called as if they where native members of the Response instance.
116
     *
117
     * @param string        $sPluginName        The name of the plugin
118
     *
119
     * @return \Jaxon\Plugin\Response
120
     */
121
    public function __get($sPluginName)
122
    {
123
        return $this->plugin($sPluginName);
124
    }
125
126
    /**
127
     * Add a response command to the array of commands that will be sent to the browser
128
     *
129
     * @param array         $aAttributes        Associative array of attributes that will describe the command
130
     * @param mixed            $mData                The data to be associated with this command
131
     *
132
     * @return AbstractResponse
133
     */
134
    public function addCommand($aAttributes, $mData)
135
    {
136
        /* merge commands if possible */
137
        if(in_array($aAttributes['cmd'], ['js', 'ap']))
138
        {
139
            if(($aLastCommand = array_pop($this->aCommands)))
140
            {
141
                if($aLastCommand['cmd'] == $aAttributes['cmd'])
142
                {
143
                    if($this->getOption('core.response.merge.js') &&
144
                            $aLastCommand['cmd'] == 'js')
145
                    {
146
                        $mData = $aLastCommand['data'] . '; ' . $mData;
147
                    }
148
                    elseif($this->getOption('core.response.merge.ap') &&
149
                            $aLastCommand['cmd'] == 'ap' &&
150
                            $aLastCommand['id'] == $aAttributes['id'] &&
151
                            $aLastCommand['prop'] == $aAttributes['prop'])
152
                    {
153
                        $mData = $aLastCommand['data'] . ' ' . $mData;
154
                    }
155
                    else
156
                    {
157
                        $this->aCommands[] = $aLastCommand;
158
                    }
159
                }
160
                else
161
                {
162
                    $this->aCommands[] = $aLastCommand;
163
                }
164
            }
165
        }
166
        $aAttributes['data'] = $mData;
167
        $this->aCommands[] = $aAttributes;
168
169
        return $this;
170
    }
171
    /**
172
     * Add a response command to the array of commands that will be sent to the browser
173
     *
174
     * @param string        $sName              The command name
175
     * @param array         $aAttributes        Associative array of attributes that will describe the command
176
     * @param mixed         $mData              The data to be associated with this command
177
     * @param boolean       $bRemoveEmpty       Remove empty attributes
178
     *
179
     * @return AbstractResponse
180
     */
181
    private function _addCommand($sName, array $aAttributes, $mData, $bRemoveEmpty = false)
182
    {
183
        array_walk($aAttributes, function(&$sAttribute) {
184
            if(!is_integer($sAttribute))
185
            {
186
                $sAttribute = trim((string)$sAttribute, " \t");
187
            }
188
        });
189
190
        if(is_array($mData))
191
        {
192
            array_walk($mData, function(&$sData) {
193
                $sData = trim((string)$sData, " \t\n");
194
            });
195
        }
196
        else
197
        {
198
            $mData = trim((string)$mData, " \t\n");
199
        }
200
201
        if($bRemoveEmpty)
202
        {
203
            foreach(array_keys($aAttributes) as $sAttr)
204
            {
205
                if($aAttributes[$sAttr] === '')
206
                {
207
                    unset($aAttributes[$sAttr]);
208
                }
209
            }
210
        }
211
212
        $aAttributes['cmd'] = $sName;
213
        $this->addCommand($aAttributes, $mData);
214
    }
215
216
    /**
217
     * Clear all the commands already added to the response
218
     *
219
     * @return Response
220
     */
221
    public function clearCommands()
222
    {
223
        $this->aCommands[] = [];
224
225
        return $this;
226
    }
227
228
    /**
229
     * Add a response command that is generated by a plugin
230
     *
231
     * @param \Jaxon\Plugin\Plugin  $xPlugin            The plugin object
232
     * @param array                 $aAttributes        The attributes for this response command
233
     * @param string                 $mData              The data to be sent with this command
234
     *
235
     * @return Response
236
     */
237
    public function addPluginCommand($xPlugin, $aAttributes, $mData)
238
    {
239
        $aAttributes['plg'] = $xPlugin->getName();
240
        return $this->addCommand($aAttributes, $mData);
241
    }
242
243
    /**
244
     * Merge the response commands from the specified <Response> object with
245
     * the response commands in this <Response> object
246
     *
247
     * @param AbstractResponse  $mCommands          The <Response> object
248
     * @param boolean           $bBefore            Add the new commands to the beginning of the list
249
     *
250
     * @return void
251
     */
252
    public function appendResponse(AbstractResponse $mCommands, $bBefore = false)
253
    {
254
        $aCommands = [];
255
        if($mCommands instanceof Response)
256
        {
257
            $this->returnValue = $mCommands->returnValue;
258
            $aCommands = $mCommands->aCommands;
259
        }
260
        elseif(is_array($mCommands))
261
        {
262
            $aCommands = $mCommands;
263
        }
264
        else
265
        {
266
            if(!empty($mCommands))
267
            {
268
                throw new \Jaxon\Exception\Error($this->trans('errors.response.data.invalid'));
269
            }
270
        }
271
272
        if(count($aCommands) > 0)
273
        {
274
            if($bBefore)
275
            {
276
                $this->aCommands = array_merge($aCommands, $this->aCommands);
277
            }
278
            else
279
            {
280
                $this->aCommands = array_merge($this->aCommands, $aCommands);
281
            }
282
        }
283
    }
284
285
    /**
286
     * Response command that prompts user with [ok] [cancel] style message box
287
     *
288
     * If the user clicks cancel, the specified number of response commands
289
     * following this one, will be skipped.
290
     *
291
     * @param integer        $iCmdNumber            The number of commands to skip upon cancel
292
     * @param string        $sMessage            The message to display to the user
293
     *
294
     * @return Response
295
     */
296
    public function confirmCommands($iCmdNumber, $sMessage)
297
    {
298
        $aAttributes = ['id' => $iCmdNumber];
299
        return $this->_addCommand('cc', $aAttributes, $sMessage);
300
    }
301
302
    /**
303
     * Add a command to assign the specified value to the given element's attribute
304
     *
305
     * @param string        $sTarget              The id of the html element on the browser
306
     * @param string        $sAttribute           The attribute to be assigned
307
     * @param string        $sData                The value to be assigned to the attribute
308
     *
309
     * @return Response
310
     */
311
    public function assign($sTarget, $sAttribute, $sData)
312
    {
313
        $aAttributes = [
314
            'id' => $sTarget,
315
            'prop' => $sAttribute
316
        ];
317
        return $this->_addCommand('as', $aAttributes, $sData);
318
    }
319
320
    /**
321
     * Add a command to assign the specified HTML content to the given element
322
     *
323
     * This is a shortcut for assign() on the innerHTML attribute.
324
     *
325
     * @param string        $sTarget              The id of the html element on the browser
326
     * @param string        $sData                The value to be assigned to the attribute
327
     *
328
     * @return Response
329
     */
330
    public function html($sTarget, $sData)
331
    {
332
        return $this->assign($sTarget, 'innerHTML', $sData);
333
    }
334
335
    /**
336
     * Add a command to append the specified data to the given element's attribute
337
     *
338
     * @param string        $sTarget            The id of the element to be updated
339
     * @param string        $sAttribute            The name of the attribute to be appended to
340
     * @param string        $sData                The data to be appended to the attribute
341
     *
342
     * @return Response
343
     */
344
    public function append($sTarget, $sAttribute, $sData)
345
    {
346
        $aAttributes = [
347
            'id' => $sTarget,
348
            'prop' => $sAttribute
349
        ];
350
        return $this->_addCommand('ap', $aAttributes, $sData);
351
    }
352
353
    /**
354
     * Add a command to prepend the specified data to the given element's attribute
355
     *
356
     * @param string        $sTarget            The id of the element to be updated
357
     * @param string        $sAttribute            The name of the attribute to be prepended to
358
     * @param string        $sData                The value to be prepended to the attribute
359
     *
360
     * @return Response
361
     */
362
    public function prepend($sTarget, $sAttribute, $sData)
363
    {
364
        $aAttributes = [
365
            'id' => $sTarget,
366
            'prop' => $sAttribute
367
        ];
368
        return $this->_addCommand('pp', $aAttributes, $sData);
369
    }
370
371
    /**
372
     * Add a command to replace a specified value with another value within the given element's attribute
373
     *
374
     * @param string        $sTarget            The id of the element to update
375
     * @param string        $sAttribute            The attribute to be updated
376
     * @param string        $sSearch            The needle to search for
377
     * @param string        $sData                The data to use in place of the needle
378
     *
379
     * @return Response
380
     */
381
    public function replace($sTarget, $sAttribute, $sSearch, $sData)
382
    {
383
        $aAttributes = [
384
            'id' => $sTarget,
385
            'prop' => $sAttribute
386
        ];
387
        $aData = [
388
            's' => $sSearch,
389
            'r' => $sData
390
        ];
391
        return $this->_addCommand('rp', $aAttributes, $aData);
392
    }
393
394
    /**
395
     * Add a command to clear the specified attribute of the given element
396
     *
397
     * @param string        $sTarget            The id of the element to be updated.
398
     * @param string        $sAttribute            The attribute to be cleared
399
     *
400
     * @return Response
401
     */
402
    public function clear($sTarget, $sAttribute)
403
    {
404
        return $this->assign($sTarget, $sAttribute, '');
405
    }
406
407
    /**
408
     * Add a command to assign a value to a member of a javascript object (or element)
409
     * that is specified by the context member of the request
410
     *
411
     * The object is referenced using the 'this' keyword in the sAttribute parameter.
412
     *
413
     * @param string        $sAttribute            The attribute to be updated
414
     * @param string        $sData                The value to assign
415
     *
416
     * @return Response
417
     */
418
    public function contextAssign($sAttribute, $sData)
419
    {
420
        $aAttributes = ['prop' => $sAttribute];
421
        return $this->_addCommand('c:as', $aAttributes, $sData);
422
    }
423
424
    /**
425
     * Add a command to append a value onto the specified member of the javascript
426
     * context object (or element) specified by the context member of the request
427
     *
428
     * The object is referenced using the 'this' keyword in the sAttribute parameter.
429
     *
430
     * @param string        $sAttribute            The attribute to be appended to
431
     * @param string        $sData                The value to append
432
     *
433
     * @return Response
434
     */
435
    public function contextAppend($sAttribute, $sData)
436
    {
437
        $aAttributes = ['prop' => $sAttribute];
438
        return $this->_addCommand('c:ap', $aAttributes, $sData);
439
    }
440
441
    /**
442
     * Add a command to prepend the speicified data to the given member of the current
443
     * javascript object specified by context in the current request
444
     *
445
     * The object is access via the 'this' keyword in the sAttribute parameter.
446
     *
447
     * @param string        $sAttribute            The attribute to be updated
448
     * @param string        $sData                The value to be prepended
449
     *
450
     * @return Response
451
     */
452
    public function contextPrepend($sAttribute, $sData)
453
    {
454
        $aAttributes = ['prop' => $sAttribute];
455
        return $this->_addCommand('c:pp', $aAttributes, $sData);
456
    }
457
458
    /**
459
     * Add a command to to clear the value of the attribute specified in the sAttribute parameter
460
     *
461
     * The member is access via the 'this' keyword and can be used to update a javascript
462
     * object specified by context in the request parameters.
463
     *
464
     * @param string        $sAttribute            The attribute to be cleared
465
     *
466
     * @return Response
467
     */
468
    public function contextClear($sAttribute)
469
    {
470
        return $this->contextAssign($sAttribute, '');
471
    }
472
473
    /**
474
     * Add a command to display an alert message to the user
475
     *
476
     * @param string        $sMessage            The message to be displayed
477
     *
478
     * @return Response
479
     */
480
    public function alert($sMessage)
481
    {
482
        return $this->_addCommand('al', [], $sMessage);
483
    }
484
485
    /**
486
     * Add a command to display a debug message to the user
487
     *
488
     * @param string        $sMessage            The message to be displayed
489
     *
490
     * @return Response
491
     */
492
    public function debug($sMessage)
493
    {
494
        return $this->_addCommand('dbg', [], $sMessage);
495
    }
496
497
    /**
498
     * Add a command to ask the browser to navigate to the specified URL
499
     *
500
     * @param string        $sURL                The relative or fully qualified URL
501
     * @param integer        $iDelay                Number of seconds to delay before the redirect occurs
502
     *
503
     * @return Response
504
     */
505
    public function redirect($sURL, $iDelay = 0)
506
    {
507
        // we need to parse the query part so that the values are rawurlencode()'ed
508
        // can't just use parse_url() cos we could be dealing with a relative URL which
509
        // parse_url() can't deal with.
510
        $queryStart = strpos($sURL, '?', strrpos($sURL, '/'));
511
        if($queryStart !== false)
512
        {
513
            $queryStart++;
514
            $queryEnd = strpos($sURL, '#', $queryStart);
515
            if($queryEnd === false)
516
                $queryEnd = strlen($sURL);
517
            $queryPart = substr($sURL, $queryStart, $queryEnd - $queryStart);
518
            parse_str($queryPart, $queryParts);
519
            $newQueryPart = "";
520
            if($queryParts)
521
            {
522
                $first = true;
523
                foreach($queryParts as $key => $value)
524
                {
525
                    if($first)
526
                        $first = false;
527
                    else
528
                        $newQueryPart .= '&';
529
                    $newQueryPart .= rawurlencode($key) . '=' . rawurlencode($value);
530
                }
531
            } elseif($_SERVER['QUERY_STRING']) {
532
                    //couldn't break up the query, but there's one there
533
                    //possibly "http://url/page.html?query1234" type of query?
534
                    //just encode it and hope it works
535
                    $newQueryPart = rawurlencode($_SERVER['QUERY_STRING']);
536
                }
537
            $sURL = str_replace($queryPart, $newQueryPart, $sURL);
538
        }
539
        if($iDelay)
540
            $this->script('window.setTimeout("window.location = \'' . $sURL . '\';",' . ($iDelay * 1000) . ');');
541
        else
542
            $this->script('window.location = "' . $sURL . '";');
543
        return $this;
544
    }
545
546
    /**
547
     * Add a command to execute a portion of javascript on the browser
548
     *
549
     * The script runs in it's own context, so variables declared locally, using the 'var' keyword,
550
     * will no longer be available after the call.
551
     * To construct a variable that will be accessable globally, even after the script has executed,
552
     * leave off the 'var' keyword.
553
     *
554
     * @param string        $sJS                The script to execute
555
     *
556
     * @return Response
557
     */
558
    public function script($sJS)
559
    {
560
        return $this->_addCommand('js', [], $sJS);
561
    }
562
563
    /**
564
     * Add a command to call the specified javascript function with the given (optional) parameters
565
     *
566
     * @param string        $sFunc                The name of the function to call
567
     *
568
     * @return Response
569
     */
570
    public function call($sFunc)
571
    {
572
        $aArgs = func_get_args();
573
        array_shift($aArgs);
574
        $aAttributes = ['cmd' => 'jc', 'func' => $sFunc];
575
        return $this->addCommand($aAttributes, $aArgs);
576
    }
577
578
    /**
579
     * Add a command to remove an element from the document
580
     *
581
     * @param string        $sTarget            The id of the element to be removed
582
     *
583
     * @return Response
584
     */
585
    public function remove($sTarget)
586
    {
587
        $aAttributes = ['id' => $sTarget];
588
        return $this->_addCommand('rm', $aAttributes, '');
589
    }
590
591
    /**
592
     * Add a command to create a new element on the browser
593
     *
594
     * @param string        $sParent            The id of the parent element
595
     * @param string        $sTag                The tag name to be used for the new element
596
     * @param string        $sId                The id to assign to the new element
597
     *
598
     * @return Response
599
     */
600
    public function create($sParent, $sTag, $sId)
601
    {
602
        $aAttributes = [
603
            'id' => $sParent,
604
            'prop' => $sId
605
        ];
606
        return $this->_addCommand('ce', $aAttributes, $sTag);
607
    }
608
609
    /**
610
     * Add a command to insert a new element just prior to the specified element
611
     *
612
     * @param string        $sBefore            The id of the element used as a reference point for the insertion
613
     * @param string        $sTag               The tag name to be used for the new element
614
     * @param string        $sId                The id to assign to the new element
615
     *
616
     * @return Response
617
     */
618
    public function insert($sBefore, $sTag, $sId)
619
    {
620
        $aAttributes = [
621
            'id' => $sBefore,
622
            'prop' => $sId
623
        ];
624
        return $this->_addCommand('ie', $aAttributes, $sTag);
625
    }
626
627
    /**
628
     * Add a command to insert a new element after the specified
629
     *
630
     * @param string        $sAfter             The id of the element used as a reference point for the insertion
631
     * @param string        $sTag               The tag name to be used for the new element
632
     * @param string        $sId                The id to assign to the new element
633
     *
634
     * @return Response
635
     */
636
    public function insertAfter($sAfter, $sTag, $sId)
637
    {
638
        $aAttributes = [
639
            'id' => $sAfter,
640
            'prop' => $sId
641
        ];
642
        return $this->_addCommand('ia', $aAttributes, $sTag);
643
    }
644
645
    /**
646
     * Add a command to create an input element on the browser
647
     *
648
     * @param string        $sParent            The id of the parent element
649
     * @param string        $sType                The type of the new input element
650
     * @param string        $sName                The name of the new input element
651
     * @param string        $sId                The id of the new element
652
     *
653
     * @return Response
654
     */
655
    public function createInput($sParent, $sType, $sName, $sId)
656
    {
657
        $aAttributes = [
658
            'id' => $sParent,
659
            'prop' => $sId,
660
            'type' => $sType
661
        ];
662
        return $this->_addCommand('ci', $aAttributes, $sName);
663
    }
664
665
    /**
666
     * Add a command to insert a new input element preceding the specified element
667
     *
668
     * @param string        $sBefore            The id of the element to be used as the reference point for the insertion
669
     * @param string        $sType                The type of the new input element
670
     * @param string        $sName                The name of the new input element
671
     * @param string        $sId                The id of the new element
672
     *
673
     * @return Response
674
     */
675
    public function insertInput($sBefore, $sType, $sName, $sId)
676
    {
677
        $aAttributes = [
678
            'id' => $sBefore,
679
            'prop' => $sId,
680
            'type' => $sType
681
        ];
682
        return $this->_addCommand('ii', $aAttributes, $sName);
683
    }
684
685
    /**
686
     * Add a command to insert a new input element after the specified element
687
     *
688
     * @param string        $sAfter                The id of the element to be used as the reference point for the insertion
689
     * @param string        $sType                The type of the new input element
690
     * @param string        $sName                The name of the new input element
691
     * @param string        $sId                The id of the new element
692
     *
693
     * @return Response
694
     */
695
    public function insertInputAfter($sAfter, $sType, $sName, $sId)
696
    {
697
        $aAttributes = [
698
            'id' => $sAfter,
699
            'prop' => $sId,
700
            'type' => $sType
701
        ];
702
        return $this->_addCommand('iia', $aAttributes, $sName);
703
    }
704
705
    /**
706
     * Add a command to set an event handler on the browser
707
     *
708
     * @param string        $sTarget            The id of the element that contains the event
709
     * @param string        $sEvent                The name of the event
710
     * @param string        $sScript            The javascript to execute when the event is fired
711
     *
712
     * @return Response
713
     */
714
    public function setEvent($sTarget, $sEvent, $sScript)
715
    {
716
        $aAttributes = [
717
            'id' => $sTarget,
718
            'prop' => $sEvent
719
        ];
720
        return $this->_addCommand('ev', $aAttributes, $sScript);
721
    }
722
723
    /**
724
     * Add a command to set a click handler on the browser
725
     *
726
     * @param string        $sTarget            The id of the element that contains the event
727
     * @param string        $sScript            The javascript to execute when the event is fired
728
     *
729
     * @return Response
730
     */
731
    public function onClick($sTarget, $sScript)
732
    {
733
        return $this->setEvent($sTarget, 'onclick', $sScript);
734
    }
735
736
    /**
737
     * Add a command to install an event handler on the specified element
738
     *
739
     * You can add more than one event handler to an element's event using this method.
740
     *
741
     * @param string        $sTarget             The id of the element
742
     * @param string        $sEvent              The name of the event
743
     * @param string        $sHandler            The name of the javascript function to call when the event is fired
744
     *
745
     * @return Response
746
     */
747
    public function addHandler($sTarget, $sEvent, $sHandler)
748
    {
749
        $aAttributes = [
750
            'id' => $sTarget,
751
            'prop' => $sEvent
752
        ];
753
        return $this->_addCommand('ah', $aAttributes, $sHandler);
754
    }
755
756
    /**
757
     * Add a command to remove an event handler from an element
758
     *
759
     * @param string        $sTarget             The id of the element
760
     * @param string        $sEvent              The name of the event
761
     * @param string        $sHandler            The name of the javascript function called when the event is fired
762
     *
763
     * @return Response
764
     */
765
    public function removeHandler($sTarget, $sEvent, $sHandler)
766
    {
767
        $aAttributes = [
768
            'id' => $sTarget,
769
            'prop' => $sEvent
770
        ];
771
        return $this->_addCommand('rh', $aAttributes, $sHandler);
772
    }
773
774
    /**
775
     * Add a command to construct a javascript function on the browser
776
     *
777
     * @param string        $sFunction            The name of the function to construct
778
     * @param string        $sArgs                Comma separated list of parameter names
779
     * @param string        $sScript            The javascript code that will become the body of the function
780
     *
781
     * @return Response
782
     */
783
    public function setFunction($sFunction, $sArgs, $sScript)
784
    {
785
        $aAttributes = [
786
            'func' => $sFunction,
787
            'prop' => $sArgs
788
        ];
789
        return $this->_addCommand('sf', $aAttributes, $sScript);
790
    }
791
792
    /**
793
     * Add a command to construct a wrapper function around an existing javascript function on the browser
794
     *
795
     * @param string        $sFunction            The name of the existing function to wrap
796
     * @param string        $sArgs                The comma separated list of parameters for the function
797
     * @param array            $aScripts            An array of javascript code snippets that will be used to build
798
     *                                             the body of the function
799
     *                                             The first piece of code specified in the array will occur before
800
     *                                             the call to the original function, the second will occur after
801
     *                                             the original function is called.
802
     * @param string        $sReturnValueVar    The name of the variable that will retain the return value
803
     *                                             from the call to the original function
804
     *
805
     * @return Response
806
     */
807
    public function wrapFunction($sFunction, $sArgs, $aScripts, $sReturnValueVar)
808
    {
809
        $aAttributes = [
810
            'cmd' => 'wpf',
811
            'func' => $sFunction,
812
            'prop' => $sArgs,
813
            'type' => $sReturnValueVar
814
        ];
815
        return $this->addCommand($aAttributes, $aScripts);
816
    }
817
818
    /**
819
     * Add a command to load a javascript file on the browser
820
     *
821
     * @param string        $sFileName            The relative or fully qualified URI of the javascript file
822
     * @param string        $sType                Determines the script type. Defaults to 'text/javascript'
823
     *
824
     * @return Response
825
     */
826 View Code Duplication
    public function includeScript($sFileName, $sType = '', $sId = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
827
    {
828
        $command = [
829
            'type' => $sType,
830
            'elm_id' => $sId
831
        ];
832
        return $this->_addCommand('in', $command, $sFileName, true);
833
    }
834
835
    /**
836
     * Add a command to include a javascript file on the browser if it has not already been loaded
837
     *
838
     * @param string        $sFileName            The relative or fully qualified URI of the javascript file
839
     * @param string        $sType                Determines the script type. Defaults to 'text/javascript'
840
     *
841
     * @return Response
842
     */
843 View Code Duplication
    public function includeScriptOnce($sFileName, $sType = '', $sId = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
844
    {
845
        $command = [
846
            'type' => $sType,
847
            'elm_id' => $sId
848
        ];
849
        return $this->_addCommand('ino', $command, $sFileName, true);
850
    }
851
852
    /**
853
     * Add a command to remove a SCRIPT reference to a javascript file on the browser
854
     *
855
     * Optionally, you can call a javascript function just prior to the file being unloaded (for cleanup).
856
     *
857
     * @param string        $sFileName            The relative or fully qualified URI of the javascript file
858
     * @param string        $sUnload            Name of a javascript function to call prior to unlaoding the file
859
     *
860
     * @return Response
861
     */
862
    public function removeScript($sFileName, $sUnload = '')
863
    {
864
        $aAttributes = ['unld' => $sUnload];
865
        return $this->_addCommand('rjs', $aAttributes, $sFileName, true);
866
    }
867
868
    /**
869
     * Add a command to include a LINK reference to the specified CSS file on the browser.
870
     *
871
     * This will cause the browser to load and apply the style sheet.
872
     *
873
     * @param string        $sFileName            The relative or fully qualified URI of the css file
874
     * @param string        $sMedia                The media type of the CSS file. Defaults to 'screen'
875
     *
876
     * @return Response
877
     */
878
    public function includeCSS($sFileName, $sMedia = '')
879
    {
880
        $command = ['media' => $sMedia];
881
        return $this->_addCommand('css', $command, $sFileName, true);
882
    }
883
884
    /**
885
     * Add a command to remove a LINK reference to a CSS file on the browser
886
     *
887
     * This causes the browser to unload the style sheet, effectively removing the style changes it caused.
888
     *
889
     * @param string        $sFileName            The relative or fully qualified URI of the css file
890
     *
891
     * @return Response
892
     */
893
    public function removeCSS($sFileName, $sMedia = '')
894
    {
895
        $command = ['media' => $sMedia];
896
        return $this->_addCommand('rcss', $command, $sFileName, true);
897
    }
898
899
    /**
900
     * Add a command to make Jaxon pause while the CSS files are loaded
901
     *
902
     * The browser is not typically a multi-threading application, with regards to javascript code.
903
     * Therefore, the CSS files included or removed with <Response->includeCSS> and
904
     * <Response->removeCSS> respectively, will not be loaded or removed until the browser regains
905
     * control from the script.
906
     * This command returns control back to the browser and pauses the execution of the response
907
     * until the CSS files, included previously, are loaded.
908
     *
909
     * @param integer        $iTimeout            The number of 1/10ths of a second to pause before timing out
910
     *                                             and continuing with the execution of the response commands
911
     *
912
     * @return Response
913
     */
914
    public function waitForCSS($iTimeout = 600)
915
    {
916
        $aAttributes = ['cmd' => 'wcss', 'prop' => $iTimeout];
917
        return $this->addCommand($aAttributes, '');
918
    }
919
920
    /**
921
     * Add a command to make Jaxon to delay execution of the response commands until a specified condition is met
922
     *
923
     * Note, this returns control to the browser, so that other script operations can execute.
924
     * Jaxon will continue to monitor the specified condition and, when it evaulates to true,
925
     * will continue processing response commands.
926
     *
927
     * @param string        $script                A piece of javascript code that evaulates to true or false
928
     * @param integer        $tenths                The number of 1/10ths of a second to wait before timing out
929
     *                                             and continuing with the execution of the response commands.
930
     *
931
     * @return Response
932
     */
933
    public function waitFor($script, $tenths)
934
    {
935
        $aAttributes = ['cmd' => 'wf', 'prop' => $tenths];
936
        return $this->addCommand($aAttributes, $script);
937
    }
938
939
    /**
940
     * Add a command to make Jaxon to pause execution of the response commands,
941
     * returning control to the browser so it can perform other commands asynchronously.
942
     *
943
     * After the specified delay, Jaxon will continue execution of the response commands.
944
     *
945
     * @param integer        $tenths                The number of 1/10ths of a second to sleep
946
     *
947
     * @return Response
948
     */
949
    public function sleep($tenths)
950
    {
951
        $aAttributes = ['cmd' =>'s', 'prop' => $tenths];
952
        return $this->addCommand($aAttributes, '');
953
    }
954
955
    /**
956
     * Add a command to start a DOM response
957
     *
958
     * @return Response
959
     */
960
    public function domStartResponse()
961
    {
962
        $this->script('jxnElm = []');
963
    }
964
965
    /**
966
     * Add a command to create a DOM element
967
     *
968
     * @param string        $variable            The DOM element name (id or class)
969
     * @param string        $tag                The HTML tag of the new DOM element
970
     *
971
     * @return Response
972
     */
973
    public function domCreateElement($variable, $tag)
974
    {
975
        $aAttributes = ['tgt' => $variable];
976
        return $this->_addCommand('DCE', $aAttributes, $tag);
977
    }
978
979
    /**
980
     * Add a command to set an attribute on a DOM element
981
     *
982
     * @param string        $variable            The DOM element name (id or class)
983
     * @param string        $key                The name of the attribute
984
     * @param string        $value                The value of the attribute
985
     *
986
     * @return Response
987
     */
988
    public function domSetAttribute($variable, $key, $value)
989
    {
990
        $aAttributes = [
991
            'tgt' => $variable,
992
            'key' => $key
993
        ];
994
        return $this->_addCommand('DSA', $aAttributes, $value);
995
    }
996
997
    /**
998
     * Add a command to remove children from a DOM element
999
     *
1000
     * @param string        $parent                The DOM parent element
1001
     * @param string        $skip                The ??
1002
     * @param string        $remove                The ??
1003
     *
1004
     * @return Response
1005
     */
1006
    public function domRemoveChildren($parent, $skip = '', $remove = '')
1007
    {
1008
        $command = [
1009
            'skip' => $skip,
1010
            'remove' => $remove
1011
        ];
1012
        return $this->_addCommand('DRC', $command, $parent, true);
1013
    }
1014
1015
    /**
1016
     * Add a command to append a child to a DOM element
1017
     *
1018
     * @param string        $parent                The DOM parent element
1019
     * @param string        $variable            The DOM element name (id or class)
1020
     *
1021
     * @return Response
1022
     */
1023
    public function domAppendChild($parent, $variable)
1024
    {
1025
        $aAttributes = ['par' => $parent];
1026
        return $this->_addCommand('DAC', $aAttributes, $variable);
1027
    }
1028
1029
    /**
1030
     * Add a command to insert a DOM element before another
1031
     *
1032
     * @param string        $target                The DOM target element
1033
     * @param string        $variable            The DOM element name (id or class)
1034
     *
1035
     * @return Response
1036
     */
1037
    public function domInsertBefore($target, $variable)
1038
    {
1039
        $aAttributes = ['tgt' => $target];
1040
        return $this->_addCommand('DIB', $aAttributes, $variable);
1041
    }
1042
1043
    /**
1044
     * Add a command to insert a DOM element after another
1045
     *
1046
     * @param string        $target                The DOM target element
1047
     * @param string        $variable            The DOM element name (id or class)
1048
     *
1049
     * @return Response
1050
     */
1051
    public function domInsertAfter($target, $variable)
1052
    {
1053
        $aAttributes = ['tgt' => $target];
1054
        return $this->_addCommand('DIA', $aAttributes, $variable);
1055
    }
1056
1057
    /**
1058
     * Add a command to append a text to a DOM element
1059
     *
1060
     * @param string        $parent                The DOM parent element
1061
     * @param string        $text                The HTML text to append
1062
     *
1063
     * @return Response
1064
     */
1065
    public function domAppendText($parent, $text)
1066
    {
1067
        $aAttributes = ['par' => $parent];
1068
        return $this->_addCommand('DAT', $aAttributes, $text);
1069
    }
1070
1071
    /**
1072
     * Add a command to end a DOM response
1073
     *
1074
     * @return Response
1075
     */
1076
    public function domEndResponse()
1077
    {
1078
        $this->script('jxnElm = []');
1079
    }
1080
1081
    /**
1082
     * Get the number of commands in the response
1083
     *
1084
     * @return integer
1085
     */
1086
    public function getCommandCount()
1087
    {
1088
        return count($this->aCommands);
1089
    }
1090
1091
    /**
1092
     * Stores a value that will be passed back as part of the response
1093
     *
1094
     * When making synchronous requests, the calling javascript can obtain this value
1095
     * immediately as the return value of the <jaxon.call> javascript function
1096
     *
1097
     * @param mixed        $value                Any value
1098
     *
1099
     * @return Response
1100
     */
1101
    public function setReturnValue($value)
1102
    {
1103
        $this->returnValue = $value;
1104
        return $this;
1105
    }
1106
1107
    /**
1108
     * Return the output, generated from the commands added to the response, that will be sent to the browser
1109
     *
1110
     * @return string
1111
     */
1112
    public function getOutput()
1113
    {
1114
        $response = [];
1115
1116
        if(($this->returnValue))
1117
        {
1118
            $response['jxnrv'] = $this->returnValue;
1119
        }
1120
        $response['jxnobj'] = [];
1121
1122
        foreach($this->aCommands as $xCommand)
1123
        {
1124
            $response['jxnobj'][] = $xCommand;
1125
        }
1126
1127
        return json_encode($response);
1128
    }
1129
}
1130