Subversion-Projekte lars-tiefland.prado

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * TActiveControlAdapter and TCallbackPageStateTracker class file.
4
 *
5
 * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
6
 * @link http://www.pradosoft.com/
7
 * @copyright Copyright &copy; 2005-2008 PradoSoft
8
 * @license http://www.pradosoft.com/license/
9
 * @version $Id: TActiveControlAdapter.php 2564 2008-11-11 21:56:02Z carlgmathisen $
10
 * @package System.Web.UI.ActiveControls
11
 */
12
 
13
/*
14
 * Load common active control options.
15
 */
16
Prado::using('System.Web.UI.ActiveControls.TBaseActiveControl');
17
 
18
/**
19
 * TActiveControlAdapter class.
20
 *
21
 * Customize the parent TControl class for active control classes.
22
 * TActiveControlAdapter instantiates a common base active control class
23
 * throught the {@link getBaseActiveControl BaseActiveControl} property.
24
 * The type of BaseActiveControl can be provided in the second parameter in the
25
 * constructor. Default is TBaseActiveControl or TBaseActiveCallbackControl if
26
 * the control adapted implements ICallbackEventHandler.
27
 *
28
 * TActiveControlAdapter will tracking viewstate changes to update the
29
 * corresponding client-side properties.
30
 *
31
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
32
 * @version $Id: TActiveControlAdapter.php 2564 2008-11-11 21:56:02Z carlgmathisen $
33
 * @package System.Web.UI.ActiveControls
34
 * @since 3.1
35
 */
36
class TActiveControlAdapter extends TControlAdapter
37
{
38
	/**
39
	 * @var string base active control class name.
40
	 */
41
	private $_activeControlType;
42
	/**
43
	 * @var TBaseActiveControl base active control instance.
44
	 */
45
	private $_baseActiveControl;
46
	/**
47
	 * @var TCallbackPageStateTracker view state tracker.
48
	 */
49
	private $_stateTracker;
50
 
51
	/**
52
	 * Constructor.
53
	 * @param IActiveControl active control to adapt.
54
	 * @param string Base active control class name.
55
	 */
56
	public function __construct(IActiveControl $control, $baseCallbackClass=null)
57
	{
58
		parent::__construct($control);
59
		$this->setBaseControlClass($baseCallbackClass);
60
	}
61
 
62
	/**
63
	 * @param string base active control instance
64
	 */
65
	protected function setBaseControlClass($type)
66
	{
67
		if(is_null($type))
68
		{
69
			if($this->getControl() instanceof ICallbackEventHandler)
70
				$this->_activeControlType = 'TBaseActiveCallbackControl';
71
			else
72
				$this->_activeControlType = 'TBaseActiveControl';
73
		}
74
		else
75
			$this->_activeControlType = $type;
76
	}
77
 
78
	/**
79
	 * Renders the callback client scripts.
80
	 */
81
	public function render($writer)
82
	{
83
		$this->renderCallbackClientScripts();
84
		parent::render($writer);
85
	}
86
 
87
	/**
88
	 * Register the callback clientscripts and sets the post loader IDs.
89
	 */
90
	protected function renderCallbackClientScripts()
91
	{
92
		$cs = $this->getPage()->getClientScript();
93
		$key = 'Prado.CallbackRequest.addPostLoaders';
94
		if(!$cs->isEndScriptRegistered($key))
95
		{
96
			$cs->registerPradoScript('ajax');
97
			$data = $this->getPage()->getPostDataLoaders();
98
			if(count($data) > 0)
99
			{
100
				$options = TJavaScript::encode($data,false);
101
				$script = "Prado.CallbackRequest.addPostLoaders({$options});";
102
				$cs->registerEndScript($key, $script);
103
			}
104
		}
105
	}
106
 
107
	/**
108
	 * @param TBaseActiveControl change base active control
109
	 */
110
	public function setBaseActiveControl($control)
111
	{
112
		$this->_baseActiveControl=$control;
113
	}
114
 
115
	/**
116
	 * @return TBaseActiveControl Common active control options.
117
	 */
118
	public function getBaseActiveControl()
119
	{
120
		if(is_null($this->_baseActiveControl))
121
		{
122
			$type = $this->_activeControlType;
123
			$this->_baseActiveControl = new $type($this->getControl());
124
		}
125
		return $this->_baseActiveControl;
126
	}
127
 
128
	/**
129
	 * @return boolean true if the viewstate needs to be tracked.
130
	 */
131
	protected function getIsTrackingPageState()
132
	{
133
		if($this->getPage()->getIsCallback())
134
		{
135
			$target = $this->getPage()->getCallbackEventTarget();
136
			if($target instanceof ICallbackEventHandler)
137
			{
138
				$client = $target->getActiveControl()->getClientSide();
139
				return $client->getEnablePageStateUpdate();
140
			}
141
		}
142
		return false;
143
	}
144
 
145
	/**
146
	 * Starts viewstate tracking if necessary after when controls has been loaded
147
	 */
148
	public function onLoad($param)
149
	{
150
		if($this->getIsTrackingPageState())
151
		{
152
			$this->_stateTracker = new TCallbackPageStateTracker($this->getControl());
153
			$this->_stateTracker->trackChanges();
154
		}
155
		parent::onLoad($param);
156
	}
157
 
158
	/**
159
	 * Saves additional persistent control state. Respond to viewstate changes
160
	 * if necessary.
161
	 */
162
	public function saveState()
163
	{
164
		if(!is_null($this->_stateTracker)
165
			&& $this->getControl()->getActiveControl()->canUpdateClientSide())
166
		{
167
			$this->_stateTracker->respondToChanges();
168
		}
169
		parent::saveState();
170
	}
171
 
172
	/**
173
	 * @return TCallbackPageStateTracker state tracker.
174
	 */
175
	public function getStateTracker()
176
	{
177
		return $this->_stateTracker;
178
	}
179
}
180
 
181
/**
182
 * TCallbackPageStateTracker class.
183
 *
184
 * Tracking changes to the page state during callback.
185
 *
186
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
187
 * @version $Id: TActiveControlAdapter.php 2564 2008-11-11 21:56:02Z carlgmathisen $
188
 * @package System.Web.UI.ActiveControls
189
 * @since 3.1
190
 */
191
class TCallbackPageStateTracker
192
{
193
	/**
194
	 * @var TMap new view state data
195
	 */
196
	private $_states;
197
	/**
198
	 * @var TMap old view state data
199
	 */
200
	private $_existingState;
201
	/**
202
	 * @var TControl the control tracked
203
	 */
204
	private $_control;
205
	/**
206
	 * @var object null object.
207
	 */
208
	private $_nullObject;
209
 
210
	/**
211
	 * Constructor. Add a set of default states to track.
212
	 * @param TControl control to track.
213
	 */
214
	public function __construct($control)
215
	{
216
		$this->_control = $control;
217
		$this->_existingState = new TMap;
218
		$this->_nullObject = new stdClass;
219
		$this->_states = new TMap;
220
		$this->addStatesToTrack();
221
	}
222
 
223
	/**
224
	 * Add a list of view states to track. Each state is added
225
	 * to the StatesToTrack property with the view state name as key.
226
	 * The value should be an array with two enteries. The first entery
227
	 * is the name of the class that will calculate the state differences.
228
	 * The second entry is a php function/method callback that handles
229
	 * the changes in the viewstate.
230
	 */
231
	protected function addStatesToTrack()
232
	{
233
		$states = $this->getStatesToTrack();
234
		$states['Visible'] = array('TScalarDiff', array($this, 'updateVisible'));
235
		$states['Enabled'] = array('TScalarDiff', array($this, 'updateEnabled'));
236
		$states['Attributes'] = array('TMapCollectionDiff', array($this, 'updateAttributes'));
237
		$states['Style'] = array('TStyleDiff', array($this, 'updateStyle'));
238
		$states['TabIndex'] = array('TScalarDiff', array($this, 'updateTabIndex'));
239
		$states['ToolTip'] = array('TScalarDiff', array($this, 'updateToolTip'));
240
		$states['AccessKey'] = array('TScalarDiff', array($this, 'updateAccessKey'));
241
	}
242
 
243
	/**
244
	 * @return TMap list of viewstates to track.
245
	 */
246
	protected function getStatesToTrack()
247
	{
248
		return $this->_states;
249
	}
250
 
251
	/**
252
	 * Start tracking view state changes. The clone function on objects are called
253
	 * for those viewstate having an object as value.
254
	 */
255
	public function trackChanges()
256
	{
257
		foreach($this->_states as $name => $value)
258
		{
259
			$obj = $this->_control->getViewState($name);
260
			$this->_existingState[$name] = is_object($obj) ? clone($obj) : $obj;
261
		}
262
	}
263
 
264
	/**
265
	 * @array list of viewstate and the changed data.
266
	 */
267
	protected function getChanges()
268
	{
269
		$changes = array();
270
		foreach($this->_states as $name => $details)
271
		{
272
			$new = $this->_control->getViewState($name);
273
			$old = $this->_existingState[$name];
274
			if($new !== $old)
275
			{
276
				$diff = new $details[0]($new, $old, $this->_nullObject);
277
				if(($change = $diff->getDifference()) !== $this->_nullObject)
278
					$changes[] = array($details[1],array($change));
279
			}
280
		}
281
		return $changes;
282
	}
283
 
284
	/**
285
	 * For each of the changes call the corresponding change handlers.
286
	 */
287
	public function respondToChanges()
288
	{
289
		foreach($this->getChanges() as $change)
290
			call_user_func_array($change[0], $change[1]);
291
	}
292
 
293
	/**
294
	 * @return TCallbackClientScript callback client scripting
295
	 */
296
	protected function client()
297
	{
298
		return $this->_control->getPage()->getCallbackClient();
299
	}
300
 
301
	/**
302
	 * Updates the tooltip.
303
	 * @param string new tooltip
304
	 */
305
	protected function updateToolTip($value)
306
	{
307
		$this->client()->setAttribute($this->_control, 'title', $value);
308
	}
309
 
310
	/**
311
	 * Updates the tab index.
312
	 * @param integer tab index
313
	 */
314
	protected function updateTabIndex($value)
315
	{
316
		$this->client()->setAttribute($this->_control, 'tabindex', $value);
317
	}
318
 
319
	/**
320
	 * Updates the modifier access key
321
	 * @param string access key
322
	 */
323
	protected function updateAccessKey($value)
324
	{
325
		$this->client()->setAttribute($this->_control, 'accesskey', $value);
326
	}
327
 
328
	/**
329
	 * Hides or shows the control on the client-side. The control must be
330
	 * already rendered on the client-side.
331
	 * @param boolean true to show the control, false to hide.
332
	 */
333
	protected function updateVisible($visible)
334
	{
335
		if($visible === false)
336
			$this->client()->hide($this->_control);
337
		else
338
			$this->client()->show($this->_control);
339
	}
340
 
341
	/**
342
	 * Enables or Disables the control on the client-side.
343
	 * @param boolean true to enable the control, false to disable.
344
	 */
345
	protected function updateEnabled($enable)
346
	{
347
		$this->client()->setAttribute($this->_control, 'disabled', $enable===false);
348
	}
349
 
350
	/**
351
	 * Updates the CSS style on the control on the client-side.
352
	 * @param array list of new CSS style declarations.
353
	 */
354
	protected function updateStyle($style)
355
	{
356
		if(!is_null($style['CssClass']))
357
			$this->client()->setAttribute($this->_control, 'class', $style['CssClass']);
358
		if(count($style['Style']) > 0)
359
			$this->client()->setStyle($this->_control, $style['Style']);
360
	}
361
 
362
	/**
363
	 * Updates/adds a list of attributes on the control.
364
	 * @param array list of attribute name-value pairs.
365
	 */
366
	protected function updateAttributes($attributes)
367
	{
368
		foreach($attributes as $name => $value)
369
			$this->client()->setAttribute($this->_control, $name, $value);
370
	}
371
}
372
 
373
/**
374
 * Calculates the viewstate changes during the request.
375
 *
376
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
377
 * @version $Id: TActiveControlAdapter.php 2564 2008-11-11 21:56:02Z carlgmathisen $
378
 * @package System.Web.UI.ActiveControls
379
 * @since 3.1
380
 */
381
abstract class TViewStateDiff
382
{
383
	/**
384
	 * @var mixed updated viewstate
385
	 */
386
	protected $_new;
387
	/**
388
	 * @var mixed viewstate value at the begining of the request.
389
	 */
390
	protected $_old;
391
	/**
392
	 * @var object null value.
393
	 */
394
	protected $_null;
395
 
396
	/**
397
	 * Constructor.
398
	 * @param mixed updated viewstate value.
399
	 * @param mixed viewstate value at the begining of the request.
400
	 * @param object representing the null value.
401
	 */
402
	public function __construct($new, $old, $null)
403
	{
404
		$this->_new = $new;
405
		$this->_old = $old;
406
		$this->_null = $null;
407
	}
408
 
409
	/**
410
	 * @return mixed view state changes, nullObject if no difference.
411
	 */
412
	public abstract function getDifference();
413
}
414
 
415
/**
416
 * TScalarDiff class.
417
 *
418
 * Calculate the changes to a scalar value.
419
 *
420
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
421
 * @version $Id: TActiveControlAdapter.php 2564 2008-11-11 21:56:02Z carlgmathisen $
422
 * @package System.Web.UI.ActiveControls
423
 * @since 3.1
424
 */
425
class TScalarDiff extends TViewStateDiff
426
{
427
	/**
428
	 * @return mixed update viewstate value.
429
	 */
430
	public function getDifference()
431
	{
432
		if(gettype($this->_new) === gettype($this->_old)
433
			&& $this->_new === $this->_old)
434
			return $this->_null;
435
		else
436
			return $this->_new;
437
	}
438
}
439
 
440
/**
441
 * TStyleDiff class.
442
 *
443
 * Calculates the changes to the Style properties.
444
 *
445
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
446
 * @version $Id: TActiveControlAdapter.php 2564 2008-11-11 21:56:02Z carlgmathisen $
447
 * @package System.Web.UI.ActiveControls
448
 * @since 3.1
449
 */
450
class TStyleDiff extends TViewStateDiff
451
{
452
	/**
453
	 * @param TStyle control style
454
	 * @return array all the style properties combined.
455
	 */
456
	protected function getCombinedStyle($obj)
457
	{
458
		if(!($obj instanceof TStyle))
459
			return array();
460
		$style = $obj->getStyleFields();
461
		$style = array_merge($style,$this->getStyleFromString($obj->getCustomStyle()));
462
		if($obj->hasFont())
463
			$style = array_merge($style, $this->getStyleFromString($obj->getFont()->toString()));
464
		return $style;
465
	}
466
 
467
	/**
468
	 * @param string CSS custom style string.
469
	 * @param array CSS style as name-value array.
470
	 */
471
	protected function getStyleFromString($string)
472
	{
473
		$style = array();
474
		if(!is_string($string)) return $style;
475
 
476
		foreach(explode(';',$string) as $sub)
477
		{
478
			$arr=explode(':',$sub);
479
			if(isset($arr[1]) && trim($arr[0])!=='')
480
				$style[trim($arr[0])] = trim($arr[1]);
481
		}
482
		return $style;
483
	}
484
 
485
	/**
486
	 * @return string changes to the CSS class name.
487
	 */
488
	protected function getCssClassDiff()
489
	{
490
		if(is_null($this->_old))
491
		{
492
			return !is_null($this->_new) && $this->_new->hasCssClass()
493
						? $this->_new->getCssClass() : null;
494
		}
495
		else
496
		{
497
			return $this->_old->getCssClass() !== $this->_new->getCssClass() ?
498
				$this->_new->getCssClass() : null;
499
		}
500
	}
501
 
502
	/**
503
	 * @return array list of changes to the control style.
504
	 */
505
	protected function getStyleDiff()
506
	{
507
		$diff = array_diff_assoc(
508
					$this->getCombinedStyle($this->_new),
509
					$this->getCombinedStyle($this->_old));
510
		return count($diff) > 0 ? $diff : null;
511
	}
512
 
513
	/**
514
	 * @return array list of changes to the control style and CSS class name.
515
	 */
516
	public function getDifference()
517
	{
518
		if(is_null($this->_new))
519
			return $this->_null;
520
		else
521
		{
522
			$css = $this->getCssClassDiff();
523
			$style = $this->getStyleDiff();
524
			if(!is_null($css) || !is_null($style))
525
				return array('CssClass' => $css, 'Style' => $style);
526
			else
527
				$this->_null;
528
		}
529
	}
530
}
531
 
532
/**
533
 * TAttributesDiff class.
534
 *
535
 * Calculate the changes to attributes collection.
536
 *
537
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
538
 * @version $Id: TActiveControlAdapter.php 2564 2008-11-11 21:56:02Z carlgmathisen $
539
 * @package System.Web.UI.ActiveControls
540
 * @since 3.1
541
 */
542
class TMapCollectionDiff extends TViewStateDiff
543
{
544
	/**
545
	 * @return array updates to the attributes collection.
546
	 */
547
	public function getDifference()
548
	{
549
		if(is_null($this->_old))
550
		{
551
			return !is_null($this->_new) ? $this->_new->toArray() : $this->_null;
552
		}
553
		else
554
		{
555
			$new = $this->_new->toArray();
556
			$old = $this->_old->toArray();
557
			$diff = array_diff_assoc($new, $old);
558
			return count($diff) > 0 ? $diff : $this->_null;
559
		}
560
	}
561
}
562