1 <?php
2 3 4 5 6 7 8 9 10 11 12
13
14 class EditableField extends CWidget
15 {
16
17 public $model = null;
18 public $attribute = null;
19 public $type = null;
20 public $url = null;
21 public $title = null;
22 public $emptytext = null;
23 public $text = null;
24 public $value = null;
25 public $placement = null;
26 public $inputclass = null;
27 public $autotext = null;
28
29
30 public $placeholder = null;
31
32
33 public $source = array();
34 public $prepend = null;
35
36
37 public $format = null;
38 public $viewformat = null;
39 public $language = null;
40 public $weekStart = null;
41 public $startView = null;
42
43
44 public $validate = null;
45 public $success = null;
46 public $error = null;
47
48
49 public $onInit = null;
50 public $onUpdate = null;
51 public $onRender = null;
52 public $onShown = null;
53 public $onHidden = null;
54
55
56 public $options = array();
57
58
59 public $htmlOptions = array();
60
61
62 public $encode = true;
63
64
65 public $enabled = null;
66
67 public function init()
68 {
69 if (!$this->model) {
70 throw new CException('Parameter "model" should be provided for Editable');
71 }
72 if (!$this->attribute) {
73 throw new CException('Parameter "attribute" should be provided for Editable');
74 }
75 if (!$this->model->hasAttribute($this->attribute)) {
76 throw new CException('Model "'.get_class($this->model).'" does not have attribute "'.$this->attribute.'"');
77 }
78
79 parent::init();
80
81 if ($this->type === null) {
82 $this->type = 'text';
83
84 if (array_key_exists($this->attribute, $this->model->tableSchema->columns)) {
85 $dbType = $this->model->tableSchema->columns[$this->attribute]->dbType;
86 if($dbType == 'date' || $dbType == 'datetime') $this->type = 'date';
87 if(stripos($dbType, 'text') !== false) $this->type = 'textarea';
88 }
89 }
90
91 92 93 94 95 96 97 98 99 100
101
102 103 104
105 if (!strlen($this->text) && $this->type != 'select' && $this->type != 'date') {
106 $this->text = $this->model->getAttribute($this->attribute);
107 }
108
109
110 if($this->enabled === null) {
111 $this->enabled = $this->model->isAttributeSafe($this->attribute);
112 }
113
114
115 if (!$this->enabled) {
116 return;
117 }
118
119
120 if ($this->language === null && yii::app()->language) {
121 $this->language = yii::app()->language;
122 }
123
124
125 $this->url = CHtml::normalizeUrl($this->url);
126
127
128 if ($this->title === null) {
129
130 $this->title = (($this->type == 'select' || $this->type == 'date') ? Yii::t('editable', 'Select') : Yii::t('editable', 'Enter')) . ' ' . $this->model->getAttributeLabel($this->attribute);
131 }
132
133 $this->buildHtmlOptions();
134 $this->buildJsOptions();
135 $this->registerAssets();
136 }
137
138 public function buildHtmlOptions()
139 {
140
141 $htmlOptions = array(
142 'href' => '#',
143 'rel' => $this->getSelector(),
144 'data-pk' => $this->model->primaryKey,
145 );
146
147
148 if ($this->type == 'select') {
149 $this->value = $this->model->getAttribute($this->attribute);
150 $this->htmlOptions['data-value'] = $this->value;
151 }
152
153
154 if ($this->type == 'date' && !strlen($this->text)) {
155 $this->value = $this->model->getAttribute($this->attribute);
156
157
158 if($this->value instanceOf DateTime) {
159 160 161 162
163 $count = 0;
164 $format = str_replace('MM', 'MMMM', $this->format, $count);
165 if(!$count) $format = str_replace('M', 'MMM', $format, $count);
166 if(!$count) $format = str_replace('m', 'M', $format);
167
168 $this->value = Yii::app()->dateFormatter->format($format, $this->value->getTimestamp());
169 }
170
171 $this->htmlOptions['data-value'] = $this->value;
172 }
173
174
175 $this->htmlOptions = CMap::mergeArray($this->htmlOptions, $htmlOptions);
176 }
177
178 public function buildJsOptions()
179 {
180 $options = array(
181 'type' => $this->type,
182 'url' => $this->url,
183 'name' => $this->attribute,
184 'title' => CHtml::encode($this->title),
185 );
186
187 if ($this->emptytext) {
188 $options['emptytext'] = $this->emptytext;
189 }
190
191 if ($this->placement) {
192 $options['placement'] = $this->placement;
193 }
194
195 if ($this->inputclass) {
196 $options['inputclass'] = $this->inputclass;
197 }
198
199 if ($this->autotext) {
200 $options['autotext'] = $this->autotext;
201 }
202
203 switch ($this->type) {
204 case 'text':
205 case 'textarea':
206 if ($this->placeholder) {
207 $options['placeholder'] = $this->placeholder;
208 }
209 break;
210 case 'select':
211 if ($this->source) {
212 $options['source'] = $this->source;
213 }
214 if ($this->prepend) {
215 $options['prepend'] = $this->prepend;
216 }
217 break;
218 case 'date':
219 if ($this->format) {
220 $options['format'] = $this->format;
221 }
222 if ($this->viewformat) {
223 $options['viewformat'] = $this->viewformat;
224 }
225 if ($this->language && substr($this->language, 0, 2) != 'en') {
226 $options['datepicker']['language'] = $this->language;
227 }
228 if ($this->weekStart !== null) {
229 $options['weekStart'] = $this->weekStart;
230 }
231 if ($this->startView !== null) {
232 $options['startView'] = $this->startView;
233 }
234 break;
235 }
236
237
238 foreach(array('validate', 'success', 'error') as $event) {
239 if($this->$event!==null) {
240 $options[$event]=(strpos($this->$event, 'js:') !== 0 ? 'js:' : '') . $this->$event;
241 }
242 }
243
244
245 $this->options = CMap::mergeArray($this->options, $options);
246 }
247
248 public function registerClientScript()
249 {
250 $script = "$('a[rel={$this->htmlOptions['rel']}]')";
251
252
253 foreach(array('init', 'update', 'render', 'shown', 'hidden') as $event) {
254 $property = 'on'.ucfirst($event);
255 if ($this->$property) {
256
257
258 $eventJs = (strpos($this->$property, 'js:') !== 0 ? 'js:' : '') . $this->$property;
259 $script .= "\n.on('".$event."', ".CJavaScript::encode($eventJs).")";
260 }
261 }
262
263
264 $options = CJavaScript::encode($this->options);
265 $script .= ".editable($options);";
266
267 Yii::app()->getClientScript()->registerScript(__CLASS__ . '#' . $this->id, $script);
268
269 return $script;
270 }
271
272
273 public function registerAssets()
274 {
275
276 if (($bootstrap = yii::app()->getComponent('bootstrap')) && !$bootstrap->enableJS) {
277 $bootstrap->registerCorePlugins();
278 }
279
280 $assetsUrl = Yii::app()->getAssetManager()->publish(Yii::getPathOfAlias('ext.editable.assets'), false, 1);
281 Yii::app()->getClientScript()->registerCssFile($assetsUrl . '/css/bootstrap-editable.css');
282 Yii::app()->clientScript->registerScriptFile($assetsUrl . '/js/bootstrap-editable.js', CClientScript::POS_END);
283
284
285 if ($this->type == 'date' && $this->language && substr($this->language, 0, 2) != 'en') {
286
287 $localesUrl = Yii::app()->getAssetManager()->publish(Yii::getPathOfAlias('ext.editable.assets.js.locales'));
288 Yii::app()->clientScript->registerScriptFile($localesUrl . '/bootstrap-datepicker.'. str_replace('_', '-', $this->language).'.js', CClientScript::POS_END);
289 }
290 }
291
292 public function run()
293 {
294 if($this->enabled) {
295 $this->registerClientScript();
296 $this->renderLink();
297 } else {
298 $this->renderText();
299 }
300 }
301
302 public function renderLink()
303 {
304 echo CHtml::openTag('a', $this->htmlOptions);
305 $this->renderText();
306 echo CHtml::closeTag('a');
307 }
308
309 public function renderText()
310 {
311 $encodedText = $this->encode ? CHtml::encode($this->text) : $this->text;
312 if($this->type == 'textarea') {
313 $encodedText = preg_replace('/\r?\n/', '<br>', $encodedText);
314 }
315 echo $encodedText;
316 }
317
318 public function getSelector()
319 {
320 return get_class($this->model) . '_' . $this->attribute . ($this->model->primaryKey ? '_' . $this->model->primaryKey : '_new');
321 }
322 }
323