Completed
Push — master ( 8b89bf...9b4408 )
by Thierry
01:58
created

Response::domInsertBefore()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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