1 <?php
2 /*
3 The Relation widget is used in forms, where the User can choose
4 between a selection of model elements, that this models belongs to.
5
6 It is able to handle BELONGS_TO, HAS_ONE and MANY_MANY Relations. The Relation
7 type is detected automatically from the Model 'relations()' section.
8
9 The Widget has different styles in which it can render the possible choices.
10 Use the 'style' option to set the appropriate style.
11
12 The following example shows how to use Relation with a minimal config,
13 assuming we have a Model "Post" and "User", where one User belongs
14 to a Post:
15
16 <pre>
17 $this->widget('application.components.Relation', array(
18 'model' => 'Post',
19 'relation' => 'user'
20 'fields' => 'username' // show the field "username" of the parent element
21 ));
22 </pre>
23
24 Results in a drop down list in which the user can choose between
25 all available Users in the Database. The shown field of the
26 Table "User" is "username" in this example.
27
28 You can choose the Style of your Widget in the 'style' option.
29 Note that a Many_Many Relation always gets rendered as a Listbox,
30 since you can select multiple Elements.
31
32 'fields' can be an array or an string.
33 If you pass an array to 'fields', the Widget will display every field in
34 this array. If you want to show further sub-relations, separate the values
35 with '.', for example: 'fields' => 'array('parent.grandparent.description')
36
37 Optional Parameters:
38
39 You can use 'field' => 'post_userid' if the field in the model
40 that represents the foreign model is called different than in the
41 relation
42
43 Use 'relatedPk' => 'id_of_user' if the primary Key of the Foreign
44 Model differs from the one given in the relation.
45
46 Normally you shouldn´t use this fields cause the Widget get the relations
47 automatically from the relation.
48
49 Use 'allowEmpty' to let the user be able to choose no parent. If you
50 set this to a string, this string will be displayed with the available
51 choices.
52
53 With 'showAddButton' => 'false' you can disable the 'create new Foreignkey'
54 Button generated beside the Selectbox.
55
56 Define the AddButtonString with 'addButtonString' => 'Add...'. This string
57 is set default to '+'
58
59 When using the '+' button you most likely want to return to where you came.
60 To accomplish this, we pass a 'returnTo' parameter by $_GET.
61 The Controller can send the user back to where he came from this way:
62
63 <pre>
64 if($model->save())
65 if(isset($_GET['returnTo']))
66 $this->redirect(array(urldecode($_GET['returnTo'])));
67 </pre>
68
69 Using the 'style' option we can configure how our Widget gets rendered.
70 The following styles are available:
71 Selectbox (default), Listbox, Checkbox and in MANY_MANY relations 'twopane'
72 The style is case insensitive so one can use dropdownlist or dropDownList.
73
74 Use the option 'createAction' if the action to add additional foreign Model
75 options differs from 'create'.
76
77 With 'parentObjects' you can limit the Parent Elements that are being shown.
78 It takes an array of elements that could be returned from an scope or
79 an SQL Query.
80
81 The parentObjects can be grouped, for example, with
82 'groupParentsBy' => 'city'
83
84 Use the option 'htmlOptions' to pass any html Options to the
85 Selectbox/Listbox form element.
86
87 Full Example:
88 <pre>
89 $this->widget('application.components.Relation', array(
90 'model' => 'Post',
91 'field' => 'Userid',
92 'style' => 'ListBox',
93 'criteria' => new CDBCriteria(array('condition' => 'id_of_user IN (1,8,20)')),
94 'parentObjects' => Parentmodel::model()->findAll('userid = 17'),
95 'groupParentsBy' => 'city',
96 'relation' => 'user',
97 'relatedPk' => 'id_of_user',
98 'fields' => array( 'username', 'username.group.groupid' ),
99 'delimiter' => ' -> ', // default: ' | '
100 'returnTo' => 'model/create',
101 'addButtonUrl' => 'othercontroller/otheraction', // default: ''
102 'showAddButton' => 'click here to add a new User', // default: ''
103 'htmlOptions' => array('style' => 'width: 100px;')
104 ));
105 </pre>
106
107
108 @author Herbert Maschke <thyseus@gmail.com>
109 @version 0.97 (after 1.0rc5)
110 @since 1.1
111 */
112
113 class Relation extends CWidget
114 {
115 // this Variable holds an instance of the Object
116 protected $_model;
117
118 // this Variable holds an instance of the related Object
119 protected $_relatedModel;
120
121 // draw the relation of which model?
122 public $model;
123
124 // which relation should be rendered?
125 public $relation;
126
127 public $field;
128
129 // the Primary Key of the foreign Model
130 public $relatedPk;
131
132 // a field or an array of fields that determine which field values
133 // should be rendered in the selection
134 public $fields;
135
136 // if this is set, the User is able to select no related model
137 // if this is set to a string, this string will be presented
138 public $allowEmpty = 0;
139
140 // Preselect which items?
141 public $preselect = false;
142
143 // disable this to hide the Add Button
144 // set this to a string to set the String to be displayed
145 public $showAddButton = true;
146 public $addButtonUrl = '';
147 // url for the action that refreshes the dropdownlist after related
148 // object is created
149 public $addButtonRefreshUrl = '';
150
151 // criteria for filtering records
152 public $criteria = false;
153
154 // How the label of a row should be rendered. {id} will be replaced by the
155 // id of the model. You can also insert every field that is available in the
156 // parent object.
157 // Use {fields} to display all fields delimited by $this->delimiter
158 // Use {myFuncName} to evaluate a user-contributed function specified in the
159 // $functions array as 'myFuncName'=>'code to be evaluated'. The code for
160 // these functions are evaluated under the context of the controller
161 // rendering the current Relation widget ($this refers to the controller).
162 // Old way, not encouraged anymore: Use {func0} to {funcX} to evaluate user-
163 // contributed functions specified in the $functions array as a keyless
164 // string entry of 'code to be evaluated'.
165 // Example of code:
166 //
167 // 'template' => '#{id} : {fields} ({title}) Allowed other Models: {func0} {func1} {preferredWay}',
168 // 'functions' => array(
169 // "CHtml::checkBoxList('parent{id}', '', CHtml::listData(Othermodel::model()->findAll(), 'id', 'title'));",
170 // '$this->funcThatReturnsText();'
171 // 'preferredWay' => '$this->instructMe();'
172 // ),
173 public $template = '{fields}';
174
175 // User-contributed functions, see comment for $template.
176 public $functions = array();
177
178 // If true, all the user-contributed functions in $functions will be
179 // substituted in $htmlOptions['template'] as well.
180 // If an array of function names, all the listed functions will be
181 // substituted in $htmlOptions['template'] as well.
182 public $functionsInHtmlOptionsTemplate = false;
183
184 // how should multiple fields be delimited
185 public $delimiter = " | ";
186
187 // style of the selection Widget
188 public $style = "dropDownList";
189 public $htmlOptions = array();
190 public $parentObjects = 0;
191 public $orderParentsBy = 0;
192 public $groupParentsBy = 0;
193
194 // override this for complicated MANY_MANY relations:
195 public $manyManyTable = '';
196 public $manyManyTableLeft = '';
197 public $manyManyTableRight = '';
198
199 public $num = 1;
200
201 public function init()
202 {
203 if (!is_object($this->model)) {
204 if (!$this->_model = new $this->model) {
205 throw new CException(
206 Yii::t('yii', 'Relation widget is not able to instantiate the given Model'));
207 }
208 }
209 else {
210 $this->_model = $this->model;
211 }
212
213 // Instantiate Model and related Model
214 foreach ($this->_model->relations() as $key => $value) {
215 if (strcmp($this->relation, $key) == 0) {
216 // $key = Name of the Relation
217 // $value[0] = Type of the Relation
218 // $value[1] = Related Model
219 // $value[2] = Related Field or Many_Many Table
220 switch ($value[0]) {
221 case 'CBelongsToRelation':
222 case 'CHasOneRelation':
223 $this->_relatedModel = new $value[1];
224 if (!isset($this->field)) {
225 $this->field = $value[2];
226 }
227 break;
228 case 'CManyManyRelation':
229 preg_match_all('/^.*\(/', $value[2], $matches);
230 $this->manyManyTable = substr($matches[0][0], 0, strlen($matches[0][0]) - 1);
231 preg_match_all('/\(.*,/', $value[2], $matches);
232 $this->manyManyTableLeft = substr($matches[0][0], 1, strlen($matches[0][0]) - 2);
233 preg_match_all('/,.*\)/', $value[2], $matches);
234 $this->manyManyTableRight = substr($matches[0][0], 2, strlen($matches[0][0]) - 3);
235
236 $this->_relatedModel = new $value[1];
237 break;
238 }
239 }
240 }
241
242 if (!is_object($this->_relatedModel)) {
243 throw new CException(
244 Yii::t('yii', 'Relation widget cannot find the given Relation(' . $this->relation . ')'));
245 }
246
247 if (!isset($this->relatedPk) || $this->relatedPk == "") {
248 $this->relatedPk = $this->_relatedModel->tableSchema->primaryKey;
249 }
250
251 if (!isset($this->fields) || $this->fields == "" || $this->fields == array()) {
252 throw new CException(Yii::t('yii', 'Widget "Relation" has been run without fields Option(string or array)'));
253 }
254 }
255
256 // Check if model-value contains '.' and generate -> directives:
257 public function getModelData($model, $field)
258 {
259 if (strstr($field, '.')) {
260 $data = explode('.', $field);
261 $value = $model->getRelated($data[0])->$data[1];
262 }
263 else {
264 $value = $model->$field;
265 }
266
267 return $value;
268 }
269
270 /**
271 * This function fetches all needed data of the related Object and returns them
272 * in an array that is prepared for use in ListData.
273 */
274 public function getRelatedData()
275 {
276 /* At first we determine, if we want to display all parent Objects, or
277 * if the User supplied an list of Objects */
278 if (is_object($this->parentObjects)) // a single Element
279 {
280 $parentobjects = array($this->parentObjects);
281 }
282 else {
283 if (is_array($this->parentObjects)) // Only show this elements
284 {
285 $parentobjects = $this->parentObjects;
286 }
287 else // Show all Parent elements
288 {
289 if ($this->criteria === false) {
290 // TODO: reimplement ORDER BY array('order'=>GHelper::guessNameColumn($this->_relatedModel->tableSchema->columns))
291 $parentobjects = CActiveRecord::model(get_class($this->_relatedModel))->findAll();
292 }
293 else {
294 $parentobjects = CActiveRecord::model(get_class($this->_relatedModel));
295 $parentobjects->setDbCriteria($this->criteria);
296 // TODO: reimplement ORDER BY array('order'=>GHelper::guessNameColumn($this->_relatedModel->tableSchema->columns))
297 $parentobjects = $parentobjects->findAll();
298 }
299 }
300 }
301
302 if ($this->allowEmpty) {
303 if (is_string($this->allowEmpty)) {
304 $dataArray[''] = $this->allowEmpty;
305 }
306 else {
307 $dataArray[''] = Yii::t('app', 'None');
308 }
309 }
310
311 foreach ($parentobjects as $obj) {
312 if (!is_array($this->fields)) {
313 $this->fields = array($this->fields);
314 }
315
316 $fields = '';
317 $i = 0;
318 foreach ($this->fields as $field) {
319 $rule = sprintf('{%s}', $field);
320 $rules[$rule] = $this->getModelData($obj, $field);
321
322 if ($i++ > 0) {
323 $fields .= $this->delimiter;
324 }
325 $fields .= $this->getModelData($obj, $field);
326 }
327
328 $defaultrules = array(
329 '{fields}' => $fields,
330 '{id}' => $obj->{$obj->tableSchema->primaryKey});
331
332 // Look for user-contributed functions and evaluate them
333 if ($this->functions != array()) {
334 foreach ($this->functions as $key => $function) {
335 // If the key is of type string, it's assumed to be a named function,
336 // used like {myFuncName}.
337 // If the key is an integer, it's assumed to be an unnamed function used
338 // the old way, {funcX} where X is its index in the functions array.
339 // We keep the integer support mostly for backwards compatibility, the
340 // new way is encouraged.
341 if (is_string($key)) {
342 $funcrules[sprintf('{%s}', $key)] = $this->controller->evaluateExpression(
343 strtr($function, $defaultrules));
344 }
345 else {
346 $funcrules[sprintf('{func%d}', $key)] = $this->controller->evaluateExpression(
347 strtr($function, $defaultrules));
348 }
349 }
350 }
351
352 // Merge the evaluated rules, if exist
353 if (isset($funcrules)) {
354 $rules = array_merge($rules, $funcrules);
355 }
356
357 // Merge the default rules into our ruleset
358 $rules = array_merge($rules, $defaultrules);
359
360 // Apply the rules to the template
361 $value = strtr($this->template, $rules);
362
363 // Apply the user contributed functions to $htmlOptions's template, if requested.
364 if (isset($this->htmlOptions['template']) && $this->functionsInHtmlOptionsTemplate !== false && isset($funcrules) && is_array($funcrules)) {
365 if (is_array($this->functionsInHtmlOptionsTemplate)) {
366 $funcrulesToUse = array();
367 foreach ($this->functionsInHtmlOptionsTemplate as $functionName) {
368 $functionName = sprintf('{%s}', $functionName);
369 if (isset($funcrules[$functionName])) {
370 $funcrulesToUse[$functionName] = $funcrules[$functionName];
371 }
372 }
373 $this->htmlOptions['template'] = strtr($this->htmlOptions['template'], $funcrulesToUse);
374 }
375 else {
376 $this->htmlOptions['template'] = strtr($this->htmlOptions['template'], $funcrules);
377 }
378 }
379
380 if ($this->groupParentsBy != '') {
381 $dataArray[$obj->{$this->groupParentsBy}][$obj->{$this->relatedPk}] = $value;
382 }
383 else {
384 $dataArray[$obj->{$this->relatedPk}] = $value;
385 }
386 }
387
388 if (!isset($dataArray) || !is_array($dataArray)) {
389 $dataArray = array();
390 }
391
392 return $dataArray;
393 }
394
395
396 /**
397 * Retrieves the Assigned Objects of the MANY_MANY related Table
398 */
399 public function getAssignedObjects()
400 {
401 if (!$this->_model->{$this->_model->tableSchema->primaryKey}) {
402 return array();
403 }
404
405 $sql = sprintf("select * from %s where %s = %s",
406 $this->manyManyTable,
407 $this->manyManyTableLeft,
408 $this->_model->{$this->_model->tableSchema->primaryKey});
409
410 $result = $this->_model->getDbConnection()->createCommand($sql)->queryAll();
411
412 foreach ($result as $foreignObject) {
413 $id = $foreignObject[$this->manyManyTableRight];
414 $objects[$id] = $this->_relatedModel->findByPk($id);
415 }
416
417 foreach ($this->_model->{$this->relation} as $relobj)
418 $objects[$relobj->{$relobj->tableSchema->primaryKey}] = $relobj;
419
420 return isset($objects) ? $objects : array();
421 }
422
423 /**
424 * Retrieves the not Assigned Objects of the MANY_MANY related Table
425 * This is used in the two-pane style view.
426 */
427 public function getNotAssignedObjects()
428 {
429 foreach ($this->getRelatedData() as $key => $value) {
430 if (!array_key_exists($key, $this->getAssignedObjects())) {
431 $objects[$key] = $this->_relatedModel->findByPk($key);
432 }
433 }
434
435 return $objects ? $objects : array();
436 }
437
438 /**
439 * Gets the Values of the given Object or Objects depending on the
440 * $this->fields the widget requests
441 */
442 public function getObjectValues($objects)
443 {
444 if (is_array($objects)) {
445 foreach ($objects as $object) {
446 $attributeValues[$object->primaryKey] = $object->{$this->fields};
447 }
448 }
449 else {
450 if (is_object($objects)) {
451 $attributeValues[$object->primaryKey] = $objects->{$this->fields};
452 }
453 }
454
455 return isset($attributeValues) ? $attributeValues : array();
456 }
457
458 /*
459 * How will the Listbox of the MANY_MANY Assignment be called?
460 */
461 public function getListBoxName($ajax = false)
462 {
463 if ($ajax) {
464 return sprintf('%s_%s',
465 get_class($this->_model),
466 get_class($this->_relatedModel)
467 );
468 }
469 else {
470 return sprintf('%s[%s]',
471 get_class($this->_model),
472 get_class($this->_relatedModel)
473 );
474 }
475 }
476
477 public function renderBelongsToSelection()
478 {
479 CWidget::render(strtolower($this->style),
480 array(
481 'id' => $this->relation . '_options',
482 'model' => $this->_model,
483 'field' => $this->field,
484 'data' => $this->getRelatedData(),
485 'htmlOptions' => $this->htmlOptions));
486 }
487
488 public function renderManyManySelection()
489 {
490 if (strcasecmp($this->style, 'twopane') == 0) {
491 $this->renderTwoPaneSelection();
492 }
493 else {
494 if (strcasecmp($this->style, 'checkbox') == 0) {
495 $this->renderCheckBoxListSelection();
496 }
497 else {
498 if (strcasecmp($this->style, 'dropDownList') == 0) {
499 $this->renderManyManyDropDownListSelection();
500 }
501 else {
502 if (strcasecmp($this->style, 'radiobutton') == 0) {
503 $this->renderManyManyRadioButtonListSelection();
504 }
505
506 else {
507 $this->renderOnePaneSelection();
508 }
509 }
510 }
511 }
512 }
513
514 // when only one of the MANY_MANY related Objects should be choosable
515 public function renderManyManyRadioButtonListSelection()
516 {
517 echo CHtml::RadiobuttonList(
518 get_class($this->_model) . '[' . get_class($this->_relatedModel) . '][]',
519 $this->_model{$this->relation}[0]->{$this->_model{$this->relation}[0]->tableSchema->primaryKey},
520 $this->getRelatedData(),
521 $this->htmlOptions);
522 }
523
524 /*
525 * Renders one dropDownList per selectable related Element.
526 * The users can add additional entries with the + and remove entries
527 * with the - Button .
528 */
529 public function renderManyManyDropDownListSelection()
530 {
531 $uniqueid = $this->_relatedModel->tableSchema->name;
532
533 if ($this->parentObjects != 0) {
534 $relatedmodels = $this->parentObjects;
535 }
536 else {
537 $relatedmodels = $this->_relatedModel->findAll();
538 }
539
540 $addbutton = sprintf('i' . $this->num . ' = %d; maxi' . $this->num . ' = %d;',
541 count($this->getAssignedObjects()) + 1,
542 count($relatedmodels));
543 Yii::app()->clientScript->registerScript(
544 'addbutton_' . $uniqueid . '_' . $this->num, $addbutton);
545
546 $i = 0;
547 foreach ($relatedmodels as $obj) {
548 $i++;
549 $isAssigned = $this->isAssigned($obj->id);
550
551 echo CHtml::openTag('div', array(
552 'id' => sprintf('div_%s_%d', $uniqueid, $i),
553 'style' => $isAssigned ? '' : 'display:none;',
554 'class' => 'relation'
555 ));
556 echo CHtml::dropDownList(sprintf('%s[%d]',
557 $this->getListBoxName(),
558 $i),
559 $isAssigned ? $obj->id : 0,
560 CHtml::listData(
561 array_merge(
562 array('0' => $this->allowEmpty), $relatedmodels),
563 $this->relatedPk,
564 $this->fields)
565 );
566 echo CHtml::button('-', array('id' => sprintf('sub_%s_%d',
567 $uniqueid,
568 $i)));
569 echo CHtml::closeTag('div');
570 $jsadd = '
571 $(\'#add_' . $uniqueid . '\').click(function() {
572 $(\'#div_' . $uniqueid . '_\' + i' . $this->num . ').show();
573 if(i' . $this->num . ' <= maxi' . $this->num . ') i' . $this->num . '++;
574 });
575 ';
576
577 $jssub = '
578 $(\'#sub_' . $uniqueid . '_' . $i . '\').click(function() {
579 $(\'#div_' . $uniqueid . '_' . $i . '\').hide();
580 $("select[name=\'' . $this->getListBoxName() . '[' . $i . ']\']").val(\'\');
581 if(i' . $this->num . ' >= 1) i--;
582 });
583 ';
584
585 Yii::app()->clientScript->registerScript('addbutton_' . $uniqueid, $jsadd);
586 Yii::app()->clientScript->registerScript('subbutton_' . $uniqueid, $jssub);
587 }
588 echo ' ';
589 echo CHtml::button('+', array('id' => sprintf('add_%s', $uniqueid)));
590
591
592 }
593
594 public function isAssigned($id)
595 {
596 return in_array($id, array_keys($this->getAssignedObjects()));
597 }
598
599 public static function retrieveValues($data)
600 {
601 $returnArray = array();
602
603 $i = 0;
604 foreach ($data as $value) {
605 if ($value != 0) {
606 $returnArray[(int)$i] = (int)$value;
607 }
608 $i++;
609 }
610
611 return $returnArray;
612 }
613
614
615 public function renderCheckBoxListSelection()
616 {
617 $keys = array_keys($this->getAssignedObjects());
618
619 if (isset($this->preselect) && $this->preselect != false) {
620 $keys = $this->preselect;
621 }
622
623 $id = $this->relation . '_options';
624 echo CHtml::openTag('div', array('id' => $id, 'class' => 'relation'));
625 echo CHtml::CheckBoxList($this->getListBoxName(),
626 $keys,
627 $this->getRelatedData(),
628 $this->htmlOptions);
629 echo CHtml::closeTag('div');
630 }
631
632
633 public function renderOnePaneSelection()
634 {
635 $keys = array_keys($this->getAssignedObjects());
636
637 echo CHtml::ListBox($this->getListBoxName(),
638 $keys,
639 $this->getRelatedData(),
640 array('multiple' => 'multiple'));
641 }
642
643 public function handleAjaxRequest($post)
644 {
645 print_r($post);
646 }
647
648 public function renderTwoPaneSelection()
649 {
650 echo CHtml::ListBox($this->getListBoxName(),
651 array(),
652 $this->getObjectValues($this->getAssignedObjects()),
653 array('multiple' => 'multiple'));
654
655 $ajax =
656 array(
657 'type' => 'POST',
658 'data' => array('yeah'),
659 'update' => '#' . $this->getListBoxName(true),
660 );
661
662 echo CHtml::ajaxSubmitButton('<<',
663 array('assign'),
664 $ajax
665 );
666
667 $ajax =
668 array(
669 'type' => 'POST',
670 'update' => '#not_' . $this->getListBoxName(true)
671 );
672
673 echo CHtml::ajaxSubmitButton('>>',
674 array('assign', 'revoke' => 1),
675 $ajax);
676 //,
677 //$data['revoke']);
678
679
680 echo CHtml::ListBox('not_' . $this->getListBoxName(),
681 array(),
682 $this->getObjectValues($this->getNotAssignedObjects()),
683 array('multiple' => 'multiple'));
684 }
685
686 public function run()
687 {
688 if ($this->manyManyTable != '') {
689 $this->renderManyManySelection();
690 }
691 else {
692 $this->renderBelongsToSelection();
693 }
694
695 }
696
697 protected function renderAddButton()
698 {
699 // TODO: reimplement add button
700 // if($this->showAddButton)
701 // $this->renderAddButton();
702 return;
703
704 $model = strtolower(get_class($this->_model));
705 $relatedModel = strtolower(get_class($this->_relatedModel));
706 $relations = $this->_model->relations();
707
708 #$controller = GHelper::resolveController($relations[$this->relation]);
709
710 if ($this->addButtonUrl != '') {
711 $link = $this->addButtonUrl;
712 }
713 else {
714 $link = $this->controller->createUrl($controller . '/create', array('relation' => $this->relation));
715 }
716
717 if ($this->addButtonRefreshUrl == '') {
718 $this->addButtonRefreshUrl = $this->controller->createUrl($model . '/getOptions',
719 array(
720 'relation' => $this->relation,
721 'style' => $this->style,
722 'fields' => $this->fields));
723 }
724
725 $string = Yii::t('app', 'Add new {model}', array('{model}' => $relatedModel));
726
727 $dialog = 'zii.widgets.jui.CJuiDialog';
728 $this->beginWidget($dialog, array(
729 'id' => $this->relation . '_dialog',
730 'options' => array('autoOpen' => false,
731 'modal' => true,
732 'title' => $string,
733 'width' => 800,
734 'height' => 600)
735 ));
736 $this->endWidget($dialog);
737
738 echo CHtml::AjaxButton(
739 is_string($this->showAddButton) ? $this->showAddButton : $string,
740 $link,
741 array(
742 'success' => "function(html) {
743 jQuery('#" . $this->relation . "_dialog').html(html);
744 $('#" . $this->relation . "_dialog').dialog('open');
745 }"),
746 array('id' => $this->relation . '_create')
747 );
748
749 // prepare the Submit button that is not loaded into the DOM yet
750 Yii::app()->clientScript->registerScript($this->relation . '_submit',
751 "jQuery('body').delegate('#submit_" . $this->relation . "','click',function(){
752 jQuery.ajax({'url':'" . $link . "',
753 'cache':false,
754 'type':'POST',
755 'data':jQuery(this).parents('form').serialize(),
756 'success':function(html){
757 jQuery('#" . $this->relation . "_dialog').html(html)}});
758 return false;});");
759
760 Yii::app()->clientScript->registerScript($this->relation . '_done',
761 "jQuery('body').delegate('#" . $this->relation . "_done','click',function(){
762 jQuery.ajax({'url':'" . $this->addButtonRefreshUrl . "',
763 'cache':false,
764 'success':function(html){
765 jQuery('#" . $this->relation . "_options').html(html)}});
766 $('#" . $this->relation . "_dialog').dialog('close');
767 return false;});");
768 }
769 }
770