FlavorFlav
(Der Doktor)
February 7, 2013, 2:01am
1
hi,
is it possible to use 2 instances of a widget with 2 different css on 1 site?
for example:
<?php
$this->widget('application.extensions.mbmenu.MbMenu',array(
'items' => $items1;
'cssFile' => Yii::app()->request->baseUrl . '/css/mbmenu1.css',
));
$this->widget('application.extensions.mbmenu.MbMenu',array(
'items' => $items2;
'cssFile' => Yii::app()->request->baseUrl . '/css/mbmenu2.css',
));
?>
yii includes both css files perfectly… but the problme is, that both css definitions overwrite each other, because both contains the same css classes
you understnad my problem?
is there any solution?
redguy
(Maciej Lizewski)
February 7, 2013, 9:03am
2
you must put both widgets in some element with differtent class/id and prepare css rules based on that context:
<div id="firstMenu">
<?php
$this->widget('application.extensions.mbmenu.MbMenu',array(
'items' => $items1;
'cssFile' => Yii::app()->request->baseUrl . '/css/mbmenu1.css',
));
?>
</div>
<div id="secondMenu">
<?php
$this->widget('application.extensions.mbmenu.MbMenu',array(
'items' => $items2;
'cssFile' => Yii::app()->request->baseUrl . '/css/mbmenu2.css',
));
?>
</div>
and corresponding css:
#firstMenu .nav {
}
#secondMenu .nav {
}
...
There is however problem with mbmenu widget which disallows it to be used more than once on one page - it creates html code with "id" attributes which are not unique. This makes your page not compliant with html standards if you use this widget twice or more.
FlavorFlav
(Der Doktor)
February 7, 2013, 9:43am
3
thanks for your answer
redguy:
you must put both widgets in some element with differtent class/id and prepare css rules based on that context:
<div id="firstMenu">
<?php
$this->widget('application.extensions.mbmenu.MbMenu',array(
'items' => $items1;
'cssFile' => Yii::app()->request->baseUrl . '/css/mbmenu1.css',
));
?>
</div>
<div id="secondMenu">
<?php
$this->widget('application.extensions.mbmenu.MbMenu',array(
'items' => $items2;
'cssFile' => Yii::app()->request->baseUrl . '/css/mbmenu2.css',
));
?>
</div>
and corresponding css:
#firstMenu .nav {
}
#secondMenu .nav {
}
...
damn… i thought about this solution, but i hoped for soemthing better
ohh thanks for lettign me know about this… any adwice for a good alternative drop-down-menu component?
i don’t know if anyone else needs this…
i wrote a widget, which do all this #id stuff in css automatically:
class CssSection extends CWidget {
public $tagName = 'div';
public $id;
public $cssFile;
public function init() {
parent::init();
$this->publishCssFile();
echo CHtml::openTag($this->tagName, array('id' => $this->id));
}
private function publishCssFile() {
//path stuff
$cssPathParts = pathinfo($this->cssFile);
$cssFileName = $this->id . '_' . $cssPathParts['filename'];
$cssSourceDir = $cssPathParts['dirname'];
$cssRuntimeDir = Yii::app()->getRuntimePath() . '/' . $cssFileName;
//only process css stuff when folder does not exist or in debug mode
$refresh=!is_dir($cssRuntimeDir) || YII_DEBUG == TRUE;
if ($refresh) {
Yii::import('application.vendors.*');
//autoloader for the use-statements in Sabberworm
spl_autoload_register(function($class) {
require_once ($class . ".php");
});
$cssParser = new Sabberworm\CSS\Parser(file_get_contents($this->cssFile));
$cssDocument = $cssParser->parse();
$this->setPrefixIdsToCssBlocks($cssDocument, $this->id);
$urls = $this->substituteUrlsInCss($cssDocument);
//create dir if not exist
if (!is_dir($cssRuntimeDir)) {
mkdir($cssRuntimeDir);
}
//save css document ot file
$cssFileContent = $cssDocument->__toString();
file_put_contents($cssRuntimeDir . '/' . $cssFileName . ".css", $cssFileContent);
//copy linked resources to runtime folder
foreach ($urls as $url => $newUrlId) {
copy($cssSourceDir . '/' . $url, $cssRuntimeDir . '/' . $newUrlId);
}
//spl_autoload_register(array('YiiBase', 'autoload'));
}
//publish css and linked resources
$cssAssetPath = Yii::app()->assetManager->publish($cssRuntimeDir,true,-1,$refresh);
//
echo '<link rel="stylesheet" type="text/css" href="' . $cssAssetPath . '/' . $cssFileName . '.css" />';
}
/**
* adds a prefix before to every css block
*
* @param type $cssDocument css documnt
* @param type $prefixId prefix
*/
private function setPrefixIdsToCssBlocks($cssDocument, $prefixId) {
//add #id to all css blocks
foreach ($cssDocument->getAllDeclarationBlocks() as $oBlock) {
foreach ($oBlock->getSelectors() as $oSelector) {
$oSelector->setSelector('#' . $prefixId . ' ' . $oSelector->getSelector());
}
}
}
/**
* @param type $cssDocument css document
* @return array (key = old url, value = new url id)
*/
private function substituteUrlsInCss($cssDocument) {
$urls = array();
$urlId = 0;
foreach ($cssDocument->getAllValues() as $value) {
if ($value instanceof Sabberworm\CSS\Value\URL) {
$url = $value->getURL();
//remove quotes from url
$url = str_replace('"', "", $url);
$url = str_replace("'", "", $url);
//evaluate new url id
if (array_key_exists($url, $urls)) {
$newUrlId = $urls[$url];
} else {
$urlPathParts = pathinfo($url);
$urlExtension = $urlPathParts['extension'];
$newUrlId = $urls[$url] = $urlId . '.' . $urlExtension;
$urlId++;
}
//change url to new url id
$value->setURL(new Sabberworm\CSS\Value\String($newUrlId));
}
}
return $urls;
}
public function run() {
parent::run();
echo CHtml::closeTag($this->tagName);
}
}
it uses the Sabberworm CSS Parser (https://github.com/sabberworm/PHP-CSS-Parser )
it can be used like this:
$this->beginWidget('CssSection', array(
'id' => 'menu2',
'cssFile'=>Yii::app()->getBasePath() . '/../css/mbmenu_orig/mbmenu.css'));
$this->widget('application.extensions.mbmenu.MbMenu', array(
'items' => $this->menuItems,
));
$this->endWidget('CssSection');
this generates a surrounding div with a id (menu2) and creates a new css file with this ids (and publish it to assets)
any advices?