Permalink
Browse files

added CJavaScriptExpression while keeping BC

  • Loading branch information...
samdark committed Jul 26, 2012
1 parent c1ac363 commit ada1cedc7dd5946cc660ce9722a9881d7eb31040
View
@@ -60,7 +60,7 @@ Version 1.1.11 work in progress
- Enh #369: Added $hashKey to CCache (kidol)
- Enh #414: Added sort parameter to yiic message command that sorts messages by key when merging (ranvis)
- Enh #455: Added support for default value in CConsoleCommand::prompt (eagleoneraptor)
-- Enh #551: Added $safe parameter to CJavaScript::encode. If set to true, 'js:' will not be allowed (samdark)
+- Enh #551: Added $safe parameter to CJavaScript::encode. If set to true, 'js:' will not be allowed. If you need to pass JavaScript, wrap your code with CJavaScriptExpression instead (samdark)
- Enh #552: Added support for http-level caching via CHttpCacheFilter (DaSourcerer)
- Enh #568: CHtml::getIdByName() will now convert spaces to underscore to get proper ID for HTML elements (mdomba)
- Enh #578: Added extension checks to CMemCache (samdark)
View
25 UPGRADE
@@ -24,24 +24,37 @@ Upgrading from v1.1.10
- API of public method CConsoleCommand::confirm() changed. If you are overriding this method make sure to update your code.
The method now has a 2nd parameter for the default value which will be used if no selection is made, so you have to
adjust the signature to fit
-
+
public function confirm($message,$default=false)
-
+
and the parent call to
-
+
parent::confirm($message,$default);
- API of protected method CConsoleCommand::afterAction() changed, if you are overriding this method make sure to update your code.
method now has a 3rd parameter for application exit code, so you have to adjust the signature to fit
-
+
protected function afterAction($action,$params,$exitCode=0)
-
+
and the parent call to
-
+
parent::afterAction($action,$params,$exitCode);
- CDateFormat::format() now will return null if the parameter $time is null. Previously it would return 1/1/1970.
+- If you are using CJavaScript::encode in your application with parameter coming
+ from user input, set second argument to true:
+
+ CJavaScript::encode($userInput, true);
+
+ It will disable prefixing parameters with "js:". If you need to pass JavaScript
+ expression it's now preferrable to wrap these with CJavaScriptExpression:
+
+ CJavaScript::encode(new CJavaScriptExpression('alert("Yii!");'), true);
+
+ Note that second "safe" parameter doesn't affect CJavaScriptExpression in any way.
+
+
Upgrading from v1.1.9
---------------------
- Previously xSendFile() was returning false if the file was not found.
@@ -68,10 +68,10 @@
'source'=>array_keys(Yii::app()->{$model->connectionId}->schema->getTables()),
'options'=>array(
'minLength'=>'0',
- 'focus' => 'js:function(event,ui) {
+ 'focus' => new CJavaScriptExpression('function(event,ui) {
$("#'.CHtml::activeId($model,'tableName').'").val(ui.item.label);
return false;
- }'
+ }')
),
'htmlOptions'=>array(
'id'=>'ModelCode_tableName',
@@ -1038,28 +1038,28 @@ public static function ajax($options)
{
Yii::app()->getClientScript()->registerCoreScript('jquery');
if(!isset($options['url']))
- $options['url']='js:location.href';
+ $options['url']=new CJavaScriptExpression('location.href');
else
$options['url']=self::normalizeUrl($options['url']);
if(!isset($options['cache']))
$options['cache']=false;
if(!isset($options['data']) && isset($options['type']))
- $options['data']='js:jQuery(this).parents("form").serialize()';
+ $options['data']=new CJavaScriptExpression('jQuery(this).parents("form").serialize()');
foreach(array('beforeSend','complete','error','success') as $name)
{
- if(isset($options[$name]) && strpos($options[$name],'js:')!==0)
- $options[$name]='js:'.$options[$name];
+ if(isset($options[$name]) && (!($options[$name] instanceof CJavaScriptExpression) || strpos($options[$name],'js:')!==0))
+ $options[$name]=new CJavaScriptExpression($options[$name]);
}
if(isset($options['update']))
{
if(!isset($options['success']))
- $options['success']='js:function(html){jQuery("'.$options['update'].'").html(html)}';
+ $options['success']=new CJavaScriptExpression('function(html){jQuery("'.$options['update'].'").html(html)}');
unset($options['update']);
}
if(isset($options['replace']))
{
if(!isset($options['success']))
- $options['success']='js:function(html){jQuery("'.$options['replace'].'").replaceWith(html)}';
+ $options['success']=new CJavaScriptExpression('function(html){jQuery("'.$options['replace'].'").replaceWith(html)}');
unset($options['replace']);
}
return 'jQuery.ajax('.CJavaScript::encode($options).');';
@@ -51,7 +51,8 @@ public static function quote($js,$forUrl=false)
* If you are encoding user input, make sure $safe is set to true.
*
* @param mixed $value PHP variable to be encoded
- * @param boolean $safe If true, 'js:' will not be allowed.
+ * @param boolean $safe If true, 'js:' will not be allowed while
+ * {@link CJavaScriptExpression} will allow you to pass JavaScript expressions.
* Default is false. This parameter is available since 1.1.11.
* @return string the encoded string
*/
@@ -79,6 +80,8 @@ public static function encode($value,$safe=false)
else
return rtrim(sprintf('%.16F',$value),'0'); // locale-independent representation
}
+ else if($value instanceof CJavaScriptExpression)
+ return (string)$value;
else if(is_object($value))
return self::encode(get_object_vars($value));
else if(is_array($value))
@@ -0,0 +1,40 @@
+<?php
+/**
+ * CJavaScriptExpression class file.
+ *
+ * @author Alexander Makarov <sam@rmcreative.ru>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2012 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+/**
+ * CJavaScriptExpression represents a JavaScript expression that does not need escaping.
+ * It can be passed to {@link CJavaScript::encode()} and the code will stay as is
+ * no matter if $safe set to true or not.
+ *
+ * @author Alexander Makarov <sam@rmcreative.ru>
+ * @package system.web.helpers
+ * @since 1.1.11
+ */
+class CJavaScriptExpression
+{
+ public $code;
+
+ /**
+ * @param $code
+ */
+ public function __construct($code)
+ {
+ $this->code=$code;
+ }
+
+ /**
+ * String magic method
+ * @return string the DB expression
+ */
+ public function __toString()
+ {
+ return $this->code;
+ }
+}
@@ -215,7 +215,7 @@ class CActiveForm extends CWidget
* the jquery representation of the form object. If the return value of this function is NOT true, the validation
* will be cancelled.
*
- * Note that because this option refers to a js function, you should prefix the value with 'js:' to prevent it
+ * Note that because this option refers to a js function, you should wrap the value with {@link CJavaScriptExpressoin} to prevent it
* from being encoded as a string. This option has been available since version 1.1.3.</li>
* <li>afterValidate: function, the function that will be invoked after performing ajax-based validation
* triggered by form submission action (available only when validateOnSubmit is set true).
@@ -224,15 +224,15 @@ class CActiveForm extends CWidget
* is a boolean value indicating whether there is any validation error. If the return value of this function is NOT true,
* the normal form submission will be cancelled.
*
- * Note that because this option refers to a js function, you should prefix the value with 'js:' to prevent it
+ * Note that because this option refers to a js function, you should wrap the value with {@link CJavaScriptExpressoin} to prevent it
* from being encoded as a string. This option has been available since version 1.1.3.</li>
* <li>beforeValidateAttribute: function, the function that will be invoked before performing ajax-based validation
* triggered by a single attribute input change. The expected function signature should be
* <code>beforeValidateAttribute(form, attribute) {...}</code>, where 'form' is the jquery representation of the form object
* and 'attribute' refers to the js options for the triggering attribute (see {@link error}).
* If the return value of this function is NOT true, the validation will be cancelled.
*
- * Note that because this option refers to a js function, you should prefix the value with 'js:' to prevent it
+ * Note that because this option refers to a js function, you should wrap the value with {@link CJavaScriptExpressoin} to prevent it
* from being encoded as a string. This option has been available since version 1.1.3.</li>
* <li>afterValidateAttribute: function, the function that will be invoked after performing ajax-based validation
* triggered by a single attribute input change. The expected function signature should be
@@ -241,7 +241,7 @@ class CActiveForm extends CWidget
* 'data' is the JSON response from the server-side validation; 'hasError' is a boolean value indicating whether
* there is any validation error.
*
- * Note that because this option refers to a js function, you should prefix the value with 'js:' to prevent it
+ * Note that because this option refers to a js function, you should wrap the value with {@link CJavaScriptExpressoin} to prevent it
* from being encoded as a string. This option has been available since version 1.1.3.</li>
* </ul>
*
@@ -479,7 +479,7 @@ public function error($model,$attribute,$htmlOptions=array(),$enableAjaxValidati
}
}
if($validators!==array())
- $option['clientValidation']="js:function(value, messages, attribute) {\n".implode("\n",$validators)."\n}";
+ $option['clientValidation']=new CJavaScriptExpression("function(value, messages, attribute) {\n".implode("\n",$validators)."\n}");
}
$html=CHtml::error($model,$attribute,$htmlOptions);
@@ -559,7 +559,7 @@ public function labelEx($model,$attribute,$htmlOptions=array())
{
return CHtml::activeLabelEx($model,$attribute,$htmlOptions);
}
-
+
/**
* Renders a url field for a model attribute.
* This method is a wrapper of {@link CHtml::activeUrlField}.
@@ -575,7 +575,7 @@ public function urlField($model,$attribute,$htmlOptions=array())
{
return CHtml::activeUrlField($model,$attribute,$htmlOptions);
}
-
+
/**
* Renders an email field for a model attribute.
* This method is a wrapper of {@link CHtml::activeEmailField}.
@@ -591,7 +591,7 @@ public function emailField($model,$attribute,$htmlOptions=array())
{
return CHtml::activeEmailField($model,$attribute,$htmlOptions);
}
-
+
/**
* Renders an number field for a model attribute.
* This method is a wrapper of {@link CHtml::activeNumberField}.
@@ -607,7 +607,7 @@ public function numberField($model,$attribute,$htmlOptions=array())
{
return CHtml::activeNumberField($model,$attribute,$htmlOptions);
}
-
+
/**
* Renders an number field for a model attribute.
* This method is a wrapper of {@link CHtml::activeRangeField}.
@@ -183,7 +183,7 @@ class CAutoComplete extends CInputWidget
* @var array additional options that can be passed to the constructor of the autocomplete js object.
* This allows you to override existing functions of the autocomplete js class (e.g. the parse() function)
*
- * If you want to provide JavaScript native code, you have to prefix the string with js: otherwise it will
+ * If you want to provide JavaScript native code, you have to wrap the string with {@link CJavaScriptExpression} otherwise it will
* be enclosed by quotes.
*/
public $options=array();
@@ -282,8 +282,8 @@ protected function getClientOptions()
}
foreach($functions as $func)
{
- if(is_string($this->$func) && strncmp($this->$func,'js:',3))
- $options[$func]='js:'.$this->$func;
+ if(!($func instanceof CJavaScriptExpression) && is_string($this->$func) && strncmp($this->$func,'js:',3))
+ $options[$func]=new CJavaScriptExpression($this->$func);
}
return $options;
@@ -103,8 +103,8 @@ protected function getClientOptions()
$options['placeholder']=$this->placeholder;
if(is_string($this->completed))
{
- if(strncmp($this->completed,'js:',3))
- $options['completed']='js:'.$this->completed;
+ if(!($this->completed instanceof CJavaScriptExpression) && strncmp($this->completed,'js:',3))
+ $options['completed']=new CJavaScriptExpression($this->completed);
else
$options['completed']=$this->completed;
}
@@ -119,8 +119,8 @@ protected function getClientOptions()
$options=$this->options;
foreach(array('onFileRemove','afterFileRemove','onFileAppend','afterFileAppend','onFileSelect','afterFileSelect') as $event)
{
- if(isset($options[$event]) && strpos($options[$event],'js:')!==0)
- $options[$event]='js:'.$options[$event];
+ if(isset($options[$event]) && !($options[$event] instanceof CJavaScriptExpression) && strpos($options[$event],'js:')!==0)
+ $options[$event]=new CJavaScriptExpression($options[$event]);
}
if($this->accept!==null)
@@ -193,22 +193,22 @@ protected function getClientOptions()
$options['readOnly']=true;
if($this->focus!==null)
{
- if(strncmp($this->focus,'js:',3))
- $options['focus']='js:'.$this->focus;
+ if(!($this->focus instanceof CJavaScriptExpression) && strncmp($this->focus,'js:',3))
+ $options['focus']=new CJavaScriptExpression($this->focus);
else
$options['focus']=$this->focus;
}
if($this->blur!==null)
{
- if(strncmp($this->blur,'js:',3))
- $options['blur']='js:'.$this->blur;
+ if(!($this->blur instanceof CJavaScriptExpression) && strncmp($this->blur,'js:',3))
+ $options['blur']=new CJavaScriptExpression($this->blur);
else
$options['blur']=$this->blur;
}
if($this->callback!==null)
{
- if(strncmp($this->callback,'js:',3))
- $options['callback']='js:'.$this->callback;
+ if(!($this->callback instanceof CJavaScriptExpression) && strncmp($this->callback,'js:',3))
+ $options['callback']=new CJavaScriptExpression($this->callback);
else
$options['callback']=$this->callback;
}
@@ -161,11 +161,11 @@ class CListView extends CBaseListView
* @since 1.1.4
*/
public $itemsTagName='div';
-
+
/**
* @var boolean whether to leverage the {@link https://developer.mozilla.org/en/DOM/window.history DOM history object}. Set this property to true
- * to persist state of list across page revisits. Note, there are two limitations for this feature:
- * - this feature is only compatible with browsers that support HTML5.
+ * to persist state of list across page revisits. Note, there are two limitations for this feature:
+ * - this feature is only compatible with browsers that support HTML5.
* - expect unexpected functionality (e.g. multiple ajax calls) if there is more than one grid/list on a single page with enableHistory turned on.
* @since 1.1.11
*/
@@ -219,9 +219,28 @@ public function registerClientScript()
if($this->updateSelector!==null)
$options['updateSelector']=$this->updateSelector;
if($this->beforeAjaxUpdate!==null)
- $options['beforeAjaxUpdate']=(strpos($this->beforeAjaxUpdate,'js:')!==0 ? 'js:' : '').$this->beforeAjaxUpdate;
+ {
+
+ if(!($this->beforeAjaxUpdate instanceof CJavaScriptExpression) && strpos($this->beforeAjaxUpdate,'js:')!==0)
+ {
+ $options['beforeAjaxUpdate']=new CJavaScriptExpression($this->beforeAjaxUpdate);
+ }
+ else
+ {
+ $options['beforeAjaxUpdate']=$this->beforeAjaxUpdate;
+ }
+ }
if($this->afterAjaxUpdate!==null)
- $options['afterAjaxUpdate']=(strpos($this->afterAjaxUpdate,'js:')!==0 ? 'js:' : '').$this->afterAjaxUpdate;
+ {
+ if(!($this->afterAjaxUpdate instanceof CJavaScriptExpression) && strpos($this->afterAjaxUpdate,'js:')!==0)
+ {
+ $options['beforeAjaxUpdate']=new CJavaScriptExpression($this->afterAjaxUpdate);
+ }
+ else
+ {
+ $options['beforeAjaxUpdate']=$this->afterAjaxUpdate;
+ }
+ }
$options=CJavaScript::encode($options);
$cs=Yii::app()->getClientScript();
@@ -175,8 +175,8 @@ public function init()
{
if(!isset($button['options']['class']))
$this->buttons[$id]['options']['class']=$id;
- if(strpos($button['click'],'js:')!==0)
- $this->buttons[$id]['click']='js:'.$button['click'];
+ if(!($button['click'] instanceof CJavaScriptExpression) && strpos($button['click'],'js:')!==0)
+ $this->buttons[$id]['click']=new CJavaScriptExpression($button['click']);
}
}
Oops, something went wrong.

0 comments on commit ada1ced

Please sign in to comment.