So, I finally found to hack this. I am extending the ClientScript class and ClientScript the registerScript method so that it accepts another $level parameter.
public function registerScript($id, $script, $position = self::POS_END, $level = 1);
Think of $level as you would a z-index in CSS, except that the higher the number of $level , the lower the position of the script.
for instance
Yii::app()->clientScript->registerScript('script1', '/** SCRIPT #1 **/', CClientScript::POS_END, 1); Yii::app()->clientScript->registerScript('script2', '/** SCRIPT #2 **/', CClientScript::POS_END, 2); Yii::app()->clientScript->registerScript('script3', '/** SCRIPT #3 **/', CClientScript::POS_END, 1);
Even if script3 declared after script2 , it will be shown above script2 in the displayed script, since the value of $level script2 greater than script3 .
Here is my solution code. It works the way I want, although I'm not sure if the organization method is optimized enough.
/** * ClientScript manages Javascript and CSS. */ class ClientScript extends CClientScript { public $scriptLevels = array(); /** * Registers a piece of javascript code. * @param string $id ID that uniquely identifies this piece of JavaScript code * @param string $script the javascript code * @param integer $position the position of the JavaScript code. * @param integer $level the rendering priority of the JavaScript code in a position. * @return CClientScript the CClientScript object itself (to support method chaining, available since version 1.1.5). */ public function registerScript($id, $script, $position = self::POS_END, $level = 1) { $this->scriptLevels[$id] = $level; return parent::registerScript($id, $script, $position); } /** * Renders the registered scripts. * Overriding from CClientScript. * @param string $output the existing output that needs to be inserted with script tags */ public function render(&$output) { if (!$this->hasScripts) return; $this->renderCoreScripts(); if (!empty($this->scriptMap)) $this->remapScripts(); $this->unifyScripts(); //=================================== //Arranging the priority $this->rearrangeLevels(); //=================================== $this->renderHead($output); if ($this->enableJavaScript) { $this->renderBodyBegin($output); $this->renderBodyEnd($output); } } /** * Rearrange the script levels. */ public function rearrangeLevels() { $scriptLevels = $this->scriptLevels; foreach ($this->scripts as $position => &$scripts) { $newscripts = array(); $tempscript = array(); foreach ($scripts as $id => $script) { $level = isset($scriptLevels[$id]) ? $scriptLevels[$id] : 1; $tempscript[$level][$id] = $script; } foreach ($tempscript as $s) { foreach ($s as $id => $script) { $newscripts[$id] = $script; } } $scripts = $newscripts; } } }
So I just need to put the class as a clientScript component in config
'components' => array( 'clientScript' => array( 'class' => 'ClientScript' ) )