Added new (clean) yii boilerplate
This commit is contained in:
955
framework/web/widgets/CActiveForm.php
Normal file
955
framework/web/widgets/CActiveForm.php
Normal file
@@ -0,0 +1,955 @@
|
||||
<?php
|
||||
/**
|
||||
* CActiveForm class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CActiveForm provides a set of methods that can help to simplify the creation
|
||||
* of complex and interactive HTML forms that are associated with data models.
|
||||
*
|
||||
* The 'beginWidget' and 'endWidget' call of CActiveForm widget will render
|
||||
* the open and close form tags. Most other methods of CActiveForm are wrappers
|
||||
* of the corresponding 'active' methods in {@link CHtml}. Calling them in between
|
||||
* the 'beginWidget' and 'endWidget' calls will render text labels, input fields,
|
||||
* etc. For example, calling {@link CActiveForm::textField}
|
||||
* would generate an input field for a specified model attribute.
|
||||
*
|
||||
* What makes CActiveForm extremely useful is its support for data validation.
|
||||
* CActiveForm supports data validation at three levels:
|
||||
* <ul>
|
||||
* <li>server-side validation: the validation is performed at server side after
|
||||
* the whole page containing the form is submitted. If there is any validation error,
|
||||
* CActiveForm will render the error in the page back to user.</li>
|
||||
* <li>AJAX-based validation: when the user enters data into an input field,
|
||||
* an AJAX request is triggered which requires server-side validation. The validation
|
||||
* result is sent back in AJAX response and the input field changes its appearance
|
||||
* accordingly.</li>
|
||||
* <li>client-side validation (available since version 1.1.7):
|
||||
* when the user enters data into an input field,
|
||||
* validation is performed on the client side using JavaScript. No server contact
|
||||
* will be made, which reduces the workload on the server.</li>
|
||||
* </ul>
|
||||
*
|
||||
* All these validations share the same set of validation rules declared in
|
||||
* the associated model class. CActiveForm is designed in such a way that
|
||||
* all these validations will lead to the same user interface changes and error
|
||||
* message content.
|
||||
*
|
||||
* To ensure data validity, server-side validation is always performed.
|
||||
* By setting {@link enableAjaxValidation} to true, one can enable AJAX-based validation;
|
||||
* and by setting {@link enableClientValidation} to true, one can enable client-side validation.
|
||||
* Note that in order to make the latter two validations work, the user's browser
|
||||
* must has its JavaScript enabled. If not, only the server-side validation will
|
||||
* be performed.
|
||||
*
|
||||
* The AJAX-based validation and client-side validation may be used together
|
||||
* or separately. For example, in a user registration form, one may use AJAX-based
|
||||
* validation to check if the user has picked a unique username, and use client-side
|
||||
* validation to ensure all required fields are entered with data.
|
||||
* Because the AJAX-based validation may bring extra workload on the server,
|
||||
* if possible, one should mainly use client-side validation.
|
||||
*
|
||||
* The AJAX-based validation has a few limitations. First, it does not work
|
||||
* with file upload fields. Second, it should not be used to perform validations that
|
||||
* may cause server-side state changes. Third, it is not designed
|
||||
* to work with tabular data input for the moment.
|
||||
*
|
||||
* Support for client-side validation varies for different validators. A validator
|
||||
* will support client-side validation only if it implements {@link CValidator::clientValidateAttribute}
|
||||
* and has its {@link CValidator::enableClientValidation} property set true.
|
||||
* At this moment, the following core validators support client-side validation:
|
||||
* <ul>
|
||||
* <li>{@link CBooleanValidator}</li>
|
||||
* <li>{@link CCaptchaValidator}</li>
|
||||
* <li>{@link CCompareValidator}</li>
|
||||
* <li>{@link CEmailValidator}</li>
|
||||
* <li>{@link CNumberValidator}</li>
|
||||
* <li>{@link CRangeValidator}</li>
|
||||
* <li>{@link CRegularExpressionValidator}</li>
|
||||
* <li>{@link CRequiredValidator}</li>
|
||||
* <li>{@link CStringValidator}</li>
|
||||
* <li>{@link CUrlValidator}</li>
|
||||
* </ul>
|
||||
*
|
||||
* CActiveForm relies on CSS to customize the appearance of input fields
|
||||
* which are in different validation states. In particular, each input field
|
||||
* may be one of the four states: initial (not validated),
|
||||
* validating, error and success. To differentiate these states, CActiveForm
|
||||
* automatically assigns different CSS classes for the last three states
|
||||
* to the HTML element containing the input field.
|
||||
* By default, these CSS classes are named as 'validating', 'error' and 'success',
|
||||
* respectively. We may customize these CSS classes by configuring the
|
||||
* {@link clientOptions} property or specifying in the {@link error} method.
|
||||
*
|
||||
* The following is a piece of sample view code showing how to use CActiveForm:
|
||||
*
|
||||
* <pre>
|
||||
* <?php $form = $this->beginWidget('CActiveForm', array(
|
||||
* 'id'=>'user-form',
|
||||
* 'enableAjaxValidation'=>true,
|
||||
* 'enableClientValidation'=>true,
|
||||
* 'focus'=>array($model,'firstName'),
|
||||
* )); ?>
|
||||
*
|
||||
* <?php echo $form->errorSummary($model); ?>
|
||||
*
|
||||
* <div class="row">
|
||||
* <?php echo $form->labelEx($model,'firstName'); ?>
|
||||
* <?php echo $form->textField($model,'firstName'); ?>
|
||||
* <?php echo $form->error($model,'firstName'); ?>
|
||||
* </div>
|
||||
* <div class="row">
|
||||
* <?php echo $form->labelEx($model,'lastName'); ?>
|
||||
* <?php echo $form->textField($model,'lastName'); ?>
|
||||
* <?php echo $form->error($model,'lastName'); ?>
|
||||
* </div>
|
||||
*
|
||||
* <?php $this->endWidget(); ?>
|
||||
* </pre>
|
||||
*
|
||||
* To respond to the AJAX validation requests, we need the following class code:
|
||||
* <pre>
|
||||
* public function actionCreate()
|
||||
* {
|
||||
* $model=new User;
|
||||
* $this->performAjaxValidation($model);
|
||||
* if(isset($_POST['User']))
|
||||
* {
|
||||
* $model->attributes=$_POST['User'];
|
||||
* if($model->save())
|
||||
* $this->redirect('index');
|
||||
* }
|
||||
* $this->render('create',array('model'=>$model));
|
||||
* }
|
||||
*
|
||||
* protected function performAjaxValidation($model)
|
||||
* {
|
||||
* if(isset($_POST['ajax']) && $_POST['ajax']==='user-form')
|
||||
* {
|
||||
* echo CActiveForm::validate($model);
|
||||
* Yii::app()->end();
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* In the above code, if we do not enable the AJAX-based validation, we can remove
|
||||
* the <code>performAjaxValidation</code> method and its invocation.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets
|
||||
* @since 1.1.1
|
||||
*/
|
||||
class CActiveForm extends CWidget
|
||||
{
|
||||
/**
|
||||
* @var mixed the form action URL (see {@link CHtml::normalizeUrl} for details about this parameter).
|
||||
* If not set, the current page URL is used.
|
||||
*/
|
||||
public $action='';
|
||||
/**
|
||||
* @var string the form submission method. This should be either 'post' or 'get'.
|
||||
* Defaults to 'post'.
|
||||
*/
|
||||
public $method='post';
|
||||
/**
|
||||
* @var boolean whether to generate a stateful form (See {@link CHtml::statefulForm}). Defaults to false.
|
||||
*/
|
||||
public $stateful=false;
|
||||
/**
|
||||
* @var string the CSS class name for error messages.
|
||||
* Since 1.1.14 this defaults to 'errorMessage' defined in {@link CHtml::$errorMessageCss}.
|
||||
* Individual {@link error} call may override this value by specifying the 'class' HTML option.
|
||||
*/
|
||||
public $errorMessageCssClass;
|
||||
/**
|
||||
* @var array additional HTML attributes that should be rendered for the form tag.
|
||||
*/
|
||||
public $htmlOptions=array();
|
||||
/**
|
||||
* @var array the options to be passed to the javascript validation plugin.
|
||||
* The following options are supported:
|
||||
* <ul>
|
||||
* <li>ajaxVar: string, the name of the parameter indicating the request is an AJAX request.
|
||||
* When the AJAX validation is triggered, a parameter named as this property will be sent
|
||||
* together with the other form data to the server. The parameter value is the form ID.
|
||||
* The server side can then detect who triggers the AJAX validation and react accordingly.
|
||||
* Defaults to 'ajax'.</li>
|
||||
* <li>validationUrl: string, the URL that performs the AJAX validations.
|
||||
* If not set, it will take the value of {@link action}.</li>
|
||||
* <li>validationDelay: integer, the number of milliseconds that an AJAX validation should be
|
||||
* delayed after an input is changed. A value 0 means the validation will be triggered immediately
|
||||
* when an input is changed. A value greater than 0 means changing several inputs may only
|
||||
* trigger a single validation if they happen fast enough, which may help reduce the server load.
|
||||
* Defaults to 200 (0.2 second).</li>
|
||||
* <li>validateOnSubmit: boolean, whether to perform AJAX validation when the form is being submitted.
|
||||
* If there are any validation errors, the form submission will be stopped.
|
||||
* Defaults to false.</li>
|
||||
* <li>validateOnChange: boolean, whether to trigger an AJAX validation
|
||||
* each time when an input's value is changed. You may want to turn this off
|
||||
* if it causes too much performance impact, because each AJAX validation request
|
||||
* will submit the data of the whole form. Defaults to true.</li>
|
||||
* <li>validateOnType: boolean, whether to trigger an AJAX validation each time when the user
|
||||
* presses a key. When setting this property to be true, you should tune up the 'validationDelay'
|
||||
* option to avoid triggering too many AJAX validations. Defaults to false.</li>
|
||||
* <li>hideErrorMessage: boolean, whether to hide the error message even if there is an error.
|
||||
* Defaults to false, which means the error message will show up whenever the input has an error.</li>
|
||||
* <li>inputContainer: string, the jQuery selector for the HTML element containing the input field.
|
||||
* During the validation process, CActiveForm will set different CSS class for the container element
|
||||
* to indicate the state change. If not set, it means the closest 'div' element that contains the input field.</li>
|
||||
* <li>errorCssClass: string, the CSS class to be assigned to the container whose associated input
|
||||
* has AJAX validation error. Defaults to 'error'.</li>
|
||||
* <li>successCssClass: string, the CSS class to be assigned to the container whose associated input
|
||||
* passes AJAX validation without any error. Defaults to 'success'.</li>
|
||||
* <li>validatingCssClass: string, the CSS class to be assigned to the container whose associated input
|
||||
* is currently being validated via AJAX. Defaults to 'validating'.</li>
|
||||
* <li>errorMessageCssClass: string, the CSS class assigned to the error messages returned
|
||||
* by AJAX validations. Defaults to 'errorMessage'.</li>
|
||||
* <li>beforeValidate: function, the function that will be invoked before performing ajax-based validation
|
||||
* triggered by form submission action (available only when validateOnSubmit is set true).
|
||||
* The expected function signature should be <code>beforeValidate(form) {...}</code>, where 'form' is
|
||||
* 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 wrap the value with {@link CJavaScriptExpression} 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).
|
||||
* The expected function signature should be <code>afterValidate(form, data, hasError) {...}</code>, where 'form' is
|
||||
* the jquery representation of the form object; 'data' is the JSON response from the server-side validation; 'hasError'
|
||||
* 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 wrap the value with {@link CJavaScriptExpression} 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 wrap the value with {@link CJavaScriptExpression} 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
|
||||
* <code>afterValidateAttribute(form, attribute, data, hasError) {...}</code>, where 'form' is the jquery
|
||||
* representation of the form object; 'attribute' refers to the js options for the triggering attribute (see {@link error});
|
||||
* '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 wrap the value with {@link CJavaScriptExpression} to prevent it
|
||||
* from being encoded as a string. This option has been available since version 1.1.3.</li>
|
||||
* </ul>
|
||||
*
|
||||
* Some of the above options may be overridden in individual calls of {@link error()}.
|
||||
* They include: validationDelay, validateOnChange, validateOnType, hideErrorMessage,
|
||||
* inputContainer, errorCssClass, successCssClass, validatingCssClass, beforeValidateAttribute, afterValidateAttribute.
|
||||
*/
|
||||
public $clientOptions=array();
|
||||
/**
|
||||
* @var boolean whether to enable data validation via AJAX. Defaults to false.
|
||||
* When this property is set true, you should respond to the AJAX validation request on the server side as shown below:
|
||||
* <pre>
|
||||
* public function actionCreate()
|
||||
* {
|
||||
* $model=new User;
|
||||
* if(isset($_POST['ajax']) && $_POST['ajax']==='user-form')
|
||||
* {
|
||||
* echo CActiveForm::validate($model);
|
||||
* Yii::app()->end();
|
||||
* }
|
||||
* ......
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public $enableAjaxValidation=false;
|
||||
/**
|
||||
* @var boolean whether to enable client-side data validation. Defaults to false.
|
||||
*
|
||||
* When this property is set true, client-side validation will be performed by validators
|
||||
* that support it (see {@link CValidator::enableClientValidation} and {@link CValidator::clientValidateAttribute}).
|
||||
*
|
||||
* @see error
|
||||
* @since 1.1.7
|
||||
*/
|
||||
public $enableClientValidation=false;
|
||||
|
||||
/**
|
||||
* @var mixed form element to get initial input focus on page load.
|
||||
*
|
||||
* Defaults to null meaning no input field has a focus.
|
||||
* If set as array, first element should be model and second element should be the attribute.
|
||||
* If set as string any jQuery selector can be used
|
||||
*
|
||||
* Example - set input focus on page load to:
|
||||
* <ul>
|
||||
* <li>'focus'=>array($model,'username') - $model->username input filed</li>
|
||||
* <li>'focus'=>'#'.CHtml::activeId($model,'username') - $model->username input field</li>
|
||||
* <li>'focus'=>'#LoginForm_username' - input field with ID LoginForm_username</li>
|
||||
* <li>'focus'=>'input[type="text"]:first' - first input element of type text</li>
|
||||
* <li>'focus'=>'input:visible:enabled:first' - first visible and enabled input element</li>
|
||||
* <li>'focus'=>'input:text[value=""]:first' - first empty input</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 1.1.4
|
||||
*/
|
||||
public $focus;
|
||||
/**
|
||||
* @var array the javascript options for model attributes (input ID => options)
|
||||
* @see error
|
||||
* @since 1.1.7
|
||||
*/
|
||||
protected $attributes=array();
|
||||
/**
|
||||
* @var string the ID of the container element for error summary
|
||||
* @see errorSummary
|
||||
* @since 1.1.7
|
||||
*/
|
||||
protected $summaryID;
|
||||
/**
|
||||
* @var string[] attribute IDs to be used to display error summary.
|
||||
* @since 1.1.14
|
||||
*/
|
||||
private $_summaryAttributes=array();
|
||||
|
||||
/**
|
||||
* Initializes the widget.
|
||||
* This renders the form open tag.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if(!isset($this->htmlOptions['id']))
|
||||
$this->htmlOptions['id']=$this->id;
|
||||
else
|
||||
$this->id=$this->htmlOptions['id'];
|
||||
|
||||
if($this->stateful)
|
||||
echo CHtml::statefulForm($this->action, $this->method, $this->htmlOptions);
|
||||
else
|
||||
echo CHtml::beginForm($this->action, $this->method, $this->htmlOptions);
|
||||
|
||||
if($this->errorMessageCssClass===null)
|
||||
$this->errorMessageCssClass=CHtml::$errorMessageCss;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the widget.
|
||||
* This registers the necessary javascript code and renders the form close tag.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
if(is_array($this->focus))
|
||||
$this->focus="#".CHtml::activeId($this->focus[0],$this->focus[1]);
|
||||
|
||||
echo CHtml::endForm();
|
||||
$cs=Yii::app()->clientScript;
|
||||
if(!$this->enableAjaxValidation && !$this->enableClientValidation || empty($this->attributes))
|
||||
{
|
||||
if($this->focus!==null)
|
||||
{
|
||||
$cs->registerCoreScript('jquery');
|
||||
$cs->registerScript('CActiveForm#focus',"
|
||||
if(!window.location.hash)
|
||||
jQuery('".$this->focus."').focus();
|
||||
");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$options=$this->clientOptions;
|
||||
if(isset($this->clientOptions['validationUrl']) && is_array($this->clientOptions['validationUrl']))
|
||||
$options['validationUrl']=CHtml::normalizeUrl($this->clientOptions['validationUrl']);
|
||||
|
||||
foreach($this->_summaryAttributes as $attribute)
|
||||
$this->attributes[$attribute]['summary']=true;
|
||||
$options['attributes']=array_values($this->attributes);
|
||||
|
||||
if($this->summaryID!==null)
|
||||
$options['summaryID']=$this->summaryID;
|
||||
|
||||
if($this->focus!==null)
|
||||
$options['focus']=$this->focus;
|
||||
|
||||
if(!empty(CHtml::$errorCss))
|
||||
$options['errorCss']=CHtml::$errorCss;
|
||||
|
||||
$options=CJavaScript::encode($options);
|
||||
$cs->registerCoreScript('yiiactiveform');
|
||||
$id=$this->id;
|
||||
$cs->registerScript(__CLASS__.'#'.$id,"jQuery('#$id').yiiactiveform($options);");
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the first validation error for a model attribute.
|
||||
* This is similar to {@link CHtml::error} except that it registers the model attribute
|
||||
* so that if its value is changed by users, an AJAX validation may be triggered.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute name
|
||||
* @param array $htmlOptions additional HTML attributes to be rendered in the container div tag.
|
||||
* Besides all those options available in {@link CHtml::error}, the following options are recognized in addition:
|
||||
* <ul>
|
||||
* <li>validationDelay</li>
|
||||
* <li>validateOnChange</li>
|
||||
* <li>validateOnType</li>
|
||||
* <li>hideErrorMessage</li>
|
||||
* <li>inputContainer</li>
|
||||
* <li>errorCssClass</li>
|
||||
* <li>successCssClass</li>
|
||||
* <li>validatingCssClass</li>
|
||||
* <li>beforeValidateAttribute</li>
|
||||
* <li>afterValidateAttribute</li>
|
||||
* </ul>
|
||||
* These options override the corresponding options as declared in {@link options} for this
|
||||
* particular model attribute. For more details about these options, please refer to {@link clientOptions}.
|
||||
* Note that these options are only used when {@link enableAjaxValidation} or {@link enableClientValidation}
|
||||
* is set true.
|
||||
* <ul>
|
||||
* <li>inputID</li>
|
||||
* </ul>
|
||||
* When an CActiveForm input field uses a custom ID, for ajax/client validation to work properly
|
||||
* inputID should be set to the same ID
|
||||
*
|
||||
* Example:
|
||||
* <pre>
|
||||
* <div class="form-element">
|
||||
* <?php echo $form->labelEx($model,'attribute'); ?>
|
||||
* <?php echo $form->textField($model,'attribute', array('id'=>'custom-id')); ?>
|
||||
* <?php echo $form->error($model,'attribute',array('inputID'=>'custom-id')); ?>
|
||||
* </div>
|
||||
* </pre>
|
||||
*
|
||||
* When client-side validation is enabled, an option named "clientValidation" is also recognized.
|
||||
* This option should take a piece of JavaScript code to perform client-side validation. In the code,
|
||||
* the variables are predefined:
|
||||
* <ul>
|
||||
* <li>value: the current input value associated with this attribute.</li>
|
||||
* <li>messages: an array that may be appended with new error messages for the attribute.</li>
|
||||
* <li>attribute: a data structure keeping all client-side options for the attribute</li>
|
||||
* </ul>
|
||||
* This should NOT be a function but just the code, Yii will enclose the code you provide inside the
|
||||
* actual JS function.
|
||||
* @param boolean $enableAjaxValidation whether to enable AJAX validation for the specified attribute.
|
||||
* Note that in order to enable AJAX validation, both {@link enableAjaxValidation} and this parameter
|
||||
* must be true.
|
||||
* @param boolean $enableClientValidation whether to enable client-side validation for the specified attribute.
|
||||
* Note that in order to enable client-side validation, both {@link enableClientValidation} and this parameter
|
||||
* must be true. This parameter has been available since version 1.1.7.
|
||||
* @return string the validation result (error display or success message).
|
||||
* @see CHtml::error
|
||||
*/
|
||||
public function error($model,$attribute,$htmlOptions=array(),$enableAjaxValidation=true,$enableClientValidation=true)
|
||||
{
|
||||
if(!$this->enableAjaxValidation)
|
||||
$enableAjaxValidation=false;
|
||||
if(!$this->enableClientValidation)
|
||||
$enableClientValidation=false;
|
||||
|
||||
if(!isset($htmlOptions['class']))
|
||||
$htmlOptions['class']=$this->errorMessageCssClass;
|
||||
|
||||
if(!$enableAjaxValidation && !$enableClientValidation)
|
||||
return CHtml::error($model,$attribute,$htmlOptions);
|
||||
|
||||
$id=CHtml::activeId($model,$attribute);
|
||||
$inputID=isset($htmlOptions['inputID']) ? $htmlOptions['inputID'] : $id;
|
||||
unset($htmlOptions['inputID']);
|
||||
if(!isset($htmlOptions['id']))
|
||||
$htmlOptions['id']=$inputID.'_em_';
|
||||
|
||||
$option=array(
|
||||
'id'=>$id,
|
||||
'inputID'=>$inputID,
|
||||
'errorID'=>$htmlOptions['id'],
|
||||
'model'=>get_class($model),
|
||||
'name'=>$attribute,
|
||||
'enableAjaxValidation'=>$enableAjaxValidation,
|
||||
);
|
||||
|
||||
$optionNames=array(
|
||||
'validationDelay',
|
||||
'validateOnChange',
|
||||
'validateOnType',
|
||||
'hideErrorMessage',
|
||||
'inputContainer',
|
||||
'errorCssClass',
|
||||
'successCssClass',
|
||||
'validatingCssClass',
|
||||
'beforeValidateAttribute',
|
||||
'afterValidateAttribute',
|
||||
);
|
||||
foreach($optionNames as $name)
|
||||
{
|
||||
if(isset($htmlOptions[$name]))
|
||||
{
|
||||
$option[$name]=$htmlOptions[$name];
|
||||
unset($htmlOptions[$name]);
|
||||
}
|
||||
}
|
||||
if($model instanceof CActiveRecord && !$model->isNewRecord)
|
||||
$option['status']=1;
|
||||
|
||||
if($enableClientValidation)
|
||||
{
|
||||
$validators=isset($htmlOptions['clientValidation']) ? array($htmlOptions['clientValidation']) : array();
|
||||
unset($htmlOptions['clientValidation']);
|
||||
|
||||
$attributeName = $attribute;
|
||||
if(($pos=strrpos($attribute,']'))!==false && $pos!==strlen($attribute)-1) // e.g. [a]name
|
||||
{
|
||||
$attributeName=substr($attribute,$pos+1);
|
||||
}
|
||||
|
||||
foreach($model->getValidators($attributeName) as $validator)
|
||||
{
|
||||
if($validator->enableClientValidation)
|
||||
{
|
||||
if(($js=$validator->clientValidateAttribute($model,$attributeName))!='')
|
||||
$validators[]=$js;
|
||||
}
|
||||
}
|
||||
if($validators!==array())
|
||||
$option['clientValidation']=new CJavaScriptExpression("function(value, messages, attribute) {\n".implode("\n",$validators)."\n}");
|
||||
}
|
||||
|
||||
$html=CHtml::error($model,$attribute,$htmlOptions);
|
||||
if($html==='')
|
||||
{
|
||||
if(isset($htmlOptions['style']))
|
||||
$htmlOptions['style']=rtrim($htmlOptions['style'],';').';display:none';
|
||||
else
|
||||
$htmlOptions['style']='display:none';
|
||||
$html=CHtml::tag(CHtml::$errorContainerTag,$htmlOptions,'');
|
||||
}
|
||||
|
||||
$this->attributes[$inputID]=$option;
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a summary of validation errors for one or several models.
|
||||
* This method is very similar to {@link CHtml::errorSummary} except that it also works
|
||||
* when AJAX validation is performed.
|
||||
* @param mixed $models the models whose input errors are to be displayed. This can be either
|
||||
* a single model or an array of models.
|
||||
* @param string $header a piece of HTML code that appears in front of the errors
|
||||
* @param string $footer a piece of HTML code that appears at the end of the errors
|
||||
* @param array $htmlOptions additional HTML attributes to be rendered in the container div tag.
|
||||
* @return string the error summary. Empty if no errors are found.
|
||||
* @see CHtml::errorSummary
|
||||
*/
|
||||
public function errorSummary($models,$header=null,$footer=null,$htmlOptions=array())
|
||||
{
|
||||
if(!$this->enableAjaxValidation && !$this->enableClientValidation)
|
||||
return CHtml::errorSummary($models,$header,$footer,$htmlOptions);
|
||||
|
||||
if(!isset($htmlOptions['id']))
|
||||
$htmlOptions['id']=$this->id.'_es_';
|
||||
$html=CHtml::errorSummary($models,$header,$footer,$htmlOptions);
|
||||
if($html==='')
|
||||
{
|
||||
if($header===null)
|
||||
$header='<p>'.Yii::t('yii','Please fix the following input errors:').'</p>';
|
||||
if(!isset($htmlOptions['class']))
|
||||
$htmlOptions['class']=CHtml::$errorSummaryCss;
|
||||
$htmlOptions['style']=isset($htmlOptions['style']) ? rtrim($htmlOptions['style'],';').';display:none' : 'display:none';
|
||||
$html=CHtml::tag('div',$htmlOptions,$header."\n<ul><li>dummy</li></ul>".$footer);
|
||||
}
|
||||
|
||||
$this->summaryID=$htmlOptions['id'];
|
||||
foreach(is_array($models) ? $models : array($models) as $model)
|
||||
foreach($model->getSafeAttributeNames() as $attribute)
|
||||
$this->_summaryAttributes[]=CHtml::activeId($model,$attribute);
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders an HTML label for a model attribute.
|
||||
* This method is a wrapper of {@link CHtml::activeLabel}.
|
||||
* Please check {@link CHtml::activeLabel} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $htmlOptions additional HTML attributes.
|
||||
* @return string the generated label tag
|
||||
*/
|
||||
public function label($model,$attribute,$htmlOptions=array())
|
||||
{
|
||||
return CHtml::activeLabel($model,$attribute,$htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders an HTML label for a model attribute.
|
||||
* This method is a wrapper of {@link CHtml::activeLabelEx}.
|
||||
* Please check {@link CHtml::activeLabelEx} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $htmlOptions additional HTML attributes.
|
||||
* @return string the generated label tag
|
||||
*/
|
||||
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}.
|
||||
* Please check {@link CHtml::activeUrlField} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $htmlOptions additional HTML attributes.
|
||||
* @return string the generated input field
|
||||
* @since 1.1.11
|
||||
*/
|
||||
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}.
|
||||
* Please check {@link CHtml::activeEmailField} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $htmlOptions additional HTML attributes.
|
||||
* @return string the generated input field
|
||||
* @since 1.1.11
|
||||
*/
|
||||
public function emailField($model,$attribute,$htmlOptions=array())
|
||||
{
|
||||
return CHtml::activeEmailField($model,$attribute,$htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a number field for a model attribute.
|
||||
* This method is a wrapper of {@link CHtml::activeNumberField}.
|
||||
* Please check {@link CHtml::activeNumberField} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $htmlOptions additional HTML attributes.
|
||||
* @return string the generated input field
|
||||
* @since 1.1.11
|
||||
*/
|
||||
public function numberField($model,$attribute,$htmlOptions=array())
|
||||
{
|
||||
return CHtml::activeNumberField($model,$attribute,$htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a range field for a model attribute.
|
||||
* This method is a wrapper of {@link CHtml::activeRangeField}.
|
||||
* Please check {@link CHtml::activeRangeField} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $htmlOptions additional HTML attributes.
|
||||
* @return string the generated input field
|
||||
* @since 1.1.11
|
||||
*/
|
||||
public function rangeField($model,$attribute,$htmlOptions=array())
|
||||
{
|
||||
return CHtml::activeRangeField($model,$attribute,$htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a date field for a model attribute.
|
||||
* This method is a wrapper of {@link CHtml::activeDateField}.
|
||||
* Please check {@link CHtml::activeDateField} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $htmlOptions additional HTML attributes.
|
||||
* @return string the generated input field
|
||||
* @since 1.1.11
|
||||
*/
|
||||
public function dateField($model,$attribute,$htmlOptions=array())
|
||||
{
|
||||
return CHtml::activeDateField($model,$attribute,$htmlOptions);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders a time field for a model attribute.
|
||||
* This method is a wrapper of {@link CHtml::activeTimeField}.
|
||||
* Please check {@link CHtml::activeTimeField} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $htmlOptions additional HTML attributes.
|
||||
* @return string the generated input field
|
||||
* @since 1.1.14
|
||||
*/
|
||||
public function timeField($model,$attribute,$htmlOptions=array())
|
||||
{
|
||||
return CHtml::activeTimeField($model,$attribute,$htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a time field for a model attribute.
|
||||
* This method is a wrapper of {@link CHtml::activeTimeField}.
|
||||
* Please check {@link CHtml::activeTimeField} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $htmlOptions additional HTML attributes.
|
||||
* @return string the generated input field
|
||||
* @since 1.1.14
|
||||
*/
|
||||
public function telField($model,$attribute,$htmlOptions=array())
|
||||
{
|
||||
return CHtml::activeTelField($model,$attribute,$htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a text field for a model attribute.
|
||||
* This method is a wrapper of {@link CHtml::activeTextField}.
|
||||
* Please check {@link CHtml::activeTextField} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $htmlOptions additional HTML attributes.
|
||||
* @return string the generated input field
|
||||
*/
|
||||
public function textField($model,$attribute,$htmlOptions=array())
|
||||
{
|
||||
return CHtml::activeTextField($model,$attribute,$htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a search field for a model attribute.
|
||||
* This method is a wrapper of {@link CHtml::activeSearchField}.
|
||||
* Please check {@link CHtml::activeSearchField} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $htmlOptions additional HTML attributes.
|
||||
* @return string the generated input field
|
||||
* @since 1.1.14
|
||||
*/
|
||||
public function searchField($model,$attribute,$htmlOptions=array())
|
||||
{
|
||||
return CHtml::activeSearchField($model,$attribute,$htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a hidden field for a model attribute.
|
||||
* This method is a wrapper of {@link CHtml::activeHiddenField}.
|
||||
* Please check {@link CHtml::activeHiddenField} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $htmlOptions additional HTML attributes.
|
||||
* @return string the generated input field
|
||||
*/
|
||||
public function hiddenField($model,$attribute,$htmlOptions=array())
|
||||
{
|
||||
return CHtml::activeHiddenField($model,$attribute,$htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a password field for a model attribute.
|
||||
* This method is a wrapper of {@link CHtml::activePasswordField}.
|
||||
* Please check {@link CHtml::activePasswordField} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $htmlOptions additional HTML attributes.
|
||||
* @return string the generated input field
|
||||
*/
|
||||
public function passwordField($model,$attribute,$htmlOptions=array())
|
||||
{
|
||||
return CHtml::activePasswordField($model,$attribute,$htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a text area for a model attribute.
|
||||
* This method is a wrapper of {@link CHtml::activeTextArea}.
|
||||
* Please check {@link CHtml::activeTextArea} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $htmlOptions additional HTML attributes.
|
||||
* @return string the generated text area
|
||||
*/
|
||||
public function textArea($model,$attribute,$htmlOptions=array())
|
||||
{
|
||||
return CHtml::activeTextArea($model,$attribute,$htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a file field for a model attribute.
|
||||
* This method is a wrapper of {@link CHtml::activeFileField}.
|
||||
* Please check {@link CHtml::activeFileField} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $htmlOptions additional HTML attributes
|
||||
* @return string the generated input field
|
||||
*/
|
||||
public function fileField($model,$attribute,$htmlOptions=array())
|
||||
{
|
||||
return CHtml::activeFileField($model,$attribute,$htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a radio button for a model attribute.
|
||||
* This method is a wrapper of {@link CHtml::activeRadioButton}.
|
||||
* Please check {@link CHtml::activeRadioButton} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $htmlOptions additional HTML attributes.
|
||||
* @return string the generated radio button
|
||||
*/
|
||||
public function radioButton($model,$attribute,$htmlOptions=array())
|
||||
{
|
||||
return CHtml::activeRadioButton($model,$attribute,$htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a checkbox for a model attribute.
|
||||
* This method is a wrapper of {@link CHtml::activeCheckBox}.
|
||||
* Please check {@link CHtml::activeCheckBox} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $htmlOptions additional HTML attributes.
|
||||
* @return string the generated check box
|
||||
*/
|
||||
public function checkBox($model,$attribute,$htmlOptions=array())
|
||||
{
|
||||
return CHtml::activeCheckBox($model,$attribute,$htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a dropdown list for a model attribute.
|
||||
* This method is a wrapper of {@link CHtml::activeDropDownList}.
|
||||
* Please check {@link CHtml::activeDropDownList} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $data data for generating the list options (value=>display)
|
||||
* @param array $htmlOptions additional HTML attributes.
|
||||
* @return string the generated drop down list
|
||||
*/
|
||||
public function dropDownList($model,$attribute,$data,$htmlOptions=array())
|
||||
{
|
||||
return CHtml::activeDropDownList($model,$attribute,$data,$htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a list box for a model attribute.
|
||||
* This method is a wrapper of {@link CHtml::activeListBox}.
|
||||
* Please check {@link CHtml::activeListBox} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $data data for generating the list options (value=>display)
|
||||
* @param array $htmlOptions additional HTML attributes.
|
||||
* @return string the generated list box
|
||||
*/
|
||||
public function listBox($model,$attribute,$data,$htmlOptions=array())
|
||||
{
|
||||
return CHtml::activeListBox($model,$attribute,$data,$htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a checkbox list for a model attribute.
|
||||
* This method is a wrapper of {@link CHtml::activeCheckBoxList}.
|
||||
* Please check {@link CHtml::activeCheckBoxList} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $data value-label pairs used to generate the check box list.
|
||||
* @param array $htmlOptions addtional HTML options.
|
||||
* @return string the generated check box list
|
||||
*/
|
||||
public function checkBoxList($model,$attribute,$data,$htmlOptions=array())
|
||||
{
|
||||
return CHtml::activeCheckBoxList($model,$attribute,$data,$htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a radio button list for a model attribute.
|
||||
* This method is a wrapper of {@link CHtml::activeRadioButtonList}.
|
||||
* Please check {@link CHtml::activeRadioButtonList} for detailed information
|
||||
* about the parameters for this method.
|
||||
* @param CModel $model the data model
|
||||
* @param string $attribute the attribute
|
||||
* @param array $data value-label pairs used to generate the radio button list.
|
||||
* @param array $htmlOptions addtional HTML options.
|
||||
* @return string the generated radio button list
|
||||
*/
|
||||
public function radioButtonList($model,$attribute,$data,$htmlOptions=array())
|
||||
{
|
||||
return CHtml::activeRadioButtonList($model,$attribute,$data,$htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates one or several models and returns the results in JSON format.
|
||||
* This is a helper method that simplifies the way of writing AJAX validation code.
|
||||
* @param mixed $models a single model instance or an array of models.
|
||||
* @param array $attributes list of attributes that should be validated. Defaults to null,
|
||||
* meaning any attribute listed in the applicable validation rules of the models should be
|
||||
* validated. If this parameter is given as a list of attributes, only
|
||||
* the listed attributes will be validated.
|
||||
* @param boolean $loadInput whether to load the data from $_POST array in this method.
|
||||
* If this is true, the model will be populated from <code>$_POST[ModelClass]</code>.
|
||||
* @return string the JSON representation of the validation error messages.
|
||||
*/
|
||||
public static function validate($models, $attributes=null, $loadInput=true)
|
||||
{
|
||||
$result=array();
|
||||
if(!is_array($models))
|
||||
$models=array($models);
|
||||
foreach($models as $model)
|
||||
{
|
||||
$modelName=CHtml::modelName($model);
|
||||
if($loadInput && isset($_POST[$modelName]))
|
||||
$model->attributes=$_POST[$modelName];
|
||||
$model->validate($attributes);
|
||||
foreach($model->getErrors() as $attribute=>$errors)
|
||||
$result[CHtml::activeId($model,$attribute)]=$errors;
|
||||
}
|
||||
return function_exists('json_encode') ? json_encode($result) : CJSON::encode($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an array of model instances and returns the results in JSON format.
|
||||
* This is a helper method that simplifies the way of writing AJAX validation code for tabular input.
|
||||
* @param mixed $models an array of model instances.
|
||||
* @param array $attributes list of attributes that should be validated. Defaults to null,
|
||||
* meaning any attribute listed in the applicable validation rules of the models should be
|
||||
* validated. If this parameter is given as a list of attributes, only
|
||||
* the listed attributes will be validated.
|
||||
* @param boolean $loadInput whether to load the data from $_POST array in this method.
|
||||
* If this is true, the model will be populated from <code>$_POST[ModelClass][$i]</code>.
|
||||
* @return string the JSON representation of the validation error messages.
|
||||
*/
|
||||
public static function validateTabular($models, $attributes=null, $loadInput=true)
|
||||
{
|
||||
$result=array();
|
||||
if(!is_array($models))
|
||||
$models=array($models);
|
||||
foreach($models as $i=>$model)
|
||||
{
|
||||
$modelName=CHtml::modelName($model);
|
||||
if($loadInput && isset($_POST[$modelName][$i]))
|
||||
$model->attributes=$_POST[$modelName][$i];
|
||||
$model->validate($attributes);
|
||||
foreach($model->getErrors() as $attribute=>$errors)
|
||||
$result[CHtml::activeId($model,'['.$i.']'.$attribute)]=$errors;
|
||||
}
|
||||
return function_exists('json_encode') ? json_encode($result) : CJSON::encode($result);
|
||||
}
|
||||
}
|
||||
294
framework/web/widgets/CAutoComplete.php
Normal file
294
framework/web/widgets/CAutoComplete.php
Normal file
@@ -0,0 +1,294 @@
|
||||
<?php
|
||||
/**
|
||||
* CAutoComplete class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CAutoComplete generates an auto-complete text field.
|
||||
*
|
||||
* CAutoComplete is based on the {@link http://plugins.jquery.com/project/autocompletex jQuery Autocomplete}.
|
||||
*
|
||||
* This class is deprecated since Yii 1.1.3. Consider using CJuiAutoComplete.
|
||||
* There is {@link http://www.learningjquery.com/2010/06/autocomplete-migration-guide a good migration guide from the author of both JavaScript solutions}.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets
|
||||
* @since 1.0
|
||||
* @deprecated in 1.1.3
|
||||
*/
|
||||
class CAutoComplete extends CInputWidget
|
||||
{
|
||||
/**
|
||||
* @var boolean whether to show the autocomplete using a text area. Defaults to false,
|
||||
* meaning a text field is used.
|
||||
*/
|
||||
public $textArea=false;
|
||||
/**
|
||||
* @var array data that would be saved as client-side data to provide candidate selections.
|
||||
* Each array element can be string or an associative array.
|
||||
* The {@link url} property will be ignored if this property is set.
|
||||
* @see url
|
||||
*/
|
||||
public $data;
|
||||
/**
|
||||
* @var string|array the URL that can return the candidate selections.
|
||||
* A 'q' GET parameter will be sent with the URL which contains what the user has entered so far.
|
||||
* If the URL is given as an array, it is considered as a route to a controller action and will
|
||||
* be used to generate a URL using {@link CController::createUrl};
|
||||
* If the URL is an empty string, the currently requested URL is used.
|
||||
* This property will be ignored if {@link data} is set.
|
||||
* @see data
|
||||
*/
|
||||
public $url='';
|
||||
/**
|
||||
* @var mixed the CSS file used for the widget. Defaults to null, meaning
|
||||
* using the default CSS file included together with the widget.
|
||||
* If false, no CSS file will be used. Otherwise, the specified CSS file
|
||||
* will be included when using this widget.
|
||||
*/
|
||||
public $cssFile;
|
||||
/**
|
||||
* @var integer the minimum number of characters a user has to type before
|
||||
* the autocompleter activates. Defaults to 1.
|
||||
*/
|
||||
public $minChars;
|
||||
/**
|
||||
* @var integer the delay in milliseconds the autocompleter waits after
|
||||
* a keystroke to activate itself. Defaults to 400.
|
||||
*/
|
||||
public $delay;
|
||||
/**
|
||||
* @var integer the number of backend query results to store in cache.
|
||||
* If set to 1 (the current result), no caching will happen. Must be >= 1. Defaults to 10.
|
||||
*/
|
||||
public $cacheLength;
|
||||
/**
|
||||
* @var boolean whether or not the autocompleter can use a cache for more
|
||||
* specific queries. This means that all matches of "foot" are a subset
|
||||
* of all matches for "foo". Usually this is true, and using this options
|
||||
* decreases server load and increases performance. Only useful with
|
||||
* cacheLength settings bigger than one, like 10. Defaults to true.
|
||||
*/
|
||||
public $matchSubset;
|
||||
/**
|
||||
* @var boolean whether or not the comparison is case sensitive. Important
|
||||
* only if you use caching. Defaults to false.
|
||||
*/
|
||||
public $matchCase;
|
||||
/**
|
||||
* @var boolean whether or not the comparison looks inside
|
||||
* (i.e. does "ba" match "foo bar") the search results. Important only if
|
||||
* you use caching. Don't mix with autofill. Defaults to false.
|
||||
*/
|
||||
public $matchContains;
|
||||
/**
|
||||
* @var boolean if set to true, the autocompleter will only allow results that
|
||||
* are presented by the backend. Note that illegal values result in an empty
|
||||
* input box. Defaults to false.
|
||||
*/
|
||||
public $mustMatch;
|
||||
/**
|
||||
* @var boolean if this is set to true, the first autocomplete value will
|
||||
* be automatically selected on tab/return, even if it has not been handpicked
|
||||
* by keyboard or mouse action. If there is a handpicked (highlighted) result,
|
||||
* that result will take precedence. Defaults to true.
|
||||
*/
|
||||
public $selectFirst;
|
||||
/**
|
||||
* @var array extra parameters for the backend. If you were to specify
|
||||
* array('bar'=>4), the autocompleter would call the backend with a GET
|
||||
* parameter 'bar' 4. The param can be a function that is called to calculate
|
||||
* the param before each request.
|
||||
*/
|
||||
public $extraParams;
|
||||
/**
|
||||
* @var string a javascript function that provides advanced markup for an item.
|
||||
* For each row of results, this function will be called. The returned value will
|
||||
* be displayed inside an LI element in the results list. Autocompleter will
|
||||
* provide 4 parameters: the results row, the position of the row in the list of
|
||||
* results (starting at 1), the number of items in the list of results and the search term.
|
||||
* The default behavior assumes that a single row contains a single value.
|
||||
*/
|
||||
public $formatItem;
|
||||
/**
|
||||
* @var string a javascript function that can be used to limit the data that autocomplete
|
||||
* searches for matches. For example, there may be items you want displayed to the user,
|
||||
* but don't want included in the data that's searched. The function is called with the same arguments
|
||||
* as {@link formatItem}. Defaults to formatItem.
|
||||
*/
|
||||
public $formatMatch;
|
||||
/**
|
||||
* @var string a javascript function that provides the formatting for the value to be
|
||||
* put into the input field. Again three arguments: Data, position (starting with one) and
|
||||
* total number of data. The default behavior assumes either plain data to use as result
|
||||
* or uses the same value as provided by formatItem.
|
||||
*/
|
||||
public $formatResult;
|
||||
/**
|
||||
* @var boolean whether to allow more than one autocompleted-value to enter. Defaults to false.
|
||||
*/
|
||||
public $multiple;
|
||||
/**
|
||||
* @var string seperator to put between values when using multiple option. Defaults to ", ".
|
||||
*/
|
||||
public $multipleSeparator;
|
||||
/**
|
||||
* @var integer specify a custom width for the select box. Defaults to the width of the input element.
|
||||
*/
|
||||
public $width;
|
||||
/**
|
||||
* @var boolean fill the textinput while still selecting a value, replacing the value
|
||||
* if more is typed or something else is selected. Defaults to false.
|
||||
*/
|
||||
public $autoFill;
|
||||
/**
|
||||
* @var integer limit the number of items in the select box. Is also sent as
|
||||
* a "limit" parameter with a remote request. Defaults to 10.
|
||||
*/
|
||||
public $max;
|
||||
/**
|
||||
* @var boolean|string Whether and how to highlight matches in the select box.
|
||||
* Set to false to disable. Set to a javascript function to customize.
|
||||
* The function gets the value as the first argument and the search term as the
|
||||
* second and must return the formatted value. Defaults to Wraps the search term in a <strong> element.
|
||||
*/
|
||||
public $highlight;
|
||||
/**
|
||||
* @var boolean whether to scroll when more results than configured via scrollHeight are available. Defaults to true.
|
||||
*/
|
||||
public $scroll;
|
||||
/**
|
||||
* @var integer height of scrolled autocomplete control in pixels. Defaults to 180.
|
||||
*/
|
||||
public $scrollHeight;
|
||||
/**
|
||||
* @var string the CSS class for the input element. Defaults to "ac_input".
|
||||
*/
|
||||
public $inputClass;
|
||||
/**
|
||||
* @var string the CSS class for the dropdown list. Defaults to "ac_results".
|
||||
*/
|
||||
public $resultsClass;
|
||||
/**
|
||||
* @var string the CSS class used when the data is being loaded from backend. Defaults to "ac_loading".
|
||||
*/
|
||||
public $loadingClass;
|
||||
/**
|
||||
* @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 wrap the string with {@link CJavaScriptExpression} otherwise it will
|
||||
* be enclosed by quotes.
|
||||
*/
|
||||
public $options=array();
|
||||
/**
|
||||
* @var string the chain of method calls that would be appended at the end of the autocomplete constructor.
|
||||
* For example, ".result(function(...){})" would cause the specified js function to execute
|
||||
* when the user selects an option.
|
||||
*/
|
||||
public $methodChain;
|
||||
|
||||
/**
|
||||
* Initializes the widget.
|
||||
* This method registers all needed client scripts and renders
|
||||
* the autocomplete input.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
list($name,$id)=$this->resolveNameID();
|
||||
if(isset($this->htmlOptions['id']))
|
||||
$id=$this->htmlOptions['id'];
|
||||
else
|
||||
$this->htmlOptions['id']=$id;
|
||||
if(isset($this->htmlOptions['name']))
|
||||
$name=$this->htmlOptions['name'];
|
||||
|
||||
$this->registerClientScript();
|
||||
|
||||
if($this->hasModel())
|
||||
{
|
||||
$field=$this->textArea ? 'activeTextArea' : 'activeTextField';
|
||||
echo CHtml::$field($this->model,$this->attribute,$this->htmlOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
$field=$this->textArea ? 'textArea' : 'textField';
|
||||
echo CHtml::$field($name,$this->value,$this->htmlOptions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the needed CSS and JavaScript.
|
||||
*/
|
||||
public function registerClientScript()
|
||||
{
|
||||
$id=$this->htmlOptions['id'];
|
||||
|
||||
$acOptions=$this->getClientOptions();
|
||||
$options=$acOptions===array()?'{}' : CJavaScript::encode($acOptions);
|
||||
|
||||
$cs=Yii::app()->getClientScript();
|
||||
$cs->registerCoreScript('autocomplete');
|
||||
if($this->data!==null)
|
||||
$data=CJavaScript::encode($this->data);
|
||||
else
|
||||
{
|
||||
$url=CHtml::normalizeUrl($this->url);
|
||||
$data='"'.$url.'"';
|
||||
}
|
||||
$cs->registerScript('Yii.CAutoComplete#'.$id,"jQuery(\"#{$id}\").legacyautocomplete($data,{$options}){$this->methodChain};");
|
||||
|
||||
if($this->cssFile!==false)
|
||||
self::registerCssFile($this->cssFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the needed CSS file.
|
||||
* @param string $url the CSS URL. If null, a default CSS URL will be used.
|
||||
*/
|
||||
public static function registerCssFile($url=null)
|
||||
{
|
||||
$cs=Yii::app()->getClientScript();
|
||||
if($url===null)
|
||||
$url=$cs->getCoreScriptUrl().'/autocomplete/jquery.autocomplete.css';
|
||||
$cs->registerCssFile($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array the javascript options
|
||||
*/
|
||||
protected function getClientOptions()
|
||||
{
|
||||
static $properties=array(
|
||||
'minChars', 'delay', 'cacheLength', 'matchSubset',
|
||||
'matchCase', 'matchContains', 'mustMatch', 'selectFirst',
|
||||
'extraParams', 'multiple', 'multipleSeparator', 'width',
|
||||
'autoFill', 'max', 'scroll', 'scrollHeight', 'inputClass',
|
||||
'resultsClass', 'loadingClass');
|
||||
static $functions=array('formatItem', 'formatMatch', 'formatResult', 'highlight');
|
||||
|
||||
$options=$this->options;
|
||||
foreach($properties as $property)
|
||||
{
|
||||
if($this->$property!==null)
|
||||
$options[$property]=$this->$property;
|
||||
}
|
||||
foreach($functions as $func)
|
||||
{
|
||||
if($this->$func!==null)
|
||||
{
|
||||
if($this->$func instanceof CJavaScriptExpression)
|
||||
$options[$func]=$this->$func;
|
||||
else
|
||||
$options[$func]=new CJavaScriptExpression($this->$func);
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
52
framework/web/widgets/CClipWidget.php
Normal file
52
framework/web/widgets/CClipWidget.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
/**
|
||||
* CClipWidget class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CClipWidget records its content and makes it available elsewhere.
|
||||
*
|
||||
* Content rendered between its {@link init()} and {@link run()} calls are saved
|
||||
* as a clip in the controller. The clip is named after the widget ID.
|
||||
*
|
||||
* See {@link CBaseController::beginClip} and {@link CBaseController::endClip}
|
||||
* for a shortcut usage of CClipWidget.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets
|
||||
* @since 1.0
|
||||
*/
|
||||
class CClipWidget extends CWidget
|
||||
{
|
||||
/**
|
||||
* @var boolean whether to render the clip content in place. Defaults to false,
|
||||
* meaning the captured clip will not be displayed.
|
||||
*/
|
||||
public $renderClip=false;
|
||||
|
||||
/**
|
||||
* Starts recording a clip.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
ob_start();
|
||||
ob_implicit_flush(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends recording a clip.
|
||||
* This method stops output buffering and saves the rendering result as a named clip in the controller.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$clip=ob_get_clean();
|
||||
if($this->renderClip)
|
||||
echo $clip;
|
||||
$this->getController()->getClips()->add($this->getId(),$clip);
|
||||
}
|
||||
}
|
||||
81
framework/web/widgets/CContentDecorator.php
Normal file
81
framework/web/widgets/CContentDecorator.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/**
|
||||
* CContentDecorator class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CContentDecorator decorates the content it encloses with the specified view.
|
||||
*
|
||||
* CContentDecorator is mostly used to implement nested layouts, i.e., a layout
|
||||
* is embedded within another layout. {@link CBaseController} defines a pair of
|
||||
* convenient methods to use CContentDecorator:
|
||||
* <pre>
|
||||
* $this->beginContent('path/to/view');
|
||||
* // ... content to be decorated
|
||||
* $this->endContent();
|
||||
* </pre>
|
||||
*
|
||||
* The property {@link view} specifies the name of the view that is used to
|
||||
* decorate the content. In the view, the content being decorated may be
|
||||
* accessed with variable <code>$content</code>.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets
|
||||
* @since 1.0
|
||||
*/
|
||||
class CContentDecorator extends COutputProcessor
|
||||
{
|
||||
/**
|
||||
* @var mixed the name of the view that will be used to decorate the captured content.
|
||||
* If this property is null (default value), the default layout will be used as
|
||||
* the decorative view. Note that if the current controller does not belong to
|
||||
* any module, the default layout refers to the application's {@link CWebApplication::layout default layout};
|
||||
* If the controller belongs to a module, the default layout refers to the module's
|
||||
* {@link CWebModule::layout default layout}.
|
||||
*/
|
||||
public $view;
|
||||
/**
|
||||
* @var array the variables (name=>value) to be extracted and made available in the decorative view.
|
||||
*/
|
||||
public $data=array();
|
||||
|
||||
/**
|
||||
* Processes the captured output.
|
||||
* This method decorates the output with the specified {@link view}.
|
||||
* @param string $output the captured output to be processed
|
||||
*/
|
||||
public function processOutput($output)
|
||||
{
|
||||
$output=$this->decorate($output);
|
||||
parent::processOutput($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorates the content by rendering a view and embedding the content in it.
|
||||
* The content being embedded can be accessed in the view using variable <code>$content</code>
|
||||
* The decorated content will be displayed directly.
|
||||
* @param string $content the content to be decorated
|
||||
* @return string the decorated content
|
||||
*/
|
||||
protected function decorate($content)
|
||||
{
|
||||
$owner=$this->getOwner();
|
||||
if($this->view===null)
|
||||
$viewFile=Yii::app()->getController()->getLayoutFile(null);
|
||||
else
|
||||
$viewFile=$owner->getViewFile($this->view);
|
||||
if($viewFile!==false)
|
||||
{
|
||||
$data=$this->data;
|
||||
$data['content']=$content;
|
||||
return $owner->renderFile($viewFile,$data,true);
|
||||
}
|
||||
else
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
74
framework/web/widgets/CFilterWidget.php
Normal file
74
framework/web/widgets/CFilterWidget.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/**
|
||||
* CFilterWidget class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CFilterWidget is the base class for widgets that can also be used as filters.
|
||||
*
|
||||
* Derived classes may need to override the following methods:
|
||||
* <ul>
|
||||
* <li>{@link CWidget::init()} : called when this is object is used as a widget and needs initialization.</li>
|
||||
* <li>{@link CWidget::run()} : called when this is object is used as a widget.</li>
|
||||
* <li>{@link filter()} : the filtering method called when this object is used as an action filter.</li>
|
||||
* </ul>
|
||||
*
|
||||
* CFilterWidget provides all properties and methods of {@link CWidget} and {@link CFilter}.
|
||||
*
|
||||
* @property boolean $isFilter Whether this widget is used as a filter.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets
|
||||
* @since 1.0
|
||||
*/
|
||||
class CFilterWidget extends CWidget implements IFilter
|
||||
{
|
||||
/**
|
||||
* @var boolean whether to stop the action execution when this widget is used as a filter.
|
||||
* This property should be changed only in {@link CWidget::init} method.
|
||||
* Defaults to false, meaning the action should be executed.
|
||||
*/
|
||||
public $stopAction=false;
|
||||
|
||||
private $_isFilter;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param CBaseController $owner owner/creator of this widget. It could be either a widget or a controller.
|
||||
*/
|
||||
public function __construct($owner=null)
|
||||
{
|
||||
parent::__construct($owner);
|
||||
$this->_isFilter=($owner===null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean whether this widget is used as a filter.
|
||||
*/
|
||||
public function getIsFilter()
|
||||
{
|
||||
return $this->_isFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the filtering.
|
||||
* The default implementation simply calls {@link init()},
|
||||
* {@link CFilterChain::run()} and {@link run()} in order
|
||||
* Derived classes may want to override this method to change this behavior.
|
||||
* @param CFilterChain $filterChain the filter chain that the filter is on.
|
||||
*/
|
||||
public function filter($filterChain)
|
||||
{
|
||||
$this->init();
|
||||
if(!$this->stopAction)
|
||||
{
|
||||
$filterChain->run();
|
||||
$this->run();
|
||||
}
|
||||
}
|
||||
}
|
||||
121
framework/web/widgets/CFlexWidget.php
Normal file
121
framework/web/widgets/CFlexWidget.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
/**
|
||||
* CFlexWidget class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CFlexWidget embeds a Flex 3.x application into a page.
|
||||
*
|
||||
* To use CFlexWidget, set {@link name} to be the Flex application name
|
||||
* (without the .swf suffix), and set {@link baseUrl} to be URL (without the ending slash)
|
||||
* of the directory containing the SWF file of the Flex application.
|
||||
*
|
||||
* @property string $flashVarsAsString The flash parameter string.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets
|
||||
* @since 1.0
|
||||
*/
|
||||
class CFlexWidget extends CWidget
|
||||
{
|
||||
/**
|
||||
* @var string name of the Flex application.
|
||||
* This should be the SWF file name without the ".swf" suffix.
|
||||
*/
|
||||
public $name;
|
||||
/**
|
||||
* @var string the base URL of the Flex application.
|
||||
* This refers to the URL of the directory containing the SWF file.
|
||||
*/
|
||||
public $baseUrl;
|
||||
/**
|
||||
* @var string width of the application region. Defaults to 450.
|
||||
*/
|
||||
public $width='100%';
|
||||
/**
|
||||
* @var string height of the application region. Defaults to 300.
|
||||
*/
|
||||
public $height='100%';
|
||||
/**
|
||||
* @var string quality of the animation. Defaults to 'high'.
|
||||
*/
|
||||
public $quality='high';
|
||||
/**
|
||||
* @var string background color of the application region. Defaults to '#FFFFFF', meaning white.
|
||||
*/
|
||||
public $bgColor='#FFFFFF';
|
||||
/**
|
||||
* @var string align of the application region. Defaults to 'middle'.
|
||||
*/
|
||||
public $align='middle';
|
||||
/**
|
||||
* @var string the access method of the script. Defaults to 'sameDomain'.
|
||||
*/
|
||||
public $allowScriptAccess='sameDomain';
|
||||
/**
|
||||
* @var boolean whether to allow running the Flash in full screen mode. Defaults to false.
|
||||
* @since 1.1.1
|
||||
*/
|
||||
public $allowFullScreen=false;
|
||||
/**
|
||||
* @var string the HTML content to be displayed if Flash player is not installed.
|
||||
*/
|
||||
public $altHtmlContent;
|
||||
/**
|
||||
* @var boolean whether history should be enabled. Defaults to true.
|
||||
*/
|
||||
public $enableHistory=true;
|
||||
/**
|
||||
* @var array parameters to be passed to the Flex application.
|
||||
*/
|
||||
public $flashVars=array();
|
||||
|
||||
/**
|
||||
* Renders the widget.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
if(empty($this->name))
|
||||
throw new CException(Yii::t('yii','CFlexWidget.name cannot be empty.'));
|
||||
if(empty($this->baseUrl))
|
||||
throw new CException(Yii::t('yii','CFlexWidget.baseUrl cannot be empty.'));
|
||||
if($this->altHtmlContent===null)
|
||||
$this->altHtmlContent=Yii::t('yii','This content requires the <a href="http://www.adobe.com/go/getflash/">Adobe Flash Player</a>.');
|
||||
|
||||
$this->registerClientScript();
|
||||
|
||||
$this->render('flexWidget');
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the needed CSS and JavaScript.
|
||||
*/
|
||||
public function registerClientScript()
|
||||
{
|
||||
$cs=Yii::app()->getClientScript();
|
||||
$cs->registerScriptFile($this->baseUrl.'/AC_OETags.js');
|
||||
|
||||
if($this->enableHistory)
|
||||
{
|
||||
$cs->registerCssFile($this->baseUrl.'/history/history.css');
|
||||
$cs->registerScriptFile($this->baseUrl.'/history/history.js');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the properly quoted flash parameter string.
|
||||
* @return string the flash parameter string.
|
||||
*/
|
||||
public function getFlashVarsAsString()
|
||||
{
|
||||
$params=array();
|
||||
foreach($this->flashVars as $k=>$v)
|
||||
$params[]=urlencode($k).'='.urlencode($v);
|
||||
return CJavaScript::quote(implode('&',$params));
|
||||
}
|
||||
}
|
||||
130
framework/web/widgets/CHtmlPurifier.php
Normal file
130
framework/web/widgets/CHtmlPurifier.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
/**
|
||||
* CHtmlPurifier class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
if(!class_exists('HTMLPurifier_Bootstrap',false))
|
||||
{
|
||||
require_once(Yii::getPathOfAlias('system.vendors.htmlpurifier').DIRECTORY_SEPARATOR.'HTMLPurifier.standalone.php');
|
||||
HTMLPurifier_Bootstrap::registerAutoload();
|
||||
}
|
||||
|
||||
/**
|
||||
* CHtmlPurifier is wrapper of {@link http://htmlpurifier.org HTML Purifier}.
|
||||
*
|
||||
* CHtmlPurifier removes all malicious code (better known as XSS) with a thoroughly audited,
|
||||
* secure yet permissive whitelist. It will also make sure the resulting code
|
||||
* is standard-compliant.
|
||||
*
|
||||
* CHtmlPurifier can be used as either a widget or a controller filter.
|
||||
*
|
||||
* Note: since HTML Purifier is a big package, its performance is not very good.
|
||||
* You should consider either caching the purification result or purifying the user input
|
||||
* before saving to database.
|
||||
*
|
||||
* Usage as a class:
|
||||
* <pre>
|
||||
* $p = new CHtmlPurifier();
|
||||
* $p->options = array('URI.AllowedSchemes'=>array(
|
||||
* 'http' => true,
|
||||
* 'https' => true,
|
||||
* ));
|
||||
* $text = $p->purify($text);
|
||||
* </pre>
|
||||
*
|
||||
* Usage as validation rule:
|
||||
* <pre>
|
||||
* array('text','filter','filter'=>array($obj=new CHtmlPurifier(),'purify')),
|
||||
* </pre>
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets
|
||||
* @since 1.0
|
||||
*/
|
||||
class CHtmlPurifier extends COutputProcessor
|
||||
{
|
||||
/**
|
||||
* @var object the HTML Purifier instance.
|
||||
*/
|
||||
private $_purifier;
|
||||
/**
|
||||
* @var mixed the options to be passed to HTML Purifier instance.
|
||||
* This can be a HTMLPurifier_Config object, an array of directives (Namespace.Directive => Value)
|
||||
* or the filename of an ini file.
|
||||
* @see http://htmlpurifier.org/live/configdoc/plain.html
|
||||
*/
|
||||
private $_options=null;
|
||||
|
||||
/**
|
||||
* Processes the captured output.
|
||||
* This method purifies the output using {@link http://htmlpurifier.org HTML Purifier}.
|
||||
* @param string $output the captured output to be processed
|
||||
*/
|
||||
public function processOutput($output)
|
||||
{
|
||||
$output=$this->purify($output);
|
||||
parent::processOutput($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Purifies the HTML content by removing malicious code.
|
||||
* @param mixed $content the content to be purified.
|
||||
* @return mixed the purified content
|
||||
*/
|
||||
public function purify($content)
|
||||
{
|
||||
if(is_array($content))
|
||||
$content=array_map(array($this,'purify'),$content);
|
||||
else
|
||||
$content=$this->getPurifier()->purify($content);
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the options for HTML Purifier and create a new HTML Purifier instance based on these options.
|
||||
* @param mixed $options the options for HTML Purifier
|
||||
* @return CHtmlPurifier
|
||||
*/
|
||||
public function setOptions($options)
|
||||
{
|
||||
$this->_options=$options;
|
||||
$this->createNewHtmlPurifierInstance();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the options for the HTML Purifier instance.
|
||||
* @return mixed the HTML Purifier instance options
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return $this->_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTML Purifier instance or create a new one if it doesn't exist.
|
||||
* @return HTMLPurifier
|
||||
*/
|
||||
protected function getPurifier()
|
||||
{
|
||||
if($this->_purifier!==null)
|
||||
return $this->_purifier;
|
||||
return $this->createNewHtmlPurifierInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new HTML Purifier instance.
|
||||
* @return HTMLPurifier
|
||||
*/
|
||||
protected function createNewHtmlPurifierInstance()
|
||||
{
|
||||
$this->_purifier=new HTMLPurifier($this->getOptions());
|
||||
$this->_purifier->config->set('Cache.SerializerPath',Yii::app()->getRuntimePath());
|
||||
return $this->_purifier;
|
||||
}
|
||||
}
|
||||
81
framework/web/widgets/CInputWidget.php
Normal file
81
framework/web/widgets/CInputWidget.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/**
|
||||
* CInputWidget class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CInputWidget is the base class for widgets that collect user inputs.
|
||||
*
|
||||
* CInputWidget declares properties common among input widgets. An input widget
|
||||
* can be associated with a data model and an attribute, or a name and a value.
|
||||
* If the former, the name and the value will be generated automatically.
|
||||
* Child classes may use {@link resolveNameID} and {@link hasModel}.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets
|
||||
* @since 1.0
|
||||
*/
|
||||
abstract class CInputWidget extends CWidget
|
||||
{
|
||||
/**
|
||||
* @var CModel the data model associated with this widget.
|
||||
*/
|
||||
public $model;
|
||||
/**
|
||||
* @var string the attribute associated with this widget.
|
||||
* The name can contain square brackets (e.g. 'name[1]') which is used to collect tabular data input.
|
||||
*/
|
||||
public $attribute;
|
||||
/**
|
||||
* @var string the input name. This must be set if {@link model} is not set.
|
||||
*/
|
||||
public $name;
|
||||
/**
|
||||
* @var string the input value
|
||||
*/
|
||||
public $value;
|
||||
/**
|
||||
* @var array additional HTML options to be rendered in the input tag
|
||||
*/
|
||||
public $htmlOptions=array();
|
||||
|
||||
|
||||
/**
|
||||
* @return array the name and the ID of the input.
|
||||
* @throws CException in case input name and ID cannot be resolved.
|
||||
*/
|
||||
protected function resolveNameID()
|
||||
{
|
||||
if($this->name!==null)
|
||||
$name=$this->name;
|
||||
elseif(isset($this->htmlOptions['name']))
|
||||
$name=$this->htmlOptions['name'];
|
||||
elseif($this->hasModel())
|
||||
$name=CHtml::activeName($this->model,$this->attribute);
|
||||
else
|
||||
throw new CException(Yii::t('yii','{class} must specify "model" and "attribute" or "name" property values.',array('{class}'=>get_class($this))));
|
||||
|
||||
if(($id=$this->getId(false))===null)
|
||||
{
|
||||
if(isset($this->htmlOptions['id']))
|
||||
$id=$this->htmlOptions['id'];
|
||||
else
|
||||
$id=CHtml::getIdByName($name);
|
||||
}
|
||||
|
||||
return array($name,$id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean whether this widget is associated with a data model.
|
||||
*/
|
||||
protected function hasModel()
|
||||
{
|
||||
return $this->model instanceof CModel && $this->attribute!==null;
|
||||
}
|
||||
}
|
||||
117
framework/web/widgets/CMarkdown.php
Normal file
117
framework/web/widgets/CMarkdown.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
/**
|
||||
* CMarkdown class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CMarkdown converts the captured content from markdown syntax to HTML code.
|
||||
*
|
||||
* CMarkdown can be used as either a widget or a filter. It is a wrapper of {@link CMarkdownParser}.
|
||||
* CMarkdown adds an additional option {@link purifyOutput} which can be set true
|
||||
* so that the converted HTML code is purified before being displayed.
|
||||
*
|
||||
* For details about the markdown syntax, please check the following:
|
||||
* <ul>
|
||||
* <li>{@link http://daringfireball.net/projects/markdown/syntax official markdown syntax}</li>
|
||||
* <li>{@link http://michelf.com/projects/php-markdown/extra/ markdown extra syntax}</li>
|
||||
* <li>{@link CMarkdownParser markdown with syntax highlighting}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @property CMarkdownParser $markdownParser The parser instance.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets
|
||||
* @since 1.0
|
||||
*/
|
||||
class CMarkdown extends COutputProcessor
|
||||
{
|
||||
/**
|
||||
* @var mixed the CSS file used for the widget. Defaults to null, meaning
|
||||
* using the default CSS file included together with the widget.
|
||||
* If false, no CSS file will be used. Otherwise, the specified CSS file
|
||||
* will be included when using this widget.
|
||||
*/
|
||||
public $cssFile;
|
||||
/**
|
||||
* @var boolean whether to use {@link CHtmlPurifier} to purify the generated HTML code. Defaults to false.
|
||||
*/
|
||||
public $purifyOutput=false;
|
||||
|
||||
private $_parser;
|
||||
|
||||
/**
|
||||
* Processes the captured output.
|
||||
* This method converts the content in markdown syntax to HTML code.
|
||||
* If {@link purifyOutput} is true, the HTML code will also be purified.
|
||||
* @param string $output the captured output to be processed
|
||||
* @see convert
|
||||
*/
|
||||
public function processOutput($output)
|
||||
{
|
||||
$output=$this->transform($output);
|
||||
if($this->purifyOutput)
|
||||
{
|
||||
$purifier=new CHtmlPurifier;
|
||||
$output=$purifier->purify($output);
|
||||
}
|
||||
parent::processOutput($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the content in markdown syntax to HTML code.
|
||||
* This method uses {@link CMarkdownParser} to do the conversion.
|
||||
* @param string $output the content to be converted
|
||||
* @return string the converted content
|
||||
*/
|
||||
public function transform($output)
|
||||
{
|
||||
$this->registerClientScript();
|
||||
return $this->getMarkdownParser()->transform($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the needed CSS and JavaScript.
|
||||
*/
|
||||
public function registerClientScript()
|
||||
{
|
||||
if($this->cssFile!==false)
|
||||
self::registerCssFile($this->cssFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the needed CSS file.
|
||||
* @param string $url the CSS URL. If null, a default CSS URL will be used.
|
||||
*/
|
||||
public static function registerCssFile($url=null)
|
||||
{
|
||||
CTextHighlighter::registerCssFile($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the markdown parser instance.
|
||||
* This method calls {@link createMarkdownParser} to create the parser instance.
|
||||
* Call this method multipe times will only return the same instance.
|
||||
* @return CMarkdownParser the parser instance
|
||||
*/
|
||||
public function getMarkdownParser()
|
||||
{
|
||||
if($this->_parser===null)
|
||||
$this->_parser=$this->createMarkdownParser();
|
||||
return $this->_parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a markdown parser.
|
||||
* By default, this method creates a {@link CMarkdownParser} instance.
|
||||
* @return CMarkdownParser the markdown parser.
|
||||
*/
|
||||
protected function createMarkdownParser()
|
||||
{
|
||||
return new CMarkdownParser;
|
||||
}
|
||||
}
|
||||
114
framework/web/widgets/CMaskedTextField.php
Normal file
114
framework/web/widgets/CMaskedTextField.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/**
|
||||
* CMaskedTextField class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CMaskedTextField generates a masked text field.
|
||||
*
|
||||
* CMaskedTextField is similar to {@link CHtml::textField} except that
|
||||
* an input mask will be used to help users enter properly formatted data.
|
||||
* The masked text field is implemented based on the jQuery masked input plugin
|
||||
* (see {@link http://digitalbush.com/projects/masked-input-plugin}).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets
|
||||
* @since 1.0
|
||||
*/
|
||||
class CMaskedTextField extends CInputWidget
|
||||
{
|
||||
/**
|
||||
* @var string the input mask (e.g. '99/99/9999' for date input). The following characters are predefined:
|
||||
* <ul>
|
||||
* <li>a: represents an alpha character (A-Z,a-z).</li>
|
||||
* <li>9: represents a numeric character (0-9).</li>
|
||||
* <li>*: represents an alphanumeric character (A-Z,a-z,0-9).</li>
|
||||
* <li>?: anything listed after '?' within the mask is considered optional user input.</li>
|
||||
* </ul>
|
||||
* Additional characters can be defined by specifying the {@link charMap} property.
|
||||
*/
|
||||
public $mask;
|
||||
/**
|
||||
* @var array the mapping between mask characters and the corresponding patterns.
|
||||
* For example, array('~'=>'[+-]') specifies that the '~' character expects '+' or '-' input.
|
||||
* Defaults to null, meaning using the map as described in {@link mask}.
|
||||
*/
|
||||
public $charMap;
|
||||
/**
|
||||
* @var string the character prompting for user input. Defaults to underscore '_'.
|
||||
*/
|
||||
public $placeholder;
|
||||
/**
|
||||
* @var string a JavaScript function callback that will be invoked when user finishes the input.
|
||||
*/
|
||||
public $completed;
|
||||
|
||||
/**
|
||||
* Executes the widget.
|
||||
* This method registers all needed client scripts and renders
|
||||
* the text field.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
if($this->mask=='')
|
||||
throw new CException(Yii::t('yii','Property CMaskedTextField.mask cannot be empty.'));
|
||||
|
||||
list($name,$id)=$this->resolveNameID();
|
||||
if(isset($this->htmlOptions['id']))
|
||||
$id=$this->htmlOptions['id'];
|
||||
else
|
||||
$this->htmlOptions['id']=$id;
|
||||
if(isset($this->htmlOptions['name']))
|
||||
$name=$this->htmlOptions['name'];
|
||||
|
||||
$this->registerClientScript();
|
||||
|
||||
if($this->hasModel())
|
||||
echo CHtml::activeTextField($this->model,$this->attribute,$this->htmlOptions);
|
||||
else
|
||||
echo CHtml::textField($name,$this->value,$this->htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the needed CSS and JavaScript.
|
||||
*/
|
||||
public function registerClientScript()
|
||||
{
|
||||
$id=$this->htmlOptions['id'];
|
||||
$miOptions=$this->getClientOptions();
|
||||
$options=$miOptions!==array() ? ','.CJavaScript::encode($miOptions) : '';
|
||||
$js='';
|
||||
if(is_array($this->charMap))
|
||||
$js.='jQuery.mask.definitions='.CJavaScript::encode($this->charMap).";\n";
|
||||
$js.="jQuery(\"#{$id}\").mask(\"{$this->mask}\"{$options});";
|
||||
|
||||
$cs=Yii::app()->getClientScript();
|
||||
$cs->registerCoreScript('maskedinput');
|
||||
$cs->registerScript('Yii.CMaskedTextField#'.$id,$js);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array the options for the text field
|
||||
*/
|
||||
protected function getClientOptions()
|
||||
{
|
||||
$options=array();
|
||||
if($this->placeholder!==null)
|
||||
$options['placeholder']=$this->placeholder;
|
||||
|
||||
if($this->completed!==null)
|
||||
{
|
||||
if($this->completed instanceof CJavaScriptExpression)
|
||||
$options['completed']=$this->completed;
|
||||
else
|
||||
$options['completed']=new CJavaScriptExpression($this->completed);
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
141
framework/web/widgets/CMultiFileUpload.php
Normal file
141
framework/web/widgets/CMultiFileUpload.php
Normal file
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
/**
|
||||
* CMultiFileUpload class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CMultiFileUpload generates a file input that can allow uploading multiple files at a time.
|
||||
*
|
||||
* This is based on the {@link http://www.fyneworks.com/jquery/multiple-file-upload/ jQuery Multi File Upload plugin}.
|
||||
* The uploaded file information can be accessed via $_FILES[widget-name], which gives an array of the uploaded
|
||||
* files. Note, you have to set the enclosing form's 'enctype' attribute to be 'multipart/form-data'.
|
||||
*
|
||||
* Example:
|
||||
* <pre>
|
||||
* <?php
|
||||
* $this->widget('CMultiFileUpload', array(
|
||||
* 'model'=>$model,
|
||||
* 'attribute'=>'files',
|
||||
* 'accept'=>'jpg|gif',
|
||||
* 'options'=>array(
|
||||
* 'onFileSelect'=>'function(e, v, m){ alert("onFileSelect - "+v) }',
|
||||
* 'afterFileSelect'=>'function(e, v, m){ alert("afterFileSelect - "+v) }',
|
||||
* 'onFileAppend'=>'function(e, v, m){ alert("onFileAppend - "+v) }',
|
||||
* 'afterFileAppend'=>'function(e, v, m){ alert("afterFileAppend - "+v) }',
|
||||
* 'onFileRemove'=>'function(e, v, m){ alert("onFileRemove - "+v) }',
|
||||
* 'afterFileRemove'=>'function(e, v, m){ alert("afterFileRemove - "+v) }',
|
||||
* ),
|
||||
* ));
|
||||
* ?>
|
||||
* </pre>
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets
|
||||
* @since 1.0
|
||||
*/
|
||||
class CMultiFileUpload extends CInputWidget
|
||||
{
|
||||
/**
|
||||
* @var string the file types that are allowed (eg "gif|jpg").
|
||||
* Note, the server side still needs to check if the uploaded files have allowed types.
|
||||
*/
|
||||
public $accept;
|
||||
/**
|
||||
* @var integer the maximum number of files that can be uploaded. If -1, it means no limits. Defaults to -1.
|
||||
*/
|
||||
public $max=-1;
|
||||
/**
|
||||
* @var string the label for the remove button. Defaults to "Remove".
|
||||
*/
|
||||
public $remove;
|
||||
/**
|
||||
* @var string message that is displayed when a file type is not allowed.
|
||||
*/
|
||||
public $denied;
|
||||
/**
|
||||
* @var string message that is displayed when a file is selected.
|
||||
*/
|
||||
public $selected;
|
||||
/**
|
||||
* @var string message that is displayed when a file appears twice.
|
||||
*/
|
||||
public $duplicate;
|
||||
/**
|
||||
* @var string the message template for displaying the uploaded file name
|
||||
* @since 1.1.3
|
||||
*/
|
||||
public $file;
|
||||
/**
|
||||
* @var array additional options that can be passed to the constructor of the multifile js object.
|
||||
* @since 1.1.7
|
||||
*/
|
||||
public $options=array();
|
||||
|
||||
|
||||
/**
|
||||
* Runs the widget.
|
||||
* This method registers all needed client scripts and renders
|
||||
* the multiple file uploader.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
list($name,$id)=$this->resolveNameID();
|
||||
if(substr($name,-2)!=='[]')
|
||||
$name.='[]';
|
||||
if(isset($this->htmlOptions['id']))
|
||||
$id=$this->htmlOptions['id'];
|
||||
else
|
||||
$this->htmlOptions['id']=$id;
|
||||
$this->registerClientScript();
|
||||
echo CHtml::fileField($name,'',$this->htmlOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the needed CSS and JavaScript.
|
||||
*/
|
||||
public function registerClientScript()
|
||||
{
|
||||
$id=$this->htmlOptions['id'];
|
||||
|
||||
$options=$this->getClientOptions();
|
||||
$options=$options===array()? '' : CJavaScript::encode($options);
|
||||
|
||||
$cs=Yii::app()->getClientScript();
|
||||
$cs->registerCoreScript('multifile');
|
||||
$cs->registerScript('Yii.CMultiFileUpload#'.$id,"jQuery(\"#{$id}\").MultiFile({$options});");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array the javascript options
|
||||
*/
|
||||
protected function getClientOptions()
|
||||
{
|
||||
$options=$this->options;
|
||||
foreach(array('onFileRemove','afterFileRemove','onFileAppend','afterFileAppend','onFileSelect','afterFileSelect') as $event)
|
||||
{
|
||||
if(isset($options[$event]) && !($options[$event] instanceof CJavaScriptExpression))
|
||||
$options[$event]=new CJavaScriptExpression($options[$event]);
|
||||
}
|
||||
|
||||
if($this->accept!==null)
|
||||
$options['accept']=$this->accept;
|
||||
if($this->max>0)
|
||||
$options['max']=$this->max;
|
||||
|
||||
$messages=array();
|
||||
foreach(array('remove','denied','selected','duplicate','file') as $messageName)
|
||||
{
|
||||
if($this->$messageName!==null)
|
||||
$messages[$messageName]=$this->$messageName;
|
||||
}
|
||||
if($messages!==array())
|
||||
$options['STRING']=$messages;
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
364
framework/web/widgets/COutputCache.php
Normal file
364
framework/web/widgets/COutputCache.php
Normal file
@@ -0,0 +1,364 @@
|
||||
<?php
|
||||
/**
|
||||
* COutputCache class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* COutputCache enables caching the output generated by an action or a view fragment.
|
||||
*
|
||||
* If the output to be displayed is found valid in cache, the cached
|
||||
* version will be displayed instead, which saves the time for generating
|
||||
* the original output.
|
||||
*
|
||||
* Since COutputCache extends from {@link CFilterWidget}, it can be used
|
||||
* as either a filter (for action caching) or a widget (for fragment caching).
|
||||
* For the latter, the shortcuts {@link CBaseController::beginCache()} and {@link CBaseController::endCache()}
|
||||
* are often used instead, like the following in a view file:
|
||||
* <pre>
|
||||
* if($this->beginCache('cacheName',array('property1'=>'value1',...))
|
||||
* {
|
||||
* // ... display the content to be cached here
|
||||
* $this->endCache();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* COutputCache must work with a cache application component specified via {@link cacheID}.
|
||||
* If the cache application component is not available, COutputCache will be disabled.
|
||||
*
|
||||
* The validity of the cached content is determined based on two factors:
|
||||
* the {@link duration} and the cache {@link dependency}.
|
||||
* The former specifies the number of seconds that the data can remain
|
||||
* valid in cache (defaults to 60s), while the latter specifies conditions
|
||||
* that the cached data depends on. If a dependency changes,
|
||||
* (e.g. relevant data in DB are updated), the cached data will be invalidated.
|
||||
* For more details about cache dependency, see {@link CCacheDependency}.
|
||||
*
|
||||
* Sometimes, it is necessary to turn off output caching only for certain request types.
|
||||
* For example, we only want to cache a form when it is initially requested;
|
||||
* any subsequent display of the form should not be cached because it contains user input.
|
||||
* We can set {@link requestTypes} to be <code>array('GET')</code> to accomplish this task.
|
||||
*
|
||||
* The content fetched from cache may be variated with respect to
|
||||
* some parameters. COutputCache supports four kinds of variations:
|
||||
* <ul>
|
||||
* <li>{@link varyByRoute}: this specifies whether the cached content
|
||||
* should be varied with the requested route (controller and action)</li>
|
||||
* <li>{@link varyByParam}: this specifies a list of GET parameter names
|
||||
* and uses the corresponding values to determine the version of the cached content.</li>
|
||||
* <li>{@link varyBySession}: this specifies whether the cached content
|
||||
* should be varied with the user session.</li>
|
||||
* <li>{@link varyByExpression}: this specifies whether the cached content
|
||||
* should be varied with the result of the specified PHP expression.</li>
|
||||
* <li>{@link varyByLanguage}: this specifies whether the cached content
|
||||
* should by varied with the user's language. Available since 1.1.14.</li>
|
||||
* </ul>
|
||||
* For more advanced variation, override {@link getBaseCacheKey()} method.
|
||||
*
|
||||
* @property boolean $isContentCached Whether the content can be found from cache.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets
|
||||
* @since 1.0
|
||||
*/
|
||||
class COutputCache extends CFilterWidget
|
||||
{
|
||||
/**
|
||||
* Prefix to the keys for storing cached data
|
||||
*/
|
||||
const CACHE_KEY_PREFIX='Yii.COutputCache.';
|
||||
|
||||
/**
|
||||
* @var integer number of seconds that the data can remain in cache. Defaults to 60 seconds.
|
||||
* If it is 0, existing cached content would be removed from the cache.
|
||||
* If it is a negative value, the cache will be disabled (any existing cached content will
|
||||
* remain in the cache.)
|
||||
*
|
||||
* Note, if cache dependency changes or cache space is limited,
|
||||
* the data may be purged out of cache earlier.
|
||||
*/
|
||||
public $duration=60;
|
||||
/**
|
||||
* @var boolean whether the content being cached should be differentiated according to route.
|
||||
* A route consists of the requested controller ID and action ID.
|
||||
* Defaults to true.
|
||||
*/
|
||||
public $varyByRoute=true;
|
||||
/**
|
||||
* @var boolean whether the content being cached should be differentiated according to user sessions. Defaults to false.
|
||||
*/
|
||||
public $varyBySession=false;
|
||||
/**
|
||||
* @var array list of GET parameters that should participate in cache key calculation.
|
||||
* By setting this property, the output cache will use different cached data
|
||||
* for each different set of GET parameter values.
|
||||
*/
|
||||
public $varyByParam;
|
||||
/**
|
||||
* @var string a PHP expression whose result is used in the cache key calculation.
|
||||
* By setting this property, the output cache will use different cached data
|
||||
* for each different expression result.
|
||||
* The expression can also be a valid PHP callback,
|
||||
* including class method name (array(ClassName/Object, MethodName)),
|
||||
* or anonymous function (PHP 5.3.0+). The function/method signature should be as follows:
|
||||
* <pre>
|
||||
* function foo($cache) { ... }
|
||||
* </pre>
|
||||
* where $cache refers to the output cache component.
|
||||
*
|
||||
* The PHP expression will be evaluated using {@link evaluateExpression}.
|
||||
*
|
||||
* A PHP expression can be any PHP code that has a value. To learn more about what an expression is,
|
||||
* please refer to the {@link http://www.php.net/manual/en/language.expressions.php php manual}.
|
||||
*/
|
||||
public $varyByExpression;
|
||||
/**
|
||||
* @var boolean whether the content being cached should be differentiated according to user's language.
|
||||
* A language is retrieved via Yii::app()->language.
|
||||
* Defaults to false.
|
||||
* @since 1.1.14
|
||||
*/
|
||||
public $varyByLanguage=false;
|
||||
/**
|
||||
* @var array list of request types (e.g. GET, POST) for which the cache should be enabled only.
|
||||
* Defaults to null, meaning all request types.
|
||||
*/
|
||||
public $requestTypes;
|
||||
/**
|
||||
* @var string the ID of the cache application component. Defaults to 'cache' (the primary cache application component.)
|
||||
*/
|
||||
public $cacheID='cache';
|
||||
/**
|
||||
* @var mixed the dependency that the cached content depends on.
|
||||
* This can be either an object implementing {@link ICacheDependency} interface or an array
|
||||
* specifying the configuration of the dependency object. For example,
|
||||
* <pre>
|
||||
* array(
|
||||
* 'class'=>'CDbCacheDependency',
|
||||
* 'sql'=>'SELECT MAX(lastModified) FROM Post',
|
||||
* )
|
||||
* </pre>
|
||||
* would make the output cache depends on the last modified time of all posts.
|
||||
* If any post has its modification time changed, the cached content would be invalidated.
|
||||
*/
|
||||
public $dependency;
|
||||
|
||||
private $_key;
|
||||
private $_cache;
|
||||
private $_contentCached;
|
||||
private $_content;
|
||||
private $_actions;
|
||||
|
||||
/**
|
||||
* Performs filtering before the action is executed.
|
||||
* This method is meant to be overridden by child classes if begin-filtering is needed.
|
||||
* @param CFilterChain $filterChain list of filters being applied to an action
|
||||
* @return boolean whether the filtering process should stop after this filter. Defaults to false.
|
||||
*/
|
||||
public function filter($filterChain)
|
||||
{
|
||||
if(!$this->getIsContentCached())
|
||||
$filterChain->run();
|
||||
$this->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the start of content to be cached.
|
||||
* Content displayed after this method call and before {@link endCache()}
|
||||
* will be captured and saved in cache.
|
||||
* This method does nothing if valid content is already found in cache.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if($this->getIsContentCached())
|
||||
$this->replayActions();
|
||||
elseif($this->_cache!==null)
|
||||
{
|
||||
$this->getController()->getCachingStack()->push($this);
|
||||
ob_start();
|
||||
ob_implicit_flush(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the end of content to be cached.
|
||||
* Content displayed before this method call and after {@link init()}
|
||||
* will be captured and saved in cache.
|
||||
* This method does nothing if valid content is already found in cache.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
if($this->getIsContentCached())
|
||||
{
|
||||
if($this->getController()->isCachingStackEmpty())
|
||||
echo $this->getController()->processDynamicOutput($this->_content);
|
||||
else
|
||||
echo $this->_content;
|
||||
}
|
||||
elseif($this->_cache!==null)
|
||||
{
|
||||
$this->_content=ob_get_clean();
|
||||
$this->getController()->getCachingStack()->pop();
|
||||
$data=array($this->_content,$this->_actions);
|
||||
if(is_array($this->dependency))
|
||||
$this->dependency=Yii::createComponent($this->dependency);
|
||||
$this->_cache->set($this->getCacheKey(),$data,$this->duration,$this->dependency);
|
||||
|
||||
if($this->getController()->isCachingStackEmpty())
|
||||
echo $this->getController()->processDynamicOutput($this->_content);
|
||||
else
|
||||
echo $this->_content;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean whether the content can be found from cache
|
||||
*/
|
||||
public function getIsContentCached()
|
||||
{
|
||||
if($this->_contentCached!==null)
|
||||
return $this->_contentCached;
|
||||
else
|
||||
return $this->_contentCached=$this->checkContentCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for content in cache.
|
||||
* @return boolean whether the content is found in cache.
|
||||
*/
|
||||
protected function checkContentCache()
|
||||
{
|
||||
if((empty($this->requestTypes) || in_array(Yii::app()->getRequest()->getRequestType(),$this->requestTypes))
|
||||
&& ($this->_cache=$this->getCache())!==null)
|
||||
{
|
||||
if($this->duration>0 && ($data=$this->_cache->get($this->getCacheKey()))!==false)
|
||||
{
|
||||
$this->_content=$data[0];
|
||||
$this->_actions=$data[1];
|
||||
return true;
|
||||
}
|
||||
if($this->duration==0)
|
||||
$this->_cache->delete($this->getCacheKey());
|
||||
if($this->duration<=0)
|
||||
$this->_cache=null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ICache the cache used for caching the content.
|
||||
*/
|
||||
protected function getCache()
|
||||
{
|
||||
return Yii::app()->getComponent($this->cacheID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Caclulates the base cache key.
|
||||
* The calculated key will be further variated in {@link getCacheKey}.
|
||||
* Derived classes may override this method if more variations are needed.
|
||||
* @return string basic cache key without variations
|
||||
*/
|
||||
protected function getBaseCacheKey()
|
||||
{
|
||||
return self::CACHE_KEY_PREFIX.$this->getId().'.';
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the cache key.
|
||||
* The key is calculated based on {@link getBaseCacheKey} and other factors, including
|
||||
* {@link varyByRoute}, {@link varyByParam}, {@link varyBySession} and {@link varyByLanguage}.
|
||||
* @return string cache key
|
||||
*/
|
||||
protected function getCacheKey()
|
||||
{
|
||||
if($this->_key!==null)
|
||||
return $this->_key;
|
||||
else
|
||||
{
|
||||
$key=$this->getBaseCacheKey().'.';
|
||||
if($this->varyByRoute)
|
||||
{
|
||||
$controller=$this->getController();
|
||||
$key.=$controller->getUniqueId().'/';
|
||||
if(($action=$controller->getAction())!==null)
|
||||
$key.=$action->getId();
|
||||
}
|
||||
$key.='.';
|
||||
|
||||
if($this->varyBySession)
|
||||
$key.=Yii::app()->getSession()->getSessionID();
|
||||
$key.='.';
|
||||
|
||||
if(is_array($this->varyByParam) && isset($this->varyByParam[0]))
|
||||
{
|
||||
$params=array();
|
||||
foreach($this->varyByParam as $name)
|
||||
{
|
||||
if(isset($_GET[$name]))
|
||||
$params[$name]=$_GET[$name];
|
||||
else
|
||||
$params[$name]='';
|
||||
}
|
||||
$key.=serialize($params);
|
||||
}
|
||||
$key.='.';
|
||||
|
||||
if($this->varyByExpression!==null)
|
||||
$key.=$this->evaluateExpression($this->varyByExpression);
|
||||
$key.='.';
|
||||
|
||||
if($this->varyByLanguage)
|
||||
$key.=Yii::app()->language;
|
||||
$key.='.';
|
||||
|
||||
return $this->_key=$key;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Records a method call when this output cache is in effect.
|
||||
* When the content is served from the output cache, the recorded
|
||||
* method will be re-invoked.
|
||||
* @param string $context a property name of the controller. The property should refer to an object
|
||||
* whose method is being recorded. If empty it means the controller itself.
|
||||
* @param string $method the method name
|
||||
* @param array $params parameters passed to the method
|
||||
*/
|
||||
public function recordAction($context,$method,$params)
|
||||
{
|
||||
$this->_actions[]=array($context,$method,$params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replays the recorded method calls.
|
||||
*/
|
||||
protected function replayActions()
|
||||
{
|
||||
if(empty($this->_actions))
|
||||
return;
|
||||
$controller=$this->getController();
|
||||
$cs=Yii::app()->getClientScript();
|
||||
foreach($this->_actions as $action)
|
||||
{
|
||||
if($action[0]==='clientScript')
|
||||
$object=$cs;
|
||||
elseif($action[0]==='')
|
||||
$object=$controller;
|
||||
else
|
||||
$object=$controller->{$action[0]};
|
||||
if(method_exists($object,$action[1]))
|
||||
call_user_func_array(array($object,$action[1]),$action[2]);
|
||||
elseif($action[0]==='' && function_exists($action[1]))
|
||||
call_user_func_array($action[1],$action[2]);
|
||||
else
|
||||
throw new CException(Yii::t('yii','Unable to replay the action "{object}.{method}". The method does not exist.',
|
||||
array('object'=>$action[0],
|
||||
'method'=>$action[1])));
|
||||
}
|
||||
}
|
||||
}
|
||||
76
framework/web/widgets/COutputProcessor.php
Normal file
76
framework/web/widgets/COutputProcessor.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
* COutputProcessor class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* COutputProcessor transforms the content into a different format.
|
||||
*
|
||||
* COutputProcessor captures the output generated by an action or a view fragment
|
||||
* and passes it to its {@link onProcessOutput} event handlers for further processing.
|
||||
*
|
||||
* The event handler may process the output and store it back to the {@link COutputEvent::output}
|
||||
* property. By setting the {@link CEvent::handled handled} property of the event parameter
|
||||
* to true, the output will not be echoed anymore. Otherwise (by default), the output will be echoed.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets
|
||||
* @since 1.0
|
||||
*/
|
||||
class COutputProcessor extends CFilterWidget
|
||||
{
|
||||
/**
|
||||
* Initializes the widget.
|
||||
* This method starts the output buffering.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
ob_start();
|
||||
ob_implicit_flush(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the widget.
|
||||
* This method stops output buffering and processes the captured output.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$output=ob_get_clean();
|
||||
$this->processOutput($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the captured output.
|
||||
*
|
||||
* The default implementation raises an {@link onProcessOutput} event.
|
||||
* If the event is not handled by any event handler, the output will be echoed.
|
||||
*
|
||||
* @param string $output the captured output to be processed
|
||||
*/
|
||||
public function processOutput($output)
|
||||
{
|
||||
if($this->hasEventHandler('onProcessOutput'))
|
||||
{
|
||||
$event=new COutputEvent($this,$output);
|
||||
$this->onProcessOutput($event);
|
||||
if(!$event->handled)
|
||||
echo $output;
|
||||
}
|
||||
else
|
||||
echo $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Raised when the output has been captured.
|
||||
* @param COutputEvent $event event parameter
|
||||
*/
|
||||
public function onProcessOutput($event)
|
||||
{
|
||||
$this->raiseEvent('onProcessOutput',$event);
|
||||
}
|
||||
}
|
||||
205
framework/web/widgets/CStarRating.php
Normal file
205
framework/web/widgets/CStarRating.php
Normal file
@@ -0,0 +1,205 @@
|
||||
<?php
|
||||
/**
|
||||
* CStarRating class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CStarRating displays a star rating control that can collect user rating input.
|
||||
*
|
||||
* CStarRating is based on {@link http://www.fyneworks.com/jquery/star-rating/ jQuery Star Rating Plugin}.
|
||||
* It displays a list of stars indicating the rating values. Users can toggle these stars
|
||||
* to indicate their rating input. On the server side, when the rating input is submitted,
|
||||
* the value can be retrieved in the same way as working with a normal HTML input.
|
||||
* For example, using
|
||||
* <pre>
|
||||
* $this->widget('CStarRating',array('name'=>'rating'));
|
||||
* </pre>
|
||||
* we can retrieve the rating value via <code>$_POST['rating']</code>.
|
||||
*
|
||||
* CStarRating allows customization of its appearance. It also supports empty rating as well as read-only rating.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets
|
||||
* @since 1.0
|
||||
*/
|
||||
class CStarRating extends CInputWidget
|
||||
{
|
||||
/**
|
||||
* @var integer the number of stars. Defaults to 5.
|
||||
*/
|
||||
public $starCount=5;
|
||||
/**
|
||||
* @var mixed the minimum rating allowed. This can be either an integer or a float value. Defaults to 1.
|
||||
*/
|
||||
public $minRating=1;
|
||||
/**
|
||||
* @var mixed the maximum rating allowed. This can be either an integer or a float value. Defaults to 10.
|
||||
*/
|
||||
public $maxRating=10;
|
||||
/**
|
||||
* @var mixed the step size of rating. This is the minimum difference between two rating values. Defaults to 1.
|
||||
*/
|
||||
public $ratingStepSize=1;
|
||||
/**
|
||||
* @var mixed the CSS file used for the widget. Defaults to null, meaning
|
||||
* using the default CSS file included together with the widget.
|
||||
* If false, no CSS file will be used. Otherwise, the specified CSS file
|
||||
* will be included when using this widget.
|
||||
*/
|
||||
public $cssFile;
|
||||
/**
|
||||
* @var array the titles associated with the rating options. The keys are ratings and the values are the corresponding titles.
|
||||
* Defaults to null, meaning using the rating value as the title.
|
||||
*/
|
||||
public $titles;
|
||||
/**
|
||||
* @var string the hint text for the reset button. Defaults to null, meaning using the system-defined text (which is 'Cancel Rating').
|
||||
*/
|
||||
public $resetText;
|
||||
/**
|
||||
* @var string the value taken when the rating is cleared. Defaults to null, meaning using the system-defined value (which is '').
|
||||
*/
|
||||
public $resetValue;
|
||||
/**
|
||||
* @var boolean whether the rating value can be empty (not set). Defaults to true.
|
||||
* When this is true, a reset button will be displayed in front of stars.
|
||||
*/
|
||||
public $allowEmpty;
|
||||
/**
|
||||
* @var integer the width of star image. Defaults to null, meaning using the system-defined value (which is 16).
|
||||
*/
|
||||
public $starWidth;
|
||||
/**
|
||||
* @var boolean whether the rating value is read-only or not. Defaults to false.
|
||||
* When this is true, the rating cannot be changed.
|
||||
*/
|
||||
public $readOnly;
|
||||
/**
|
||||
* @var string Callback when the stars are focused.
|
||||
*/
|
||||
public $focus;
|
||||
/**
|
||||
* @var string Callback when the stars are not focused.
|
||||
*/
|
||||
public $blur;
|
||||
/**
|
||||
* @var string Callback when the stars are clicked.
|
||||
*/
|
||||
public $callback;
|
||||
|
||||
|
||||
/**
|
||||
* Executes the widget.
|
||||
* This method registers all needed client scripts and renders
|
||||
* the text field.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
list($name,$id)=$this->resolveNameID();
|
||||
if(isset($this->htmlOptions['id']))
|
||||
$id=$this->htmlOptions['id'];
|
||||
else
|
||||
$this->htmlOptions['id']=$id;
|
||||
if(isset($this->htmlOptions['name']))
|
||||
$name=$this->htmlOptions['name'];
|
||||
|
||||
$this->registerClientScript($id);
|
||||
|
||||
echo CHtml::openTag('span',$this->htmlOptions)."\n";
|
||||
$this->renderStars($id,$name);
|
||||
echo "</span>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the necessary javascript and css scripts.
|
||||
* @param string $id the ID of the container
|
||||
*/
|
||||
public function registerClientScript($id)
|
||||
{
|
||||
$jsOptions=$this->getClientOptions();
|
||||
$jsOptions=empty($jsOptions) ? '' : CJavaScript::encode($jsOptions);
|
||||
$js="jQuery('#{$id} > input').rating({$jsOptions});";
|
||||
$cs=Yii::app()->getClientScript();
|
||||
$cs->registerCoreScript('rating');
|
||||
$cs->registerScript('Yii.CStarRating#'.$id,$js);
|
||||
|
||||
if($this->cssFile!==false)
|
||||
self::registerCssFile($this->cssFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the needed CSS file.
|
||||
* @param string $url the CSS URL. If null, a default CSS URL will be used.
|
||||
*/
|
||||
public static function registerCssFile($url=null)
|
||||
{
|
||||
$cs=Yii::app()->getClientScript();
|
||||
if($url===null)
|
||||
$url=$cs->getCoreScriptUrl().'/rating/jquery.rating.css';
|
||||
$cs->registerCssFile($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the stars.
|
||||
* @param string $id the ID of the container
|
||||
* @param string $name the name of the input
|
||||
*/
|
||||
protected function renderStars($id,$name)
|
||||
{
|
||||
$inputCount=(int)(($this->maxRating-$this->minRating)/$this->ratingStepSize+1);
|
||||
$starSplit=(int)($inputCount/$this->starCount);
|
||||
if($this->hasModel())
|
||||
{
|
||||
$attr=$this->attribute;
|
||||
CHtml::resolveName($this->model,$attr);
|
||||
$selection=$this->model->$attr;
|
||||
}
|
||||
else
|
||||
$selection=$this->value;
|
||||
$options=$starSplit>1 ? array('class'=>"{split:{$starSplit}}") : array();
|
||||
for($value=$this->minRating, $i=0;$i<$inputCount; ++$i, $value+=$this->ratingStepSize)
|
||||
{
|
||||
$options['id']=$id.'_'.$i;
|
||||
$options['value']=$value;
|
||||
if(isset($this->titles[$value]))
|
||||
$options['title']=$this->titles[$value];
|
||||
else
|
||||
unset($options['title']);
|
||||
echo CHtml::radioButton($name,!strcmp($value,$selection),$options) . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array the javascript options for the star rating
|
||||
*/
|
||||
protected function getClientOptions()
|
||||
{
|
||||
$options=array();
|
||||
if($this->resetText!==null)
|
||||
$options['cancel']=$this->resetText;
|
||||
if($this->resetValue!==null)
|
||||
$options['cancelValue']=$this->resetValue;
|
||||
if($this->allowEmpty===false)
|
||||
$options['required']=true;
|
||||
if($this->starWidth!==null)
|
||||
$options['starWidth']=$this->starWidth;
|
||||
if($this->readOnly===true)
|
||||
$options['readOnly']=true;
|
||||
foreach(array('focus', 'blur', 'callback') as $event)
|
||||
{
|
||||
if($this->$event!==null)
|
||||
{
|
||||
if($this->$event instanceof CJavaScriptExpression)
|
||||
$options[$event]=$this->$event;
|
||||
else
|
||||
$options[$event]=new CJavaScriptExpression($this->$event);
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
222
framework/web/widgets/CTabView.php
Normal file
222
framework/web/widgets/CTabView.php
Normal file
@@ -0,0 +1,222 @@
|
||||
<?php
|
||||
/**
|
||||
* CTabView class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CTabView displays contents in multiple tabs.
|
||||
*
|
||||
* At any time, only one tab is visible. Users can click on the tab header
|
||||
* to switch to see another tab of content.
|
||||
*
|
||||
* JavaScript is used to control the tab switching. If JavaScript is disabled,
|
||||
* CTabView still manages to display the content in a semantically appropriate way.
|
||||
*
|
||||
* To specify contents and their tab structure, configure the {@link tabs} property.
|
||||
* The {@link tabs} property takes an array with tab ID being mapped tab definition.
|
||||
* Each tab definition is an array of the following structure:
|
||||
* <ul>
|
||||
* <li>title: the tab title.</li>
|
||||
* <li>content: the content to be displayed in the tab.</li>
|
||||
* <li>view: the name of the view to be displayed in this tab.
|
||||
* The view will be rendered using the current controller's
|
||||
* {@link CController::renderPartial} method.
|
||||
* When both 'content' and 'view' are specified, 'content' will take precedence.
|
||||
* </li>
|
||||
* <li>url: a URL that the user browser will be redirected to when clicking on this tab.</li>
|
||||
* <li>data: array (name=>value), this will be passed to the view when 'view' is specified.</li>
|
||||
* </ul>
|
||||
*
|
||||
* For example, the {@link tabs} property can be configured as follows,
|
||||
* <pre>
|
||||
* $this->widget('CTabView', array(
|
||||
* 'tabs'=>array(
|
||||
* 'tab1'=>array(
|
||||
* 'title'=>'tab 1 title',
|
||||
* 'view'=>'view1',
|
||||
* 'data'=>array('model'=>$model),
|
||||
* ),
|
||||
* 'tab2'=>array(
|
||||
* 'title'=>'tab 2 title',
|
||||
* 'url'=>'http://www.yiiframework.com/',
|
||||
* ),
|
||||
* ),
|
||||
* ));
|
||||
* </pre>
|
||||
*
|
||||
* By default, the first tab will be activated. To activate a different tab
|
||||
* when the page is initially loaded, set {@link activeTab} to be the ID of the desired tab.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets
|
||||
* @since 1.0
|
||||
*/
|
||||
class CTabView extends CWidget
|
||||
{
|
||||
/**
|
||||
* Default CSS class for the tab container
|
||||
*/
|
||||
const CSS_CLASS='yiiTab';
|
||||
|
||||
/**
|
||||
* @var mixed the CSS file used for the widget. Defaults to null, meaning
|
||||
* using the default CSS file included together with the widget.
|
||||
* If false, no CSS file will be used. Otherwise, the specified CSS file
|
||||
* will be included when using this widget.
|
||||
*/
|
||||
public $cssFile;
|
||||
/**
|
||||
* @var string the ID of the tab that should be activated when the page is initially loaded.
|
||||
* If not set, the first tab will be activated.
|
||||
*/
|
||||
public $activeTab;
|
||||
/**
|
||||
* @var array the data that will be passed to the partial view rendered by each tab.
|
||||
*/
|
||||
public $viewData;
|
||||
/**
|
||||
* @var array additional HTML options to be rendered in the container tag.
|
||||
*/
|
||||
public $htmlOptions;
|
||||
/**
|
||||
* @var array tab definitions. The array keys are the IDs,
|
||||
* and the array values are the corresponding tab contents.
|
||||
* Each array value must be an array with the following elements:
|
||||
* <ul>
|
||||
* <li>title: the tab title. You need to make sure this is HTML-encoded.</li>
|
||||
* <li>content: the content to be displayed in the tab.</li>
|
||||
* <li>view: the name of the view to be displayed in this tab.
|
||||
* The view will be rendered using the current controller's
|
||||
* {@link CController::renderPartial} method.
|
||||
* When both 'content' and 'view' are specified, 'content' will take precedence.
|
||||
* </li>
|
||||
* <li>url: a URL that the user browser will be redirected to when clicking on this tab.</li>
|
||||
* <li>data: array (name=>value), this will be passed to the view when 'view' is specified.
|
||||
* This option is available since version 1.1.1.</li>
|
||||
* <li>visible: whether this tab is visible. Defaults to true.
|
||||
* this option is available since version 1.1.11.</li>
|
||||
* </ul>
|
||||
* <pre>
|
||||
* array(
|
||||
* 'tab1'=>array(
|
||||
* 'title'=>'tab 1 title',
|
||||
* 'view'=>'view1',
|
||||
* ),
|
||||
* 'tab2'=>array(
|
||||
* 'title'=>'tab 2 title',
|
||||
* 'url'=>'http://www.yiiframework.com/',
|
||||
* ),
|
||||
* )
|
||||
* </pre>
|
||||
*/
|
||||
public $tabs=array();
|
||||
|
||||
/**
|
||||
* Runs the widget.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
foreach($this->tabs as $id=>$tab)
|
||||
if(isset($tab['visible']) && $tab['visible']==false)
|
||||
unset($this->tabs[$id]);
|
||||
|
||||
if(empty($this->tabs))
|
||||
return;
|
||||
|
||||
if($this->activeTab===null || !isset($this->tabs[$this->activeTab]))
|
||||
{
|
||||
reset($this->tabs);
|
||||
list($this->activeTab, )=each($this->tabs);
|
||||
}
|
||||
|
||||
$htmlOptions=$this->htmlOptions;
|
||||
if(isset($this->htmlOptions['id']))
|
||||
$this->id=$this->htmlOptions['id'];
|
||||
else
|
||||
$htmlOptions['id']=$this->id;
|
||||
if(!isset($htmlOptions['class']))
|
||||
$htmlOptions['class']=self::CSS_CLASS;
|
||||
|
||||
$this->registerClientScript();
|
||||
|
||||
echo CHtml::openTag('div',$htmlOptions)."\n";
|
||||
$this->renderHeader();
|
||||
$this->renderBody();
|
||||
echo CHtml::closeTag('div');
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the needed CSS and JavaScript.
|
||||
*/
|
||||
public function registerClientScript()
|
||||
{
|
||||
$cs=Yii::app()->getClientScript();
|
||||
$cs->registerCoreScript('yiitab');
|
||||
$id=$this->getId();
|
||||
$cs->registerScript('Yii.CTabView#'.$id,"jQuery(\"#{$id}\").yiitab();");
|
||||
|
||||
if($this->cssFile!==false)
|
||||
self::registerCssFile($this->cssFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the needed CSS file.
|
||||
* @param string $url the CSS URL. If null, a default CSS URL will be used.
|
||||
*/
|
||||
public static function registerCssFile($url=null)
|
||||
{
|
||||
$cs=Yii::app()->getClientScript();
|
||||
if($url===null)
|
||||
$url=$cs->getCoreScriptUrl().'/yiitab/jquery.yiitab.css';
|
||||
$cs->registerCssFile($url,'screen');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the header part.
|
||||
*/
|
||||
protected function renderHeader()
|
||||
{
|
||||
echo "<ul class=\"tabs\">\n";
|
||||
foreach($this->tabs as $id=>$tab)
|
||||
{
|
||||
$title=isset($tab['title'])?$tab['title']:'undefined';
|
||||
$active=$id===$this->activeTab?' class="active"' : '';
|
||||
$url=isset($tab['url'])?$tab['url']:"#{$id}";
|
||||
echo "<li><a href=\"{$url}\"{$active}>{$title}</a></li>\n";
|
||||
}
|
||||
echo "</ul>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the body part.
|
||||
*/
|
||||
protected function renderBody()
|
||||
{
|
||||
foreach($this->tabs as $id=>$tab)
|
||||
{
|
||||
$inactive=$id!==$this->activeTab?' style="display:none"' : '';
|
||||
echo "<div class=\"view\" id=\"{$id}\"{$inactive}>\n";
|
||||
if(isset($tab['content']))
|
||||
echo $tab['content'];
|
||||
elseif(isset($tab['view']))
|
||||
{
|
||||
if(isset($tab['data']))
|
||||
{
|
||||
if(is_array($this->viewData))
|
||||
$data=array_merge($this->viewData, $tab['data']);
|
||||
else
|
||||
$data=$tab['data'];
|
||||
}
|
||||
else
|
||||
$data=$this->viewData;
|
||||
$this->getController()->renderPartial($tab['view'], $data);
|
||||
}
|
||||
echo "</div><!-- {$id} -->\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
124
framework/web/widgets/CTextHighlighter.php
Normal file
124
framework/web/widgets/CTextHighlighter.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
/**
|
||||
* CTextHighlighter class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
require_once(Yii::getPathOfAlias('system.vendors.TextHighlighter.Text.Highlighter').'.php');
|
||||
require_once(Yii::getPathOfAlias('system.vendors.TextHighlighter.Text.Highlighter.Renderer.Html').'.php');
|
||||
|
||||
/**
|
||||
* CTextHighlighter does syntax highlighting for its body content.
|
||||
*
|
||||
* The language of the syntax to be applied is specified via {@link language} property.
|
||||
* Currently, CTextHighlighter supports the following languages:
|
||||
* ABAP, CPP, CSS, DIFF, DTD, HTML, JAVA, JAVASCRIPT, MYSQL, PERL,
|
||||
* PHP, PYTHON, RUBY, SQL, XML. By setting {@link showLineNumbers}
|
||||
* to true, the highlighted result may be shown with line numbers.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets
|
||||
* @since 1.0
|
||||
*/
|
||||
class CTextHighlighter extends COutputProcessor
|
||||
{
|
||||
/**
|
||||
* @var string the language whose syntax is to be used for highlighting.
|
||||
* Valid values are those file names (without suffix) that are contained
|
||||
* in 'vendors/TextHighlighter/Text/Highlighter'. Currently, the following
|
||||
* languages are supported:
|
||||
* ABAP, CPP, CSS, DIFF, DTD, HTML, JAVA, JAVASCRIPT,
|
||||
* MYSQL, PERL, PHP, PYTHON, RUBY, SQL, XML
|
||||
* If a language is not supported, it will be displayed as plain text.
|
||||
* Language names are case-insensitive.
|
||||
*/
|
||||
public $language;
|
||||
/**
|
||||
* @var boolean whether to show line numbers in the highlighted result. Defaults to false.
|
||||
* @see lineNumberStyle
|
||||
*/
|
||||
public $showLineNumbers=false;
|
||||
/**
|
||||
* @var string the style of line number display. It can be either 'list' or 'table'. Defaults to 'list'.
|
||||
* @see showLineNumbers
|
||||
*/
|
||||
public $lineNumberStyle='list';
|
||||
/**
|
||||
* @var integer tab size. Defaults to 4.
|
||||
*/
|
||||
public $tabSize=4;
|
||||
/**
|
||||
* @var mixed the CSS file used for the widget. Defaults to null, meaning
|
||||
* using the default CSS file included together with the widget.
|
||||
* If false, no CSS file will be used. Otherwise, the specified CSS file
|
||||
* will be included when using this widget.
|
||||
*/
|
||||
public $cssFile;
|
||||
/**
|
||||
* @var array the HTML attributes to be applied to the container element.
|
||||
* The highlighted content is contained in a DIV element.
|
||||
*/
|
||||
public $containerOptions=array();
|
||||
|
||||
|
||||
/**
|
||||
* Processes the captured output.
|
||||
* This method highlights the output according to the syntax of the specified {@link language}.
|
||||
* @param string $output the captured output to be processed
|
||||
*/
|
||||
public function processOutput($output)
|
||||
{
|
||||
$output=$this->highlight($output);
|
||||
parent::processOutput($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlights the content by the syntax of the specified language.
|
||||
* @param string $content the content to be highlighted.
|
||||
* @return string the highlighted content
|
||||
*/
|
||||
public function highlight($content)
|
||||
{
|
||||
$this->registerClientScript();
|
||||
|
||||
$options['use_language']=true;
|
||||
$options['tabsize']=$this->tabSize;
|
||||
if($this->showLineNumbers)
|
||||
$options['numbers']=($this->lineNumberStyle==='list')?HL_NUMBERS_LI:HL_NUMBERS_TABLE;
|
||||
|
||||
$highlighter=empty($this->language)?false:Text_Highlighter::factory($this->language);
|
||||
if($highlighter===false)
|
||||
$o='<pre>'.CHtml::encode($content).'</pre>';
|
||||
else
|
||||
{
|
||||
$highlighter->setRenderer(new Text_Highlighter_Renderer_Html($options));
|
||||
$o=preg_replace('/<span\s+[^>]*>(\s*)<\/span>/','\1',$highlighter->highlight($content));
|
||||
}
|
||||
|
||||
return CHtml::tag('div',$this->containerOptions,$o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the needed CSS and JavaScript.
|
||||
*/
|
||||
public function registerClientScript()
|
||||
{
|
||||
if($this->cssFile!==false)
|
||||
self::registerCssFile($this->cssFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the needed CSS file.
|
||||
* @param string $url the CSS URL. If null, a default CSS URL will be used.
|
||||
*/
|
||||
public static function registerCssFile($url=null)
|
||||
{
|
||||
if($url===null)
|
||||
$url=CHtml::asset(Yii::getPathOfAlias('system.vendors.TextHighlighter.highlight').'.css');
|
||||
Yii::app()->getClientScript()->registerCssFile($url);
|
||||
}
|
||||
}
|
||||
245
framework/web/widgets/CTreeView.php
Normal file
245
framework/web/widgets/CTreeView.php
Normal file
@@ -0,0 +1,245 @@
|
||||
<?php
|
||||
/**
|
||||
* CTreeView class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CTreeView displays a tree view of hierarchical data.
|
||||
*
|
||||
* It encapsulates the excellent tree view plugin for jQuery
|
||||
* ({@link http://bassistance.de/jquery-plugins/jquery-plugin-treeview/}).
|
||||
*
|
||||
* To use CTreeView, simply sets {@link data} to the data that you want
|
||||
* to present and you are there.
|
||||
*
|
||||
* CTreeView also supports dynamic data loading via AJAX. To do so, set
|
||||
* {@link url} to be the URL that can serve the tree view data upon request.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets
|
||||
* @since 1.0
|
||||
*/
|
||||
class CTreeView extends CWidget
|
||||
{
|
||||
/**
|
||||
* @var array the data that can be used to generate the tree view content.
|
||||
* Each array element corresponds to a tree view node with the following structure:
|
||||
* <ul>
|
||||
* <li>text: string, required, the HTML text associated with this node.</li>
|
||||
* <li>expanded: boolean, optional, whether the tree view node is expanded.</li>
|
||||
* <li>id: string, optional, the ID identifying the node. This is used
|
||||
* in dynamic loading of tree view (see {@link url}).</li>
|
||||
* <li>hasChildren: boolean, optional, defaults to false, whether clicking on this
|
||||
* node should trigger dynamic loading of more tree view nodes from server.
|
||||
* The {@link url} property must be set in order to make this effective.</li>
|
||||
* <li>children: array, optional, child nodes of this node.</li>
|
||||
* <li>htmlOptions: array, additional HTML attributes (see {@link CHtml::tag}).
|
||||
* This option has been available since version 1.1.7.</li>
|
||||
* </ul>
|
||||
* Note, anything enclosed between the beginWidget and endWidget calls will
|
||||
* also be treated as tree view content, which appends to the content generated
|
||||
* from this data.
|
||||
*/
|
||||
public $data;
|
||||
/**
|
||||
* @var mixed the CSS file used for the widget. Defaults to null, meaning
|
||||
* using the default CSS file included together with the widget.
|
||||
* If false, no CSS file will be used. Otherwise, the specified CSS file
|
||||
* will be included when using this widget.
|
||||
*/
|
||||
public $cssFile;
|
||||
/**
|
||||
* @var string|array the URL to which the treeview can be dynamically loaded (in AJAX).
|
||||
* See {@link CHtml::normalizeUrl} for possible URL formats.
|
||||
* Setting this property will enable the dynamic treeview loading.
|
||||
* When the page is displayed, the browser will request this URL with a GET parameter
|
||||
* named 'root' whose value is 'source'. The server script should then generate the
|
||||
* needed tree view data corresponding to the root of the tree (see {@link saveDataAsJson}.)
|
||||
* When a node has a CSS class 'hasChildren', then expanding this node will also
|
||||
* cause a dynamic loading of its child nodes. In this case, the value of the 'root' GET parameter
|
||||
* is the 'id' property of the node.
|
||||
*/
|
||||
public $url;
|
||||
/**
|
||||
* @var string|integer animation speed. This can be one of the three predefined speeds
|
||||
* ("slow", "normal", or "fast") or the number of milliseconds to run the animation (e.g. 1000).
|
||||
* If not set, no animation is used.
|
||||
*/
|
||||
public $animated;
|
||||
/**
|
||||
* @var boolean whether the tree should start with all branches collapsed. Defaults to false.
|
||||
*/
|
||||
public $collapsed;
|
||||
/**
|
||||
* @var string container for a tree-control, allowing the user to expand, collapse and toggle all branches with one click.
|
||||
* In the container, clicking on the first hyperlink will collapse the tree;
|
||||
* the second hyperlink will expand the tree; while the third hyperlink will toggle the tree.
|
||||
* The property should be a valid jQuery selector (e.g. '#treecontrol' where 'treecontrol' is
|
||||
* the ID of the 'div' element containing the hyperlinks.)
|
||||
*/
|
||||
public $control;
|
||||
/**
|
||||
* @var boolean set to allow only one branch on one level to be open (closing siblings which opening).
|
||||
* Defaults to false.
|
||||
*/
|
||||
public $unique;
|
||||
/**
|
||||
* @var string Callback when toggling a branch. Arguments: "this" refers to the UL that was shown or hidden
|
||||
*/
|
||||
public $toggle;
|
||||
/**
|
||||
* @var string Persist the tree state in cookies or the page location. If set to "location", looks for
|
||||
* the anchor that matches location.href and activates that part of the treeview it.
|
||||
* Great for href-based state-saving. If set to "cookie", saves the state of the tree on
|
||||
* each click to a cookie and restores that state on page load.
|
||||
*/
|
||||
public $persist;
|
||||
/**
|
||||
* @var string The cookie name to use when persisting via persist:"cookie". Defaults to 'treeview'.
|
||||
*/
|
||||
public $cookieId;
|
||||
/**
|
||||
* @var boolean Set to skip rendering of classes and hitarea divs, assuming that is done by the serverside. Defaults to false.
|
||||
*/
|
||||
public $prerendered;
|
||||
/**
|
||||
* @var array additional options that can be passed to the constructor of the treeview js object.
|
||||
*/
|
||||
public $options=array();
|
||||
/**
|
||||
* @var array additional HTML attributes that will be rendered in the UL tag.
|
||||
* The default tree view CSS has defined the following CSS classes which can be enabled
|
||||
* by specifying the 'class' option here:
|
||||
* <ul>
|
||||
* <li>treeview-black</li>
|
||||
* <li>treeview-gray</li>
|
||||
* <li>treeview-red</li>
|
||||
* <li>treeview-famfamfam</li>
|
||||
* <li>filetree</li>
|
||||
* </ul>
|
||||
*/
|
||||
public $htmlOptions;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the widget.
|
||||
* This method registers all needed client scripts and renders
|
||||
* the tree view content.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if(isset($this->htmlOptions['id']))
|
||||
$id=$this->htmlOptions['id'];
|
||||
else
|
||||
$id=$this->htmlOptions['id']=$this->getId();
|
||||
if($this->url!==null)
|
||||
$this->url=CHtml::normalizeUrl($this->url);
|
||||
$cs=Yii::app()->getClientScript();
|
||||
$cs->registerCoreScript('treeview');
|
||||
$options=$this->getClientOptions();
|
||||
$options=$options===array()?'{}' : CJavaScript::encode($options);
|
||||
$cs->registerScript('Yii.CTreeView#'.$id,"jQuery(\"#{$id}\").treeview($options);");
|
||||
if($this->cssFile===null)
|
||||
$cs->registerCssFile($cs->getCoreScriptUrl().'/treeview/jquery.treeview.css');
|
||||
elseif($this->cssFile!==false)
|
||||
$cs->registerCssFile($this->cssFile);
|
||||
|
||||
echo CHtml::tag('ul',$this->htmlOptions,false,false)."\n";
|
||||
echo self::saveDataAsHtml($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends running the widget.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
echo "</ul>";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array the javascript options
|
||||
*/
|
||||
protected function getClientOptions()
|
||||
{
|
||||
$options=$this->options;
|
||||
foreach(array('url','animated','collapsed','control','unique','toggle','persist','cookieId','prerendered') as $name)
|
||||
{
|
||||
if($this->$name!==null)
|
||||
$options[$name]=$this->$name;
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates tree view nodes in HTML from the data array.
|
||||
* @param array $data the data for the tree view (see {@link data} for possible data structure).
|
||||
* @return string the generated HTML for the tree view
|
||||
*/
|
||||
public static function saveDataAsHtml($data)
|
||||
{
|
||||
$html='';
|
||||
if(is_array($data))
|
||||
{
|
||||
foreach($data as $node)
|
||||
{
|
||||
if(!isset($node['text']))
|
||||
continue;
|
||||
|
||||
if(isset($node['expanded']))
|
||||
$css=$node['expanded'] ? 'open' : 'closed';
|
||||
else
|
||||
$css='';
|
||||
|
||||
if(isset($node['hasChildren']) && $node['hasChildren'])
|
||||
{
|
||||
if($css!=='')
|
||||
$css.=' ';
|
||||
$css.='hasChildren';
|
||||
}
|
||||
|
||||
$options=isset($node['htmlOptions']) ? $node['htmlOptions'] : array();
|
||||
if($css!=='')
|
||||
{
|
||||
if(isset($options['class']))
|
||||
$options['class'].=' '.$css;
|
||||
else
|
||||
$options['class']=$css;
|
||||
}
|
||||
|
||||
if(isset($node['id']))
|
||||
$options['id']=$node['id'];
|
||||
|
||||
$html.=CHtml::tag('li',$options,$node['text'],false);
|
||||
if(!empty($node['children']))
|
||||
{
|
||||
$html.="\n<ul>\n";
|
||||
$html.=self::saveDataAsHtml($node['children']);
|
||||
$html.="</ul>\n";
|
||||
}
|
||||
$html.=CHtml::closeTag('li')."\n";
|
||||
}
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves tree view data in JSON format.
|
||||
* This method is typically used in dynamic tree view loading
|
||||
* when the server code needs to send to the client the dynamic
|
||||
* tree view data.
|
||||
* @param array $data the data for the tree view (see {@link data} for possible data structure).
|
||||
* @return string the JSON representation of the data
|
||||
*/
|
||||
public static function saveDataAsJson($data)
|
||||
{
|
||||
if(empty($data))
|
||||
return '[]';
|
||||
else
|
||||
return CJavaScript::jsonEncode($data);
|
||||
}
|
||||
}
|
||||
249
framework/web/widgets/CWidget.php
Normal file
249
framework/web/widgets/CWidget.php
Normal file
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
/**
|
||||
* CWidget class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CWidget is the base class for widgets.
|
||||
*
|
||||
* A widget is a self-contained component that may generate presentation
|
||||
* based on model data. It can be viewed as a micro-controller that embeds
|
||||
* into the controller-managed views.
|
||||
*
|
||||
* Compared with {@link CController controller}, a widget has neither actions nor filters.
|
||||
*
|
||||
* Usage is described at {@link CBaseController} and {@link CBaseController::widget}.
|
||||
*
|
||||
* @property CBaseController $owner Owner/creator of this widget. It could be either a widget or a controller.
|
||||
* @property string $id Id of the widget.
|
||||
* @property CController $controller The controller that this widget belongs to.
|
||||
* @property string $viewPath The directory containing the view files for this widget.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets
|
||||
* @since 1.0
|
||||
*/
|
||||
class CWidget extends CBaseController
|
||||
{
|
||||
/**
|
||||
* @var string the prefix to the IDs of the {@link actions}.
|
||||
* When a widget is declared an action provider in {@link CController::actions},
|
||||
* a prefix can be specified to differentiate its action IDs from others.
|
||||
* The same prefix should then also be used to configure this property
|
||||
* when the widget is used in a view of the controller.
|
||||
*/
|
||||
public $actionPrefix;
|
||||
/**
|
||||
* @var mixed the name of the skin to be used by this widget. Defaults to 'default'.
|
||||
* If this is set as false, no skin will be applied to this widget.
|
||||
* @see CWidgetFactory
|
||||
* @since 1.1
|
||||
*/
|
||||
public $skin='default';
|
||||
|
||||
/**
|
||||
* @var array view paths for different types of widgets
|
||||
*/
|
||||
private static $_viewPaths;
|
||||
/**
|
||||
* @var integer the counter for generating implicit IDs.
|
||||
*/
|
||||
private static $_counter=0;
|
||||
/**
|
||||
* @var string id of the widget.
|
||||
*/
|
||||
private $_id;
|
||||
/**
|
||||
* @var CBaseController owner/creator of this widget. It could be either a widget or a controller.
|
||||
*/
|
||||
private $_owner;
|
||||
|
||||
/**
|
||||
* Returns a list of actions that are used by this widget.
|
||||
* The structure of this method's return value is similar to
|
||||
* that returned by {@link CController::actions}.
|
||||
*
|
||||
* When a widget uses several actions, you can declare these actions using
|
||||
* this method. The widget will then become an action provider, and the actions
|
||||
* can be easily imported into a controller.
|
||||
*
|
||||
* Note, when creating URLs referring to the actions listed in this method,
|
||||
* make sure the action IDs are prefixed with {@link actionPrefix}.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @see actionPrefix
|
||||
* @see CController::actions
|
||||
*/
|
||||
public static function actions()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param CBaseController $owner owner/creator of this widget. It could be either a widget or a controller.
|
||||
*/
|
||||
public function __construct($owner=null)
|
||||
{
|
||||
$this->_owner=$owner===null?Yii::app()->getController():$owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the owner/creator of this widget.
|
||||
* @return CBaseController owner/creator of this widget. It could be either a widget or a controller.
|
||||
*/
|
||||
public function getOwner()
|
||||
{
|
||||
return $this->_owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID of the widget or generates a new one if requested.
|
||||
* @param boolean $autoGenerate whether to generate an ID if it is not set previously
|
||||
* @return string id of the widget.
|
||||
*/
|
||||
public function getId($autoGenerate=true)
|
||||
{
|
||||
if($this->_id!==null)
|
||||
return $this->_id;
|
||||
elseif($autoGenerate)
|
||||
return $this->_id='yw'.self::$_counter++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ID of the widget.
|
||||
* @param string $value id of the widget.
|
||||
*/
|
||||
public function setId($value)
|
||||
{
|
||||
$this->_id=$value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the controller that this widget belongs to.
|
||||
* @return CController the controller that this widget belongs to.
|
||||
*/
|
||||
public function getController()
|
||||
{
|
||||
if($this->_owner instanceof CController)
|
||||
return $this->_owner;
|
||||
else
|
||||
return Yii::app()->getController();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the widget.
|
||||
* This method is called by {@link CBaseController::createWidget}
|
||||
* and {@link CBaseController::beginWidget} after the widget's
|
||||
* properties have been initialized.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the widget.
|
||||
* This method is called by {@link CBaseController::endWidget}.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directory containing the view files for this widget.
|
||||
* The default implementation returns the 'views' subdirectory of the directory containing the widget class file.
|
||||
* If $checkTheme is set true, the directory "ThemeID/views/ClassName" will be returned when it exists.
|
||||
* @param boolean $checkTheme whether to check if the theme contains a view path for the widget.
|
||||
* @return string the directory containing the view files for this widget.
|
||||
*/
|
||||
public function getViewPath($checkTheme=false)
|
||||
{
|
||||
$className=get_class($this);
|
||||
$scope=$checkTheme?'theme':'local';
|
||||
if(isset(self::$_viewPaths[$className][$scope]))
|
||||
return self::$_viewPaths[$className][$scope];
|
||||
else
|
||||
{
|
||||
if($checkTheme && ($theme=Yii::app()->getTheme())!==null)
|
||||
{
|
||||
$path=$theme->getViewPath().DIRECTORY_SEPARATOR;
|
||||
if(strpos($className,'\\')!==false) // namespaced class
|
||||
$path.=str_replace('\\','_',ltrim($className,'\\'));
|
||||
else
|
||||
$path.=$className;
|
||||
if(is_dir($path))
|
||||
return self::$_viewPaths[$className]['theme']=$path;
|
||||
}
|
||||
|
||||
$class=new ReflectionClass($className);
|
||||
return self::$_viewPaths[$className]['local']=dirname($class->getFileName()).DIRECTORY_SEPARATOR.'views';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for the view script file according to the view name.
|
||||
* This method will look for the view under the widget's {@link getViewPath viewPath}.
|
||||
* The view script file is named as "ViewName.php". A localized view file
|
||||
* may be returned if internationalization is needed. See {@link CApplication::findLocalizedFile}
|
||||
* for more details.
|
||||
* The view name can also refer to a path alias if it contains dot characters.
|
||||
* @param string $viewName name of the view (without file extension)
|
||||
* @return string the view file path. False if the view file does not exist
|
||||
* @see CApplication::findLocalizedFile
|
||||
*/
|
||||
public function getViewFile($viewName)
|
||||
{
|
||||
if(($renderer=Yii::app()->getViewRenderer())!==null)
|
||||
$extension=$renderer->fileExtension;
|
||||
else
|
||||
$extension='.php';
|
||||
if(strpos($viewName,'.')) // a path alias
|
||||
$viewFile=Yii::getPathOfAlias($viewName);
|
||||
else
|
||||
{
|
||||
$viewFile=$this->getViewPath(true).DIRECTORY_SEPARATOR.$viewName;
|
||||
if(is_file($viewFile.$extension))
|
||||
return Yii::app()->findLocalizedFile($viewFile.$extension);
|
||||
elseif($extension!=='.php' && is_file($viewFile.'.php'))
|
||||
return Yii::app()->findLocalizedFile($viewFile.'.php');
|
||||
$viewFile=$this->getViewPath(false).DIRECTORY_SEPARATOR.$viewName;
|
||||
}
|
||||
|
||||
if(is_file($viewFile.$extension))
|
||||
return Yii::app()->findLocalizedFile($viewFile.$extension);
|
||||
elseif($extension!=='.php' && is_file($viewFile.'.php'))
|
||||
return Yii::app()->findLocalizedFile($viewFile.'.php');
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a view.
|
||||
*
|
||||
* The named view refers to a PHP script (resolved via {@link getViewFile})
|
||||
* that is included by this method. If $data is an associative array,
|
||||
* it will be extracted as PHP variables and made available to the script.
|
||||
*
|
||||
* @param string $view name of the view to be rendered. See {@link getViewFile} for details
|
||||
* about how the view script is resolved.
|
||||
* @param array $data data to be extracted into PHP variables and made available to the view script
|
||||
* @param boolean $return whether the rendering result should be returned instead of being displayed to end users
|
||||
* @return string the rendering result. Null if the rendering result is not required.
|
||||
* @throws CException if the view does not exist
|
||||
* @see getViewFile
|
||||
*/
|
||||
public function render($view,$data=null,$return=false)
|
||||
{
|
||||
if(($viewFile=$this->getViewFile($view))!==false)
|
||||
return $this->renderFile($viewFile,$data,$return);
|
||||
else
|
||||
throw new CException(Yii::t('yii','{widget} cannot find the view "{view}".',
|
||||
array('{widget}'=>get_class($this), '{view}'=>$view)));
|
||||
}
|
||||
}
|
||||
188
framework/web/widgets/captcha/CCaptcha.php
Normal file
188
framework/web/widgets/captcha/CCaptcha.php
Normal file
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
/**
|
||||
* CCaptcha class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CCaptcha renders a CAPTCHA image element.
|
||||
*
|
||||
* CCaptcha is used together with {@link CCaptchaAction} to provide {@link http://en.wikipedia.org/wiki/Captcha CAPTCHA}
|
||||
* - a way of preventing site spam.
|
||||
*
|
||||
* The image element rendered by CCaptcha will display a CAPTCHA image generated
|
||||
* by an action of class {@link CCaptchaAction} belonging to the current controller.
|
||||
* By default, the action ID should be 'captcha', which can be changed by setting {@link captchaAction}.
|
||||
*
|
||||
* CCaptcha may also render a button next to the CAPTCHA image. Clicking on the button
|
||||
* will change the CAPTCHA image to be a new one in an AJAX way.
|
||||
*
|
||||
* If {@link clickableImage} is set true, clicking on the CAPTCHA image
|
||||
* will refresh the CAPTCHA.
|
||||
*
|
||||
* A {@link CCaptchaValidator} may be used to validate that the user enters
|
||||
* a verification code matching the code displayed in the CAPTCHA image.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets.captcha
|
||||
* @since 1.0
|
||||
*/
|
||||
class CCaptcha extends CWidget
|
||||
{
|
||||
/**
|
||||
* @var string the ID of the action that should provide CAPTCHA image. Defaults to 'captcha',
|
||||
* meaning the 'captcha' action of the current controller. This property may also
|
||||
* be in the format of 'ControllerID/ActionID'. Underneath, this property is used
|
||||
* by {@link CController::createUrl} to create the URL that would serve the CAPTCHA image.
|
||||
* The action has to be of {@link CCaptchaAction}.
|
||||
*/
|
||||
public $captchaAction='captcha';
|
||||
/**
|
||||
* @var boolean whether to display a button next to the CAPTCHA image. Clicking on the button
|
||||
* will cause the CAPTCHA image to be changed to a new one. Defaults to true.
|
||||
*/
|
||||
public $showRefreshButton=true;
|
||||
/**
|
||||
* @var boolean whether to allow clicking on the CAPTCHA image to refresh the CAPTCHA letters.
|
||||
* Defaults to false. Hint: you may want to set {@link showRefreshButton} to false if you set
|
||||
* this property to be true because they serve for the same purpose.
|
||||
* To enhance accessibility, you may set {@link imageOptions} to provide hints to end-users that
|
||||
* the image is clickable.
|
||||
*/
|
||||
public $clickableImage=false;
|
||||
/**
|
||||
* @var string the label for the refresh button. Defaults to 'Get a new code'.
|
||||
*/
|
||||
public $buttonLabel;
|
||||
/**
|
||||
* @var string the type of the refresh button. This should be either 'link' or 'button'.
|
||||
* The former refers to hyperlink button while the latter a normal push button.
|
||||
* Defaults to 'link'.
|
||||
*/
|
||||
public $buttonType='link';
|
||||
/**
|
||||
* @var array HTML attributes to be applied to the rendered image element.
|
||||
*/
|
||||
public $imageOptions=array();
|
||||
/**
|
||||
* @var array HTML attributes to be applied to the rendered refresh button element.
|
||||
*/
|
||||
public $buttonOptions=array();
|
||||
|
||||
|
||||
/**
|
||||
* Renders the widget.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
if(self::checkRequirements('imagick') || self::checkRequirements('gd'))
|
||||
{
|
||||
$this->renderImage();
|
||||
$this->registerClientScript();
|
||||
}
|
||||
else
|
||||
throw new CException(Yii::t('yii','GD with FreeType or ImageMagick PHP extensions are required.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the CAPTCHA image.
|
||||
*/
|
||||
protected function renderImage()
|
||||
{
|
||||
if(!isset($this->imageOptions['id']))
|
||||
$this->imageOptions['id']=$this->getId();
|
||||
|
||||
$url=$this->getController()->createUrl($this->captchaAction,array('v'=>uniqid()));
|
||||
$alt=isset($this->imageOptions['alt'])?$this->imageOptions['alt']:'';
|
||||
echo CHtml::image($url,$alt,$this->imageOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the needed client scripts.
|
||||
*/
|
||||
public function registerClientScript()
|
||||
{
|
||||
$cs=Yii::app()->clientScript;
|
||||
$id=$this->imageOptions['id'];
|
||||
$url=$this->getController()->createUrl($this->captchaAction,array(CCaptchaAction::REFRESH_GET_VAR=>true));
|
||||
|
||||
$js="";
|
||||
if($this->showRefreshButton)
|
||||
{
|
||||
// reserve a place in the registered script so that any enclosing button js code appears after the captcha js
|
||||
$cs->registerScript('Yii.CCaptcha#'.$id,'// dummy');
|
||||
$label=$this->buttonLabel===null?Yii::t('yii','Get a new code'):$this->buttonLabel;
|
||||
$options=$this->buttonOptions;
|
||||
if(isset($options['id']))
|
||||
$buttonID=$options['id'];
|
||||
else
|
||||
$buttonID=$options['id']=$id.'_button';
|
||||
if($this->buttonType==='button')
|
||||
$html=CHtml::button($label, $options);
|
||||
else
|
||||
$html=CHtml::link($label, $url, $options);
|
||||
$js="jQuery('#$id').after(".CJSON::encode($html).");";
|
||||
$selector="#$buttonID";
|
||||
}
|
||||
|
||||
if($this->clickableImage)
|
||||
$selector=isset($selector) ? "$selector, #$id" : "#$id";
|
||||
|
||||
if(!isset($selector))
|
||||
return;
|
||||
|
||||
$js.="
|
||||
jQuery(document).on('click', '$selector', function(){
|
||||
jQuery.ajax({
|
||||
url: ".CJSON::encode($url).",
|
||||
dataType: 'json',
|
||||
cache: false,
|
||||
success: function(data) {
|
||||
jQuery('#$id').attr('src', data['url']);
|
||||
jQuery('body').data('{$this->captchaAction}.hash', [data['hash1'], data['hash2']]);
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
";
|
||||
$cs->registerScript('Yii.CCaptcha#'.$id,$js);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if specified graphic extension support is loaded.
|
||||
* @param string $extension name to be checked. Possible values are 'gd', 'imagick' and null.
|
||||
* Default value is null meaning that both extensions will be checked. This parameter
|
||||
* is available since 1.1.13.
|
||||
* @return boolean true if ImageMagick extension with PNG support or GD with FreeType support is loaded,
|
||||
* otherwise false
|
||||
* @since 1.1.5
|
||||
*/
|
||||
public static function checkRequirements($extension=null)
|
||||
{
|
||||
if(extension_loaded('imagick'))
|
||||
{
|
||||
$imagick=new Imagick();
|
||||
$imagickFormats=$imagick->queryFormats('PNG');
|
||||
}
|
||||
if(extension_loaded('gd'))
|
||||
{
|
||||
$gdInfo=gd_info();
|
||||
}
|
||||
if($extension===null)
|
||||
{
|
||||
if(isset($imagickFormats) && in_array('PNG',$imagickFormats))
|
||||
return true;
|
||||
if(isset($gdInfo) && $gdInfo['FreeType Support'])
|
||||
return true;
|
||||
}
|
||||
elseif($extension=='imagick' && isset($imagickFormats) && in_array('PNG',$imagickFormats))
|
||||
return true;
|
||||
elseif($extension=='gd' && isset($gdInfo) && $gdInfo['FreeType Support'])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
336
framework/web/widgets/captcha/CCaptchaAction.php
Normal file
336
framework/web/widgets/captcha/CCaptchaAction.php
Normal file
@@ -0,0 +1,336 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* CCaptchaAction class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CCaptchaAction renders a CAPTCHA image.
|
||||
*
|
||||
* CCaptchaAction is used together with {@link CCaptcha} and {@link CCaptchaValidator}
|
||||
* to provide the {@link http://en.wikipedia.org/wiki/Captcha CAPTCHA} feature.
|
||||
*
|
||||
* You must configure properties of CCaptchaAction to customize the appearance of
|
||||
* the generated image.
|
||||
*
|
||||
* Note, CCaptchaAction requires PHP GD2 extension.
|
||||
*
|
||||
* Using CAPTCHA involves the following steps:
|
||||
* <ol>
|
||||
* <li>Override {@link CController::actions()} and register an action of class CCaptchaAction with ID 'captcha'.</li>
|
||||
* <li>In the form model, declare an attribute to store user-entered verification code, and declare the attribute
|
||||
* to be validated by the 'captcha' validator.</li>
|
||||
* <li>In the controller view, insert a {@link CCaptcha} widget in the form.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @property string $verifyCode The verification code.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets.captcha
|
||||
* @since 1.0
|
||||
*/
|
||||
class CCaptchaAction extends CAction
|
||||
{
|
||||
/**
|
||||
* The name of the GET parameter indicating whether the CAPTCHA image should be regenerated.
|
||||
*/
|
||||
const REFRESH_GET_VAR='refresh';
|
||||
/**
|
||||
* Prefix to the session variable name used by the action.
|
||||
*/
|
||||
const SESSION_VAR_PREFIX='Yii.CCaptchaAction.';
|
||||
/**
|
||||
* @var integer how many times should the same CAPTCHA be displayed. Defaults to 3.
|
||||
* A value less than or equal to 0 means the test is unlimited (available since version 1.1.2).
|
||||
*/
|
||||
public $testLimit = 3;
|
||||
/**
|
||||
* @var integer the width of the generated CAPTCHA image. Defaults to 120.
|
||||
*/
|
||||
public $width = 120;
|
||||
/**
|
||||
* @var integer the height of the generated CAPTCHA image. Defaults to 50.
|
||||
*/
|
||||
public $height = 50;
|
||||
/**
|
||||
* @var integer padding around the text. Defaults to 2.
|
||||
*/
|
||||
public $padding = 2;
|
||||
/**
|
||||
* @var integer the background color. For example, 0x55FF00.
|
||||
* Defaults to 0xFFFFFF, meaning white color.
|
||||
*/
|
||||
public $backColor = 0xFFFFFF;
|
||||
/**
|
||||
* @var integer the font color. For example, 0x55FF00. Defaults to 0x2040A0 (blue color).
|
||||
*/
|
||||
public $foreColor = 0x2040A0;
|
||||
/**
|
||||
* @var boolean whether to use transparent background. Defaults to false.
|
||||
*/
|
||||
public $transparent = false;
|
||||
/**
|
||||
* @var integer the minimum length for randomly generated word. Defaults to 6.
|
||||
*/
|
||||
public $minLength = 6;
|
||||
/**
|
||||
* @var integer the maximum length for randomly generated word. Defaults to 7.
|
||||
*/
|
||||
public $maxLength = 7;
|
||||
/**
|
||||
* @var integer the offset between characters. Defaults to -2. You can adjust this property
|
||||
* in order to decrease or increase the readability of the captcha.
|
||||
* @since 1.1.7
|
||||
**/
|
||||
public $offset = -2;
|
||||
/**
|
||||
* @var string the TrueType font file. Defaults to SpicyRice.ttf which is provided with the Yii release.
|
||||
* Note that non-free Duality.ttf has been changed to open/free SpicyRice.ttf since 1.1.14.
|
||||
*/
|
||||
public $fontFile;
|
||||
/**
|
||||
* @var string the fixed verification code. When this is property is set,
|
||||
* {@link getVerifyCode} will always return this value.
|
||||
* This is mainly used in automated tests where we want to be able to reproduce
|
||||
* the same verification code each time we run the tests.
|
||||
* Defaults to null, meaning the verification code will be randomly generated.
|
||||
* @since 1.1.4
|
||||
*/
|
||||
public $fixedVerifyCode;
|
||||
/**
|
||||
* @var string the graphic extension that will be used to draw CAPTCHA image. Possible values
|
||||
* are 'gd', 'imagick' and null. Null value means that fallback mode will be used: ImageMagick
|
||||
* is preferred over GD. Default value is null.
|
||||
* @since 1.1.13
|
||||
*/
|
||||
public $backend;
|
||||
|
||||
/**
|
||||
* Runs the action.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
if(isset($_GET[self::REFRESH_GET_VAR])) // AJAX request for regenerating code
|
||||
{
|
||||
$code=$this->getVerifyCode(true);
|
||||
echo CJSON::encode(array(
|
||||
'hash1'=>$this->generateValidationHash($code),
|
||||
'hash2'=>$this->generateValidationHash(strtolower($code)),
|
||||
// we add a random 'v' parameter so that FireFox can refresh the image
|
||||
// when src attribute of image tag is changed
|
||||
'url'=>$this->getController()->createUrl($this->getId(),array('v' => uniqid())),
|
||||
));
|
||||
}
|
||||
else
|
||||
$this->renderImage($this->getVerifyCode());
|
||||
Yii::app()->end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a hash code that can be used for client side validation.
|
||||
* @param string $code the CAPTCHA code
|
||||
* @return string a hash code generated from the CAPTCHA code
|
||||
* @since 1.1.7
|
||||
*/
|
||||
public function generateValidationHash($code)
|
||||
{
|
||||
for($h=0,$i=strlen($code)-1;$i>=0;--$i)
|
||||
$h+=ord($code[$i]);
|
||||
return $h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the verification code.
|
||||
* @param boolean $regenerate whether the verification code should be regenerated.
|
||||
* @return string the verification code.
|
||||
*/
|
||||
public function getVerifyCode($regenerate=false)
|
||||
{
|
||||
if($this->fixedVerifyCode !== null)
|
||||
return $this->fixedVerifyCode;
|
||||
|
||||
$session = Yii::app()->session;
|
||||
$session->open();
|
||||
$name = $this->getSessionKey();
|
||||
if($session[$name] === null || $regenerate)
|
||||
{
|
||||
$session[$name] = $this->generateVerifyCode();
|
||||
$session[$name . 'count'] = 1;
|
||||
}
|
||||
return $session[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the input to see if it matches the generated code.
|
||||
* @param string $input user input
|
||||
* @param boolean $caseSensitive whether the comparison should be case-sensitive
|
||||
* @return boolean whether the input is valid
|
||||
*/
|
||||
public function validate($input,$caseSensitive)
|
||||
{
|
||||
$code = $this->getVerifyCode();
|
||||
$valid = $caseSensitive ? ($input === $code) : strcasecmp($input,$code)===0;
|
||||
$session = Yii::app()->session;
|
||||
$session->open();
|
||||
$name = $this->getSessionKey() . 'count';
|
||||
$session[$name] = $session[$name] + 1;
|
||||
if($session[$name] > $this->testLimit && $this->testLimit > 0)
|
||||
$this->getVerifyCode(true);
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new verification code.
|
||||
* @return string the generated verification code
|
||||
*/
|
||||
protected function generateVerifyCode()
|
||||
{
|
||||
if($this->minLength > $this->maxLength)
|
||||
$this->maxLength = $this->minLength;
|
||||
if($this->minLength < 3)
|
||||
$this->minLength = 3;
|
||||
if($this->maxLength > 20)
|
||||
$this->maxLength = 20;
|
||||
$length = mt_rand($this->minLength,$this->maxLength);
|
||||
|
||||
$letters = 'bcdfghjklmnpqrstvwxyz';
|
||||
$vowels = 'aeiou';
|
||||
$code = '';
|
||||
for($i = 0; $i < $length; ++$i)
|
||||
{
|
||||
if($i % 2 && mt_rand(0,10) > 2 || !($i % 2) && mt_rand(0,10) > 9)
|
||||
$code.=$vowels[mt_rand(0,4)];
|
||||
else
|
||||
$code.=$letters[mt_rand(0,20)];
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the session variable name used to store verification code.
|
||||
* @return string the session variable name
|
||||
*/
|
||||
protected function getSessionKey()
|
||||
{
|
||||
return self::SESSION_VAR_PREFIX . Yii::app()->getId() . '.' . $this->getController()->getUniqueId() . '.' . $this->getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the CAPTCHA image based on the code using library specified in the {@link $backend} property.
|
||||
* @param string $code the verification code
|
||||
*/
|
||||
protected function renderImage($code)
|
||||
{
|
||||
if($this->backend===null && CCaptcha::checkRequirements('imagick') || $this->backend==='imagick')
|
||||
$this->renderImageImagick($code);
|
||||
else if($this->backend===null && CCaptcha::checkRequirements('gd') || $this->backend==='gd')
|
||||
$this->renderImageGD($code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the CAPTCHA image based on the code using GD library.
|
||||
* @param string $code the verification code
|
||||
* @since 1.1.13
|
||||
*/
|
||||
protected function renderImageGD($code)
|
||||
{
|
||||
$image = imagecreatetruecolor($this->width,$this->height);
|
||||
|
||||
$backColor = imagecolorallocate($image,
|
||||
(int)($this->backColor % 0x1000000 / 0x10000),
|
||||
(int)($this->backColor % 0x10000 / 0x100),
|
||||
$this->backColor % 0x100);
|
||||
imagefilledrectangle($image,0,0,$this->width,$this->height,$backColor);
|
||||
imagecolordeallocate($image,$backColor);
|
||||
|
||||
if($this->transparent)
|
||||
imagecolortransparent($image,$backColor);
|
||||
|
||||
$foreColor = imagecolorallocate($image,
|
||||
(int)($this->foreColor % 0x1000000 / 0x10000),
|
||||
(int)($this->foreColor % 0x10000 / 0x100),
|
||||
$this->foreColor % 0x100);
|
||||
|
||||
if($this->fontFile === null)
|
||||
$this->fontFile = dirname(__FILE__) . '/SpicyRice.ttf';
|
||||
|
||||
$length = strlen($code);
|
||||
$box = imagettfbbox(30,0,$this->fontFile,$code);
|
||||
$w = $box[4] - $box[0] + $this->offset * ($length - 1);
|
||||
$h = $box[1] - $box[5];
|
||||
$scale = min(($this->width - $this->padding * 2) / $w,($this->height - $this->padding * 2) / $h);
|
||||
$x = 10;
|
||||
$y = round($this->height * 27 / 40);
|
||||
for($i = 0; $i < $length; ++$i)
|
||||
{
|
||||
$fontSize = (int)(rand(26,32) * $scale * 0.8);
|
||||
$angle = rand(-10,10);
|
||||
$letter = $code[$i];
|
||||
$box = imagettftext($image,$fontSize,$angle,$x,$y,$foreColor,$this->fontFile,$letter);
|
||||
$x = $box[2] + $this->offset;
|
||||
}
|
||||
|
||||
imagecolordeallocate($image,$foreColor);
|
||||
|
||||
header('Pragma: public');
|
||||
header('Expires: 0');
|
||||
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
|
||||
header('Content-Transfer-Encoding: binary');
|
||||
header("Content-Type: image/png");
|
||||
imagepng($image);
|
||||
imagedestroy($image);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the CAPTCHA image based on the code using ImageMagick library.
|
||||
* @param string $code the verification code
|
||||
* @since 1.1.13
|
||||
*/
|
||||
protected function renderImageImagick($code)
|
||||
{
|
||||
$backColor=$this->transparent ? new ImagickPixel('transparent') : new ImagickPixel(sprintf('#%06x',$this->backColor));
|
||||
$foreColor=new ImagickPixel(sprintf('#%06x',$this->foreColor));
|
||||
|
||||
$image=new Imagick();
|
||||
$image->newImage($this->width,$this->height,$backColor);
|
||||
|
||||
if($this->fontFile===null)
|
||||
$this->fontFile=dirname(__FILE__).'/SpicyRice.ttf';
|
||||
|
||||
$draw=new ImagickDraw();
|
||||
$draw->setFont($this->fontFile);
|
||||
$draw->setFontSize(30);
|
||||
$fontMetrics=$image->queryFontMetrics($draw,$code);
|
||||
|
||||
$length=strlen($code);
|
||||
$w=(int)($fontMetrics['textWidth'])-8+$this->offset*($length-1);
|
||||
$h=(int)($fontMetrics['textHeight'])-8;
|
||||
$scale=min(($this->width-$this->padding*2)/$w,($this->height-$this->padding*2)/$h);
|
||||
$x=10;
|
||||
$y=round($this->height*27/40);
|
||||
for($i=0; $i<$length; ++$i)
|
||||
{
|
||||
$draw=new ImagickDraw();
|
||||
$draw->setFont($this->fontFile);
|
||||
$draw->setFontSize((int)(rand(26,32)*$scale*0.8));
|
||||
$draw->setFillColor($foreColor);
|
||||
$image->annotateImage($draw,$x,$y,rand(-10,10),$code[$i]);
|
||||
$fontMetrics=$image->queryFontMetrics($draw,$code[$i]);
|
||||
$x+=(int)($fontMetrics['textWidth'])+$this->offset;
|
||||
}
|
||||
|
||||
header('Pragma: public');
|
||||
header('Expires: 0');
|
||||
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
|
||||
header('Content-Transfer-Encoding: binary');
|
||||
header("Content-Type: image/png");
|
||||
$image->setImageFormat('png');
|
||||
echo $image;
|
||||
}
|
||||
}
|
||||
11
framework/web/widgets/captcha/SpicyRice.md
Normal file
11
framework/web/widgets/captcha/SpicyRice.md
Normal file
@@ -0,0 +1,11 @@
|
||||
## Spicy Rice font
|
||||
|
||||
* **Author:** Brian J. Bonislawsky, Astigmatic (AOETI, Astigmatic One Eye Typographic Institute)
|
||||
* **License:** SIL Open Font License (OFL), version 1.1, [notes and FAQ](http://scripts.sil.org/OFL)
|
||||
|
||||
## Links
|
||||
|
||||
* [Astigmatic](http://www.astigmatic.com/)
|
||||
* [Google WebFonts](http://www.google.com/webfonts/specimen/Spicy+Rice)
|
||||
* [fontsquirrel.com](http://www.fontsquirrel.com/fonts/spicy-rice)
|
||||
* [fontspace.com](http://www.fontspace.com/astigmatic-one-eye-typographic-institute/spicy-rice)
|
||||
BIN
framework/web/widgets/captcha/SpicyRice.ttf
Normal file
BIN
framework/web/widgets/captcha/SpicyRice.ttf
Normal file
Binary file not shown.
134
framework/web/widgets/pagers/CBasePager.php
Normal file
134
framework/web/widgets/pagers/CBasePager.php
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
/**
|
||||
* CBasePager class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CBasePager is the base class for all pagers.
|
||||
*
|
||||
* It provides the calculation of page count and maintains the current page.
|
||||
*
|
||||
* @property CPagination $pages The pagination information.
|
||||
* @property integer $pageSize Number of items in each page.
|
||||
* @property integer $itemCount Total number of items.
|
||||
* @property integer $pageCount Number of pages.
|
||||
* @property integer $currentPage The zero-based index of the current page. Defaults to 0.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets.pagers
|
||||
* @since 1.0
|
||||
*/
|
||||
abstract class CBasePager extends CWidget
|
||||
{
|
||||
private $_pages;
|
||||
|
||||
/**
|
||||
* Returns the pagination information used by this pager.
|
||||
* @return CPagination the pagination information
|
||||
*/
|
||||
public function getPages()
|
||||
{
|
||||
if($this->_pages===null)
|
||||
$this->_pages=$this->createPages();
|
||||
return $this->_pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pagination information used by this pager.
|
||||
* @param CPagination $pages the pagination information
|
||||
*/
|
||||
public function setPages($pages)
|
||||
{
|
||||
$this->_pages=$pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the default pagination.
|
||||
* This is called by {@link getPages} when the pagination is not set before.
|
||||
* @return CPagination the default pagination instance.
|
||||
*/
|
||||
protected function createPages()
|
||||
{
|
||||
return new CPagination;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer number of items in each page.
|
||||
* @see CPagination::getPageSize
|
||||
*/
|
||||
public function getPageSize()
|
||||
{
|
||||
return $this->getPages()->getPageSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $value number of items in each page
|
||||
* @see CPagination::setPageSize
|
||||
*/
|
||||
public function setPageSize($value)
|
||||
{
|
||||
$this->getPages()->setPageSize($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer total number of items.
|
||||
* @see CPagination::getItemCount
|
||||
*/
|
||||
public function getItemCount()
|
||||
{
|
||||
return $this->getPages()->getItemCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $value total number of items.
|
||||
* @see CPagination::setItemCount
|
||||
*/
|
||||
public function setItemCount($value)
|
||||
{
|
||||
$this->getPages()->setItemCount($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer number of pages
|
||||
* @see CPagination::getPageCount
|
||||
*/
|
||||
public function getPageCount()
|
||||
{
|
||||
return $this->getPages()->getPageCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean $recalculate whether to recalculate the current page based on the page size and item count.
|
||||
* @return integer the zero-based index of the current page. Defaults to 0.
|
||||
* @see CPagination::getCurrentPage
|
||||
*/
|
||||
public function getCurrentPage($recalculate=true)
|
||||
{
|
||||
return $this->getPages()->getCurrentPage($recalculate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $value the zero-based index of the current page.
|
||||
* @see CPagination::setCurrentPage
|
||||
*/
|
||||
public function setCurrentPage($value)
|
||||
{
|
||||
$this->getPages()->setCurrentPage($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the URL suitable for pagination.
|
||||
* @param integer $page the page that the URL should point to.
|
||||
* @return string the created URL
|
||||
* @see CPagination::createPageUrl
|
||||
*/
|
||||
protected function createPageUrl($page)
|
||||
{
|
||||
return $this->getPages()->createPageUrl($this->getController(),$page);
|
||||
}
|
||||
}
|
||||
229
framework/web/widgets/pagers/CLinkPager.php
Normal file
229
framework/web/widgets/pagers/CLinkPager.php
Normal file
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
/**
|
||||
* CLinkPager class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CLinkPager displays a list of hyperlinks that lead to different pages of target.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets.pagers
|
||||
* @since 1.0
|
||||
*/
|
||||
class CLinkPager extends CBasePager
|
||||
{
|
||||
const CSS_FIRST_PAGE='first';
|
||||
const CSS_LAST_PAGE='last';
|
||||
const CSS_PREVIOUS_PAGE='previous';
|
||||
const CSS_NEXT_PAGE='next';
|
||||
const CSS_INTERNAL_PAGE='page';
|
||||
const CSS_HIDDEN_PAGE='hidden';
|
||||
const CSS_SELECTED_PAGE='selected';
|
||||
|
||||
/**
|
||||
* @var string the CSS class for the first page button. Defaults to 'first'.
|
||||
* @since 1.1.11
|
||||
*/
|
||||
public $firstPageCssClass=self::CSS_FIRST_PAGE;
|
||||
/**
|
||||
* @var string the CSS class for the last page button. Defaults to 'last'.
|
||||
* @since 1.1.11
|
||||
*/
|
||||
public $lastPageCssClass=self::CSS_LAST_PAGE;
|
||||
/**
|
||||
* @var string the CSS class for the previous page button. Defaults to 'previous'.
|
||||
* @since 1.1.11
|
||||
*/
|
||||
public $previousPageCssClass=self::CSS_PREVIOUS_PAGE;
|
||||
/**
|
||||
* @var string the CSS class for the next page button. Defaults to 'next'.
|
||||
* @since 1.1.11
|
||||
*/
|
||||
public $nextPageCssClass=self::CSS_NEXT_PAGE;
|
||||
/**
|
||||
* @var string the CSS class for the internal page buttons. Defaults to 'page'.
|
||||
* @since 1.1.11
|
||||
*/
|
||||
public $internalPageCssClass=self::CSS_INTERNAL_PAGE;
|
||||
/**
|
||||
* @var string the CSS class for the hidden page buttons. Defaults to 'hidden'.
|
||||
* @since 1.1.11
|
||||
*/
|
||||
public $hiddenPageCssClass=self::CSS_HIDDEN_PAGE;
|
||||
/**
|
||||
* @var string the CSS class for the selected page buttons. Defaults to 'selected'.
|
||||
* @since 1.1.11
|
||||
*/
|
||||
public $selectedPageCssClass=self::CSS_SELECTED_PAGE;
|
||||
/**
|
||||
* @var integer maximum number of page buttons that can be displayed. Defaults to 10.
|
||||
*/
|
||||
public $maxButtonCount=10;
|
||||
/**
|
||||
* @var string the text label for the next page button. Defaults to 'Next >'.
|
||||
*/
|
||||
public $nextPageLabel;
|
||||
/**
|
||||
* @var string the text label for the previous page button. Defaults to '< Previous'.
|
||||
*/
|
||||
public $prevPageLabel;
|
||||
/**
|
||||
* @var string the text label for the first page button. Defaults to '<< First'.
|
||||
*/
|
||||
public $firstPageLabel;
|
||||
/**
|
||||
* @var string the text label for the last page button. Defaults to 'Last >>'.
|
||||
*/
|
||||
public $lastPageLabel;
|
||||
/**
|
||||
* @var string the text shown before page buttons. Defaults to 'Go to page: '.
|
||||
*/
|
||||
public $header;
|
||||
/**
|
||||
* @var string the text shown after page buttons.
|
||||
*/
|
||||
public $footer='';
|
||||
/**
|
||||
* @var mixed the CSS file used for the widget. Defaults to null, meaning
|
||||
* using the default CSS file included together with the widget.
|
||||
* If false, no CSS file will be used. Otherwise, the specified CSS file
|
||||
* will be included when using this widget.
|
||||
*/
|
||||
public $cssFile;
|
||||
/**
|
||||
* @var array HTML attributes for the pager container tag.
|
||||
*/
|
||||
public $htmlOptions=array();
|
||||
|
||||
/**
|
||||
* Initializes the pager by setting some default property values.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if($this->nextPageLabel===null)
|
||||
$this->nextPageLabel=Yii::t('yii','Next >');
|
||||
if($this->prevPageLabel===null)
|
||||
$this->prevPageLabel=Yii::t('yii','< Previous');
|
||||
if($this->firstPageLabel===null)
|
||||
$this->firstPageLabel=Yii::t('yii','<< First');
|
||||
if($this->lastPageLabel===null)
|
||||
$this->lastPageLabel=Yii::t('yii','Last >>');
|
||||
if($this->header===null)
|
||||
$this->header=Yii::t('yii','Go to page: ');
|
||||
|
||||
if(!isset($this->htmlOptions['id']))
|
||||
$this->htmlOptions['id']=$this->getId();
|
||||
if(!isset($this->htmlOptions['class']))
|
||||
$this->htmlOptions['class']='yiiPager';
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the widget.
|
||||
* This overrides the parent implementation by displaying the generated page buttons.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->registerClientScript();
|
||||
$buttons=$this->createPageButtons();
|
||||
if(empty($buttons))
|
||||
return;
|
||||
echo $this->header;
|
||||
echo CHtml::tag('ul',$this->htmlOptions,implode("\n",$buttons));
|
||||
echo $this->footer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the page buttons.
|
||||
* @return array a list of page buttons (in HTML code).
|
||||
*/
|
||||
protected function createPageButtons()
|
||||
{
|
||||
if(($pageCount=$this->getPageCount())<=1)
|
||||
return array();
|
||||
|
||||
list($beginPage,$endPage)=$this->getPageRange();
|
||||
$currentPage=$this->getCurrentPage(false); // currentPage is calculated in getPageRange()
|
||||
$buttons=array();
|
||||
|
||||
// first page
|
||||
$buttons[]=$this->createPageButton($this->firstPageLabel,0,$this->firstPageCssClass,$currentPage<=0,false);
|
||||
|
||||
// prev page
|
||||
if(($page=$currentPage-1)<0)
|
||||
$page=0;
|
||||
$buttons[]=$this->createPageButton($this->prevPageLabel,$page,$this->previousPageCssClass,$currentPage<=0,false);
|
||||
|
||||
// internal pages
|
||||
for($i=$beginPage;$i<=$endPage;++$i)
|
||||
$buttons[]=$this->createPageButton($i+1,$i,$this->internalPageCssClass,false,$i==$currentPage);
|
||||
|
||||
// next page
|
||||
if(($page=$currentPage+1)>=$pageCount-1)
|
||||
$page=$pageCount-1;
|
||||
$buttons[]=$this->createPageButton($this->nextPageLabel,$page,$this->nextPageCssClass,$currentPage>=$pageCount-1,false);
|
||||
|
||||
// last page
|
||||
$buttons[]=$this->createPageButton($this->lastPageLabel,$pageCount-1,$this->lastPageCssClass,$currentPage>=$pageCount-1,false);
|
||||
|
||||
return $buttons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a page button.
|
||||
* You may override this method to customize the page buttons.
|
||||
* @param string $label the text label for the button
|
||||
* @param integer $page the page number
|
||||
* @param string $class the CSS class for the page button.
|
||||
* @param boolean $hidden whether this page button is visible
|
||||
* @param boolean $selected whether this page button is selected
|
||||
* @return string the generated button
|
||||
*/
|
||||
protected function createPageButton($label,$page,$class,$hidden,$selected)
|
||||
{
|
||||
if($hidden || $selected)
|
||||
$class.=' '.($hidden ? $this->hiddenPageCssClass : $this->selectedPageCssClass);
|
||||
return '<li class="'.$class.'">'.CHtml::link($label,$this->createPageUrl($page)).'</li>';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array the begin and end pages that need to be displayed.
|
||||
*/
|
||||
protected function getPageRange()
|
||||
{
|
||||
$currentPage=$this->getCurrentPage();
|
||||
$pageCount=$this->getPageCount();
|
||||
|
||||
$beginPage=max(0, $currentPage-(int)($this->maxButtonCount/2));
|
||||
if(($endPage=$beginPage+$this->maxButtonCount-1)>=$pageCount)
|
||||
{
|
||||
$endPage=$pageCount-1;
|
||||
$beginPage=max(0,$endPage-$this->maxButtonCount+1);
|
||||
}
|
||||
return array($beginPage,$endPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the needed client scripts (mainly CSS file).
|
||||
*/
|
||||
public function registerClientScript()
|
||||
{
|
||||
if($this->cssFile!==false)
|
||||
self::registerCssFile($this->cssFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the needed CSS file.
|
||||
* @param string $url the CSS URL. If null, a default CSS URL will be used.
|
||||
*/
|
||||
public static function registerCssFile($url=null)
|
||||
{
|
||||
if($url===null)
|
||||
$url=CHtml::asset(Yii::getPathOfAlias('system.web.widgets.pagers.pager').'.css');
|
||||
Yii::app()->getClientScript()->registerCssFile($url);
|
||||
}
|
||||
}
|
||||
88
framework/web/widgets/pagers/CListPager.php
Normal file
88
framework/web/widgets/pagers/CListPager.php
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
/**
|
||||
* CListPager class file.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* CListPager displays a dropdown list that contains options leading to different pages of target.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.web.widgets.pagers
|
||||
* @since 1.0
|
||||
*/
|
||||
class CListPager extends CBasePager
|
||||
{
|
||||
/**
|
||||
* @var string the text shown before page buttons. Defaults to 'Go to page: '.
|
||||
*/
|
||||
public $header;
|
||||
/**
|
||||
* @var string the text shown after page buttons.
|
||||
*/
|
||||
public $footer;
|
||||
/**
|
||||
* @var string the text displayed as a prompt option in the dropdown list. Defaults to null, meaning no prompt.
|
||||
*/
|
||||
public $promptText;
|
||||
/**
|
||||
* @var string the format string used to generate page selection text.
|
||||
* The sprintf function will be used to perform the formatting.
|
||||
*/
|
||||
public $pageTextFormat;
|
||||
/**
|
||||
* @var array HTML attributes for the enclosing 'div' tag.
|
||||
*/
|
||||
public $htmlOptions=array();
|
||||
|
||||
/**
|
||||
* Initializes the pager by setting some default property values.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if($this->header===null)
|
||||
$this->header=Yii::t('yii','Go to page: ');
|
||||
if(!isset($this->htmlOptions['id']))
|
||||
$this->htmlOptions['id']=$this->getId();
|
||||
if($this->promptText!==null)
|
||||
$this->htmlOptions['prompt']=$this->promptText;
|
||||
if(!isset($this->htmlOptions['onchange']))
|
||||
$this->htmlOptions['onchange']="if(this.value!='') {window.location=this.value;};";
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the widget.
|
||||
* This overrides the parent implementation by displaying the generated page buttons.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
if(($pageCount=$this->getPageCount())<=1)
|
||||
return;
|
||||
$pages=array();
|
||||
for($i=0;$i<$pageCount;++$i)
|
||||
$pages[$this->createPageUrl($i)]=$this->generatePageText($i);
|
||||
$selection=$this->createPageUrl($this->getCurrentPage());
|
||||
echo $this->header;
|
||||
echo CHtml::dropDownList($this->getId(),$selection,$pages,$this->htmlOptions);
|
||||
echo $this->footer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the list option for the specified page number.
|
||||
* You may override this method to customize the option display.
|
||||
* @param integer $page zero-based page number
|
||||
* @return string the list option for the page number
|
||||
*/
|
||||
protected function generatePageText($page)
|
||||
{
|
||||
if($this->pageTextFormat!==null)
|
||||
return sprintf($this->pageTextFormat,$page+1);
|
||||
else
|
||||
return $page+1;
|
||||
}
|
||||
}
|
||||
66
framework/web/widgets/pagers/pager.css
Normal file
66
framework/web/widgets/pagers/pager.css
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* CSS styles for CLinkPager.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2010 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
* @since 1.0
|
||||
*/
|
||||
|
||||
ul.yiiPager
|
||||
{
|
||||
font-size:11px;
|
||||
border:0;
|
||||
margin:0;
|
||||
padding:0;
|
||||
line-height:100%;
|
||||
display:inline;
|
||||
}
|
||||
|
||||
ul.yiiPager li
|
||||
{
|
||||
display:inline;
|
||||
}
|
||||
|
||||
ul.yiiPager a:link,
|
||||
ul.yiiPager a:visited
|
||||
{
|
||||
border:solid 1px #9aafe5;
|
||||
font-weight:bold;
|
||||
color:#0e509e;
|
||||
padding:1px 6px;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
ul.yiiPager .page a
|
||||
{
|
||||
font-weight:normal;
|
||||
}
|
||||
|
||||
ul.yiiPager a:hover
|
||||
{
|
||||
border:solid 1px #0e509e;
|
||||
}
|
||||
|
||||
ul.yiiPager .selected a
|
||||
{
|
||||
background:#2e6ab1;
|
||||
color:#FFFFFF;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
ul.yiiPager .hidden a
|
||||
{
|
||||
border:solid 1px #DEDEDE;
|
||||
color:#888888;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide first and last buttons by default.
|
||||
*/
|
||||
ul.yiiPager .first,
|
||||
ul.yiiPager .last
|
||||
{
|
||||
display:none;
|
||||
}
|
||||
99
framework/web/widgets/views/flexWidget.php
Normal file
99
framework/web/widgets/views/flexWidget.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
/**
|
||||
* The view file for CFlexWidget.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008-2013 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
* @package system.web.widgets.views
|
||||
* @since 1.0
|
||||
*/
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
/*<![CDATA[*/
|
||||
// Version check for the Flash Player that has the ability to start Player Product Install (6.0r65)
|
||||
var hasProductInstall = DetectFlashVer(6, 0, 65);
|
||||
|
||||
// Version check based upon the values defined in globals
|
||||
var hasRequestedVersion = DetectFlashVer(9, 0, 0);
|
||||
|
||||
// Check to see if a player with Flash Product Install is available and the version does not meet the requirements for playback
|
||||
if ( hasProductInstall && !hasRequestedVersion ) {
|
||||
// MMdoctitle is the stored document.title value used by the installation process to close the window that started the process
|
||||
// This is necessary in order to close browser windows that are still utilizing the older version of the player after installation has completed
|
||||
// DO NOT MODIFY THE FOLLOWING FOUR LINES
|
||||
// Location visited after installation is complete if installation is required
|
||||
var MMPlayerType = (isIE == true) ? "ActiveX" : "PlugIn";
|
||||
var MMredirectURL = window.location;
|
||||
document.title = document.title.slice(0, 47) + " - Flash Player Installation";
|
||||
var MMdoctitle = document.title;
|
||||
|
||||
AC_FL_RunContent(
|
||||
"src", "<?php echo $this->baseUrl ?>/playerProductInstall",
|
||||
"FlashVars", "MMredirectURL="+MMredirectURL+'&MMplayerType='+MMPlayerType+'&MMdoctitle='+MMdoctitle+"",
|
||||
"width", "<?php echo $this->width; ?>",
|
||||
"height", "<?php echo $this->height; ?>",
|
||||
"align", "<?php echo $this->align; ?>",
|
||||
"id", "<?php echo $this->name; ?>",
|
||||
"quality", "<?php echo $this->quality; ?>",
|
||||
"bgcolor", "<?php echo $this->bgColor; ?>",
|
||||
"name", "<?php echo $this->name; ?>",
|
||||
"allowScriptAccess","<?php echo $this->allowScriptAccess ?>",
|
||||
"allowFullScreen","<?php echo $this->allowFullScreen ?>",
|
||||
"type", "application/x-shockwave-flash",
|
||||
"pluginspage", "http://www.adobe.com/go/getflashplayer"
|
||||
);
|
||||
} else if (hasRequestedVersion) {
|
||||
// if we've detected an acceptable version
|
||||
// embed the Flash Content SWF when all tests are passed
|
||||
AC_FL_RunContent(
|
||||
"src", "<?php echo $this->baseUrl ?>/<?php echo $this->name ?>",
|
||||
"width", "<?php echo $this->width ?>",
|
||||
"height", "<?php echo $this->height ?>",
|
||||
"align", "<?php echo $this->align ?>",
|
||||
"id", "<?php echo $this->name ?>",
|
||||
"quality", "<?php echo $this->quality ?>",
|
||||
"bgcolor", "<?php echo $this->bgColor ?>",
|
||||
"name", "<?php echo $this->name ?>",
|
||||
"flashvars","<?php echo $this->flashVarsAsString; ?>",
|
||||
"allowScriptAccess","<?php echo $this->allowScriptAccess ?>",
|
||||
"allowFullScreen","<?php echo $this->allowFullScreen ?>",
|
||||
"type", "application/x-shockwave-flash",
|
||||
"pluginspage", "http://www.adobe.com/go/getflashplayer"
|
||||
);
|
||||
} else { // flash is too old or we can't detect the plugin
|
||||
var alternateContent = '<?php echo CJavaScript::quote($this->altHtmlContent); ?>';
|
||||
document.write(alternateContent); // insert non-flash content
|
||||
}
|
||||
/*]]>*/
|
||||
</script>
|
||||
<noscript>
|
||||
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
|
||||
id="<?php echo $this->name ?>"
|
||||
width="<?php echo $this->width ?>"
|
||||
height="<?php echo $this->height ?>"
|
||||
codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
|
||||
<param name="movie" value="<?php echo $this->baseUrl ?>/<?php echo $this->name ?>.swf" />
|
||||
<param name="quality" value="<?php echo $this->quality ?>" />
|
||||
<param name="bgcolor" value="<?php echo $this->bgColor ?>" />
|
||||
<param name="flashVars" value="<?php echo $this->flashVarsAsString ?>" />
|
||||
<param name="allowScriptAccess" value="<?php echo $this->allowScriptAccess ?>" />
|
||||
<param name="allowFullScreen" value="<?php echo $this->allowFullScreen ?>" />
|
||||
<embed src="<?php echo $this->baseUrl ?>/<?php echo $this->name ?>.swf"
|
||||
quality="<?php echo $this->quality ?>"
|
||||
bgcolor="<?php echo $this->bgColor ?>"
|
||||
width="<?php echo $this->width ?>"
|
||||
height="<?php echo $this->height ?>"
|
||||
name="<?php echo $this->name ?>"
|
||||
align="<?php echo $this->align ?>"
|
||||
play="true"
|
||||
loop="false"
|
||||
quality="<?php echo $this->quality ?>"
|
||||
allowScriptAccess="<?php echo $this->allowScriptAccess ?>"
|
||||
allowFullScreen="<?php echo $this->allowFullScreen ?>"
|
||||
type="application/x-shockwave-flash"
|
||||
pluginspage="http://www.adobe.com/go/getflashplayer">
|
||||
</embed>
|
||||
</object>
|
||||
</noscript>
|
||||
Reference in New Issue
Block a user