Added new (clean) yii boilerplate
134
framework/gii/CCodeFile.php
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
/**
|
||||
* CCodeFile 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/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CCodeFile represents a code file being generated.
|
||||
*
|
||||
* @property string $relativePath The code file path relative to the application base path.
|
||||
* @property string $type The code file extension (e.g. php, txt).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.gii
|
||||
* @since 1.1.2
|
||||
*/
|
||||
class CCodeFile extends CComponent
|
||||
{
|
||||
const OP_NEW='new';
|
||||
const OP_OVERWRITE='overwrite';
|
||||
const OP_SKIP='skip';
|
||||
|
||||
/**
|
||||
* @var string the file path that the new code should be saved to.
|
||||
*/
|
||||
public $path;
|
||||
/**
|
||||
* @var mixed the newly generated code. If this is null, it means {@link path}
|
||||
* should be treated as a directory.
|
||||
*/
|
||||
public $content;
|
||||
/**
|
||||
* @var string the operation to be performed
|
||||
*/
|
||||
public $operation;
|
||||
/**
|
||||
* @var string the error occurred when saving the code into a file
|
||||
*/
|
||||
public $error;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param string $path the file path that the new code should be saved to.
|
||||
* @param string $content the newly generated code
|
||||
*/
|
||||
public function __construct($path,$content)
|
||||
{
|
||||
$this->path=strtr($path,array('/'=>DIRECTORY_SEPARATOR,'\\'=>DIRECTORY_SEPARATOR));
|
||||
$this->content=$content;
|
||||
if(is_file($path))
|
||||
$this->operation=file_get_contents($path)===$content ? self::OP_SKIP : self::OP_OVERWRITE;
|
||||
elseif($content===null) // is dir
|
||||
$this->operation=is_dir($path) ? self::OP_SKIP : self::OP_NEW;
|
||||
else
|
||||
$this->operation=self::OP_NEW;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the code into the file {@link path}.
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$module=Yii::app()->controller->module;
|
||||
if($this->content===null) // a directory
|
||||
{
|
||||
if(!is_dir($this->path))
|
||||
{
|
||||
$oldmask=@umask(0);
|
||||
$result=@mkdir($this->path,$module->newDirMode,true);
|
||||
@umask($oldmask);
|
||||
if(!$result)
|
||||
{
|
||||
$this->error="Unable to create the directory '{$this->path}'.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if($this->operation===self::OP_NEW)
|
||||
{
|
||||
$dir=dirname($this->path);
|
||||
if(!is_dir($dir))
|
||||
{
|
||||
$oldmask=@umask(0);
|
||||
$result=@mkdir($dir,$module->newDirMode,true);
|
||||
@umask($oldmask);
|
||||
if(!$result)
|
||||
{
|
||||
$this->error="Unable to create the directory '$dir'.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(@file_put_contents($this->path,$this->content)===false)
|
||||
{
|
||||
$this->error="Unable to write the file '{$this->path}'.";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oldmask=@umask(0);
|
||||
@chmod($this->path,$module->newFileMode);
|
||||
@umask($oldmask);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the code file path relative to the application base path.
|
||||
*/
|
||||
public function getRelativePath()
|
||||
{
|
||||
if(strpos($this->path,Yii::app()->basePath)===0)
|
||||
return substr($this->path,strlen(Yii::app()->basePath)+1);
|
||||
else
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the code file extension (e.g. php, txt)
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
if(($pos=strrpos($this->path,'.'))!==false)
|
||||
return substr($this->path,$pos+1);
|
||||
else
|
||||
return 'unknown';
|
||||
}
|
||||
}
|
||||
59
framework/gii/CCodeForm.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
/**
|
||||
* CCodeForm 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/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CCodeForm represents the form for collecting code generation parameters.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.gii
|
||||
* @since 1.1.2
|
||||
*/
|
||||
class CCodeForm extends CActiveForm
|
||||
{
|
||||
/**
|
||||
* @var CCodeModel the code model associated with the form
|
||||
*/
|
||||
public $model;
|
||||
|
||||
/**
|
||||
* Initializes the widget.
|
||||
* This renders the form open tag.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
echo <<<EOD
|
||||
<div class="form gii">
|
||||
<p class="note">
|
||||
Fields with <span class="required">*</span> are required.
|
||||
Click on the <span class="sticky">highlighted fields</span> to edit them.
|
||||
</p>
|
||||
EOD;
|
||||
parent::init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the widget.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$templates=array();
|
||||
foreach($this->model->getTemplates() as $i=>$template)
|
||||
$templates[$i]=basename($template).' ('.$template.')';
|
||||
|
||||
$this->renderFile(Yii::getPathOfAlias('gii.views.common.generator').'.php',array(
|
||||
'model'=>$this->model,
|
||||
'templates'=>$templates,
|
||||
));
|
||||
|
||||
parent::run();
|
||||
|
||||
echo "</div>";
|
||||
}
|
||||
}
|
||||
167
framework/gii/CCodeGenerator.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
/**
|
||||
* CCodeGenerator 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/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CCodeGenerator is the base class for code generator classes.
|
||||
*
|
||||
* CCodeGenerator is a controller that predefines several actions for code generation purpose.
|
||||
* Derived classes mainly need to configure the {@link codeModel} property
|
||||
* override the {@link getSuccessMessage} method. The former specifies which
|
||||
* code model (extending {@link CCodeModel}) that this generator should use,
|
||||
* while the latter should return a success message to be displayed when
|
||||
* code files are successfully generated.
|
||||
*
|
||||
* @property string $pageTitle The page title.
|
||||
* @property string $viewPath The view path of the generator.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.gii
|
||||
* @since 1.1.2
|
||||
*/
|
||||
class CCodeGenerator extends CController
|
||||
{
|
||||
/**
|
||||
* @var string the layout to be used by the generator. Defaults to 'generator'.
|
||||
*/
|
||||
public $layout='generator';
|
||||
/**
|
||||
* @var array a list of available code templates (name=>path)
|
||||
*/
|
||||
public $templates=array();
|
||||
/**
|
||||
* @var string the code model class. This can be either a class name (if it can be autoloaded)
|
||||
* or a path alias referring to the class file.
|
||||
* Child classes must configure this property with a concrete value.
|
||||
*/
|
||||
public $codeModel;
|
||||
|
||||
private $_viewPath;
|
||||
|
||||
/**
|
||||
* @return string the page title
|
||||
*/
|
||||
public function getPageTitle()
|
||||
{
|
||||
return 'Gii - '.ucfirst($this->id).' Generator';
|
||||
}
|
||||
|
||||
/**
|
||||
* The code generation action.
|
||||
* This is the action that displays the code generation interface.
|
||||
* Child classes mainly need to provide the 'index' view for collecting user parameters
|
||||
* for code generation.
|
||||
*/
|
||||
public function actionIndex()
|
||||
{
|
||||
$model=$this->prepare();
|
||||
if($model->files!=array() && isset($_POST['generate'], $_POST['answers']))
|
||||
{
|
||||
$model->answers=$_POST['answers'];
|
||||
$model->status=$model->save() ? CCodeModel::STATUS_SUCCESS : CCodeModel::STATUS_ERROR;
|
||||
}
|
||||
|
||||
$this->render('index',array(
|
||||
'model'=>$model,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* The code preview action.
|
||||
* This action shows up the specified generated code.
|
||||
* @throws CHttpException if unable to find code generated.
|
||||
*/
|
||||
public function actionCode()
|
||||
{
|
||||
$model=$this->prepare();
|
||||
if(isset($_GET['id']) && isset($model->files[$_GET['id']]))
|
||||
{
|
||||
$this->renderPartial('/common/code', array(
|
||||
'file'=>$model->files[$_GET['id']],
|
||||
));
|
||||
}
|
||||
else
|
||||
throw new CHttpException(404,'Unable to find the code you requested.');
|
||||
}
|
||||
|
||||
/**
|
||||
* The code diff action.
|
||||
* This action shows up the difference between the newly generated code and the corresponding existing code.
|
||||
* @throws CHttpException if unable to find code generated.
|
||||
*/
|
||||
public function actionDiff()
|
||||
{
|
||||
Yii::import('gii.components.TextDiff');
|
||||
|
||||
$model=$this->prepare();
|
||||
if(isset($_GET['id']) && isset($model->files[$_GET['id']]))
|
||||
{
|
||||
$file=$model->files[$_GET['id']];
|
||||
if(!in_array($file->type,array('php', 'txt','js','css')))
|
||||
$diff=false;
|
||||
elseif($file->operation===CCodeFile::OP_OVERWRITE)
|
||||
$diff=TextDiff::compare(file_get_contents($file->path), $file->content);
|
||||
else
|
||||
$diff='';
|
||||
|
||||
$this->renderPartial('/common/diff',array(
|
||||
'file'=>$file,
|
||||
'diff'=>$diff,
|
||||
));
|
||||
}
|
||||
else
|
||||
throw new CHttpException(404,'Unable to find the code you requested.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the view path of the generator.
|
||||
* The "views" directory under the directory containing the generator class file will be returned.
|
||||
* @return string the view path of the generator
|
||||
*/
|
||||
public function getViewPath()
|
||||
{
|
||||
if($this->_viewPath===null)
|
||||
{
|
||||
$class=new ReflectionClass(get_class($this));
|
||||
$this->_viewPath=dirname($class->getFileName()).DIRECTORY_SEPARATOR.'views';
|
||||
}
|
||||
return $this->_viewPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value the view path of the generator.
|
||||
*/
|
||||
public function setViewPath($value)
|
||||
{
|
||||
$this->_viewPath=$value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the code model.
|
||||
*/
|
||||
protected function prepare()
|
||||
{
|
||||
if($this->codeModel===null)
|
||||
throw new CException(get_class($this).'.codeModel property must be specified.');
|
||||
$modelClass=Yii::import($this->codeModel,true);
|
||||
$model=new $modelClass;
|
||||
$model->loadStickyAttributes();
|
||||
if(isset($_POST[$modelClass]))
|
||||
{
|
||||
$model->attributes=$_POST[$modelClass];
|
||||
$model->status=CCodeModel::STATUS_PREVIEW;
|
||||
if($model->validate())
|
||||
{
|
||||
$model->saveStickyAttributes();
|
||||
$model->prepare();
|
||||
}
|
||||
}
|
||||
return $model;
|
||||
}
|
||||
}
|
||||
484
framework/gii/CCodeModel.php
Normal file
@@ -0,0 +1,484 @@
|
||||
<?php
|
||||
/**
|
||||
* CCodeModel 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/
|
||||
*/
|
||||
|
||||
/**
|
||||
* CCodeModel is the base class for model classes that are used to generate code.
|
||||
*
|
||||
* Each code generator should have at least one code model class that extends from this class.
|
||||
* The purpose of a code model is to represent user-supplied parameters and use them to
|
||||
* generate customized code.
|
||||
*
|
||||
* Derived classes should implement the {@link prepare} method whose main task is to
|
||||
* fill up the {@link files} property based on the user parameters.
|
||||
*
|
||||
* The {@link files} property should be filled with a set of {@link CCodeFile} instances,
|
||||
* each representing a single code file to be generated.
|
||||
*
|
||||
* CCodeModel implements the feature of "sticky attributes". A sticky attribute is an attribute
|
||||
* that can remember its last valid value, even if the user closes his browser window
|
||||
* and reopen it. To declare an attribute is sticky, simply list it in a validation rule with
|
||||
* the validator name being "sticky".
|
||||
*
|
||||
* @property array $templates A list of available code templates (name=>directory).
|
||||
* @property string $templatePath The directory that contains the template files.
|
||||
* @property string $stickyFile The file path that stores the sticky attribute values.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.gii
|
||||
* @since 1.1.2
|
||||
*/
|
||||
abstract class CCodeModel extends CFormModel
|
||||
{
|
||||
const STATUS_NEW=1;
|
||||
const STATUS_PREVIEW=2;
|
||||
const STATUS_SUCCESS=3;
|
||||
const STATUS_ERROR=4;
|
||||
|
||||
static $keywords=array(
|
||||
'__class__',
|
||||
'__dir__',
|
||||
'__file__',
|
||||
'__function__',
|
||||
'__line__',
|
||||
'__method__',
|
||||
'__namespace__',
|
||||
'abstract',
|
||||
'and',
|
||||
'array',
|
||||
'as',
|
||||
'break',
|
||||
'case',
|
||||
'catch',
|
||||
'cfunction',
|
||||
'class',
|
||||
'clone',
|
||||
'const',
|
||||
'continue',
|
||||
'declare',
|
||||
'default',
|
||||
'die',
|
||||
'do',
|
||||
'echo',
|
||||
'else',
|
||||
'elseif',
|
||||
'empty',
|
||||
'enddeclare',
|
||||
'endfor',
|
||||
'endforeach',
|
||||
'endif',
|
||||
'endswitch',
|
||||
'endwhile',
|
||||
'eval',
|
||||
'exception',
|
||||
'exit',
|
||||
'extends',
|
||||
'final',
|
||||
'final',
|
||||
'for',
|
||||
'foreach',
|
||||
'function',
|
||||
'global',
|
||||
'goto',
|
||||
'if',
|
||||
'implements',
|
||||
'include',
|
||||
'include_once',
|
||||
'instanceof',
|
||||
'interface',
|
||||
'isset',
|
||||
'list',
|
||||
'namespace',
|
||||
'new',
|
||||
'old_function',
|
||||
'or',
|
||||
'parent',
|
||||
'php_user_filter',
|
||||
'print',
|
||||
'private',
|
||||
'protected',
|
||||
'public',
|
||||
'require',
|
||||
'require_once',
|
||||
'return',
|
||||
'static',
|
||||
'switch',
|
||||
'this',
|
||||
'throw',
|
||||
'try',
|
||||
'unset',
|
||||
'use',
|
||||
'var',
|
||||
'while',
|
||||
'xor',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array user confirmations on whether to overwrite existing code files with the newly generated ones.
|
||||
* The value of this property is internally managed by this class and {@link CCodeGenerator}.
|
||||
*/
|
||||
public $answers;
|
||||
/**
|
||||
* @var string the name of the code template that the user has selected.
|
||||
* The value of this property is internally managed by this class and {@link CCodeGenerator}.
|
||||
*/
|
||||
public $template;
|
||||
/**
|
||||
* @var array a list of {@link CCodeFile} objects that represent the code files to be generated.
|
||||
* The {@link prepare()} method is responsible to populate this property.
|
||||
*/
|
||||
public $files=array();
|
||||
/**
|
||||
* @var integer the status of this model. T
|
||||
* The value of this property is internally managed by {@link CCodeGenerator}.
|
||||
*/
|
||||
public $status=self::STATUS_NEW;
|
||||
|
||||
private $_stickyAttributes=array();
|
||||
|
||||
/**
|
||||
* Prepares the code files to be generated.
|
||||
* This is the main method that child classes should implement. It should contain the logic
|
||||
* that populates the {@link files} property with a list of code files to be generated.
|
||||
*/
|
||||
abstract public function prepare();
|
||||
|
||||
/**
|
||||
* Declares the model validation rules.
|
||||
* Child classes must override this method in the following format:
|
||||
* <pre>
|
||||
* return array_merge(parent::rules(), array(
|
||||
* ...rules for the child class...
|
||||
* ));
|
||||
* </pre>
|
||||
* @return array validation rules
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return array(
|
||||
array('template', 'required'),
|
||||
array('template', 'validateTemplate', 'skipOnError'=>true),
|
||||
array('template', 'sticky'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the template selection.
|
||||
* This method validates whether the user selects an existing template
|
||||
* and the template contains all required template files as specified in {@link requiredTemplates}.
|
||||
* @param string $attribute the attribute to be validated
|
||||
* @param array $params validation parameters
|
||||
*/
|
||||
public function validateTemplate($attribute,$params)
|
||||
{
|
||||
$templates=$this->templates;
|
||||
if(!isset($templates[$this->template]))
|
||||
$this->addError('template', 'Invalid template selection.');
|
||||
else
|
||||
{
|
||||
$templatePath=$this->templatePath;
|
||||
foreach($this->requiredTemplates() as $template)
|
||||
{
|
||||
if(!is_file($templatePath.'/'.$template))
|
||||
$this->addError('template', "Unable to find the required code template file '$template'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the named class exists (in a case sensitive manner).
|
||||
* @param string $name class name to be checked
|
||||
* @return boolean whether the class exists
|
||||
*/
|
||||
public function classExists($name)
|
||||
{
|
||||
return class_exists($name,false) && in_array($name, get_declared_classes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Declares the model attribute labels.
|
||||
* Child classes must override this method in the following format:
|
||||
* <pre>
|
||||
* return array_merge(parent::attributeLabels(), array(
|
||||
* ...labels for the child class attributes...
|
||||
* ));
|
||||
* </pre>
|
||||
* @return array the attribute labels
|
||||
*/
|
||||
public function attributeLabels()
|
||||
{
|
||||
return array(
|
||||
'template'=>'Code Template',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of code templates that are required.
|
||||
* Derived classes usually should override this method.
|
||||
* @return array list of code templates that are required. They should be file paths
|
||||
* relative to {@link templatePath}.
|
||||
*/
|
||||
public function requiredTemplates()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the generated code into files.
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$result=true;
|
||||
foreach($this->files as $file)
|
||||
{
|
||||
if($this->confirmed($file))
|
||||
$result=$file->save() && $result;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message to be displayed when the newly generated code is saved successfully.
|
||||
* Child classes should override this method if the message needs to be customized.
|
||||
* @return string the message to be displayed when the newly generated code is saved successfully.
|
||||
*/
|
||||
public function successMessage()
|
||||
{
|
||||
return 'The code has been generated successfully.';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message to be displayed when some error occurred during code file saving.
|
||||
* Child classes should override this method if the message needs to be customized.
|
||||
* @return string the message to be displayed when some error occurred during code file saving.
|
||||
*/
|
||||
public function errorMessage()
|
||||
{
|
||||
return 'There was some error when generating the code. Please check the following messages.';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of available code templates (name=>directory).
|
||||
* This method simply returns the {@link CCodeGenerator::templates} property value.
|
||||
* @return array a list of available code templates (name=>directory).
|
||||
*/
|
||||
public function getTemplates()
|
||||
{
|
||||
return Yii::app()->controller->templates;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the directory that contains the template files.
|
||||
* @throws CHttpException if {@link templates} is empty or template selection is invalid
|
||||
*/
|
||||
public function getTemplatePath()
|
||||
{
|
||||
$templates=$this->getTemplates();
|
||||
if(isset($templates[$this->template]))
|
||||
return $templates[$this->template];
|
||||
elseif(empty($templates))
|
||||
throw new CHttpException(500,'No templates are available.');
|
||||
else
|
||||
throw new CHttpException(500,'Invalid template selection.');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CCodeFile $file whether the code file should be saved
|
||||
* @return bool whether the confirmation is found in {@link answers} with appropriate {@link operation}
|
||||
*/
|
||||
public function confirmed($file)
|
||||
{
|
||||
return $this->answers===null && $file->operation===CCodeFile::OP_NEW
|
||||
|| is_array($this->answers) && isset($this->answers[md5($file->path)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the code using the specified code template file.
|
||||
* This method is manly used in {@link generate} to generate code.
|
||||
* @param string $templateFile the code template file path
|
||||
* @param array $_params_ a set of parameters to be extracted and made available in the code template
|
||||
* @throws CException is template file does not exist
|
||||
* @return string the generated code
|
||||
*/
|
||||
public function render($templateFile,$_params_=null)
|
||||
{
|
||||
if(!is_file($templateFile))
|
||||
throw new CException("The template file '$templateFile' does not exist.");
|
||||
|
||||
if(is_array($_params_))
|
||||
extract($_params_,EXTR_PREFIX_SAME,'params');
|
||||
else
|
||||
$params=$_params_;
|
||||
ob_start();
|
||||
ob_implicit_flush(false);
|
||||
require($templateFile);
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the code generation result log.
|
||||
*/
|
||||
public function renderResults()
|
||||
{
|
||||
$output='Generating code using template "'.$this->templatePath."\"...\n";
|
||||
foreach($this->files as $file)
|
||||
{
|
||||
if($file->error!==null)
|
||||
$output.="<span class=\"error\">generating {$file->relativePath}<br/> {$file->error}</span>\n";
|
||||
elseif($file->operation===CCodeFile::OP_NEW && $this->confirmed($file))
|
||||
$output.=' generated '.$file->relativePath."\n";
|
||||
elseif($file->operation===CCodeFile::OP_OVERWRITE && $this->confirmed($file))
|
||||
$output.=' overwrote '.$file->relativePath."\n";
|
||||
else
|
||||
$output.=' skipped '.$file->relativePath."\n";
|
||||
}
|
||||
$output.="done!\n";
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* The "sticky" validator.
|
||||
* This validator does not really validate the attributes.
|
||||
* It actually saves the attribute value in a file to make it sticky.
|
||||
* @param string $attribute the attribute to be validated
|
||||
* @param array $params the validation parameters
|
||||
*/
|
||||
public function sticky($attribute,$params)
|
||||
{
|
||||
if(!$this->hasErrors())
|
||||
$this->_stickyAttributes[$attribute]=$this->$attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads sticky attributes from a file and populates them into the model.
|
||||
*/
|
||||
public function loadStickyAttributes()
|
||||
{
|
||||
$this->_stickyAttributes=array();
|
||||
$path=$this->getStickyFile();
|
||||
if(is_file($path))
|
||||
{
|
||||
$result=@include($path);
|
||||
if(is_array($result))
|
||||
{
|
||||
$this->_stickyAttributes=$result;
|
||||
foreach($this->_stickyAttributes as $name=>$value)
|
||||
{
|
||||
if(property_exists($this,$name) || $this->canSetProperty($name))
|
||||
$this->$name=$value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves sticky attributes into a file.
|
||||
*/
|
||||
public function saveStickyAttributes()
|
||||
{
|
||||
$path=$this->getStickyFile();
|
||||
@mkdir(dirname($path),0755,true);
|
||||
file_put_contents($path,"<?php\nreturn ".var_export($this->_stickyAttributes,true).";\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the file path that stores the sticky attribute values.
|
||||
*/
|
||||
public function getStickyFile()
|
||||
{
|
||||
return Yii::app()->runtimePath.'/gii-'.Yii::getVersion().'/'.get_class($this).'.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a word to its plural form.
|
||||
* Note that this is for English only!
|
||||
* For example, 'apple' will become 'apples', and 'child' will become 'children'.
|
||||
* @param string $name the word to be pluralized
|
||||
* @return string the pluralized word
|
||||
*/
|
||||
public function pluralize($name)
|
||||
{
|
||||
$rules=array(
|
||||
'/(m)ove$/i' => '\1oves',
|
||||
'/(f)oot$/i' => '\1eet',
|
||||
'/(c)hild$/i' => '\1hildren',
|
||||
'/(h)uman$/i' => '\1umans',
|
||||
'/(m)an$/i' => '\1en',
|
||||
'/(s)taff$/i' => '\1taff',
|
||||
'/(t)ooth$/i' => '\1eeth',
|
||||
'/(p)erson$/i' => '\1eople',
|
||||
'/([m|l])ouse$/i' => '\1ice',
|
||||
'/(x|ch|ss|sh|us|as|is|os)$/i' => '\1es',
|
||||
'/([^aeiouy]|qu)y$/i' => '\1ies',
|
||||
'/(?:([^f])fe|([lr])f)$/i' => '\1\2ves',
|
||||
'/(shea|lea|loa|thie)f$/i' => '\1ves',
|
||||
'/([ti])um$/i' => '\1a',
|
||||
'/(tomat|potat|ech|her|vet)o$/i' => '\1oes',
|
||||
'/(bu)s$/i' => '\1ses',
|
||||
'/(ax|test)is$/i' => '\1es',
|
||||
'/s$/' => 's',
|
||||
);
|
||||
foreach($rules as $rule=>$replacement)
|
||||
{
|
||||
if(preg_match($rule,$name))
|
||||
return preg_replace($rule,$replacement,$name);
|
||||
}
|
||||
return $name.'s';
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a class name into a HTML ID.
|
||||
* For example, 'PostTag' will be converted as 'post-tag'.
|
||||
* @param string $name the string to be converted
|
||||
* @return string the resulting ID
|
||||
*/
|
||||
public function class2id($name)
|
||||
{
|
||||
return trim(strtolower(str_replace('_','-',preg_replace('/(?<![A-Z])[A-Z]/', '-\0', $name))),'-');
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a class name into space-separated words.
|
||||
* For example, 'PostTag' will be converted as 'Post Tag'.
|
||||
* @param string $name the string to be converted
|
||||
* @param boolean $ucwords whether to capitalize the first letter in each word
|
||||
* @return string the resulting words
|
||||
*/
|
||||
public function class2name($name,$ucwords=true)
|
||||
{
|
||||
$result=trim(strtolower(str_replace('_',' ',preg_replace('/(?<![A-Z])[A-Z]/', ' \0', $name))));
|
||||
return $ucwords ? ucwords($result) : $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a class name into a variable name with the first letter in lower case.
|
||||
* This method is provided because lcfirst() PHP function is only available for PHP 5.3+.
|
||||
* @param string $name the class name
|
||||
* @return string the variable name converted from the class name
|
||||
* @since 1.1.4
|
||||
*/
|
||||
public function class2var($name)
|
||||
{
|
||||
$name[0]=strtolower($name[0]);
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an attribute to make sure it is not taking a PHP reserved keyword.
|
||||
* @param string $attribute the attribute to be validated
|
||||
* @param array $params validation parameters
|
||||
*/
|
||||
public function validateReservedWord($attribute,$params)
|
||||
{
|
||||
$value=$this->$attribute;
|
||||
if(in_array(strtolower($value),self::$keywords))
|
||||
$this->addError($attribute, $this->getAttributeLabel($attribute).' cannot take a reserved PHP keyword.');
|
||||
}
|
||||
}
|
||||
244
framework/gii/GiiModule.php
Normal file
@@ -0,0 +1,244 @@
|
||||
<?php
|
||||
/**
|
||||
* GiiModule 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/
|
||||
*/
|
||||
|
||||
Yii::import('system.gii.CCodeGenerator');
|
||||
Yii::import('system.gii.CCodeModel');
|
||||
Yii::import('system.gii.CCodeFile');
|
||||
Yii::import('system.gii.CCodeForm');
|
||||
|
||||
/**
|
||||
* GiiModule is a module that provides Web-based code generation capabilities.
|
||||
*
|
||||
* To use GiiModule, you must include it as a module in the application configuration like the following:
|
||||
* <pre>
|
||||
* return array(
|
||||
* ......
|
||||
* 'modules'=>array(
|
||||
* 'gii'=>array(
|
||||
* 'class'=>'system.gii.GiiModule',
|
||||
* 'password'=>***choose a password***
|
||||
* ),
|
||||
* ),
|
||||
* )
|
||||
* </pre>
|
||||
*
|
||||
* Because GiiModule generates new code files on the server, you should only use it on your own
|
||||
* development machine. To prevent other people from using this module, it is required that
|
||||
* you specify a secret password in the configuration. Later when you access
|
||||
* the module via browser, you will be prompted to enter the correct password.
|
||||
*
|
||||
* By default, GiiModule can only be accessed by localhost. You may configure its {@link ipFilters}
|
||||
* property if you want to make it accessible on other machines.
|
||||
*
|
||||
* With the above configuration, you will be able to access GiiModule in your browser using
|
||||
* the following URL:
|
||||
*
|
||||
* http://localhost/path/to/index.php?r=gii
|
||||
*
|
||||
* If your application is using path-format URLs with some customized URL rules, you may need to add
|
||||
* the following URLs in your application configuration in order to access GiiModule:
|
||||
* <pre>
|
||||
* 'components'=>array(
|
||||
* 'urlManager'=>array(
|
||||
* 'urlFormat'=>'path',
|
||||
* 'rules'=>array(
|
||||
* 'gii'=>'gii',
|
||||
* 'gii/<controller:\w+>'=>'gii/<controller>',
|
||||
* 'gii/<controller:\w+>/<action:\w+>'=>'gii/<controller>/<action>',
|
||||
* ...other rules...
|
||||
* ),
|
||||
* )
|
||||
* )
|
||||
* </pre>
|
||||
*
|
||||
* You can then access GiiModule via:
|
||||
*
|
||||
* http://localhost/path/to/index.php/gii
|
||||
*
|
||||
* @property string $assetsUrl The base URL that contains all published asset files of gii.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @package system.gii
|
||||
* @since 1.1.2
|
||||
*/
|
||||
class GiiModule extends CWebModule
|
||||
{
|
||||
/**
|
||||
* @var string the password that can be used to access GiiModule.
|
||||
* If this property is set false, then GiiModule can be accessed without password
|
||||
* (DO NOT DO THIS UNLESS YOU KNOW THE CONSEQUENCE!!!)
|
||||
*/
|
||||
public $password;
|
||||
/**
|
||||
* @var array the IP filters that specify which IP addresses are allowed to access GiiModule.
|
||||
* Each array element represents a single filter. A filter can be either an IP address
|
||||
* or an address with wildcard (e.g. 192.168.0.*) to represent a network segment.
|
||||
* If you want to allow all IPs to access gii, you may set this property to be false
|
||||
* (DO NOT DO THIS UNLESS YOU KNOW THE CONSEQUENCE!!!)
|
||||
* The default value is array('127.0.0.1', '::1'), which means GiiModule can only be accessed
|
||||
* on the localhost.
|
||||
*/
|
||||
public $ipFilters=array('127.0.0.1','::1');
|
||||
/**
|
||||
* @var array a list of path aliases that refer to the directories containing code generators.
|
||||
* The directory referred by a single path alias may contain multiple code generators, each stored
|
||||
* under a sub-directory whose name is the generator name.
|
||||
* Defaults to array('application.gii').
|
||||
*/
|
||||
public $generatorPaths=array('application.gii');
|
||||
/**
|
||||
* @var integer the permission to be set for newly generated code files.
|
||||
* This value will be used by PHP chmod function.
|
||||
* Defaults to 0666, meaning the file is read-writable by all users.
|
||||
*/
|
||||
public $newFileMode=0666;
|
||||
/**
|
||||
* @var integer the permission to be set for newly generated directories.
|
||||
* This value will be used by PHP chmod function.
|
||||
* Defaults to 0777, meaning the directory can be read, written and executed by all users.
|
||||
*/
|
||||
public $newDirMode=0777;
|
||||
|
||||
private $_assetsUrl;
|
||||
|
||||
/**
|
||||
* Initializes the gii module.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
Yii::setPathOfAlias('gii',dirname(__FILE__));
|
||||
Yii::app()->setComponents(array(
|
||||
'errorHandler'=>array(
|
||||
'class'=>'CErrorHandler',
|
||||
'errorAction'=>$this->getId().'/default/error',
|
||||
),
|
||||
'user'=>array(
|
||||
'class'=>'CWebUser',
|
||||
'stateKeyPrefix'=>'gii',
|
||||
'loginUrl'=>Yii::app()->createUrl($this->getId().'/default/login'),
|
||||
),
|
||||
'widgetFactory' => array(
|
||||
'class'=>'CWidgetFactory',
|
||||
'widgets' => array()
|
||||
)
|
||||
), false);
|
||||
$this->generatorPaths[]='gii.generators';
|
||||
$this->controllerMap=$this->findGenerators();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the base URL that contains all published asset files of gii.
|
||||
*/
|
||||
public function getAssetsUrl()
|
||||
{
|
||||
if($this->_assetsUrl===null)
|
||||
$this->_assetsUrl=Yii::app()->getAssetManager()->publish(Yii::getPathOfAlias('gii.assets'));
|
||||
return $this->_assetsUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value the base URL that contains all published asset files of gii.
|
||||
*/
|
||||
public function setAssetsUrl($value)
|
||||
{
|
||||
$this->_assetsUrl=$value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs access check to gii.
|
||||
* This method will check to see if user IP and password are correct if they attempt
|
||||
* to access actions other than "default/login" and "default/error".
|
||||
* @param CController $controller the controller to be accessed.
|
||||
* @param CAction $action the action to be accessed.
|
||||
* @throws CHttpException if access denied
|
||||
* @return boolean whether the action should be executed.
|
||||
*/
|
||||
public function beforeControllerAction($controller, $action)
|
||||
{
|
||||
if(parent::beforeControllerAction($controller, $action))
|
||||
{
|
||||
$route=$controller->id.'/'.$action->id;
|
||||
if(!$this->allowIp(Yii::app()->request->userHostAddress) && $route!=='default/error')
|
||||
throw new CHttpException(403,"You are not allowed to access this page.");
|
||||
|
||||
$publicPages=array(
|
||||
'default/login',
|
||||
'default/error',
|
||||
);
|
||||
if($this->password!==false && Yii::app()->user->isGuest && !in_array($route,$publicPages))
|
||||
Yii::app()->user->loginRequired();
|
||||
else
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the user IP is allowed by {@link ipFilters}.
|
||||
* @param string $ip the user IP
|
||||
* @return boolean whether the user IP is allowed by {@link ipFilters}.
|
||||
*/
|
||||
protected function allowIp($ip)
|
||||
{
|
||||
if(empty($this->ipFilters))
|
||||
return true;
|
||||
foreach($this->ipFilters as $filter)
|
||||
{
|
||||
if($filter==='*' || $filter===$ip || (($pos=strpos($filter,'*'))!==false && !strncmp($ip,$filter,$pos)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all available code generators and their code templates.
|
||||
* @return array
|
||||
*/
|
||||
protected function findGenerators()
|
||||
{
|
||||
$generators=array();
|
||||
$n=count($this->generatorPaths);
|
||||
for($i=$n-1;$i>=0;--$i)
|
||||
{
|
||||
$alias=$this->generatorPaths[$i];
|
||||
$path=Yii::getPathOfAlias($alias);
|
||||
if($path===false || !is_dir($path))
|
||||
continue;
|
||||
|
||||
$names=scandir($path);
|
||||
foreach($names as $name)
|
||||
{
|
||||
if($name[0]!=='.' && is_dir($path.'/'.$name))
|
||||
{
|
||||
$className=ucfirst($name).'Generator';
|
||||
if(is_file("$path/$name/$className.php"))
|
||||
{
|
||||
$generators[$name]=array(
|
||||
'class'=>"$alias.$name.$className",
|
||||
);
|
||||
}
|
||||
|
||||
if(isset($generators[$name]) && is_dir("$path/$name/templates"))
|
||||
{
|
||||
$templatePath="$path/$name/templates";
|
||||
$dirs=scandir($templatePath);
|
||||
foreach($dirs as $dir)
|
||||
{
|
||||
if($dir[0]!=='.' && is_dir($templatePath.'/'.$dir))
|
||||
$generators[$name]['templates'][$dir]=strtr($templatePath.'/'.$dir,array('/'=>DIRECTORY_SEPARATOR,'\\'=>DIRECTORY_SEPARATOR));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $generators;
|
||||
}
|
||||
}
|
||||
35
framework/gii/assets/css/ie.css
Normal file
@@ -0,0 +1,35 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
|
||||
|
||||
Blueprint CSS Framework 0.9
|
||||
http://blueprintcss.org
|
||||
|
||||
* Copyright (c) 2007-Present. See LICENSE for more info.
|
||||
* See README for instructions on how to use Blueprint.
|
||||
* For credits and origins, see AUTHORS.
|
||||
* This is a compressed file. See the sources in the 'src' directory.
|
||||
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
/* ie.css */
|
||||
body {text-align:center;}
|
||||
.container {text-align:left;}
|
||||
* html .column, * html div.span-1, * html div.span-2, * html div.span-3, * html div.span-4, * html div.span-5, * html div.span-6, * html div.span-7, * html div.span-8, * html div.span-9, * html div.span-10, * html div.span-11, * html div.span-12, * html div.span-13, * html div.span-14, * html div.span-15, * html div.span-16, * html div.span-17, * html div.span-18, * html div.span-19, * html div.span-20, * html div.span-21, * html div.span-22, * html div.span-23, * html div.span-24 {display:inline;overflow-x:hidden;}
|
||||
* html legend {margin:0px -8px 16px 0;padding:0;}
|
||||
sup {vertical-align:text-top;}
|
||||
sub {vertical-align:text-bottom;}
|
||||
html>body p code {*white-space:normal;}
|
||||
hr {margin:-8px auto 11px;}
|
||||
img {-ms-interpolation-mode:bicubic;}
|
||||
.clearfix, .container {display:inline-block;}
|
||||
* html .clearfix, * html .container {height:1%;}
|
||||
fieldset {padding-top:0;}
|
||||
textarea {overflow:auto;}
|
||||
input.text, input.title, textarea {background-color:#fff;border:1px solid #bbb;}
|
||||
input.text:focus, input.title:focus {border-color:#666;}
|
||||
input.text, input.title, textarea, select {margin:0.5em 0;}
|
||||
input.checkbox, input.radio {position:relative;top:.25em;}
|
||||
form.inline div, form.inline p {vertical-align:middle;}
|
||||
form.inline label {position:relative;top:-0.25em;}
|
||||
form.inline input.checkbox, form.inline input.radio, form.inline input.button, form.inline button {margin:0.5em 0;}
|
||||
button, input.button {position:relative;top:0.25em;}
|
||||
528
framework/gii/assets/css/main.css
Normal file
@@ -0,0 +1,528 @@
|
||||
body
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #555;
|
||||
font: normal 10pt Arial,Helvetica,Verdana,"DejaVu Sans","Bitstream Vera Sans",Geneva,sans-serif;
|
||||
background: #EFEFEF;
|
||||
}
|
||||
|
||||
h1
|
||||
{
|
||||
font-size: 1.6em;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
h2
|
||||
{
|
||||
font-size: 1.4em;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
h3
|
||||
{
|
||||
font-size: 1.2em;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
#page
|
||||
{
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
background: white;
|
||||
border: 1px solid #C9E0ED;
|
||||
}
|
||||
|
||||
#header
|
||||
{
|
||||
padding: 0px;
|
||||
margin: 0px 20px;
|
||||
border-bottom: 1px solid #C9E0ED;
|
||||
}
|
||||
|
||||
#content
|
||||
{
|
||||
padding: 20px;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
#sidebar
|
||||
{
|
||||
padding: 20px 0 20px 20px;
|
||||
}
|
||||
|
||||
#footer
|
||||
{
|
||||
margin: 0 auto;
|
||||
width: 950px;
|
||||
font-size: 0.8em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#logo
|
||||
{
|
||||
padding: 5px 0px;
|
||||
}
|
||||
|
||||
#logo a
|
||||
{
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#header .top-menus
|
||||
{
|
||||
margin: 20px 0px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
div.flash-error, div.flash-notice, div.flash-success
|
||||
{
|
||||
padding:.8em;
|
||||
margin-bottom:1em;
|
||||
border:2px solid #ddd;
|
||||
}
|
||||
|
||||
div.flash-error
|
||||
{
|
||||
background:#FBE3E4;
|
||||
color:#8a1f11;
|
||||
border-color:#FBC2C4;
|
||||
}
|
||||
|
||||
div.flash-notice
|
||||
{
|
||||
background:#FFF6BF;
|
||||
color:#514721;
|
||||
border-color:#FFD324;
|
||||
}
|
||||
|
||||
div.flash-success
|
||||
{
|
||||
background:#E6EFC2;
|
||||
color:#264409;
|
||||
border-color:#C6D880;
|
||||
}
|
||||
|
||||
div.flash-error a
|
||||
{
|
||||
color:#8a1f11;
|
||||
}
|
||||
|
||||
div.flash-notice a
|
||||
{
|
||||
color:#514721;
|
||||
}
|
||||
|
||||
div.flash-success a
|
||||
{
|
||||
color:#264409;
|
||||
}
|
||||
|
||||
div.view
|
||||
{
|
||||
padding: 10px;
|
||||
margin: 10px 0;
|
||||
border: 1px solid #C9E0ED;
|
||||
}
|
||||
|
||||
div.breadcrumbs
|
||||
{
|
||||
font-size: 0.9em;
|
||||
padding: 5px 20px;
|
||||
}
|
||||
|
||||
div.breadcrumbs span
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.search-form
|
||||
{
|
||||
padding: 10px;
|
||||
margin: 10px 0;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.portlet
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
.portlet-decoration
|
||||
{
|
||||
padding: 3px 8px;
|
||||
background: #79B4DC;
|
||||
border-left: 5px solid #6293B3;
|
||||
}
|
||||
|
||||
.portlet-title
|
||||
{
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.portlet-content
|
||||
{
|
||||
font-size:0.9em;
|
||||
margin: 0 0 15px 0;
|
||||
padding: 5px 8px;
|
||||
background:#EFFDFF;
|
||||
}
|
||||
|
||||
.portlet-content ul
|
||||
{
|
||||
list-style-image:none;
|
||||
list-style-position:outside;
|
||||
list-style-type:none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.portlet-content li
|
||||
{
|
||||
padding: 2px 0 4px 0px;
|
||||
}
|
||||
|
||||
div.form
|
||||
{
|
||||
}
|
||||
|
||||
div.form input,
|
||||
div.form textarea,
|
||||
div.form select
|
||||
{
|
||||
margin: 0.2em 0 0.5em 0;
|
||||
}
|
||||
|
||||
div.form fieldset
|
||||
{
|
||||
border: 1px solid #DDD;
|
||||
padding: 10px;
|
||||
margin: 0 0 10px 0;
|
||||
-moz-border-radius:7px;
|
||||
}
|
||||
|
||||
div.form label
|
||||
{
|
||||
font-weight: bold;
|
||||
font-size: 0.9em;
|
||||
display: block;
|
||||
}
|
||||
|
||||
div.form .row
|
||||
{
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
div.form .row.buttons
|
||||
{
|
||||
padding: 5px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
div.form .row.buttons input
|
||||
{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.form .hint
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
div.form .note
|
||||
{
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
div.form span.required
|
||||
{
|
||||
color: red;
|
||||
}
|
||||
|
||||
div.form div.error label,
|
||||
div.form label.error,
|
||||
div.form span.error
|
||||
{
|
||||
color: #C00;
|
||||
}
|
||||
|
||||
div.form div.error input,
|
||||
div.form div.error textarea,
|
||||
div.form div.error select,
|
||||
div.form input.error,
|
||||
div.form textarea.error,
|
||||
div.form select.error
|
||||
{
|
||||
background: #FEE;
|
||||
border-color: #C00;
|
||||
}
|
||||
|
||||
div.form div.success input,
|
||||
div.form div.success textarea,
|
||||
div.form div.success select,
|
||||
div.form input.success,
|
||||
div.form textarea.success,
|
||||
div.form select.success
|
||||
{
|
||||
background: #E6EFC2;
|
||||
border-color: #C6D880;
|
||||
}
|
||||
|
||||
|
||||
div.form .errorSummary
|
||||
{
|
||||
border: 2px solid #C00;
|
||||
padding: 7px 7px 12px 7px;
|
||||
margin: 0 0 20px 0;
|
||||
background: #FEE;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
div.form .errorMessage
|
||||
{
|
||||
color: red;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
div.form .errorSummary p
|
||||
{
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
div.form .errorSummary ul
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0 0 0 20px;
|
||||
}
|
||||
|
||||
div.wide.form label
|
||||
{
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
position: relative;
|
||||
text-align: right;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
div.wide.form .row
|
||||
{
|
||||
clear: left;
|
||||
}
|
||||
|
||||
div.wide.form .buttons, div.wide.form .hint, div.wide.form .errorMessage
|
||||
{
|
||||
clear: left;
|
||||
padding-left: 110px;
|
||||
}
|
||||
|
||||
div.form .tooltip
|
||||
{
|
||||
display: none;
|
||||
background-color:#EFFDFF;
|
||||
border:1px solid #79B4DC;
|
||||
padding: 10px;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
div.form .tooltip ul
|
||||
{
|
||||
margin: 0;
|
||||
padding: 10px 0 0 20px;
|
||||
}
|
||||
|
||||
div.form .tooltip code
|
||||
{
|
||||
color: #CA0EE3;
|
||||
font-size:0.9em;
|
||||
}
|
||||
|
||||
div.form.login
|
||||
{
|
||||
border: 1px solid #C9E0ED;
|
||||
width: 200px;
|
||||
margin: 0 auto;
|
||||
margin-top: 50px;
|
||||
margin-bottom: 50px;
|
||||
padding: 20px 10px 10px 10px;
|
||||
text-align: center;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
}
|
||||
|
||||
div.form.login p
|
||||
{
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
div.form.gii .row.sticky .value, span.sticky
|
||||
{
|
||||
padding: 3px;
|
||||
background: lightyellow;
|
||||
}
|
||||
|
||||
div.form.gii .row.template select
|
||||
{
|
||||
width: 420px;
|
||||
}
|
||||
|
||||
div.form.gii table.preview
|
||||
{
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
div.form.gii table.preview th
|
||||
{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.form.gii table.preview th.confirm
|
||||
{
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
div.form.gii table.preview th.confirm label
|
||||
{
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.form.gii table.preview td.confirm
|
||||
{
|
||||
width: 80px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
div.form.gii table.preview td.confirm input
|
||||
{
|
||||
margin:0;
|
||||
}
|
||||
|
||||
div.form.gii table.preview td.confirm label
|
||||
{
|
||||
display: inline;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
div.form.gii table.preview,
|
||||
div.form.gii table.preview th,
|
||||
div.form.gii table.preview td
|
||||
{
|
||||
border: 1px solid #529EC6;
|
||||
}
|
||||
|
||||
div.form.gii table.preview tr.skip
|
||||
{
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
div.form.gii table.preview tr.new
|
||||
{
|
||||
background-color: #C5FBBD;
|
||||
}
|
||||
|
||||
div.form.gii table.preview tr.overwrite
|
||||
{
|
||||
background-color: #FFE0E1;
|
||||
}
|
||||
|
||||
div.form.gii pre.results
|
||||
{
|
||||
overflow: auto;
|
||||
background-color: gray;
|
||||
max-height: 300px;
|
||||
color: white;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
div.form.gii div.success
|
||||
{
|
||||
background: #C5FBBD;
|
||||
border: 1px solid #76C376;
|
||||
padding: 10px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
div.form.gii div.error
|
||||
{
|
||||
background: #FFE0E1;
|
||||
border: 1px solid #FFA0A2;
|
||||
padding: 10px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
div.form.gii div.success code
|
||||
{
|
||||
overflow: auto;
|
||||
display: block;
|
||||
padding: 5px;
|
||||
font-size: 12px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
div.form.gii pre.results span.error
|
||||
{
|
||||
background: #FFE0E1;
|
||||
color: black;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
#fancybox-inner .error
|
||||
{
|
||||
color: red;
|
||||
}
|
||||
|
||||
#fancybox-inner .title
|
||||
{
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#fancybox-inner .buttons
|
||||
{
|
||||
float: right;
|
||||
padding: 0 10px 0 0;
|
||||
}
|
||||
|
||||
#fancybox-inner .content
|
||||
{
|
||||
background: #F0F4FF;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#fancybox-inner pre.diff
|
||||
{
|
||||
margin:0;
|
||||
}
|
||||
|
||||
#fancybox-inner pre.diff del
|
||||
{
|
||||
background: pink;
|
||||
}
|
||||
|
||||
#fancybox-inner pre.diff ins
|
||||
{
|
||||
background: lightgreen;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#fancybox-wrap #tip7-title
|
||||
{
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#fancybox-wrap #tip7-title b
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
|
||||
#fancybox-wrap #tip7-title span
|
||||
{
|
||||
float: right;
|
||||
}
|
||||
29
framework/gii/assets/css/print.css
Normal file
@@ -0,0 +1,29 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
|
||||
|
||||
Blueprint CSS Framework 0.9
|
||||
http://blueprintcss.org
|
||||
|
||||
* Copyright (c) 2007-Present. See LICENSE for more info.
|
||||
* See README for instructions on how to use Blueprint.
|
||||
* For credits and origins, see AUTHORS.
|
||||
* This is a compressed file. See the sources in the 'src' directory.
|
||||
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
/* print.css */
|
||||
body {line-height:1.5;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;color:#000;background:none;font-size:10pt;}
|
||||
.container {background:none;}
|
||||
hr {background:#ccc;color:#ccc;width:100%;height:2px;margin:2em 0;padding:0;border:none;}
|
||||
hr.space {background:#fff;color:#fff;visibility:hidden;}
|
||||
h1, h2, h3, h4, h5, h6 {font-family:"Helvetica Neue", Arial, "Lucida Grande", sans-serif;}
|
||||
code {font:.9em "Courier New", Monaco, Courier, monospace;}
|
||||
a img {border:none;}
|
||||
p img.top {margin-top:0;}
|
||||
blockquote {margin:1.5em;padding:1em;font-style:italic;font-size:.9em;}
|
||||
.small {font-size:.9em;}
|
||||
.large {font-size:1.1em;}
|
||||
.quiet {color:#999;}
|
||||
.hide {display:none;}
|
||||
a:link, a:visited {background:transparent;font-weight:700;text-decoration:underline;}
|
||||
a:link:after, a:visited:after {content:" (" attr(href) ")";font-size:90%;}
|
||||
235
framework/gii/assets/css/screen.css
Normal file
@@ -0,0 +1,235 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
|
||||
|
||||
Blueprint CSS Framework 0.9
|
||||
http://blueprintcss.org
|
||||
|
||||
* Copyright (c) 2007-Present. See LICENSE for more info.
|
||||
* See README for instructions on how to use Blueprint.
|
||||
* For credits and origins, see AUTHORS.
|
||||
* This is a compressed file. See the sources in the 'src' directory.
|
||||
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
/* reset.css */
|
||||
html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {margin:0;padding:0;border:0;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;vertical-align:baseline;}
|
||||
body {line-height:1.5;}
|
||||
table {border-collapse:separate;border-spacing:0;}
|
||||
caption, th, td {text-align:left;font-weight:normal;}
|
||||
table, td, th {vertical-align:middle;}
|
||||
blockquote:before, blockquote:after, q:before, q:after {content:"";}
|
||||
blockquote, q {quotes:"" "";}
|
||||
a img {border:none;}
|
||||
|
||||
/* typography.css */
|
||||
html {font-size:100.01%;}
|
||||
body {font-size:75%;color:#222;background:#fff;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;}
|
||||
h1, h2, h3, h4, h5, h6 {font-weight:normal;color:#111;}
|
||||
h1 {font-size:2em;line-height:1;margin-bottom:0.5em;}
|
||||
h2 {font-size:1.6em;margin-bottom:0.75em;}
|
||||
h3 {font-size:1.4em;line-height:1;margin-bottom:1em;}
|
||||
h4 {font-size:1.2em;line-height:1.25;margin-bottom:1.25em;}
|
||||
h5 {font-size:1em;font-weight:bold;margin-bottom:1.5em;}
|
||||
h6 {font-size:1em;font-weight:bold;}
|
||||
h1 img, h2 img, h3 img, h4 img, h5 img, h6 img {margin:0;}
|
||||
p {margin:0 0 1.5em;}
|
||||
p img.left {float:left;margin:1.5em 1.5em 1.5em 0;padding:0;}
|
||||
p img.right {float:right;margin:1.5em 0 1.5em 1.5em;}
|
||||
a:focus, a:hover {color:#000;}
|
||||
a {color:#009;text-decoration:underline;}
|
||||
blockquote {margin:1.5em;color:#666;font-style:italic;}
|
||||
strong {font-weight:bold;}
|
||||
em, dfn {font-style:italic;}
|
||||
dfn {font-weight:bold;}
|
||||
sup, sub {line-height:0;}
|
||||
abbr, acronym {border-bottom:1px dotted #666;}
|
||||
address {margin:0 0 1.5em;font-style:italic;}
|
||||
del {color:#666;}
|
||||
pre {margin:1.5em 0;white-space:pre;}
|
||||
pre, code, tt {font:1em 'andale mono', 'lucida console', monospace;line-height:1.5;}
|
||||
li ul, li ol {margin:0;}
|
||||
ul, ol {margin:0 1.5em 1.5em 0;padding-left:3.333em;}
|
||||
ul {list-style-type:disc;}
|
||||
ol {list-style-type:decimal;}
|
||||
dl {margin:0 0 1.5em 0;}
|
||||
dl dt {font-weight:bold;}
|
||||
dd {margin-left:1.5em;}
|
||||
table {margin-bottom:1.4em;width:100%;}
|
||||
th {font-weight:bold;}
|
||||
thead th {background:#c3d9ff;}
|
||||
th, td, caption {padding:4px 10px 4px 5px;}
|
||||
tfoot {font-style:italic;}
|
||||
caption {background:#eee;}
|
||||
.small {font-size:.8em;margin-bottom:1.875em;line-height:1.875em;}
|
||||
.large {font-size:1.2em;line-height:2.5em;margin-bottom:1.25em;}
|
||||
.hide {display:none;}
|
||||
.quiet {color:#666;}
|
||||
.loud {color:#000;}
|
||||
.highlight {background:#ff0;}
|
||||
.added {background:#060;color:#fff;}
|
||||
.removed {background:#900;color:#fff;}
|
||||
.first {margin-left:0;padding-left:0;}
|
||||
.last {margin-right:0;padding-right:0;}
|
||||
.top {margin-top:0;padding-top:0;}
|
||||
.bottom {margin-bottom:0;padding-bottom:0;}
|
||||
|
||||
/* grid.css */
|
||||
.container {width:950px;margin:0 auto;}
|
||||
.showgrid {background:url(src/grid.png);}
|
||||
.column, div.span-1, div.span-2, div.span-3, div.span-4, div.span-5, div.span-6, div.span-7, div.span-8, div.span-9, div.span-10, div.span-11, div.span-12, div.span-13, div.span-14, div.span-15, div.span-16, div.span-17, div.span-18, div.span-19, div.span-20, div.span-21, div.span-22, div.span-23, div.span-24 {float:left;margin-right:10px;}
|
||||
.last, div.last {margin-right:0;}
|
||||
.span-1 {width:30px;}
|
||||
.span-2 {width:70px;}
|
||||
.span-3 {width:110px;}
|
||||
.span-4 {width:150px;}
|
||||
.span-5 {width:190px;}
|
||||
.span-6 {width:230px;}
|
||||
.span-7 {width:270px;}
|
||||
.span-8 {width:310px;}
|
||||
.span-9 {width:350px;}
|
||||
.span-10 {width:390px;}
|
||||
.span-11 {width:430px;}
|
||||
.span-12 {width:470px;}
|
||||
.span-13 {width:510px;}
|
||||
.span-14 {width:550px;}
|
||||
.span-15 {width:590px;}
|
||||
.span-16 {width:630px;}
|
||||
.span-17 {width:670px;}
|
||||
.span-18 {width:710px;}
|
||||
.span-19 {width:750px;}
|
||||
.span-20 {width:790px;}
|
||||
.span-21 {width:830px;}
|
||||
.span-22 {width:870px;}
|
||||
.span-23 {width:910px;}
|
||||
.span-24, div.span-24 {width:950px;margin-right:0;}
|
||||
input.span-1, textarea.span-1, input.span-2, textarea.span-2, input.span-3, textarea.span-3, input.span-4, textarea.span-4, input.span-5, textarea.span-5, input.span-6, textarea.span-6, input.span-7, textarea.span-7, input.span-8, textarea.span-8, input.span-9, textarea.span-9, input.span-10, textarea.span-10, input.span-11, textarea.span-11, input.span-12, textarea.span-12, input.span-13, textarea.span-13, input.span-14, textarea.span-14, input.span-15, textarea.span-15, input.span-16, textarea.span-16, input.span-17, textarea.span-17, input.span-18, textarea.span-18, input.span-19, textarea.span-19, input.span-20, textarea.span-20, input.span-21, textarea.span-21, input.span-22, textarea.span-22, input.span-23, textarea.span-23, input.span-24, textarea.span-24 {border-left-width:1px!important;border-right-width:1px!important;padding-left:5px!important;padding-right:5px!important;}
|
||||
input.span-1, textarea.span-1 {width:18px!important;}
|
||||
input.span-2, textarea.span-2 {width:58px!important;}
|
||||
input.span-3, textarea.span-3 {width:98px!important;}
|
||||
input.span-4, textarea.span-4 {width:138px!important;}
|
||||
input.span-5, textarea.span-5 {width:178px!important;}
|
||||
input.span-6, textarea.span-6 {width:218px!important;}
|
||||
input.span-7, textarea.span-7 {width:258px!important;}
|
||||
input.span-8, textarea.span-8 {width:298px!important;}
|
||||
input.span-9, textarea.span-9 {width:338px!important;}
|
||||
input.span-10, textarea.span-10 {width:378px!important;}
|
||||
input.span-11, textarea.span-11 {width:418px!important;}
|
||||
input.span-12, textarea.span-12 {width:458px!important;}
|
||||
input.span-13, textarea.span-13 {width:498px!important;}
|
||||
input.span-14, textarea.span-14 {width:538px!important;}
|
||||
input.span-15, textarea.span-15 {width:578px!important;}
|
||||
input.span-16, textarea.span-16 {width:618px!important;}
|
||||
input.span-17, textarea.span-17 {width:658px!important;}
|
||||
input.span-18, textarea.span-18 {width:698px!important;}
|
||||
input.span-19, textarea.span-19 {width:738px!important;}
|
||||
input.span-20, textarea.span-20 {width:778px!important;}
|
||||
input.span-21, textarea.span-21 {width:818px!important;}
|
||||
input.span-22, textarea.span-22 {width:858px!important;}
|
||||
input.span-23, textarea.span-23 {width:898px!important;}
|
||||
input.span-24, textarea.span-24 {width:938px!important;}
|
||||
.append-1 {padding-right:40px;}
|
||||
.append-2 {padding-right:80px;}
|
||||
.append-3 {padding-right:120px;}
|
||||
.append-4 {padding-right:160px;}
|
||||
.append-5 {padding-right:200px;}
|
||||
.append-6 {padding-right:240px;}
|
||||
.append-7 {padding-right:280px;}
|
||||
.append-8 {padding-right:320px;}
|
||||
.append-9 {padding-right:360px;}
|
||||
.append-10 {padding-right:400px;}
|
||||
.append-11 {padding-right:440px;}
|
||||
.append-12 {padding-right:480px;}
|
||||
.append-13 {padding-right:520px;}
|
||||
.append-14 {padding-right:560px;}
|
||||
.append-15 {padding-right:600px;}
|
||||
.append-16 {padding-right:640px;}
|
||||
.append-17 {padding-right:680px;}
|
||||
.append-18 {padding-right:720px;}
|
||||
.append-19 {padding-right:760px;}
|
||||
.append-20 {padding-right:800px;}
|
||||
.append-21 {padding-right:840px;}
|
||||
.append-22 {padding-right:880px;}
|
||||
.append-23 {padding-right:920px;}
|
||||
.prepend-1 {padding-left:40px;}
|
||||
.prepend-2 {padding-left:80px;}
|
||||
.prepend-3 {padding-left:120px;}
|
||||
.prepend-4 {padding-left:160px;}
|
||||
.prepend-5 {padding-left:200px;}
|
||||
.prepend-6 {padding-left:240px;}
|
||||
.prepend-7 {padding-left:280px;}
|
||||
.prepend-8 {padding-left:320px;}
|
||||
.prepend-9 {padding-left:360px;}
|
||||
.prepend-10 {padding-left:400px;}
|
||||
.prepend-11 {padding-left:440px;}
|
||||
.prepend-12 {padding-left:480px;}
|
||||
.prepend-13 {padding-left:520px;}
|
||||
.prepend-14 {padding-left:560px;}
|
||||
.prepend-15 {padding-left:600px;}
|
||||
.prepend-16 {padding-left:640px;}
|
||||
.prepend-17 {padding-left:680px;}
|
||||
.prepend-18 {padding-left:720px;}
|
||||
.prepend-19 {padding-left:760px;}
|
||||
.prepend-20 {padding-left:800px;}
|
||||
.prepend-21 {padding-left:840px;}
|
||||
.prepend-22 {padding-left:880px;}
|
||||
.prepend-23 {padding-left:920px;}
|
||||
div.border {padding-right:4px;margin-right:5px;border-right:1px solid #eee;}
|
||||
div.colborder {padding-right:24px;margin-right:25px;border-right:1px solid #eee;}
|
||||
.pull-1 {margin-left:-40px;}
|
||||
.pull-2 {margin-left:-80px;}
|
||||
.pull-3 {margin-left:-120px;}
|
||||
.pull-4 {margin-left:-160px;}
|
||||
.pull-5 {margin-left:-200px;}
|
||||
.pull-6 {margin-left:-240px;}
|
||||
.pull-7 {margin-left:-280px;}
|
||||
.pull-8 {margin-left:-320px;}
|
||||
.pull-9 {margin-left:-360px;}
|
||||
.pull-10 {margin-left:-400px;}
|
||||
.pull-11 {margin-left:-440px;}
|
||||
.pull-12 {margin-left:-480px;}
|
||||
.pull-13 {margin-left:-520px;}
|
||||
.pull-14 {margin-left:-560px;}
|
||||
.pull-15 {margin-left:-600px;}
|
||||
.pull-16 {margin-left:-640px;}
|
||||
.pull-17 {margin-left:-680px;}
|
||||
.pull-18 {margin-left:-720px;}
|
||||
.pull-19 {margin-left:-760px;}
|
||||
.pull-20 {margin-left:-800px;}
|
||||
.pull-21 {margin-left:-840px;}
|
||||
.pull-22 {margin-left:-880px;}
|
||||
.pull-23 {margin-left:-920px;}
|
||||
.pull-24 {margin-left:-960px;}
|
||||
.pull-1, .pull-2, .pull-3, .pull-4, .pull-5, .pull-6, .pull-7, .pull-8, .pull-9, .pull-10, .pull-11, .pull-12, .pull-13, .pull-14, .pull-15, .pull-16, .pull-17, .pull-18, .pull-19, .pull-20, .pull-21, .pull-22, .pull-23, .pull-24 {float:left;position:relative;}
|
||||
.push-1 {margin:0 -40px 1.5em 40px;}
|
||||
.push-2 {margin:0 -80px 1.5em 80px;}
|
||||
.push-3 {margin:0 -120px 1.5em 120px;}
|
||||
.push-4 {margin:0 -160px 1.5em 160px;}
|
||||
.push-5 {margin:0 -200px 1.5em 200px;}
|
||||
.push-6 {margin:0 -240px 1.5em 240px;}
|
||||
.push-7 {margin:0 -280px 1.5em 280px;}
|
||||
.push-8 {margin:0 -320px 1.5em 320px;}
|
||||
.push-9 {margin:0 -360px 1.5em 360px;}
|
||||
.push-10 {margin:0 -400px 1.5em 400px;}
|
||||
.push-11 {margin:0 -440px 1.5em 440px;}
|
||||
.push-12 {margin:0 -480px 1.5em 480px;}
|
||||
.push-13 {margin:0 -520px 1.5em 520px;}
|
||||
.push-14 {margin:0 -560px 1.5em 560px;}
|
||||
.push-15 {margin:0 -600px 1.5em 600px;}
|
||||
.push-16 {margin:0 -640px 1.5em 640px;}
|
||||
.push-17 {margin:0 -680px 1.5em 680px;}
|
||||
.push-18 {margin:0 -720px 1.5em 720px;}
|
||||
.push-19 {margin:0 -760px 1.5em 760px;}
|
||||
.push-20 {margin:0 -800px 1.5em 800px;}
|
||||
.push-21 {margin:0 -840px 1.5em 840px;}
|
||||
.push-22 {margin:0 -880px 1.5em 880px;}
|
||||
.push-23 {margin:0 -920px 1.5em 920px;}
|
||||
.push-24 {margin:0 -960px 1.5em 960px;}
|
||||
.push-1, .push-2, .push-3, .push-4, .push-5, .push-6, .push-7, .push-8, .push-9, .push-10, .push-11, .push-12, .push-13, .push-14, .push-15, .push-16, .push-17, .push-18, .push-19, .push-20, .push-21, .push-22, .push-23, .push-24 {float:right;position:relative;}
|
||||
.prepend-top {margin-top:1.5em;}
|
||||
.append-bottom {margin-bottom:1.5em;}
|
||||
.box {padding:1.5em;margin-bottom:1.5em;background:#E5ECF9;}
|
||||
hr {background:#ddd;color:#ddd;clear:both;float:none;width:100%;height:.1em;margin:0 0 1.45em;border:none;}
|
||||
hr.space {background:#fff;color:#fff;visibility:hidden;}
|
||||
.clearfix:after, .container:after {content:"\0020";display:block;height:0;clear:both;visibility:hidden;overflow:hidden;}
|
||||
.clearfix, .container {display:block;}
|
||||
.clear {clear:both;}
|
||||
BIN
framework/gii/assets/images/logo.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
framework/gii/assets/js/fancybox/blank.gif
Normal file
|
After Width: | Height: | Size: 43 B |
BIN
framework/gii/assets/js/fancybox/fancy_close.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
framework/gii/assets/js/fancybox/fancy_loading.png
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
BIN
framework/gii/assets/js/fancybox/fancy_nav_left.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
framework/gii/assets/js/fancybox/fancy_nav_right.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
framework/gii/assets/js/fancybox/fancy_shadow_e.png
Normal file
|
After Width: | Height: | Size: 107 B |
BIN
framework/gii/assets/js/fancybox/fancy_shadow_n.png
Normal file
|
After Width: | Height: | Size: 101 B |
BIN
framework/gii/assets/js/fancybox/fancy_shadow_ne.png
Normal file
|
After Width: | Height: | Size: 313 B |
BIN
framework/gii/assets/js/fancybox/fancy_shadow_nw.png
Normal file
|
After Width: | Height: | Size: 310 B |
BIN
framework/gii/assets/js/fancybox/fancy_shadow_s.png
Normal file
|
After Width: | Height: | Size: 107 B |
BIN
framework/gii/assets/js/fancybox/fancy_shadow_se.png
Normal file
|
After Width: | Height: | Size: 330 B |
BIN
framework/gii/assets/js/fancybox/fancy_shadow_sw.png
Normal file
|
After Width: | Height: | Size: 317 B |
BIN
framework/gii/assets/js/fancybox/fancy_shadow_w.png
Normal file
|
After Width: | Height: | Size: 99 B |
BIN
framework/gii/assets/js/fancybox/fancy_title_left.png
Normal file
|
After Width: | Height: | Size: 496 B |
BIN
framework/gii/assets/js/fancybox/fancy_title_main.png
Normal file
|
After Width: | Height: | Size: 96 B |
BIN
framework/gii/assets/js/fancybox/fancy_title_over.png
Normal file
|
After Width: | Height: | Size: 68 B |
BIN
framework/gii/assets/js/fancybox/fancy_title_right.png
Normal file
|
After Width: | Height: | Size: 495 B |
BIN
framework/gii/assets/js/fancybox/fancybox-x.png
Normal file
|
After Width: | Height: | Size: 159 B |
BIN
framework/gii/assets/js/fancybox/fancybox-y.png
Normal file
|
After Width: | Height: | Size: 128 B |
BIN
framework/gii/assets/js/fancybox/fancybox.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
363
framework/gii/assets/js/fancybox/jquery.fancybox-1.3.1.css
Normal file
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* FancyBox - jQuery Plugin
|
||||
* Simple and fancy lightbox alternative
|
||||
*
|
||||
* Examples and documentation at: http://fancybox.net
|
||||
*
|
||||
* Copyright (c) 2008 - 2010 Janis Skarnelis
|
||||
*
|
||||
* Version: 1.3.1 (05/03/2010)
|
||||
* Requires: jQuery v1.3+
|
||||
*
|
||||
* Dual licensed under the MIT and GPL licenses:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*/
|
||||
|
||||
#fancybox-loading {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
margin-top: -20px;
|
||||
margin-left: -20px;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
z-index: 1104;
|
||||
display: none;
|
||||
}
|
||||
|
||||
* html #fancybox-loading { /* IE6 */
|
||||
position: absolute;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#fancybox-loading div {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 40px;
|
||||
height: 480px;
|
||||
background-image: url('fancybox.png');
|
||||
}
|
||||
|
||||
#fancybox-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background: #000;
|
||||
z-index: 1100;
|
||||
display: none;
|
||||
}
|
||||
|
||||
* html #fancybox-overlay { /* IE6 */
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#fancybox-tmp {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
overflow: auto;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fancybox-wrap {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
z-index: 1101;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fancybox-outer {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #FFF;
|
||||
}
|
||||
|
||||
#fancybox-inner {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
outline: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#fancybox-hide-sel-frame {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
#fancybox-close {
|
||||
position: absolute;
|
||||
top: -15px;
|
||||
right: -15px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background-image: url('fancybox.png');
|
||||
background-position: -40px 0px;
|
||||
cursor: pointer;
|
||||
z-index: 1103;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fancybox_error {
|
||||
color: #444;
|
||||
font: normal 12px/20px Arial;
|
||||
padding: 7px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#fancybox-content {
|
||||
height: auto;
|
||||
width: auto;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#fancybox-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
outline: none;
|
||||
line-height: 0;
|
||||
vertical-align: top;
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
|
||||
#fancybox-frame {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#fancybox-title {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
font-family: Arial;
|
||||
font-size: 12px;
|
||||
z-index: 1102;
|
||||
}
|
||||
|
||||
.fancybox-title-inside {
|
||||
padding: 10px 0;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.fancybox-title-outside {
|
||||
padding-top: 5px;
|
||||
color: #FFF;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.fancybox-title-over {
|
||||
color: #FFF;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#fancybox-title-over {
|
||||
padding: 10px;
|
||||
background-image: url('fancy_title_over.png');
|
||||
display: block;
|
||||
}
|
||||
|
||||
#fancybox-title-wrap {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#fancybox-title-wrap span {
|
||||
height: 32px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#fancybox-title-left {
|
||||
padding-left: 15px;
|
||||
background-image: url('fancybox.png');
|
||||
background-position: -40px -90px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
#fancybox-title-main {
|
||||
font-weight: bold;
|
||||
line-height: 29px;
|
||||
background-image: url('fancybox-x.png');
|
||||
background-position: 0px -40px;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
#fancybox-title-right {
|
||||
padding-left: 15px;
|
||||
background-image: url('fancybox.png');
|
||||
background-position: -55px -90px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
#fancybox-left, #fancybox-right {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
height: 100%;
|
||||
width: 35%;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
background-image: url('blank.gif');
|
||||
z-index: 1102;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fancybox-left {
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
#fancybox-right {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
#fancybox-left-ico, #fancybox-right-ico {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: -9999px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-top: -15px;
|
||||
cursor: pointer;
|
||||
z-index: 1102;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#fancybox-left-ico {
|
||||
background-image: url('fancybox.png');
|
||||
background-position: -40px -30px;
|
||||
}
|
||||
|
||||
#fancybox-right-ico {
|
||||
background-image: url('fancybox.png');
|
||||
background-position: -40px -60px;
|
||||
}
|
||||
|
||||
#fancybox-left:hover, #fancybox-right:hover {
|
||||
visibility: visible; /* IE6 */
|
||||
}
|
||||
|
||||
#fancybox-left:hover span {
|
||||
left: 20px;
|
||||
}
|
||||
|
||||
#fancybox-right:hover span {
|
||||
left: auto;
|
||||
right: 20px;
|
||||
}
|
||||
|
||||
.fancy-bg {
|
||||
position: absolute;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
#fancy-bg-n {
|
||||
top: -20px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-image: url('fancybox-x.png');
|
||||
}
|
||||
|
||||
#fancy-bg-ne {
|
||||
top: -20px;
|
||||
right: -20px;
|
||||
background-image: url('fancybox.png');
|
||||
background-position: -40px -162px;
|
||||
}
|
||||
|
||||
#fancy-bg-e {
|
||||
top: 0;
|
||||
right: -20px;
|
||||
height: 100%;
|
||||
background-image: url('fancybox-y.png');
|
||||
background-position: -20px 0px;
|
||||
}
|
||||
|
||||
#fancy-bg-se {
|
||||
bottom: -20px;
|
||||
right: -20px;
|
||||
background-image: url('fancybox.png');
|
||||
background-position: -40px -182px;
|
||||
}
|
||||
|
||||
#fancy-bg-s {
|
||||
bottom: -20px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-image: url('fancybox-x.png');
|
||||
background-position: 0px -20px;
|
||||
}
|
||||
|
||||
#fancy-bg-sw {
|
||||
bottom: -20px;
|
||||
left: -20px;
|
||||
background-image: url('fancybox.png');
|
||||
background-position: -40px -142px;
|
||||
}
|
||||
|
||||
#fancy-bg-w {
|
||||
top: 0;
|
||||
left: -20px;
|
||||
height: 100%;
|
||||
background-image: url('fancybox-y.png');
|
||||
}
|
||||
|
||||
#fancy-bg-nw {
|
||||
top: -20px;
|
||||
left: -20px;
|
||||
background-image: url('fancybox.png');
|
||||
background-position: -40px -122px;
|
||||
}
|
||||
|
||||
/* IE */
|
||||
|
||||
#fancybox-loading.fancybox-ie div { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_loading.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancybox-close { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_close.png', sizingMethod='scale'); }
|
||||
|
||||
.fancybox-ie #fancybox-title-over { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_over.png', sizingMethod='scale'); zoom: 1; }
|
||||
.fancybox-ie #fancybox-title-left { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_left.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancybox-title-main { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_main.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancybox-title-right { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_right.png', sizingMethod='scale'); }
|
||||
|
||||
.fancybox-ie #fancybox-left-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_left.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancybox-right-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_right.png', sizingMethod='scale'); }
|
||||
|
||||
.fancybox-ie .fancy-bg { background: transparent !important; }
|
||||
|
||||
.fancybox-ie #fancy-bg-n { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_n.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancy-bg-ne { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_ne.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancy-bg-e { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_e.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancy-bg-se { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_se.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancy-bg-s { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_s.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancy-bg-sw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_sw.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancy-bg-w { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_w.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancy-bg-nw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_nw.png', sizingMethod='scale'); }
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* FancyBox - jQuery Plugin
|
||||
* Simple and fancy lightbox alternative
|
||||
*
|
||||
* Examples and documentation at: http://fancybox.net
|
||||
*
|
||||
* Copyright (c) 2008 - 2010 Janis Skarnelis
|
||||
*
|
||||
* Version: 1.3.1 (05/03/2010)
|
||||
* Requires: jQuery v1.3+
|
||||
*
|
||||
* Dual licensed under the MIT and GPL licenses:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*/
|
||||
|
||||
(function(b){var m,u,x,g,D,i,z,A,B,p=0,e={},q=[],n=0,c={},j=[],E=null,s=new Image,G=/\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,S=/[^\.]\.(swf)\s*$/i,H,I=1,k,l,h=false,y=b.extend(b("<div/>")[0],{prop:0}),v=0,O=!b.support.opacity&&!window.XMLHttpRequest,J=function(){u.hide();s.onerror=s.onload=null;E&&E.abort();m.empty()},P=function(){b.fancybox('<p id="fancybox_error">The requested content cannot be loaded.<br />Please try again later.</p>',{scrolling:"no",padding:20,transitionIn:"none",transitionOut:"none"})},
|
||||
K=function(){return[b(window).width(),b(window).height(),b(document).scrollLeft(),b(document).scrollTop()]},T=function(){var a=K(),d={},f=c.margin,o=c.autoScale,t=(20+f)*2,w=(20+f)*2,r=c.padding*2;if(c.width.toString().indexOf("%")>-1){d.width=a[0]*parseFloat(c.width)/100-40;o=false}else d.width=c.width+r;if(c.height.toString().indexOf("%")>-1){d.height=a[1]*parseFloat(c.height)/100-40;o=false}else d.height=c.height+r;if(o&&(d.width>a[0]-t||d.height>a[1]-w))if(e.type=="image"||e.type=="swf"){t+=r;
|
||||
w+=r;o=Math.min(Math.min(a[0]-t,c.width)/c.width,Math.min(a[1]-w,c.height)/c.height);d.width=Math.round(o*(d.width-r))+r;d.height=Math.round(o*(d.height-r))+r}else{d.width=Math.min(d.width,a[0]-t);d.height=Math.min(d.height,a[1]-w)}d.top=a[3]+(a[1]-(d.height+40))*0.5;d.left=a[2]+(a[0]-(d.width+40))*0.5;if(c.autoScale===false){d.top=Math.max(a[3]+f,d.top);d.left=Math.max(a[2]+f,d.left)}return d},U=function(a){if(a&&a.length)switch(c.titlePosition){case "inside":return a;case "over":return'<span id="fancybox-title-over">'+
|
||||
a+"</span>";default:return'<span id="fancybox-title-wrap"><span id="fancybox-title-left"></span><span id="fancybox-title-main">'+a+'</span><span id="fancybox-title-right"></span></span>'}return false},V=function(){var a=c.title,d=l.width-c.padding*2,f="fancybox-title-"+c.titlePosition;b("#fancybox-title").remove();v=0;if(c.titleShow!==false){a=b.isFunction(c.titleFormat)?c.titleFormat(a,j,n,c):U(a);if(!(!a||a==="")){b('<div id="fancybox-title" class="'+f+'" />').css({width:d,paddingLeft:c.padding,
|
||||
paddingRight:c.padding}).html(a).appendTo("body");switch(c.titlePosition){case "inside":v=b("#fancybox-title").outerHeight(true)-c.padding;l.height+=v;break;case "over":b("#fancybox-title").css("bottom",c.padding);break;default:b("#fancybox-title").css("bottom",b("#fancybox-title").outerHeight(true)*-1);break}b("#fancybox-title").appendTo(D).hide()}}},W=function(){b(document).unbind("keydown.fb").bind("keydown.fb",function(a){if(a.keyCode==27&&c.enableEscapeButton){a.preventDefault();b.fancybox.close()}else if(a.keyCode==
|
||||
37){a.preventDefault();b.fancybox.prev()}else if(a.keyCode==39){a.preventDefault();b.fancybox.next()}});if(b.fn.mousewheel){g.unbind("mousewheel.fb");j.length>1&&g.bind("mousewheel.fb",function(a,d){a.preventDefault();h||d===0||(d>0?b.fancybox.prev():b.fancybox.next())})}if(c.showNavArrows){if(c.cyclic&&j.length>1||n!==0)A.show();if(c.cyclic&&j.length>1||n!=j.length-1)B.show()}},X=function(){var a,d;if(j.length-1>n){a=j[n+1].href;if(typeof a!=="undefined"&&a.match(G)){d=new Image;d.src=a}}if(n>0){a=
|
||||
j[n-1].href;if(typeof a!=="undefined"&&a.match(G)){d=new Image;d.src=a}}},L=function(){i.css("overflow",c.scrolling=="auto"?c.type=="image"||c.type=="iframe"||c.type=="swf"?"hidden":"auto":c.scrolling=="yes"?"auto":"visible");if(!b.support.opacity){i.get(0).style.removeAttribute("filter");g.get(0).style.removeAttribute("filter")}b("#fancybox-title").show();c.hideOnContentClick&&i.one("click",b.fancybox.close);c.hideOnOverlayClick&&x.one("click",b.fancybox.close);c.showCloseButton&&z.show();W();b(window).bind("resize.fb",
|
||||
b.fancybox.center);c.centerOnScroll?b(window).bind("scroll.fb",b.fancybox.center):b(window).unbind("scroll.fb");b.isFunction(c.onComplete)&&c.onComplete(j,n,c);h=false;X()},M=function(a){var d=Math.round(k.width+(l.width-k.width)*a),f=Math.round(k.height+(l.height-k.height)*a),o=Math.round(k.top+(l.top-k.top)*a),t=Math.round(k.left+(l.left-k.left)*a);g.css({width:d+"px",height:f+"px",top:o+"px",left:t+"px"});d=Math.max(d-c.padding*2,0);f=Math.max(f-(c.padding*2+v*a),0);i.css({width:d+"px",height:f+
|
||||
"px"});if(typeof l.opacity!=="undefined")g.css("opacity",a<0.5?0.5:a)},Y=function(a){var d=a.offset();d.top+=parseFloat(a.css("paddingTop"))||0;d.left+=parseFloat(a.css("paddingLeft"))||0;d.top+=parseFloat(a.css("border-top-width"))||0;d.left+=parseFloat(a.css("border-left-width"))||0;d.width=a.width();d.height=a.height();return d},Q=function(){var a=e.orig?b(e.orig):false,d={};if(a&&a.length){a=Y(a);d={width:a.width+c.padding*2,height:a.height+c.padding*2,top:a.top-c.padding-20,left:a.left-c.padding-
|
||||
20}}else{a=K();d={width:1,height:1,top:a[3]+a[1]*0.5,left:a[2]+a[0]*0.5}}return d},N=function(){u.hide();if(g.is(":visible")&&b.isFunction(c.onCleanup))if(c.onCleanup(j,n,c)===false){b.event.trigger("fancybox-cancel");h=false;return}j=q;n=p;c=e;i.get(0).scrollTop=0;i.get(0).scrollLeft=0;if(c.overlayShow){O&&b("select:not(#fancybox-tmp select)").filter(function(){return this.style.visibility!=="hidden"}).css({visibility:"hidden"}).one("fancybox-cleanup",function(){this.style.visibility="inherit"});
|
||||
x.css({"background-color":c.overlayColor,opacity:c.overlayOpacity}).unbind().show()}l=T();V();if(g.is(":visible")){b(z.add(A).add(B)).hide();var a=g.position(),d;k={top:a.top,left:a.left,width:g.width(),height:g.height()};d=k.width==l.width&&k.height==l.height;i.fadeOut(c.changeFade,function(){var f=function(){i.html(m.contents()).fadeIn(c.changeFade,L)};b.event.trigger("fancybox-change");i.empty().css("overflow","hidden");if(d){i.css({top:c.padding,left:c.padding,width:Math.max(l.width-c.padding*
|
||||
2,1),height:Math.max(l.height-c.padding*2-v,1)});f()}else{i.css({top:c.padding,left:c.padding,width:Math.max(k.width-c.padding*2,1),height:Math.max(k.height-c.padding*2,1)});y.prop=0;b(y).animate({prop:1},{duration:c.changeSpeed,easing:c.easingChange,step:M,complete:f})}})}else{g.css("opacity",1);if(c.transitionIn=="elastic"){k=Q();i.css({top:c.padding,left:c.padding,width:Math.max(k.width-c.padding*2,1),height:Math.max(k.height-c.padding*2,1)}).html(m.contents());g.css(k).show();if(c.opacity)l.opacity=
|
||||
0;y.prop=0;b(y).animate({prop:1},{duration:c.speedIn,easing:c.easingIn,step:M,complete:L})}else{i.css({top:c.padding,left:c.padding,width:Math.max(l.width-c.padding*2,1),height:Math.max(l.height-c.padding*2-v,1)}).html(m.contents());g.css(l).fadeIn(c.transitionIn=="none"?0:c.speedIn,L)}}},F=function(){m.width(e.width);m.height(e.height);if(e.width=="auto")e.width=m.width();if(e.height=="auto")e.height=m.height();N()},Z=function(){h=true;e.width=s.width;e.height=s.height;b("<img />").attr({id:"fancybox-img",
|
||||
src:s.src,alt:e.title}).appendTo(m);N()},C=function(){J();var a=q[p],d,f,o,t,w;e=b.extend({},b.fn.fancybox.defaults,typeof b(a).data("fancybox")=="undefined"?e:b(a).data("fancybox"));o=a.title||b(a).title||e.title||"";if(a.nodeName&&!e.orig)e.orig=b(a).children("img:first").length?b(a).children("img:first"):b(a);if(o===""&&e.orig)o=e.orig.attr("alt");d=a.nodeName&&/^(?:javascript|#)/i.test(a.href)?e.href||null:e.href||a.href||null;if(e.type){f=e.type;if(!d)d=e.content}else if(e.content)f="html";else if(d)if(d.match(G))f=
|
||||
"image";else if(d.match(S))f="swf";else if(b(a).hasClass("iframe"))f="iframe";else if(d.match(/#/)){a=d.substr(d.indexOf("#"));f=b(a).length>0?"inline":"ajax"}else f="ajax";else f="inline";e.type=f;e.href=d;e.title=o;if(e.autoDimensions&&e.type!=="iframe"&&e.type!=="swf"){e.width="auto";e.height="auto"}if(e.modal){e.overlayShow=true;e.hideOnOverlayClick=false;e.hideOnContentClick=false;e.enableEscapeButton=false;e.showCloseButton=false}if(b.isFunction(e.onStart))if(e.onStart(q,p,e)===false){h=false;
|
||||
return}m.css("padding",20+e.padding+e.margin);b(".fancybox-inline-tmp").unbind("fancybox-cancel").bind("fancybox-change",function(){b(this).replaceWith(i.children())});switch(f){case "html":m.html(e.content);F();break;case "inline":b('<div class="fancybox-inline-tmp" />').hide().insertBefore(b(a)).bind("fancybox-cleanup",function(){b(this).replaceWith(i.children())}).bind("fancybox-cancel",function(){b(this).replaceWith(m.children())});b(a).appendTo(m);F();break;case "image":h=false;b.fancybox.showActivity();
|
||||
s=new Image;s.onerror=function(){P()};s.onload=function(){s.onerror=null;s.onload=null;Z()};s.src=d;break;case "swf":t='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+e.width+'" height="'+e.height+'"><param name="movie" value="'+d+'"></param>';w="";b.each(e.swf,function(r,R){t+='<param name="'+r+'" value="'+R+'"></param>';w+=" "+r+'="'+R+'"'});t+='<embed src="'+d+'" type="application/x-shockwave-flash" width="'+e.width+'" height="'+e.height+'"'+w+"></embed></object>";m.html(t);
|
||||
F();break;case "ajax":a=d.split("#",2);f=e.ajax.data||{};if(a.length>1){d=a[0];if(typeof f=="string")f+="&selector="+a[1];else f.selector=a[1]}h=false;b.fancybox.showActivity();E=b.ajax(b.extend(e.ajax,{url:d,data:f,error:P,success:function(r){if(E.status==200){m.html(r);F()}}}));break;case "iframe":b('<iframe id="fancybox-frame" name="fancybox-frame'+(new Date).getTime()+'" frameborder="0" hspace="0" scrolling="'+e.scrolling+'" src="'+e.href+'"></iframe>').appendTo(m);N();break}},$=function(){if(u.is(":visible")){b("div",
|
||||
u).css("top",I*-40+"px");I=(I+1)%12}else clearInterval(H)},aa=function(){if(!b("#fancybox-wrap").length){b("body").append(m=b('<div id="fancybox-tmp"></div>'),u=b('<div id="fancybox-loading"><div></div></div>'),x=b('<div id="fancybox-overlay"></div>'),g=b('<div id="fancybox-wrap"></div>'));if(!b.support.opacity){g.addClass("fancybox-ie");u.addClass("fancybox-ie")}D=b('<div id="fancybox-outer"></div>').append('<div class="fancy-bg" id="fancy-bg-n"></div><div class="fancy-bg" id="fancy-bg-ne"></div><div class="fancy-bg" id="fancy-bg-e"></div><div class="fancy-bg" id="fancy-bg-se"></div><div class="fancy-bg" id="fancy-bg-s"></div><div class="fancy-bg" id="fancy-bg-sw"></div><div class="fancy-bg" id="fancy-bg-w"></div><div class="fancy-bg" id="fancy-bg-nw"></div>').appendTo(g);
|
||||
D.append(i=b('<div id="fancybox-inner"></div>'),z=b('<a id="fancybox-close"></a>'),A=b('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),B=b('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>'));z.click(b.fancybox.close);u.click(b.fancybox.cancel);A.click(function(a){a.preventDefault();b.fancybox.prev()});B.click(function(a){a.preventDefault();b.fancybox.next()});if(O){x.get(0).style.setExpression("height",
|
||||
"document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'");u.get(0).style.setExpression("top","(-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px'");D.prepend('<iframe id="fancybox-hide-sel-frame" src="javascript:\'\';" scrolling="no" frameborder="0" ></iframe>')}}};
|
||||
b.fn.fancybox=function(a){b(this).data("fancybox",b.extend({},a,b.metadata?b(this).metadata():{})).unbind("click.fb").bind("click.fb",function(d){d.preventDefault();if(!h){h=true;b(this).blur();q=[];p=0;d=b(this).attr("rel")||"";if(!d||d==""||d==="nofollow")q.push(this);else{q=b("a[rel="+d+"], area[rel="+d+"]");p=q.index(this)}C();return false}});return this};b.fancybox=function(a,d){if(!h){h=true;d=typeof d!=="undefined"?d:{};q=[];p=d.index||0;if(b.isArray(a)){for(var f=0,o=a.length;f<o;f++)if(typeof a[f]==
|
||||
"object")b(a[f]).data("fancybox",b.extend({},d,a[f]));else a[f]=b({}).data("fancybox",b.extend({content:a[f]},d));q=jQuery.merge(q,a)}else{if(typeof a=="object")b(a).data("fancybox",b.extend({},d,a));else a=b({}).data("fancybox",b.extend({content:a},d));q.push(a)}if(p>q.length||p<0)p=0;C()}};b.fancybox.showActivity=function(){clearInterval(H);u.show();H=setInterval($,66)};b.fancybox.hideActivity=function(){u.hide()};b.fancybox.next=function(){return b.fancybox.pos(n+1)};b.fancybox.prev=function(){return b.fancybox.pos(n-
|
||||
1)};b.fancybox.pos=function(a){if(!h){a=parseInt(a,10);if(a>-1&&j.length>a){p=a;C()}if(c.cyclic&&j.length>1&&a<0){p=j.length-1;C()}if(c.cyclic&&j.length>1&&a>=j.length){p=0;C()}}};b.fancybox.cancel=function(){if(!h){h=true;b.event.trigger("fancybox-cancel");J();e&&b.isFunction(e.onCancel)&&e.onCancel(q,p,e);h=false}};b.fancybox.close=function(){function a(){x.fadeOut("fast");g.hide();b.event.trigger("fancybox-cleanup");i.empty();b.isFunction(c.onClosed)&&c.onClosed(j,n,c);j=e=[];n=p=0;c=e={};h=false}
|
||||
if(!(h||g.is(":hidden"))){h=true;if(c&&b.isFunction(c.onCleanup))if(c.onCleanup(j,n,c)===false){h=false;return}J();b(z.add(A).add(B)).hide();b("#fancybox-title").remove();g.add(i).add(x).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");i.css("overflow","hidden");if(c.transitionOut=="elastic"){k=Q();var d=g.position();l={top:d.top,left:d.left,width:g.width(),height:g.height()};if(c.opacity)l.opacity=1;y.prop=1;b(y).animate({prop:0},{duration:c.speedOut,easing:c.easingOut,
|
||||
step:M,complete:a})}else g.fadeOut(c.transitionOut=="none"?0:c.speedOut,a)}};b.fancybox.resize=function(){var a,d;if(!(h||g.is(":hidden"))){h=true;a=i.wrapInner("<div style='overflow:auto'></div>").children();d=a.height();g.css({height:d+c.padding*2+v});i.css({height:d});a.replaceWith(a.children());b.fancybox.center()}};b.fancybox.center=function(){h=true;var a=K(),d=c.margin,f={};f.top=a[3]+(a[1]-(g.height()-v+40))*0.5;f.left=a[2]+(a[0]-(g.width()+40))*0.5;f.top=Math.max(a[3]+d,f.top);f.left=Math.max(a[2]+
|
||||
d,f.left);g.css(f);h=false};b.fn.fancybox.defaults={padding:10,margin:20,opacity:false,modal:false,cyclic:false,scrolling:"auto",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:"transparent"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.3,overlayColor:"#666",titleShow:true,titlePosition:"outside",titleFormat:null,transitionIn:"fade",transitionOut:"fade",speedIn:300,speedOut:300,changeSpeed:300,changeFade:"fast",
|
||||
easingIn:"swing",easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,onStart:null,onCancel:null,onComplete:null,onCleanup:null,onClosed:null};b(document).ready(function(){aa()})})(jQuery);
|
||||
79
framework/gii/assets/js/main.js
Normal file
@@ -0,0 +1,79 @@
|
||||
$(document).ready(function() {
|
||||
if($('div.form.login').length) { // in login page
|
||||
$('input#LoginForm_password').focus();
|
||||
}
|
||||
|
||||
$('table.preview input[name="checkAll"]').click(function() {
|
||||
$('table.preview .confirm input').prop('checked', this.checked);
|
||||
});
|
||||
|
||||
$('table.preview td.confirm input').click(function() {
|
||||
$('table.preview input[name="checkAll"]').prop('checked', !$('table.preview td.confirm input:not(:checked)').length);
|
||||
});
|
||||
$('table.preview input[name="checkAll"]').prop('checked', !$('table.preview td.confirm input:not(:checked)').length);
|
||||
|
||||
$('.form .row.sticky input:not(.error), .form .row.sticky select:not(.error), .form .row.sticky textarea:not(.error)').each(function(){
|
||||
var value;
|
||||
if(this.tagName=='SELECT')
|
||||
value=this.options[this.selectedIndex].text;
|
||||
else if(this.tagName=='TEXTAREA')
|
||||
value=$(this).html();
|
||||
else
|
||||
value=$(this).val();
|
||||
if(value=='')
|
||||
value='[empty]';
|
||||
$(this).before('<div class="value">'+value+'</div>').hide();
|
||||
});
|
||||
|
||||
$(document).on('click', '.form.gii .row.sticky .value', function(){
|
||||
$(this).hide();
|
||||
$(this).next().show().get(0).focus();
|
||||
});
|
||||
|
||||
|
||||
$('.form.gii .row input, .form.gii .row textarea, .form.gii .row select, .with-tooltip').not('.no-tooltip, .no-tooltip *').tooltip2({
|
||||
position: "center right",
|
||||
offset: [-2, 10]
|
||||
});
|
||||
|
||||
$('.form.gii .row input').change(function(){
|
||||
$('.form.gii .feedback').hide();
|
||||
$('.form.gii input[name="generate"]').hide();
|
||||
});
|
||||
|
||||
$('.form.gii .view-code').click(function(){
|
||||
var title=$(this).attr('rel');
|
||||
$.fancybox.showActivity();
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
cache: false,
|
||||
url: $(this).attr('href'),
|
||||
data: $('.form.gii form').serializeArray(),
|
||||
success: function(data){
|
||||
$.fancybox(data, {
|
||||
'title': title,
|
||||
'titlePosition': 'inside',
|
||||
'titleFormat': function(title, currentArray, currentIndex, currentOpts) {
|
||||
return '<div id="tip7-title"><span><a href="javascript:;" onclick="$.fancybox.close();">close</a></span>' + (title && title.length ? '<b>' + title + '</b>' : '' ) + '</div>';
|
||||
},
|
||||
'showCloseButton': false,
|
||||
'autoDimensions': false,
|
||||
'width': 900,
|
||||
'height': 'auto',
|
||||
'onComplete':function(){
|
||||
$('#fancybox-inner').scrollTop(0);
|
||||
}
|
||||
});
|
||||
},
|
||||
error: function(XMLHttpRequest, textStatus, errorThrown) {
|
||||
$.fancybox('<div class="error">'+XMLHttpRequest.responseText+'</div>');
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
$(document).on('click', '#fancybox-inner .close-code', function(){
|
||||
$.fancybox.close();
|
||||
return false;
|
||||
});
|
||||
});
|
||||
364
framework/gii/assets/js/tooltip.js
Normal file
@@ -0,0 +1,364 @@
|
||||
/**
|
||||
* CHANGES MADE BY YII DEVELOPERS, READ CAREFULLY BEFORE UPGRADING THIS FILE:
|
||||
* 1. This commit has been used:
|
||||
* https://github.com/jquerytools/jquerytools/commit/4f3f3f14e83b0ff276a795e9f45400930904adff#src/tooltip/tooltip.js
|
||||
* 2. Original `$.fn.tooltip` has been changed to `$.fn.tooltip2` to prevent conflict between jQuery UI Tooltip and
|
||||
* jQuery Tools Tooltip.
|
||||
*
|
||||
* @license
|
||||
* jQuery Tools @VERSION Tooltip - UI essentials
|
||||
*
|
||||
* NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
|
||||
*
|
||||
* http://flowplayer.org/tools/tooltip/
|
||||
*
|
||||
* Since: November 2008
|
||||
* Date: @DATE
|
||||
*/
|
||||
(function($) {
|
||||
// static constructs
|
||||
$.tools = $.tools || {version: '@VERSION'};
|
||||
|
||||
$.tools.tooltip = {
|
||||
|
||||
conf: {
|
||||
|
||||
// default effect variables
|
||||
effect: 'toggle',
|
||||
fadeOutSpeed: "fast",
|
||||
predelay: 0,
|
||||
delay: 30,
|
||||
opacity: 1,
|
||||
tip: 0,
|
||||
fadeIE: false, // enables fade effect in IE
|
||||
|
||||
// 'top', 'bottom', 'right', 'left', 'center'
|
||||
position: ['top', 'center'],
|
||||
offset: [0, 0],
|
||||
relative: false,
|
||||
cancelDefault: true,
|
||||
|
||||
// type to event mapping
|
||||
events: {
|
||||
def: "mouseenter,mouseleave",
|
||||
input: "focus,blur",
|
||||
widget: "focus mouseenter,blur mouseleave",
|
||||
tooltip: "mouseenter,mouseleave"
|
||||
},
|
||||
|
||||
// 1.2
|
||||
layout: '<div/>',
|
||||
tipClass: 'tooltip'
|
||||
},
|
||||
|
||||
addEffect: function(name, loadFn, hideFn) {
|
||||
effects[name] = [loadFn, hideFn];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var effects = {
|
||||
toggle: [
|
||||
function(done) {
|
||||
var conf = this.getConf(), tip = this.getTip(), o = conf.opacity;
|
||||
if (o < 1) { tip.css({opacity: o}); }
|
||||
tip.show();
|
||||
done.call();
|
||||
},
|
||||
|
||||
function(done) {
|
||||
this.getTip().hide();
|
||||
done.call();
|
||||
}
|
||||
],
|
||||
|
||||
fade: [
|
||||
function(done) {
|
||||
var conf = this.getConf();
|
||||
if (!$.browser.msie || conf.fadeIE) {
|
||||
this.getTip().fadeTo(conf.fadeInSpeed, conf.opacity, done);
|
||||
}
|
||||
else {
|
||||
this.getTip().show();
|
||||
done();
|
||||
}
|
||||
},
|
||||
function(done) {
|
||||
var conf = this.getConf();
|
||||
if (!$.browser.msie || conf.fadeIE) {
|
||||
this.getTip().fadeOut(conf.fadeOutSpeed, done);
|
||||
}
|
||||
else {
|
||||
this.getTip().hide();
|
||||
done();
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
/* calculate tip position relative to the trigger */
|
||||
function getPosition(trigger, tip, conf) {
|
||||
|
||||
|
||||
// get origin top/left position
|
||||
var top = conf.relative ? trigger.position().top : trigger.offset().top,
|
||||
left = conf.relative ? trigger.position().left : trigger.offset().left,
|
||||
pos = conf.position[0];
|
||||
|
||||
top -= tip.outerHeight() - conf.offset[0];
|
||||
left += trigger.outerWidth() + conf.offset[1];
|
||||
|
||||
// iPad position fix
|
||||
if (/iPad/i.test(navigator.userAgent)) {
|
||||
top -= $(window).scrollTop();
|
||||
}
|
||||
|
||||
// adjust Y
|
||||
var height = tip.outerHeight() + trigger.outerHeight();
|
||||
if (pos == 'center') { top += height / 2; }
|
||||
if (pos == 'bottom') { top += height; }
|
||||
|
||||
|
||||
// adjust X
|
||||
pos = conf.position[1];
|
||||
var width = tip.outerWidth() + trigger.outerWidth();
|
||||
if (pos == 'center') { left -= width / 2; }
|
||||
if (pos == 'left') { left -= width; }
|
||||
|
||||
return {top: top, left: left};
|
||||
}
|
||||
|
||||
|
||||
|
||||
function Tooltip(trigger, conf) {
|
||||
|
||||
var self = this,
|
||||
fire = trigger.add(self),
|
||||
tip,
|
||||
timer = 0,
|
||||
pretimer = 0,
|
||||
title = trigger.attr("title"),
|
||||
tipAttr = trigger.attr("data-tooltip"),
|
||||
effect = effects[conf.effect],
|
||||
shown,
|
||||
|
||||
// get show/hide configuration
|
||||
isInput = trigger.is(":input"),
|
||||
isWidget = isInput && trigger.is(":checkbox, :radio, select, :button, :submit"),
|
||||
type = trigger.attr("type"),
|
||||
evt = conf.events[type] || conf.events[isInput ? (isWidget ? 'widget' : 'input') : 'def'];
|
||||
|
||||
|
||||
// check that configuration is sane
|
||||
if (!effect) { throw "Nonexistent effect \"" + conf.effect + "\""; }
|
||||
|
||||
evt = evt.split(/,\s*/);
|
||||
if (evt.length != 2) { throw "Tooltip: bad events configuration for " + type; }
|
||||
|
||||
|
||||
// trigger --> show
|
||||
trigger.on(evt[0], function(e) {
|
||||
|
||||
clearTimeout(timer);
|
||||
if (conf.predelay) {
|
||||
pretimer = setTimeout(function() { self.show(e); }, conf.predelay);
|
||||
|
||||
} else {
|
||||
self.show(e);
|
||||
}
|
||||
|
||||
// trigger --> hide
|
||||
}).on(evt[1], function(e) {
|
||||
clearTimeout(pretimer);
|
||||
if (conf.delay) {
|
||||
timer = setTimeout(function() { self.hide(e); }, conf.delay);
|
||||
|
||||
} else {
|
||||
self.hide(e);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
// remove default title
|
||||
if (title && conf.cancelDefault) {
|
||||
trigger.removeAttr("title");
|
||||
trigger.data("title", title);
|
||||
}
|
||||
|
||||
$.extend(self, {
|
||||
|
||||
show: function(e) {
|
||||
|
||||
// tip not initialized yet
|
||||
if (!tip) {
|
||||
|
||||
// data-tooltip
|
||||
if (tipAttr) {
|
||||
tip = $(tipAttr);
|
||||
|
||||
// single tip element for all
|
||||
} else if (conf.tip) {
|
||||
tip = $(conf.tip).eq(0);
|
||||
|
||||
// autogenerated tooltip
|
||||
} else if (title) {
|
||||
tip = $(conf.layout).addClass(conf.tipClass).appendTo(document.body)
|
||||
.hide().append(title);
|
||||
|
||||
// manual tooltip
|
||||
} else {
|
||||
tip = trigger.next();
|
||||
if (!tip.length) { tip = trigger.parent().next(); }
|
||||
}
|
||||
|
||||
if (!tip.length) { throw "Cannot find tooltip for " + trigger; }
|
||||
}
|
||||
|
||||
if (self.isShown()) { return self; }
|
||||
|
||||
// stop previous animation
|
||||
tip.stop(true, true);
|
||||
|
||||
// get position
|
||||
var pos = getPosition(trigger, tip, conf);
|
||||
|
||||
// restore title for single tooltip element
|
||||
if (conf.tip) {
|
||||
tip.html(trigger.data("title"));
|
||||
}
|
||||
|
||||
// onBeforeShow
|
||||
e = $.Event();
|
||||
e.type = "onBeforeShow";
|
||||
fire.trigger(e, [pos]);
|
||||
if (e.isDefaultPrevented()) { return self; }
|
||||
|
||||
|
||||
// onBeforeShow may have altered the configuration
|
||||
pos = getPosition(trigger, tip, conf);
|
||||
|
||||
// set position
|
||||
tip.css({position:'absolute', top: pos.top, left: pos.left});
|
||||
|
||||
shown = true;
|
||||
|
||||
// invoke effect
|
||||
effect[0].call(self, function() {
|
||||
e.type = "onShow";
|
||||
shown = 'full';
|
||||
fire.trigger(e);
|
||||
});
|
||||
|
||||
|
||||
// tooltip events
|
||||
var event = conf.events.tooltip.split(/,\s*/);
|
||||
|
||||
if (!tip.data("__set")) {
|
||||
|
||||
tip.off(event[0]).on(event[0], function() {
|
||||
clearTimeout(timer);
|
||||
clearTimeout(pretimer);
|
||||
});
|
||||
|
||||
if (event[1] && !trigger.is("input:not(:checkbox, :radio), textarea")) {
|
||||
tip.off(event[1]).on(event[1], function(e) {
|
||||
|
||||
// being moved to the trigger element
|
||||
if (e.relatedTarget != trigger[0]) {
|
||||
trigger.trigger(evt[1].split(" ")[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// bind agein for if same tip element
|
||||
if (!conf.tip) tip.data("__set", true);
|
||||
}
|
||||
|
||||
return self;
|
||||
},
|
||||
|
||||
hide: function(e) {
|
||||
|
||||
if (!tip || !self.isShown()) { return self; }
|
||||
|
||||
// onBeforeHide
|
||||
e = $.Event();
|
||||
e.type = "onBeforeHide";
|
||||
fire.trigger(e);
|
||||
if (e.isDefaultPrevented()) { return; }
|
||||
|
||||
shown = false;
|
||||
|
||||
effects[conf.effect][1].call(self, function() {
|
||||
e.type = "onHide";
|
||||
fire.trigger(e);
|
||||
});
|
||||
|
||||
return self;
|
||||
},
|
||||
|
||||
isShown: function(fully) {
|
||||
return fully ? shown == 'full' : shown;
|
||||
},
|
||||
|
||||
getConf: function() {
|
||||
return conf;
|
||||
},
|
||||
|
||||
getTip: function() {
|
||||
return tip;
|
||||
},
|
||||
|
||||
getTrigger: function() {
|
||||
return trigger;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// callbacks
|
||||
$.each("onHide,onBeforeShow,onShow,onBeforeHide".split(","), function(i, name) {
|
||||
|
||||
// configuration
|
||||
if ($.isFunction(conf[name])) {
|
||||
$(self).on(name, conf[name]);
|
||||
}
|
||||
|
||||
// API
|
||||
self[name] = function(fn) {
|
||||
if (fn) { $(self).on(name, fn); }
|
||||
return self;
|
||||
};
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
// jQuery plugin implementation
|
||||
$.fn.tooltip2 = function(conf) {
|
||||
|
||||
// return existing instance
|
||||
var api = this.data("tooltip");
|
||||
if (api) { return api; }
|
||||
|
||||
conf = $.extend(true, {}, $.tools.tooltip.conf, conf);
|
||||
|
||||
// position can also be given as string
|
||||
if (typeof conf.position == 'string') {
|
||||
conf.position = conf.position.split(/,?\s/);
|
||||
}
|
||||
|
||||
// install tooltip for each entry in jQuery object
|
||||
this.each(function() {
|
||||
api = new Tooltip($(this), conf);
|
||||
$(this).data("tooltip", api);
|
||||
});
|
||||
|
||||
return conf.api ? api: this;
|
||||
};
|
||||
|
||||
}) (jQuery);
|
||||
|
||||
|
||||
|
||||
453
framework/gii/components/Pear/Text/Diff.php
Normal file
@@ -0,0 +1,453 @@
|
||||
<?php
|
||||
/**
|
||||
* General API for generating and formatting diffs - the differences between
|
||||
* two sequences of strings.
|
||||
*
|
||||
* The original PHP version of this code was written by Geoffrey T. Dairiki
|
||||
* <dairiki@dairiki.org>, and is used/adapted with his permission.
|
||||
*
|
||||
* $Horde: framework/Text_Diff/Diff.php,v 1.11.2.11 2008/02/24 10:57:46 jan Exp $
|
||||
*
|
||||
* Copyright 2004 Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
* Copyright 2004-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
|
||||
*
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*/
|
||||
class Text_Diff {
|
||||
|
||||
/**
|
||||
* Array of changes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $_edits;
|
||||
|
||||
/**
|
||||
* Computes diffs between sequences of strings.
|
||||
*
|
||||
* @param string $engine Name of the diffing engine to use. 'auto'
|
||||
* will automatically select the best.
|
||||
* @param array $params Parameters to pass to the diffing engine.
|
||||
* Normally an array of two arrays, each
|
||||
* containing the lines from a file.
|
||||
*/
|
||||
function Text_Diff($engine, $params)
|
||||
{
|
||||
// Backward compatibility workaround.
|
||||
if (!is_string($engine)) {
|
||||
$params = array($engine, $params);
|
||||
$engine = 'auto';
|
||||
}
|
||||
|
||||
if ($engine == 'auto') {
|
||||
$engine = extension_loaded('xdiff') ? 'xdiff' : 'native';
|
||||
} else {
|
||||
$engine = basename($engine);
|
||||
}
|
||||
|
||||
require_once 'Text/Diff/Engine/' . $engine . '.php';
|
||||
$class = 'Text_Diff_Engine_' . $engine;
|
||||
$diff_engine = new $class();
|
||||
|
||||
$this->_edits = call_user_func_array(array($diff_engine, 'diff'), $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array of differences.
|
||||
*/
|
||||
function getDiff()
|
||||
{
|
||||
return $this->_edits;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the number of new (added) lines in a given diff.
|
||||
*
|
||||
* @since Text_Diff 1.1.0
|
||||
* @since Horde 3.2
|
||||
*
|
||||
* @return integer The number of new lines
|
||||
*/
|
||||
function countAddedLines()
|
||||
{
|
||||
$count = 0;
|
||||
foreach ($this->_edits as $edit) {
|
||||
if (is_a($edit, 'Text_Diff_Op_add') ||
|
||||
is_a($edit, 'Text_Diff_Op_change')) {
|
||||
$count += $edit->nfinal();
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of deleted (removed) lines in a given diff.
|
||||
*
|
||||
* @since Text_Diff 1.1.0
|
||||
* @since Horde 3.2
|
||||
*
|
||||
* @return integer The number of deleted lines
|
||||
*/
|
||||
function countDeletedLines()
|
||||
{
|
||||
$count = 0;
|
||||
foreach ($this->_edits as $edit) {
|
||||
if (is_a($edit, 'Text_Diff_Op_delete') ||
|
||||
is_a($edit, 'Text_Diff_Op_change')) {
|
||||
$count += $edit->norig();
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a reversed diff.
|
||||
*
|
||||
* Example:
|
||||
* <code>
|
||||
* $diff = new Text_Diff($lines1, $lines2);
|
||||
* $rev = $diff->reverse();
|
||||
* </code>
|
||||
*
|
||||
* @return Text_Diff A Diff object representing the inverse of the
|
||||
* original diff. Note that we purposely don't return a
|
||||
* reference here, since this essentially is a clone()
|
||||
* method.
|
||||
*/
|
||||
function reverse()
|
||||
{
|
||||
if (version_compare(zend_version(), '2', '>')) {
|
||||
$rev = clone($this);
|
||||
} else {
|
||||
$rev = $this;
|
||||
}
|
||||
$rev->_edits = array();
|
||||
foreach ($this->_edits as $edit) {
|
||||
$rev->_edits[] = $edit->reverse();
|
||||
}
|
||||
return $rev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for an empty diff.
|
||||
*
|
||||
* @return boolean True if two sequences were identical.
|
||||
*/
|
||||
function isEmpty()
|
||||
{
|
||||
foreach ($this->_edits as $edit) {
|
||||
if (!is_a($edit, 'Text_Diff_Op_copy')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the length of the Longest Common Subsequence (LCS).
|
||||
*
|
||||
* This is mostly for diagnostic purposes.
|
||||
*
|
||||
* @return integer The length of the LCS.
|
||||
*/
|
||||
function lcs()
|
||||
{
|
||||
$lcs = 0;
|
||||
foreach ($this->_edits as $edit) {
|
||||
if (is_a($edit, 'Text_Diff_Op_copy')) {
|
||||
$lcs += count($edit->orig);
|
||||
}
|
||||
}
|
||||
return $lcs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the original set of lines.
|
||||
*
|
||||
* This reconstructs the $from_lines parameter passed to the constructor.
|
||||
*
|
||||
* @return array The original sequence of strings.
|
||||
*/
|
||||
function getOriginal()
|
||||
{
|
||||
$lines = array();
|
||||
foreach ($this->_edits as $edit) {
|
||||
if ($edit->orig) {
|
||||
array_splice($lines, count($lines), 0, $edit->orig);
|
||||
}
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the final set of lines.
|
||||
*
|
||||
* This reconstructs the $to_lines parameter passed to the constructor.
|
||||
*
|
||||
* @return array The sequence of strings.
|
||||
*/
|
||||
function getFinal()
|
||||
{
|
||||
$lines = array();
|
||||
foreach ($this->_edits as $edit) {
|
||||
if ($edit->final) {
|
||||
array_splice($lines, count($lines), 0, $edit->final);
|
||||
}
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes trailing newlines from a line of text. This is meant to be used
|
||||
* with array_walk().
|
||||
*
|
||||
* @param string $line The line to trim.
|
||||
* @param integer $key The index of the line in the array. Not used.
|
||||
*/
|
||||
static function trimNewlines(&$line, $key)
|
||||
{
|
||||
$line = str_replace(array("\n", "\r"), '', $line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the location of the system temporary directory.
|
||||
*
|
||||
* @static
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @return string A directory name which can be used for temp files.
|
||||
* Returns false if one could not be found.
|
||||
*/
|
||||
function _getTempDir()
|
||||
{
|
||||
$tmp_locations = array('/tmp', '/var/tmp', 'c:\WUTemp', 'c:\temp',
|
||||
'c:\windows\temp', 'c:\winnt\temp');
|
||||
|
||||
/* Try PHP's upload_tmp_dir directive. */
|
||||
$tmp = ini_get('upload_tmp_dir');
|
||||
|
||||
/* Otherwise, try to determine the TMPDIR environment variable. */
|
||||
if (!strlen($tmp)) {
|
||||
$tmp = getenv('TMPDIR');
|
||||
}
|
||||
|
||||
/* If we still cannot determine a value, then cycle through a list of
|
||||
* preset possibilities. */
|
||||
while (!strlen($tmp) && count($tmp_locations)) {
|
||||
$tmp_check = array_shift($tmp_locations);
|
||||
if (@is_dir($tmp_check)) {
|
||||
$tmp = $tmp_check;
|
||||
}
|
||||
}
|
||||
|
||||
/* If it is still empty, we have failed, so return false; otherwise
|
||||
* return the directory determined. */
|
||||
return strlen($tmp) ? $tmp : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a diff for validity.
|
||||
*
|
||||
* This is here only for debugging purposes.
|
||||
*/
|
||||
function _check($from_lines, $to_lines)
|
||||
{
|
||||
if (serialize($from_lines) != serialize($this->getOriginal())) {
|
||||
trigger_error("Reconstructed original doesn't match", E_USER_ERROR);
|
||||
}
|
||||
if (serialize($to_lines) != serialize($this->getFinal())) {
|
||||
trigger_error("Reconstructed final doesn't match", E_USER_ERROR);
|
||||
}
|
||||
|
||||
$rev = $this->reverse();
|
||||
if (serialize($to_lines) != serialize($rev->getOriginal())) {
|
||||
trigger_error("Reversed original doesn't match", E_USER_ERROR);
|
||||
}
|
||||
if (serialize($from_lines) != serialize($rev->getFinal())) {
|
||||
trigger_error("Reversed final doesn't match", E_USER_ERROR);
|
||||
}
|
||||
|
||||
$prevtype = null;
|
||||
foreach ($this->_edits as $edit) {
|
||||
if ($prevtype == get_class($edit)) {
|
||||
trigger_error("Edit sequence is non-optimal", E_USER_ERROR);
|
||||
}
|
||||
$prevtype = get_class($edit);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*/
|
||||
class Text_MappedDiff extends Text_Diff {
|
||||
|
||||
/**
|
||||
* Computes a diff between sequences of strings.
|
||||
*
|
||||
* This can be used to compute things like case-insensitve diffs, or diffs
|
||||
* which ignore changes in white-space.
|
||||
*
|
||||
* @param array $from_lines An array of strings.
|
||||
* @param array $to_lines An array of strings.
|
||||
* @param array $mapped_from_lines This array should have the same size
|
||||
* number of elements as $from_lines. The
|
||||
* elements in $mapped_from_lines and
|
||||
* $mapped_to_lines are what is actually
|
||||
* compared when computing the diff.
|
||||
* @param array $mapped_to_lines This array should have the same number
|
||||
* of elements as $to_lines.
|
||||
*/
|
||||
function Text_MappedDiff($from_lines, $to_lines,
|
||||
$mapped_from_lines, $mapped_to_lines)
|
||||
{
|
||||
assert(count($from_lines) == count($mapped_from_lines));
|
||||
assert(count($to_lines) == count($mapped_to_lines));
|
||||
|
||||
parent::Text_Diff($mapped_from_lines, $mapped_to_lines);
|
||||
|
||||
$xi = $yi = 0;
|
||||
for ($i = 0; $i < count($this->_edits); $i++) {
|
||||
$orig = &$this->_edits[$i]->orig;
|
||||
if (is_array($orig)) {
|
||||
$orig = array_slice($from_lines, $xi, count($orig));
|
||||
$xi += count($orig);
|
||||
}
|
||||
|
||||
$final = &$this->_edits[$i]->final;
|
||||
if (is_array($final)) {
|
||||
$final = array_slice($to_lines, $yi, count($final));
|
||||
$yi += count($final);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
class Text_Diff_Op {
|
||||
|
||||
var $orig;
|
||||
var $final;
|
||||
|
||||
function &reverse()
|
||||
{
|
||||
trigger_error('Abstract method', E_USER_ERROR);
|
||||
}
|
||||
|
||||
function norig()
|
||||
{
|
||||
return $this->orig ? count($this->orig) : 0;
|
||||
}
|
||||
|
||||
function nfinal()
|
||||
{
|
||||
return $this->final ? count($this->final) : 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
class Text_Diff_Op_copy extends Text_Diff_Op {
|
||||
|
||||
function Text_Diff_Op_copy($orig, $final = false)
|
||||
{
|
||||
if (!is_array($final)) {
|
||||
$final = $orig;
|
||||
}
|
||||
$this->orig = $orig;
|
||||
$this->final = $final;
|
||||
}
|
||||
|
||||
function &reverse()
|
||||
{
|
||||
$reverse = new Text_Diff_Op_copy($this->final, $this->orig);
|
||||
return $reverse;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
class Text_Diff_Op_delete extends Text_Diff_Op {
|
||||
|
||||
function Text_Diff_Op_delete($lines)
|
||||
{
|
||||
$this->orig = $lines;
|
||||
$this->final = false;
|
||||
}
|
||||
|
||||
function &reverse()
|
||||
{
|
||||
$reverse = new Text_Diff_Op_add($this->orig);
|
||||
return $reverse;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
class Text_Diff_Op_add extends Text_Diff_Op {
|
||||
|
||||
function Text_Diff_Op_add($lines)
|
||||
{
|
||||
$this->final = $lines;
|
||||
$this->orig = false;
|
||||
}
|
||||
|
||||
function &reverse()
|
||||
{
|
||||
$reverse = new Text_Diff_Op_delete($this->final);
|
||||
return $reverse;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
class Text_Diff_Op_change extends Text_Diff_Op {
|
||||
|
||||
function Text_Diff_Op_change($orig, $final)
|
||||
{
|
||||
$this->orig = $orig;
|
||||
$this->final = $final;
|
||||
}
|
||||
|
||||
function &reverse()
|
||||
{
|
||||
$reverse = new Text_Diff_Op_change($this->final, $this->orig);
|
||||
return $reverse;
|
||||
}
|
||||
|
||||
}
|
||||
438
framework/gii/components/Pear/Text/Diff/Engine/native.php
Normal file
@@ -0,0 +1,438 @@
|
||||
<?php
|
||||
/**
|
||||
* Class used internally by Text_Diff to actually compute the diffs.
|
||||
*
|
||||
* This class is implemented using native PHP code.
|
||||
*
|
||||
* The algorithm used here is mostly lifted from the perl module
|
||||
* Algorithm::Diff (version 1.06) by Ned Konz, which is available at:
|
||||
* http://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip
|
||||
*
|
||||
* More ideas are taken from: http://www.ics.uci.edu/~eppstein/161/960229.html
|
||||
*
|
||||
* Some ideas (and a bit of code) are taken from analyze.c, of GNU
|
||||
* diffutils-2.7, which can be found at:
|
||||
* ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz
|
||||
*
|
||||
* Some ideas (subdivision by NCHUNKS > 2, and some optimizations) are from
|
||||
* Geoffrey T. Dairiki <dairiki@dairiki.org>. The original PHP version of this
|
||||
* code was written by him, and is used/adapted with his permission.
|
||||
*
|
||||
* $Horde: framework/Text_Diff/Diff/Engine/native.php,v 1.7.2.4 2008/01/04 10:38:10 jan Exp $
|
||||
*
|
||||
* Copyright 2004-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
|
||||
*
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
* @package Text_Diff
|
||||
*/
|
||||
class Text_Diff_Engine_native {
|
||||
|
||||
function diff($from_lines, $to_lines)
|
||||
{
|
||||
array_walk($from_lines, array('Text_Diff', 'trimNewlines'));
|
||||
array_walk($to_lines, array('Text_Diff', 'trimNewlines'));
|
||||
|
||||
$n_from = count($from_lines);
|
||||
$n_to = count($to_lines);
|
||||
|
||||
$this->xchanged = $this->ychanged = array();
|
||||
$this->xv = $this->yv = array();
|
||||
$this->xind = $this->yind = array();
|
||||
unset($this->seq);
|
||||
unset($this->in_seq);
|
||||
unset($this->lcs);
|
||||
|
||||
// Skip leading common lines.
|
||||
for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) {
|
||||
if ($from_lines[$skip] !== $to_lines[$skip]) {
|
||||
break;
|
||||
}
|
||||
$this->xchanged[$skip] = $this->ychanged[$skip] = false;
|
||||
}
|
||||
|
||||
// Skip trailing common lines.
|
||||
$xi = $n_from; $yi = $n_to;
|
||||
for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) {
|
||||
if ($from_lines[$xi] !== $to_lines[$yi]) {
|
||||
break;
|
||||
}
|
||||
$this->xchanged[$xi] = $this->ychanged[$yi] = false;
|
||||
}
|
||||
|
||||
// Ignore lines which do not exist in both files.
|
||||
for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
|
||||
$xhash[$from_lines[$xi]] = 1;
|
||||
}
|
||||
for ($yi = $skip; $yi < $n_to - $endskip; $yi++) {
|
||||
$line = $to_lines[$yi];
|
||||
if (($this->ychanged[$yi] = empty($xhash[$line]))) {
|
||||
continue;
|
||||
}
|
||||
$yhash[$line] = 1;
|
||||
$this->yv[] = $line;
|
||||
$this->yind[] = $yi;
|
||||
}
|
||||
for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
|
||||
$line = $from_lines[$xi];
|
||||
if (($this->xchanged[$xi] = empty($yhash[$line]))) {
|
||||
continue;
|
||||
}
|
||||
$this->xv[] = $line;
|
||||
$this->xind[] = $xi;
|
||||
}
|
||||
|
||||
// Find the LCS.
|
||||
$this->_compareseq(0, count($this->xv), 0, count($this->yv));
|
||||
|
||||
// Merge edits when possible.
|
||||
$this->_shiftBoundaries($from_lines, $this->xchanged, $this->ychanged);
|
||||
$this->_shiftBoundaries($to_lines, $this->ychanged, $this->xchanged);
|
||||
|
||||
// Compute the edit operations.
|
||||
$edits = array();
|
||||
$xi = $yi = 0;
|
||||
while ($xi < $n_from || $yi < $n_to) {
|
||||
assert($yi < $n_to || $this->xchanged[$xi]);
|
||||
assert($xi < $n_from || $this->ychanged[$yi]);
|
||||
|
||||
// Skip matching "snake".
|
||||
$copy = array();
|
||||
while ($xi < $n_from && $yi < $n_to
|
||||
&& !$this->xchanged[$xi] && !$this->ychanged[$yi]) {
|
||||
$copy[] = $from_lines[$xi++];
|
||||
++$yi;
|
||||
}
|
||||
if ($copy) {
|
||||
$edits[] = new Text_Diff_Op_copy($copy);
|
||||
}
|
||||
|
||||
// Find deletes & adds.
|
||||
$delete = array();
|
||||
while ($xi < $n_from && $this->xchanged[$xi]) {
|
||||
$delete[] = $from_lines[$xi++];
|
||||
}
|
||||
|
||||
$add = array();
|
||||
while ($yi < $n_to && $this->ychanged[$yi]) {
|
||||
$add[] = $to_lines[$yi++];
|
||||
}
|
||||
|
||||
if ($delete && $add) {
|
||||
$edits[] = new Text_Diff_Op_change($delete, $add);
|
||||
} elseif ($delete) {
|
||||
$edits[] = new Text_Diff_Op_delete($delete);
|
||||
} elseif ($add) {
|
||||
$edits[] = new Text_Diff_Op_add($add);
|
||||
}
|
||||
}
|
||||
|
||||
return $edits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides the Largest Common Subsequence (LCS) of the sequences (XOFF,
|
||||
* XLIM) and (YOFF, YLIM) into NCHUNKS approximately equally sized
|
||||
* segments.
|
||||
*
|
||||
* Returns (LCS, PTS). LCS is the length of the LCS. PTS is an array of
|
||||
* NCHUNKS+1 (X, Y) indexes giving the diving points between sub
|
||||
* sequences. The first sub-sequence is contained in (X0, X1), (Y0, Y1),
|
||||
* the second in (X1, X2), (Y1, Y2) and so on. Note that (X0, Y0) ==
|
||||
* (XOFF, YOFF) and (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM).
|
||||
*
|
||||
* This function assumes that the first lines of the specified portions of
|
||||
* the two files do not match, and likewise that the last lines do not
|
||||
* match. The caller must trim matching lines from the beginning and end
|
||||
* of the portions it is going to specify.
|
||||
*/
|
||||
function _diag ($xoff, $xlim, $yoff, $ylim, $nchunks)
|
||||
{
|
||||
$flip = false;
|
||||
|
||||
if ($xlim - $xoff > $ylim - $yoff) {
|
||||
/* Things seems faster (I'm not sure I understand why) when the
|
||||
* shortest sequence is in X. */
|
||||
$flip = true;
|
||||
list ($xoff, $xlim, $yoff, $ylim)
|
||||
= array($yoff, $ylim, $xoff, $xlim);
|
||||
}
|
||||
|
||||
if ($flip) {
|
||||
for ($i = $ylim - 1; $i >= $yoff; $i--) {
|
||||
$ymatches[$this->xv[$i]][] = $i;
|
||||
}
|
||||
} else {
|
||||
for ($i = $ylim - 1; $i >= $yoff; $i--) {
|
||||
$ymatches[$this->yv[$i]][] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
$this->lcs = 0;
|
||||
$this->seq[0]= $yoff - 1;
|
||||
$this->in_seq = array();
|
||||
$ymids[0] = array();
|
||||
|
||||
$numer = $xlim - $xoff + $nchunks - 1;
|
||||
$x = $xoff;
|
||||
for ($chunk = 0; $chunk < $nchunks; $chunk++) {
|
||||
if ($chunk > 0) {
|
||||
for ($i = 0; $i <= $this->lcs; $i++) {
|
||||
$ymids[$i][$chunk - 1] = $this->seq[$i];
|
||||
}
|
||||
}
|
||||
|
||||
$x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $chunk) / $nchunks);
|
||||
for (; $x < $x1; $x++) {
|
||||
$line = $flip ? $this->yv[$x] : $this->xv[$x];
|
||||
if (empty($ymatches[$line])) {
|
||||
continue;
|
||||
}
|
||||
$matches = $ymatches[$line];
|
||||
reset($matches);
|
||||
while (list(, $y) = each($matches)) {
|
||||
if (empty($this->in_seq[$y])) {
|
||||
$k = $this->_lcsPos($y);
|
||||
assert($k > 0);
|
||||
$ymids[$k] = $ymids[$k - 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (list(, $y) = each($matches)) {
|
||||
if ($y > $this->seq[$k - 1]) {
|
||||
assert($y <= $this->seq[$k]);
|
||||
/* Optimization: this is a common case: next match is
|
||||
* just replacing previous match. */
|
||||
$this->in_seq[$this->seq[$k]] = false;
|
||||
$this->seq[$k] = $y;
|
||||
$this->in_seq[$y] = 1;
|
||||
} elseif (empty($this->in_seq[$y])) {
|
||||
$k = $this->_lcsPos($y);
|
||||
assert($k > 0);
|
||||
$ymids[$k] = $ymids[$k - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$seps[] = $flip ? array($yoff, $xoff) : array($xoff, $yoff);
|
||||
$ymid = $ymids[$this->lcs];
|
||||
for ($n = 0; $n < $nchunks - 1; $n++) {
|
||||
$x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $n) / $nchunks);
|
||||
$y1 = $ymid[$n] + 1;
|
||||
$seps[] = $flip ? array($y1, $x1) : array($x1, $y1);
|
||||
}
|
||||
$seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim);
|
||||
|
||||
return array($this->lcs, $seps);
|
||||
}
|
||||
|
||||
function _lcsPos($ypos)
|
||||
{
|
||||
$end = $this->lcs;
|
||||
if ($end == 0 || $ypos > $this->seq[$end]) {
|
||||
$this->seq[++$this->lcs] = $ypos;
|
||||
$this->in_seq[$ypos] = 1;
|
||||
return $this->lcs;
|
||||
}
|
||||
|
||||
$beg = 1;
|
||||
while ($beg < $end) {
|
||||
$mid = (int)(($beg + $end) / 2);
|
||||
if ($ypos > $this->seq[$mid]) {
|
||||
$beg = $mid + 1;
|
||||
} else {
|
||||
$end = $mid;
|
||||
}
|
||||
}
|
||||
|
||||
assert($ypos != $this->seq[$end]);
|
||||
|
||||
$this->in_seq[$this->seq[$end]] = false;
|
||||
$this->seq[$end] = $ypos;
|
||||
$this->in_seq[$ypos] = 1;
|
||||
return $end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds LCS of two sequences.
|
||||
*
|
||||
* The results are recorded in the vectors $this->{x,y}changed[], by
|
||||
* storing a 1 in the element for each line that is an insertion or
|
||||
* deletion (ie. is not in the LCS).
|
||||
*
|
||||
* The subsequence of file 0 is (XOFF, XLIM) and likewise for file 1.
|
||||
*
|
||||
* Note that XLIM, YLIM are exclusive bounds. All line numbers are
|
||||
* origin-0 and discarded lines are not counted.
|
||||
*/
|
||||
function _compareseq ($xoff, $xlim, $yoff, $ylim)
|
||||
{
|
||||
/* Slide down the bottom initial diagonal. */
|
||||
while ($xoff < $xlim && $yoff < $ylim
|
||||
&& $this->xv[$xoff] == $this->yv[$yoff]) {
|
||||
++$xoff;
|
||||
++$yoff;
|
||||
}
|
||||
|
||||
/* Slide up the top initial diagonal. */
|
||||
while ($xlim > $xoff && $ylim > $yoff
|
||||
&& $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) {
|
||||
--$xlim;
|
||||
--$ylim;
|
||||
}
|
||||
|
||||
if ($xoff == $xlim || $yoff == $ylim) {
|
||||
$lcs = 0;
|
||||
} else {
|
||||
/* This is ad hoc but seems to work well. $nchunks =
|
||||
* sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5); $nchunks =
|
||||
* max(2,min(8,(int)$nchunks)); */
|
||||
$nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1;
|
||||
list($lcs, $seps)
|
||||
= $this->_diag($xoff, $xlim, $yoff, $ylim, $nchunks);
|
||||
}
|
||||
|
||||
if ($lcs == 0) {
|
||||
/* X and Y sequences have no common subsequence: mark all
|
||||
* changed. */
|
||||
while ($yoff < $ylim) {
|
||||
$this->ychanged[$this->yind[$yoff++]] = 1;
|
||||
}
|
||||
while ($xoff < $xlim) {
|
||||
$this->xchanged[$this->xind[$xoff++]] = 1;
|
||||
}
|
||||
} else {
|
||||
/* Use the partitions to split this problem into subproblems. */
|
||||
reset($seps);
|
||||
$pt1 = $seps[0];
|
||||
while ($pt2 = next($seps)) {
|
||||
$this->_compareseq ($pt1[0], $pt2[0], $pt1[1], $pt2[1]);
|
||||
$pt1 = $pt2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts inserts/deletes of identical lines to join changes as much as
|
||||
* possible.
|
||||
*
|
||||
* We do something when a run of changed lines include a line at one end
|
||||
* and has an excluded, identical line at the other. We are free to
|
||||
* choose which identical line is included. `compareseq' usually chooses
|
||||
* the one at the beginning, but usually it is cleaner to consider the
|
||||
* following identical line to be the "change".
|
||||
*
|
||||
* This is extracted verbatim from analyze.c (GNU diffutils-2.7).
|
||||
*/
|
||||
function _shiftBoundaries($lines, &$changed, $other_changed)
|
||||
{
|
||||
$i = 0;
|
||||
$j = 0;
|
||||
|
||||
assert('count($lines) == count($changed)');
|
||||
$len = count($lines);
|
||||
$other_len = count($other_changed);
|
||||
|
||||
while (1) {
|
||||
/* Scan forward to find the beginning of another run of
|
||||
* changes. Also keep track of the corresponding point in the
|
||||
* other file.
|
||||
*
|
||||
* Throughout this code, $i and $j are adjusted together so that
|
||||
* the first $i elements of $changed and the first $j elements of
|
||||
* $other_changed both contain the same number of zeros (unchanged
|
||||
* lines).
|
||||
*
|
||||
* Furthermore, $j is always kept so that $j == $other_len or
|
||||
* $other_changed[$j] == false. */
|
||||
while ($j < $other_len && $other_changed[$j]) {
|
||||
$j++;
|
||||
}
|
||||
|
||||
while ($i < $len && ! $changed[$i]) {
|
||||
assert('$j < $other_len && ! $other_changed[$j]');
|
||||
$i++; $j++;
|
||||
while ($j < $other_len && $other_changed[$j]) {
|
||||
$j++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($i == $len) {
|
||||
break;
|
||||
}
|
||||
|
||||
$start = $i;
|
||||
|
||||
/* Find the end of this run of changes. */
|
||||
while (++$i < $len && $changed[$i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
do {
|
||||
/* Record the length of this run of changes, so that we can
|
||||
* later determine whether the run has grown. */
|
||||
$runlength = $i - $start;
|
||||
|
||||
/* Move the changed region back, so long as the previous
|
||||
* unchanged line matches the last changed one. This merges
|
||||
* with previous changed regions. */
|
||||
while ($start > 0 && $lines[$start - 1] == $lines[$i - 1]) {
|
||||
$changed[--$start] = 1;
|
||||
$changed[--$i] = false;
|
||||
while ($start > 0 && $changed[$start - 1]) {
|
||||
$start--;
|
||||
}
|
||||
assert('$j > 0');
|
||||
while ($other_changed[--$j]) {
|
||||
continue;
|
||||
}
|
||||
assert('$j >= 0 && !$other_changed[$j]');
|
||||
}
|
||||
|
||||
/* Set CORRESPONDING to the end of the changed run, at the
|
||||
* last point where it corresponds to a changed run in the
|
||||
* other file. CORRESPONDING == LEN means no such point has
|
||||
* been found. */
|
||||
$corresponding = $j < $other_len ? $i : $len;
|
||||
|
||||
/* Move the changed region forward, so long as the first
|
||||
* changed line matches the following unchanged one. This
|
||||
* merges with following changed regions. Do this second, so
|
||||
* that if there are no merges, the changed region is moved
|
||||
* forward as far as possible. */
|
||||
while ($i < $len && $lines[$start] == $lines[$i]) {
|
||||
$changed[$start++] = false;
|
||||
$changed[$i++] = 1;
|
||||
while ($i < $len && $changed[$i]) {
|
||||
$i++;
|
||||
}
|
||||
|
||||
assert('$j < $other_len && ! $other_changed[$j]');
|
||||
$j++;
|
||||
if ($j < $other_len && $other_changed[$j]) {
|
||||
$corresponding = $i;
|
||||
while ($j < $other_len && $other_changed[$j]) {
|
||||
$j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while ($runlength != $i - $start);
|
||||
|
||||
/* If possible, move the fully-merged run of changes back to a
|
||||
* corresponding run in the other file. */
|
||||
while ($corresponding < $i) {
|
||||
$changed[--$start] = 1;
|
||||
$changed[--$i] = 0;
|
||||
assert('$j > 0');
|
||||
while ($other_changed[--$j]) {
|
||||
continue;
|
||||
}
|
||||
assert('$j >= 0 && !$other_changed[$j]');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
162
framework/gii/components/Pear/Text/Diff/Engine/shell.php
Normal file
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
/**
|
||||
* Class used internally by Diff to actually compute the diffs.
|
||||
*
|
||||
* This class uses the Unix `diff` program via shell_exec to compute the
|
||||
* differences between the two input arrays.
|
||||
*
|
||||
* $Horde: framework/Text_Diff/Diff/Engine/shell.php,v 1.6.2.3 2008/01/04 10:37:27 jan Exp $
|
||||
*
|
||||
* Copyright 2007-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
|
||||
*
|
||||
* @author Milian Wolff <mail@milianw.de>
|
||||
* @package Text_Diff
|
||||
* @since 0.3.0
|
||||
*/
|
||||
class Text_Diff_Engine_shell {
|
||||
|
||||
/**
|
||||
* Path to the diff executable
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $_diffCommand = 'diff';
|
||||
|
||||
/**
|
||||
* Returns the array of differences.
|
||||
*
|
||||
* @param array $from_lines lines of text from old file
|
||||
* @param array $to_lines lines of text from new file
|
||||
*
|
||||
* @return array all changes made (array with Text_Diff_Op_* objects)
|
||||
*/
|
||||
function diff($from_lines, $to_lines)
|
||||
{
|
||||
array_walk($from_lines, array('Text_Diff', 'trimNewlines'));
|
||||
array_walk($to_lines, array('Text_Diff', 'trimNewlines'));
|
||||
|
||||
$temp_dir = Text_Diff::_getTempDir();
|
||||
|
||||
// Execute gnu diff or similar to get a standard diff file.
|
||||
$from_file = tempnam($temp_dir, 'Text_Diff');
|
||||
$to_file = tempnam($temp_dir, 'Text_Diff');
|
||||
$fp = fopen($from_file, 'w');
|
||||
fwrite($fp, implode("\n", $from_lines));
|
||||
fclose($fp);
|
||||
$fp = fopen($to_file, 'w');
|
||||
fwrite($fp, implode("\n", $to_lines));
|
||||
fclose($fp);
|
||||
$diff = shell_exec($this->_diffCommand . ' ' . $from_file . ' ' . $to_file);
|
||||
unlink($from_file);
|
||||
unlink($to_file);
|
||||
|
||||
if (is_null($diff)) {
|
||||
// No changes were made
|
||||
return array(new Text_Diff_Op_copy($from_lines));
|
||||
}
|
||||
|
||||
$from_line_no = 1;
|
||||
$to_line_no = 1;
|
||||
$edits = array();
|
||||
|
||||
// Get changed lines by parsing something like:
|
||||
// 0a1,2
|
||||
// 1,2c4,6
|
||||
// 1,5d6
|
||||
preg_match_all('#^(\d+)(?:,(\d+))?([adc])(\d+)(?:,(\d+))?$#m', $diff,
|
||||
$matches, PREG_SET_ORDER);
|
||||
|
||||
foreach ($matches as $match) {
|
||||
if (!isset($match[5])) {
|
||||
// This paren is not set every time (see regex).
|
||||
$match[5] = false;
|
||||
}
|
||||
|
||||
if ($match[3] == 'a') {
|
||||
$from_line_no--;
|
||||
}
|
||||
|
||||
if ($match[3] == 'd') {
|
||||
$to_line_no--;
|
||||
}
|
||||
|
||||
if ($from_line_no < $match[1] || $to_line_no < $match[4]) {
|
||||
// copied lines
|
||||
assert('$match[1] - $from_line_no == $match[4] - $to_line_no');
|
||||
array_push($edits,
|
||||
new Text_Diff_Op_copy(
|
||||
$this->_getLines($from_lines, $from_line_no, $match[1] - 1),
|
||||
$this->_getLines($to_lines, $to_line_no, $match[4] - 1)));
|
||||
}
|
||||
|
||||
switch ($match[3]) {
|
||||
case 'd':
|
||||
// deleted lines
|
||||
array_push($edits,
|
||||
new Text_Diff_Op_delete(
|
||||
$this->_getLines($from_lines, $from_line_no, $match[2])));
|
||||
$to_line_no++;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
// changed lines
|
||||
array_push($edits,
|
||||
new Text_Diff_Op_change(
|
||||
$this->_getLines($from_lines, $from_line_no, $match[2]),
|
||||
$this->_getLines($to_lines, $to_line_no, $match[5])));
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
// added lines
|
||||
array_push($edits,
|
||||
new Text_Diff_Op_add(
|
||||
$this->_getLines($to_lines, $to_line_no, $match[5])));
|
||||
$from_line_no++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($from_lines)) {
|
||||
// Some lines might still be pending. Add them as copied
|
||||
array_push($edits,
|
||||
new Text_Diff_Op_copy(
|
||||
$this->_getLines($from_lines, $from_line_no,
|
||||
$from_line_no + count($from_lines) - 1),
|
||||
$this->_getLines($to_lines, $to_line_no,
|
||||
$to_line_no + count($to_lines) - 1)));
|
||||
}
|
||||
|
||||
return $edits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lines from either the old or new text
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param array &$text_lines Either $from_lines or $to_lines
|
||||
* @param integer &$line_no Current line number
|
||||
* @param integer $end Optional end line, when we want to chop more than one line.
|
||||
* @return array The chopped lines
|
||||
*/
|
||||
function _getLines(&$text_lines, &$line_no, $end = false)
|
||||
{
|
||||
if (!empty($end)) {
|
||||
$lines = array();
|
||||
// We can shift even more
|
||||
while ($line_no <= $end) {
|
||||
array_push($lines, array_shift($text_lines));
|
||||
$line_no++;
|
||||
}
|
||||
} else {
|
||||
$lines = array(array_shift($text_lines));
|
||||
$line_no++;
|
||||
}
|
||||
|
||||
return $lines;
|
||||
}
|
||||
|
||||
}
|
||||
237
framework/gii/components/Pear/Text/Diff/Engine/string.php
Normal file
@@ -0,0 +1,237 @@
|
||||
<?php
|
||||
/**
|
||||
* Parses unified or context diffs output from eg. the diff utility.
|
||||
*
|
||||
* Example:
|
||||
* <code>
|
||||
* $patch = file_get_contents('example.patch');
|
||||
* $diff = new Text_Diff('string', array($patch));
|
||||
* $renderer = new Text_Diff_Renderer_inline();
|
||||
* echo $renderer->render($diff);
|
||||
* </code>
|
||||
*
|
||||
* $Horde: framework/Text_Diff/Diff/Engine/string.php,v 1.5.2.5 2008/09/10 08:31:58 jan Exp $
|
||||
*
|
||||
* Copyright 2005 <20>rjan Persson <o@42mm.org>
|
||||
* Copyright 2005-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
|
||||
*
|
||||
* @author <20>rjan Persson <o@42mm.org>
|
||||
* @package Text_Diff
|
||||
* @since 0.2.0
|
||||
*/
|
||||
class Text_Diff_Engine_string {
|
||||
|
||||
/**
|
||||
* Parses a unified or context diff.
|
||||
*
|
||||
* First param contains the whole diff and the second can be used to force
|
||||
* a specific diff type. If the second parameter is 'autodetect', the
|
||||
* diff will be examined to find out which type of diff this is.
|
||||
*
|
||||
* @param string $diff The diff content.
|
||||
* @param string $mode The diff mode of the content in $diff. One of
|
||||
* 'context', 'unified', or 'autodetect'.
|
||||
*
|
||||
* @return array List of all diff operations.
|
||||
*/
|
||||
function diff($diff, $mode = 'autodetect')
|
||||
{
|
||||
if ($mode != 'autodetect' && $mode != 'context' && $mode != 'unified') {
|
||||
return PEAR::raiseError('Type of diff is unsupported');
|
||||
}
|
||||
|
||||
if ($mode == 'autodetect') {
|
||||
$context = strpos($diff, '***');
|
||||
$unified = strpos($diff, '---');
|
||||
if ($context === $unified) {
|
||||
return PEAR::raiseError('Type of diff could not be detected');
|
||||
} elseif ($context === false || $unified === false) {
|
||||
$mode = $context !== false ? 'context' : 'unified';
|
||||
} else {
|
||||
$mode = $context < $unified ? 'context' : 'unified';
|
||||
}
|
||||
}
|
||||
|
||||
// Split by new line and remove the diff header, if there is one.
|
||||
$diff = explode("\n", $diff);
|
||||
if (($mode == 'context' && strpos($diff[0], '***') === 0) ||
|
||||
($mode == 'unified' && strpos($diff[0], '---') === 0)) {
|
||||
array_shift($diff);
|
||||
array_shift($diff);
|
||||
}
|
||||
|
||||
if ($mode == 'context') {
|
||||
return $this->parseContextDiff($diff);
|
||||
} else {
|
||||
return $this->parseUnifiedDiff($diff);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an array containing the unified diff.
|
||||
*
|
||||
* @param array $diff Array of lines.
|
||||
*
|
||||
* @return array List of all diff operations.
|
||||
*/
|
||||
function parseUnifiedDiff($diff)
|
||||
{
|
||||
$edits = array();
|
||||
$end = count($diff) - 1;
|
||||
for ($i = 0; $i < $end;) {
|
||||
$diff1 = array();
|
||||
switch (substr($diff[$i], 0, 1)) {
|
||||
case ' ':
|
||||
do {
|
||||
$diff1[] = substr($diff[$i], 1);
|
||||
} while (++$i < $end && substr($diff[$i], 0, 1) == ' ');
|
||||
$edits[] = new Text_Diff_Op_copy($diff1);
|
||||
break;
|
||||
|
||||
case '+':
|
||||
// get all new lines
|
||||
do {
|
||||
$diff1[] = substr($diff[$i], 1);
|
||||
} while (++$i < $end && substr($diff[$i], 0, 1) == '+');
|
||||
$edits[] = new Text_Diff_Op_add($diff1);
|
||||
break;
|
||||
|
||||
case '-':
|
||||
// get changed or removed lines
|
||||
$diff2 = array();
|
||||
do {
|
||||
$diff1[] = substr($diff[$i], 1);
|
||||
} while (++$i < $end && substr($diff[$i], 0, 1) == '-');
|
||||
|
||||
while ($i < $end && substr($diff[$i], 0, 1) == '+') {
|
||||
$diff2[] = substr($diff[$i++], 1);
|
||||
}
|
||||
if (count($diff2) == 0) {
|
||||
$edits[] = new Text_Diff_Op_delete($diff1);
|
||||
} else {
|
||||
$edits[] = new Text_Diff_Op_change($diff1, $diff2);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $edits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an array containing the context diff.
|
||||
*
|
||||
* @param array $diff Array of lines.
|
||||
*
|
||||
* @return array List of all diff operations.
|
||||
*/
|
||||
function parseContextDiff(&$diff)
|
||||
{
|
||||
$edits = array();
|
||||
$i = $max_i = $j = $max_j = 0;
|
||||
$end = count($diff) - 1;
|
||||
while ($i < $end && $j < $end) {
|
||||
while ($i >= $max_i && $j >= $max_j) {
|
||||
// Find the boundaries of the diff output of the two files
|
||||
for ($i = $j;
|
||||
$i < $end && substr($diff[$i], 0, 3) == '***';
|
||||
$i++);
|
||||
for ($max_i = $i;
|
||||
$max_i < $end && substr($diff[$max_i], 0, 3) != '---';
|
||||
$max_i++);
|
||||
for ($j = $max_i;
|
||||
$j < $end && substr($diff[$j], 0, 3) == '---';
|
||||
$j++);
|
||||
for ($max_j = $j;
|
||||
$max_j < $end && substr($diff[$max_j], 0, 3) != '***';
|
||||
$max_j++);
|
||||
}
|
||||
|
||||
// find what hasn't been changed
|
||||
$array = array();
|
||||
while ($i < $max_i &&
|
||||
$j < $max_j &&
|
||||
strcmp($diff[$i], $diff[$j]) == 0) {
|
||||
$array[] = substr($diff[$i], 2);
|
||||
$i++;
|
||||
$j++;
|
||||
}
|
||||
|
||||
while ($i < $max_i && ($max_j-$j) <= 1) {
|
||||
if ($diff[$i] != '' && substr($diff[$i], 0, 1) != ' ') {
|
||||
break;
|
||||
}
|
||||
$array[] = substr($diff[$i++], 2);
|
||||
}
|
||||
|
||||
while ($j < $max_j && ($max_i-$i) <= 1) {
|
||||
if ($diff[$j] != '' && substr($diff[$j], 0, 1) != ' ') {
|
||||
break;
|
||||
}
|
||||
$array[] = substr($diff[$j++], 2);
|
||||
}
|
||||
if (count($array) > 0) {
|
||||
$edits[] = new Text_Diff_Op_copy($array);
|
||||
}
|
||||
|
||||
if ($i < $max_i) {
|
||||
$diff1 = array();
|
||||
switch (substr($diff[$i], 0, 1)) {
|
||||
case '!':
|
||||
$diff2 = array();
|
||||
do {
|
||||
$diff1[] = substr($diff[$i], 2);
|
||||
if ($j < $max_j && substr($diff[$j], 0, 1) == '!') {
|
||||
$diff2[] = substr($diff[$j++], 2);
|
||||
}
|
||||
} while (++$i < $max_i && substr($diff[$i], 0, 1) == '!');
|
||||
$edits[] = new Text_Diff_Op_change($diff1, $diff2);
|
||||
break;
|
||||
|
||||
case '+':
|
||||
do {
|
||||
$diff1[] = substr($diff[$i], 2);
|
||||
} while (++$i < $max_i && substr($diff[$i], 0, 1) == '+');
|
||||
$edits[] = new Text_Diff_Op_add($diff1);
|
||||
break;
|
||||
|
||||
case '-':
|
||||
do {
|
||||
$diff1[] = substr($diff[$i], 2);
|
||||
} while (++$i < $max_i && substr($diff[$i], 0, 1) == '-');
|
||||
$edits[] = new Text_Diff_Op_delete($diff1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($j < $max_j) {
|
||||
$diff2 = array();
|
||||
switch (substr($diff[$j], 0, 1)) {
|
||||
case '+':
|
||||
do {
|
||||
$diff2[] = substr($diff[$j++], 2);
|
||||
} while ($j < $max_j && substr($diff[$j], 0, 1) == '+');
|
||||
$edits[] = new Text_Diff_Op_add($diff2);
|
||||
break;
|
||||
|
||||
case '-':
|
||||
do {
|
||||
$diff2[] = substr($diff[$j++], 2);
|
||||
} while ($j < $max_j && substr($diff[$j], 0, 1) == '-');
|
||||
$edits[] = new Text_Diff_Op_delete($diff2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $edits;
|
||||
}
|
||||
|
||||
}
|
||||
63
framework/gii/components/Pear/Text/Diff/Engine/xdiff.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
/**
|
||||
* Class used internally by Diff to actually compute the diffs.
|
||||
*
|
||||
* This class uses the xdiff PECL package (http://pecl.php.net/package/xdiff)
|
||||
* to compute the differences between the two input arrays.
|
||||
*
|
||||
* $Horde: framework/Text_Diff/Diff/Engine/xdiff.php,v 1.4.2.3 2008/01/04 10:37:27 jan Exp $
|
||||
*
|
||||
* Copyright 2004-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
|
||||
*
|
||||
* @author Jon Parise <jon@horde.org>
|
||||
* @package Text_Diff
|
||||
*/
|
||||
class Text_Diff_Engine_xdiff {
|
||||
|
||||
/**
|
||||
*/
|
||||
function diff($from_lines, $to_lines)
|
||||
{
|
||||
array_walk($from_lines, array('Text_Diff', 'trimNewlines'));
|
||||
array_walk($to_lines, array('Text_Diff', 'trimNewlines'));
|
||||
|
||||
/* Convert the two input arrays into strings for xdiff processing. */
|
||||
$from_string = implode("\n", $from_lines);
|
||||
$to_string = implode("\n", $to_lines);
|
||||
|
||||
/* Diff the two strings and convert the result to an array. */
|
||||
$diff = xdiff_string_diff($from_string, $to_string, count($to_lines));
|
||||
$diff = explode("\n", $diff);
|
||||
|
||||
/* Walk through the diff one line at a time. We build the $edits
|
||||
* array of diff operations by reading the first character of the
|
||||
* xdiff output (which is in the "unified diff" format).
|
||||
*
|
||||
* Note that we don't have enough information to detect "changed"
|
||||
* lines using this approach, so we can't add Text_Diff_Op_changed
|
||||
* instances to the $edits array. The result is still perfectly
|
||||
* valid, albeit a little less descriptive and efficient. */
|
||||
$edits = array();
|
||||
foreach ($diff as $line) {
|
||||
switch ($line[0]) {
|
||||
case ' ':
|
||||
$edits[] = new Text_Diff_Op_copy(array(substr($line, 1)));
|
||||
break;
|
||||
|
||||
case '+':
|
||||
$edits[] = new Text_Diff_Op_add(array(substr($line, 1)));
|
||||
break;
|
||||
|
||||
case '-':
|
||||
$edits[] = new Text_Diff_Op_delete(array(substr($line, 1)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $edits;
|
||||
}
|
||||
|
||||
}
|
||||
55
framework/gii/components/Pear/Text/Diff/Mapped.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/**
|
||||
* $Horde: framework/Text_Diff/Diff/Mapped.php,v 1.3.2.3 2008/01/04 10:37:27 jan Exp $
|
||||
*
|
||||
* Copyright 2007-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
|
||||
*
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*/
|
||||
class Text_Diff_Mapped extends Text_Diff {
|
||||
|
||||
/**
|
||||
* Computes a diff between sequences of strings.
|
||||
*
|
||||
* This can be used to compute things like case-insensitve diffs, or diffs
|
||||
* which ignore changes in white-space.
|
||||
*
|
||||
* @param array $from_lines An array of strings.
|
||||
* @param array $to_lines An array of strings.
|
||||
* @param array $mapped_from_lines This array should have the same size
|
||||
* number of elements as $from_lines. The
|
||||
* elements in $mapped_from_lines and
|
||||
* $mapped_to_lines are what is actually
|
||||
* compared when computing the diff.
|
||||
* @param array $mapped_to_lines This array should have the same number
|
||||
* of elements as $to_lines.
|
||||
*/
|
||||
function Text_Diff_Mapped($from_lines, $to_lines,
|
||||
$mapped_from_lines, $mapped_to_lines)
|
||||
{
|
||||
assert(count($from_lines) == count($mapped_from_lines));
|
||||
assert(count($to_lines) == count($mapped_to_lines));
|
||||
|
||||
parent::Text_Diff($mapped_from_lines, $mapped_to_lines);
|
||||
|
||||
$xi = $yi = 0;
|
||||
for ($i = 0; $i < count($this->_edits); $i++) {
|
||||
$orig = &$this->_edits[$i]->orig;
|
||||
if (is_array($orig)) {
|
||||
$orig = array_slice($from_lines, $xi, count($orig));
|
||||
$xi += count($orig);
|
||||
}
|
||||
|
||||
$final = &$this->_edits[$i]->final;
|
||||
if (is_array($final)) {
|
||||
$final = array_slice($to_lines, $yi, count($final));
|
||||
$yi += count($final);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
237
framework/gii/components/Pear/Text/Diff/Renderer.php
Normal file
@@ -0,0 +1,237 @@
|
||||
<?php
|
||||
/**
|
||||
* A class to render Diffs in different formats.
|
||||
*
|
||||
* This class renders the diff in classic diff format. It is intended that
|
||||
* this class be customized via inheritance, to obtain fancier outputs.
|
||||
*
|
||||
* $Horde: framework/Text_Diff/Diff/Renderer.php,v 1.5.10.10 2008/01/04 10:37:27 jan Exp $
|
||||
*
|
||||
* Copyright 2004-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
|
||||
*
|
||||
* @package Text_Diff
|
||||
*/
|
||||
class Text_Diff_Renderer {
|
||||
|
||||
/**
|
||||
* Number of leading context "lines" to preserve.
|
||||
*
|
||||
* This should be left at zero for this class, but subclasses may want to
|
||||
* set this to other values.
|
||||
*/
|
||||
var $_leading_context_lines = 0;
|
||||
|
||||
/**
|
||||
* Number of trailing context "lines" to preserve.
|
||||
*
|
||||
* This should be left at zero for this class, but subclasses may want to
|
||||
* set this to other values.
|
||||
*/
|
||||
var $_trailing_context_lines = 0;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
function Text_Diff_Renderer($params = array())
|
||||
{
|
||||
foreach ($params as $param => $value) {
|
||||
$v = '_' . $param;
|
||||
if (isset($this->$v)) {
|
||||
$this->$v = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any renderer parameters.
|
||||
*
|
||||
* @return array All parameters of this renderer object.
|
||||
*/
|
||||
function getParams()
|
||||
{
|
||||
$params = array();
|
||||
foreach (get_object_vars($this) as $k => $v) {
|
||||
if ($k[0] == '_') {
|
||||
$params[substr($k, 1)] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a diff.
|
||||
*
|
||||
* @param Text_Diff $diff A Text_Diff object.
|
||||
*
|
||||
* @return string The formatted output.
|
||||
*/
|
||||
function render($diff)
|
||||
{
|
||||
$xi = $yi = 1;
|
||||
$block = false;
|
||||
$context = array();
|
||||
|
||||
$nlead = $this->_leading_context_lines;
|
||||
$ntrail = $this->_trailing_context_lines;
|
||||
|
||||
$output = $this->_startDiff();
|
||||
|
||||
$diffs = $diff->getDiff();
|
||||
foreach ($diffs as $i => $edit) {
|
||||
/* If these are unchanged (copied) lines, and we want to keep
|
||||
* leading or trailing context lines, extract them from the copy
|
||||
* block. */
|
||||
if (is_a($edit, 'Text_Diff_Op_copy')) {
|
||||
/* Do we have any diff blocks yet? */
|
||||
if (is_array($block)) {
|
||||
/* How many lines to keep as context from the copy
|
||||
* block. */
|
||||
$keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail;
|
||||
if (count($edit->orig) <= $keep) {
|
||||
/* We have less lines in the block than we want for
|
||||
* context => keep the whole block. */
|
||||
$block[] = $edit;
|
||||
} else {
|
||||
if ($ntrail) {
|
||||
/* Create a new block with as many lines as we need
|
||||
* for the trailing context. */
|
||||
$context = array_slice($edit->orig, 0, $ntrail);
|
||||
$block[] = new Text_Diff_Op_copy($context);
|
||||
}
|
||||
/* @todo */
|
||||
$output .= $this->_block($x0, $ntrail + $xi - $x0,
|
||||
$y0, $ntrail + $yi - $y0,
|
||||
$block);
|
||||
$block = false;
|
||||
}
|
||||
}
|
||||
/* Keep the copy block as the context for the next block. */
|
||||
$context = $edit->orig;
|
||||
} else {
|
||||
/* Don't we have any diff blocks yet? */
|
||||
if (!is_array($block)) {
|
||||
/* Extract context lines from the preceding copy block. */
|
||||
$context = array_slice($context, count($context) - $nlead);
|
||||
$x0 = $xi - count($context);
|
||||
$y0 = $yi - count($context);
|
||||
$block = array();
|
||||
if ($context) {
|
||||
$block[] = new Text_Diff_Op_copy($context);
|
||||
}
|
||||
}
|
||||
$block[] = $edit;
|
||||
}
|
||||
|
||||
if ($edit->orig) {
|
||||
$xi += count($edit->orig);
|
||||
}
|
||||
if ($edit->final) {
|
||||
$yi += count($edit->final);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($block)) {
|
||||
$output .= $this->_block($x0, $xi - $x0,
|
||||
$y0, $yi - $y0,
|
||||
$block);
|
||||
}
|
||||
|
||||
return $output . $this->_endDiff();
|
||||
}
|
||||
|
||||
function _block($xbeg, $xlen, $ybeg, $ylen, &$edits)
|
||||
{
|
||||
$output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen));
|
||||
|
||||
foreach ($edits as $edit) {
|
||||
switch (strtolower(get_class($edit))) {
|
||||
case 'text_diff_op_copy':
|
||||
$output .= $this->_context($edit->orig);
|
||||
break;
|
||||
|
||||
case 'text_diff_op_add':
|
||||
$output .= $this->_added($edit->final);
|
||||
break;
|
||||
|
||||
case 'text_diff_op_delete':
|
||||
$output .= $this->_deleted($edit->orig);
|
||||
break;
|
||||
|
||||
case 'text_diff_op_change':
|
||||
$output .= $this->_changed($edit->orig, $edit->final);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $output . $this->_endBlock();
|
||||
}
|
||||
|
||||
function _startDiff()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
function _endDiff()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
|
||||
{
|
||||
if ($xlen > 1) {
|
||||
$xbeg .= ',' . ($xbeg + $xlen - 1);
|
||||
}
|
||||
if ($ylen > 1) {
|
||||
$ybeg .= ',' . ($ybeg + $ylen - 1);
|
||||
}
|
||||
|
||||
// this matches the GNU Diff behaviour
|
||||
if ($xlen && !$ylen) {
|
||||
$ybeg--;
|
||||
} elseif (!$xlen) {
|
||||
$xbeg--;
|
||||
}
|
||||
|
||||
return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
|
||||
}
|
||||
|
||||
function _startBlock($header)
|
||||
{
|
||||
return $header . "\n";
|
||||
}
|
||||
|
||||
function _endBlock()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
function _lines($lines, $prefix = ' ')
|
||||
{
|
||||
return $prefix . implode("\n$prefix", $lines) . "\n";
|
||||
}
|
||||
|
||||
function _context($lines)
|
||||
{
|
||||
return $this->_lines($lines, ' ');
|
||||
}
|
||||
|
||||
function _added($lines)
|
||||
{
|
||||
return $this->_lines($lines, '> ');
|
||||
}
|
||||
|
||||
function _deleted($lines)
|
||||
{
|
||||
return $this->_lines($lines, '< ');
|
||||
}
|
||||
|
||||
function _changed($orig, $final)
|
||||
{
|
||||
return $this->_deleted($orig) . "---\n" . $this->_added($final);
|
||||
}
|
||||
|
||||
}
|
||||
77
framework/gii/components/Pear/Text/Diff/Renderer/context.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
/**
|
||||
* "Context" diff renderer.
|
||||
*
|
||||
* This class renders the diff in classic "context diff" format.
|
||||
*
|
||||
* $Horde: framework/Text_Diff/Diff/Renderer/context.php,v 1.3.2.3 2008/01/04 10:37:27 jan Exp $
|
||||
*
|
||||
* Copyright 2004-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
|
||||
*
|
||||
* @package Text_Diff
|
||||
*/
|
||||
|
||||
/** Text_Diff_Renderer */
|
||||
require_once 'Text/Diff/Renderer.php';
|
||||
|
||||
/**
|
||||
* @package Text_Diff
|
||||
*/
|
||||
class Text_Diff_Renderer_context extends Text_Diff_Renderer {
|
||||
|
||||
/**
|
||||
* Number of leading context "lines" to preserve.
|
||||
*/
|
||||
var $_leading_context_lines = 4;
|
||||
|
||||
/**
|
||||
* Number of trailing context "lines" to preserve.
|
||||
*/
|
||||
var $_trailing_context_lines = 4;
|
||||
|
||||
var $_second_block = '';
|
||||
|
||||
function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
|
||||
{
|
||||
if ($xlen != 1) {
|
||||
$xbeg .= ',' . $xlen;
|
||||
}
|
||||
if ($ylen != 1) {
|
||||
$ybeg .= ',' . $ylen;
|
||||
}
|
||||
$this->_second_block = "--- $ybeg ----\n";
|
||||
return "***************\n*** $xbeg ****";
|
||||
}
|
||||
|
||||
function _endBlock()
|
||||
{
|
||||
return $this->_second_block;
|
||||
}
|
||||
|
||||
function _context($lines)
|
||||
{
|
||||
$this->_second_block .= $this->_lines($lines, ' ');
|
||||
return $this->_lines($lines, ' ');
|
||||
}
|
||||
|
||||
function _added($lines)
|
||||
{
|
||||
$this->_second_block .= $this->_lines($lines, '+ ');
|
||||
return '';
|
||||
}
|
||||
|
||||
function _deleted($lines)
|
||||
{
|
||||
return $this->_lines($lines, '- ');
|
||||
}
|
||||
|
||||
function _changed($orig, $final)
|
||||
{
|
||||
$this->_second_block .= $this->_lines($final, '! ');
|
||||
return $this->_lines($orig, '! ');
|
||||
}
|
||||
|
||||
}
|
||||
170
framework/gii/components/Pear/Text/Diff/Renderer/inline.php
Normal file
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
/**
|
||||
* "Inline" diff renderer.
|
||||
*
|
||||
* $Horde: framework/Text_Diff/Diff/Renderer/inline.php,v 1.4.10.14 2008/01/04 10:37:27 jan Exp $
|
||||
*
|
||||
* Copyright 2004-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
|
||||
*
|
||||
* @author Ciprian Popovici
|
||||
* @package Text_Diff
|
||||
*/
|
||||
|
||||
/** Text_Diff_Renderer */
|
||||
require_once 'Text/Diff/Renderer.php';
|
||||
|
||||
/**
|
||||
* "Inline" diff renderer.
|
||||
*
|
||||
* This class renders diffs in the Wiki-style "inline" format.
|
||||
*
|
||||
* @author Ciprian Popovici
|
||||
* @package Text_Diff
|
||||
*/
|
||||
class Text_Diff_Renderer_inline extends Text_Diff_Renderer {
|
||||
|
||||
/**
|
||||
* Number of leading context "lines" to preserve.
|
||||
*/
|
||||
var $_leading_context_lines = 10000;
|
||||
|
||||
/**
|
||||
* Number of trailing context "lines" to preserve.
|
||||
*/
|
||||
var $_trailing_context_lines = 10000;
|
||||
|
||||
/**
|
||||
* Prefix for inserted text.
|
||||
*/
|
||||
var $_ins_prefix = '<ins>';
|
||||
|
||||
/**
|
||||
* Suffix for inserted text.
|
||||
*/
|
||||
var $_ins_suffix = '</ins>';
|
||||
|
||||
/**
|
||||
* Prefix for deleted text.
|
||||
*/
|
||||
var $_del_prefix = '<del>';
|
||||
|
||||
/**
|
||||
* Suffix for deleted text.
|
||||
*/
|
||||
var $_del_suffix = '</del>';
|
||||
|
||||
/**
|
||||
* Header for each change block.
|
||||
*/
|
||||
var $_block_header = '';
|
||||
|
||||
/**
|
||||
* What are we currently splitting on? Used to recurse to show word-level
|
||||
* changes.
|
||||
*/
|
||||
var $_split_level = 'lines';
|
||||
|
||||
function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
|
||||
{
|
||||
return $this->_block_header;
|
||||
}
|
||||
|
||||
function _startBlock($header)
|
||||
{
|
||||
return $header;
|
||||
}
|
||||
|
||||
function _lines($lines, $prefix = ' ', $encode = true)
|
||||
{
|
||||
if ($encode) {
|
||||
array_walk($lines, array(&$this, '_encode'));
|
||||
}
|
||||
|
||||
if ($this->_split_level == 'words') {
|
||||
return implode('', $lines);
|
||||
} else {
|
||||
return implode("\n", $lines) . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
function _added($lines)
|
||||
{
|
||||
array_walk($lines, array(&$this, '_encode'));
|
||||
$lines[0] = $this->_ins_prefix . $lines[0];
|
||||
$lines[count($lines) - 1] .= $this->_ins_suffix;
|
||||
return $this->_lines($lines, ' ', false);
|
||||
}
|
||||
|
||||
function _deleted($lines, $words = false)
|
||||
{
|
||||
array_walk($lines, array(&$this, '_encode'));
|
||||
$lines[0] = $this->_del_prefix . $lines[0];
|
||||
$lines[count($lines) - 1] .= $this->_del_suffix;
|
||||
return $this->_lines($lines, ' ', false);
|
||||
}
|
||||
|
||||
function _changed($orig, $final)
|
||||
{
|
||||
/* If we've already split on words, don't try to do so again - just
|
||||
* display. */
|
||||
if ($this->_split_level == 'words') {
|
||||
$prefix = '';
|
||||
while ($orig[0] !== false && $final[0] !== false &&
|
||||
substr($orig[0], 0, 1) == ' ' &&
|
||||
substr($final[0], 0, 1) == ' ') {
|
||||
$prefix .= substr($orig[0], 0, 1);
|
||||
$orig[0] = substr($orig[0], 1);
|
||||
$final[0] = substr($final[0], 1);
|
||||
}
|
||||
return $prefix . $this->_deleted($orig) . $this->_added($final);
|
||||
}
|
||||
|
||||
$text1 = implode("\n", $orig);
|
||||
$text2 = implode("\n", $final);
|
||||
|
||||
/* Non-printing newline marker. */
|
||||
$nl = "\0";
|
||||
|
||||
/* We want to split on word boundaries, but we need to
|
||||
* preserve whitespace as well. Therefore we split on words,
|
||||
* but include all blocks of whitespace in the wordlist. */
|
||||
$diff = new Text_Diff($this->_splitOnWords($text1, $nl),
|
||||
$this->_splitOnWords($text2, $nl));
|
||||
|
||||
/* Get the diff in inline format. */
|
||||
$renderer = new Text_Diff_Renderer_inline(array_merge($this->getParams(),
|
||||
array('split_level' => 'words')));
|
||||
|
||||
/* Run the diff and get the output. */
|
||||
return str_replace($nl, "\n", $renderer->render($diff)) . "\n";
|
||||
}
|
||||
|
||||
function _splitOnWords($string, $newlineEscape = "\n")
|
||||
{
|
||||
// Ignore \0; otherwise the while loop will never finish.
|
||||
$string = str_replace("\0", '', $string);
|
||||
|
||||
$words = array();
|
||||
$length = strlen($string);
|
||||
$pos = 0;
|
||||
|
||||
while ($pos < $length) {
|
||||
// Eat a word with any preceding whitespace.
|
||||
$spaces = strspn(substr($string, $pos), " \n");
|
||||
$nextpos = strcspn(substr($string, $pos + $spaces), " \n");
|
||||
$words[] = str_replace("\n", $newlineEscape, substr($string, $pos, $spaces + $nextpos));
|
||||
$pos += $spaces + $nextpos;
|
||||
}
|
||||
|
||||
return $words;
|
||||
}
|
||||
|
||||
function _encode(&$string)
|
||||
{
|
||||
$string = htmlspecialchars($string);
|
||||
}
|
||||
|
||||
}
|
||||
67
framework/gii/components/Pear/Text/Diff/Renderer/unified.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/**
|
||||
* "Unified" diff renderer.
|
||||
*
|
||||
* This class renders the diff in classic "unified diff" format.
|
||||
*
|
||||
* $Horde: framework/Text_Diff/Diff/Renderer/unified.php,v 1.3.10.6 2008/01/04 10:37:27 jan Exp $
|
||||
*
|
||||
* Copyright 2004-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
|
||||
*
|
||||
* @author Ciprian Popovici
|
||||
* @package Text_Diff
|
||||
*/
|
||||
|
||||
/** Text_Diff_Renderer */
|
||||
require_once 'Text/Diff/Renderer.php';
|
||||
|
||||
/**
|
||||
* @package Text_Diff
|
||||
*/
|
||||
class Text_Diff_Renderer_unified extends Text_Diff_Renderer {
|
||||
|
||||
/**
|
||||
* Number of leading context "lines" to preserve.
|
||||
*/
|
||||
var $_leading_context_lines = 4;
|
||||
|
||||
/**
|
||||
* Number of trailing context "lines" to preserve.
|
||||
*/
|
||||
var $_trailing_context_lines = 4;
|
||||
|
||||
function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
|
||||
{
|
||||
if ($xlen != 1) {
|
||||
$xbeg .= ',' . $xlen;
|
||||
}
|
||||
if ($ylen != 1) {
|
||||
$ybeg .= ',' . $ylen;
|
||||
}
|
||||
return "@@ -$xbeg +$ybeg @@";
|
||||
}
|
||||
|
||||
function _context($lines)
|
||||
{
|
||||
return $this->_lines($lines, ' ');
|
||||
}
|
||||
|
||||
function _added($lines)
|
||||
{
|
||||
return $this->_lines($lines, '+');
|
||||
}
|
||||
|
||||
function _deleted($lines)
|
||||
{
|
||||
return $this->_lines($lines, '-');
|
||||
}
|
||||
|
||||
function _changed($orig, $final)
|
||||
{
|
||||
return $this->_deleted($orig) . $this->_added($final);
|
||||
}
|
||||
|
||||
}
|
||||
276
framework/gii/components/Pear/Text/Diff/ThreeWay.php
Normal file
@@ -0,0 +1,276 @@
|
||||
<?php
|
||||
/**
|
||||
* A class for computing three way diffs.
|
||||
*
|
||||
* $Horde: framework/Text_Diff/Diff/ThreeWay.php,v 1.3.2.3 2008/01/04 10:37:27 jan Exp $
|
||||
*
|
||||
* Copyright 2007-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
|
||||
*
|
||||
* @package Text_Diff
|
||||
* @since 0.3.0
|
||||
*/
|
||||
|
||||
/** Text_Diff */
|
||||
require_once 'Text/Diff.php';
|
||||
|
||||
/**
|
||||
* A class for computing three way diffs.
|
||||
*
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*/
|
||||
class Text_Diff_ThreeWay extends Text_Diff {
|
||||
|
||||
/**
|
||||
* Conflict counter.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $_conflictingBlocks = 0;
|
||||
|
||||
/**
|
||||
* Computes diff between 3 sequences of strings.
|
||||
*
|
||||
* @param array $orig The original lines to use.
|
||||
* @param array $final1 The first version to compare to.
|
||||
* @param array $final2 The second version to compare to.
|
||||
*/
|
||||
function Text_Diff_ThreeWay($orig, $final1, $final2)
|
||||
{
|
||||
if (extension_loaded('xdiff')) {
|
||||
$engine = new Text_Diff_Engine_xdiff();
|
||||
} else {
|
||||
$engine = new Text_Diff_Engine_native();
|
||||
}
|
||||
|
||||
$this->_edits = $this->_diff3($engine->diff($orig, $final1),
|
||||
$engine->diff($orig, $final2));
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function mergedOutput($label1 = false, $label2 = false)
|
||||
{
|
||||
$lines = array();
|
||||
foreach ($this->_edits as $edit) {
|
||||
if ($edit->isConflict()) {
|
||||
/* FIXME: this should probably be moved somewhere else. */
|
||||
$lines = array_merge($lines,
|
||||
array('<<<<<<<' . ($label1 ? ' ' . $label1 : '')),
|
||||
$edit->final1,
|
||||
array("======="),
|
||||
$edit->final2,
|
||||
array('>>>>>>>' . ($label2 ? ' ' . $label2 : '')));
|
||||
$this->_conflictingBlocks++;
|
||||
} else {
|
||||
$lines = array_merge($lines, $edit->merged());
|
||||
}
|
||||
}
|
||||
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @access private
|
||||
*/
|
||||
function _diff3($edits1, $edits2)
|
||||
{
|
||||
$edits = array();
|
||||
$bb = new Text_Diff_ThreeWay_BlockBuilder();
|
||||
|
||||
$e1 = current($edits1);
|
||||
$e2 = current($edits2);
|
||||
while ($e1 || $e2) {
|
||||
if ($e1 && $e2 && is_a($e1, 'Text_Diff_Op_copy') && is_a($e2, 'Text_Diff_Op_copy')) {
|
||||
/* We have copy blocks from both diffs. This is the (only)
|
||||
* time we want to emit a diff3 copy block. Flush current
|
||||
* diff3 diff block, if any. */
|
||||
if ($edit = $bb->finish()) {
|
||||
$edits[] = $edit;
|
||||
}
|
||||
|
||||
$ncopy = min($e1->norig(), $e2->norig());
|
||||
assert($ncopy > 0);
|
||||
$edits[] = new Text_Diff_ThreeWay_Op_copy(array_slice($e1->orig, 0, $ncopy));
|
||||
|
||||
if ($e1->norig() > $ncopy) {
|
||||
array_splice($e1->orig, 0, $ncopy);
|
||||
array_splice($e1->final, 0, $ncopy);
|
||||
} else {
|
||||
$e1 = next($edits1);
|
||||
}
|
||||
|
||||
if ($e2->norig() > $ncopy) {
|
||||
array_splice($e2->orig, 0, $ncopy);
|
||||
array_splice($e2->final, 0, $ncopy);
|
||||
} else {
|
||||
$e2 = next($edits2);
|
||||
}
|
||||
} else {
|
||||
if ($e1 && $e2) {
|
||||
if ($e1->orig && $e2->orig) {
|
||||
$norig = min($e1->norig(), $e2->norig());
|
||||
$orig = array_splice($e1->orig, 0, $norig);
|
||||
array_splice($e2->orig, 0, $norig);
|
||||
$bb->input($orig);
|
||||
}
|
||||
|
||||
if (is_a($e1, 'Text_Diff_Op_copy')) {
|
||||
$bb->out1(array_splice($e1->final, 0, $norig));
|
||||
}
|
||||
|
||||
if (is_a($e2, 'Text_Diff_Op_copy')) {
|
||||
$bb->out2(array_splice($e2->final, 0, $norig));
|
||||
}
|
||||
}
|
||||
|
||||
if ($e1 && ! $e1->orig) {
|
||||
$bb->out1($e1->final);
|
||||
$e1 = next($edits1);
|
||||
}
|
||||
if ($e2 && ! $e2->orig) {
|
||||
$bb->out2($e2->final);
|
||||
$e2 = next($edits2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($edit = $bb->finish()) {
|
||||
$edits[] = $edit;
|
||||
}
|
||||
|
||||
return $edits;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
class Text_Diff_ThreeWay_Op {
|
||||
|
||||
function Text_Diff_ThreeWay_Op($orig = false, $final1 = false, $final2 = false)
|
||||
{
|
||||
$this->orig = $orig ? $orig : array();
|
||||
$this->final1 = $final1 ? $final1 : array();
|
||||
$this->final2 = $final2 ? $final2 : array();
|
||||
}
|
||||
|
||||
function merged()
|
||||
{
|
||||
if (!isset($this->_merged)) {
|
||||
if ($this->final1 === $this->final2) {
|
||||
$this->_merged = &$this->final1;
|
||||
} elseif ($this->final1 === $this->orig) {
|
||||
$this->_merged = &$this->final2;
|
||||
} elseif ($this->final2 === $this->orig) {
|
||||
$this->_merged = &$this->final1;
|
||||
} else {
|
||||
$this->_merged = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_merged;
|
||||
}
|
||||
|
||||
function isConflict()
|
||||
{
|
||||
return $this->merged() === false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
class Text_Diff_ThreeWay_Op_copy extends Text_Diff_ThreeWay_Op {
|
||||
|
||||
function Text_Diff_ThreeWay_Op_Copy($lines = false)
|
||||
{
|
||||
$this->orig = $lines ? $lines : array();
|
||||
$this->final1 = &$this->orig;
|
||||
$this->final2 = &$this->orig;
|
||||
}
|
||||
|
||||
function merged()
|
||||
{
|
||||
return $this->orig;
|
||||
}
|
||||
|
||||
function isConflict()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
class Text_Diff_ThreeWay_BlockBuilder {
|
||||
|
||||
function Text_Diff_ThreeWay_BlockBuilder()
|
||||
{
|
||||
$this->_init();
|
||||
}
|
||||
|
||||
function input($lines)
|
||||
{
|
||||
if ($lines) {
|
||||
$this->_append($this->orig, $lines);
|
||||
}
|
||||
}
|
||||
|
||||
function out1($lines)
|
||||
{
|
||||
if ($lines) {
|
||||
$this->_append($this->final1, $lines);
|
||||
}
|
||||
}
|
||||
|
||||
function out2($lines)
|
||||
{
|
||||
if ($lines) {
|
||||
$this->_append($this->final2, $lines);
|
||||
}
|
||||
}
|
||||
|
||||
function isEmpty()
|
||||
{
|
||||
return !$this->orig && !$this->final1 && !$this->final2;
|
||||
}
|
||||
|
||||
function finish()
|
||||
{
|
||||
if ($this->isEmpty()) {
|
||||
return false;
|
||||
} else {
|
||||
$edit = new Text_Diff_ThreeWay_Op($this->orig, $this->final1, $this->final2);
|
||||
$this->_init();
|
||||
return $edit;
|
||||
}
|
||||
}
|
||||
|
||||
function _init()
|
||||
{
|
||||
$this->orig = $this->final1 = $this->final2 = array();
|
||||
}
|
||||
|
||||
function _append(&$array, $lines)
|
||||
{
|
||||
array_splice($array, sizeof($array), 0, $lines);
|
||||
}
|
||||
|
||||
}
|
||||
276
framework/gii/components/Pear/Text/Diff3.php
Normal file
@@ -0,0 +1,276 @@
|
||||
<?php
|
||||
/**
|
||||
* A class for computing three way diffs.
|
||||
*
|
||||
* $Horde: framework/Text_Diff/Diff3.php,v 1.2.10.6 2008/01/04 10:37:26 jan Exp $
|
||||
*
|
||||
* Copyright 2007-2008 The Horde Project (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
|
||||
*
|
||||
* @package Text_Diff
|
||||
* @since 0.3.0
|
||||
*/
|
||||
|
||||
/** Text_Diff */
|
||||
require_once 'Text/Diff.php';
|
||||
|
||||
/**
|
||||
* A class for computing three way diffs.
|
||||
*
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*/
|
||||
class Text_Diff3 extends Text_Diff {
|
||||
|
||||
/**
|
||||
* Conflict counter.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
var $_conflictingBlocks = 0;
|
||||
|
||||
/**
|
||||
* Computes diff between 3 sequences of strings.
|
||||
*
|
||||
* @param array $orig The original lines to use.
|
||||
* @param array $final1 The first version to compare to.
|
||||
* @param array $final2 The second version to compare to.
|
||||
*/
|
||||
function Text_Diff3($orig, $final1, $final2)
|
||||
{
|
||||
if (extension_loaded('xdiff')) {
|
||||
$engine = new Text_Diff_Engine_xdiff();
|
||||
} else {
|
||||
$engine = new Text_Diff_Engine_native();
|
||||
}
|
||||
|
||||
$this->_edits = $this->_diff3($engine->diff($orig, $final1),
|
||||
$engine->diff($orig, $final2));
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function mergedOutput($label1 = false, $label2 = false)
|
||||
{
|
||||
$lines = array();
|
||||
foreach ($this->_edits as $edit) {
|
||||
if ($edit->isConflict()) {
|
||||
/* FIXME: this should probably be moved somewhere else. */
|
||||
$lines = array_merge($lines,
|
||||
array('<<<<<<<' . ($label1 ? ' ' . $label1 : '')),
|
||||
$edit->final1,
|
||||
array("======="),
|
||||
$edit->final2,
|
||||
array('>>>>>>>' . ($label2 ? ' ' . $label2 : '')));
|
||||
$this->_conflictingBlocks++;
|
||||
} else {
|
||||
$lines = array_merge($lines, $edit->merged());
|
||||
}
|
||||
}
|
||||
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @access private
|
||||
*/
|
||||
function _diff3($edits1, $edits2)
|
||||
{
|
||||
$edits = array();
|
||||
$bb = new Text_Diff3_BlockBuilder();
|
||||
|
||||
$e1 = current($edits1);
|
||||
$e2 = current($edits2);
|
||||
while ($e1 || $e2) {
|
||||
if ($e1 && $e2 && is_a($e1, 'Text_Diff_Op_copy') && is_a($e2, 'Text_Diff_Op_copy')) {
|
||||
/* We have copy blocks from both diffs. This is the (only)
|
||||
* time we want to emit a diff3 copy block. Flush current
|
||||
* diff3 diff block, if any. */
|
||||
if ($edit = $bb->finish()) {
|
||||
$edits[] = $edit;
|
||||
}
|
||||
|
||||
$ncopy = min($e1->norig(), $e2->norig());
|
||||
assert($ncopy > 0);
|
||||
$edits[] = new Text_Diff3_Op_copy(array_slice($e1->orig, 0, $ncopy));
|
||||
|
||||
if ($e1->norig() > $ncopy) {
|
||||
array_splice($e1->orig, 0, $ncopy);
|
||||
array_splice($e1->final, 0, $ncopy);
|
||||
} else {
|
||||
$e1 = next($edits1);
|
||||
}
|
||||
|
||||
if ($e2->norig() > $ncopy) {
|
||||
array_splice($e2->orig, 0, $ncopy);
|
||||
array_splice($e2->final, 0, $ncopy);
|
||||
} else {
|
||||
$e2 = next($edits2);
|
||||
}
|
||||
} else {
|
||||
if ($e1 && $e2) {
|
||||
if ($e1->orig && $e2->orig) {
|
||||
$norig = min($e1->norig(), $e2->norig());
|
||||
$orig = array_splice($e1->orig, 0, $norig);
|
||||
array_splice($e2->orig, 0, $norig);
|
||||
$bb->input($orig);
|
||||
}
|
||||
|
||||
if (is_a($e1, 'Text_Diff_Op_copy')) {
|
||||
$bb->out1(array_splice($e1->final, 0, $norig));
|
||||
}
|
||||
|
||||
if (is_a($e2, 'Text_Diff_Op_copy')) {
|
||||
$bb->out2(array_splice($e2->final, 0, $norig));
|
||||
}
|
||||
}
|
||||
|
||||
if ($e1 && ! $e1->orig) {
|
||||
$bb->out1($e1->final);
|
||||
$e1 = next($edits1);
|
||||
}
|
||||
if ($e2 && ! $e2->orig) {
|
||||
$bb->out2($e2->final);
|
||||
$e2 = next($edits2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($edit = $bb->finish()) {
|
||||
$edits[] = $edit;
|
||||
}
|
||||
|
||||
return $edits;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
class Text_Diff3_Op {
|
||||
|
||||
function Text_Diff3_Op($orig = false, $final1 = false, $final2 = false)
|
||||
{
|
||||
$this->orig = $orig ? $orig : array();
|
||||
$this->final1 = $final1 ? $final1 : array();
|
||||
$this->final2 = $final2 ? $final2 : array();
|
||||
}
|
||||
|
||||
function merged()
|
||||
{
|
||||
if (!isset($this->_merged)) {
|
||||
if ($this->final1 === $this->final2) {
|
||||
$this->_merged = &$this->final1;
|
||||
} elseif ($this->final1 === $this->orig) {
|
||||
$this->_merged = &$this->final2;
|
||||
} elseif ($this->final2 === $this->orig) {
|
||||
$this->_merged = &$this->final1;
|
||||
} else {
|
||||
$this->_merged = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_merged;
|
||||
}
|
||||
|
||||
function isConflict()
|
||||
{
|
||||
return $this->merged() === false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
class Text_Diff3_Op_copy extends Text_Diff3_Op {
|
||||
|
||||
function Text_Diff3_Op_Copy($lines = false)
|
||||
{
|
||||
$this->orig = $lines ? $lines : array();
|
||||
$this->final1 = &$this->orig;
|
||||
$this->final2 = &$this->orig;
|
||||
}
|
||||
|
||||
function merged()
|
||||
{
|
||||
return $this->orig;
|
||||
}
|
||||
|
||||
function isConflict()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
class Text_Diff3_BlockBuilder {
|
||||
|
||||
function Text_Diff3_BlockBuilder()
|
||||
{
|
||||
$this->_init();
|
||||
}
|
||||
|
||||
function input($lines)
|
||||
{
|
||||
if ($lines) {
|
||||
$this->_append($this->orig, $lines);
|
||||
}
|
||||
}
|
||||
|
||||
function out1($lines)
|
||||
{
|
||||
if ($lines) {
|
||||
$this->_append($this->final1, $lines);
|
||||
}
|
||||
}
|
||||
|
||||
function out2($lines)
|
||||
{
|
||||
if ($lines) {
|
||||
$this->_append($this->final2, $lines);
|
||||
}
|
||||
}
|
||||
|
||||
function isEmpty()
|
||||
{
|
||||
return !$this->orig && !$this->final1 && !$this->final2;
|
||||
}
|
||||
|
||||
function finish()
|
||||
{
|
||||
if ($this->isEmpty()) {
|
||||
return false;
|
||||
} else {
|
||||
$edit = new Text_Diff3_Op($this->orig, $this->final1, $this->final2);
|
||||
$this->_init();
|
||||
return $edit;
|
||||
}
|
||||
}
|
||||
|
||||
function _init()
|
||||
{
|
||||
$this->orig = $this->final1 = $this->final2 = array();
|
||||
}
|
||||
|
||||
function _append(&$array, $lines)
|
||||
{
|
||||
array_splice($array, sizeof($array), 0, $lines);
|
||||
}
|
||||
|
||||
}
|
||||
22
framework/gii/components/TextDiff.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
error_reporting(E_ALL);
|
||||
|
||||
Yii::import('gii.components.Pear.*');
|
||||
require_once 'Text/Diff.php';
|
||||
require_once 'Text/Diff/Renderer.php';
|
||||
require_once 'Text/Diff/Renderer/inline.php';
|
||||
|
||||
class TextDiff extends CComponent
|
||||
{
|
||||
public static function compare($lines1, $lines2)
|
||||
{
|
||||
if(is_string($lines1))
|
||||
$lines1=explode("\n",$lines1);
|
||||
if(is_string($lines2))
|
||||
$lines2=explode("\n",$lines2);
|
||||
$diff = new Text_Diff('auto', array($lines1, $lines2));
|
||||
$renderer = new Text_Diff_Renderer_inline();
|
||||
return $renderer->render($diff);
|
||||
}
|
||||
}
|
||||
20
framework/gii/components/UserIdentity.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
class UserIdentity extends CUserIdentity
|
||||
{
|
||||
/**
|
||||
* Authenticates a user.
|
||||
* @return boolean whether authentication succeeds.
|
||||
*/
|
||||
public function authenticate()
|
||||
{
|
||||
$password=Yii::app()->getController()->getModule()->password;
|
||||
if($password===null)
|
||||
throw new CException('Please configure the "password" property of the "gii" module.');
|
||||
elseif($password===false || $password===$this->password)
|
||||
$this->errorCode=self::ERROR_NONE;
|
||||
else
|
||||
$this->errorCode=self::ERROR_UNKNOWN_IDENTITY;
|
||||
return !$this->errorCode;
|
||||
}
|
||||
}
|
||||
58
framework/gii/controllers/DefaultController.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
class DefaultController extends CController
|
||||
{
|
||||
public $layout='/layouts/column1';
|
||||
|
||||
public function getPageTitle()
|
||||
{
|
||||
if($this->action->id==='index')
|
||||
return 'Gii: a Web-based code generator for Yii';
|
||||
else
|
||||
return 'Gii - '.ucfirst($this->action->id).' Generator';
|
||||
}
|
||||
|
||||
public function actionIndex()
|
||||
{
|
||||
$this->render('index');
|
||||
}
|
||||
|
||||
public function actionError()
|
||||
{
|
||||
if($error=Yii::app()->errorHandler->error)
|
||||
{
|
||||
if(Yii::app()->request->isAjaxRequest)
|
||||
echo $error['message'];
|
||||
else
|
||||
$this->render('error', $error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the login page
|
||||
*/
|
||||
public function actionLogin()
|
||||
{
|
||||
$model=Yii::createComponent('gii.models.LoginForm');
|
||||
|
||||
// collect user input data
|
||||
if(isset($_POST['LoginForm']))
|
||||
{
|
||||
$model->attributes=$_POST['LoginForm'];
|
||||
// validate user input and redirect to the previous page if valid
|
||||
if($model->validate() && $model->login())
|
||||
$this->redirect(array('index'));
|
||||
}
|
||||
// display the login form
|
||||
$this->render('login',array('model'=>$model));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs out the current user and redirect to homepage.
|
||||
*/
|
||||
public function actionLogout()
|
||||
{
|
||||
Yii::app()->user->logout(false);
|
||||
$this->redirect(array('index'));
|
||||
}
|
||||
}
|
||||
130
framework/gii/generators/controller/ControllerCode.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
class ControllerCode extends CCodeModel
|
||||
{
|
||||
public $controller;
|
||||
public $baseClass='Controller';
|
||||
public $actions='index';
|
||||
|
||||
public function rules()
|
||||
{
|
||||
return array_merge(parent::rules(), array(
|
||||
array('controller, actions, baseClass', 'filter', 'filter'=>'trim'),
|
||||
array('controller, baseClass', 'required'),
|
||||
array('controller', 'match', 'pattern'=>'/^\w+[\w+\\/]*$/', 'message'=>'{attribute} should only contain word characters and slashes.'),
|
||||
array('actions', 'match', 'pattern'=>'/^\w+[\w\s,]*$/', 'message'=>'{attribute} should only contain word characters, spaces and commas.'),
|
||||
array('baseClass', 'match', 'pattern'=>'/^[a-zA-Z_][\w\\\\]*$/', 'message'=>'{attribute} should only contain word characters and backslashes.'),
|
||||
array('baseClass', 'validateReservedWord', 'skipOnError'=>true),
|
||||
array('baseClass, actions', 'sticky'),
|
||||
));
|
||||
}
|
||||
|
||||
public function attributeLabels()
|
||||
{
|
||||
return array_merge(parent::attributeLabels(), array(
|
||||
'baseClass'=>'Base Class',
|
||||
'controller'=>'Controller ID',
|
||||
'actions'=>'Action IDs',
|
||||
));
|
||||
}
|
||||
|
||||
public function requiredTemplates()
|
||||
{
|
||||
return array(
|
||||
'controller.php',
|
||||
'view.php',
|
||||
);
|
||||
}
|
||||
|
||||
public function successMessage()
|
||||
{
|
||||
$link=CHtml::link('try it now', Yii::app()->createUrl($this->controller), array('target'=>'_blank'));
|
||||
return "The controller has been generated successfully. You may $link.";
|
||||
}
|
||||
|
||||
public function prepare()
|
||||
{
|
||||
$this->files=array();
|
||||
$templatePath=$this->templatePath;
|
||||
|
||||
$this->files[]=new CCodeFile(
|
||||
$this->controllerFile,
|
||||
$this->render($templatePath.'/controller.php')
|
||||
);
|
||||
|
||||
foreach($this->getActionIDs() as $action)
|
||||
{
|
||||
$this->files[]=new CCodeFile(
|
||||
$this->getViewFile($action),
|
||||
$this->render($templatePath.'/view.php', array('action'=>$action))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function getActionIDs()
|
||||
{
|
||||
$actions=preg_split('/[\s,]+/',$this->actions,-1,PREG_SPLIT_NO_EMPTY);
|
||||
$actions=array_unique($actions);
|
||||
sort($actions);
|
||||
return $actions;
|
||||
}
|
||||
|
||||
public function getControllerClass()
|
||||
{
|
||||
if(($pos=strrpos($this->controller,'/'))!==false)
|
||||
return ucfirst(substr($this->controller,$pos+1)).'Controller';
|
||||
else
|
||||
return ucfirst($this->controller).'Controller';
|
||||
}
|
||||
|
||||
public function getModule()
|
||||
{
|
||||
if(($pos=strpos($this->controller,'/'))!==false)
|
||||
{
|
||||
$id=substr($this->controller,0,$pos);
|
||||
if(($module=Yii::app()->getModule($id))!==null)
|
||||
return $module;
|
||||
}
|
||||
return Yii::app();
|
||||
}
|
||||
|
||||
public function getControllerID()
|
||||
{
|
||||
if($this->getModule()!==Yii::app())
|
||||
$id=substr($this->controller,strpos($this->controller,'/')+1);
|
||||
else
|
||||
$id=$this->controller;
|
||||
if(($pos=strrpos($id,'/'))!==false)
|
||||
$id[$pos+1]=strtolower($id[$pos+1]);
|
||||
else
|
||||
$id[0]=strtolower($id[0]);
|
||||
return $id;
|
||||
}
|
||||
|
||||
public function getUniqueControllerID()
|
||||
{
|
||||
$id=$this->controller;
|
||||
if(($pos=strrpos($id,'/'))!==false)
|
||||
$id[$pos+1]=strtolower($id[$pos+1]);
|
||||
else
|
||||
$id[0]=strtolower($id[0]);
|
||||
return $id;
|
||||
}
|
||||
|
||||
public function getControllerFile()
|
||||
{
|
||||
$module=$this->getModule();
|
||||
$id=$this->getControllerID();
|
||||
if(($pos=strrpos($id,'/'))!==false)
|
||||
$id[$pos+1]=strtoupper($id[$pos+1]);
|
||||
else
|
||||
$id[0]=strtoupper($id[0]);
|
||||
return $module->getControllerPath().'/'.$id.'Controller.php';
|
||||
}
|
||||
|
||||
public function getViewFile($action)
|
||||
{
|
||||
$module=$this->getModule();
|
||||
return $module->getViewPath().'/'.$this->getControllerID().'/'.$action.'.php';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
class ControllerGenerator extends CCodeGenerator
|
||||
{
|
||||
public $codeModel='gii.generators.controller.ControllerCode';
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* This is the template for generating a controller class file.
|
||||
* The following variables are available in this template:
|
||||
* - $this: the ControllerCode object
|
||||
*/
|
||||
?>
|
||||
<?php echo "<?php\n"; ?>
|
||||
|
||||
class <?php echo $this->controllerClass; ?> extends <?php echo $this->baseClass."\n"; ?>
|
||||
{
|
||||
<?php foreach($this->getActionIDs() as $action): ?>
|
||||
public function action<?php echo ucfirst($action); ?>()
|
||||
{
|
||||
$this->render('<?php echo $action; ?>');
|
||||
}
|
||||
|
||||
<?php endforeach; ?>
|
||||
// Uncomment the following methods and override them if needed
|
||||
/*
|
||||
public function filters()
|
||||
{
|
||||
// return the filter configuration for this controller, e.g.:
|
||||
return array(
|
||||
'inlineFilterName',
|
||||
array(
|
||||
'class'=>'path.to.FilterClass',
|
||||
'propertyName'=>'propertyValue',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function actions()
|
||||
{
|
||||
// return external action classes, e.g.:
|
||||
return array(
|
||||
'action1'=>'path.to.ActionClass',
|
||||
'action2'=>array(
|
||||
'class'=>'path.to.AnotherActionClass',
|
||||
'propertyName'=>'propertyValue',
|
||||
),
|
||||
);
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* This is the template for generating an action view file.
|
||||
* The following variables are available in this template:
|
||||
* - $this: the ControllerCode object
|
||||
* - $action: the action ID
|
||||
*/
|
||||
?>
|
||||
<?php echo "<?php\n"; ?>
|
||||
/* @var $this <?php echo $this->getControllerClass(); ?> */
|
||||
|
||||
<?php
|
||||
$label=ucwords(trim(strtolower(str_replace(array('-','_','.'),' ',preg_replace('/(?<![A-Z])[A-Z]/', ' \0', basename($this->getControllerID()))))));
|
||||
if($action==='index')
|
||||
{
|
||||
echo "\$this->breadcrumbs=array(
|
||||
'$label',
|
||||
);";
|
||||
}
|
||||
else
|
||||
{
|
||||
$action=ucfirst($action);
|
||||
echo "\$this->breadcrumbs=array(
|
||||
'$label'=>array('/{$this->uniqueControllerID}'),
|
||||
'$action',
|
||||
);";
|
||||
}
|
||||
?>
|
||||
|
||||
?>
|
||||
<h1><?php echo '<?php'; ?> echo $this->id . '/' . $this->action->id; ?></h1>
|
||||
|
||||
<p>
|
||||
You may change the content of this page by modifying
|
||||
the file <tt><?php echo '<?php'; ?> echo __FILE__; ?></tt>.
|
||||
</p>
|
||||
45
framework/gii/generators/controller/views/index.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<h1>Controller Generator</h1>
|
||||
|
||||
<p>This generator helps you to quickly generate a new controller class,
|
||||
one or several controller actions and their corresponding views.</p>
|
||||
|
||||
<?php $form=$this->beginWidget('CCodeForm', array('model'=>$model)); ?>
|
||||
|
||||
<div class="row">
|
||||
<?php echo $form->labelEx($model,'controller'); ?>
|
||||
<?php echo $form->textField($model,'controller',array('size'=>65)); ?>
|
||||
<div class="tooltip">
|
||||
Controller ID is case-sensitive. Below are some examples:
|
||||
<ul>
|
||||
<li><code>post</code> generates <code>PostController.php</code></li>
|
||||
<li><code>postTag</code> generates <code>PostTagController.php</code></li>
|
||||
<li><code>admin/user</code> generates <code>admin/UserController.php</code>.
|
||||
If the application has an <code>admin</code> module enabled,
|
||||
it will generate <code>UserController</code> within the module instead.
|
||||
Make sure to write module name in the correct case if it has a camelCase name.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<?php echo $form->error($model,'controller'); ?>
|
||||
</div>
|
||||
|
||||
<div class="row sticky">
|
||||
<?php echo $form->labelEx($model,'baseClass'); ?>
|
||||
<?php echo $form->textField($model,'baseClass',array('size'=>65)); ?>
|
||||
<div class="tooltip">
|
||||
This is the class that the new controller class will extend from.
|
||||
Please make sure the class exists and can be autoloaded.
|
||||
</div>
|
||||
<?php echo $form->error($model,'baseClass'); ?>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<?php echo $form->labelEx($model,'actions'); ?>
|
||||
<?php echo $form->textField($model,'actions',array('size'=>65)); ?>
|
||||
<div class="tooltip">
|
||||
Action IDs are case-insensitive. Separate multiple action IDs with commas or spaces.
|
||||
</div>
|
||||
<?php echo $form->error($model,'actions'); ?>
|
||||
</div>
|
||||
|
||||
<?php $this->endWidget(); ?>
|
||||
248
framework/gii/generators/crud/CrudCode.php
Normal file
@@ -0,0 +1,248 @@
|
||||
<?php
|
||||
|
||||
class CrudCode extends CCodeModel
|
||||
{
|
||||
public $model;
|
||||
public $controller;
|
||||
public $baseControllerClass='Controller';
|
||||
|
||||
private $_modelClass;
|
||||
private $_table;
|
||||
|
||||
public function rules()
|
||||
{
|
||||
return array_merge(parent::rules(), array(
|
||||
array('model, controller', 'filter', 'filter'=>'trim'),
|
||||
array('model, controller, baseControllerClass', 'required'),
|
||||
array('model', 'match', 'pattern'=>'/^\w+[\w+\\.]*$/', 'message'=>'{attribute} should only contain word characters and dots.'),
|
||||
array('controller', 'match', 'pattern'=>'/^\w+[\w+\\/]*$/', 'message'=>'{attribute} should only contain word characters and slashes.'),
|
||||
array('baseControllerClass', 'match', 'pattern'=>'/^[a-zA-Z_][\w\\\\]*$/', 'message'=>'{attribute} should only contain word characters and backslashes.'),
|
||||
array('baseControllerClass', 'validateReservedWord', 'skipOnError'=>true),
|
||||
array('model', 'validateModel'),
|
||||
array('baseControllerClass', 'sticky'),
|
||||
));
|
||||
}
|
||||
|
||||
public function attributeLabels()
|
||||
{
|
||||
return array_merge(parent::attributeLabels(), array(
|
||||
'model'=>'Model Class',
|
||||
'controller'=>'Controller ID',
|
||||
'baseControllerClass'=>'Base Controller Class',
|
||||
));
|
||||
}
|
||||
|
||||
public function requiredTemplates()
|
||||
{
|
||||
return array(
|
||||
'controller.php',
|
||||
);
|
||||
}
|
||||
|
||||
public function init()
|
||||
{
|
||||
if(Yii::app()->db===null)
|
||||
throw new CHttpException(500,'An active "db" connection is required to run this generator.');
|
||||
parent::init();
|
||||
}
|
||||
|
||||
public function successMessage()
|
||||
{
|
||||
$link=CHtml::link('try it now', Yii::app()->createUrl($this->controller), array('target'=>'_blank'));
|
||||
return "The controller has been generated successfully. You may $link.";
|
||||
}
|
||||
|
||||
public function validateModel($attribute,$params)
|
||||
{
|
||||
if($this->hasErrors('model'))
|
||||
return;
|
||||
$class=@Yii::import($this->model,true);
|
||||
if(!is_string($class) || !$this->classExists($class))
|
||||
$this->addError('model', "Class '{$this->model}' does not exist or has syntax error.");
|
||||
elseif(!is_subclass_of($class,'CActiveRecord'))
|
||||
$this->addError('model', "'{$this->model}' must extend from CActiveRecord.");
|
||||
else
|
||||
{
|
||||
$table=CActiveRecord::model($class)->tableSchema;
|
||||
if($table->primaryKey===null)
|
||||
$this->addError('model',"Table '{$table->name}' does not have a primary key.");
|
||||
elseif(is_array($table->primaryKey))
|
||||
$this->addError('model',"Table '{$table->name}' has a composite primary key which is not supported by crud generator.");
|
||||
else
|
||||
{
|
||||
$this->_modelClass=$class;
|
||||
$this->_table=$table;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function prepare()
|
||||
{
|
||||
$this->files=array();
|
||||
$templatePath=$this->templatePath;
|
||||
$controllerTemplateFile=$templatePath.DIRECTORY_SEPARATOR.'controller.php';
|
||||
|
||||
$this->files[]=new CCodeFile(
|
||||
$this->controllerFile,
|
||||
$this->render($controllerTemplateFile)
|
||||
);
|
||||
|
||||
$files=scandir($templatePath);
|
||||
foreach($files as $file)
|
||||
{
|
||||
if(is_file($templatePath.'/'.$file) && CFileHelper::getExtension($file)==='php' && $file!=='controller.php')
|
||||
{
|
||||
$this->files[]=new CCodeFile(
|
||||
$this->viewPath.DIRECTORY_SEPARATOR.$file,
|
||||
$this->render($templatePath.'/'.$file)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getModelClass()
|
||||
{
|
||||
return $this->_modelClass;
|
||||
}
|
||||
|
||||
public function getControllerClass()
|
||||
{
|
||||
if(($pos=strrpos($this->controller,'/'))!==false)
|
||||
return ucfirst(substr($this->controller,$pos+1)).'Controller';
|
||||
else
|
||||
return ucfirst($this->controller).'Controller';
|
||||
}
|
||||
|
||||
public function getModule()
|
||||
{
|
||||
if(($pos=strpos($this->controller,'/'))!==false)
|
||||
{
|
||||
$id=substr($this->controller,0,$pos);
|
||||
if(($module=Yii::app()->getModule($id))!==null)
|
||||
return $module;
|
||||
}
|
||||
return Yii::app();
|
||||
}
|
||||
|
||||
public function getControllerID()
|
||||
{
|
||||
if($this->getModule()!==Yii::app())
|
||||
$id=substr($this->controller,strpos($this->controller,'/')+1);
|
||||
else
|
||||
$id=$this->controller;
|
||||
if(($pos=strrpos($id,'/'))!==false)
|
||||
$id[$pos+1]=strtolower($id[$pos+1]);
|
||||
else
|
||||
$id[0]=strtolower($id[0]);
|
||||
return $id;
|
||||
}
|
||||
|
||||
public function getUniqueControllerID()
|
||||
{
|
||||
$id=$this->controller;
|
||||
if(($pos=strrpos($id,'/'))!==false)
|
||||
$id[$pos+1]=strtolower($id[$pos+1]);
|
||||
else
|
||||
$id[0]=strtolower($id[0]);
|
||||
return $id;
|
||||
}
|
||||
|
||||
public function getControllerFile()
|
||||
{
|
||||
$module=$this->getModule();
|
||||
$id=$this->getControllerID();
|
||||
if(($pos=strrpos($id,'/'))!==false)
|
||||
$id[$pos+1]=strtoupper($id[$pos+1]);
|
||||
else
|
||||
$id[0]=strtoupper($id[0]);
|
||||
return $module->getControllerPath().'/'.$id.'Controller.php';
|
||||
}
|
||||
|
||||
public function getViewPath()
|
||||
{
|
||||
return $this->getModule()->getViewPath().'/'.$this->getControllerID();
|
||||
}
|
||||
|
||||
public function getTableSchema()
|
||||
{
|
||||
return $this->_table;
|
||||
}
|
||||
|
||||
public function generateInputLabel($modelClass,$column)
|
||||
{
|
||||
return "CHtml::activeLabelEx(\$model,'{$column->name}')";
|
||||
}
|
||||
|
||||
public function generateInputField($modelClass,$column)
|
||||
{
|
||||
if($column->type==='boolean')
|
||||
return "CHtml::activeCheckBox(\$model,'{$column->name}')";
|
||||
elseif(stripos($column->dbType,'text')!==false)
|
||||
return "CHtml::activeTextArea(\$model,'{$column->name}',array('rows'=>6, 'cols'=>50))";
|
||||
else
|
||||
{
|
||||
if(preg_match('/^(password|pass|passwd|passcode)$/i',$column->name))
|
||||
$inputField='activePasswordField';
|
||||
else
|
||||
$inputField='activeTextField';
|
||||
|
||||
if($column->type!=='string' || $column->size===null)
|
||||
return "CHtml::{$inputField}(\$model,'{$column->name}')";
|
||||
else
|
||||
{
|
||||
if(($size=$maxLength=$column->size)>60)
|
||||
$size=60;
|
||||
return "CHtml::{$inputField}(\$model,'{$column->name}',array('size'=>$size,'maxlength'=>$maxLength))";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function generateActiveLabel($modelClass,$column)
|
||||
{
|
||||
return "\$form->labelEx(\$model,'{$column->name}')";
|
||||
}
|
||||
|
||||
public function generateActiveField($modelClass,$column)
|
||||
{
|
||||
if($column->type==='boolean')
|
||||
return "\$form->checkBox(\$model,'{$column->name}')";
|
||||
elseif(stripos($column->dbType,'text')!==false)
|
||||
return "\$form->textArea(\$model,'{$column->name}',array('rows'=>6, 'cols'=>50))";
|
||||
else
|
||||
{
|
||||
if(preg_match('/^(password|pass|passwd|passcode)$/i',$column->name))
|
||||
$inputField='passwordField';
|
||||
else
|
||||
$inputField='textField';
|
||||
|
||||
if($column->type!=='string' || $column->size===null)
|
||||
return "\$form->{$inputField}(\$model,'{$column->name}')";
|
||||
else
|
||||
{
|
||||
if(($size=$maxLength=$column->size)>60)
|
||||
$size=60;
|
||||
return "\$form->{$inputField}(\$model,'{$column->name}',array('size'=>$size,'maxlength'=>$maxLength))";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function guessNameColumn($columns)
|
||||
{
|
||||
foreach($columns as $column)
|
||||
{
|
||||
if(!strcasecmp($column->name,'name'))
|
||||
return $column->name;
|
||||
}
|
||||
foreach($columns as $column)
|
||||
{
|
||||
if(!strcasecmp($column->name,'title'))
|
||||
return $column->name;
|
||||
}
|
||||
foreach($columns as $column)
|
||||
{
|
||||
if($column->isPrimaryKey)
|
||||
return $column->name;
|
||||
}
|
||||
return 'id';
|
||||
}
|
||||
}
|
||||
6
framework/gii/generators/crud/CrudGenerator.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
class CrudGenerator extends CCodeGenerator
|
||||
{
|
||||
public $codeModel='gii.generators.crud.CrudCode';
|
||||
}
|
||||
49
framework/gii/generators/crud/templates/default/_form.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/**
|
||||
* The following variables are available in this template:
|
||||
* - $this: the CrudCode object
|
||||
*/
|
||||
?>
|
||||
<?php echo "<?php\n"; ?>
|
||||
/* @var $this <?php echo $this->getControllerClass(); ?> */
|
||||
/* @var $model <?php echo $this->getModelClass(); ?> */
|
||||
/* @var $form CActiveForm */
|
||||
?>
|
||||
|
||||
<div class="form">
|
||||
|
||||
<?php echo "<?php \$form=\$this->beginWidget('CActiveForm', array(
|
||||
'id'=>'".$this->class2id($this->modelClass)."-form',
|
||||
// Please note: When you enable ajax validation, make sure the corresponding
|
||||
// controller action is handling ajax validation correctly.
|
||||
// There is a call to performAjaxValidation() commented in generated controller code.
|
||||
// See class documentation of CActiveForm for details on this.
|
||||
'enableAjaxValidation'=>false,
|
||||
)); ?>\n"; ?>
|
||||
|
||||
<p class="note">Fields with <span class="required">*</span> are required.</p>
|
||||
|
||||
<?php echo "<?php echo \$form->errorSummary(\$model); ?>\n"; ?>
|
||||
|
||||
<?php
|
||||
foreach($this->tableSchema->columns as $column)
|
||||
{
|
||||
if($column->autoIncrement)
|
||||
continue;
|
||||
?>
|
||||
<div class="row">
|
||||
<?php echo "<?php echo ".$this->generateActiveLabel($this->modelClass,$column)."; ?>\n"; ?>
|
||||
<?php echo "<?php echo ".$this->generateActiveField($this->modelClass,$column)."; ?>\n"; ?>
|
||||
<?php echo "<?php echo \$form->error(\$model,'{$column->name}'); ?>\n"; ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<div class="row buttons">
|
||||
<?php echo "<?php echo CHtml::submitButton(\$model->isNewRecord ? 'Create' : 'Save'); ?>\n"; ?>
|
||||
</div>
|
||||
|
||||
<?php echo "<?php \$this->endWidget(); ?>\n"; ?>
|
||||
|
||||
</div><!-- form -->
|
||||
38
framework/gii/generators/crud/templates/default/_search.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* The following variables are available in this template:
|
||||
* - $this: the CrudCode object
|
||||
*/
|
||||
?>
|
||||
<?php echo "<?php\n"; ?>
|
||||
/* @var $this <?php echo $this->getControllerClass(); ?> */
|
||||
/* @var $model <?php echo $this->getModelClass(); ?> */
|
||||
/* @var $form CActiveForm */
|
||||
?>
|
||||
|
||||
<div class="wide form">
|
||||
|
||||
<?php echo "<?php \$form=\$this->beginWidget('CActiveForm', array(
|
||||
'action'=>Yii::app()->createUrl(\$this->route),
|
||||
'method'=>'get',
|
||||
)); ?>\n"; ?>
|
||||
|
||||
<?php foreach($this->tableSchema->columns as $column): ?>
|
||||
<?php
|
||||
$field=$this->generateInputField($this->modelClass,$column);
|
||||
if(strpos($field,'password')!==false)
|
||||
continue;
|
||||
?>
|
||||
<div class="row">
|
||||
<?php echo "<?php echo \$form->label(\$model,'{$column->name}'); ?>\n"; ?>
|
||||
<?php echo "<?php echo ".$this->generateActiveField($this->modelClass,$column)."; ?>\n"; ?>
|
||||
</div>
|
||||
|
||||
<?php endforeach; ?>
|
||||
<div class="row buttons">
|
||||
<?php echo "<?php echo CHtml::submitButton('Search'); ?>\n"; ?>
|
||||
</div>
|
||||
|
||||
<?php echo "<?php \$this->endWidget(); ?>\n"; ?>
|
||||
|
||||
</div><!-- search-form -->
|
||||
31
framework/gii/generators/crud/templates/default/_view.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
/**
|
||||
* The following variables are available in this template:
|
||||
* - $this: the CrudCode object
|
||||
*/
|
||||
?>
|
||||
<?php echo "<?php\n"; ?>
|
||||
/* @var $this <?php echo $this->getControllerClass(); ?> */
|
||||
/* @var $data <?php echo $this->getModelClass(); ?> */
|
||||
?>
|
||||
|
||||
<div class="view">
|
||||
|
||||
<?php
|
||||
echo "\t<b><?php echo CHtml::encode(\$data->getAttributeLabel('{$this->tableSchema->primaryKey}')); ?>:</b>\n";
|
||||
echo "\t<?php echo CHtml::link(CHtml::encode(\$data->{$this->tableSchema->primaryKey}), array('view', 'id'=>\$data->{$this->tableSchema->primaryKey})); ?>\n\t<br />\n\n";
|
||||
$count=0;
|
||||
foreach($this->tableSchema->columns as $column)
|
||||
{
|
||||
if($column->isPrimaryKey)
|
||||
continue;
|
||||
if(++$count==7)
|
||||
echo "\t<?php /*\n";
|
||||
echo "\t<b><?php echo CHtml::encode(\$data->getAttributeLabel('{$column->name}')); ?>:</b>\n";
|
||||
echo "\t<?php echo CHtml::encode(\$data->{$column->name}); ?>\n\t<br />\n\n";
|
||||
}
|
||||
if($count>=7)
|
||||
echo "\t*/ ?>\n";
|
||||
?>
|
||||
|
||||
</div>
|
||||
73
framework/gii/generators/crud/templates/default/admin.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
* The following variables are available in this template:
|
||||
* - $this: the CrudCode object
|
||||
*/
|
||||
?>
|
||||
<?php echo "<?php\n"; ?>
|
||||
/* @var $this <?php echo $this->getControllerClass(); ?> */
|
||||
/* @var $model <?php echo $this->getModelClass(); ?> */
|
||||
|
||||
<?php
|
||||
$label=$this->pluralize($this->class2name($this->modelClass));
|
||||
echo "\$this->breadcrumbs=array(
|
||||
'$label'=>array('index'),
|
||||
'Manage',
|
||||
);\n";
|
||||
?>
|
||||
|
||||
$this->menu=array(
|
||||
array('label'=>'List <?php echo $this->modelClass; ?>', 'url'=>array('index')),
|
||||
array('label'=>'Create <?php echo $this->modelClass; ?>', 'url'=>array('create')),
|
||||
);
|
||||
|
||||
Yii::app()->clientScript->registerScript('search', "
|
||||
$('.search-button').click(function(){
|
||||
$('.search-form').toggle();
|
||||
return false;
|
||||
});
|
||||
$('.search-form form').submit(function(){
|
||||
$('#<?php echo $this->class2id($this->modelClass); ?>-grid').yiiGridView('update', {
|
||||
data: $(this).serialize()
|
||||
});
|
||||
return false;
|
||||
});
|
||||
");
|
||||
?>
|
||||
|
||||
<h1>Manage <?php echo $this->pluralize($this->class2name($this->modelClass)); ?></h1>
|
||||
|
||||
<p>
|
||||
You may optionally enter a comparison operator (<b><</b>, <b><=</b>, <b>></b>, <b>>=</b>, <b><></b>
|
||||
or <b>=</b>) at the beginning of each of your search values to specify how the comparison should be done.
|
||||
</p>
|
||||
|
||||
<?php echo "<?php echo CHtml::link('Advanced Search','#',array('class'=>'search-button')); ?>"; ?>
|
||||
|
||||
<div class="search-form" style="display:none">
|
||||
<?php echo "<?php \$this->renderPartial('_search',array(
|
||||
'model'=>\$model,
|
||||
)); ?>\n"; ?>
|
||||
</div><!-- search-form -->
|
||||
|
||||
<?php echo "<?php"; ?> $this->widget('zii.widgets.grid.CGridView', array(
|
||||
'id'=>'<?php echo $this->class2id($this->modelClass); ?>-grid',
|
||||
'dataProvider'=>$model->search(),
|
||||
'filter'=>$model,
|
||||
'columns'=>array(
|
||||
<?php
|
||||
$count=0;
|
||||
foreach($this->tableSchema->columns as $column)
|
||||
{
|
||||
if(++$count==7)
|
||||
echo "\t\t/*\n";
|
||||
echo "\t\t'".$column->name."',\n";
|
||||
}
|
||||
if($count>=7)
|
||||
echo "\t\t*/\n";
|
||||
?>
|
||||
array(
|
||||
'class'=>'CButtonColumn',
|
||||
),
|
||||
),
|
||||
)); ?>
|
||||
180
framework/gii/generators/crud/templates/default/controller.php
Normal file
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
/**
|
||||
* This is the template for generating a controller class file for CRUD feature.
|
||||
* The following variables are available in this template:
|
||||
* - $this: the CrudCode object
|
||||
*/
|
||||
?>
|
||||
<?php echo "<?php\n"; ?>
|
||||
|
||||
class <?php echo $this->controllerClass; ?> extends <?php echo $this->baseControllerClass."\n"; ?>
|
||||
{
|
||||
/**
|
||||
* @var string the default layout for the views. Defaults to '//layouts/column2', meaning
|
||||
* using two-column layout. See 'protected/views/layouts/column2.php'.
|
||||
*/
|
||||
public $layout='//layouts/column2';
|
||||
|
||||
/**
|
||||
* @return array action filters
|
||||
*/
|
||||
public function filters()
|
||||
{
|
||||
return array(
|
||||
'accessControl', // perform access control for CRUD operations
|
||||
'postOnly + delete', // we only allow deletion via POST request
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the access control rules.
|
||||
* This method is used by the 'accessControl' filter.
|
||||
* @return array access control rules
|
||||
*/
|
||||
public function accessRules()
|
||||
{
|
||||
return array(
|
||||
array('allow', // allow all users to perform 'index' and 'view' actions
|
||||
'actions'=>array('index','view'),
|
||||
'users'=>array('*'),
|
||||
),
|
||||
array('allow', // allow authenticated user to perform 'create' and 'update' actions
|
||||
'actions'=>array('create','update'),
|
||||
'users'=>array('@'),
|
||||
),
|
||||
array('allow', // allow admin user to perform 'admin' and 'delete' actions
|
||||
'actions'=>array('admin','delete'),
|
||||
'users'=>array('admin'),
|
||||
),
|
||||
array('deny', // deny all users
|
||||
'users'=>array('*'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a particular model.
|
||||
* @param integer $id the ID of the model to be displayed
|
||||
*/
|
||||
public function actionView($id)
|
||||
{
|
||||
$this->render('view',array(
|
||||
'model'=>$this->loadModel($id),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new model.
|
||||
* If creation is successful, the browser will be redirected to the 'view' page.
|
||||
*/
|
||||
public function actionCreate()
|
||||
{
|
||||
$model=new <?php echo $this->modelClass; ?>;
|
||||
|
||||
// Uncomment the following line if AJAX validation is needed
|
||||
// $this->performAjaxValidation($model);
|
||||
|
||||
if(isset($_POST['<?php echo $this->modelClass; ?>']))
|
||||
{
|
||||
$model->attributes=$_POST['<?php echo $this->modelClass; ?>'];
|
||||
if($model->save())
|
||||
$this->redirect(array('view','id'=>$model-><?php echo $this->tableSchema->primaryKey; ?>));
|
||||
}
|
||||
|
||||
$this->render('create',array(
|
||||
'model'=>$model,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a particular model.
|
||||
* If update is successful, the browser will be redirected to the 'view' page.
|
||||
* @param integer $id the ID of the model to be updated
|
||||
*/
|
||||
public function actionUpdate($id)
|
||||
{
|
||||
$model=$this->loadModel($id);
|
||||
|
||||
// Uncomment the following line if AJAX validation is needed
|
||||
// $this->performAjaxValidation($model);
|
||||
|
||||
if(isset($_POST['<?php echo $this->modelClass; ?>']))
|
||||
{
|
||||
$model->attributes=$_POST['<?php echo $this->modelClass; ?>'];
|
||||
if($model->save())
|
||||
$this->redirect(array('view','id'=>$model-><?php echo $this->tableSchema->primaryKey; ?>));
|
||||
}
|
||||
|
||||
$this->render('update',array(
|
||||
'model'=>$model,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a particular model.
|
||||
* If deletion is successful, the browser will be redirected to the 'admin' page.
|
||||
* @param integer $id the ID of the model to be deleted
|
||||
*/
|
||||
public function actionDelete($id)
|
||||
{
|
||||
$this->loadModel($id)->delete();
|
||||
|
||||
// if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser
|
||||
if(!isset($_GET['ajax']))
|
||||
$this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all models.
|
||||
*/
|
||||
public function actionIndex()
|
||||
{
|
||||
$dataProvider=new CActiveDataProvider('<?php echo $this->modelClass; ?>');
|
||||
$this->render('index',array(
|
||||
'dataProvider'=>$dataProvider,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages all models.
|
||||
*/
|
||||
public function actionAdmin()
|
||||
{
|
||||
$model=new <?php echo $this->modelClass; ?>('search');
|
||||
$model->unsetAttributes(); // clear any default values
|
||||
if(isset($_GET['<?php echo $this->modelClass; ?>']))
|
||||
$model->attributes=$_GET['<?php echo $this->modelClass; ?>'];
|
||||
|
||||
$this->render('admin',array(
|
||||
'model'=>$model,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data model based on the primary key given in the GET variable.
|
||||
* If the data model is not found, an HTTP exception will be raised.
|
||||
* @param integer $id the ID of the model to be loaded
|
||||
* @return <?php echo $this->modelClass; ?> the loaded model
|
||||
* @throws CHttpException
|
||||
*/
|
||||
public function loadModel($id)
|
||||
{
|
||||
$model=<?php echo $this->modelClass; ?>::model()->findByPk($id);
|
||||
if($model===null)
|
||||
throw new CHttpException(404,'The requested page does not exist.');
|
||||
return $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the AJAX validation.
|
||||
* @param <?php echo $this->modelClass; ?> $model the model to be validated
|
||||
*/
|
||||
protected function performAjaxValidation($model)
|
||||
{
|
||||
if(isset($_POST['ajax']) && $_POST['ajax']==='<?php echo $this->class2id($this->modelClass); ?>-form')
|
||||
{
|
||||
echo CActiveForm::validate($model);
|
||||
Yii::app()->end();
|
||||
}
|
||||
}
|
||||
}
|
||||
27
framework/gii/generators/crud/templates/default/create.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* The following variables are available in this template:
|
||||
* - $this: the CrudCode object
|
||||
*/
|
||||
?>
|
||||
<?php echo "<?php\n"; ?>
|
||||
/* @var $this <?php echo $this->getControllerClass(); ?> */
|
||||
/* @var $model <?php echo $this->getModelClass(); ?> */
|
||||
|
||||
<?php
|
||||
$label=$this->pluralize($this->class2name($this->modelClass));
|
||||
echo "\$this->breadcrumbs=array(
|
||||
'$label'=>array('index'),
|
||||
'Create',
|
||||
);\n";
|
||||
?>
|
||||
|
||||
$this->menu=array(
|
||||
array('label'=>'List <?php echo $this->modelClass; ?>', 'url'=>array('index')),
|
||||
array('label'=>'Manage <?php echo $this->modelClass; ?>', 'url'=>array('admin')),
|
||||
);
|
||||
?>
|
||||
|
||||
<h1>Create <?php echo $this->modelClass; ?></h1>
|
||||
|
||||
<?php echo "<?php \$this->renderPartial('_form', array('model'=>\$model)); ?>"; ?>
|
||||
29
framework/gii/generators/crud/templates/default/index.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/**
|
||||
* The following variables are available in this template:
|
||||
* - $this: the CrudCode object
|
||||
*/
|
||||
?>
|
||||
<?php echo "<?php\n"; ?>
|
||||
/* @var $this <?php echo $this->getControllerClass(); ?> */
|
||||
/* @var $dataProvider CActiveDataProvider */
|
||||
|
||||
<?php
|
||||
$label=$this->pluralize($this->class2name($this->modelClass));
|
||||
echo "\$this->breadcrumbs=array(
|
||||
'$label',
|
||||
);\n";
|
||||
?>
|
||||
|
||||
$this->menu=array(
|
||||
array('label'=>'Create <?php echo $this->modelClass; ?>', 'url'=>array('create')),
|
||||
array('label'=>'Manage <?php echo $this->modelClass; ?>', 'url'=>array('admin')),
|
||||
);
|
||||
?>
|
||||
|
||||
<h1><?php echo $label; ?></h1>
|
||||
|
||||
<?php echo "<?php"; ?> $this->widget('zii.widgets.CListView', array(
|
||||
'dataProvider'=>$dataProvider,
|
||||
'itemView'=>'_view',
|
||||
)); ?>
|
||||
31
framework/gii/generators/crud/templates/default/update.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
/**
|
||||
* The following variables are available in this template:
|
||||
* - $this: the CrudCode object
|
||||
*/
|
||||
?>
|
||||
<?php echo "<?php\n"; ?>
|
||||
/* @var $this <?php echo $this->getControllerClass(); ?> */
|
||||
/* @var $model <?php echo $this->getModelClass(); ?> */
|
||||
|
||||
<?php
|
||||
$nameColumn=$this->guessNameColumn($this->tableSchema->columns);
|
||||
$label=$this->pluralize($this->class2name($this->modelClass));
|
||||
echo "\$this->breadcrumbs=array(
|
||||
'$label'=>array('index'),
|
||||
\$model->{$nameColumn}=>array('view','id'=>\$model->{$this->tableSchema->primaryKey}),
|
||||
'Update',
|
||||
);\n";
|
||||
?>
|
||||
|
||||
$this->menu=array(
|
||||
array('label'=>'List <?php echo $this->modelClass; ?>', 'url'=>array('index')),
|
||||
array('label'=>'Create <?php echo $this->modelClass; ?>', 'url'=>array('create')),
|
||||
array('label'=>'View <?php echo $this->modelClass; ?>', 'url'=>array('view', 'id'=>$model-><?php echo $this->tableSchema->primaryKey; ?>)),
|
||||
array('label'=>'Manage <?php echo $this->modelClass; ?>', 'url'=>array('admin')),
|
||||
);
|
||||
?>
|
||||
|
||||
<h1>Update <?php echo $this->modelClass." <?php echo \$model->{$this->tableSchema->primaryKey}; ?>"; ?></h1>
|
||||
|
||||
<?php echo "<?php \$this->renderPartial('_form', array('model'=>\$model)); ?>"; ?>
|
||||
39
framework/gii/generators/crud/templates/default/view.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
* The following variables are available in this template:
|
||||
* - $this: the CrudCode object
|
||||
*/
|
||||
?>
|
||||
<?php echo "<?php\n"; ?>
|
||||
/* @var $this <?php echo $this->getControllerClass(); ?> */
|
||||
/* @var $model <?php echo $this->getModelClass(); ?> */
|
||||
|
||||
<?php
|
||||
$nameColumn=$this->guessNameColumn($this->tableSchema->columns);
|
||||
$label=$this->pluralize($this->class2name($this->modelClass));
|
||||
echo "\$this->breadcrumbs=array(
|
||||
'$label'=>array('index'),
|
||||
\$model->{$nameColumn},
|
||||
);\n";
|
||||
?>
|
||||
|
||||
$this->menu=array(
|
||||
array('label'=>'List <?php echo $this->modelClass; ?>', 'url'=>array('index')),
|
||||
array('label'=>'Create <?php echo $this->modelClass; ?>', 'url'=>array('create')),
|
||||
array('label'=>'Update <?php echo $this->modelClass; ?>', 'url'=>array('update', 'id'=>$model-><?php echo $this->tableSchema->primaryKey; ?>)),
|
||||
array('label'=>'Delete <?php echo $this->modelClass; ?>', 'url'=>'#', 'linkOptions'=>array('submit'=>array('delete','id'=>$model-><?php echo $this->tableSchema->primaryKey; ?>),'confirm'=>'Are you sure you want to delete this item?')),
|
||||
array('label'=>'Manage <?php echo $this->modelClass; ?>', 'url'=>array('admin')),
|
||||
);
|
||||
?>
|
||||
|
||||
<h1>View <?php echo $this->modelClass." #<?php echo \$model->{$this->tableSchema->primaryKey}; ?>"; ?></h1>
|
||||
|
||||
<?php echo "<?php"; ?> $this->widget('zii.widgets.CDetailView', array(
|
||||
'data'=>$model,
|
||||
'attributes'=>array(
|
||||
<?php
|
||||
foreach($this->tableSchema->columns as $column)
|
||||
echo "\t\t'".$column->name."',\n";
|
||||
?>
|
||||
),
|
||||
)); ?>
|
||||
64
framework/gii/generators/crud/views/index.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
$class=get_class($model);
|
||||
Yii::app()->clientScript->registerScript('gii.crud',"
|
||||
$('#{$class}_controller').change(function(){
|
||||
$(this).data('changed',$(this).val()!='');
|
||||
});
|
||||
$('#{$class}_model').bind('keyup change', function(){
|
||||
var controller=$('#{$class}_controller');
|
||||
if(!controller.data('changed')) {
|
||||
var id=new String($(this).val().match(/\\w*$/));
|
||||
if(id.length>0)
|
||||
id=id.substring(0,1).toLowerCase()+id.substring(1);
|
||||
controller.val(id);
|
||||
}
|
||||
});
|
||||
");
|
||||
?>
|
||||
<h1>Crud Generator</h1>
|
||||
|
||||
<p>This generator generates a controller and views that implement CRUD operations for the specified data model.</p>
|
||||
|
||||
<?php $form=$this->beginWidget('CCodeForm', array('model'=>$model)); ?>
|
||||
|
||||
<div class="row">
|
||||
<?php echo $form->labelEx($model,'model'); ?>
|
||||
<?php echo $form->textField($model,'model',array('size'=>65)); ?>
|
||||
<div class="tooltip">
|
||||
Model class is case-sensitive. It can be either a class name (e.g. <code>Post</code>)
|
||||
or the path alias of the class file (e.g. <code>application.models.Post</code>).
|
||||
Note that if the former, the class must be auto-loadable.
|
||||
</div>
|
||||
<?php echo $form->error($model,'model'); ?>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<?php echo $form->labelEx($model,'controller'); ?>
|
||||
<?php echo $form->textField($model,'controller',array('size'=>65)); ?>
|
||||
<div class="tooltip">
|
||||
Controller ID is case-sensitive. CRUD controllers are often named after
|
||||
the model class name that they are dealing with. Below are some examples:
|
||||
<ul>
|
||||
<li><code>post</code> generates <code>PostController.php</code></li>
|
||||
<li><code>postTag</code> generates <code>PostTagController.php</code></li>
|
||||
<li><code>admin/user</code> generates <code>admin/UserController.php</code>.
|
||||
If the application has an <code>admin</code> module enabled,
|
||||
it will generate <code>UserController</code> (and other CRUD code)
|
||||
within the module instead.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<?php echo $form->error($model,'controller'); ?>
|
||||
</div>
|
||||
|
||||
<div class="row sticky">
|
||||
<?php echo $form->labelEx($model,'baseControllerClass'); ?>
|
||||
<?php echo $form->textField($model,'baseControllerClass',array('size'=>65)); ?>
|
||||
<div class="tooltip">
|
||||
This is the class that the new CRUD controller class will extend from.
|
||||
Please make sure the class exists and can be autoloaded.
|
||||
</div>
|
||||
<?php echo $form->error($model,'baseControllerClass'); ?>
|
||||
</div>
|
||||
|
||||
<?php $this->endWidget(); ?>
|
||||
94
framework/gii/generators/form/FormCode.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
class FormCode extends CCodeModel
|
||||
{
|
||||
public $model;
|
||||
public $viewPath='application.views';
|
||||
public $viewName;
|
||||
public $scenario;
|
||||
|
||||
private $_modelClass;
|
||||
|
||||
public function rules()
|
||||
{
|
||||
return array_merge(parent::rules(), array(
|
||||
array('model, viewName, scenario', 'filter', 'filter'=>'trim'),
|
||||
array('model, viewName, viewPath', 'required'),
|
||||
array('model, viewPath', 'match', 'pattern'=>'/^\w+[\.\w+]*$/', 'message'=>'{attribute} should only contain word characters and dots.'),
|
||||
array('viewName', 'match', 'pattern'=>'/^\w+[\\/\w+]*$/', 'message'=>'{attribute} should only contain word characters and slashes.'),
|
||||
array('model', 'validateModel'),
|
||||
array('viewPath', 'validateViewPath'),
|
||||
array('scenario', 'match', 'pattern'=>'/^\w+$/', 'message'=>'{attribute} should only contain word characters.'),
|
||||
array('viewPath', 'sticky'),
|
||||
));
|
||||
}
|
||||
|
||||
public function attributeLabels()
|
||||
{
|
||||
return array_merge(parent::attributeLabels(), array(
|
||||
'model'=>'Model Class',
|
||||
'viewName'=>'View Name',
|
||||
'viewPath'=>'View Path',
|
||||
'scenario'=>'Scenario',
|
||||
));
|
||||
}
|
||||
|
||||
public function requiredTemplates()
|
||||
{
|
||||
return array(
|
||||
'form.php',
|
||||
'action.php',
|
||||
);
|
||||
}
|
||||
|
||||
public function successMessage()
|
||||
{
|
||||
$output=<<<EOD
|
||||
<p>The form has been generated successfully.</p>
|
||||
<p>You may add the following code in an appropriate controller class to invoke the view:</p>
|
||||
EOD;
|
||||
$code="<?php\n".$this->render($this->templatePath.'/action.php');
|
||||
return $output.highlight_string($code,true);
|
||||
}
|
||||
|
||||
public function validateModel($attribute,$params)
|
||||
{
|
||||
if($this->hasErrors('model'))
|
||||
return;
|
||||
$class=@Yii::import($this->model,true);
|
||||
if(!is_string($class) || !$this->classExists($class))
|
||||
$this->addError('model', "Class '{$this->model}' does not exist or has syntax error.");
|
||||
elseif(!is_subclass_of($class,'CModel'))
|
||||
$this->addError('model', "'{$this->model}' must extend from CModel.");
|
||||
else
|
||||
$this->_modelClass=$class;
|
||||
}
|
||||
|
||||
public function validateViewPath($attribute,$params)
|
||||
{
|
||||
if($this->hasErrors('viewPath'))
|
||||
return;
|
||||
if(Yii::getPathOfAlias($this->viewPath)===false)
|
||||
$this->addError('viewPath','View Path must be a valid path alias.');
|
||||
}
|
||||
|
||||
public function prepare()
|
||||
{
|
||||
$templatePath=$this->templatePath;
|
||||
$this->files[]=new CCodeFile(
|
||||
Yii::getPathOfAlias($this->viewPath).'/'.$this->viewName.'.php',
|
||||
$this->render($templatePath.'/form.php')
|
||||
);
|
||||
}
|
||||
|
||||
public function getModelClass()
|
||||
{
|
||||
return $this->_modelClass;
|
||||
}
|
||||
|
||||
public function getModelAttributes()
|
||||
{
|
||||
$model=new $this->_modelClass($this->scenario);
|
||||
return $model->getSafeAttributeNames();
|
||||
}
|
||||
}
|
||||
6
framework/gii/generators/form/FormGenerator.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
class FormGenerator extends CCodeGenerator
|
||||
{
|
||||
public $codeModel='gii.generators.form.FormCode';
|
||||
}
|
||||
33
framework/gii/generators/form/templates/default/action.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* This is the template for generating the action script for the form.
|
||||
* - $this: the CrudCode object
|
||||
*/
|
||||
?>
|
||||
<?php
|
||||
$viewName=basename($this->viewName);
|
||||
?>
|
||||
public function action<?php echo ucfirst(trim($viewName,'_')); ?>()
|
||||
{
|
||||
$model=new <?php echo $this->modelClass; ?><?php echo empty($this->scenario) ? '' : "('{$this->scenario}')"; ?>;
|
||||
|
||||
// uncomment the following code to enable ajax-based validation
|
||||
/*
|
||||
if(isset($_POST['ajax']) && $_POST['ajax']==='<?php echo $this->class2id($this->modelClass); ?>-<?php echo $viewName; ?>-form')
|
||||
{
|
||||
echo CActiveForm::validate($model);
|
||||
Yii::app()->end();
|
||||
}
|
||||
*/
|
||||
|
||||
if(isset($_POST['<?php echo $this->modelClass; ?>']))
|
||||
{
|
||||
$model->attributes=$_POST['<?php echo $this->modelClass; ?>'];
|
||||
if($model->validate())
|
||||
{
|
||||
// form inputs are valid, do something here
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->render('<?php echo $viewName; ?>',array('model'=>$model));
|
||||
}
|
||||
44
framework/gii/generators/form/templates/default/form.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/**
|
||||
* This is the template for generating a form script file.
|
||||
* The following variables are available in this template:
|
||||
* - $this: the FormCode object
|
||||
*/
|
||||
?>
|
||||
<?php echo "<?php\n"; ?>
|
||||
/* @var $this <?php echo $this->getModelClass(); ?>Controller */
|
||||
/* @var $model <?php echo $this->getModelClass(); ?> */
|
||||
/* @var $form CActiveForm */
|
||||
?>
|
||||
|
||||
<div class="form">
|
||||
|
||||
<?php echo "<?php \$form=\$this->beginWidget('CActiveForm', array(
|
||||
'id'=>'".$this->class2id($this->modelClass).'-'.basename($this->viewName)."-form',
|
||||
// Please note: When you enable ajax validation, make sure the corresponding
|
||||
// controller action is handling ajax validation correctly.
|
||||
// See class documentation of CActiveForm for details on this,
|
||||
// you need to use the performAjaxValidation()-method described there.
|
||||
'enableAjaxValidation'=>false,
|
||||
)); ?>\n"; ?>
|
||||
|
||||
<p class="note">Fields with <span class="required">*</span> are required.</p>
|
||||
|
||||
<?php echo "<?php echo \$form->errorSummary(\$model); ?>\n"; ?>
|
||||
|
||||
<?php foreach($this->getModelAttributes() as $attribute): ?>
|
||||
<div class="row">
|
||||
<?php echo "<?php echo \$form->labelEx(\$model,'$attribute'); ?>\n"; ?>
|
||||
<?php echo "<?php echo \$form->textField(\$model,'$attribute'); ?>\n"; ?>
|
||||
<?php echo "<?php echo \$form->error(\$model,'$attribute'); ?>\n"; ?>
|
||||
</div>
|
||||
|
||||
<?php endforeach; ?>
|
||||
|
||||
<div class="row buttons">
|
||||
<?php echo "<?php echo CHtml::submitButton('Submit'); ?>\n"; ?>
|
||||
</div>
|
||||
|
||||
<?php echo "<?php \$this->endWidget(); ?>\n"; ?>
|
||||
|
||||
</div><!-- form -->
|
||||
49
framework/gii/generators/form/views/index.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<h1>Form Generator</h1>
|
||||
|
||||
<p>This generator generates a view script file that displays a form to collect input for the specified model class.</p>
|
||||
|
||||
<?php $form=$this->beginWidget('CCodeForm', array('model'=>$model)); ?>
|
||||
|
||||
<div class="row">
|
||||
<?php echo $form->labelEx($model,'model'); ?>
|
||||
<?php echo $form->textField($model,'model', array('size'=>65)); ?>
|
||||
<div class="tooltip">
|
||||
Model class is case-sensitive. It can be either a class name (e.g. <code>Post</code>)
|
||||
or the path alias of the class file (e.g. <code>application.models.LoginForm</code>).
|
||||
Note that if the former, the class must be auto-loadable.
|
||||
</div>
|
||||
<?php echo $form->error($model,'model'); ?>
|
||||
</div>
|
||||
<div class="row">
|
||||
<?php echo $form->labelEx($model,'viewName'); ?>
|
||||
<?php echo $form->textField($model,'viewName', array('size'=>65)); ?>
|
||||
<div class="tooltip">
|
||||
This refers to the name of the view script to be generated, for example,
|
||||
<code>site/contact</code>, <code>user/login</code>. The actual view script file will be generated
|
||||
under the View Path specified below.
|
||||
</div>
|
||||
<?php echo $form->error($model,'viewName'); ?>
|
||||
</div>
|
||||
<div class="row sticky">
|
||||
<?php echo $form->labelEx($model,'viewPath'); ?>
|
||||
<?php echo $form->textField($model,'viewPath', array('size'=>65)); ?>
|
||||
<div class="tooltip">
|
||||
This refers to the directory that the new view script file should be generated under.
|
||||
It should be specified in the form of a path alias, for example, <code>application.views</code>,
|
||||
<code>mymodule.views</code>.
|
||||
</div>
|
||||
<?php echo $form->error($model,'viewPath'); ?>
|
||||
</div>
|
||||
<div class="row">
|
||||
<?php echo $form->labelEx($model,'scenario'); ?>
|
||||
<?php echo $form->textField($model,'scenario', array('size'=>65)); ?>
|
||||
<div class="tooltip">
|
||||
This refers to the scenario in which the model should be used to collect user input.
|
||||
For example, a <code>User</code> model can be used in both <code>login</code> and <code>register</code> scenarios.
|
||||
To create a form for the login purpose, the scenario should be specified as <code>login</code>.
|
||||
Leave this empty if the model does not need to differentiate scenarios.
|
||||
</div>
|
||||
<?php echo $form->error($model,'scenario'); ?>
|
||||
</div>
|
||||
|
||||
<?php $this->endWidget(); ?>
|
||||
431
framework/gii/generators/model/ModelCode.php
Normal file
@@ -0,0 +1,431 @@
|
||||
<?php
|
||||
|
||||
class ModelCode extends CCodeModel
|
||||
{
|
||||
public $connectionId='db';
|
||||
public $tablePrefix;
|
||||
public $tableName;
|
||||
public $modelClass;
|
||||
public $modelPath='application.models';
|
||||
public $baseClass='CActiveRecord';
|
||||
public $buildRelations=true;
|
||||
public $commentsAsLabels=false;
|
||||
|
||||
/**
|
||||
* @var array list of candidate relation code. The array are indexed by AR class names and relation names.
|
||||
* Each element represents the code of the one relation in one AR class.
|
||||
*/
|
||||
protected $relations;
|
||||
|
||||
public function rules()
|
||||
{
|
||||
return array_merge(parent::rules(), array(
|
||||
array('tablePrefix, baseClass, tableName, modelClass, modelPath, connectionId', 'filter', 'filter'=>'trim'),
|
||||
array('connectionId, tableName, modelPath, baseClass', 'required'),
|
||||
array('tablePrefix, tableName, modelPath', 'match', 'pattern'=>'/^(\w+[\w\.]*|\*?|\w+\.\*)$/', 'message'=>'{attribute} should only contain word characters, dots, and an optional ending asterisk.'),
|
||||
array('connectionId', 'validateConnectionId', 'skipOnError'=>true),
|
||||
array('tableName', 'validateTableName', 'skipOnError'=>true),
|
||||
array('tablePrefix, modelClass', 'match', 'pattern'=>'/^[a-zA-Z_]\w*$/', 'message'=>'{attribute} should only contain word characters.'),
|
||||
array('baseClass', 'match', 'pattern'=>'/^[a-zA-Z_][\w\\\\]*$/', 'message'=>'{attribute} should only contain word characters and backslashes.'),
|
||||
array('modelPath', 'validateModelPath', 'skipOnError'=>true),
|
||||
array('baseClass, modelClass', 'validateReservedWord', 'skipOnError'=>true),
|
||||
array('baseClass', 'validateBaseClass', 'skipOnError'=>true),
|
||||
array('connectionId, tablePrefix, modelPath, baseClass, buildRelations, commentsAsLabels', 'sticky'),
|
||||
));
|
||||
}
|
||||
|
||||
public function attributeLabels()
|
||||
{
|
||||
return array_merge(parent::attributeLabels(), array(
|
||||
'tablePrefix'=>'Table Prefix',
|
||||
'tableName'=>'Table Name',
|
||||
'modelPath'=>'Model Path',
|
||||
'modelClass'=>'Model Class',
|
||||
'baseClass'=>'Base Class',
|
||||
'buildRelations'=>'Build Relations',
|
||||
'commentsAsLabels'=>'Use Column Comments as Attribute Labels',
|
||||
'connectionId'=>'Database Connection',
|
||||
));
|
||||
}
|
||||
|
||||
public function requiredTemplates()
|
||||
{
|
||||
return array(
|
||||
'model.php',
|
||||
);
|
||||
}
|
||||
|
||||
public function init()
|
||||
{
|
||||
if(Yii::app()->{$this->connectionId}===null)
|
||||
throw new CHttpException(500,'A valid database connection is required to run this generator.');
|
||||
$this->tablePrefix=Yii::app()->{$this->connectionId}->tablePrefix;
|
||||
parent::init();
|
||||
}
|
||||
|
||||
public function prepare()
|
||||
{
|
||||
if(($pos=strrpos($this->tableName,'.'))!==false)
|
||||
{
|
||||
$schema=substr($this->tableName,0,$pos);
|
||||
$tableName=substr($this->tableName,$pos+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
$schema='';
|
||||
$tableName=$this->tableName;
|
||||
}
|
||||
if($tableName[strlen($tableName)-1]==='*')
|
||||
{
|
||||
$tables=Yii::app()->{$this->connectionId}->schema->getTables($schema);
|
||||
if($this->tablePrefix!='')
|
||||
{
|
||||
foreach($tables as $i=>$table)
|
||||
{
|
||||
if(strpos($table->name,$this->tablePrefix)!==0)
|
||||
unset($tables[$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
$tables=array($this->getTableSchema($this->tableName));
|
||||
|
||||
$this->files=array();
|
||||
$templatePath=$this->templatePath;
|
||||
$this->relations=$this->generateRelations();
|
||||
|
||||
foreach($tables as $table)
|
||||
{
|
||||
$tableName=$this->removePrefix($table->name);
|
||||
$className=$this->generateClassName($table->name);
|
||||
$params=array(
|
||||
'tableName'=>$schema==='' ? $tableName : $schema.'.'.$tableName,
|
||||
'modelClass'=>$className,
|
||||
'columns'=>$table->columns,
|
||||
'labels'=>$this->generateLabels($table),
|
||||
'rules'=>$this->generateRules($table),
|
||||
'relations'=>isset($this->relations[$className]) ? $this->relations[$className] : array(),
|
||||
'connectionId'=>$this->connectionId,
|
||||
);
|
||||
$this->files[]=new CCodeFile(
|
||||
Yii::getPathOfAlias($this->modelPath).'/'.$className.'.php',
|
||||
$this->render($templatePath.'/model.php', $params)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function validateTableName($attribute,$params)
|
||||
{
|
||||
if($this->hasErrors())
|
||||
return;
|
||||
|
||||
$invalidTables=array();
|
||||
$invalidColumns=array();
|
||||
|
||||
if($this->tableName[strlen($this->tableName)-1]==='*')
|
||||
{
|
||||
if(($pos=strrpos($this->tableName,'.'))!==false)
|
||||
$schema=substr($this->tableName,0,$pos);
|
||||
else
|
||||
$schema='';
|
||||
|
||||
$this->modelClass='';
|
||||
$tables=Yii::app()->{$this->connectionId}->schema->getTables($schema);
|
||||
foreach($tables as $table)
|
||||
{
|
||||
if($this->tablePrefix=='' || strpos($table->name,$this->tablePrefix)===0)
|
||||
{
|
||||
if(in_array(strtolower($table->name),self::$keywords))
|
||||
$invalidTables[]=$table->name;
|
||||
if(($invalidColumn=$this->checkColumns($table))!==null)
|
||||
$invalidColumns[]=$invalidColumn;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(($table=$this->getTableSchema($this->tableName))===null)
|
||||
$this->addError('tableName',"Table '{$this->tableName}' does not exist.");
|
||||
if($this->modelClass==='')
|
||||
$this->addError('modelClass','Model Class cannot be blank.');
|
||||
|
||||
if(!$this->hasErrors($attribute) && ($invalidColumn=$this->checkColumns($table))!==null)
|
||||
$invalidColumns[]=$invalidColumn;
|
||||
}
|
||||
|
||||
if($invalidTables!=array())
|
||||
$this->addError('tableName', 'Model class cannot take a reserved PHP keyword! Table name: '.implode(', ', $invalidTables).".");
|
||||
if($invalidColumns!=array())
|
||||
$this->addError('tableName', 'Column names that does not follow PHP variable naming convention: '.implode(', ', $invalidColumns).".");
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that all database field names conform to PHP variable naming rules
|
||||
* For example mysql allows field name like "2011aa", but PHP does not allow variable like "$model->2011aa"
|
||||
* @param CDbTableSchema $table the table schema object
|
||||
* @return string the invalid table column name. Null if no error.
|
||||
*/
|
||||
public function checkColumns($table)
|
||||
{
|
||||
foreach($table->columns as $column)
|
||||
{
|
||||
if(!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/',$column->name))
|
||||
return $table->name.'.'.$column->name;
|
||||
}
|
||||
}
|
||||
|
||||
public function validateModelPath($attribute,$params)
|
||||
{
|
||||
if(Yii::getPathOfAlias($this->modelPath)===false)
|
||||
$this->addError('modelPath','Model Path must be a valid path alias.');
|
||||
}
|
||||
|
||||
public function validateBaseClass($attribute,$params)
|
||||
{
|
||||
$class=@Yii::import($this->baseClass,true);
|
||||
if(!is_string($class) || !$this->classExists($class))
|
||||
$this->addError('baseClass', "Class '{$this->baseClass}' does not exist or has syntax error.");
|
||||
elseif($class!=='CActiveRecord' && !is_subclass_of($class,'CActiveRecord'))
|
||||
$this->addError('baseClass', "'{$this->model}' must extend from CActiveRecord.");
|
||||
}
|
||||
|
||||
public function getTableSchema($tableName)
|
||||
{
|
||||
$connection=Yii::app()->{$this->connectionId};
|
||||
return $connection->getSchema()->getTable($tableName, $connection->schemaCachingDuration!==0);
|
||||
}
|
||||
|
||||
public function generateLabels($table)
|
||||
{
|
||||
$labels=array();
|
||||
foreach($table->columns as $column)
|
||||
{
|
||||
if($this->commentsAsLabels && $column->comment)
|
||||
$labels[$column->name]=$column->comment;
|
||||
else
|
||||
{
|
||||
$label=ucwords(trim(strtolower(str_replace(array('-','_'),' ',preg_replace('/(?<![A-Z])[A-Z]/', ' \0', $column->name)))));
|
||||
$label=preg_replace('/\s+/',' ',$label);
|
||||
if(strcasecmp(substr($label,-3),' id')===0)
|
||||
$label=substr($label,0,-3);
|
||||
if($label==='Id')
|
||||
$label='ID';
|
||||
$label=str_replace("'","\\'",$label);
|
||||
$labels[$column->name]=$label;
|
||||
}
|
||||
}
|
||||
return $labels;
|
||||
}
|
||||
|
||||
public function generateRules($table)
|
||||
{
|
||||
$rules=array();
|
||||
$required=array();
|
||||
$integers=array();
|
||||
$numerical=array();
|
||||
$length=array();
|
||||
$safe=array();
|
||||
foreach($table->columns as $column)
|
||||
{
|
||||
if($column->autoIncrement)
|
||||
continue;
|
||||
$r=!$column->allowNull && $column->defaultValue===null;
|
||||
if($r)
|
||||
$required[]=$column->name;
|
||||
if($column->type==='integer')
|
||||
$integers[]=$column->name;
|
||||
elseif($column->type==='double')
|
||||
$numerical[]=$column->name;
|
||||
elseif($column->type==='string' && $column->size>0)
|
||||
$length[$column->size][]=$column->name;
|
||||
elseif(!$column->isPrimaryKey && !$r)
|
||||
$safe[]=$column->name;
|
||||
}
|
||||
if($required!==array())
|
||||
$rules[]="array('".implode(', ',$required)."', 'required')";
|
||||
if($integers!==array())
|
||||
$rules[]="array('".implode(', ',$integers)."', 'numerical', 'integerOnly'=>true)";
|
||||
if($numerical!==array())
|
||||
$rules[]="array('".implode(', ',$numerical)."', 'numerical')";
|
||||
if($length!==array())
|
||||
{
|
||||
foreach($length as $len=>$cols)
|
||||
$rules[]="array('".implode(', ',$cols)."', 'length', 'max'=>$len)";
|
||||
}
|
||||
if($safe!==array())
|
||||
$rules[]="array('".implode(', ',$safe)."', 'safe')";
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
public function getRelations($className)
|
||||
{
|
||||
return isset($this->relations[$className]) ? $this->relations[$className] : array();
|
||||
}
|
||||
|
||||
protected function removePrefix($tableName,$addBrackets=true)
|
||||
{
|
||||
if($addBrackets && Yii::app()->{$this->connectionId}->tablePrefix=='')
|
||||
return $tableName;
|
||||
$prefix=$this->tablePrefix!='' ? $this->tablePrefix : Yii::app()->{$this->connectionId}->tablePrefix;
|
||||
if($prefix!='')
|
||||
{
|
||||
if($addBrackets && Yii::app()->{$this->connectionId}->tablePrefix!='')
|
||||
{
|
||||
$prefix=Yii::app()->{$this->connectionId}->tablePrefix;
|
||||
$lb='{{';
|
||||
$rb='}}';
|
||||
}
|
||||
else
|
||||
$lb=$rb='';
|
||||
if(($pos=strrpos($tableName,'.'))!==false)
|
||||
{
|
||||
$schema=substr($tableName,0,$pos);
|
||||
$name=substr($tableName,$pos+1);
|
||||
if(strpos($name,$prefix)===0)
|
||||
return $schema.'.'.$lb.substr($name,strlen($prefix)).$rb;
|
||||
}
|
||||
elseif(strpos($tableName,$prefix)===0)
|
||||
return $lb.substr($tableName,strlen($prefix)).$rb;
|
||||
}
|
||||
return $tableName;
|
||||
}
|
||||
|
||||
protected function generateRelations()
|
||||
{
|
||||
if(!$this->buildRelations)
|
||||
return array();
|
||||
|
||||
$schemaName='';
|
||||
if(($pos=strpos($this->tableName,'.'))!==false)
|
||||
$schemaName=substr($this->tableName,0,$pos);
|
||||
|
||||
$relations=array();
|
||||
foreach(Yii::app()->{$this->connectionId}->schema->getTables($schemaName) as $table)
|
||||
{
|
||||
if($this->tablePrefix!='' && strpos($table->name,$this->tablePrefix)!==0)
|
||||
continue;
|
||||
$tableName=$table->name;
|
||||
|
||||
if ($this->isRelationTable($table))
|
||||
{
|
||||
$pks=$table->primaryKey;
|
||||
$fks=$table->foreignKeys;
|
||||
|
||||
$table0=$fks[$pks[0]][0];
|
||||
$table1=$fks[$pks[1]][0];
|
||||
$className0=$this->generateClassName($table0);
|
||||
$className1=$this->generateClassName($table1);
|
||||
|
||||
$unprefixedTableName=$this->removePrefix($tableName);
|
||||
|
||||
$relationName=$this->generateRelationName($table0, $table1, true);
|
||||
$relations[$className0][$relationName]="array(self::MANY_MANY, '$className1', '$unprefixedTableName($pks[0], $pks[1])')";
|
||||
|
||||
$relationName=$this->generateRelationName($table1, $table0, true);
|
||||
|
||||
$i=1;
|
||||
$rawName=$relationName;
|
||||
while(isset($relations[$className1][$relationName]))
|
||||
$relationName=$rawName.$i++;
|
||||
|
||||
$relations[$className1][$relationName]="array(self::MANY_MANY, '$className0', '$unprefixedTableName($pks[1], $pks[0])')";
|
||||
}
|
||||
else
|
||||
{
|
||||
$className=$this->generateClassName($tableName);
|
||||
foreach ($table->foreignKeys as $fkName => $fkEntry)
|
||||
{
|
||||
// Put table and key name in variables for easier reading
|
||||
$refTable=$fkEntry[0]; // Table name that current fk references to
|
||||
$refKey=$fkEntry[1]; // Key in that table being referenced
|
||||
$refClassName=$this->generateClassName($refTable);
|
||||
|
||||
// Add relation for this table
|
||||
$relationName=$this->generateRelationName($tableName, $fkName, false);
|
||||
$relations[$className][$relationName]="array(self::BELONGS_TO, '$refClassName', '$fkName')";
|
||||
|
||||
// Add relation for the referenced table
|
||||
$relationType=$table->primaryKey === $fkName ? 'HAS_ONE' : 'HAS_MANY';
|
||||
$relationName=$this->generateRelationName($refTable, $this->removePrefix($tableName,false), $relationType==='HAS_MANY');
|
||||
$i=1;
|
||||
$rawName=$relationName;
|
||||
while(isset($relations[$refClassName][$relationName]))
|
||||
$relationName=$rawName.($i++);
|
||||
$relations[$refClassName][$relationName]="array(self::$relationType, '$className', '$fkName')";
|
||||
}
|
||||
}
|
||||
}
|
||||
return $relations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given table is a "many to many" pivot table.
|
||||
* Their PK has 2 fields, and both of those fields are also FK to other separate tables.
|
||||
* @param CDbTableSchema table to inspect
|
||||
* @return boolean true if table matches description of helpter table.
|
||||
*/
|
||||
protected function isRelationTable($table)
|
||||
{
|
||||
$pk=$table->primaryKey;
|
||||
return (count($pk) === 2 // we want 2 columns
|
||||
&& isset($table->foreignKeys[$pk[0]]) // pk column 1 is also a foreign key
|
||||
&& isset($table->foreignKeys[$pk[1]]) // pk column 2 is also a foriegn key
|
||||
&& $table->foreignKeys[$pk[0]][0] !== $table->foreignKeys[$pk[1]][0]); // and the foreign keys point different tables
|
||||
}
|
||||
|
||||
protected function generateClassName($tableName)
|
||||
{
|
||||
if($this->tableName===$tableName || ($pos=strrpos($this->tableName,'.'))!==false && substr($this->tableName,$pos+1)===$tableName)
|
||||
return $this->modelClass;
|
||||
|
||||
$tableName=$this->removePrefix($tableName,false);
|
||||
if(($pos=strpos($tableName,'.'))!==false) // remove schema part (e.g. remove 'public2.' from 'public2.post')
|
||||
$tableName=substr($tableName,$pos+1);
|
||||
$className='';
|
||||
foreach(explode('_',$tableName) as $name)
|
||||
{
|
||||
if($name!=='')
|
||||
$className.=ucfirst($name);
|
||||
}
|
||||
return $className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a name for use as a relation name (inside relations() function in a model).
|
||||
* @param string the name of the table to hold the relation
|
||||
* @param string the foreign key name
|
||||
* @param boolean whether the relation would contain multiple objects
|
||||
* @return string the relation name
|
||||
*/
|
||||
protected function generateRelationName($tableName, $fkName, $multiple)
|
||||
{
|
||||
if(strcasecmp(substr($fkName,-2),'id')===0 && strcasecmp($fkName,'id'))
|
||||
$relationName=rtrim(substr($fkName, 0, -2),'_');
|
||||
else
|
||||
$relationName=$fkName;
|
||||
$relationName[0]=strtolower($relationName);
|
||||
|
||||
if($multiple)
|
||||
$relationName=$this->pluralize($relationName);
|
||||
|
||||
$names=preg_split('/_+/',$relationName,-1,PREG_SPLIT_NO_EMPTY);
|
||||
if(empty($names)) return $relationName; // unlikely
|
||||
for($name=$names[0], $i=1;$i<count($names);++$i)
|
||||
$name.=ucfirst($names[$i]);
|
||||
|
||||
$rawName=$name;
|
||||
$table=Yii::app()->{$this->connectionId}->schema->getTable($tableName);
|
||||
$i=0;
|
||||
while(isset($table->columns[$name]))
|
||||
$name=$rawName.($i++);
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
public function validateConnectionId($attribute, $params)
|
||||
{
|
||||
if(Yii::app()->hasComponent($this->connectionId)===false || !(Yii::app()->getComponent($this->connectionId) instanceof CDbConnection))
|
||||
$this->addError('connectionId','A valid database connection is required to run this generator.');
|
||||
}
|
||||
}
|
||||
25
framework/gii/generators/model/ModelGenerator.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
class ModelGenerator extends CCodeGenerator
|
||||
{
|
||||
public $codeModel='gii.generators.model.ModelCode';
|
||||
|
||||
/**
|
||||
* Provides autocomplete table names
|
||||
* @param string $db the database connection component id
|
||||
* @return string the json array of tablenames that contains the entered term $q
|
||||
*/
|
||||
public function actionGetTableNames($db)
|
||||
{
|
||||
if(Yii::app()->getRequest()->getIsAjaxRequest())
|
||||
{
|
||||
$all = array();
|
||||
if(!empty($db) && Yii::app()->hasComponent($db)!==false && (Yii::app()->getComponent($db) instanceof CDbConnection))
|
||||
$all=array_keys(Yii::app()->{$db}->schema->getTables());
|
||||
|
||||
echo json_encode($all);
|
||||
}
|
||||
else
|
||||
throw new CHttpException(404,'The requested page does not exist.');
|
||||
}
|
||||
}
|
||||
163
framework/gii/generators/model/templates/default/model.php
Normal file
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
/**
|
||||
* This is the template for generating the model class of a specified table.
|
||||
* - $this: the ModelCode object
|
||||
* - $tableName: the table name for this class (prefix is already removed if necessary)
|
||||
* - $modelClass: the model class name
|
||||
* - $columns: list of table columns (name=>CDbColumnSchema)
|
||||
* - $labels: list of attribute labels (name=>label)
|
||||
* - $rules: list of validation rules
|
||||
* - $relations: list of relations (name=>relation declaration)
|
||||
*/
|
||||
?>
|
||||
<?php echo "<?php\n"; ?>
|
||||
|
||||
/**
|
||||
* This is the model class for table "<?php echo $tableName; ?>".
|
||||
*
|
||||
* The followings are the available columns in table '<?php echo $tableName; ?>':
|
||||
<?php foreach($columns as $column): ?>
|
||||
* @property <?php echo $column->type.' $'.$column->name."\n"; ?>
|
||||
<?php endforeach; ?>
|
||||
<?php if(!empty($relations)): ?>
|
||||
*
|
||||
* The followings are the available model relations:
|
||||
<?php foreach($relations as $name=>$relation): ?>
|
||||
* @property <?php
|
||||
if (preg_match("~^array\(self::([^,]+), '([^']+)', '([^']+)'\)$~", $relation, $matches))
|
||||
{
|
||||
$relationType = $matches[1];
|
||||
$relationModel = $matches[2];
|
||||
|
||||
switch($relationType){
|
||||
case 'HAS_ONE':
|
||||
echo $relationModel.' $'.$name."\n";
|
||||
break;
|
||||
case 'BELONGS_TO':
|
||||
echo $relationModel.' $'.$name."\n";
|
||||
break;
|
||||
case 'HAS_MANY':
|
||||
echo $relationModel.'[] $'.$name."\n";
|
||||
break;
|
||||
case 'MANY_MANY':
|
||||
echo $relationModel.'[] $'.$name."\n";
|
||||
break;
|
||||
default:
|
||||
echo 'mixed $'.$name."\n";
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
*/
|
||||
class <?php echo $modelClass; ?> extends <?php echo $this->baseClass."\n"; ?>
|
||||
{
|
||||
/**
|
||||
* @return string the associated database table name
|
||||
*/
|
||||
public function tableName()
|
||||
{
|
||||
return '<?php echo $tableName; ?>';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array validation rules for model attributes.
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
// NOTE: you should only define rules for those attributes that
|
||||
// will receive user inputs.
|
||||
return array(
|
||||
<?php foreach($rules as $rule): ?>
|
||||
<?php echo $rule.",\n"; ?>
|
||||
<?php endforeach; ?>
|
||||
// The following rule is used by search().
|
||||
// @todo Please remove those attributes that should not be searched.
|
||||
array('<?php echo implode(', ', array_keys($columns)); ?>', 'safe', 'on'=>'search'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array relational rules.
|
||||
*/
|
||||
public function relations()
|
||||
{
|
||||
// NOTE: you may need to adjust the relation name and the related
|
||||
// class name for the relations automatically generated below.
|
||||
return array(
|
||||
<?php foreach($relations as $name=>$relation): ?>
|
||||
<?php echo "'$name' => $relation,\n"; ?>
|
||||
<?php endforeach; ?>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array customized attribute labels (name=>label)
|
||||
*/
|
||||
public function attributeLabels()
|
||||
{
|
||||
return array(
|
||||
<?php foreach($labels as $name=>$label): ?>
|
||||
<?php echo "'$name' => '$label',\n"; ?>
|
||||
<?php endforeach; ?>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of models based on the current search/filter conditions.
|
||||
*
|
||||
* Typical usecase:
|
||||
* - Initialize the model fields with values from filter form.
|
||||
* - Execute this method to get CActiveDataProvider instance which will filter
|
||||
* models according to data in model fields.
|
||||
* - Pass data provider to CGridView, CListView or any similar widget.
|
||||
*
|
||||
* @return CActiveDataProvider the data provider that can return the models
|
||||
* based on the search/filter conditions.
|
||||
*/
|
||||
public function search()
|
||||
{
|
||||
// @todo Please modify the following code to remove attributes that should not be searched.
|
||||
|
||||
$criteria=new CDbCriteria;
|
||||
|
||||
<?php
|
||||
foreach($columns as $name=>$column)
|
||||
{
|
||||
if($column->type==='string')
|
||||
{
|
||||
echo "\t\t\$criteria->compare('$name',\$this->$name,true);\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "\t\t\$criteria->compare('$name',\$this->$name);\n";
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
return new CActiveDataProvider($this, array(
|
||||
'criteria'=>$criteria,
|
||||
));
|
||||
}
|
||||
|
||||
<?php if($connectionId!='db'):?>
|
||||
/**
|
||||
* @return CDbConnection the database connection used for this class
|
||||
*/
|
||||
public function getDbConnection()
|
||||
{
|
||||
return Yii::app()-><?php echo $connectionId ?>;
|
||||
}
|
||||
|
||||
<?php endif?>
|
||||
/**
|
||||
* Returns the static model of the specified AR class.
|
||||
* Please note that you should have this exact method in all your CActiveRecord descendants!
|
||||
* @param string $className active record class name.
|
||||
* @return <?php echo $modelClass; ?> the static model class
|
||||
*/
|
||||
public static function model($className=__CLASS__)
|
||||
{
|
||||
return parent::model($className);
|
||||
}
|
||||
}
|
||||
149
framework/gii/generators/model/views/index.php
Normal file
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
$class=get_class($model);
|
||||
Yii::app()->clientScript->registerScript('gii.model',"
|
||||
$('#{$class}_connectionId').change(function(){
|
||||
var tableName=$('#{$class}_tableName');
|
||||
tableName.autocomplete('option', 'source', []);
|
||||
$.ajax({
|
||||
url: '".Yii::app()->getUrlManager()->createUrl('gii/model/getTableNames')."',
|
||||
data: {db: this.value},
|
||||
dataType: 'json'
|
||||
}).done(function(data){
|
||||
tableName.autocomplete('option', 'source', data);
|
||||
});
|
||||
});
|
||||
$('#{$class}_modelClass').change(function(){
|
||||
$(this).data('changed',$(this).val()!='');
|
||||
});
|
||||
$('#{$class}_tableName').bind('keyup change', function(){
|
||||
var model=$('#{$class}_modelClass');
|
||||
var tableName=$(this).val();
|
||||
if(tableName.substring(tableName.length-1)!='*') {
|
||||
$('.form .row.model-class').show();
|
||||
}
|
||||
else {
|
||||
$('#{$class}_modelClass').val('');
|
||||
$('.form .row.model-class').hide();
|
||||
}
|
||||
if(!model.data('changed')) {
|
||||
var i=tableName.lastIndexOf('.');
|
||||
if(i>=0)
|
||||
tableName=tableName.substring(i+1);
|
||||
var tablePrefix=$('#{$class}_tablePrefix').val();
|
||||
if(tablePrefix!='' && tableName.indexOf(tablePrefix)==0)
|
||||
tableName=tableName.substring(tablePrefix.length);
|
||||
var modelClass='';
|
||||
$.each(tableName.split('_'), function() {
|
||||
if(this.length>0)
|
||||
modelClass+=this.substring(0,1).toUpperCase()+this.substring(1);
|
||||
});
|
||||
model.val(modelClass);
|
||||
}
|
||||
});
|
||||
$('.form .row.model-class').toggle($('#{$class}_tableName').val().substring($('#{$class}_tableName').val().length-1)!='*');
|
||||
");
|
||||
?>
|
||||
<h1>Model Generator</h1>
|
||||
|
||||
<p>This generator generates a model class for the specified database table.</p>
|
||||
|
||||
<?php $form=$this->beginWidget('CCodeForm', array('model'=>$model)); ?>
|
||||
|
||||
<div class="row sticky">
|
||||
<?php echo $form->labelEx($model, 'connectionId')?>
|
||||
<?php echo $form->textField($model, 'connectionId', array('size'=>65))?>
|
||||
<div class="tooltip">
|
||||
The database component that should be used.
|
||||
</div>
|
||||
<?php echo $form->error($model,'connectionId'); ?>
|
||||
</div>
|
||||
<div class="row sticky">
|
||||
<?php echo $form->labelEx($model,'tablePrefix'); ?>
|
||||
<?php echo $form->textField($model,'tablePrefix', array('size'=>65)); ?>
|
||||
<div class="tooltip">
|
||||
This refers to the prefix name that is shared by all database tables.
|
||||
Setting this property mainly affects how model classes are named based on
|
||||
the table names. For example, a table prefix <code>tbl_</code> with a table name <code>tbl_post</code>
|
||||
will generate a model class named <code>Post</code>.
|
||||
<br/>
|
||||
Leave this field empty if your database tables do not use common prefix.
|
||||
</div>
|
||||
<?php echo $form->error($model,'tablePrefix'); ?>
|
||||
</div>
|
||||
<div class="row">
|
||||
<?php echo $form->labelEx($model,'tableName'); ?>
|
||||
<?php $this->widget('zii.widgets.jui.CJuiAutoComplete',array(
|
||||
'model'=>$model,
|
||||
'attribute'=>'tableName',
|
||||
'name'=>'tableName',
|
||||
'source'=>Yii::app()->hasComponent($model->connectionId) ? array_keys(Yii::app()->{$model->connectionId}->schema->getTables()) : array(),
|
||||
'options'=>array(
|
||||
'minLength'=>'0',
|
||||
'focus'=>new CJavaScriptExpression('function(event,ui) {
|
||||
$("#'.CHtml::activeId($model,'tableName').'").val(ui.item.label).change();
|
||||
return false;
|
||||
}')
|
||||
),
|
||||
'htmlOptions'=>array(
|
||||
'id'=>CHtml::activeId($model,'tableName'),
|
||||
'size'=>'65',
|
||||
'data-tooltip'=>'#tableName-tooltip'
|
||||
),
|
||||
)); ?>
|
||||
<div class="tooltip" id="tableName-tooltip">
|
||||
This refers to the table name that a new model class should be generated for
|
||||
(e.g. <code>tbl_user</code>). It can contain schema name, if needed (e.g. <code>public.tbl_post</code>).
|
||||
You may also enter <code>*</code> (or <code>schemaName.*</code> for a particular DB schema)
|
||||
to generate a model class for EVERY table.
|
||||
</div>
|
||||
<?php echo $form->error($model,'tableName'); ?>
|
||||
</div>
|
||||
<div class="row model-class">
|
||||
<?php echo $form->label($model,'modelClass',array('required'=>true)); ?>
|
||||
<?php echo $form->textField($model,'modelClass', array('size'=>65)); ?>
|
||||
<div class="tooltip">
|
||||
This is the name of the model class to be generated (e.g. <code>Post</code>, <code>Comment</code>).
|
||||
It is case-sensitive.
|
||||
</div>
|
||||
<?php echo $form->error($model,'modelClass'); ?>
|
||||
</div>
|
||||
<div class="row sticky">
|
||||
<?php echo $form->labelEx($model,'baseClass'); ?>
|
||||
<?php echo $form->textField($model,'baseClass',array('size'=>65)); ?>
|
||||
<div class="tooltip">
|
||||
This is the class that the new model class will extend from.
|
||||
Please make sure the class exists and can be autoloaded.
|
||||
</div>
|
||||
<?php echo $form->error($model,'baseClass'); ?>
|
||||
</div>
|
||||
<div class="row sticky">
|
||||
<?php echo $form->labelEx($model,'modelPath'); ?>
|
||||
<?php echo $form->textField($model,'modelPath', array('size'=>65)); ?>
|
||||
<div class="tooltip">
|
||||
This refers to the directory that the new model class file should be generated under.
|
||||
It should be specified in the form of a path alias, for example, <code>application.models</code>.
|
||||
</div>
|
||||
<?php echo $form->error($model,'modelPath'); ?>
|
||||
</div>
|
||||
<div class="row">
|
||||
<?php echo $form->labelEx($model,'buildRelations'); ?>
|
||||
<?php echo $form->checkBox($model,'buildRelations'); ?>
|
||||
<div class="tooltip">
|
||||
Whether relations should be generated for the model class.
|
||||
In order to generate relations, full scan of the whole database is needed.
|
||||
You should disable this option if your database contains too many tables.
|
||||
</div>
|
||||
<?php echo $form->error($model,'buildRelations'); ?>
|
||||
</div>
|
||||
<div class="row">
|
||||
<?php echo $form->labelEx($model,'commentsAsLabels'); ?>
|
||||
<?php echo $form->checkBox($model,'commentsAsLabels'); ?>
|
||||
<div class="tooltip">
|
||||
Whether comments specified for the table columns should be used as the new model's attribute labels.
|
||||
In case your RDBMS doesn't support feature of commenting columns or column comment wasn't set,
|
||||
column name would be used as the attribute name base.
|
||||
</div>
|
||||
<?php echo $form->error($model,'commentsAsLabels'); ?>
|
||||
</div>
|
||||
|
||||
<?php $this->endWidget(); ?>
|
||||
94
framework/gii/generators/module/ModuleCode.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
class ModuleCode extends CCodeModel
|
||||
{
|
||||
public $moduleID;
|
||||
|
||||
public function rules()
|
||||
{
|
||||
return array_merge(parent::rules(), array(
|
||||
array('moduleID', 'filter', 'filter'=>'trim'),
|
||||
array('moduleID', 'required'),
|
||||
array('moduleID', 'match', 'pattern'=>'/^\w+$/', 'message'=>'{attribute} should only contain word characters.'),
|
||||
));
|
||||
}
|
||||
|
||||
public function attributeLabels()
|
||||
{
|
||||
return array_merge(parent::attributeLabels(), array(
|
||||
'moduleID'=>'Module ID',
|
||||
));
|
||||
}
|
||||
|
||||
public function successMessage()
|
||||
{
|
||||
if(Yii::app()->hasModule($this->moduleID))
|
||||
return 'The module has been generated successfully. You may '.CHtml::link('try it now', Yii::app()->createUrl($this->moduleID), array('target'=>'_blank')).'.';
|
||||
|
||||
$output=<<<EOD
|
||||
<p>The module has been generated successfully.</p>
|
||||
<p>To access the module, you need to modify the application configuration as follows:</p>
|
||||
EOD;
|
||||
$code=<<<EOD
|
||||
<?php
|
||||
return array(
|
||||
'modules'=>array(
|
||||
'{$this->moduleID}',
|
||||
),
|
||||
......
|
||||
);
|
||||
EOD;
|
||||
|
||||
return $output.highlight_string($code,true);
|
||||
}
|
||||
|
||||
public function prepare()
|
||||
{
|
||||
$this->files=array();
|
||||
$templatePath=$this->templatePath;
|
||||
$modulePath=$this->modulePath;
|
||||
$moduleTemplateFile=$templatePath.DIRECTORY_SEPARATOR.'module.php';
|
||||
|
||||
$this->files[]=new CCodeFile(
|
||||
$modulePath.'/'.$this->moduleClass.'.php',
|
||||
$this->render($moduleTemplateFile)
|
||||
);
|
||||
|
||||
$files=CFileHelper::findFiles($templatePath,array(
|
||||
'exclude'=>array(
|
||||
'.svn',
|
||||
'.gitignore'
|
||||
),
|
||||
));
|
||||
|
||||
foreach($files as $file)
|
||||
{
|
||||
if($file!==$moduleTemplateFile)
|
||||
{
|
||||
if(CFileHelper::getExtension($file)==='php')
|
||||
$content=$this->render($file);
|
||||
elseif(basename($file)==='.yii') // an empty directory
|
||||
{
|
||||
$file=dirname($file);
|
||||
$content=null;
|
||||
}
|
||||
else
|
||||
$content=file_get_contents($file);
|
||||
$this->files[]=new CCodeFile(
|
||||
$modulePath.substr($file,strlen($templatePath)),
|
||||
$content
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getModuleClass()
|
||||
{
|
||||
return ucfirst($this->moduleID).'Module';
|
||||
}
|
||||
|
||||
public function getModulePath()
|
||||
{
|
||||
return Yii::app()->modulePath.DIRECTORY_SEPARATOR.$this->moduleID;
|
||||
}
|
||||
}
|
||||
6
framework/gii/generators/module/ModuleGenerator.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
class ModuleGenerator extends CCodeGenerator
|
||||
{
|
||||
public $codeModel='gii.generators.module.ModuleCode';
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php echo "<?php\n"; ?>
|
||||
|
||||
class DefaultController extends Controller
|
||||
{
|
||||
public function actionIndex()
|
||||
{
|
||||
$this->render('index');
|
||||
}
|
||||
}
|
||||
28
framework/gii/generators/module/templates/default/module.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php echo "<?php\n"; ?>
|
||||
|
||||
class <?php echo $this->moduleClass; ?> extends CWebModule
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
// this method is called when the module is being created
|
||||
// you may place code here to customize the module or the application
|
||||
|
||||
// import the module-level models and components
|
||||
$this->setImport(array(
|
||||
'<?php echo $this->moduleID; ?>.models.*',
|
||||
'<?php echo $this->moduleID; ?>.components.*',
|
||||
));
|
||||
}
|
||||
|
||||
public function beforeControllerAction($controller, $action)
|
||||
{
|
||||
if(parent::beforeControllerAction($controller, $action))
|
||||
{
|
||||
// this method is called before any module controller action is performed
|
||||
// you may place customized code here
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php echo "<?php\n"; ?>
|
||||
/* @var $this DefaultController */
|
||||
|
||||
$this->breadcrumbs=array(
|
||||
$this->module->id,
|
||||
);
|
||||
?>
|
||||
<h1><?php echo "<?php"; ?> echo $this->uniqueId . '/' . $this->action->id; ?></h1>
|
||||
|
||||
<p>
|
||||
This is the view content for action "<?php echo "<?php"; ?> echo $this->action->id; ?>".
|
||||
The action belongs to the controller "<?php echo "<?php"; ?> echo get_class($this); ?>"
|
||||
in the "<?php echo "<?php"; ?> echo $this->module->id; ?>" module.
|
||||
</p>
|
||||
<p>
|
||||
You may customize this page by editing <tt><?php echo "<?php"; ?> echo __FILE__; ?></tt>
|
||||
</p>
|
||||
19
framework/gii/generators/module/views/index.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<h1>Module Generator</h1>
|
||||
|
||||
<p>This generator helps you to generate the skeleton code needed by a Yii module.</p>
|
||||
|
||||
<?php $form=$this->beginWidget('CCodeForm', array('model'=>$model)); ?>
|
||||
|
||||
<div class="row">
|
||||
<?php echo $form->labelEx($model,'moduleID'); ?>
|
||||
<?php echo $form->textField($model,'moduleID',array('size'=>65)); ?>
|
||||
<div class="tooltip">
|
||||
Module ID is case-sensitive. It should only contain word characters.
|
||||
The generated module class will be named after the module ID.
|
||||
For example, a module ID <code>forum</code> will generate the module class
|
||||
<code>ForumModule</code>.
|
||||
</div>
|
||||
<?php echo $form->error($model,'moduleID'); ?>
|
||||
</div>
|
||||
|
||||
<?php $this->endWidget(); ?>
|
||||
49
framework/gii/models/LoginForm.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
Yii::import('gii.components.UserIdentity');
|
||||
|
||||
class LoginForm extends CFormModel
|
||||
{
|
||||
public $password;
|
||||
|
||||
private $_identity;
|
||||
|
||||
public function rules()
|
||||
{
|
||||
return array(
|
||||
array('password', 'required'),
|
||||
array('password', 'authenticate'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticates the password.
|
||||
* This is the 'authenticate' validator as declared in rules().
|
||||
*/
|
||||
public function authenticate($attribute,$params)
|
||||
{
|
||||
$this->_identity=new UserIdentity('yiier',$this->password);
|
||||
if(!$this->_identity->authenticate())
|
||||
$this->addError('password','Incorrect password.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs in the user using the given password in the model.
|
||||
* @return boolean whether login is successful
|
||||
*/
|
||||
public function login()
|
||||
{
|
||||
if($this->_identity===null)
|
||||
{
|
||||
$this->_identity=new UserIdentity('yiier',$this->password);
|
||||
$this->_identity->authenticate();
|
||||
}
|
||||
if($this->_identity->errorCode===UserIdentity::ERROR_NONE)
|
||||
{
|
||||
Yii::app()->user->login($this->_identity);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
16
framework/gii/views/common/code.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
if($file->type==='php')
|
||||
{
|
||||
echo '<div class="content">';
|
||||
highlight_string($file->content);
|
||||
echo '</div>';
|
||||
}
|
||||
elseif(in_array($file->type,array('txt','js','css')))
|
||||
{
|
||||
echo '<div class="content">';
|
||||
echo nl2br($file->content);
|
||||
echo '</div>';
|
||||
}
|
||||
else
|
||||
echo '<div class="error">Preview is not available for this file type.</div>';
|
||||
?>
|
||||
9
framework/gii/views/common/diff.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php if($diff===false): ?>
|
||||
<div class="error">Diff is not supported for this file type.</div>
|
||||
<?php elseif(empty($diff)): ?>
|
||||
<div class="error">No changes.</div>
|
||||
<?php else: ?>
|
||||
<div class="content">
|
||||
<pre class="diff"><?php echo $diff; ?></pre>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
76
framework/gii/views/common/generator.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<div class="row template sticky">
|
||||
<?php echo $this->labelEx($model,'template'); ?>
|
||||
<?php echo $this->dropDownList($model,'template',$templates); ?>
|
||||
<div class="tooltip">
|
||||
Please select which set of the templates should be used to generated the code.
|
||||
</div>
|
||||
<?php echo $this->error($model,'template'); ?>
|
||||
</div>
|
||||
|
||||
<div class="buttons">
|
||||
<?php echo CHtml::submitButton('Preview',array('name'=>'preview')); ?>
|
||||
|
||||
<?php if($model->status===CCodeModel::STATUS_PREVIEW && !$model->hasErrors()): ?>
|
||||
<?php echo CHtml::submitButton('Generate',array('name'=>'generate')); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if(!$model->hasErrors()): ?>
|
||||
<div class="feedback">
|
||||
<?php if($model->status===CCodeModel::STATUS_SUCCESS): ?>
|
||||
<div class="success">
|
||||
<?php echo $model->successMessage(); ?>
|
||||
</div>
|
||||
<?php elseif($model->status===CCodeModel::STATUS_ERROR): ?>
|
||||
<div class="error">
|
||||
<?php echo $model->errorMessage(); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if(isset($_POST['generate'])): ?>
|
||||
<pre class="results"><?php echo $model->renderResults(); ?></pre>
|
||||
<?php elseif(isset($_POST['preview'])): ?>
|
||||
<?php echo CHtml::hiddenField("answers"); ?>
|
||||
<table class="preview">
|
||||
<tr>
|
||||
<th class="file">Code File</th>
|
||||
<th class="confirm">
|
||||
<label for="check-all">Generate</label>
|
||||
<?php
|
||||
$count=0;
|
||||
foreach($model->files as $file)
|
||||
{
|
||||
if($file->operation!==CCodeFile::OP_SKIP)
|
||||
$count++;
|
||||
}
|
||||
if($count>1)
|
||||
echo '<input type="checkbox" name="checkAll" id="check-all" />';
|
||||
?>
|
||||
</th>
|
||||
</tr>
|
||||
<?php foreach($model->files as $i=>$file): ?>
|
||||
<tr class="<?php echo $file->operation; ?>">
|
||||
<td class="file">
|
||||
<?php echo CHtml::link(CHtml::encode($file->relativePath), array('code','id'=>$i), array('class'=>'view-code','rel'=>$file->path)); ?>
|
||||
<?php if($file->operation===CCodeFile::OP_OVERWRITE): ?>
|
||||
(<?php echo CHtml::link('diff', array('diff','id'=>$i), array('class'=>'view-code','rel'=>$file->path)); ?>)
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="confirm">
|
||||
<?php
|
||||
if($file->operation===CCodeFile::OP_SKIP)
|
||||
echo 'unchanged';
|
||||
else
|
||||
{
|
||||
$key=md5($file->path);
|
||||
echo CHtml::label($file->operation, "answers_{$key}")
|
||||
. ' ' . CHtml::checkBox("answers[$key]", $model->confirmed($file));
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
5
framework/gii/views/default/error.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<h1>Error <?php echo $code; ?></h1>
|
||||
|
||||
<div class="error">
|
||||
<?php echo CHtml::encode($message); ?>
|
||||
</div>
|
||||
11
framework/gii/views/default/index.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<h1>Welcome to Yii Code Generator!</h1>
|
||||
|
||||
<p>
|
||||
You may use the following generators to quickly build up your Yii application:
|
||||
</p>
|
||||
<ul>
|
||||
<?php foreach($this->module->controllerMap as $name=>$config): ?>
|
||||
<li><?php echo CHtml::link(ucwords(CHtml::encode($name).' generator'),array($name.'/index'));?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
|
||||
11
framework/gii/views/default/login.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<div class="form login">
|
||||
<?php $form=$this->beginWidget('CActiveForm'); ?>
|
||||
<p>Please enter your password</p>
|
||||
|
||||
<?php echo $form->passwordField($model,'password'); ?>
|
||||
<?php echo $form->error($model,'password'); ?>
|
||||
|
||||
<?php echo CHtml::submitButton('Enter'); ?>
|
||||
|
||||
<?php $this->endWidget(); ?>
|
||||
</div><!-- form -->
|
||||
7
framework/gii/views/layouts/column1.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php $this->beginContent('gii.views.layouts.main'); ?>
|
||||
<div class="container">
|
||||
<div id="content">
|
||||
<?php echo $content; ?>
|
||||
</div><!-- content -->
|
||||
</div>
|
||||
<?php $this->endContent(); ?>
|
||||
25
framework/gii/views/layouts/generator.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php $this->beginContent('gii.views.layouts.main'); ?>
|
||||
<div class="container">
|
||||
<div class="span-4">
|
||||
<div id="sidebar">
|
||||
<?php $this->beginWidget('zii.widgets.CPortlet', array(
|
||||
'title'=>'Generators',
|
||||
)); ?>
|
||||
<ul>
|
||||
<?php foreach($this->module->controllerMap as $name=>$config): ?>
|
||||
<li><?php echo CHtml::link(ucwords(CHtml::encode($name).' generator'),array($name.'/index'));?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php $this->endWidget(); ?>
|
||||
</div><!-- sidebar -->
|
||||
</div>
|
||||
<div class="span-16">
|
||||
<div id="content">
|
||||
<?php echo $content; ?>
|
||||
</div><!-- content -->
|
||||
</div>
|
||||
<div class="span-4 last">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<?php $this->endContent(); ?>
|
||||
57
framework/gii/views/layouts/main.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
$cs=Yii::app()->clientScript;
|
||||
$cs->coreScriptPosition=CClientScript::POS_HEAD;
|
||||
$cs->scriptMap=array();
|
||||
$baseUrl=$this->module->assetsUrl;
|
||||
$cs->registerCoreScript('jquery');
|
||||
$cs->registerScriptFile($baseUrl.'/js/tooltip.js');
|
||||
$cs->registerScriptFile($baseUrl.'/js/fancybox/jquery.fancybox-1.3.1.pack.js');
|
||||
$cs->registerCssFile($baseUrl.'/js/fancybox/jquery.fancybox-1.3.1.css');
|
||||
?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="language" content="en" />
|
||||
|
||||
<!-- blueprint CSS framework -->
|
||||
<link rel="stylesheet" type="text/css" href="<?php echo $this->module->assetsUrl; ?>/css/screen.css" media="screen, projection" />
|
||||
<link rel="stylesheet" type="text/css" href="<?php echo $this->module->assetsUrl; ?>/css/print.css" media="print" />
|
||||
<!--[if lt IE 8]>
|
||||
<link rel="stylesheet" type="text/css" href="<?php echo $this->module->assetsUrl; ?>/css/ie.css" media="screen, projection" />
|
||||
<![endif]-->
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="<?php echo $this->module->assetsUrl; ?>/css/main.css" />
|
||||
|
||||
<title><?php echo CHtml::encode($this->pageTitle); ?></title>
|
||||
|
||||
<script type="text/javascript" src="<?php echo $this->module->assetsUrl; ?>/js/main.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="container" id="page">
|
||||
<div id="header">
|
||||
<div class="top-menus">
|
||||
<?php echo CHtml::link('help','http://www.yiiframework.com/doc/guide/topics.gii'); ?> |
|
||||
<?php echo CHtml::link('webapp',Yii::app()->homeUrl); ?> |
|
||||
<a href="http://www.yiiframework.com">yii</a>
|
||||
<?php if(!Yii::app()->user->isGuest): ?>
|
||||
| <?php echo CHtml::link('logout',array('default/logout')); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div id="logo"><?php echo CHtml::link(CHtml::image($this->module->assetsUrl.'/images/logo.png'),array('default/index')); ?></div>
|
||||
</div><!-- header -->
|
||||
|
||||
<?php echo $content; ?>
|
||||
|
||||
</div><!-- page -->
|
||||
|
||||
<div id="footer">
|
||||
<?php echo Yii::powered(); ?>
|
||||
<br/>A product of <a href="http://www.yiisoft.com">Yii Software LLC</a>.
|
||||
</div><!-- footer -->
|
||||
|
||||
</body>
|
||||
</html>
|
||||