PageRenderTime 72ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/common/extensions/bootstrap/widgets/TbEditableField.php

https://bitbucket.org/haichau59/manga
PHP | 326 lines | 213 code | 50 blank | 63 comment | 59 complexity | c4977b15f167bc6af0ede142f888c5ad MD5 | raw file
  1. <?php
  2. /**
  3. * EditableField class file.
  4. *
  5. * This widget makes editable single attribute of model
  6. *
  7. * @author Vitaliy Potapov <noginsk@rambler.ru>
  8. * @link https://github.com/vitalets/yii-bootstrap-editable
  9. * @copyright Copyright &copy; Vitaliy Potapov 2012
  10. * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
  11. * @version 1.0.0
  12. * @since 10/2/12 12:24 AM renamed class for YiiBooster integration antonio ramirez <antonio@clevertech.ibz>
  13. */
  14. class TbEditableField extends CWidget
  15. {
  16. //for all types
  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; //will be used as content
  24. public $value = null;
  25. public $placement = null;
  26. public $inputclass = null;
  27. public $autotext = null;
  28. //for text & textarea
  29. public $placeholder = null;
  30. //for select
  31. public $source = array();
  32. public $prepend = null;
  33. //for date
  34. public $format = null;
  35. public $viewformat = null;
  36. public $language = null;
  37. public $weekStart = null;
  38. public $startView = null;
  39. //methods
  40. public $validate = null;
  41. public $success = null;
  42. public $error = null;
  43. //events
  44. public $onInit = null;
  45. public $onUpdate = null;
  46. public $onRender = null;
  47. public $onShown = null;
  48. public $onHidden = null;
  49. //js options
  50. public $options = array();
  51. //html options
  52. public $htmlOptions = array();
  53. //weather to encode text on output
  54. public $encode = true;
  55. //if false text will not be editable, but will be rendered
  56. public $enabled = null;
  57. public function init()
  58. {
  59. if (!$this->model) {
  60. throw new CException(Yii::t('zii', 'Parameter "model" should be provided for Editable'));
  61. }
  62. if (!$this->attribute) {
  63. throw new CException(Yii::t('zii', 'Parameter "attribute" should be provided for Editable'));
  64. }
  65. if (!$this->model->hasAttribute($this->attribute)) {
  66. throw new CException(Yii::t('zii', 'Model "{model}" does not have attribute "{attribute}"',
  67. array('{model}'=>get_class($this->model), '{attribute}'=>$this->attribute)));
  68. }
  69. parent::init();
  70. if ($this->type === null) {
  71. $this->type = 'text';
  72. //try detect type from metadata.
  73. if (array_key_exists($this->attribute, $this->model->tableSchema->columns)) {
  74. $dbType = $this->model->tableSchema->columns[$this->attribute]->dbType;
  75. if($dbType == 'date' || $dbType == 'datetime') $this->type = 'date';
  76. if(stripos($dbType, 'text') !== false) $this->type = 'textarea';
  77. }
  78. }
  79. /*
  80. * unfortunatly datepicker's format does not match Yii locale dateFormat
  81. * and we cannot take format from application locale
  82. *
  83. * see http://www.unicode.org/reports/tr35/#Date_Format_Patterns
  84. *
  85. if($this->type == 'date' && $this->format === null) {
  86. $this->format = Yii::app()->locale->getDateFormat();
  87. }
  88. */
  89. /* generate text from model attribute (for all types except 'select'.
  90. * For select/date autotext will be applied)
  91. */
  92. if (!strlen($this->text) && $this->type != 'select' && $this->type != 'date') {
  93. $this->text = $this->model->getAttribute($this->attribute);
  94. }
  95. //if enabled not defined directly, set it to true only for safe attributes
  96. if($this->enabled === null) {
  97. $this->enabled = $this->model->isAttributeSafe($this->attribute);
  98. }
  99. //if not enabled --> just print text
  100. if (!$this->enabled) {
  101. return;
  102. }
  103. //language: use config's value if not defined directly
  104. if ($this->language === null && yii::app()->language) {
  105. $this->language = yii::app()->language;
  106. }
  107. //normalize url from array if needed
  108. $this->url = CHtml::normalizeUrl($this->url);
  109. //generate title from attribute label
  110. if ($this->title === null) {
  111. //todo: i18n here. Add messages folder to extension
  112. $this->title = (($this->type == 'select' || $this->type == 'date') ? Yii::t('zii', 'Select') : Yii::t('zii', 'Enter')) . ' ' . $this->model->getAttributeLabel($this->attribute);
  113. }
  114. $this->buildHtmlOptions();
  115. $this->buildJsOptions();
  116. $this->registerAssets();
  117. }
  118. public function buildHtmlOptions()
  119. {
  120. //html options
  121. $htmlOptions = array(
  122. 'href' => '#',
  123. 'rel' => $this->getSelector(),
  124. 'data-pk' => $this->model->primaryKey,
  125. );
  126. //for select we need to define value directly
  127. if ($this->type == 'select') {
  128. $this->value = $this->model->getAttribute($this->attribute);
  129. $this->htmlOptions['data-value'] = $this->value;
  130. }
  131. //for date we use 'format' to put it into value (if text not defined)
  132. if ($this->type == 'date' && !strlen($this->text)) {
  133. $this->value = $this->model->getAttribute($this->attribute);
  134. //if date comes as object, format it to string
  135. if($this->value instanceOf DateTime) {
  136. /*
  137. * unfortunatly datepicker's format does not match Yii locale dateFormat,
  138. * we need replacements below to convert date correctly
  139. */
  140. $count = 0;
  141. $format = str_replace('MM', 'MMMM', $this->format, $count);
  142. if(!$count) $format = str_replace('M', 'MMM', $format, $count);
  143. if(!$count) $format = str_replace('m', 'M', $format);
  144. $this->value = Yii::app()->dateFormatter->format($format, $this->value->getTimestamp());
  145. }
  146. $this->htmlOptions['data-value'] = $this->value;
  147. }
  148. //merging options
  149. $this->htmlOptions = CMap::mergeArray($this->htmlOptions, $htmlOptions);
  150. }
  151. public function buildJsOptions()
  152. {
  153. $options = array(
  154. 'type' => $this->type,
  155. 'url' => $this->url,
  156. 'name' => $this->attribute,
  157. 'title' => CHtml::encode($this->title),
  158. );
  159. if ($this->emptytext) {
  160. $options['emptytext'] = $this->emptytext;
  161. }
  162. if ($this->placement) {
  163. $options['placement'] = $this->placement;
  164. }
  165. if ($this->inputclass) {
  166. $options['inputclass'] = $this->inputclass;
  167. }
  168. if ($this->autotext) {
  169. $options['autotext'] = $this->autotext;
  170. }
  171. switch ($this->type) {
  172. case 'text':
  173. case 'textarea':
  174. if ($this->placeholder) {
  175. $options['placeholder'] = $this->placeholder;
  176. }
  177. break;
  178. case 'select':
  179. if ($this->source) {
  180. $options['source'] = $this->source;
  181. }
  182. if ($this->prepend) {
  183. $options['prepend'] = $this->prepend;
  184. }
  185. break;
  186. case 'date':
  187. if ($this->format) {
  188. $options['format'] = $this->format;
  189. }
  190. if ($this->viewformat) {
  191. $options['viewformat'] = $this->viewformat;
  192. }
  193. if ($this->language && substr($this->language, 0, 2) != 'en') {
  194. $options['datepicker']['language'] = $this->language;
  195. }
  196. if ($this->weekStart !== null) {
  197. $options['weekStart'] = $this->weekStart;
  198. }
  199. if ($this->startView !== null) {
  200. $options['startView'] = $this->startView;
  201. }
  202. break;
  203. }
  204. //methods
  205. foreach(array('validate', 'success', 'error') as $event) {
  206. if($this->$event!==null) {
  207. $options[$event]=(strpos($this->$event, 'js:') !== 0 ? 'js:' : '') . $this->$event;
  208. }
  209. }
  210. //merging options
  211. $this->options = CMap::mergeArray($this->options, $options);
  212. }
  213. public function registerClientScript()
  214. {
  215. $script = "$('a[rel={$this->htmlOptions['rel']}]')";
  216. //attach events
  217. foreach(array('init', 'update', 'render', 'shown', 'hidden') as $event) {
  218. $property = 'on'.ucfirst($event);
  219. if ($this->$property) {
  220. // CJavaScriptExpression appeared only in 1.1.11, will turn to it later
  221. //$event = ($this->onInit instanceof CJavaScriptExpression) ? $this->onInit : new CJavaScriptExpression($this->onInit);
  222. $eventJs = (strpos($this->$property, 'js:') !== 0 ? 'js:' : '') . $this->$property;
  223. $script .= "\n.on('".$event."', ".CJavaScript::encode($eventJs).")";
  224. }
  225. }
  226. //apply editable
  227. $options = CJavaScript::encode($this->options);
  228. $script .= ".editable($options);";
  229. Yii::app()->getClientScript()->registerScript(__CLASS__ . '#' . $this->id, $script);
  230. return $script;
  231. }
  232. /**
  233. * @since 10/2/12 12:32 AM refactored to make use of Component's registerAssetCss|Js function.
  234. * @author antonio ramirez <antonio@clevertech.biz>
  235. */
  236. public function registerAssets()
  237. {
  238. //if bootstrap extension installed, but no js registered -> register it!
  239. if (($bootstrap = Yii::app()->getComponent('bootstrap')) && !$bootstrap->enableJS) {
  240. $bootstrap->registerCorePlugins(); //enable bootstrap js if needed
  241. }
  242. $bootstrap->registerAssetCss('bootstrap-editable.css') ;
  243. $bootstrap->registerAssetJs('bootstrap-editable' . (!YII_DEBUG ? '.min' : '') . '.js', CClientScript::POS_END);
  244. //include locale for datepicker
  245. if ($this->type == 'date' && $this->language && substr($this->language, 0, 2) != 'en') {
  246. $bootstrap->registerAssetJs('locales/bootstrap-datepicker.'. str_replace('_', '-', $this->language).'.js', CClientScript::POS_END);
  247. }
  248. }
  249. public function run()
  250. {
  251. if($this->enabled) {
  252. $this->registerClientScript();
  253. $this->renderLink();
  254. } else {
  255. $this->renderText();
  256. }
  257. }
  258. public function renderLink()
  259. {
  260. echo CHtml::openTag('a', $this->htmlOptions);
  261. $this->renderText();
  262. echo CHtml::closeTag('a');
  263. }
  264. public function renderText()
  265. {
  266. $encodedText = $this->encode ? CHtml::encode($this->text) : $this->text;
  267. if($this->type == 'textarea') {
  268. $encodedText = preg_replace('/\r?\n/', '<br>', $encodedText);
  269. }
  270. echo $encodedText;
  271. }
  272. public function getSelector()
  273. {
  274. return get_class($this->model) . '_' . $this->attribute . ($this->model->primaryKey ? '_' . $this->model->primaryKey : '_new');
  275. }
  276. }