commit 9f28c5a3487d1a573c830252ae2ab9d153a0c8dd
parent 6d7ef8335c330597814d0c9dcb126aae1312e0cb
Author: Jan Dankert <devnull@localhost>
Date: Fri, 10 Nov 2017 01:53:33 +0100
CSS und Javascript je als 1 Datei zusammenfassen, um HTTP-Requests einzusparen. Im Production-Mode wird minifiziert (Laufzeit prüfen, ggf. kommt das wieder raus). Einbau LESS-Parser, vorerst nur für die Theme-Einstellungen.
Diffstat:
18 files changed, 15628 insertions(+), 2053 deletions(-)
diff --git a/action/Action.class.php b/action/Action.class.php
@@ -70,7 +70,7 @@ class Action
function setStyle( $style )
{
- $this->setControlVar( "new_style", css_link($style) );
+ $this->setControlVar( "new_style", $style );
}
@@ -578,7 +578,7 @@ class Action
*
* @param Timestamp Letztes Aenderungsdatum des Objektes
*/
- protected function lastModified( $time )
+ protected function lastModified( $time, $expirationDuration = 0 )
{
$user = Session::getUser();
@@ -586,7 +586,7 @@ class Action
if ( ! config('cache','conditional_get') )
return;
- $expires = substr(date('r',time()-date('Z')),0,-5).'GMT';
+ $expires = substr(date('r',time()+$expirationDuration-date('Z')),0,-5).'GMT';
$lastModified = substr(date('r',$time -date('Z')),0,-5).'GMT';
$etag = '"'.base_convert($time,10,36).'"';
@@ -604,15 +604,19 @@ class Action
$if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']) : false;
$if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH'] ) ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH'] ) : false;
- if ( !$if_modified_since && !$if_none_match )
- return;
-
+ // Bug in Apache 2.2, mod_deflat adds '-gzip' to E-Tag
+ if ( substr($if_none_match,-6) == '-gzip"' )
+ $if_none_match = substr($if_none_match,0,-6).'"';
+
// At least one of the headers is there - check them
if ( $if_none_match && $if_none_match != $etag )
return; // etag is there but doesn't match
if ( $if_modified_since && $if_modified_since != $lastModified )
return; // if-modified-since is there but doesn't match
+
+ if ( !$if_modified_since && !$if_none_match )
+ return;
// Der entfernte Browser bzw. Proxy holt die Seite nun aus seinem Cache
header('HTTP/1.0 304 Not Modified');
diff --git a/action/IndexAction.class.php b/action/IndexAction.class.php
@@ -34,6 +34,7 @@ class IndexAction extends Action
function IndexAction()
{
$this->perspective = Session::get('perspective');
+// $this->lastModified( filemtime(__FILE__) );
}
@@ -99,5 +100,191 @@ class IndexAction extends Action
require('themes/default/layout/index.php');
exit;
}
+
+
+ public function stylesheetView()
+ {
+ if ( DEVELOPMENT )
+ $this->lastModified( config('config','last_modification') );
+ else
+ $this->lastModified(config('config','last_modification',1*60*60) );
+
+
+ function minifyCSS( $source ) {
+
+ // Remove comments
+ $source = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $source);
+ // Remove space after colons
+ $source = str_replace(': ', ':', $source);
+ // Remove whitespace
+ $source = str_replace(array("\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $source);
+
+ return $source;
+ }
+
+ header('Content-Type: text/css');
+ $css = array();
+ // $css[] = link id="userstyle" rel="stylesheet" type="text/css" href="<?php echo css_link($style) "
+// $cssParam = css_link($style);
+
+// $css['userstyle'] = OR_THEMES_EXT_DIR.'default/css/openrat-theme.css.php';
+ $css[] = OR_THEMES_EXT_DIR.'default/css/openrat-ui.css';
+ $css[] = OR_THEMES_EXT_DIR.'default/css/openrat-workbench.css';
+
+ // $css[] = OR_THEMES_EXT_DIR.'../editor/markitup/markitup/skins/markitup/style.css';
+ // $css[] = OR_THEMES_EXT_DIR.'../editor/markitup/markitup/sets/default/style.css';
+
+ // Komponentenbasiertes CSS
+ $elements = parse_ini_file( OR_THEMES_DIR.config('interface','theme').'/include/elements.ini.'.PHP_EXT);
+
+ foreach( array_keys($elements) as $c )
+ {
+ $componentCssFile = OR_THEMES_DIR.config('interface','theme').'/include/html/'.$c.'/'.$c.'.css';
+ if ( is_file($componentCssFile) )
+ $css[] = $componentCssFile;
+
+ // LESS-Version vorhanden?
+ $componentCssFile = OR_THEMES_DIR.config('interface','theme').'/include/html/'.$c.'/'.$c.'.less';
+ if ( is_file($componentCssFile) )
+ $css[] = $componentCssFile;
+
+ }
+
+ if ( DEVELOPMENT ) {
+
+ foreach( $css as $id=>$cssFile )
+ {
+ if ( substr($cssFile,-5)=='.less')
+ {
+ echo "/* LESS Source file: $cssFile */";
+ $parser = new Less_Parser();
+ $parser->parse( file_get_contents($cssFile) );
+ echo $parser->getCss();
+ }
+ else
+ {
+ echo "/* CSS Source file: $cssFile */";
+ echo file_get_contents($cssFile);
+ }
+ }
+ }
+ else
+ {
+ // Production mode: Inline minified CSS
+ ob_start('minifyCSS');
+ foreach( $css as $id=>$cssFile )
+ {
+ if ( substr($cssFile,-5)=='.less')
+ {
+ $parser = new Less_Parser();
+ $parser->parse( file_get_contents($cssFile) );
+ echo $parser->getCss();
+ }
+ else
+ {
+ echo file_get_contents($cssFile);
+ }
+
+ }
+ ob_end_flush();
+ }
+
+ // Je Theme die Theme-CSS-Datei ausgeben.
+ foreach( array_keys(config('style')) as $styleId )
+ {
+
+ $css = file_get_contents(OR_THEMES_EXT_DIR.'default/css/openrat-theme.less');
+ $css = str_replace('__name__',$styleId,$css);
+ $css = str_replace('__IMAGE_PATH__',OR_THEMES_EXT_DIR.'default/images/',$css);
+ foreach( config('style',$styleId) as $key=>$value)
+ {
+ $css = str_replace('__'.$key.'__',$value,$css);
+ }
+ $parser = new Less_Parser();
+ $parser->parse( $css );
+ $css = $parser->getCss();
+ if ( PRODUCTION)
+ $css = minifyCSS($css);
+ echo $css;
+ }
+
+ exit;
+ }
+
+
+ public function javascriptView()
+ {
+ if ( DEVELOPMENT )
+ $this->lastModified( config('config','last_modification') );
+ else
+ $this->lastModified(config('config','last_modification',1*60*60) );
+
+ header('Content-Type: text/javascript');
+
+ function minifyJS( $source ) {
+ $jz = new JSqueeze();
+
+ return $jz->squeeze(
+ $source,
+ true, // $singleLine
+ true, // $keepImportantComments
+ false // $specialVarRx
+ );
+ }
+
+ $js = array();
+ $js[] = OR_THEMES_EXT_DIR.'default/js/jquery-1.12.4.min.js';
+ $js[] = OR_THEMES_EXT_DIR.'default/js/jquery-ui/js/jquery-ui-1.8.16.custom.min.js';
+ $js[] = OR_THEMES_EXT_DIR.'default/js/jquery.scrollTo.js';
+ //$js[] = OR_THEMES_EXT_DIR default/js/jquery.mjs.nestedSortable.js"></script>
+
+ //<!-- OpenRat internal JS -->
+ $js[] = OR_THEMES_EXT_DIR.'default/js/openrat.js';
+ $js[] = OR_THEMES_EXT_DIR.'default/js/plugin/jquery-plugin-orHint.js';
+ $js[] = OR_THEMES_EXT_DIR.'default/js/plugin/jquery-plugin-orSearch.js';
+ $js[] = OR_THEMES_EXT_DIR.'default/js/plugin/jquery-plugin-orLinkify.js';
+ $js[] = OR_THEMES_EXT_DIR.'default/js/plugin/jquery-plugin-orTree.js';
+ $js[] = OR_THEMES_EXT_DIR.'default/js/plugin/jquery-plugin-orLoadView.js';
+ $js[] = OR_THEMES_EXT_DIR.'default/js/plugin/jquery-plugin-orAutoheight.js';
+ $js[] = OR_THEMES_EXT_DIR.'default/js/jquery-qrcode.min.js';
+ // $js[] = OR_THEMES_EXT_DIR.'../editor/wymeditor/wymeditor/jquery.wymeditor.min.js"></script> -->
+ $js[] = OR_THEMES_EXT_DIR.'../editor/markitup/markitup/jquery.markitup.js';
+ $js[] = OR_THEMES_EXT_DIR.'../editor/editor/ckeditor.js';
+ $js[] = OR_THEMES_EXT_DIR.'../editor/ace/src-min-noconflict/ace.js';
+ $js[] = OR_THEMES_EXT_DIR.'../editor/editor/adapters/jquery.js';
+
+ // Komponentenbasiertes Javascript
+ $elements = parse_ini_file( OR_THEMES_DIR.config('interface','theme').'/include/elements.ini.'.PHP_EXT);
+
+ foreach( array_keys($elements) as $c )
+ {
+ $componentJsFile = OR_THEMES_DIR.config('interface','theme').'/include/html/'.$c.'/'.$c.'.js';
+ if ( is_file($componentJsFile) )
+ $js[] = $componentJsFile;
+
+ }
+
+ if ( DEVELOPMENT )
+ {
+
+ foreach( $js as $jsFile )
+ {
+ echo "\n// JS source file: $jsFile\n";
+ readFile($jsFile);
+ }
+ }
+ else
+ {
+ foreach( $js as $jsFile )
+ {
+ ob_start('minifyJS');
+ echo minifyJS( file_get_contents($jsFile));
+ ob_end_flush();
+ }
+ }
+
+ exit;
+
+ }
}
?>
\ No newline at end of file
diff --git a/action/LoginAction.class.php b/action/LoginAction.class.php
@@ -398,7 +398,7 @@ class LoginAction extends Action
{
if ( is_array($dbconf) && $dbconf['enabled'] )
$dbids[$dbname] = array('key' =>$dbname,
- 'value'=>Text::maxLength($dbconf['comment']),
+ 'value'=>Text::maxLength($dbconf['description']),
'title'=>$dbconf['comment'].(isset($dbconf['host'])?' ('.$dbconf['host'].')':'') );
}
diff --git a/dispatcher.php b/dispatcher.php
@@ -118,7 +118,9 @@ try
define('TEMPLATE_DIR',OR_THEMES_DIR.$conf['interface']['theme'].'/templates');
define('CSS_DIR' ,OR_THEMES_DIR.$conf['interface']['theme'].'/css' );
define('IMAGE_DIR' ,OR_THEMES_DIR.$conf['interface']['theme'].'/images' );
- define('DEVELOPMENT' ,!$conf['production']);
+
+ define('PRODUCTION' ,$conf['production']);
+ define('DEVELOPMENT' ,!PRODUCTION);
require_once( "functions/config.inc.php" );
require_once( "functions/language.inc.".PHP_EXT );
diff --git a/themes/default/css/openrat-theme.css.php b/themes/default/css/openrat-theme.css.php
@@ -1,9 +0,0 @@
-<?php header('Content-Type: text/css',true) ?>
-
-
-html
-{
- scrollbar-face-color: <?php echo $_GET['title_background_color']; ?>;
- scrollbar-arrow-color: <?php echo $_GET['title_background_color']; ?>;
- scrollbar-base-color: <?php echo $_GET['title_text_color']; ?>;
-}
diff --git a/themes/default/css/openrat-theme.less b/themes/default/css/openrat-theme.less
@@ -0,0 +1,1819 @@
+
+html.theme-__name__
+{
+ scrollbar-face-color: __title_background_color__;
+ scrollbar-arrow-color: __title_background_color__;
+ scrollbar-base-color: __title_text_color__;
+
+
+ div#workbench div.panel.modal
+ {
+ border-color: __text_color__ !important;
+ -webkit-box-shadow: 0px 0px 40px __text_color__;
+ -moz-box-shadow: 0px 0px 40px __text_color__;
+ box-shadow: 0px 0px 40px __text_color__;
+
+ }
+
+
+
+ div#dialog
+ {
+ background-color:__background_color__;
+ color:__text_color__;
+
+ border-color: __text_color__ !important;
+ -webkit-box-shadow: 0px 0px 40px __text_color__;
+ -moz-box-shadow: 0px 0px 40px __text_color__;
+ box-shadow: 0px 0px 40px __text_color__;
+ }
+
+
+
+ /* Mouseover */
+ div.container > div.divider.ui-draggable-dragging
+ {
+ background-color: __title_background_color__;
+ }
+
+
+
+ /* Pfeile */
+ div#workbench div.panel div.arrow-down
+ {
+ border-top-color: __title_background_color__;
+ }
+ div#workbench div.panel div.arrow-right
+ {
+ border-left-color: __title_background_color__;
+ }
+
+ /* ab hier erstmal alles openrat-ui reinkopiert */
+ /*
+OpenRat Content Management System
+Copyright (C) 2002-2010 Jan Dankert
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+
+iframe
+{
+ width:100%;
+ height:500px;
+ display:block;
+ border: 1px solid __title_background_color__;
+}
+
+div.breadcrumb,
+div.breadcrumb a,
+div.panel > div.title
+{
+ x-background-color:__title_background_color__;
+ xsopacity:0.7;
+ color:__title_text_color__;
+ font-weight:bold;
+}
+
+/* H e a d e r */
+div#header
+{
+ width:100%;
+ height:27px;
+ overflow:hidden;
+ padding:5px;
+ margin:0px;
+ margin-bottom:3px;
+ float:left;
+}
+
+div#header div.projects,
+div#header div.menu,
+div#header div.title
+{
+ float:left;
+ margin-right:10px;
+ margin-left :0px;
+}
+
+div#header div.user,
+div#header div.search,
+div#header div.history
+{
+ float:right;
+ margin-right:10px;
+ margin-left :10px;
+}
+
+/*
+
+div#tree
+{
+ padding:5px;
+ width:25%;
+ margin-left:0px;
+ float:left;
+}
+*/
+
+
+/* N o t i c e */
+div#noticebar
+{
+ display:block;
+ position:fixed;
+ bottom:40px;
+ right:40px;
+ width:250px;
+ z-index:113;
+}
+
+div#noticebar div.notice
+{
+ border: 2px solid __text_color__;
+
+ padding:5px;
+ margin:5px;
+
+ -moz-border-radius:5px; /* Mozilla */
+ -webkit-border-radius:5px; /* Webkit */
+ -khtml-border-radius:5px; /* Konqui */
+ border-radius:5px; /* CSS 3 */
+
+ -webkit-box-shadow: 3px 2px 5px __text_color__;
+ -moz-box-shadow: 3px 2px 5px __text_color__;
+ box-shadow: 3px 2px 5px __text_color__;
+
+ display:none;
+}
+div#noticebar div.notice.ok
+{
+ background-color: green;
+}
+div#noticebar div.notice.warning
+{
+ background-color: yellow;
+}
+div#noticebar div.notice.error
+{
+ background-color:red;
+}
+div#noticebar div.notice.info
+{
+ background-color:__inactive_background_color__;
+}
+div#noticebar div.notice.error div.text
+{
+ font-weight: bold;
+}
+div#noticebar div.log
+{
+ font-family: monospace;
+}
+
+/* H o e h e n */
+html,body
+{
+ height:100%;
+}
+
+
+/*
+
+div#tree, div#content
+{
+ height:auto;
+}
+*/
+
+/*div.panel {
+ height:90%;
+}
+*/
+
+div.panel div.title
+{
+ height:20px;
+}
+
+
+
+div.panel div.status
+{
+ height:35px;
+}
+div.panel > div.content
+{
+ xxoverflow-x:auto;
+}
+
+
+ul#history > li,
+div.content a.action,
+div.content a.help,
+div.filler div.headermenu > a.entry,
+div.filler div.header a.back.button
+{
+ margin:9px;
+ padding-top:4px;
+ padding-bottom:4px;
+ padding-left:7px;
+ padding-right:7px;
+ border:1px solid __title_background_color__;
+ -moz-border-radius:5px; /* Mozilla */
+ -webkit-border-radius:5px; /* Webkit */
+ -khtml-border-radius:5px; /* Konqui */
+ border-radius:5px;
+ background-color: __title_text_color__;
+ background: -moz-linear-gradient(top, __title_background_color__, __inactive_background_color__);
+ background: -webkit-gradient(linear, left top, left bottom, from(__title_background_color__), to(__inactive_background_color__));
+ font-style:normal;
+ font-weight:normal;
+ text-decoration:none;
+ color:__text_color__;
+}
+
+ul#history > li.active
+{
+ background-color: __title_text_color__;
+ font-weight:bold;
+ color:__text_color__;
+}
+
+
+a.help
+{
+ float:right;
+}
+
+a.help
+{
+ cursor:help;
+}
+
+a.action:hover,
+a.help:hover,
+div.noaction:hover
+{
+ text-decoration:none;
+ border-color:__title_text_color__;
+}
+
+a.action:active,
+a.help:active,
+div.noaction:active,
+input.ok:active
+{
+ border-color:red;
+}
+
+
+a
+{
+ color:__text_color__;
+}
+
+
+
+/* D r o p d o w n - M e n u e s */
+div.dropdown
+{
+ z-index:2;
+ display:none;
+ position: absolute;
+ padding:5px 0px;
+}
+
+div.dropdownalignright
+{
+ right:0;
+}
+
+div.dropdown > a
+{
+ display:block;
+}
+div.dropdown div.entry
+{
+ padding:2px 5px;
+}
+
+div.dropdown > div.divide
+{
+ height:1px;
+ background-color: __title_background_color__;
+ width:100%;
+ margin-top: 5px;
+ margin-bottom: 5px;
+}
+
+div#header > div.menu {
+ overflow: hidden;
+}
+/*Dropdown anzeigen!!!*/
+div#header div:hover div.dropdown,
+div.panel div:hover > div.dropdown,
+div.panel-icon:hover > div.dropdown
+{
+ display:block;
+}
+
+
+
+div.onrowvisible
+{
+ visibility: hidden;
+ display:inline;
+}
+td:hover > div.onrowvisible
+{
+ visibility: visible;
+}
+
+
+
+/* Vorschau von Text-Inhalten */
+
+td.preview { background-color:papayawhip; border-top:1px solid __inactive_background_color__; border-bottom:1px solid __inactive_background_color__; }
+.preview h1 { font-size:138.5%; }
+.preview h2 { font-size:123.1%; }
+.preview h3 { font-size:108%; }
+.preview h1,.preview h2,.preview h3 {
+ margin:1em 0;
+}
+.preview h1,
+.preview h2,
+.preview h3,
+.preview h4,
+.preview h5,
+.preview h6,
+.preview strong
+{
+ font-weight:bold;
+}
+.preview abbr,.preview acronym {
+ border-bottom:1px dotted #000;
+ cursor:help;
+}
+.preview em {
+ font-style:italic;
+}
+.preview ol,.preview ul,.preview dl {
+ margin-left:2em;
+}
+.preview ol li
+{
+ list-style: decimal outside;
+}
+.preview ul li
+{
+ list-style: disc outside;
+}
+.preview a:link,
+.preview a:visited,
+.preview a:active,
+.preview a:hover
+{
+ text-decoration:underline;
+ color:blue;
+}
+
+
+
+/* Verweise */
+a:link,
+a:visited
+{
+ font-weight:normal;
+ text-decoration:none;
+}
+a:active,
+a:hover
+{
+ font-weight:normal;
+ text-decoration:none;
+}
+
+
+
+/* Submenu-Entrys */
+body.menu tr.menu td table tr td,
+body.main tr.menu td table tr td
+{
+ padding:4px; padding-right:6px;padding-left:6px; width:30px;
+ white-space:nowrap;
+}
+
+/* Submenu-Width */
+body.menu tr.menu table { width:50px;}
+
+
+/* Inaktive Menuepunkte werden ausgegraut */
+body.menu tr.menu td table tr td.noaction,
+body.main tr.menu td table tr td.noaction
+{
+ color:__title_background_color__;
+}
+
+/* Icon-Innenabstand */
+img[align=left],
+img[align=right] {padding-right:1px;padding-left:1px;}
+
+/* Vorformatierter Text */
+pre
+{
+ font-family:Courier;
+ font-size:13px;
+}
+
+/* Kleingedrucktes */
+small
+{
+ color:__title_background_color__;
+}
+
+
+/* Kurztasten */
+body.menu span.accesskey,
+body.main span.accesskey
+{
+ text-decoration:underline;
+}
+
+
+
+
+/* Menzue-Titel-Zeile */
+body.menu tr.title td,
+body.main tr.title td
+{
+ vertical-align:middle;
+ padding:4px;
+ height:30px;
+}
+
+/* Hinweis */
+td.message { padding:10px; font-weight:bold; }
+
+
+/* Allgemeine Inhaltszellen */
+body.main table.main td.window td
+{
+ padding:4px;
+}
+
+
+/* Action-Button */
+body.main table.main td.window td.act
+{
+ padding:15px;
+ margin-top:20px;
+ border-top:1px solid __title_background_color__;
+ text-align:right;
+}
+
+/* Lizenzhinweis */
+a.copyright
+{
+ font-size:0.7em;
+ text-decoration:none;
+}
+
+/* Message of the day */
+td.motd
+{
+ border-left: 3px solid red;
+ border-right: 3px solid red;
+ font-weight: bold;
+ padding:10px;
+ margin:10px;
+}
+
+/* Hauptfenster */
+table.main
+{
+ x-border:3px solid;
+}
+
+
+
+div.panel input.checkbox,
+div.panel input.radio
+{
+ border:1px solid __title_background_color__;
+}
+
+/* Eingabefeld fuer Beschreibung */
+textarea.desc,
+textarea.description
+{
+ font-family:Arial;
+ font-size:13px;
+}
+
+/* Eingabefeld fuer Textabsatz */
+textarea.longtext
+{
+ font-family:Arial;
+ font-size:13px;
+ width:100%;
+ border:1px solid __text_color__;
+}
+
+
+
+
+
+/* Hilfe-Texte */
+tr td.help
+{
+ font-style: italic;
+}
+
+tr.headline td.help
+{
+ /*
+ border-bottom:1px solid __text_color__;
+ */
+ font-style: normal;
+
+}
+
+/* Logo */
+td.logo
+{
+ padding:10px;
+ margin:0px;
+}
+
+div.logo h2
+{
+ font-family:Verdana;
+ font-weight:normal;
+ font-size:24px;
+}
+div.logo p
+{
+ font-family:Verdana;
+ font-size:13px;
+}
+
+div#header div.search input
+{
+ margin:0px;
+ padding:0px;
+}
+
+
+
+/* Notizen */
+td.notice
+{
+ margin:0px;
+ padding:5%;
+ text-align:center;
+}
+table.notice
+{
+ width:100%;
+ border:1px solid;
+ border-spacing:0px;
+}
+table.notice th
+{
+ padding:2px;
+ white-space:nowrap;
+ border-bottom:1px solid __text_color__;
+ font-weight:normal;
+ text-align:left;
+}
+
+table.notice tr.error
+{
+}
+
+table.notice tr.warning
+{
+ margin:0px;
+ padding:0px;
+}
+
+
+
+/* Kalender */
+table.calendar
+{
+ table-layout:fixed;
+ border-collapse:collapse;
+ text-align: center;
+}
+table.calendar td
+{
+ border: 1px dotted;
+}
+
+
+label,
+.clickable
+{
+ cursor: pointer;
+}
+
+body {
+ cursor:default;
+}
+
+input {
+ xcursor:text;
+}
+
+
+div.menu
+{
+ float:none;
+ xclear:left;
+}
+
+
+
+form.xlogin
+{
+ xbackground-color:#E0E0D5;
+ border:2px solid __inactive_background_color__;
+ position:absolute;
+ z-index:999;
+ top:5%;
+ left:5%;
+ width:80%;
+ margin:5%;
+ padding:10%;
+ opacity:1;
+
+ -webkit-box-shadow: 3px 2px 5px __title_background_color__;
+ -moz-box-shadow: 3px 2px 5px __title_background_color__;
+ box-shadow: 3px 2px 5px __title_background_color__;
+}
+
+
+
+
+
+
+
+/* B a u m */
+ul.tree,
+ul.tree ul
+{
+ list-style-type: none;
+ background: url(__IMAGE_PATH__/tree_line.gif) repeat-y;
+ margin: 0; padding: 0;
+}
+
+ul.tree ul
+{
+ margin-left:18px;
+}
+
+div.entry.selected,
+div.dropdown > div.entry:hover,
+div.dropdown > div.entry:hover > a,
+a.element
+{
+ background-color:__title_background_color__;
+ color:__title_text_color__;
+}
+
+
+
+ul.tree div.tree
+{
+ width:18px;
+ min-width:18px;
+ height:18px;
+ xbackground-color:red;
+ float:left;
+}
+ul.tree div.tree,
+ul.tree div.entry
+{
+ height:18px;
+ max-height:18px;
+ min-height:18px;
+}
+
+ul.tree div img
+{
+ cfloat:left;
+}
+
+ul.tree li
+{margin: 0; padding: 0 0px;
+ line-height: 18px;
+ background: url(__IMAGE_PATH__/tree_none.gif) no-repeat;
+ xcolor: #369;
+ font-weight: normal;
+ white-space:nowrap;
+}
+
+ul.tree li.last,
+ul.tree li:last-child
+{
+ background: url(__IMAGE_PATH__/tree_none_end.gif) no-repeat;
+}
+
+div.tree.open
+{
+ background: url(__IMAGE_PATH__/tree_minus.png) no-repeat;
+}
+div.tree.closed
+{
+ background: url(__IMAGE_PATH__/tree_plus.png) no-repeat;
+}
+
+
+body > div
+{
+ display:none;
+}
+
+
+/* Strukturen
+div.structure ul
+{
+ padding-left:10px;
+ margin-left:10px;
+}
+*/
+
+div.structure em
+{
+ font-style: italic;
+}
+
+
+
+
+/* T a b s */
+
+.drophover
+{
+ border:2px dotted green;
+ cursor: move;
+}
+.dropactive
+{
+ border:1px dotted blue;
+ cursor: move;
+}
+
+div.panel > div.header > div.panel-icon
+{
+ xposition: static;
+ xright:-30px;
+ top:3px;
+}
+
+div.backward_link
+{
+ float:left;
+}
+div.forward_link
+{
+ float:right;
+}
+
+div.panel > div.header
+{
+ padding:0px;
+ width:100%;
+ height:25px;
+ border-bottom: 1px solid __title_background_color__;
+}
+
+
+div.panel div.header ul.views
+{
+ text-align: left; /* set to left, right or center */
+ list-style-type: none;
+ overflow: hidden; /* Gescrollt wird hier mit JavaScript */
+ white-space:nowrap;
+}
+
+img.icon
+{
+ padding:4px;
+ width: 16px;
+ height: 16px;
+}
+
+
+ul.views div.tabname
+{
+ overflow: hidden;
+ white-space: nowrap;
+ padding:4px;
+ vertical-align: middle;
+}
+ul.views > li > img,
+ul.views > li > div
+{
+ float:left;
+}
+
+div.panel div.header div.panel-icon,
+div.inputholder > div.icon
+{
+ float: right;
+}
+
+
+div.panel div.header > ul.views
+{
+ float:left;
+ height: 25px;
+}
+
+div.panel div.header
+{
+ xborder-bottom: 1px solid __title_background_color__;
+}
+
+
+div.content
+{
+ clear: both;
+}
+
+div.panel ul.views li
+{
+ vertical-align: middle;
+ padding:0px;
+
+ cursor:pointer;
+
+ border-right: 1px solid __title_background_color__;
+
+ -moz-border-radius-topleft:5px; /* Mozilla */
+ -webkit-border-radius-topleft:5px; /* Webkit */
+ -khtml-border-top-radius-topleft:5px; /* Konqui */
+ border-top-right-radius:5px;
+ -moz-border-radius-topright:5px; /* Mozilla */
+ -webkit-border-radius-topright:5px; /* Webkit */
+ -khtml-border-top-radius-topright:5px; /* Konqui */
+ border-top-right-radius:5px;
+
+ xborder-top:1px solid __title_background_color__;
+ xborder-left:1px solid __title_background_color__;
+ xborder-right:1px solid __title_background_color__;
+ xmargin-right:10px;
+ display: inline;
+ white-space:nowrap;
+ float:left;
+}
+
+
+
+
+
+
+/*
+
+div#workbench div.frame {
+ padding:3px;
+ border:1px solid __title_background_color__;
+
+ -moz-border-radius:3px;
+ -webkit-border-radius:3px;
+ -khtml-border-radius:3px;
+ border-radius:3px;
+}
+*/
+
+
+
+/*
+div.panel {
+ padding:3px;
+ border:1px solid __title_background_color__;
+
+ -moz-border-radius:5px;
+ -webkit-border-radius:5px;
+ -khtml-border-radius:5px;
+ border-radius:5px;
+}
+*/
+
+
+
+div.panel {
+ margin:0px;
+ padding:0px;
+}
+
+div.panel div.content table
+{
+ overflow:auto;
+ border:2px __inactive_background_color__;
+}
+
+
+table tr.headline > td {
+
+ /*
+ background-color: __inactive_background_color__;
+ background: -moz-linear-gradient(top, __title_background_color__, __inactive_background_color__);
+ background: -webkit-gradient(linear, left top, left bottom, from(__title_background_color__), to(__inactive_background_color__));
+
+ border-right:1px solid __inactive_background_color__;
+
+ */
+ border-bottom:1px solid __title_background_color__;
+ padding:3px;
+ font-weight: bold;
+}
+
+
+table tr.data > td {
+ border-bottom:1px solid __title_background_color__;
+ /*
+ border-right:1px solid __inactive_background_color__;
+ */
+ padding:3px;
+}
+
+
+
+/* F a r b e n */
+
+/* Ungerade Tabellenzeilen (funktioniert nicht im FF) */
+table > tr.data:nth-child(2n) {
+ background-color: __inactive_background_color__;
+}
+
+/* Datenzeile - Mauseffekt */
+table tr.data:hover,
+div.content li div.entry:hover
+{
+ background-color:__inactive_background_color__;;
+}
+
+ul.tree div
+{
+cursor:pointer;
+}
+
+
+/* Hintergrund Fenster */
+/*
+
+div.panel {
+ background-color: #3399FF;
+}
+*/
+
+
+
+
+/* S t a t u s z e i l e */
+div.panel div.status
+{
+ padding:10px;
+}
+
+
+div.panel div.status div.error,
+div.message.error
+{
+ background: url(__IMAGE_PATH__/notice_error.png) no-repeat;
+ background-position:5px 7px;
+}
+div.panel div.status div.warn,
+div.message.warn
+{
+ background: url(__IMAGE_PATH__/notice_warning.png) no-repeat;
+ background-position:5px 7px;
+}
+div.panel div.status div.ok,
+div.message.ok
+{
+ background: url(__IMAGE_PATH__/notice_ok.png) no-repeat;
+ background-position:5px 7px;
+}
+div.panel div.status div.info,
+div.message.info
+{
+ background: url(__IMAGE_PATH__/notice_info.png) no-repeat;
+ background-position:5px 7px;
+}
+
+div.panel div.status div,
+div.message
+{
+ border:1px solid __title_background_color__;
+ padding:5px 0px 5px 25px;
+ margin:10px 10px 20px 10px;
+
+ -moz-border-radius:5px;
+ -webkit-border-radius:5px;
+ -khtml-border-radius:5px;
+ border-radius:5px;
+}
+
+/* Fortschrittsbalken */
+div.loader,
+div.progress
+{
+ background: url(__IMAGE_PATH__/loader.gif) no-repeat;
+ background-position: center;
+ opacity: 0.5;
+ cursor: wait;
+ min-height:50px;
+}
+
+
+
+/* V o l l b i l d */
+div#workbench div.panel.fullscreen
+{
+ display:block;
+ z-index:109;
+
+ /*set the div in the top-left corner of the screen*/
+ position:fixed;
+ top:0;
+ left:0;
+ background-color:__background_color__;
+ margin:0px;
+
+ /*set the width and height to 100% of the screen*/
+ width:100% !important;
+ height:100% !important;
+}
+div#workbench div.panel.fullscreen > div.content
+{
+ width:100% !important;
+ height:100% !important;
+}
+
+.invisible
+{
+ visibility:hidden;
+}
+.visible
+{
+ visibility:visible;
+}
+
+
+div#workbench
+{
+ width:100%;
+}
+
+body
+{
+ overflow:hidden;
+}
+
+div#workbench div.panel
+{
+ border:1px solid __title_background_color__;
+ margin:0px;
+ padding:0px;
+ -moz-border-radius:5px;
+ -webkit-border-radius:5px;
+ -khtml-border-radius:5px;
+ border-radius:5px;
+}
+
+div#workbench div.container,
+div#workbench div.panel,
+div#workbench div.divider
+{
+ display: inline;
+ float: left;
+ margin: 0px;
+}
+
+div#workbench
+{
+ padding:3px;
+}
+
+
+div#workbench div.panel > div.content
+{
+ overflow:auto;
+}
+
+
+/*
+ * Formular-Button-Leiste
+ */
+div.panel {
+ position:relative;
+}
+div.content div.bottom
+{
+ xbackground-color: __background_color__;
+ height:55px;
+ width:100%;
+ position:absolute;
+ padding-right:40px;
+ bottom:0px;
+ right:0px;
+ xvisibility:hidden;
+}
+
+div.content div.bottom > div.command
+{
+ xvisibility:visible;
+ float:right;
+ z-index:20;
+}
+div.content form[data-autosave='true'] div.command
+{
+ display: none;
+}
+
+div.content > form
+{
+ padding-bottom:45px;
+}
+
+input.submit
+{
+ background-color: __title_background_color__;
+ color: __title_text_color__;
+ padding: 7px;
+ border:0px;
+ -moz-border-radius:7px; /* Mozilla */
+ -webkit-border-radius:7px; /* Webkit */
+ -khtml-border-radius:7px; /* Konqui */
+ border-radius:7px;
+ margin-left:20px;
+ -webkit-box-shadow: 0px 0px 15px __background_color__;
+ -moz-box-shadow: 0px 0px 15px __background_color__;
+ box-shadow: 0px 0px 15px 10px __background_color__;
+ cursor:pointer;
+}
+
+
+input.submit.ok
+{
+ font-weight:bold; /* Primäre Aktion in Fettdruck */
+}
+
+
+/* Pfeile nur anzeigen, wenn Maus über der Titelleiste */
+div.views > div.backward_link,
+div.views > div.forward_link
+{
+ visibility: hidden;
+}
+div.views:HOVER > div.backward_link,
+div.views:HOVER > div.forward_link
+{
+ visibility: visible;
+}
+
+
+div#shortcuts {
+ height:24px;
+ margin-left:10px;
+}
+div#shortcuts > div.shortcut {
+ width:24px;
+ height:24px;
+ margin-left:5px;
+ float:left;
+ opacity:0.8;
+}
+
+div#shortcuts > div.shortcut:HOVER {
+
+ xborder: 1px solid __title_background_color__;
+ x-moz-border-radius:2px; /* Mozilla */
+ x-webkit-border-radius:2px; /* Webkit */
+ x-khtml-border-radius:2px; /* Konqui */
+ opacity:1.0;
+ position:relative;
+ bottom:3px;
+
+}
+
+
+
+
+/* Smaller screens */
+
+@media only screen and (max-width: 1023px) {
+
+ body {
+ font-size: 0.8em;
+ line-height: 1.5em;
+ }
+
+ }
+
+
+/* Mobile */
+
+@media handheld, only screen and (max-width: 767px) {
+
+ body {
+ font-size: 16px;
+ -webkit-text-size-adjust: none;
+ overflow: visible;
+ }
+ div#header,
+ div#workbench {
+ width: 100%;
+ height: auto;
+ min-width: 0;
+ margin-left: 0px;
+ margin-right: 0px;
+ padding-left: 0px;
+ padding-right: 0px;
+ }
+
+ div#workbench div.panel
+ {
+ width:auto !important;
+ }
+
+ li.action div.tabname
+ {
+ width:auto !important;
+ }
+
+ div#workbench div.panel
+ {
+ width: auto;
+ float: none;
+ margin-left: 0px;
+ margin-right: 0px;
+ padding-left: 20px;
+ padding-right: 20px;
+ }
+ div#workbench div.panel > div.content
+ {
+ overflow:auto;
+ height: auto !important;
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+body > div#header {
+ display:block;
+}
+
+ul#history > li {
+
+ xdisplay:inline;
+ margin:5px;
+ padding:5px;
+ border:1px solid __title_background_color__;
+ background-color: __inactive_background_color__;
+ color:__text_color__;
+}
+ul#history > li.active {
+
+ xdisplay:inline;
+ margin:5px;
+ padding:5px;
+ border:1px solid __text_color__;
+ background-color: __title_text_color__;
+ color:__text_color__;
+}
+
+ul#history {
+ display:none;
+}
+
+
+table td.readonly {
+ font-style: italic;
+ font-weight: normal;
+}
+table td.default {
+ font-style: normal;
+ font-weight: normal;
+}
+table td.changed {
+ font-style: normal;
+ font-weight: bold;
+}
+
+
+/* Modale Dialoge */
+
+div#filler
+{
+ xxxxdisplay: block;
+ position:absolute;
+ z-index: 100;
+ top: 0;
+ left: 0;
+ height:100%;
+ width:100%;
+ background-color: __text_color__;
+ opacity: 0.5;
+}
+
+
+div.clickable.filtered.inactive > a
+{
+ color: __inactive_background_color__;
+}
+
+/* Pfeile */
+div#header > div > div.arrow-down
+{
+ display: inline;
+ width:0;
+ height:0;
+ margin:6;
+ padding:0px;
+ border-right : 6px solid __title_background_color__;
+ border-left : 6px solid __title_background_color__;
+ border-top : 6px solid __inactive_background_color__;
+ border-bottom: 4px solid __title_background_color__;
+ margin-top: 10px;
+font-size: 0;
+}
+
+
+
+/* D r o p d o w n - M e n u e s */
+div.dropdown
+{
+ /* Schatten */
+ -webkit-box-shadow: 3px 2px 10px __title_background_color__;
+ -moz-box-shadow: 3px 2px 10px __title_background_color__;
+ box-shadow: 3px 2px 10px __title_background_color__;
+
+ opacity:0.95;
+
+ border:2px solid __title_background_color__;
+ -moz-border-radius:5px; /* Mozilla */
+ -webkit-border-radius:5px; /* Webkit */
+ -khtml-border-radius:5px; /* Konqui */
+ border-radius:5px;
+
+ /*
+ background: -moz-linear-gradient(top, __title_background_color__, __inactive_background_color__);
+ background: -webkit-gradient(linear, left top, left bottom, from(__title_background_color__), to(__inactive_background_color__));
+ */
+ font-style:normal;
+ font-weight:normal;
+ text-decoration:none;
+}
+
+
+div#header span.titletext
+{
+ color:__title_text_color__;
+}
+
+
+div.toolbar-icon
+{
+ border:1px solid __title_background_color__;
+ padding:2px;
+ margin-left:5px;
+ float: left;
+
+ -moz-border-radius:3px;
+ -webkit-border-radius:3px;
+ -khtml-border-radius:3px;
+ border-radius:3px;
+}
+div.toolbar-icon.inactive
+{
+ opacity:0.5;
+}
+
+div.toolbar-icon:hover
+{
+ border:1px solid __inactive_background_color__;
+ xxbackground-color: __inactive_background_color__;
+}
+
+
+div.headermenu
+{
+ margin:5px;
+ z-index: 1;
+ position: relative;
+ right: 0;
+ top: 0;
+}
+div.headermenu > div.toolbar-icon
+{
+ float:right;
+}
+
+
+ /* Voreingestellte Schriftart */
+body
+{
+
+}
+
+
+
+/* Formulare breit */
+div.panel.wide form div.line
+{
+ clear:left;
+ margin-top:10px;
+}
+
+div.panel.wide form div.label
+{
+ display:inline-block;
+ width:30%;
+ vertical-align:top;
+ text-align: right;
+}
+
+div.panel.wide form div.input
+{
+ display:inline-block;
+ width:60%;
+ vertical-align:top;
+ text-align: left;
+}
+
+/* Formulare schmal */
+div.panel.small form div.line
+{
+ clear:left;
+ padding:10px;
+}
+
+div.panel.small form div.label
+{
+ display:block;
+ width:100%;
+ vertical-align:top;
+ text-align: left;
+}
+
+div.panel.small form div.input
+{
+ display:block;
+ width:100%;
+ vertical-align:top;
+ text-align: left;
+}
+
+
+
+form div.label > label,
+form div.input > div.intputholder
+{
+ padding:0px 5px;
+}
+
+form div.input input[type=text],
+form div.input input[type=password],
+form div.input textarea,
+form div.input select
+{
+ width:100%;
+}
+form div.input input[type=checkbox],
+form div.input input[type=radio]
+{
+ vertical-align:top;
+}
+
+label
+{
+ display:inline-block;
+}
+
+input[type=checkbox] + label,
+input[type=radio] + label
+{
+ width:80%;
+}
+
+label div.description
+{
+ font-size: 0.75em;
+ color:__title_background_color__;
+}
+
+
+div.inputholder
+{
+ background-color:__title_text_color__;
+ border:1px solid __title_background_color__;
+ margin:0px;
+ padding:4px;
+ -moz-border-radius:3px;
+ -webkit-border-radius:3px;
+ -khtml-border-radius:3px;
+ border-radius:3px;
+
+ -webkit-box-shadow:inset 0px 0px 3px __title_background_color__;
+ -moz-box-shadow:inset 0px 0px 3px __title_background_color__;
+ box-shadow:inset 0px 0px 3px __title_background_color__;
+
+}
+
+
+div.inputholder ul.tree,
+div.inputholder ul.tree li.last,
+div.inputholder ul.tree li:last-child
+{
+ background-color:__title_text_color__;
+}
+
+div.inputholder > div.dropdown
+{
+ width:70%;
+}
+
+div.search > div.inputholder
+{
+ padding-top:1px;
+}
+
+div.inputholder > input,
+div.inputholder > textarea,
+div.inputholder > select
+{
+ border:0px;
+ border-bottom:1px solid __title_text_color__;
+ padding:2px;
+ margin:0px;
+ background-color:__title_text_color__;
+}
+
+input:focus,
+textarea:focus,
+select:focus
+{
+ border:0px;
+ border-bottom:1px solid __inactive_background_color__;
+}
+
+
+input.error,
+textarea.error,
+select.error
+{
+ border-bottom:1px dotted __text_color__ !important;
+}
+
+div.inputholder.error
+{
+ border:1px solid red !important;
+}
+
+input.hint
+{
+ color:__title_background_color__;
+}
+
+
+
+
+/* Eingabfeld fuer Namen */
+fieldset > div input.name,
+fieldset > div span.name
+{
+ font-weight:bold;
+}
+
+
+fieldset
+{
+ border-color:__title_background_color__;
+}
+
+/* Eingabfelder fuer Dateiname */
+fieldset > div input.filename,
+fieldset > div input.extension,
+fieldset > div input.ansidate,
+fieldset > div span.filename,
+fieldset > div span.extension,
+fieldset > div span.ansidate
+{
+ font-family:Courier;
+ font-size:1em;
+}
+
+
+div#tree
+{
+ overflow:visible;
+}
+
+
+
+
+
+/* Anzeige von Text-Unterschieden */
+
+/* Zeilen-Nr */
+tr.diff > td.line
+{
+ background-color:__title_text_color__;
+ padding-right:2px;
+ border-right:3px solid __title_background_color__;
+ text-align:right;
+ margin-right:2px;
+}
+
+/* Unveränderter Text */
+tr.diff > td.equal
+{
+}
+
+/* Entfernter Text */
+tr.diff > td.old
+{
+ background-color:red;
+}
+
+/* Hinzugefuegter Text */
+tr.diff > td.new
+{
+ background-color:green;
+}
+
+/* Geaenderter Text */
+tr.diff > td.notequal
+{
+ background-color:yellow;
+}
+
+dl.notice
+{
+ border-left:10px __inactive_background_color__ solid;
+ border-right:1px __inactive_background_color__ solid;
+ padding:15px;
+}
+
+dl.notice > dt
+{
+ border-top: 1px __inactive_background_color__ solid;
+}
+dl.notice > dd
+{
+ border-bottom: 1px __inactive_background_color__ solid;
+}
+
+
+/* S c h a t t e n */
+div.content a.action,
+div.content a.help
+{
+ -webkit-box-shadow: 3px 2px 5px __title_background_color__;
+ -moz-box-shadow: 3px 2px 5px __title_background_color__;
+ box-shadow: 3px 2px 5px __title_background_color__;
+}
+
+
+
+/* F a r b e n */
+
+/* Gesamt-Hintergrund */
+body
+{
+ xxxbackground-color:#c9c9c9;
+ background-color:__inactive_background_color__;
+}
+
+/* Fenster-Hintergrund */
+div.panel ul.views > li.active,
+div.panel ul.views > li.active:hover
+{
+ background-color: __title_background_color__;
+ background-image: linear-gradient(__inactive_background_color__ 0%, __title_background_color__ 15%);
+ color: __title_text_color__;
+}
+
+/* Titelleiste-Hintergrund */
+div#header
+{
+ background-color: __title_background_color__;
+ background-image: linear-gradient(__title_background_color__ 85%, __inactive_background_color__ 100%);
+ color: __title_text_color__;
+}
+
+/* Titelleiste */
+div#header div.toolbar-icon > a
+{
+ color: __title_text_color__;
+}
+
+div#header, /* Titelleite */
+ul.views > li.action /* Tabreiter */
+{
+ font-family: Arial, sans-serif;
+ font-size:13px;
+}
+
+div.content
+{
+ font-family: Trebuchet MS, Helvetica, Arial, sans-serif;
+ font-size:13px;
+}
+
+
+/* Reiter */
+div.panel ul.views li
+{
+ /*
+ background-color:__background_color__;
+ */
+}
+
+
+div.panel > div.content
+{
+ background-color:__background_color__;
+}
+
+div.panel > div.header
+{
+ background-color:__background_color__;
+ background-image: linear-gradient(__inactive_background_color__ 00%, __background_color__ 85%);
+}
+
+
+
+
+div.panel ul.views li:hover {
+ background-color: __inactive_background_color__;
+ /*
+ color: blue;
+ */
+}
+
+
+
+ul.tree li.last,
+ul.tree li:last-child
+{
+ background-color:__background_color__;
+}
+
+
+
+div.content pre,
+div.dropdown
+{
+ background-color:__title_text_color__;
+ color:__text_color__;
+ min-width: 150px;
+ max-width: 450px;
+}
+
+
+
+
+
+div.filler div.headermenu > a.entry,
+div.filler div.header a.back.button
+{
+ font-size: 0.8em;
+}
+
+
+}+
\ No newline at end of file
diff --git a/themes/default/css/openrat-ui.css b/themes/default/css/openrat-ui.css
@@ -0,0 +1,1765 @@
+/*
+OpenRat Content Management System
+Copyright (C) 2002-2010 Jan Dankert
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+
+iframe
+{
+ width:100%;
+ height:500px;
+ display:block;
+ border: 1px solid __title_background_color__;
+}
+
+div.breadcrumb,
+div.breadcrumb a,
+div.panel > div.title
+{
+ x-background-color:__title_background_color__;
+ xsopacity:0.7;
+ color:__title_text_color__;
+ font-weight:bold;
+}
+
+/* H e a d e r */
+div#header
+{
+ width:100%;
+ height:27px;
+ overflow:hidden;
+ padding:5px;
+ margin:0px;
+ margin-bottom:3px;
+ float:left;
+}
+
+div#header div.projects,
+div#header div.menu,
+div#header div.title
+{
+ float:left;
+ margin-right:10px;
+ margin-left :0px;
+}
+
+div#header div.user,
+div#header div.search,
+div#header div.history
+{
+ float:right;
+ margin-right:10px;
+ margin-left :10px;
+}
+
+/*
+
+div#tree
+{
+ padding:5px;
+ width:25%;
+ margin-left:0px;
+ float:left;
+}
+*/
+
+
+/* N o t i c e */
+div#noticebar
+{
+ display:block;
+ position:fixed;
+ bottom:40px;
+ right:40px;
+ width:250px;
+ z-index:113;
+}
+
+div#noticebar div.notice
+{
+ border: 2px solid __text_color__;
+
+ padding:5px;
+ margin:5px;
+
+ -moz-border-radius:5px; /* Mozilla */
+ -webkit-border-radius:5px; /* Webkit */
+ -khtml-border-radius:5px; /* Konqui */
+ border-radius:5px; /* CSS 3 */
+
+ -webkit-box-shadow: 3px 2px 5px __text_color__;
+ -moz-box-shadow: 3px 2px 5px __text_color__;
+ box-shadow: 3px 2px 5px __text_color__;
+
+ display:none;
+}
+div#noticebar div.notice.ok
+{
+ background-color: green;
+}
+div#noticebar div.notice.warning
+{
+ background-color: yellow;
+}
+div#noticebar div.notice.error
+{
+ background-color:red;
+}
+div#noticebar div.notice.info
+{
+ background-color:__inactive_background_color__;
+}
+div#noticebar div.notice.error div.text
+{
+ font-weight: bold;
+}
+div#noticebar div.log
+{
+ font-family: monospace;
+}
+
+/* H o e h e n */
+html,body
+{
+ height:100%;
+}
+
+
+/*
+
+div#tree, div#content
+{
+ height:auto;
+}
+*/
+
+/*div.panel {
+ height:90%;
+}
+*/
+
+div.panel div.title
+{
+ height:20px;
+}
+
+
+
+div.panel div.status
+{
+ height:35px;
+}
+div.panel > div.content
+{
+ xxoverflow-x:auto;
+}
+
+
+ul#history > li,
+div.content a.action,
+div.content a.help,
+div.filler div.headermenu > a.entry,
+div.filler div.header a.back.button
+{
+ margin:9px;
+ padding-top:4px;
+ padding-bottom:4px;
+ padding-left:7px;
+ padding-right:7px;
+ border:1px solid __title_background_color__;
+ -moz-border-radius:5px; /* Mozilla */
+ -webkit-border-radius:5px; /* Webkit */
+ -khtml-border-radius:5px; /* Konqui */
+ border-radius:5px;
+ background-color: __title_text_color__;
+ background: -moz-linear-gradient(top, __title_background_color__, __inactive_background_color__);
+ background: -webkit-gradient(linear, left top, left bottom, from(__title_background_color__), to(__inactive_background_color__));
+ font-style:normal;
+ font-weight:normal;
+ text-decoration:none;
+ color:__text_color__;
+}
+
+ul#history > li.active
+{
+ background-color: __title_text_color__;
+ font-weight:bold;
+ color:__text_color__;
+}
+
+
+a.help
+{
+ float:right;
+}
+
+a.help
+{
+ cursor:help;
+}
+
+a.action:hover,
+a.help:hover,
+div.noaction:hover
+{
+ text-decoration:none;
+ border-color:__title_text_color__;
+}
+
+a.action:active,
+a.help:active,
+div.noaction:active,
+input.ok:active
+{
+ border-color:red;
+}
+
+
+a
+{
+ color:__text_color__;
+}
+
+
+
+/* D r o p d o w n - M e n u e s */
+div.dropdown
+{
+ z-index:2;
+ display:none;
+ position: absolute;
+ padding:5px 0px;
+}
+
+div.dropdownalignright
+{
+ right:0;
+}
+
+div.dropdown > a
+{
+ display:block;
+}
+div.dropdown div.entry
+{
+ padding:2px 5px;
+}
+
+div.dropdown > div.divide
+{
+ height:1px;
+ background-color: __title_background_color__;
+ width:100%;
+ margin-top: 5px;
+ margin-bottom: 5px;
+}
+
+div#header > div.menu {
+ overflow: hidden;
+}
+/*Dropdown anzeigen!!!*/
+div#header div:hover div.dropdown,
+div.panel div:hover > div.dropdown,
+div.panel-icon:hover > div.dropdown
+{
+ display:block;
+}
+
+
+
+div.onrowvisible
+{
+ visibility: hidden;
+ display:inline;
+}
+td:hover > div.onrowvisible
+{
+ visibility: visible;
+}
+
+
+
+/* Vorschau von Text-Inhalten */
+
+td.preview { background-color:papayawhip; border-top:1px solid __inactive_background_color__; border-bottom:1px solid __inactive_background_color__; }
+.preview h1 { font-size:138.5%; }
+.preview h2 { font-size:123.1%; }
+.preview h3 { font-size:108%; }
+.preview h1,.preview h2,.preview h3 {
+ margin:1em 0;
+}
+.preview h1,
+.preview h2,
+.preview h3,
+.preview h4,
+.preview h5,
+.preview h6,
+.preview strong
+{
+ font-weight:bold;
+}
+.preview abbr,.preview acronym {
+ border-bottom:1px dotted #000;
+ cursor:help;
+}
+.preview em {
+ font-style:italic;
+}
+.preview ol,.preview ul,.preview dl {
+ margin-left:2em;
+}
+.preview ol li
+{
+ list-style: decimal outside;
+}
+.preview ul li
+{
+ list-style: disc outside;
+}
+.preview a:link,
+.preview a:visited,
+.preview a:active,
+.preview a:hover
+{
+ text-decoration:underline;
+ color:blue;
+}
+
+
+
+/* Verweise */
+a:link,
+a:visited
+{
+ font-weight:normal;
+ text-decoration:none;
+}
+a:active,
+a:hover
+{
+ font-weight:normal;
+ text-decoration:none;
+}
+
+
+
+/* Submenu-Entrys */
+body.menu tr.menu td table tr td,
+body.main tr.menu td table tr td
+{
+ padding:4px; padding-right:6px;padding-left:6px; width:30px;
+ white-space:nowrap;
+}
+
+/* Submenu-Width */
+body.menu tr.menu table { width:50px;}
+
+
+/* Inaktive Menuepunkte werden ausgegraut */
+body.menu tr.menu td table tr td.noaction,
+body.main tr.menu td table tr td.noaction
+{
+ color:__title_background_color__;
+}
+
+/* Icon-Innenabstand */
+img[align=left],
+img[align=right] {padding-right:1px;padding-left:1px;}
+
+/* Vorformatierter Text */
+pre
+{
+ font-family:Courier;
+ font-size:13px;
+}
+
+/* Kleingedrucktes */
+small
+{
+ color:__title_background_color__;
+}
+
+
+/* Kurztasten */
+body.menu span.accesskey,
+body.main span.accesskey
+{
+ text-decoration:underline;
+}
+
+
+
+
+/* Menzue-Titel-Zeile */
+body.menu tr.title td,
+body.main tr.title td
+{
+ vertical-align:middle;
+ padding:4px;
+ height:30px;
+}
+
+/* Hinweis */
+td.message { padding:10px; font-weight:bold; }
+
+
+/* Allgemeine Inhaltszellen */
+body.main table.main td.window td
+{
+ padding:4px;
+}
+
+
+/* Action-Button */
+body.main table.main td.window td.act
+{
+ padding:15px;
+ margin-top:20px;
+ border-top:1px solid __title_background_color__;
+ text-align:right;
+}
+
+/* Lizenzhinweis */
+a.copyright
+{
+ font-size:0.7em;
+ text-decoration:none;
+}
+
+/* Message of the day */
+td.motd
+{
+ border-left: 3px solid red;
+ border-right: 3px solid red;
+ font-weight: bold;
+ padding:10px;
+ margin:10px;
+}
+
+/* Hauptfenster */
+table.main
+{
+ x-border:3px solid;
+}
+
+
+
+div.panel input.checkbox,
+div.panel input.radio
+{
+ border:1px solid __title_background_color__;
+}
+
+/* Eingabefeld fuer Beschreibung */
+textarea.desc,
+textarea.description
+{
+ font-family:Arial;
+ font-size:13px;
+}
+
+/* Eingabefeld fuer Textabsatz */
+textarea.longtext
+{
+ font-family:Arial;
+ font-size:13px;
+ width:100%;
+ border:1px solid __text_color__;
+}
+
+
+
+
+
+/* Hilfe-Texte */
+tr td.help
+{
+ font-style: italic;
+}
+
+tr.headline td.help
+{
+ /*
+ border-bottom:1px solid __text_color__;
+ */
+ font-style: normal;
+
+}
+
+/* Logo */
+td.logo
+{
+ padding:10px;
+ margin:0px;
+}
+
+div.logo h2
+{
+ font-family:Verdana;
+ font-weight:normal;
+ font-size:24px;
+}
+div.logo p
+{
+ font-family:Verdana;
+ font-size:13px;
+}
+
+div#header div.search input
+{
+ margin:0px;
+ padding:0px;
+}
+
+
+
+/* Notizen */
+td.notice
+{
+ margin:0px;
+ padding:5%;
+ text-align:center;
+}
+table.notice
+{
+ width:100%;
+ border:1px solid;
+ border-spacing:0px;
+}
+table.notice th
+{
+ padding:2px;
+ white-space:nowrap;
+ border-bottom:1px solid __text_color__;
+ font-weight:normal;
+ text-align:left;
+}
+
+table.notice tr.error
+{
+}
+
+table.notice tr.warning
+{
+ margin:0px;
+ padding:0px;
+}
+
+
+
+/* Kalender */
+table.calendar
+{
+ table-layout:fixed;
+ border-collapse:collapse;
+ text-align: center;
+}
+table.calendar td
+{
+ border: 1px dotted;
+}
+
+
+label,
+.clickable
+{
+ cursor: pointer;
+}
+
+body {
+ cursor:default;
+}
+
+input {
+ xcursor:text;
+}
+
+
+div.menu
+{
+ float:none;
+ xclear:left;
+}
+
+
+
+form.xlogin
+{
+ xbackground-color:#E0E0D5;
+ border:2px solid __inactive_background_color__;
+ position:absolute;
+ z-index:999;
+ top:5%;
+ left:5%;
+ width:80%;
+ margin:5%;
+ padding:10%;
+ opacity:1;
+
+ -webkit-box-shadow: 3px 2px 5px __title_background_color__;
+ -moz-box-shadow: 3px 2px 5px __title_background_color__;
+ box-shadow: 3px 2px 5px __title_background_color__;
+}
+
+
+
+
+
+
+
+/* B a u m */
+ul.tree,
+ul.tree ul
+{
+ list-style-type: none;
+ background: url(__IMAGE_PATH__/tree_line.gif) repeat-y;
+ margin: 0; padding: 0;
+}
+
+ul.tree ul
+{
+ margin-left:18px;
+}
+
+div.entry.selected,
+div.dropdown > div.entry:hover,
+div.dropdown > div.entry:hover > a,
+a.element
+{
+ background-color:__title_background_color__;
+ color:__title_text_color__;
+}
+
+
+
+ul.tree div.tree
+{
+ width:18px;
+ min-width:18px;
+ height:18px;
+ xbackground-color:red;
+ float:left;
+}
+ul.tree div.tree,
+ul.tree div.entry
+{
+ height:18px;
+ max-height:18px;
+ min-height:18px;
+}
+
+ul.tree div img
+{
+ cfloat:left;
+}
+
+ul.tree li
+{margin: 0; padding: 0 0px;
+ line-height: 18px;
+ background: url(__IMAGE_PATH__/tree_none.gif) no-repeat;
+ xcolor: #369;
+ font-weight: normal;
+ white-space:nowrap;
+}
+
+ul.tree li.last,
+ul.tree li:last-child
+{
+ background: url(__IMAGE_PATH__/tree_none_end.gif) no-repeat;
+}
+
+div.tree.open
+{
+ background: url(__IMAGE_PATH__/tree_minus.png) no-repeat;
+}
+div.tree.closed
+{
+ background: url(__IMAGE_PATH__/tree_plus.png) no-repeat;
+}
+
+
+body > div
+{
+ display:none;
+}
+
+
+/* Strukturen
+div.structure ul
+{
+ padding-left:10px;
+ margin-left:10px;
+}
+*/
+
+div.structure em
+{
+ font-style: italic;
+}
+
+
+
+
+/* T a b s */
+
+.drophover
+{
+ border:2px dotted green;
+ cursor: move;
+}
+.dropactive
+{
+ border:1px dotted blue;
+ cursor: move;
+}
+
+div.panel > div.header > div.panel-icon
+{
+ xposition: static;
+ xright:-30px;
+ top:3px;
+}
+
+div.backward_link
+{
+ float:left;
+}
+div.forward_link
+{
+ float:right;
+}
+
+div.panel > div.header
+{
+ padding:0px;
+ width:100%;
+ height:25px;
+ border-bottom: 1px solid __title_background_color__;
+}
+
+
+div.panel div.header ul.views
+{
+ text-align: left; /* set to left, right or center */
+ list-style-type: none;
+ overflow: hidden; /* Gescrollt wird hier mit JavaScript */
+ white-space:nowrap;
+}
+
+img.icon
+{
+ padding:4px;
+ width: 16px;
+ height: 16px;
+}
+
+
+ul.views div.tabname
+{
+ overflow: hidden;
+ white-space: nowrap;
+ padding:4px;
+ vertical-align: middle;
+}
+ul.views > li > img,
+ul.views > li > div
+{
+ float:left;
+}
+
+div.panel div.header div.panel-icon,
+div.inputholder > div.icon
+{
+ float: right;
+}
+
+
+div.panel div.header > ul.views
+{
+ float:left;
+ height: 25px;
+}
+
+div.panel div.header
+{
+ xborder-bottom: 1px solid __title_background_color__;
+}
+
+
+div.content
+{
+ clear: both;
+}
+
+div.panel ul.views li
+{
+ vertical-align: middle;
+ padding:0px;
+
+ cursor:pointer;
+
+ border-right: 1px solid __title_background_color__;
+
+ -moz-border-radius-topleft:5px; /* Mozilla */
+ -webkit-border-radius-topleft:5px; /* Webkit */
+ -khtml-border-top-radius-topleft:5px; /* Konqui */
+ border-top-right-radius:5px;
+ -moz-border-radius-topright:5px; /* Mozilla */
+ -webkit-border-radius-topright:5px; /* Webkit */
+ -khtml-border-top-radius-topright:5px; /* Konqui */
+ border-top-right-radius:5px;
+
+ xborder-top:1px solid __title_background_color__;
+ xborder-left:1px solid __title_background_color__;
+ xborder-right:1px solid __title_background_color__;
+ xmargin-right:10px;
+ display: inline;
+ white-space:nowrap;
+ float:left;
+}
+
+
+
+
+
+
+/*
+
+div#workbench div.frame {
+ padding:3px;
+ border:1px solid __title_background_color__;
+
+ -moz-border-radius:3px;
+ -webkit-border-radius:3px;
+ -khtml-border-radius:3px;
+ border-radius:3px;
+}
+*/
+
+
+
+/*
+div.panel {
+ padding:3px;
+ border:1px solid __title_background_color__;
+
+ -moz-border-radius:5px;
+ -webkit-border-radius:5px;
+ -khtml-border-radius:5px;
+ border-radius:5px;
+}
+*/
+
+
+
+div.panel {
+ margin:0px;
+ padding:0px;
+}
+
+div.panel div.content table
+{
+ overflow:auto;
+ border:2px __inactive_background_color__;
+}
+
+
+table tr.headline > td {
+
+ /*
+ background-color: __inactive_background_color__;
+ background: -moz-linear-gradient(top, __title_background_color__, __inactive_background_color__);
+ background: -webkit-gradient(linear, left top, left bottom, from(__title_background_color__), to(__inactive_background_color__));
+
+ border-right:1px solid __inactive_background_color__;
+
+ */
+ border-bottom:1px solid __title_background_color__;
+ padding:3px;
+ font-weight: bold;
+}
+
+
+table tr.data > td {
+ border-bottom:1px solid __title_background_color__;
+ /*
+ border-right:1px solid __inactive_background_color__;
+ */
+ padding:3px;
+}
+
+
+
+/* F a r b e n */
+
+/* Ungerade Tabellenzeilen (funktioniert nicht im FF) */
+table > tr.data:nth-child(2n) {
+ background-color: __inactive_background_color__;
+}
+
+/* Datenzeile - Mauseffekt */
+table tr.data:hover,
+div.content li div.entry:hover
+{
+ background-color:__inactive_background_color__;;
+}
+
+ul.tree div
+{
+cursor:pointer;
+}
+
+
+/* Hintergrund Fenster */
+/*
+
+div.panel {
+ background-color: #3399FF;
+}
+*/
+
+
+
+
+/* S t a t u s z e i l e */
+div.panel div.status
+{
+ padding:10px;
+}
+
+
+div.panel div.status div.error,
+div.message.error
+{
+ background: url(__IMAGE_PATH__/notice_error.png) no-repeat;
+ background-position:5px 7px;
+}
+div.panel div.status div.warn,
+div.message.warn
+{
+ background: url(__IMAGE_PATH__/notice_warning.png) no-repeat;
+ background-position:5px 7px;
+}
+div.panel div.status div.ok,
+div.message.ok
+{
+ background: url(__IMAGE_PATH__/notice_ok.png) no-repeat;
+ background-position:5px 7px;
+}
+div.panel div.status div.info,
+div.message.info
+{
+ background: url(__IMAGE_PATH__/notice_info.png) no-repeat;
+ background-position:5px 7px;
+}
+
+div.panel div.status div,
+div.message
+{
+ border:1px solid __title_background_color__;
+ padding:5px 0px 5px 25px;
+ margin:10px 10px 20px 10px;
+
+ -moz-border-radius:5px;
+ -webkit-border-radius:5px;
+ -khtml-border-radius:5px;
+ border-radius:5px;
+}
+
+/* Fortschrittsbalken */
+div.loader,
+div.progress
+{
+ background: url(__IMAGE_PATH__/loader.gif) no-repeat;
+ background-position: center;
+ opacity: 0.5;
+ cursor: wait;
+ min-height:50px;
+}
+
+
+
+/* V o l l b i l d */
+div#workbench div.panel.fullscreen
+{
+ display:block;
+ z-index:109;
+
+ /*set the div in the top-left corner of the screen*/
+ position:fixed;
+ top:0;
+ left:0;
+ background-color:__background_color__;
+ margin:0px;
+
+ /*set the width and height to 100% of the screen*/
+ width:100% !important;
+ height:100% !important;
+}
+div#workbench div.panel.fullscreen > div.content
+{
+ width:100% !important;
+ height:100% !important;
+}
+
+.invisible
+{
+ visibility:hidden;
+}
+.visible
+{
+ visibility:visible;
+}
+
+
+div#workbench
+{
+ width:100%;
+}
+
+body
+{
+ overflow:hidden;
+}
+
+div#workbench div.panel
+{
+ border:1px solid __title_background_color__;
+ margin:0px;
+ padding:0px;
+ -moz-border-radius:5px;
+ -webkit-border-radius:5px;
+ -khtml-border-radius:5px;
+ border-radius:5px;
+}
+
+div#workbench div.container,
+div#workbench div.panel,
+div#workbench div.divider
+{
+ display: inline;
+ float: left;
+ margin: 0px;
+}
+
+div#workbench
+{
+ padding:3px;
+}
+
+
+div#workbench div.panel > div.content
+{
+ overflow:auto;
+}
+
+
+/*
+ * Formular-Button-Leiste
+ */
+div.panel {
+ position:relative;
+}
+div.content div.bottom
+{
+ xbackground-color: __background_color__;
+ height:55px;
+ width:100%;
+ position:absolute;
+ padding-right:40px;
+ bottom:0px;
+ right:0px;
+ xvisibility:hidden;
+}
+
+div.content div.bottom > div.command
+{
+ xvisibility:visible;
+ float:right;
+ z-index:20;
+}
+div.content form[data-autosave='true'] div.command
+{
+ display: none;
+}
+
+div.content > form
+{
+ padding-bottom:45px;
+}
+
+input.submit
+{
+ background-color: __title_background_color__;
+ color: __title_text_color__;
+ padding: 7px;
+ border:0px;
+ -moz-border-radius:7px; /* Mozilla */
+ -webkit-border-radius:7px; /* Webkit */
+ -khtml-border-radius:7px; /* Konqui */
+ border-radius:7px;
+ margin-left:20px;
+ -webkit-box-shadow: 0px 0px 15px __background_color__;
+ -moz-box-shadow: 0px 0px 15px __background_color__;
+ box-shadow: 0px 0px 15px 10px __background_color__;
+ cursor:pointer;
+}
+
+
+input.submit.ok
+{
+ font-weight:bold; /* Primäre Aktion in Fettdruck */
+}
+
+
+/* Pfeile nur anzeigen, wenn Maus über der Titelleiste */
+div.views > div.backward_link,
+div.views > div.forward_link
+{
+ visibility: hidden;
+}
+div.views:HOVER > div.backward_link,
+div.views:HOVER > div.forward_link
+{
+ visibility: visible;
+}
+
+
+div#shortcuts {
+ height:24px;
+ margin-left:10px;
+}
+div#shortcuts > div.shortcut {
+ width:24px;
+ height:24px;
+ margin-left:5px;
+ float:left;
+ opacity:0.8;
+}
+
+div#shortcuts > div.shortcut:HOVER {
+
+ xborder: 1px solid __title_background_color__;
+ x-moz-border-radius:2px; /* Mozilla */
+ x-webkit-border-radius:2px; /* Webkit */
+ x-khtml-border-radius:2px; /* Konqui */
+ opacity:1.0;
+ position:relative;
+ bottom:3px;
+
+}
+
+
+
+
+/* Smaller screens */
+
+@media only screen and (max-width: 1023px) {
+
+ body {
+ font-size: 0.8em;
+ line-height: 1.5em;
+ }
+
+ }
+
+
+/* Mobile */
+
+@media handheld, only screen and (max-width: 767px) {
+
+ body {
+ font-size: 16px;
+ -webkit-text-size-adjust: none;
+ overflow: visible;
+ }
+ div#header,
+ div#workbench {
+ width: 100%;
+ height: auto;
+ min-width: 0;
+ margin-left: 0px;
+ margin-right: 0px;
+ padding-left: 0px;
+ padding-right: 0px;
+ }
+
+ div#workbench div.panel
+ {
+ width:auto !important;
+ }
+
+ li.action div.tabname
+ {
+ width:auto !import;ant;
+ }
+
+ div#workbench div.panel
+ {
+ width: auto;
+ float: none;
+ margin-left: 0px;
+ margin-right: 0px;
+ padding-left: 20px;
+ padding-right: 20px;
+ }
+ div#workbench div.panel > div.content
+ {
+ overflow:auto;
+ height: auto !important;
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+body > div#header {
+ display:block;
+}
+
+ul#history > li {
+
+ xdisplay:inline;
+ margin:5px;
+ padding:5px;
+ border:1px solid __title_background_color__;
+ background-color: __inactive_background_color__;
+ color:__text_color__;
+}
+ul#history > li.active {
+
+ xdisplay:inline;
+ margin:5px;
+ padding:5px;
+ border:1px solid __text_color__;
+ background-color: __title_text_color__;
+ color:__text_color__;
+}
+
+ul#history {
+ display:none;
+}
+
+
+table td.readonly {
+ font-style: italic;
+ font-weight: normal;
+}
+table td.default {
+ font-style: normal;
+ font-weight: normal;
+}
+table td.changed {
+ font-style: normal;
+ font-weight: bold;
+}
+
+
+/* Modale Dialoge */
+
+div#filler
+{
+ xxxxdisplay: block;
+ position:absolute;
+ z-index: 100;
+ top: 0;
+ left: 0;
+ height:100%;
+ width:100%;
+ background-color: __text_color__;
+ opacity: 0.5;
+}
+
+
+div.clickable.filtered.inactive > a
+{
+ color: __inactive_background_color__;
+}
+
+/* Pfeile */
+div#header > div > div.arrow-down
+{
+ display: inline;
+ width:0;
+ height:0;
+ margin:6;
+ padding:0px;
+ border-right : 6px solid __title_background_color__;
+ border-left : 6px solid __title_background_color__;
+ border-top : 6px solid __inactive_background_color__;
+ border-bottom: 4px solid __title_background_color__;
+ margin-top: 10px;
+font-size: 0;
+}
+
+
+
+/* D r o p d o w n - M e n u e s */
+div.dropdown
+{
+ /* Schatten */
+ -webkit-box-shadow: 3px 2px 10px __title_background_color__;
+ -moz-box-shadow: 3px 2px 10px __title_background_color__;
+ box-shadow: 3px 2px 10px __title_background_color__;
+
+ opacity:0.95;
+
+ border:2px solid __title_background_color__;
+ -moz-border-radius:5px; /* Mozilla */
+ -webkit-border-radius:5px; /* Webkit */
+ -khtml-border-radius:5px; /* Konqui */
+ border-radius:5px;
+
+ /*
+ background: -moz-linear-gradient(top, __title_background_color__, __inactive_background_color__);
+ background: -webkit-gradient(linear, left top, left bottom, from(__title_background_color__), to(__inactive_background_color__));
+ */
+ font-style:normal;
+ font-weight:normal;
+ text-decoration:none;
+}
+
+
+div#header span.titletext
+{
+ color:__title_text_color__;
+}
+
+
+div.toolbar-icon
+{
+ border:1px solid __title_background_color__;
+ padding:2px;
+ margin-left:5px;
+ float: left;
+
+ -moz-border-radius:3px;
+ -webkit-border-radius:3px;
+ -khtml-border-radius:3px;
+ border-radius:3px;
+}
+div.toolbar-icon.inactive
+{
+ opacity:0.5;
+}
+
+div.toolbar-icon:hover
+{
+ border:1px solid __inactive_background_color__;
+ xxbackground-color: __inactive_background_color__;
+}
+
+
+div.headermenu
+{
+ margin:5px;
+ z-index: 1;
+ position: relative;
+ right: 0;
+ top: 0;
+}
+div.headermenu > div.toolbar-icon
+{
+ float:right;
+}
+
+
+ /* Voreingestellte Schriftart */
+body
+{
+
+}
+
+
+
+/* Formulare breit */
+div.panel.wide form div.line
+{
+ clear:left;
+ margin-top:10px;
+}
+
+div.panel.wide form div.label
+{
+ display:inline-block;
+ width:30%;
+ vertical-align:top;
+ text-align: right;
+}
+
+div.panel.wide form div.input
+{
+ display:inline-block;
+ width:60%;
+ vertical-align:top;
+ text-align: left;
+}
+
+/* Formulare schmal */
+div.panel.small form div.line
+{
+ clear:left;
+ padding:10px;
+}
+
+div.panel.small form div.label
+{
+ display:block;
+ width:100%;
+ vertical-align:top;
+ text-align: left;
+}
+
+div.panel.small form div.input
+{
+ display:block;
+ width:100%;
+ vertical-align:top;
+ text-align: left;
+}
+
+
+
+form div.label > label,
+form div.input > div.intputholder
+{
+ padding:0px 5px;
+}
+
+form div.input input[type=text],
+form div.input input[type=password],
+form div.input textarea,
+form div.input select
+{
+ width:100%;
+}
+form div.input input[type=checkbox],
+form div.input input[type=radio]
+{
+ vertical-align:top;
+}
+
+label
+{
+ display:inline-block;
+}
+
+input[type=checkbox] + label,
+input[type=radio] + label
+{
+ width:80%;
+}
+
+label div.description
+{
+ font-size: 0.75em;
+ color:__title_background_color__;
+}
+
+
+div.inputholder
+{
+ background-color:__title_text_color__;
+ border:1px solid __title_background_color__;
+ margin:0px;
+ padding:4px;
+ -moz-border-radius:3px;
+ -webkit-border-radius:3px;
+ -khtml-border-radius:3px;
+ border-radius:3px;
+
+ -webkit-box-shadow:inset 0px 0px 3px __title_background_color__;
+ -moz-box-shadow:inset 0px 0px 3px __title_background_color__;
+ box-shadow:inset 0px 0px 3px __title_background_color__;
+
+}
+
+
+div.inputholder ul.tree,
+div.inputholder ul.tree li.last,
+div.inputholder ul.tree li:last-child
+{
+ background-color:__title_text_color__;
+}
+
+div.inputholder > div.dropdown
+{
+ width:70%;
+}
+
+div.search > div.inputholder
+{
+ padding-top:1px;
+}
+
+div.inputholder > input,
+div.inputholder > textarea,
+div.inputholder > select
+{
+ border:0px;
+ border-bottom:1px solid __title_text_color__;
+ padding:2px;
+ margin:0px;
+ background-color:__title_text_color__;
+}
+
+input:focus,
+textarea:focus,
+select:focus
+{
+ border:0px;
+ border-bottom:1px solid __inactive_background_color__;
+}
+
+
+input.error,
+textarea.error,
+select.error
+{
+ border-bottom:1px dotted __text_color__ !important;
+}
+
+div.inputholder.error
+{
+ border:1px solid red !important;
+}
+
+input.hint
+{
+ color:__title_background_color__;
+}
+
+
+
+
+/* Eingabfeld fuer Namen */
+fieldset > div input.name,
+fieldset > div span.name
+{
+ font-weight:bold;
+}
+
+
+fieldset
+{
+ border-color:__title_background_color__;
+}
+
+/* Eingabfelder fuer Dateiname */
+fieldset > div input.filename,
+fieldset > div input.extension,
+fieldset > div input.ansidate,
+fieldset > div span.filename,
+fieldset > div span.extension,
+fieldset > div span.ansidate
+{
+ font-family:Courier;
+ font-size:1em;
+}
+
+
+div#tree
+{
+ overflow:visible;
+}
+
+
+
+
+
+/* Anzeige von Text-Unterschieden */
+
+/* Zeilen-Nr */
+tr.diff > td.line
+{
+ background-color:__title_text_color__;
+ padding-right:2px;
+ border-right:3px solid __title_background_color__;
+ text-align:right;
+ margin-right:2px;
+}
+
+/* Unveränderter Text */
+tr.diff > td.equal
+{
+}
+
+/* Entfernter Text */
+tr.diff > td.old
+{
+ background-color:red;
+}
+
+/* Hinzugefuegter Text */
+tr.diff > td.new
+{
+ background-color:green;
+}
+
+/* Geaenderter Text */
+tr.diff > td.notequal
+{
+ background-color:yellow;
+}
+
+dl.notice
+{
+ border-left:10px __inactive_background_color__ solid;
+ border-right:1px __inactive_background_color__ solid;
+ padding:15px;
+}
+
+dl.notice > dt
+{
+ border-top: 1px __inactive_background_color__ solid;
+}
+dl.notice > dd
+{
+ border-bottom: 1px __inactive_background_color__ solid;
+}
+
+
+/* S c h a t t e n */
+div.content a.action,
+div.content a.help
+{
+ -webkit-box-shadow: 3px 2px 5px __title_background_color__;
+ -moz-box-shadow: 3px 2px 5px __title_background_color__;
+ box-shadow: 3px 2px 5px __title_background_color__;
+}
+
+
+
+/* F a r b e n */
+
+/* Gesamt-Hintergrund */
+body
+{
+ xxxbackground-color:#c9c9c9;
+ background-color:__inactive_background_color__;
+}
+
+/* Fenster-Hintergrund */
+div.panel ul.views > li.active,
+div.panel ul.views > li.active:hover
+{
+ background-color: __title_background_color__;
+ background-image: linear-gradient(__inactive_background_color__ 0%, __title_background_color__ 15%);
+ color: __title_text_color__;
+}
+
+/* Titelleiste-Hintergrund */
+div#header
+{
+ background-color: __title_background_color__;
+ background-image: linear-gradient(__title_background_color__ 85%, __inactive_background_color__ 100%);
+ color: __title_text_color__;
+}
+
+/* Titelleiste */
+div#header div.toolbar-icon > a
+{
+ color: __title_text_color__;
+}
+
+div#header, /* Titelleite */
+ul.views > li.action /* Tabreiter */
+{
+ font-family: Arial, sans-serif;
+ font-size:13px;
+}
+
+div.content
+{
+ font-family: Trebuchet MS, Helvetica, Arial, sans-serif;
+ font-size:13px;
+}
+
+
+/* Reiter */
+div.panel ul.views li
+{
+ /*
+ background-color:__background_color__;
+ */
+}
+
+
+div.panel > div.content
+{
+ background-color:__background_color__;
+}
+
+div.panel > div.header
+{
+ background-color:__background_color__;
+ background-image: linear-gradient(__inactive_background_color__ 00%, __background_color__ 85%);
+}
+
+
+
+
+div.panel ul.views li:hover {
+ background-color: __inactive_background_color__;
+ /*
+ color: blue;
+ */
+}
+
+
+
+ul.tree li.last,
+ul.tree li:last-child
+{
+ background-color:__background_color__;
+}
+
+
+
+div.content pre,
+div.dropdown
+{
+ background-color:__title_text_color__;
+ color:__text_color__;
+ min-width: 150px;
+ max-width: 450px;
+}
+
+
+
+
+
+div.filler div.headermenu > a.entry,
+div.filler div.header a.back.button
+{
+ font-size: 0.8em;
+}
diff --git a/themes/default/css/openrat-ui.css.php b/themes/default/css/openrat-ui.css.php
@@ -1,1766 +0,0 @@
-<?php header('Content-Type: text/css',true) ?>
-/*
-OpenRat Content Management System
-Copyright (C) 2002-2010 Jan Dankert
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-
-
-iframe
-{
- width:100%;
- height:500px;
- display:block;
- border: 1px solid <?php echo $_GET['title_background_color']; ?>;
-}
-
-div.breadcrumb,
-div.breadcrumb a,
-div.panel > div.title
-{
- x-background-color:<?php echo $_GET['title_background_color']; ?>;
- xsopacity:0.7;
- color:<?php echo $_GET['title_text_color']; ?>;
- font-weight:bold;
-}
-
-/* H e a d e r */
-div#header
-{
- width:100%;
- height:27px;
- overflow:hidden;
- padding:5px;
- margin:0px;
- margin-bottom:3px;
- float:left;
-}
-
-div#header div.projects,
-div#header div.menu,
-div#header div.title
-{
- float:left;
- margin-right:10px;
- margin-left :0px;
-}
-
-div#header div.user,
-div#header div.search,
-div#header div.history
-{
- float:right;
- margin-right:10px;
- margin-left :10px;
-}
-
-/*
-
-div#tree
-{
- padding:5px;
- width:25%;
- margin-left:0px;
- float:left;
-}
-*/
-
-
-/* N o t i c e */
-div#noticebar
-{
- display:block;
- position:fixed;
- bottom:40px;
- right:40px;
- width:250px;
- z-index:113;
-}
-
-div#noticebar div.notice
-{
- border: 2px solid <?php echo $_GET['text_color']; ?>;
-
- padding:5px;
- margin:5px;
-
- -moz-border-radius:5px; /* Mozilla */
- -webkit-border-radius:5px; /* Webkit */
- -khtml-border-radius:5px; /* Konqui */
- border-radius:5px; /* CSS 3 */
-
- -webkit-box-shadow: 3px 2px 5px <?php echo $_GET['text_color']; ?>;
- -moz-box-shadow: 3px 2px 5px <?php echo $_GET['text_color']; ?>;
- box-shadow: 3px 2px 5px <?php echo $_GET['text_color']; ?>;
-
- display:none;
-}
-div#noticebar div.notice.ok
-{
- background-color: green;
-}
-div#noticebar div.notice.warning
-{
- background-color: yellow;
-}
-div#noticebar div.notice.error
-{
- background-color:red;
-}
-div#noticebar div.notice.info
-{
- background-color:<?php echo $_GET['inactive_background_color']; ?>;
-}
-div#noticebar div.notice.error div.text
-{
- font-weight: bold;
-}
-div#noticebar div.log
-{
- font-family: monospace;
-}
-
-/* H o e h e n */
-html,body
-{
- height:100%;
-}
-
-
-/*
-
-div#tree, div#content
-{
- height:auto;
-}
-*/
-
-/*div.panel {
- height:90%;
-}
-*/
-
-div.panel div.title
-{
- height:20px;
-}
-
-
-
-div.panel div.status
-{
- height:35px;
-}
-div.panel > div.content
-{
- xxoverflow-x:auto;
-}
-
-
-ul#history > li,
-div.content a.action,
-div.content a.help,
-div.filler div.headermenu > a.entry,
-div.filler div.header a.back.button
-{
- margin:9px;
- padding-top:4px;
- padding-bottom:4px;
- padding-left:7px;
- padding-right:7px;
- border:1px solid <?php echo $_GET['title_background_color']; ?>;
- -moz-border-radius:5px; /* Mozilla */
- -webkit-border-radius:5px; /* Webkit */
- -khtml-border-radius:5px; /* Konqui */
- border-radius:5px;
- background-color: <?php echo $_GET['title_text_color']; ?>;
- background: -moz-linear-gradient(top, <?php echo $_GET['title_background_color']; ?>, <?php echo $_GET['inactive_background_color']; ?>);
- background: -webkit-gradient(linear, left top, left bottom, from(<?php echo $_GET['title_background_color']; ?>), to(<?php echo $_GET['inactive_background_color']; ?>));
- font-style:normal;
- font-weight:normal;
- text-decoration:none;
- color:<?php echo $_GET['text_color']; ?>;
-}
-
-ul#history > li.active
-{
- background-color: <?php echo $_GET['title_text_color']; ?>;
- font-weight:bold;
- color:<?php echo $_GET['text_color']; ?>;
-}
-
-
-a.help
-{
- float:right;
-}
-
-a.help
-{
- cursor:help;
-}
-
-a.action:hover,
-a.help:hover,
-div.noaction:hover
-{
- text-decoration:none;
- border-color:<?php echo $_GET['title_text_color']; ?>;
-}
-
-a.action:active,
-a.help:active,
-div.noaction:active,
-input.ok:active
-{
- border-color:red;
-}
-
-
-a
-{
- color:<?php echo $_GET['text_color']; ?>;
-}
-
-
-
-/* D r o p d o w n - M e n u e s */
-div.dropdown
-{
- z-index:2;
- display:none;
- position: absolute;
- padding:5px 0px;
-}
-
-div.dropdownalignright
-{
- right:0;
-}
-
-div.dropdown > a
-{
- display:block;
-}
-div.dropdown div.entry
-{
- padding:2px 5px;
-}
-
-div.dropdown > div.divide
-{
- height:1px;
- background-color: <?php echo $_GET['title_background_color']; ?>;
- width:100%;
- margin-top: 5px;
- margin-bottom: 5px;
-}
-
-div#header > div.menu {
- overflow: hidden;
-}
-/*Dropdown anzeigen!!!*/
-div#header div:hover div.dropdown,
-div.panel div:hover > div.dropdown,
-div.panel-icon:hover > div.dropdown
-{
- display:block;
-}
-
-
-
-div.onrowvisible
-{
- visibility: hidden;
- display:inline;
-}
-td:hover > div.onrowvisible
-{
- visibility: visible;
-}
-
-
-
-/* Vorschau von Text-Inhalten */
-
-td.preview { background-color:papayawhip; border-top:1px solid <?php echo $_GET['inactive_background_color']; ?>; border-bottom:1px solid <?php echo $_GET['inactive_background_color']; ?>; }
-.preview h1 { font-size:138.5%; }
-.preview h2 { font-size:123.1%; }
-.preview h3 { font-size:108%; }
-.preview h1,.preview h2,.preview h3 {
- margin:1em 0;
-}
-.preview h1,
-.preview h2,
-.preview h3,
-.preview h4,
-.preview h5,
-.preview h6,
-.preview strong
-{
- font-weight:bold;
-}
-.preview abbr,.preview acronym {
- border-bottom:1px dotted #000;
- cursor:help;
-}
-.preview em {
- font-style:italic;
-}
-.preview ol,.preview ul,.preview dl {
- margin-left:2em;
-}
-.preview ol li
-{
- list-style: decimal outside;
-}
-.preview ul li
-{
- list-style: disc outside;
-}
-.preview a:link,
-.preview a:visited,
-.preview a:active,
-.preview a:hover
-{
- text-decoration:underline;
- color:blue;
-}
-
-
-
-/* Verweise */
-a:link,
-a:visited
-{
- font-weight:normal;
- text-decoration:none;
-}
-a:active,
-a:hover
-{
- font-weight:normal;
- text-decoration:none;
-}
-
-
-
-/* Submenu-Entrys */
-body.menu tr.menu td table tr td,
-body.main tr.menu td table tr td
-{
- padding:4px; padding-right:6px;padding-left:6px; width:30px;
- white-space:nowrap;
-}
-
-/* Submenu-Width */
-body.menu tr.menu table { width:50px;}
-
-
-/* Inaktive Menuepunkte werden ausgegraut */
-body.menu tr.menu td table tr td.noaction,
-body.main tr.menu td table tr td.noaction
-{
- color:<?php echo $_GET['title_background_color']; ?>;
-}
-
-/* Icon-Innenabstand */
-img[align=left],
-img[align=right] {padding-right:1px;padding-left:1px;}
-
-/* Vorformatierter Text */
-pre
-{
- font-family:Courier;
- font-size:13px;
-}
-
-/* Kleingedrucktes */
-small
-{
- color:<?php echo $_GET['title_background_color']; ?>;
-}
-
-
-/* Kurztasten */
-body.menu span.accesskey,
-body.main span.accesskey
-{
- text-decoration:underline;
-}
-
-
-
-
-/* Menzue-Titel-Zeile */
-body.menu tr.title td,
-body.main tr.title td
-{
- vertical-align:middle;
- padding:4px;
- height:30px;
-}
-
-/* Hinweis */
-td.message { padding:10px; font-weight:bold; }
-
-
-/* Allgemeine Inhaltszellen */
-body.main table.main td.window td
-{
- padding:4px;
-}
-
-
-/* Action-Button */
-body.main table.main td.window td.act
-{
- padding:15px;
- margin-top:20px;
- border-top:1px solid <?php echo $_GET['title_background_color']; ?>;
- text-align:right;
-}
-
-/* Lizenzhinweis */
-a.copyright
-{
- font-size:0.7em;
- text-decoration:none;
-}
-
-/* Message of the day */
-td.motd
-{
- border-left: 3px solid red;
- border-right: 3px solid red;
- font-weight: bold;
- padding:10px;
- margin:10px;
-}
-
-/* Hauptfenster */
-table.main
-{
- x-border:3px solid;
-}
-
-
-
-div.panel input.checkbox,
-div.panel input.radio
-{
- border:1px solid <?php echo $_GET['title_background_color']; ?>;
-}
-
-/* Eingabefeld fuer Beschreibung */
-textarea.desc,
-textarea.description
-{
- font-family:Arial;
- font-size:13px;
-}
-
-/* Eingabefeld fuer Textabsatz */
-textarea.longtext
-{
- font-family:Arial;
- font-size:13px;
- width:100%;
- border:1px solid <?php echo $_GET['text_color']; ?>;
-}
-
-
-
-
-
-/* Hilfe-Texte */
-tr td.help
-{
- font-style: italic;
-}
-
-tr.headline td.help
-{
- /*
- border-bottom:1px solid <?php echo $_GET['text_color']; ?>;
- */
- font-style: normal;
-
-}
-
-/* Logo */
-td.logo
-{
- padding:10px;
- margin:0px;
-}
-
-div.logo h2
-{
- font-family:Verdana;
- font-weight:normal;
- font-size:24px;
-}
-div.logo p
-{
- font-family:Verdana;
- font-size:13px;
-}
-
-div#header div.search input
-{
- margin:0px;
- padding:0px;
-}
-
-
-
-/* Notizen */
-td.notice
-{
- margin:0px;
- padding:5%;
- text-align:center;
-}
-table.notice
-{
- width:100%;
- border:1px solid;
- border-spacing:0px;
-}
-table.notice th
-{
- padding:2px;
- white-space:nowrap;
- border-bottom:1px solid <?php echo $_GET['text_color']; ?>;
- font-weight:normal;
- text-align:left;
-}
-
-table.notice tr.error
-{
-}
-
-table.notice tr.warning
-{
- margin:0px;
- padding:0px;
-}
-
-
-
-/* Kalender */
-table.calendar
-{
- table-layout:fixed;
- border-collapse:collapse;
- text-align: center;
-}
-table.calendar td
-{
- border: 1px dotted;
-}
-
-
-label,
-.clickable
-{
- cursor: pointer;
-}
-
-body {
- cursor:default;
-}
-
-input {
- xcursor:text;
-}
-
-
-div.menu
-{
- float:none;
- xclear:left;
-}
-
-
-
-form.xlogin
-{
- xbackground-color:#E0E0D5;
- border:2px solid <?php echo $_GET['inactive_background_color']; ?>;
- position:absolute;
- z-index:999;
- top:5%;
- left:5%;
- width:80%;
- margin:5%;
- padding:10%;
- opacity:1;
-
- -webkit-box-shadow: 3px 2px 5px <?php echo $_GET['title_background_color']; ?>;
- -moz-box-shadow: 3px 2px 5px <?php echo $_GET['title_background_color']; ?>;
- box-shadow: 3px 2px 5px <?php echo $_GET['title_background_color']; ?>;
-}
-
-
-
-
-
-
-
-/* B a u m */
-ul.tree,
-ul.tree ul
-{
- list-style-type: none;
- background: url(../images/tree_line.gif) repeat-y;
- margin: 0; padding: 0;
-}
-
-ul.tree ul
-{
- margin-left:18px;
-}
-
-div.entry.selected,
-div.dropdown > div.entry:hover,
-div.dropdown > div.entry:hover > a,
-a.element
-{
- background-color:<?php echo $_GET['title_background_color']; ?>;
- color:<?php echo $_GET['title_text_color']; ?>;
-}
-
-
-
-ul.tree div.tree
-{
- width:18px;
- min-width:18px;
- height:18px;
- xbackground-color:red;
- float:left;
-}
-ul.tree div.tree,
-ul.tree div.entry
-{
- height:18px;
- max-height:18px;
- min-height:18px;
-}
-
-ul.tree div img
-{
- cfloat:left;
-}
-
-ul.tree li
-{margin: 0; padding: 0 0px;
- line-height: 18px;
- background: url(../images/tree_none.gif) no-repeat;
- xcolor: #369;
- font-weight: normal;
- white-space:nowrap;
-}
-
-ul.tree li.last,
-ul.tree li:last-child
-{
- background: url(../images/tree_none_end.gif) no-repeat;
-}
-
-div.tree.open
-{
- background: url(../images/tree_minus.png) no-repeat;
-}
-div.tree.closed
-{
- background: url(../images/tree_plus.png) no-repeat;
-}
-
-
-body > div
-{
- display:none;
-}
-
-
-/* Strukturen
-div.structure ul
-{
- padding-left:10px;
- margin-left:10px;
-}
-*/
-
-div.structure em
-{
- font-style: italic;
-}
-
-
-
-
-/* T a b s */
-
-.drophover
-{
- border:2px dotted green;
- cursor: move;
-}
-.dropactive
-{
- border:1px dotted blue;
- cursor: move;
-}
-
-div.panel > div.header > div.panel-icon
-{
- xposition: static;
- xright:-30px;
- top:3px;
-}
-
-div.backward_link
-{
- float:left;
-}
-div.forward_link
-{
- float:right;
-}
-
-div.panel > div.header
-{
- padding:0px;
- width:100%;
- height:25px;
- border-bottom: 1px solid <?php echo $_GET['title_background_color'] ?>;
-}
-
-
-div.panel div.header ul.views
-{
- text-align: left; /* set to left, right or center */
- list-style-type: none;
- overflow: hidden; /* Gescrollt wird hier mit JavaScript */
- white-space:nowrap;
-}
-
-img.icon
-{
- padding:4px;
- width: 16px;
- height: 16px;
-}
-
-
-ul.views div.tabname
-{
- overflow: hidden;
- white-space: nowrap;
- padding:4px;
- vertical-align: middle;
-}
-ul.views > li > img,
-ul.views > li > div
-{
- float:left;
-}
-
-div.panel div.header div.panel-icon,
-div.inputholder > div.icon
-{
- float: right;
-}
-
-
-div.panel div.header > ul.views
-{
- float:left;
- height: 25px;
-}
-
-div.panel div.header
-{
- xborder-bottom: 1px solid <?php echo $_GET['title_background_color']; ?>;
-}
-
-
-div.content
-{
- clear: both;
-}
-
-div.panel ul.views li
-{
- vertical-align: middle;
- padding:0px;
-
- cursor:pointer;
-
- border-right: 1px solid <?php echo $_GET['title_background_color']; ?>;
-
- -moz-border-radius-topleft:5px; /* Mozilla */
- -webkit-border-radius-topleft:5px; /* Webkit */
- -khtml-border-top-radius-topleft:5px; /* Konqui */
- border-top-right-radius:5px;
- -moz-border-radius-topright:5px; /* Mozilla */
- -webkit-border-radius-topright:5px; /* Webkit */
- -khtml-border-top-radius-topright:5px; /* Konqui */
- border-top-right-radius:5px;
-
- xborder-top:1px solid <?php echo $_GET['title_background_color']; ?>;
- xborder-left:1px solid <?php echo $_GET['title_background_color']; ?>;
- xborder-right:1px solid <?php echo $_GET['title_background_color']; ?>;
- xmargin-right:10px;
- display: inline;
- white-space:nowrap;
- float:left;
-}
-
-
-
-
-
-
-/*
-
-div#workbench div.frame {
- padding:3px;
- border:1px solid <?php echo $_GET['title_background_color']; ?>;
-
- -moz-border-radius:3px;
- -webkit-border-radius:3px;
- -khtml-border-radius:3px;
- border-radius:3px;
-}
-*/
-
-
-
-/*
-div.panel {
- padding:3px;
- border:1px solid <?php echo $_GET['title_background_color']; ?>;
-
- -moz-border-radius:5px;
- -webkit-border-radius:5px;
- -khtml-border-radius:5px;
- border-radius:5px;
-}
-*/
-
-
-
-div.panel {
- margin:0px;
- padding:0px;
-}
-
-div.panel div.content table
-{
- overflow:auto;
- border:2px <?php echo $_GET['inactive_background_color']; ?>;
-}
-
-
-table tr.headline > td {
-
- /*
- background-color: <?php echo $_GET['inactive_background_color']; ?>;
- background: -moz-linear-gradient(top, <?php echo $_GET['title_background_color']; ?>, <?php echo $_GET['inactive_background_color']; ?>);
- background: -webkit-gradient(linear, left top, left bottom, from(<?php echo $_GET['title_background_color']; ?>), to(<?php echo $_GET['inactive_background_color']; ?>));
-
- border-right:1px solid <?php echo $_GET['inactive_background_color']; ?>;
-
- */
- border-bottom:1px solid <?php echo $_GET['title_background_color']; ?>;
- padding:3px;
- font-weight: bold;
-}
-
-
-table tr.data > td {
- border-bottom:1px solid <?php echo $_GET['title_background_color']; ?>;
- /*
- border-right:1px solid <?php echo $_GET['inactive_background_color']; ?>;
- */
- padding:3px;
-}
-
-
-
-/* F a r b e n */
-
-/* Ungerade Tabellenzeilen (funktioniert nicht im FF) */
-table > tr.data:nth-child(2n) {
- background-color: <?php echo $_GET['inactive_background_color']; ?>;
-}
-
-/* Datenzeile - Mauseffekt */
-table tr.data:hover,
-div.content li div.entry:hover
-{
- background-color:<?php echo $_GET['inactive_background_color']; ?>;;
-}
-
-ul.tree div
-{
-cursor:pointer;
-}
-
-
-/* Hintergrund Fenster */
-/*
-
-div.panel {
- background-color: #3399FF;
-}
-*/
-
-
-
-
-/* S t a t u s z e i l e */
-div.panel div.status
-{
- padding:10px;
-}
-
-
-div.panel div.status div.error,
-div.message.error
-{
- background: url(../images/notice_error.png) no-repeat;
- background-position:5px 7px;
-}
-div.panel div.status div.warn,
-div.message.warn
-{
- background: url(../images/notice_warning.png) no-repeat;
- background-position:5px 7px;
-}
-div.panel div.status div.ok,
-div.message.ok
-{
- background: url(../images/notice_ok.png) no-repeat;
- background-position:5px 7px;
-}
-div.panel div.status div.info,
-div.message.info
-{
- background: url(../images/notice_info.png) no-repeat;
- background-position:5px 7px;
-}
-
-div.panel div.status div,
-div.message
-{
- border:1px solid <?php echo $_GET['title_background_color']; ?>;
- padding:5px 0px 5px 25px;
- margin:10px 10px 20px 10px;
-
- -moz-border-radius:5px;
- -webkit-border-radius:5px;
- -khtml-border-radius:5px;
- border-radius:5px;
-}
-
-/* Fortschrittsbalken */
-div.loader,
-div.progress
-{
- background: url(../images/loader.gif) no-repeat;
- background-position: center;
- opacity: 0.5;
- cursor: wait;
- min-height:50px;
-}
-
-
-
-/* V o l l b i l d */
-div#workbench div.panel.fullscreen
-{
- display:block;
- z-index:109;
-
- /*set the div in the top-left corner of the screen*/
- position:fixed;
- top:0;
- left:0;
- background-color:<?php echo $_GET['background_color']; ?>;
- margin:0px;
-
- /*set the width and height to 100% of the screen*/
- width:100% !important;
- height:100% !important;
-}
-div#workbench div.panel.fullscreen > div.content
-{
- width:100% !important;
- height:100% !important;
-}
-
-.invisible
-{
- visibility:hidden;
-}
-.visible
-{
- visibility:visible;
-}
-
-
-div#workbench
-{
- width:100%;
-}
-
-body
-{
- overflow:hidden;
-}
-
-div#workbench div.panel
-{
- border:1px solid <?php echo $_GET['title_background_color']; ?>;
- margin:0px;
- padding:0px;
- -moz-border-radius:5px;
- -webkit-border-radius:5px;
- -khtml-border-radius:5px;
- border-radius:5px;
-}
-
-div#workbench div.container,
-div#workbench div.panel,
-div#workbench div.divider
-{
- display: inline;
- float: left;
- margin: 0px;
-}
-
-div#workbench
-{
- padding:3px;
-}
-
-
-div#workbench div.panel > div.content
-{
- overflow:auto;
-}
-
-
-/*
- * Formular-Button-Leiste
- */
-div.panel {
- position:relative;
-}
-div.content div.bottom
-{
- xbackground-color: <?php echo $_GET['background_color']; ?>;
- height:55px;
- width:100%;
- position:absolute;
- padding-right:40px;
- bottom:0px;
- right:0px;
- xvisibility:hidden;
-}
-
-div.content div.bottom > div.command
-{
- xvisibility:visible;
- float:right;
- z-index:20;
-}
-div.content form[data-autosave='true'] div.command
-{
- display: none;
-}
-
-div.content > form
-{
- padding-bottom:45px;
-}
-
-input.submit
-{
- background-color: <?php echo $_GET['title_background_color']; ?>;
- color: <?php echo $_GET['title_text_color']; ?>;
- padding: 7px;
- border:0px;
- -moz-border-radius:7px; /* Mozilla */
- -webkit-border-radius:7px; /* Webkit */
- -khtml-border-radius:7px; /* Konqui */
- border-radius:7px;
- margin-left:20px;
- -webkit-box-shadow: 0px 0px 15px <?php echo $_GET['background_color']; ?>;
- -moz-box-shadow: 0px 0px 15px <?php echo $_GET['background_color']; ?>;
- box-shadow: 0px 0px 15px 10px <?php echo $_GET['background_color']; ?>;
- cursor:pointer;
-}
-
-
-input.submit.ok
-{
- font-weight:bold; /* Primäre Aktion in Fettdruck */
-}
-
-
-/* Pfeile nur anzeigen, wenn Maus über der Titelleiste */
-div.views > div.backward_link,
-div.views > div.forward_link
-{
- visibility: hidden;
-}
-div.views:HOVER > div.backward_link,
-div.views:HOVER > div.forward_link
-{
- visibility: visible;
-}
-
-
-div#shortcuts {
- height:24px;
- margin-left:10px;
-}
-div#shortcuts > div.shortcut {
- width:24px;
- height:24px;
- margin-left:5px;
- float:left;
- opacity:0.8;
-}
-
-div#shortcuts > div.shortcut:HOVER {
-
- xborder: 1px solid <?php echo $_GET['title_background_color']; ?>;
- x-moz-border-radius:2px; /* Mozilla */
- x-webkit-border-radius:2px; /* Webkit */
- x-khtml-border-radius:2px; /* Konqui */
- opacity:1.0;
- position:relative;
- bottom:3px;
-
-}
-
-
-
-
-/* Smaller screens */
-
-@media only screen and (max-width: 1023px) {
-
- body {
- font-size: 0.8em;
- line-height: 1.5em;
- }
-
- }
-
-
-/* Mobile */
-
-@media handheld, only screen and (max-width: 767px) {
-
- body {
- font-size: 16px;
- -webkit-text-size-adjust: none;
- overflow: visible;
- }
- div#header,
- div#workbench {
- width: 100%;
- height: auto;
- min-width: 0;
- margin-left: 0px;
- margin-right: 0px;
- padding-left: 0px;
- padding-right: 0px;
- }
-
- div#workbench div.panel
- {
- width:auto !important;
- }
-
- li.action div.tabname
- {
- width:auto !import;ant;
- }
-
- div#workbench div.panel
- {
- width: auto;
- float: none;
- margin-left: 0px;
- margin-right: 0px;
- padding-left: 20px;
- padding-right: 20px;
- }
- div#workbench div.panel > div.content
- {
- overflow:auto;
- height: auto !important;
- }
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-body > div#header {
- display:block;
-}
-
-ul#history > li {
-
- xdisplay:inline;
- margin:5px;
- padding:5px;
- border:1px solid <?php echo $_GET['title_background_color']; ?>;
- background-color: <?php echo $_GET['inactive_background_color']; ?>;
- color:<?php echo $_GET['text_color']; ?>;
-}
-ul#history > li.active {
-
- xdisplay:inline;
- margin:5px;
- padding:5px;
- border:1px solid <?php echo $_GET['text_color']; ?>;
- background-color: <?php echo $_GET['title_text_color']; ?>;
- color:<?php echo $_GET['text_color']; ?>;
-}
-
-ul#history {
- display:none;
-}
-
-
-table td.readonly {
- font-style: italic;
- font-weight: normal;
-}
-table td.default {
- font-style: normal;
- font-weight: normal;
-}
-table td.changed {
- font-style: normal;
- font-weight: bold;
-}
-
-
-/* Modale Dialoge */
-
-div#filler
-{
- xxxxdisplay: block;
- position:absolute;
- z-index: 100;
- top: 0;
- left: 0;
- height:100%;
- width:100%;
- background-color: <?php echo $_GET['text_color']; ?>;
- opacity: 0.5;
-}
-
-
-div.clickable.filtered.inactive > a
-{
- color: <?php echo $_GET['inactive_background_color']; ?>;
-}
-
-/* Pfeile */
-div#header > div > div.arrow-down
-{
- display: inline;
- width:0;
- height:0;
- margin:6;
- padding:0px;
- border-right : 6px solid <?php echo $_GET['title_background_color']; ?>;
- border-left : 6px solid <?php echo $_GET['title_background_color']; ?>;
- border-top : 6px solid <?php echo $_GET['inactive_background_color' ]; ?>;
- border-bottom: 4px solid <?php echo $_GET['title_background_color' ]; ?>;
- margin-top: 10px;
-font-size: 0;
-}
-
-
-
-/* D r o p d o w n - M e n u e s */
-div.dropdown
-{
- /* Schatten */
- -webkit-box-shadow: 3px 2px 10px <?php echo $_GET['title_background_color']; ?>;
- -moz-box-shadow: 3px 2px 10px <?php echo $_GET['title_background_color']; ?>;
- box-shadow: 3px 2px 10px <?php echo $_GET['title_background_color']; ?>;
-
- opacity:0.95;
-
- border:2px solid <?php echo $_GET['title_background_color']; ?>;
- -moz-border-radius:5px; /* Mozilla */
- -webkit-border-radius:5px; /* Webkit */
- -khtml-border-radius:5px; /* Konqui */
- border-radius:5px;
-
- /*
- background: -moz-linear-gradient(top, <?php echo $_GET['title_background_color']; ?>, <?php echo $_GET['inactive_background_color']; ?>);
- background: -webkit-gradient(linear, left top, left bottom, from(<?php echo $_GET['title_background_color']; ?>), to(<?php echo $_GET['inactive_background_color']; ?>));
- */
- font-style:normal;
- font-weight:normal;
- text-decoration:none;
-}
-
-
-div#header span.titletext
-{
- color:<?php echo $_GET['title_text_color']; ?>;
-}
-
-
-div.toolbar-icon
-{
- border:1px solid <?php echo $_GET['title_background_color']; ?>;
- padding:2px;
- margin-left:5px;
- float: left;
-
- -moz-border-radius:3px;
- -webkit-border-radius:3px;
- -khtml-border-radius:3px;
- border-radius:3px;
-}
-div.toolbar-icon.inactive
-{
- opacity:0.5;
-}
-
-div.toolbar-icon:hover
-{
- border:1px solid <?php echo $_GET['inactive_background_color']; ?>;
- xxbackground-color: <?php echo $_GET['inactive_background_color']; ?>;
-}
-
-
-div.headermenu
-{
- margin:5px;
- z-index: 1;
- position: relative;
- right: 0;
- top: 0;
-}
-div.headermenu > div.toolbar-icon
-{
- float:right;
-}
-
-
- /* Voreingestellte Schriftart */
-body
-{
-
-}
-
-
-
-/* Formulare breit */
-div.panel.wide form div.line
-{
- clear:left;
- margin-top:10px;
-}
-
-div.panel.wide form div.label
-{
- display:inline-block;
- width:30%;
- vertical-align:top;
- text-align: right;
-}
-
-div.panel.wide form div.input
-{
- display:inline-block;
- width:60%;
- vertical-align:top;
- text-align: left;
-}
-
-/* Formulare schmal */
-div.panel.small form div.line
-{
- clear:left;
- padding:10px;
-}
-
-div.panel.small form div.label
-{
- display:block;
- width:100%;
- vertical-align:top;
- text-align: left;
-}
-
-div.panel.small form div.input
-{
- display:block;
- width:100%;
- vertical-align:top;
- text-align: left;
-}
-
-
-
-form div.label > label,
-form div.input > div.intputholder
-{
- padding:0px 5px;
-}
-
-form div.input input[type=text],
-form div.input input[type=password],
-form div.input textarea,
-form div.input select
-{
- width:100%;
-}
-form div.input input[type=checkbox],
-form div.input input[type=radio]
-{
- vertical-align:top;
-}
-
-label
-{
- display:inline-block;
-}
-
-input[type=checkbox] + label,
-input[type=radio] + label
-{
- width:80%;
-}
-
-label div.description
-{
- font-size: 0.75em;
- color:<?php echo $_GET['title_background_color']; ?>;
-}
-
-
-div.inputholder
-{
- background-color:<?php echo $_GET['title_text_color']; ?>;
- border:1px solid <?php echo $_GET['title_background_color']; ?>;
- margin:0px;
- padding:4px;
- -moz-border-radius:3px;
- -webkit-border-radius:3px;
- -khtml-border-radius:3px;
- border-radius:3px;
-
- -webkit-box-shadow:inset 0px 0px 3px <?php echo $_GET['title_background_color']; ?>;
- -moz-box-shadow:inset 0px 0px 3px <?php echo $_GET['title_background_color']; ?>;
- box-shadow:inset 0px 0px 3px <?php echo $_GET['title_background_color']; ?>;
-
-}
-
-
-div.inputholder ul.tree,
-div.inputholder ul.tree li.last,
-div.inputholder ul.tree li:last-child
-{
- background-color:<?php echo $_GET['title_text_color']; ?>;
-}
-
-div.inputholder > div.dropdown
-{
- width:70%;
-}
-
-div.search > div.inputholder
-{
- padding-top:1px;
-}
-
-div.inputholder > input,
-div.inputholder > textarea,
-div.inputholder > select
-{
- border:0px;
- border-bottom:1px solid <?php echo $_GET['title_text_color']; ?>;
- padding:2px;
- margin:0px;
- background-color:<?php echo $_GET['title_text_color']; ?>;
-}
-
-input:focus,
-textarea:focus,
-select:focus
-{
- border:0px;
- border-bottom:1px solid <?php echo $_GET['inactive_background_color']; ?>;
-}
-
-
-input.error,
-textarea.error,
-select.error
-{
- border-bottom:1px dotted <?php echo $_GET['text_color']; ?> !important;
-}
-
-div.inputholder.error
-{
- border:1px solid red !important;
-}
-
-input.hint
-{
- color:<?php echo $_GET['title_background_color']; ?>;
-}
-
-
-
-
-/* Eingabfeld fuer Namen */
-fieldset > div input.name,
-fieldset > div span.name
-{
- font-weight:bold;
-}
-
-
-fieldset
-{
- border-color:<?php echo $_GET['title_background_color']; ?>;
-}
-
-/* Eingabfelder fuer Dateiname */
-fieldset > div input.filename,
-fieldset > div input.extension,
-fieldset > div input.ansidate,
-fieldset > div span.filename,
-fieldset > div span.extension,
-fieldset > div span.ansidate
-{
- font-family:Courier;
- font-size:1em;
-}
-
-
-div#tree
-{
- overflow:visible;
-}
-
-
-
-
-
-/* Anzeige von Text-Unterschieden */
-
-/* Zeilen-Nr */
-tr.diff > td.line
-{
- background-color:<?php echo $_GET['title_text_color']; ?>;
- padding-right:2px;
- border-right:3px solid <?php echo $_GET['title_background_color']; ?>;
- text-align:right;
- margin-right:2px;
-}
-
-/* Unveränderter Text */
-tr.diff > td.equal
-{
-}
-
-/* Entfernter Text */
-tr.diff > td.old
-{
- background-color:red;
-}
-
-/* Hinzugefuegter Text */
-tr.diff > td.new
-{
- background-color:green;
-}
-
-/* Geaenderter Text */
-tr.diff > td.notequal
-{
- background-color:yellow;
-}
-
-dl.notice
-{
- border-left:10px <?php echo $_GET['inactive_background_color']; ?> solid;
- border-right:1px <?php echo $_GET['inactive_background_color']; ?> solid;
- padding:15px;
-}
-
-dl.notice > dt
-{
- border-top: 1px <?php echo $_GET['inactive_background_color']; ?> solid;
-}
-dl.notice > dd
-{
- border-bottom: 1px <?php echo $_GET['inactive_background_color']; ?> solid;
-}
-
-
-/* S c h a t t e n */
-div.content a.action,
-div.content a.help
-{
- -webkit-box-shadow: 3px 2px 5px <?php echo $_GET['title_background_color']; ?>;
- -moz-box-shadow: 3px 2px 5px <?php echo $_GET['title_background_color']; ?>;
- box-shadow: 3px 2px 5px <?php echo $_GET['title_background_color']; ?>;
-}
-
-
-
-/* F a r b e n */
-
-/* Gesamt-Hintergrund */
-body
-{
- xxxbackground-color:#c9c9c9;
- background-color:<?php echo $_GET['inactive_background_color'] ?>;
-}
-
-/* Fenster-Hintergrund */
-div.panel ul.views > li.active,
-div.panel ul.views > li.active:hover
-{
- background-color: <?php echo $_GET['title_background_color']; ?>;
- background-image: linear-gradient(<?php echo $_GET['inactive_background_color']; ?> 0%, <?php echo $_GET['title_background_color']; ?> 15%);
- color: <?php echo $_GET['title_text_color']; ?>;
-}
-
-/* Titelleiste-Hintergrund */
-div#header
-{
- background-color: <?php echo $_GET['title_background_color']; ?>;
- background-image: linear-gradient(<?php echo $_GET['title_background_color']; ?> 85%, <?php echo $_GET['inactive_background_color']; ?> 100%);
- color: <?php echo $_GET['title_text_color']; ?>;
-}
-
-/* Titelleiste */
-div#header div.toolbar-icon > a
-{
- color: <?php echo $_GET['title_text_color']; ?>;
-}
-
-div#header, /* Titelleite */
-ul.views > li.action /* Tabreiter */
-{
- font-family: Arial, sans-serif;
- font-size:13px;
-}
-
-div.content
-{
- font-family: Trebuchet MS, Helvetica, Arial, sans-serif;
- font-size:13px;
-}
-
-
-/* Reiter */
-div.panel ul.views li
-{
- /*
- background-color:<?php echo $_GET['background_color']; ?>;
- */
-}
-
-
-div.panel > div.content
-{
- background-color:<?php echo $_GET['background_color']; ?>;
-}
-
-div.panel > div.header
-{
- background-color:<?php echo $_GET['background_color']; ?>;
- background-image: linear-gradient(<?php echo $_GET['inactive_background_color']; ?> 00%, <?php echo $_GET['background_color']; ?> 85%);
-}
-
-
-
-
-div.panel ul.views li:hover {
- background-color: <?php echo $_GET['inactive_background_color']; ?>;
- /*
- color: blue;
- */
-}
-
-
-
-ul.tree li.last,
-ul.tree li:last-child
-{
- background-color:<?php echo $_GET['background_color']; ?>;
-}
-
-
-
-div.content pre,
-div.dropdown
-{
- background-color:<?php echo $_GET['title_text_color']; ?>;
- color:<?php echo $_GET['text_color']; ?>;
- min-width: 150px;
- max-width: 450px;
-}
-
-
-
-
-
-div.filler div.headermenu > a.entry,
-div.filler div.header a.back.button
-{
- font-size: 0.8em;
-}
diff --git a/themes/default/css/openrat-workbench.css b/themes/default/css/openrat-workbench.css
@@ -0,0 +1,158 @@
+/*
+OpenRat Content Management System
+Copyright (C) 2002-2010 Jan Dankert
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/*
+Basis-Style for Openrat.
+*/
+
+
+/* R e s e t - Alle Elemente zuruecksetzen */
+/* Source: http://meyerweb.com/eric/tools/css/reset/ */
+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:top;}
+blockquote:before, blockquote:after, q:before, q:after {content:"";}
+blockquote, q {quotes:"" "";}
+a img {border:none;}
+
+
+
+div#workbench div.panel.modal
+{
+
+ /*width:60%;*/
+ position:relative;
+ xtop:0;
+ xleft:0;
+
+ z-index: 101;
+
+ border:1px solid !important;
+
+ -webkit-box-shadow: 0px 0px 40px __text_color__;
+ -moz-box-shadow: 0px 0px 40px __text_color__;
+ box-shadow: 0px 0px 40px __text_color__;
+
+}
+
+
+
+div#dialog
+{
+ overflow: auto;
+
+ /*width:60%;*/
+ position:absolute;
+ top:5%;
+ left:10%;
+ width:80%;
+ height:80%;
+
+ z-index: 104;
+
+ border:1px solid !important;
+
+
+ -webkit-box-shadow: 0px 0px 40px ;
+ -moz-box-shadow: 0px 0px 40px ;
+ box-shadow: 0px 0px 40px ;
+
+ -moz-border-radius:5px;
+ -webkit-border-radius:5px;
+ -khtml-border-radius:5px;
+ border-radius:5px;
+}
+
+
+
+
+div.container.axle-x > div.divider
+{
+ width:5px;
+}
+div.container.axle-y > div.divider
+{
+ height:5px;
+}
+
+/* Pfeile */
+div.divider.to-left
+{
+ cursor: w-resize;
+}
+div.divider.to-right
+{
+ cursor: e-resize;
+}
+div.divider.to-top
+{
+ cursor: n-resize;
+}
+div.divider.to-bottom
+{
+ cursor: s-resize;
+}
+
+/* Mouseover */
+div.container > div.divider.ui-draggable-dragging
+{
+ z-index: 150;
+}
+
+
+
+/* Pfeile */
+div#workbench div.panel div.arrow-down
+{
+ width:0;
+ height:0;
+ margin:6px;
+ padding:0px;
+ border-right : 6px solid transparent;
+ border-top : 6px solid ;
+ border-left : 6px solid transparent;
+ border-bottom : 4px solid transparent;
+ margin-top: 10px;
+ font-size: 0;
+}
+/* Pfeile */
+div#workbench div.panel div.arrow-right
+{
+ width:0;
+ height:0;
+ margin:6px;
+ padding:0;
+ border-top: 6px solid transparent;
+ border-left: 6px solid ;
+ border-bottom: 6px solid transparent;
+ border-right: 4px solid transparent;
+ margin-left: 10px;
+ font-size: 0;
+}
+
+
+div#workbench div.panel li.action.dirty
+{
+ font-weight: bold;
+}
+
+
+
diff --git a/themes/default/css/openrat-workbench.css.php b/themes/default/css/openrat-workbench.css.php
@@ -1,170 +0,0 @@
-<?php header('Content-Type: text/css',true) ?>
-/*
-OpenRat Content Management System
-Copyright (C) 2002-2010 Jan Dankert
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-
-/*
-Basis-Style for Openrat.
-*/
-
-
-/* R e s e t - Alle Elemente zuruecksetzen */
-/* Source: http://meyerweb.com/eric/tools/css/reset/ */
-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:top;}
-blockquote:before, blockquote:after, q:before, q:after {content:"";}
-blockquote, q {quotes:"" "";}
-a img {border:none;}
-
-
-
-div#workbench div.panel.modal
-{
-
- /*width:60%;*/
- position:relative;
- xtop:0;
- xleft:0;
-
- z-index: 101;
-
- border:1px solid <?php echo $_GET['text_color']; ?> !important;
- /*
- border:3px solid <?php echo $_GET['text_color']; ?> !important;
- background-color:<?php echo $_GET['title_text_color']; ?> !important;
- */
- /*
-
- margin:5% 20% !important;
- */
-
- -webkit-box-shadow: 0px 0px 40px <?php echo $_GET['text_color']; ?>;
- -moz-box-shadow: 0px 0px 40px <?php echo $_GET['text_color']; ?>;
- box-shadow: 0px 0px 40px <?php echo $_GET['text_color']; ?>;
-
-}
-
-
-
-div#dialog
-{
- background-color:<?php echo $_GET['background_color']; ?>;
- color:<?php echo $_GET['text_color']; ?>;
- overflow: auto;
-
- /*width:60%;*/
- position:absolute;
- top:5%;
- left:10%;
- width:80%;
- height:80%;
-
- z-index: 104;
-
- border:1px solid <?php echo $_GET['text_color']; ?> !important;
-
-
- -webkit-box-shadow: 0px 0px 40px <?php echo $_GET['text_color']; ?>;
- -moz-box-shadow: 0px 0px 40px <?php echo $_GET['text_color']; ?>;
- box-shadow: 0px 0px 40px <?php echo $_GET['text_color']; ?>;
-
- -moz-border-radius:5px;
- -webkit-border-radius:5px;
- -khtml-border-radius:5px;
- border-radius:5px;
-}
-
-
-
-
-div.container.axle-x > div.divider
-{
- width:5px;
-}
-div.container.axle-y > div.divider
-{
- height:5px;
-}
-
-/* Pfeile */
-div.divider.to-left
-{
- cursor: w-resize;
-}
-div.divider.to-right
-{
- cursor: e-resize;
-}
-div.divider.to-top
-{
- cursor: n-resize;
-}
-div.divider.to-bottom
-{
- cursor: s-resize;
-}
-
-/* Mouseover */
-div.container > div.divider.ui-draggable-dragging
-{
- z-index: 150;
- background-color: <?php echo $_GET['title_background_color']; ?>;
-}
-
-
-
-/* Pfeile */
-div#workbench div.panel div.arrow-down
-{
- width:0;
- height:0;
- margin:6px;
- padding:0px;
- border-right : 6px solid transparent;
- border-top : 6px solid <?php echo $_GET['title_background_color']; ?>;
- border-left : 6px solid transparent;
- border-bottom : 4px solid transparent;
- margin-top: 10px;
- font-size: 0;
-}
-/* Pfeile */
-div#workbench div.panel div.arrow-right
-{
- width:0;
- height:0;
- margin:6px;
- padding:0;
- border-top: 6px solid transparent;
- border-left: 6px solid <?php echo $_GET['title_background_color']; ?>;
- border-bottom: 6px solid transparent;
- border-right: 4px solid transparent;
- margin-left: 10px;
- font-size: 0;
-}
-
-
-div#workbench div.panel li.action.dirty
-{
- font-weight: bold;
-}
-
-
-
diff --git a/themes/default/include/html/form/form.js b/themes/default/include/html/form/form.js
@@ -39,7 +39,7 @@ function formSubmit(form)
}
- var status = $('<div class="notice info"><div class="text loader"></div></div');
+ var status = $('<div class="notice info"><div class="text loader"></div></div>');
$('#noticebar').prepend(status); // Notice anhängen.
$(status).show();
@@ -133,7 +133,7 @@ function doResponse(data,status,element)
$.each(data['notices'], function(idx,value) {
// Notice-Bar mit dieser Meldung erweitern.
- var notice = $('<div class="notice '+value.status+'"><div class="text">'+value.text+'</div></div');
+ var notice = $('<div class="notice '+value.status+'"><div class="text">'+value.text+'</div></div>');
notifyBrowser(value.text);
$.each(value.log, function(name,value) {
$(notice).append('<div class="log">'+value+'</div>');
diff --git a/themes/default/include/html/upload/upload.css b/themes/default/include/html/upload/upload.css
@@ -3,6 +3,6 @@ div.line.filedropzone > div.input
width: 100%;
height: 100px;
- background-color:<?php echo $_GET['title_text_color']; ?>;
- border:1px dotted <?php echo $_GET['text_color']; ?>;
+ background-color:<?php echo $title_text_color; ?>;
+ border:1px dotted <?php echo $text_color; ?>;
}
diff --git a/themes/default/include/html/upload/upload.js b/themes/default/include/html/upload/upload.js
@@ -53,7 +53,7 @@ function handleFileUpload(form,files)
form_data.append('token' ,$(form).find('input[name=token]').val() );
form_data.append('id' ,$(form).find('input[name=id]' ).val() );
- var status = $('<div class="notice info"><div class="text loader"></div></div');
+ var status = $('<div class="notice info"><div class="text loader"></div></div>');
$('#noticebar').prepend(status); // Notice anhängen.
$(status).show();
diff --git a/themes/default/js/openrat.js b/themes/default/js/openrat.js
@@ -969,35 +969,24 @@ function notifyBrowser(text)
-function setUserStyle( url )
+/**
+ * Setzt einen neuen Theme.
+ * @param styleName
+ * @returns
+ */
+function setUserStyle( styleName )
{
- $('#userstyle').attr('href',url);
+ var html = $('html');
+ var classList = html.attr('class').split(/\s+/);
+ $.each(classList, function(index, item) {
+ if (item.startsWith('theme-')) {
+ html.removeClass(item);
+ }
+ });
+ html.addClass( 'theme-' + styleName.toLowerCase() );
}
-/*
-$(function(){ //Document ready shorthand
-
-var $search = $('#search');//Cache the element for faster DOM searching since we are using it more than once
-original_val = $search.val(); //Get the original value to test against. We use .val() to grab value="Search"
-$search.focus(function(){ //When the user tabs/clicks the search box.
- if($(this).val()===original_val){ //If the value is still the default, in this case, "Search"
- $(this).val('');//If it is, set it to blank
- }
-})
-.blur(function(){//When the user tabs/clicks out of the input
- if($(this).val()===''){//If the value is blank (such as the user clicking in it and clicking out)...
- $(this).val(original_val); //... set back to the original value
- }
-});
-
-});
-
- */
-
-
-
-
//Quelle:
@@ -1098,62 +1087,6 @@ function loadSubaction( el, actionName, subactionName,id )
-function loadWindow( el, actionName, subactionName )
-{
- alert('loadWindow()');
- // Zeichnet das Fenster-Gerüst, erstmal ohne Inhalt.
- $(el).html('<div class="window"><div class="title"></div><ul class="menu"></div><div class="content"></div><div class="status"></div></div>');
-
- // Icon
- $(el).find('div.title').html('<img src="'+image_dir+'icon_'+icon+'.'+IMG_ICON_EXT+'" align="left" />');
-
- /* Pfad
- <span class="path"><?php echo langHtml($actionName) ?></span> <strong>→</strong>
- <a javascript:void(0);" onclick="javascript:loadViewByName('<?php echo $view ?>','<?php echo $url ?>'); return false; " title="<?php echo $title ?>" class="path"><?php echo (!empty($key)?langHtml($key):$name) ?></a>
- →
- <?php } ?>
- <span class="title"><?php echo langHtml(@$windowTitle) ?></span>
- */
-
-
- /*
- * Menü
- if ( !isset($windowMenu) || !is_array($windowMenu) ) $windowMenu = array();
- foreach( $windowMenu as $menu )
- {
- $tmp_text = langHtml($menu['text']);
- $tmp_key = strtoupper(langHtml($menu['key' ]));
- $tmp_pos = strpos(strtolower($tmp_text),strtolower($tmp_key));
- if ( $tmp_pos !== false )
- $tmp_text = substr($tmp_text,0,max($tmp_pos,0)).'<span class="accesskey">'. substr($tmp_text,$tmp_pos,1).'</span>'.substr($tmp_text,$tmp_pos+1);
-
- $liClass = (isset($menu['url'])?'':'no').'action'.($this->subActionName==$menu['subaction']?'_active':'');
- $icon_url = $image_dir.'icon/'.$menu['subaction'].'.png';
-
- ?><li class="<?php echo $liClass?>"><?php
- if ( isset($menu['url']) )
- {
- $link_url = Html::url($actionName,$menu['subaction'],$this->getRequestId() );
- ?><a href="javascript:void(0);" onclick="javascript:loadViewByName('<?php echo $view ?>','<?php echo $link_url ?>'); return false; " accesskey="<?php echo $tmp_key ?>" title="<?php echo langHtml($menu['text'].'_DESC') ?>"><img src="<?php echo $icon_url ?>" /><?php echo $tmp_text ?></a><?php
- }
- else
- {
- ?><span><img src="<?php echo $icon_url ?>" /><?php echo $tmp_text ?></span><?php
- }
- }
- ?></li><?php
- */
-
- /*
- * Hilfe
- * if ( false && @$conf['help']['enabled'] )
- {
- ?><a class="help" href="<?php echo $conf['help']['url'].$actionName.'/'.$subActionName.@$conf['help']['suffix'] ?> " target="_new" title="<?php echo langHtml('MENU_HELP_DESC') ?>"><img src="<?php echo $image_dir.'icon/help.png' ?>" /><?php echo @$conf['help']['only_question_mark']?'?':langHtml('MENU_HELP') ?></a><?php
- }
- ?><?php
- */
-}
-
/**
* Erzeugt eine URL, um die gewünschte Action vom Server zu laden.
@@ -1311,7 +1244,7 @@ function help(el,url,suffix)
function notify( type,msg )
{
// Notice-Bar mit dieser Meldung erweitern.
- var notice = $('<div class="notice '+type+'"><div class="text">'+msg+'</div></div');
+ var notice = $('<div class="notice '+type+'"><div class="text">'+msg+'</div></div>');
$('#noticebar').prepend(notice); // Notice anhängen.
notifyBrowser(msg);
diff --git a/themes/default/layout/index.php b/themes/default/layout/index.php
@@ -2,7 +2,7 @@
if (!defined('OR_VERSION')) die('Forbidden');
if (!headers_sent()) header('Content-Type: text/html; charset=UTF-8')
?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-<html>
+<html class="theme-<?php echo strtolower($style) ?> nojs">
<head>
<?php $appName = config('application','name'); $appOperator = config('application','operator');
$title = $appName.(($appOperator!=$appName)?' - '.$appOperator:''); ?>
@@ -31,12 +31,12 @@
// $css[] = link id="userstyle" rel="stylesheet" type="text/css" href="<?php echo css_link($style) "
$cssParam = css_link($style);
- $css['userstyle'] = OR_THEMES_EXT_DIR.'default/css/openrat-theme.css.php?'.$cssParam;
- $css[] = OR_THEMES_EXT_DIR.'default/css/openrat-ui.css.php?'.$cssParam;
- $css[] = OR_THEMES_EXT_DIR.'default/css/openrat-workbench.css.php?'.$cssParam;
+ $css['userstyle'] = OR_THEMES_EXT_DIR.'default/css/openrat-theme.css.php';
+ $css[] = OR_THEMES_EXT_DIR.'default/css/openrat-ui.css.php';
+ $css[] = OR_THEMES_EXT_DIR.'default/css/openrat-workbench.css.php';
- $css[] = OR_THEMES_EXT_DIR.'../editor/markitup/markitup/skins/markitup/style.css';
- $css[] = OR_THEMES_EXT_DIR.'../editor/markitup/markitup/sets/default/style.css';
+// $css[] = OR_THEMES_EXT_DIR.'../editor/markitup/markitup/skins/markitup/style.css';
+// $css[] = OR_THEMES_EXT_DIR.'../editor/markitup/markitup/sets/default/style.css';
// Komponentenbasiertes CSS
$elements = parse_ini_file( OR_THEMES_DIR.config('interface','theme').'/include/elements.ini.'.PHP_EXT);
@@ -48,12 +48,31 @@
$css[] = $componentCssFile;
}
-
+
+ /*
+if ( DEVELOPMENT ) {
+
foreach( $css as $id=>$cssFile )
{
?><link <?php if ( !is_numeric($id)) {?>id="<?php echo $id ?>" <?php } ?>rel="stylesheet" type="text/css" href="<?php echo $cssFile ?>" />
<?php
}
+}else {
+ // Production mode: Inline minified CSS
+ ?><style><?php
+ ob_start('minifyCSS');
+ foreach( $css as $id=>$cssFile )
+ {
+ foreach( array_keys(config('style')) as $styleId )
+ {
+ extract( config('style',$styleId) );
+ include( $cssFile );
+ }
+
+ }
+ ob_end_flush();
+ ?></style><?php
+}
$js = array();
$js[] = OR_THEMES_EXT_DIR.'default/js/jquery-1.12.4.min.js';
@@ -72,10 +91,34 @@
$js[] = OR_THEMES_EXT_DIR.'default/js/jquery-qrcode.min.js';
// $js[] = OR_THEMES_EXT_DIR.'../editor/wymeditor/wymeditor/jquery.wymeditor.min.js"></script> -->
$js[] = OR_THEMES_EXT_DIR.'../editor/markitup/markitup/jquery.markitup.js';
- $js[] = OR_THEMES_EXT_DIR.'../editor/editor/ckeditor.js';
+ //$js[] = OR_THEMES_EXT_DIR.'../editor/editor/ckeditor.js';
$js[] = OR_THEMES_EXT_DIR.'../editor/ace/src-min-noconflict/ace.js';
$js[] = OR_THEMES_EXT_DIR.'../editor/editor/adapters/jquery.js';
+ function minifyJS( $source ) {
+// return $source;
+ $jz = new JSqueeze();
+
+ return $jz->squeeze(
+ $source,
+ true, // $singleLine
+ true, // $keepImportantComments
+ false // $specialVarRx
+ );
+ }
+ function minifyCSS( $source ) {
+
+// return $source;
+ // Remove comments
+ //$source = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)* /!', '', $source);
+ // Remove space after colons
+ $source = str_replace(': ', ':', $source);
+ // Remove whitespace
+ $source = str_replace(array("\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $source);
+
+ return $source;
+ }
+
// Komponentenbasiertes Javascript
foreach( array_keys($elements) as $c )
@@ -86,13 +129,29 @@
}
- foreach( $js as $jsFile )
- {
- ?><script src="<?php echo $jsFile ?>" defer></script>
- <?php
- }
+ if ( DEVELOPMENT )
+ {
+
+ foreach( $js as $jsFile )
+ {
+ ?><script src="<?php echo $jsFile ?>" defer></script><?php
+ }
+ }
+ else
+ {
+ ?><script type="text/javascript">
+ document.addEventListener("DOMContentLoaded", function(event) {<?php
+ ob_start('minifyJS');
+ foreach( $js as $jsFile )
+ include(''.$jsFile);
+ ob_end_flush();
+ ?>});</script><?php
+
+ }*/
?>
+<script src="dispatcher.php?action=index&subaction=javascript" defer></script>
+<link rel="stylesheet" type="text/css" href="dispatcher.php?action=index&subaction=stylesheet" />
</head>
<?php
diff --git a/util/JSqueeze.class.php b/util/JSqueeze.class.php
@@ -0,0 +1,1064 @@
+<?php
+
+/*
+ * Copyright (C) 2016 Nicolas Grekas - p@tchwork.com
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the (at your option):
+ * Apache License v2.0 (see provided LICENCE.ASL20 file), or
+ * GNU General Public License v2.0 (see provided LICENCE.GPLv2 file).
+ */
+
+//namespace Patchwork;
+
+/*
+*
+* This class shrinks Javascript code
+* (a process called minification nowadays)
+*
+* Should work with most valid Javascript code,
+* even when semi-colons are missing.
+*
+* Features:
+* - Removes comments and white spaces.
+* - Renames every local vars, typically to a single character.
+* - Renames also global vars, methods and properties, but only if they
+* are marked special by some naming convention. By default, special
+* var names begin with one or more "$", or with a single "_".
+* - Renames also local/global vars found in strings,
+* but only if they are marked special.
+* - Keep Microsoft's conditional comments.
+* - Output is optimized for later HTTP compression.
+*
+* Notes:
+* - Source code must be parse error free before processing.
+* - In order to maximise later HTTP compression (deflate, gzip),
+* new variables names are chosen by considering closures,
+* variables' frequency and characters' frequency.
+* - If you use with/eval then be careful.
+*
+* Bonus:
+* - Replaces false/true by !1/!0
+* - Replaces new Array/Object by []/{}
+* - Merges consecutive "var" declarations with commas
+* - Merges consecutive concatened strings
+* - Fix a bug in Safari's parser (http://forums.asp.net/thread/1585609.aspx)
+* - Can replace optional semi-colons by line feeds,
+* thus facilitating output debugging.
+* - Keep important comments marked with /*!...
+* - Treats three semi-colons ;;; like single-line comments
+* (http://dean.edwards.name/packer/2/usage/#triple-semi-colon).
+* - Fix special catch scope across browsers
+* - Work around buggy-handling of named function expressions in IE<=8
+*
+* TODO?
+* - foo['bar'] => foo.bar
+* - {'foo':'bar'} => {foo:'bar'}
+* - Dead code removal (never used function)
+* - Munge primitives: var WINDOW=window, etc.
+*/
+
+class JSqueeze
+{
+ const
+
+ SPECIAL_VAR_PACKER = '(\$+[a-zA-Z_]|_[a-zA-Z0-9$])[a-zA-Z0-9_$]*';
+
+ public
+
+ $charFreq;
+
+ protected
+
+ $strings,
+ $closures,
+ $str0,
+ $str1,
+ $argFreq,
+ $specialVarRx,
+ $keepImportantComments,
+
+ $varRx = '(?:[a-zA-Z_$])[a-zA-Z0-9_$]*',
+ $reserved = array(
+ // Literals
+ 'true','false','null',
+ // ES6
+ 'break','case','class','catch','const','continue','debugger','default','delete','do','else','export','extends','finally','for','function','if','import','in','instanceof','new','return','super','switch','this','throw','try','typeof','var','void','while','with','yield',
+ // Future
+ 'enum',
+ // Strict mode
+ 'implements','package','protected','static','let','interface','private','public',
+ // Module
+ 'await',
+ // Older standards
+ 'abstract','boolean','byte','char','double','final','float','goto','int','long','native','short','synchronized','throws','transient','volatile',
+ );
+
+ public function __construct()
+ {
+ $this->reserved = array_flip($this->reserved);
+ $this->charFreq = array_fill(0, 256, 0);
+ }
+
+ /**
+ * Squeezes a JavaScript source code.
+ *
+ * Set $singleLine to false if you want optional
+ * semi-colons to be replaced by line feeds.
+ *
+ * Set $keepImportantComments to false if you want /*! comments to be removed.
+ *
+ * $specialVarRx defines the regular expression of special variables names
+ * for global vars, methods, properties and in string substitution.
+ * Set it to false if you don't want any.
+ *
+ * If the analysed javascript source contains a single line comment like
+ * this one, then the directive will overwrite $specialVarRx:
+ *
+ * // jsqueeze.specialVarRx = your_special_var_regexp_here
+ *
+ * Only the first directive is parsed, others are ignored. It is not possible
+ * to redefine $specialVarRx in the middle of the javascript source.
+ *
+ * Example:
+ * $parser = new JSqueeze;
+ * $squeezed_js = $parser->squeeze($fat_js);
+ */
+ public function squeeze($code, $singleLine = true, $keepImportantComments = true, $specialVarRx = false)
+ {
+ $code = trim($code);
+ if ('' === $code) {
+ return '';
+ }
+
+ $this->argFreq = array(-1 => 0);
+ $this->specialVarRx = $specialVarRx;
+ $this->keepImportantComments = !!$keepImportantComments;
+
+ if (preg_match("#//[ \t]*jsqueeze\.specialVarRx[ \t]*=[ \t]*([\"']?)(.*)\\1#i", $code, $key)) {
+ if (!$key[1]) {
+ $key[2] = trim($key[2]);
+ $key[1] = strtolower($key[2]);
+ $key[1] = $key[1] && $key[1] != 'false' && $key[1] != 'none' && $key[1] != 'off';
+ }
+
+ $this->specialVarRx = $key[1] ? $key[2] : false;
+ }
+
+ // Remove capturing parentheses
+ $this->specialVarRx && $this->specialVarRx = preg_replace('/(?<!\\\\)((?:\\\\\\\\)*)\((?!\?)/', '(?:', $this->specialVarRx);
+
+ false !== strpos($code, "\r") && $code = strtr(str_replace("\r\n", "\n", $code), "\r", "\n");
+ false !== strpos($code, "\xC2\x85") && $code = str_replace("\xC2\x85", "\n", $code); // Next Line
+ false !== strpos($code, "\xE2\x80\xA8") && $code = str_replace("\xE2\x80\xA8", "\n", $code); // Line Separator
+ false !== strpos($code, "\xE2\x80\xA9") && $code = str_replace("\xE2\x80\xA9", "\n", $code); // Paragraph Separator
+
+ list($code, $this->strings) = $this->extractStrings($code);
+ list($code, $this->closures) = $this->extractClosures($code);
+
+ $key = "//''\"\"#0'"; // This crap has a wonderful property: it can not happen in any valid javascript, even in strings
+ $this->closures[$key] = &$code;
+
+ $tree = array($key => array('parent' => false));
+ $this->makeVars($code, $tree[$key], $key);
+ $this->renameVars($tree[$key], true);
+
+ $code = substr($tree[$key]['code'], 1);
+ $code = preg_replace("'\breturn !'", 'return!', $code);
+ $code = preg_replace("'\}(?=(else|while)[^\$.a-zA-Z0-9_])'", "}\r", $code);
+ $code = str_replace(array_keys($this->strings), array_values($this->strings), $code);
+
+ if ($singleLine) {
+ $code = strtr($code, "\n", ';');
+ } else {
+ $code = str_replace("\n", ";\n", $code);
+ }
+ false !== strpos($code, "\r") && $code = strtr(trim($code), "\r", "\n");
+
+ // Cleanup memory
+ $this->charFreq = array_fill(0, 256, 0);
+ $this->strings = $this->closures = $this->argFreq = array();
+ $this->str0 = $this->str1 = '';
+
+ return $code;
+ }
+
+ protected function extractStrings($f)
+ {
+ if ($cc_on = false !== strpos($f, '@cc_on')) {
+ // Protect conditional comments from being removed
+ $f = str_replace('#', '##', $f);
+ $f = str_replace('/*@', '1#@', $f);
+ $f = preg_replace("'//@([^\n]+)'", '2#@$1@#3', $f);
+ $f = str_replace('@*/', '@#1', $f);
+ }
+
+ $len = strlen($f);
+ $code = str_repeat(' ', $len);
+ $j = 0;
+
+ $strings = array();
+ $K = 0;
+
+ $instr = false;
+
+ $q = array(
+ "'", '"',
+ "'" => 0,
+ '"' => 0,
+ );
+
+ // Extract strings, removes comments
+ for ($i = 0; $i < $len; ++$i) {
+ if ($instr) {
+ if ('//' == $instr) {
+ if ("\n" == $f[$i]) {
+ $f[$i--] = ' ';
+ $instr = false;
+ }
+ } elseif ($f[$i] == $instr || ('/' == $f[$i] && "/'" == $instr)) {
+ if ('!' == $instr) {
+ } elseif ('*' == $instr) {
+ if ('/' == $f[$i + 1]) {
+ ++$i;
+ $instr = false;
+ }
+ } else {
+ if ("/'" == $instr) {
+ while (isset($f[$i + 1]) && false !== strpos('gmi', $f[$i + 1])) {
+ $s[] = $f[$i++];
+ }
+ $s[] = $f[$i];
+ }
+
+ $instr = false;
+ }
+ } elseif ('*' == $instr) {
+ } elseif ('!' == $instr) {
+ if ('*' == $f[$i] && '/' == $f[$i + 1]) {
+ $s[] = "*/\r";
+ ++$i;
+ $instr = false;
+ } elseif ("\n" == $f[$i]) {
+ $s[] = "\r";
+ } else {
+ $s[] = $f[$i];
+ }
+ } elseif ('\\' == $f[$i]) {
+ ++$i;
+
+ if ("\n" != $f[$i]) {
+ isset($q[$f[$i]]) && ++$q[$f[$i]];
+ $s[] = '\\'.$f[$i];
+ }
+ } elseif ('[' == $f[$i] && "/'" == $instr) {
+ $instr = '/[';
+ $s[] = '[';
+ } elseif (']' == $f[$i] && '/[' == $instr) {
+ $instr = "/'";
+ $s[] = ']';
+ } elseif ("'" == $f[$i] || '"' == $f[$i]) {
+ ++$q[$f[$i]];
+ $s[] = '\\'.$f[$i];
+ } else {
+ $s[] = $f[$i];
+ }
+ } else {
+ switch ($f[$i]) {
+ case ';':
+ // Remove triple semi-colon
+ if ($i > 0 && ';' == $f[$i - 1] && $i + 1 < $len && ';' == $f[$i + 1]) {
+ $f[$i] = $f[$i + 1] = '/';
+ } else {
+ $code[++$j] = ';';
+ break;
+ }
+
+ case '/':
+ if ('*' == $f[$i + 1]) {
+ ++$i;
+ $instr = '*';
+
+ if ($this->keepImportantComments && '!' == $f[$i + 1]) {
+ ++$i;
+ // no break here
+ } else {
+ break;
+ }
+ } elseif ('/' == $f[$i + 1]) {
+ ++$i;
+ $instr = '//';
+ break;
+ } else {
+ $a = $j && (' ' == $code[$j] || "\x7F" == $code[$j]) ? $code[$j - 1] : $code[$j];
+ if (false !== strpos('-!%&;<=>~:^+|,()*?[{} ', $a)
+ || (false !== strpos('oenfd', $a)
+ && preg_match(
+ "'(?<![\$.a-zA-Z0-9_])(do|else|return|typeof|yield[ \x7F]?\*?)[ \x7F]?$'",
+ substr($code, $j - 7, 8)
+ ))
+ ) {
+ if (')' === $a && $j > 1) {
+ $a = 1;
+ $k = $j - (' ' == $code[$j] || "\x7F" == $code[$j]) - 1;
+ while ($k >= 0 && $a) {
+ if ('(' === $code[$k]) {
+ --$a;
+ } elseif (')' === $code[$k]) {
+ ++$a;
+ }
+ --$k;
+ }
+ if (!preg_match("'(?<![\$.a-zA-Z0-9_])(if|for|while)[ \x7F]?$'", substr($code, 0, $k + 1))) {
+ $code[++$j] = '/';
+ break;
+ }
+ }
+
+ $key = "//''\"\"".$K++.$instr = "/'";
+ $a = $j;
+ $code .= $key;
+ while (isset($key[++$j - $a - 1])) {
+ $code[$j] = $key[$j - $a - 1];
+ }
+ --$j;
+ isset($s) && ($s = implode('', $s)) && $cc_on && $this->restoreCc($s);
+ $strings[$key] = array('/');
+ $s = &$strings[$key];
+ } else {
+ $code[++$j] = '/';
+ }
+
+ break;
+ }
+
+ case "'":
+ case '"':
+ $instr = $f[$i];
+ $key = "//''\"\"".$K++.('!' == $instr ? ']' : "'");
+ $a = $j;
+ $code .= $key;
+ while (isset($key[++$j - $a - 1])) {
+ $code[$j] = $key[$j - $a - 1];
+ }
+ --$j;
+ isset($s) && ($s = implode('', $s)) && $cc_on && $this->restoreCc($s);
+ $strings[$key] = array();
+ $s = &$strings[$key];
+ '!' == $instr && $s[] = "\r/*!";
+
+ break;
+
+ case "\n":
+ if ($j > 3) {
+ if (' ' == $code[$j] || "\x7F" == $code[$j]) {
+ --$j;
+ }
+
+ $code[++$j] =
+ false !== strpos('kend+-', $code[$j - 1])
+ && preg_match(
+ "'(?:\+\+|--|(?<![\$.a-zA-Z0-9_])(break|continue|return|yield[ \x7F]?\*?))[ \x7F]?$'",
+ substr($code, $j - 8, 9)
+ )
+ ? ';' : "\x7F";
+
+ break;
+ }
+
+ case "\t": $f[$i] = ' ';
+ case ' ':
+ if (!$j || ' ' == $code[$j] || "\x7F" == $code[$j]) {
+ break;
+ }
+
+ default:
+ $code[++$j] = $f[$i];
+ }
+ }
+ }
+
+ isset($s) && ($s = implode('', $s)) && $cc_on && $this->restoreCc($s);
+ unset($s);
+
+ $code = substr($code, 0, $j + 1);
+ $cc_on && $this->restoreCc($code, false);
+
+ // Protect wanted spaces and remove unwanted ones
+ $code = strtr($code, "\x7F", ' ');
+ $code = str_replace('- -', "-\x7F-", $code);
+ $code = str_replace('+ +', "+\x7F+", $code);
+ $code = preg_replace("'(\d)\s+\.\s*([a-zA-Z\$_[(])'", "$1\x7F.$2", $code);
+ $code = preg_replace("# ([-!%&;<=>~:.^+|,()*?[\]{}/']+)#", '$1', $code);
+ $code = preg_replace("#([-!%&;<=>~:.^+|,()*?[\]{}/]+) #", '$1', $code);
+ $cc_on && $code = preg_replace_callback("'//[^\'].*?@#3'", function ($m) { return strtr($m[0], ' ', "\x7F"); }, $code);
+
+ // Replace new Array/Object by []/{}
+ false !== strpos($code, 'new Array') && $code = preg_replace("'new Array(?:\(\)|([;\])},:]))'", '[]$1', $code);
+ false !== strpos($code, 'new Object') && $code = preg_replace("'new Object(?:\(\)|([;\])},:]))'", '{}$1', $code);
+
+ // Add missing semi-colons after curly braces
+ // This adds more semi-colons than strictly needed,
+ // but it seems that later gzipping is favorable to the repetition of "};"
+ $code = preg_replace("'\}(?![:,;.()\[\]}\|&]|(else|catch|finally|while)[^\$.a-zA-Z0-9_])'", '};', $code);
+
+ // Tag possible empty instruction for easy detection
+ $code = preg_replace("'(?<![\$.a-zA-Z0-9_])if\('", '1#(', $code);
+ $code = preg_replace("'(?<![\$.a-zA-Z0-9_])for\('", '2#(', $code);
+ $code = preg_replace("'(?<![\$.a-zA-Z0-9_])while\('", '3#(', $code);
+
+ $forPool = array();
+ $instrPool = array();
+ $s = 0;
+
+ $f = array();
+ $j = -1;
+
+ // Remove as much semi-colon as possible
+ $len = strlen($code);
+ for ($i = 0; $i < $len; ++$i) {
+ switch ($code[$i]) {
+ case '(':
+ if ($j >= 0 && "\n" == $f[$j]) {
+ $f[$j] = ';';
+ }
+
+ ++$s;
+
+ if ($i && '#' == $code[$i - 1]) {
+ $instrPool[$s - 1] = 1;
+ if ('2' == $code[$i - 2]) {
+ $forPool[$s] = 1;
+ }
+ }
+
+ $f[++$j] = '(';
+ break;
+
+ case ']':
+ case ')':
+ if ($i + 1 < $len && !isset($forPool[$s]) && !isset($instrPool[$s - 1]) && preg_match("'[a-zA-Z0-9_\$]'", $code[$i + 1])) {
+ $f[$j] .= $code[$i];
+ $f[++$j] = "\n";
+ } else {
+ $f[++$j] = $code[$i];
+ }
+
+ if (')' == $code[$i]) {
+ unset($forPool[$s]);
+ --$s;
+ }
+
+ continue 2;
+
+ case '}':
+ if ("\n" == $f[$j]) {
+ $f[$j] = '}';
+ } else {
+ $f[++$j] = '}';
+ }
+ break;
+
+ case ';':
+ if (isset($forPool[$s]) || isset($instrPool[$s])) {
+ $f[++$j] = ';';
+ } elseif ($j >= 0 && "\n" != $f[$j] && ';' != $f[$j]) {
+ $f[++$j] = "\n";
+ }
+
+ break;
+
+ case '#':
+ switch ($f[$j]) {
+ case '1': $f[$j] = 'if'; break 2;
+ case '2': $f[$j] = 'for'; break 2;
+ case '3': $f[$j] = 'while'; break 2;
+ }
+
+ case '[';
+ if ($j >= 0 && "\n" == $f[$j]) {
+ $f[$j] = ';';
+ }
+
+ default: $f[++$j] = $code[$i];
+ }
+
+ unset($instrPool[$s]);
+ }
+
+ $f = implode('', $f);
+ $cc_on && $f = str_replace('@#3', "\r", $f);
+
+ // Fix "else ;" empty instructions
+ $f = preg_replace("'(?<![\$.a-zA-Z0-9_])else\n'", "\n", $f);
+
+ $r1 = array( // keywords with a direct object
+ 'case','delete','do','else','function','in','instanceof','of','break',
+ 'new','return','throw','typeof','var','void','yield','let','if',
+ 'const','get','set',
+ );
+
+ $r2 = array( // keywords with a subject
+ 'in','instanceof','of',
+ );
+
+ // Fix missing semi-colons
+ $f = preg_replace("'(?<!(?<![a-zA-Z0-9_\$])".implode(')(?<!(?<![a-zA-Z0-9_\$])', $r1).') (?!('.implode('|', $r2).")(?![a-zA-Z0-9_\$]))'", "\n", $f);
+ $f = preg_replace("'(?<!(?<![a-zA-Z0-9_\$])do)(?<!(?<![a-zA-Z0-9_\$])else) if\('", "\nif(", $f);
+ $f = preg_replace("'(?<=--|\+\+)(?<![a-zA-Z0-9_\$])(".implode('|', $r1).")(?![a-zA-Z0-9_\$])'", "\n$1", $f);
+ $f = preg_replace("'(?<![a-zA-Z0-9_\$])for\neach\('", 'for each(', $f);
+ $f = preg_replace("'(?<![a-zA-Z0-9_\$])\n(".implode('|', $r2).")(?![a-zA-Z0-9_\$])'", '$1', $f);
+
+ // Merge strings
+ if ($q["'"] > $q['"']) {
+ $q = array($q[1], $q[0]);
+ }
+ $f = preg_replace("#//''\"\"[0-9]+'#", $q[0].'$0'.$q[0], $f);
+ strpos($f, $q[0].'+'.$q[0]) && $f = str_replace($q[0].'+'.$q[0], '', $f);
+ $len = count($strings);
+ foreach ($strings as $r1 => &$r2) {
+ $r2 = "/'" == substr($r1, -2)
+ ? str_replace(array("\\'", '\\"'), array("'", '"'), $r2)
+ : str_replace('\\'.$q[1], $q[1], $r2);
+ }
+
+ // Restore wanted spaces
+ $f = strtr($f, "\x7F", ' ');
+
+ return array($f, $strings);
+ }
+
+ protected function extractClosures($code)
+ {
+ $code = ';'.$code;
+
+ $this->argFreq[-1] += substr_count($code, '}catch(');
+
+ if ($this->argFreq[-1]) {
+ // Special catch scope handling
+
+ // FIXME: this implementation doesn't work with nested catch scopes who need
+ // access to their parent's caught variable (but who needs that?).
+
+ $f = preg_split("@}catch\(({$this->varRx})@", $code, -1, PREG_SPLIT_DELIM_CAPTURE);
+
+ $code = 'catch$scope$var'.mt_rand();
+ $this->specialVarRx = $this->specialVarRx ? '(?:'.$this->specialVarRx.'|'.preg_quote($code).')' : preg_quote($code);
+ $i = count($f) - 1;
+
+ while ($i) {
+ $c = 1;
+ $j = 0;
+ $l = strlen($f[$i]);
+
+ while ($c && $j < $l) {
+ $s = $f[$i][$j++];
+ $c += '(' == $s ? 1 : (')' == $s ? -1 : 0);
+ }
+
+ if (!$c) {
+ do {
+ $s = $f[$i][$j++];
+ $c += '{' == $s ? 1 : ('}' == $s ? -1 : 0);
+ } while ($c && $j < $l);
+ }
+
+ $c = preg_quote($f[$i - 1], '#');
+ $f[$i - 2] .= '}catch('.preg_replace("#([.,{]?)(?<![a-zA-Z0-9_\$@]){$c}\\b#", '$1'.$code, $f[$i - 1].substr($f[$i], 0, $j)).substr($f[$i], $j);
+
+ unset($f[$i--], $f[$i--]);
+ }
+
+ $code = $f[0];
+ }
+
+ $f = preg_split("'(?<![a-zA-Z0-9_\$])((?:function[ (]|get |set ).*?\{)'", $code, -1, PREG_SPLIT_DELIM_CAPTURE);
+ $i = count($f) - 1;
+ $closures = array();
+
+ while ($i) {
+ $c = 1;
+ $j = 0;
+ $l = strlen($f[$i]);
+
+ while ($c && $j < $l) {
+ $s = $f[$i][$j++];
+ $c += '{' == $s ? 1 : ('}' == $s ? -1 : 0);
+ }
+
+ switch (substr($f[$i - 2], -1)) {
+ default:
+ if (false !== $c = strpos($f[$i - 1], ' ', 8)) {
+ break;
+ }
+ case false: case "\n": case ';': case '{': case '}': case ')': case ']':
+ $c = strpos($f[$i - 1], '(', 4);
+ }
+
+ $l = "//''\"\"#$i'";
+ $code = substr($f[$i - 1], $c);
+ $closures[$l] = $code.substr($f[$i], 0, $j);
+ $f[$i - 2] .= substr($f[$i - 1], 0, $c).$l.substr($f[$i], $j);
+
+ if ('(){' !== $code) {
+ $j = substr_count($code, ',');
+ do {
+ isset($this->argFreq[$j]) ? ++$this->argFreq[$j] : $this->argFreq[$j] = 1;
+ } while ($j--);
+ }
+
+ $i -= 2;
+ }
+
+ return array($f[0], $closures);
+ }
+
+ protected function makeVars($closure, &$tree, $key)
+ {
+ $tree['code'] = &$closure;
+ $tree['nfe'] = false;
+ $tree['used'] = array();
+ $tree['local'] = array();
+
+ // Replace multiple "var" declarations by a single one
+ $closure = preg_replace_callback("'(?<=[\n\{\}])var [^\n\{\};]+(?:\nvar [^\n\{\};]+)+'", array($this, 'mergeVarDeclarations'), $closure);
+
+ // Get all local vars (functions, arguments and "var" prefixed)
+
+ $vars = &$tree['local'];
+
+ if (preg_match("'^( [^(]*)?\((.*?)\)\{'", $closure, $v)) {
+ if ($v[1]) {
+ $vars[$tree['nfe'] = substr($v[1], 1)] = -1;
+ $tree['parent']['local'][';'.$key] = &$vars[$tree['nfe']];
+ }
+
+ if ($v[2]) {
+ $i = 0;
+ $v = explode(',', $v[2]);
+ foreach ($v as $w) {
+ $vars[$w] = $this->argFreq[$i++] - 1; // Give a bonus to argument variables
+ }
+ }
+ }
+
+ $v = preg_split("'(?<![\$.a-zA-Z0-9_])var '", $closure);
+ if ($i = count($v) - 1) {
+ $w = array();
+
+ while ($i) {
+ $j = $c = 0;
+ $l = strlen($v[$i]);
+
+ while ($j < $l) {
+ switch ($v[$i][$j]) {
+ case '(': case '[': case '{':
+ ++$c;
+ break;
+
+ case ')': case ']': case '}':
+ if ($c-- <= 0) {
+ break 2;
+ }
+ break;
+
+ case ';': case "\n":
+ if (!$c) {
+ break 2;
+ }
+
+ default:
+ $c || $w[] = $v[$i][$j];
+ }
+
+ ++$j;
+ }
+
+ $w[] = ',';
+ --$i;
+ }
+
+ $v = explode(',', implode('', $w));
+ foreach ($v as $w) {
+ if (preg_match("'^{$this->varRx}'", $w, $v)) {
+ isset($vars[$v[0]]) || $vars[$v[0]] = 0;
+ }
+ }
+ }
+
+ if (preg_match_all("@function ({$this->varRx})//''\"\"#@", $closure, $v)) {
+ foreach ($v[1] as $w) {
+ isset($vars[$w]) || $vars[$w] = 0;
+ }
+ }
+
+ if ($this->argFreq[-1] && preg_match_all("@}catch\(({$this->varRx})@", $closure, $v)) {
+ $v[0] = array();
+ foreach ($v[1] as $w) {
+ isset($v[0][$w]) ? ++$v[0][$w] : $v[0][$w] = 1;
+ }
+ foreach ($v[0] as $w => $v) {
+ $vars[$w] = $this->argFreq[-1] - $v;
+ }
+ }
+
+ // Get all used vars, local and non-local
+
+ $vars = &$tree['used'];
+
+ if (preg_match_all("#([.,{]?(?:[gs]et )?)(?<![a-zA-Z0-9_\$])({$this->varRx})(:?)#", $closure, $w, PREG_SET_ORDER)) {
+ foreach ($w as $k) {
+ if (isset($k[1][0]) && (',' === $k[1][0] || '{' === $k[1][0])) {
+ if (':' === $k[3]) {
+ $k = '.'.$k[2];
+ } elseif ('get ' === substr($k[1], 1, 4) || 'set ' === substr($k[1], 1, 4)) {
+ ++$this->charFreq[ord($k[1][1])]; // "g" or "s"
+ ++$this->charFreq[101]; // "e"
+ ++$this->charFreq[116]; // "t"
+ $k = '.'.$k[2];
+ } else {
+ $k = $k[2];
+ }
+ } else {
+ $k = $k[1].$k[2];
+ }
+
+ isset($vars[$k]) ? ++$vars[$k] : $vars[$k] = 1;
+ }
+ }
+
+ if (preg_match_all("#//''\"\"[0-9]+(?:['!]|/')#", $closure, $w)) {
+ foreach ($w[0] as $a) {
+ $v = "'" === substr($a, -1) && "/'" !== substr($a, -2) && $this->specialVarRx
+ ? preg_split("#([.,{]?(?:[gs]et )?(?<![a-zA-Z0-9_\$@]){$this->specialVarRx}:?)#", $this->strings[$a], -1, PREG_SPLIT_DELIM_CAPTURE)
+ : array($this->strings[$a]);
+ $a = count($v);
+
+ for ($i = 0; $i < $a; ++$i) {
+ $k = $v[$i];
+
+ if (1 === $i % 2) {
+ if (',' === $k[0] || '{' === $k[0]) {
+ if (':' === substr($k, -1)) {
+ $k = '.'.substr($k, 1, -1);
+ } elseif ('get ' === substr($k, 1, 4) || 'set ' === substr($k, 1, 4)) {
+ ++$this->charFreq[ord($k[1])]; // "g" or "s"
+ ++$this->charFreq[101]; // "e"
+ ++$this->charFreq[116]; // "t"
+ $k = '.'.substr($k, 5);
+ } else {
+ $k = substr($k, 1);
+ }
+ } elseif (':' === substr($k, -1)) {
+ $k = substr($k, 0, -1);
+ }
+
+ $w = &$tree;
+
+ while (isset($w['parent']) && !(isset($w['used'][$k]) || isset($w['local'][$k]))) {
+ $w = &$w['parent'];
+ }
+
+ (isset($w['used'][$k]) || isset($w['local'][$k])) && (isset($vars[$k]) ? ++$vars[$k] : $vars[$k] = 1);
+
+ unset($w);
+ }
+
+ if (0 === $i % 2 || !isset($vars[$k])) {
+ foreach (count_chars($v[$i], 1) as $k => $w) {
+ $this->charFreq[$k] += $w;
+ }
+ }
+ }
+ }
+ }
+
+ // Propagate the usage number to parents
+
+ foreach ($vars as $w => $a) {
+ $k = &$tree;
+ $chain = array();
+ do {
+ $vars = &$k['local'];
+ $chain[] = &$k;
+ if (isset($vars[$w])) {
+ unset($k['used'][$w]);
+ if (isset($vars[$w])) {
+ $vars[$w] += $a;
+ } else {
+ $vars[$w] = $a;
+ }
+ $a = false;
+ break;
+ }
+ } while ($k['parent'] && $k = &$k['parent']);
+
+ if ($a && !$k['parent']) {
+ if (isset($vars[$w])) {
+ $vars[$w] += $a;
+ } else {
+ $vars[$w] = $a;
+ }
+ }
+
+ if (isset($tree['used'][$w]) && isset($vars[$w])) {
+ foreach ($chain as &$b) {
+ isset($b['local'][$w]) || $b['used'][$w] = &$vars[$w];
+ }
+ }
+ }
+
+ // Analyse childs
+
+ $tree['childs'] = array();
+ $vars = &$tree['childs'];
+
+ if (preg_match_all("@//''\"\"#[0-9]+'@", $closure, $w)) {
+ foreach ($w[0] as $a) {
+ $vars[$a] = array('parent' => &$tree);
+ $this->makeVars($this->closures[$a], $vars[$a], $a);
+ }
+ }
+ }
+
+ protected function mergeVarDeclarations($m)
+ {
+ return str_replace("\nvar ", ',', $m[0]);
+ }
+
+ protected function renameVars(&$tree, $root)
+ {
+ if ($root) {
+ $tree['local'] += $tree['used'];
+ $tree['used'] = array();
+
+ foreach ($tree['local'] as $k => $v) {
+ if ('.' == $k[0]) {
+ $k = substr($k, 1);
+ }
+
+ if ('true' === $k) {
+ $this->charFreq[48] += $v;
+ } elseif ('false' === $k) {
+ $this->charFreq[49] += $v;
+ } elseif (!$this->specialVarRx || !preg_match("#^{$this->specialVarRx}$#", $k)) {
+ foreach (count_chars($k, 1) as $k => $w) {
+ $this->charFreq[$k] += $w * $v;
+ }
+ } elseif (2 == strlen($k)) {
+ $tree['used'][] = $k[1];
+ }
+ }
+
+ $this->charFreq = $this->rsort($this->charFreq);
+
+ $this->str0 = '';
+ $this->str1 = '';
+
+ foreach ($this->charFreq as $k => $v) {
+ if (!$v) {
+ break;
+ }
+
+ $v = chr($k);
+
+ if ((64 < $k && $k < 91) || (96 < $k && $k < 123)) { // A-Z a-z
+ $this->str0 .= $v;
+ $this->str1 .= $v;
+ } elseif (47 < $k && $k < 58) { // 0-9
+ $this->str1 .= $v;
+ }
+ }
+
+ if ('' === $this->str0) {
+ $this->str0 = 'claspemitdbfrugnjvhowkxqyzCLASPEMITDBFRUGNJVHOWKXQYZ';
+ $this->str1 = $this->str0.'0123456789';
+ }
+
+ foreach ($tree['local'] as $var => $root) {
+ if ('.' != substr($var, 0, 1) && isset($tree['local'][".{$var}"])) {
+ $tree['local'][$var] += $tree['local'][".{$var}"];
+ }
+ }
+
+ foreach ($tree['local'] as $var => $root) {
+ if ('.' == substr($var, 0, 1) && isset($tree['local'][substr($var, 1)])) {
+ $tree['local'][$var] = $tree['local'][substr($var, 1)];
+ }
+ }
+
+ $tree['local'] = $this->rsort($tree['local']);
+
+ foreach ($tree['local'] as $var => $root) {
+ switch (substr($var, 0, 1)) {
+ case '.':
+ if (!isset($tree['local'][substr($var, 1)])) {
+ $tree['local'][$var] = '#'.($this->specialVarRx && 3 < strlen($var) && preg_match("'^\.{$this->specialVarRx}$'", $var) ? $this->getNextName($tree).'$' : substr($var, 1));
+ }
+ break;
+
+ case ';': $tree['local'][$var] = 0 === $root ? '' : $this->getNextName($tree);
+ case '#': break;
+
+ default:
+ $root = $this->specialVarRx && 2 < strlen($var) && preg_match("'^{$this->specialVarRx}$'", $var) ? $this->getNextName($tree).'$' : $var;
+ $tree['local'][$var] = $root;
+ if (isset($tree['local'][".{$var}"])) {
+ $tree['local'][".{$var}"] = '#'.$root;
+ }
+ }
+ }
+
+ foreach ($tree['local'] as $var => $root) {
+ $tree['local'][$var] = preg_replace("'^#'", '.', $tree['local'][$var]);
+ }
+ } else {
+ $tree['local'] = $this->rsort($tree['local']);
+ if (false !== $tree['nfe']) {
+ $tree['used'][] = $tree['local'][$tree['nfe']];
+ }
+
+ foreach ($tree['local'] as $var => $root) {
+ if ($tree['nfe'] !== $var) {
+ $tree['local'][$var] = 0 === $root ? '' : $this->getNextName($tree);
+ }
+ }
+ }
+
+ $this->local_tree = &$tree['local'];
+ $this->used_tree = &$tree['used'];
+
+ $tree['code'] = preg_replace_callback("#[.,{ ]?(?:[gs]et )?(?<![a-zA-Z0-9_\$@]){$this->varRx}:?#", array($this, 'getNewName'), $tree['code']);
+
+ if ($this->specialVarRx && preg_match_all("#//''\"\"[0-9]+'#", $tree['code'], $b)) {
+ foreach ($b[0] as $a) {
+ $this->strings[$a] = preg_replace_callback(
+ "#[.,{]?(?:[gs]et )?(?<![a-zA-Z0-9_\$@]){$this->specialVarRx}:?#",
+ array($this, 'getNewName'),
+ $this->strings[$a]
+ );
+ }
+ }
+
+ foreach ($tree['childs'] as $a => &$b) {
+ $this->renameVars($b, false);
+ $tree['code'] = str_replace($a, $b['code'], $tree['code']);
+ unset($tree['childs'][$a]);
+ }
+ }
+
+ protected function getNewName($m)
+ {
+ $m = $m[0];
+
+ $pre = '.' === $m[0] ? '.' : '';
+ $post = '';
+
+ if (',' === $m[0] || '{' === $m[0] || ' ' === $m[0]) {
+ $pre = $m[0];
+
+ if (':' === substr($m, -1)) {
+ $post = ':';
+ $m = (' ' !== $m[0] ? '.' : '').substr($m, 1, -1);
+ } elseif ('get ' === substr($m, 1, 4) || 'set ' === substr($m, 1, 4)) {
+ $pre .= substr($m, 1, 4);
+ $m = '.'.substr($m, 5);
+ } else {
+ $m = substr($m, 1);
+ }
+ } elseif (':' === substr($m, -1)) {
+ $post = ':';
+ $m = substr($m, 0, -1);
+ }
+
+ $post = (isset($this->reserved[$m])
+ ? ('true' === $m ? '!0' : ('false' === $m ? '!1' : $m))
+ : (
+ isset($this->local_tree[$m])
+ ? $this->local_tree[$m]
+ : (
+ isset($this->used_tree[$m])
+ ? $this->used_tree[$m]
+ : $m
+ )
+ )
+ ).$post;
+
+ return '' === $post ? '' : ($pre.('.' === $post[0] ? substr($post, 1) : $post));
+ }
+
+ protected function getNextName(&$tree = array(), &$counter = false)
+ {
+ if (false === $counter) {
+ $counter = &$tree['counter'];
+ isset($counter) || $counter = -1;
+ $exclude = array_flip($tree['used']);
+ } else {
+ $exclude = $tree;
+ }
+
+ ++$counter;
+
+ $len0 = strlen($this->str0);
+ $len1 = strlen($this->str0);
+
+ $name = $this->str0[$counter % $len0];
+
+ $i = intval($counter / $len0) - 1;
+ while ($i >= 0) {
+ $name .= $this->str1[ $i % $len1 ];
+ $i = intval($i / $len1) - 1;
+ }
+
+ return !(isset($this->reserved[$name]) || isset($exclude[$name])) ? $name : $this->getNextName($exclude, $counter);
+ }
+
+ protected function restoreCc(&$s, $lf = true)
+ {
+ $lf && $s = str_replace('@#3', '', $s);
+
+ $s = str_replace('@#1', '@*/', $s);
+ $s = str_replace('2#@', '//@', $s);
+ $s = str_replace('1#@', '/*@', $s);
+ $s = str_replace('##', '#', $s);
+ }
+
+ private function rsort($array)
+ {
+ if (!$array) {
+ return $array;
+ }
+
+ $i = 0;
+ $tuples = array();
+ foreach ($array as $k => &$v) {
+ $tuples[] = array(++$i, $k, &$v);
+ }
+
+ usort($tuples, function ($a, $b) {
+ if ($b[2] > $a[2]) {
+ return 1;
+ }
+ if ($b[2] < $a[2]) {
+ return -1;
+ }
+ if ($b[0] > $a[0]) {
+ return -1;
+ }
+ if ($b[0] < $a[0]) {
+ return 1;
+ }
+
+ return 0;
+ });
+
+ $array = array();
+
+ foreach ($tuples as $t) {
+ $array[$t[1]] = &$t[2];
+ }
+
+ return $array;
+ }
+}
+?>+
\ No newline at end of file
diff --git a/util/Less.php b/util/Less.php
@@ -0,0 +1,10524 @@
+<?php
+
+/**
+ * Class for parsing and compiling less files into css
+ *
+ * @package Less
+ * @subpackage parser
+ *
+ */
+class Less_Parser{
+
+
+ /**
+ * Default parser options
+ */
+ public static $default_options = array(
+ 'compress' => false, // option - whether to compress
+ 'strictUnits' => false, // whether units need to evaluate correctly
+ 'strictMath' => false, // whether math has to be within parenthesis
+ 'relativeUrls' => true, // option - whether to adjust URL's to be relative
+ 'urlArgs' => '', // whether to add args into url tokens
+ 'numPrecision' => 8,
+
+ 'import_dirs' => array(),
+ 'import_callback' => null,
+ 'cache_dir' => null,
+ 'cache_method' => 'php', // false, 'serialize', 'php', 'var_export', 'callback';
+ 'cache_callback_get' => null,
+ 'cache_callback_set' => null,
+
+ 'sourceMap' => false, // whether to output a source map
+ 'sourceMapBasepath' => null,
+ 'sourceMapWriteTo' => null,
+ 'sourceMapURL' => null,
+
+ 'indentation' => ' ',
+
+ 'plugins' => array(),
+
+ );
+
+ public static $options = array();
+
+
+ private $input; // Less input string
+ private $input_len; // input string length
+ private $pos; // current index in `input`
+ private $saveStack = array(); // holds state for backtracking
+ private $furthest;
+ private $mb_internal_encoding = ''; // for remember exists value of mbstring.internal_encoding
+
+ /**
+ * @var Less_Environment
+ */
+ private $env;
+
+ protected $rules = array();
+
+ private static $imports = array();
+
+ public static $has_extends = false;
+
+ public static $next_id = 0;
+
+ /**
+ * Filename to contents of all parsed the files
+ *
+ * @var array
+ */
+ public static $contentsMap = array();
+
+
+ /**
+ * @param Less_Environment|array|null $env
+ */
+ public function __construct( $env = null ){
+
+ // Top parser on an import tree must be sure there is one "env"
+ // which will then be passed around by reference.
+ if( $env instanceof Less_Environment ){
+ $this->env = $env;
+ }else{
+ $this->SetOptions(Less_Parser::$default_options);
+ $this->Reset( $env );
+ }
+
+ // mbstring.func_overload > 1 bugfix
+ // The encoding value must be set for each source file,
+ // therefore, to conserve resources and improve the speed of this design is taken here
+ if (ini_get('mbstring.func_overload')) {
+ $this->mb_internal_encoding = ini_get('mbstring.internal_encoding');
+ @ini_set('mbstring.internal_encoding', 'ascii');
+ }
+
+ }
+
+
+ /**
+ * Reset the parser state completely
+ *
+ */
+ public function Reset( $options = null ){
+ $this->rules = array();
+ self::$imports = array();
+ self::$has_extends = false;
+ self::$imports = array();
+ self::$contentsMap = array();
+
+ $this->env = new Less_Environment($options);
+ $this->env->Init();
+
+ //set new options
+ if( is_array($options) ){
+ $this->SetOptions(Less_Parser::$default_options);
+ $this->SetOptions($options);
+ }
+ }
+
+ /**
+ * Set one or more compiler options
+ * options: import_dirs, cache_dir, cache_method
+ *
+ */
+ public function SetOptions( $options ){
+ foreach($options as $option => $value){
+ $this->SetOption($option,$value);
+ }
+ }
+
+ /**
+ * Set one compiler option
+ *
+ */
+ public function SetOption($option,$value){
+
+ switch($option){
+
+ case 'import_dirs':
+ $this->SetImportDirs($value);
+ return;
+
+ case 'cache_dir':
+ if( is_string($value) ){
+ Less_Cache::SetCacheDir($value);
+ Less_Cache::CheckCacheDir();
+ }
+ return;
+ }
+
+ Less_Parser::$options[$option] = $value;
+ }
+
+ /**
+ * Registers a new custom function
+ *
+ * @param string $name function name
+ * @param callable $callback callback
+ */
+ public function registerFunction($name, $callback) {
+ $this->env->functions[$name] = $callback;
+ }
+
+ /**
+ * Removed an already registered function
+ *
+ * @param string $name function name
+ */
+ public function unregisterFunction($name) {
+ if( isset($this->env->functions[$name]) )
+ unset($this->env->functions[$name]);
+ }
+
+
+ /**
+ * Get the current css buffer
+ *
+ * @return string
+ */
+ public function getCss(){
+
+ $precision = ini_get('precision');
+ @ini_set('precision',16);
+ $locale = setlocale(LC_NUMERIC, 0);
+ setlocale(LC_NUMERIC, "C");
+
+ try {
+
+ $root = new Less_Tree_Ruleset(array(), $this->rules );
+ $root->root = true;
+ $root->firstRoot = true;
+
+
+ $this->PreVisitors($root);
+
+ self::$has_extends = false;
+ $evaldRoot = $root->compile($this->env);
+
+
+
+ $this->PostVisitors($evaldRoot);
+
+ if( Less_Parser::$options['sourceMap'] ){
+ $generator = new Less_SourceMap_Generator($evaldRoot, Less_Parser::$contentsMap, Less_Parser::$options );
+ // will also save file
+ // FIXME: should happen somewhere else?
+ $css = $generator->generateCSS();
+ }else{
+ $css = $evaldRoot->toCSS();
+ }
+
+ if( Less_Parser::$options['compress'] ){
+ $css = preg_replace('/(^(\s)+)|((\s)+$)/', '', $css);
+ }
+
+ } catch (Exception $exc) {
+ // Intentional fall-through so we can reset environment
+ }
+
+ //reset php settings
+ @ini_set('precision',$precision);
+ setlocale(LC_NUMERIC, $locale);
+
+ // If you previously defined $this->mb_internal_encoding
+ // is required to return the encoding as it was before
+ if ($this->mb_internal_encoding != '') {
+ @ini_set("mbstring.internal_encoding", $this->mb_internal_encoding);
+ $this->mb_internal_encoding = '';
+ }
+
+ // Rethrow exception after we handled resetting the environment
+ if (!empty($exc)) {
+ throw $exc;
+ }
+
+
+
+ return $css;
+ }
+
+ /**
+ * Run pre-compile visitors
+ *
+ */
+ private function PreVisitors($root){
+
+ if( Less_Parser::$options['plugins'] ){
+ foreach(Less_Parser::$options['plugins'] as $plugin){
+ if( !empty($plugin->isPreEvalVisitor) ){
+ $plugin->run($root);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Run post-compile visitors
+ *
+ */
+ private function PostVisitors($evaldRoot){
+
+ $visitors = array();
+ $visitors[] = new Less_Visitor_joinSelector();
+ if( self::$has_extends ){
+ $visitors[] = new Less_Visitor_processExtends();
+ }
+ $visitors[] = new Less_Visitor_toCSS();
+
+
+ if( Less_Parser::$options['plugins'] ){
+ foreach(Less_Parser::$options['plugins'] as $plugin){
+ if( property_exists($plugin,'isPreEvalVisitor') && $plugin->isPreEvalVisitor ){
+ continue;
+ }
+
+ if( property_exists($plugin,'isPreVisitor') && $plugin->isPreVisitor ){
+ array_unshift( $visitors, $plugin);
+ }else{
+ $visitors[] = $plugin;
+ }
+ }
+ }
+
+
+ for($i = 0; $i < count($visitors); $i++ ){
+ $visitors[$i]->run($evaldRoot);
+ }
+
+ }
+
+
+ /**
+ * Parse a Less string into css
+ *
+ * @param string $str The string to convert
+ * @param string $uri_root The url of the file
+ * @return Less_Tree_Ruleset|Less_Parser
+ */
+ public function parse( $str, $file_uri = null ){
+
+ if( !$file_uri ){
+ $uri_root = '';
+ $filename = 'anonymous-file-'.Less_Parser::$next_id++.'.less';
+ }else{
+ $file_uri = self::WinPath($file_uri);
+ $filename = $file_uri;
+ $uri_root = dirname($file_uri);
+ }
+
+ $previousFileInfo = $this->env->currentFileInfo;
+ $uri_root = self::WinPath($uri_root);
+ $this->SetFileInfo($filename, $uri_root);
+
+ $this->input = $str;
+ $this->_parse();
+
+ if( $previousFileInfo ){
+ $this->env->currentFileInfo = $previousFileInfo;
+ }
+
+ return $this;
+ }
+
+
+ /**
+ * Parse a Less string from a given file
+ *
+ * @throws Less_Exception_Parser
+ * @param string $filename The file to parse
+ * @param string $uri_root The url of the file
+ * @param bool $returnRoot Indicates whether the return value should be a css string a root node
+ * @return Less_Tree_Ruleset|Less_Parser
+ */
+ public function parseFile( $filename, $uri_root = '', $returnRoot = false){
+
+ if( !file_exists($filename) ){
+ $this->Error(sprintf('File `%s` not found.', $filename));
+ }
+
+
+ // fix uri_root?
+ // Instead of The mixture of file path for the first argument and directory path for the second argument has bee
+ if( !$returnRoot && !empty($uri_root) && basename($uri_root) == basename($filename) ){
+ $uri_root = dirname($uri_root);
+ }
+
+
+ $previousFileInfo = $this->env->currentFileInfo;
+
+
+ if( $filename ){
+ $filename = self::WinPath(realpath($filename));
+ }
+ $uri_root = self::WinPath($uri_root);
+
+ $this->SetFileInfo($filename, $uri_root);
+
+ self::AddParsedFile($filename);
+
+ if( $returnRoot ){
+ $rules = $this->GetRules( $filename );
+ $return = new Less_Tree_Ruleset(array(), $rules );
+ }else{
+ $this->_parse( $filename );
+ $return = $this;
+ }
+
+ if( $previousFileInfo ){
+ $this->env->currentFileInfo = $previousFileInfo;
+ }
+
+ return $return;
+ }
+
+
+ /**
+ * Allows a user to set variables values
+ * @param array $vars
+ * @return Less_Parser
+ */
+ public function ModifyVars( $vars ){
+
+ $this->input = Less_Parser::serializeVars( $vars );
+ $this->_parse();
+
+ return $this;
+ }
+
+
+ /**
+ * @param string $filename
+ */
+ public function SetFileInfo( $filename, $uri_root = ''){
+
+ $filename = Less_Environment::normalizePath($filename);
+ $dirname = preg_replace('/[^\/\\\\]*$/','',$filename);
+
+ if( !empty($uri_root) ){
+ $uri_root = rtrim($uri_root,'/').'/';
+ }
+
+ $currentFileInfo = array();
+
+ //entry info
+ if( isset($this->env->currentFileInfo) ){
+ $currentFileInfo['entryPath'] = $this->env->currentFileInfo['entryPath'];
+ $currentFileInfo['entryUri'] = $this->env->currentFileInfo['entryUri'];
+ $currentFileInfo['rootpath'] = $this->env->currentFileInfo['rootpath'];
+
+ }else{
+ $currentFileInfo['entryPath'] = $dirname;
+ $currentFileInfo['entryUri'] = $uri_root;
+ $currentFileInfo['rootpath'] = $dirname;
+ }
+
+ $currentFileInfo['currentDirectory'] = $dirname;
+ $currentFileInfo['currentUri'] = $uri_root.basename($filename);
+ $currentFileInfo['filename'] = $filename;
+ $currentFileInfo['uri_root'] = $uri_root;
+
+
+ //inherit reference
+ if( isset($this->env->currentFileInfo['reference']) && $this->env->currentFileInfo['reference'] ){
+ $currentFileInfo['reference'] = true;
+ }
+
+ $this->env->currentFileInfo = $currentFileInfo;
+ }
+
+
+ /**
+ * @deprecated 1.5.1.2
+ *
+ */
+ public function SetCacheDir( $dir ){
+
+ if( !file_exists($dir) ){
+ if( mkdir($dir) ){
+ return true;
+ }
+ throw new Less_Exception_Parser('Less.php cache directory couldn\'t be created: '.$dir);
+
+ }elseif( !is_dir($dir) ){
+ throw new Less_Exception_Parser('Less.php cache directory doesn\'t exist: '.$dir);
+
+ }elseif( !is_writable($dir) ){
+ throw new Less_Exception_Parser('Less.php cache directory isn\'t writable: '.$dir);
+
+ }else{
+ $dir = self::WinPath($dir);
+ Less_Cache::$cache_dir = rtrim($dir,'/').'/';
+ return true;
+ }
+ }
+
+
+ /**
+ * Set a list of directories or callbacks the parser should use for determining import paths
+ *
+ * @param array $dirs
+ */
+ public function SetImportDirs( $dirs ){
+ Less_Parser::$options['import_dirs'] = array();
+
+ foreach($dirs as $path => $uri_root){
+
+ $path = self::WinPath($path);
+ if( !empty($path) ){
+ $path = rtrim($path,'/').'/';
+ }
+
+ if ( !is_callable($uri_root) ){
+ $uri_root = self::WinPath($uri_root);
+ if( !empty($uri_root) ){
+ $uri_root = rtrim($uri_root,'/').'/';
+ }
+ }
+
+ Less_Parser::$options['import_dirs'][$path] = $uri_root;
+ }
+ }
+
+ /**
+ * @param string $file_path
+ */
+ private function _parse( $file_path = null ){
+ $this->rules = array_merge($this->rules, $this->GetRules( $file_path ));
+ }
+
+
+ /**
+ * Return the results of parsePrimary for $file_path
+ * Use cache and save cached results if possible
+ *
+ * @param string|null $file_path
+ */
+ private function GetRules( $file_path ){
+
+ $this->SetInput($file_path);
+
+ $cache_file = $this->CacheFile( $file_path );
+ if( $cache_file ){
+ if( Less_Parser::$options['cache_method'] == 'callback' ){
+ if( is_callable(Less_Parser::$options['cache_callback_get']) ){
+ $cache = call_user_func_array(
+ Less_Parser::$options['cache_callback_get'],
+ array($this, $file_path, $cache_file)
+ );
+
+ if( $cache ){
+ $this->UnsetInput();
+ return $cache;
+ }
+ }
+
+ }elseif( file_exists($cache_file) ){
+ switch(Less_Parser::$options['cache_method']){
+
+ // Using serialize
+ // Faster but uses more memory
+ case 'serialize':
+ $cache = unserialize(file_get_contents($cache_file));
+ if( $cache ){
+ touch($cache_file);
+ $this->UnsetInput();
+ return $cache;
+ }
+ break;
+
+
+ // Using generated php code
+ case 'var_export':
+ case 'php':
+ $this->UnsetInput();
+ return include($cache_file);
+ }
+ }
+ }
+
+ $rules = $this->parsePrimary();
+
+ if( $this->pos < $this->input_len ){
+ throw new Less_Exception_Chunk($this->input, null, $this->furthest, $this->env->currentFileInfo);
+ }
+
+ $this->UnsetInput();
+
+
+ //save the cache
+ if( $cache_file ){
+ if( Less_Parser::$options['cache_method'] == 'callback' ){
+ if( is_callable(Less_Parser::$options['cache_callback_set']) ){
+ call_user_func_array(
+ Less_Parser::$options['cache_callback_set'],
+ array($this, $file_path, $cache_file, $rules)
+ );
+ }
+
+ }else{
+ //msg('write cache file');
+ switch(Less_Parser::$options['cache_method']){
+ case 'serialize':
+ file_put_contents( $cache_file, serialize($rules) );
+ break;
+ case 'php':
+ file_put_contents( $cache_file, '<?php return '.self::ArgString($rules).'; ?>' );
+ break;
+ case 'var_export':
+ //Requires __set_state()
+ file_put_contents( $cache_file, '<?php return '.var_export($rules,true).'; ?>' );
+ break;
+ }
+
+ Less_Cache::CleanCache();
+ }
+ }
+
+ return $rules;
+ }
+
+
+ /**
+ * Set up the input buffer
+ *
+ */
+ public function SetInput( $file_path ){
+
+ if( $file_path ){
+ $this->input = file_get_contents( $file_path );
+ }
+
+ $this->pos = $this->furthest = 0;
+
+ // Remove potential UTF Byte Order Mark
+ $this->input = preg_replace('/\\G\xEF\xBB\xBF/', '', $this->input);
+ $this->input_len = strlen($this->input);
+
+
+ if( Less_Parser::$options['sourceMap'] && $this->env->currentFileInfo ){
+ $uri = $this->env->currentFileInfo['currentUri'];
+ Less_Parser::$contentsMap[$uri] = $this->input;
+ }
+
+ }
+
+
+ /**
+ * Free up some memory
+ *
+ */
+ public function UnsetInput(){
+ unset($this->input, $this->pos, $this->input_len, $this->furthest);
+ $this->saveStack = array();
+ }
+
+
+ public function CacheFile( $file_path ){
+
+ if( $file_path && $this->CacheEnabled() ){
+
+ $env = get_object_vars($this->env);
+ unset($env['frames']);
+
+ $parts = array();
+ $parts[] = $file_path;
+ $parts[] = filesize( $file_path );
+ $parts[] = filemtime( $file_path );
+ $parts[] = $env;
+ $parts[] = Less_Version::cache_version;
+ $parts[] = Less_Parser::$options['cache_method'];
+ return Less_Cache::$cache_dir . Less_Cache::$prefix . base_convert( sha1(json_encode($parts) ), 16, 36) . '.lesscache';
+ }
+ }
+
+
+ static function AddParsedFile($file){
+ self::$imports[] = $file;
+ }
+
+ static function AllParsedFiles(){
+ return self::$imports;
+ }
+
+ /**
+ * @param string $file
+ */
+ static function FileParsed($file){
+ return in_array($file,self::$imports);
+ }
+
+
+ function save() {
+ $this->saveStack[] = $this->pos;
+ }
+
+ private function restore() {
+ $this->pos = array_pop($this->saveStack);
+ }
+
+ private function forget(){
+ array_pop($this->saveStack);
+ }
+
+
+ private function isWhitespace($offset = 0) {
+ return preg_match('/\s/',$this->input[ $this->pos + $offset]);
+ }
+
+ /**
+ * Parse from a token, regexp or string, and move forward if match
+ *
+ * @param array $toks
+ * @return array
+ */
+ private function match($toks){
+
+ // The match is confirmed, add the match length to `this::pos`,
+ // and consume any extra white-space characters (' ' || '\n')
+ // which come after that. The reason for this is that LeSS's
+ // grammar is mostly white-space insensitive.
+ //
+
+ foreach($toks as $tok){
+
+ $char = $tok[0];
+
+ if( $char === '/' ){
+ $match = $this->MatchReg($tok);
+
+ if( $match ){
+ return count($match) === 1 ? $match[0] : $match;
+ }
+
+ }elseif( $char === '#' ){
+ $match = $this->MatchChar($tok[1]);
+
+ }else{
+ // Non-terminal, match using a function call
+ $match = $this->$tok();
+
+ }
+
+ if( $match ){
+ return $match;
+ }
+ }
+ }
+
+ /**
+ * @param string[] $toks
+ *
+ * @return string
+ */
+ private function MatchFuncs($toks){
+
+ if( $this->pos < $this->input_len ){
+ foreach($toks as $tok){
+ $match = $this->$tok();
+ if( $match ){
+ return $match;
+ }
+ }
+ }
+
+ }
+
+ // Match a single character in the input,
+ private function MatchChar($tok){
+ if( ($this->pos < $this->input_len) && ($this->input[$this->pos] === $tok) ){
+ $this->skipWhitespace(1);
+ return $tok;
+ }
+ }
+
+ // Match a regexp from the current start point
+ private function MatchReg($tok){
+
+ if( preg_match($tok, $this->input, $match, 0, $this->pos) ){
+ $this->skipWhitespace(strlen($match[0]));
+ return $match;
+ }
+ }
+
+
+ /**
+ * Same as match(), but don't change the state of the parser,
+ * just return the match.
+ *
+ * @param string $tok
+ * @return integer
+ */
+ public function PeekReg($tok){
+ return preg_match($tok, $this->input, $match, 0, $this->pos);
+ }
+
+ /**
+ * @param string $tok
+ */
+ public function PeekChar($tok){
+ //return ($this->input[$this->pos] === $tok );
+ return ($this->pos < $this->input_len) && ($this->input[$this->pos] === $tok );
+ }
+
+
+ /**
+ * @param integer $length
+ */
+ public function skipWhitespace($length){
+
+ $this->pos += $length;
+
+ for(; $this->pos < $this->input_len; $this->pos++ ){
+ $c = $this->input[$this->pos];
+
+ if( ($c !== "\n") && ($c !== "\r") && ($c !== "\t") && ($c !== ' ') ){
+ break;
+ }
+ }
+ }
+
+
+ /**
+ * @param string $tok
+ * @param string|null $msg
+ */
+ public function expect($tok, $msg = NULL) {
+ $result = $this->match( array($tok) );
+ if (!$result) {
+ $this->Error( $msg ? "Expected '" . $tok . "' got '" . $this->input[$this->pos] . "'" : $msg );
+ } else {
+ return $result;
+ }
+ }
+
+ /**
+ * @param string $tok
+ */
+ public function expectChar($tok, $msg = null ){
+ $result = $this->MatchChar($tok);
+ if( !$result ){
+ $this->Error( $msg ? "Expected '" . $tok . "' got '" . $this->input[$this->pos] . "'" : $msg );
+ }else{
+ return $result;
+ }
+ }
+
+ //
+ // Here in, the parsing rules/functions
+ //
+ // The basic structure of the syntax tree generated is as follows:
+ //
+ // Ruleset -> Rule -> Value -> Expression -> Entity
+ //
+ // Here's some LESS code:
+ //
+ // .class {
+ // color: #fff;
+ // border: 1px solid #000;
+ // width: @w + 4px;
+ // > .child {...}
+ // }
+ //
+ // And here's what the parse tree might look like:
+ //
+ // Ruleset (Selector '.class', [
+ // Rule ("color", Value ([Expression [Color #fff]]))
+ // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]]))
+ // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]]))
+ // Ruleset (Selector [Element '>', '.child'], [...])
+ // ])
+ //
+ // In general, most rules will try to parse a token with the `$()` function, and if the return
+ // value is truly, will return a new node, of the relevant type. Sometimes, we need to check
+ // first, before parsing, that's when we use `peek()`.
+ //
+
+ //
+ // The `primary` rule is the *entry* and *exit* point of the parser.
+ // The rules here can appear at any level of the parse tree.
+ //
+ // The recursive nature of the grammar is an interplay between the `block`
+ // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule,
+ // as represented by this simplified grammar:
+ //
+ // primary → (ruleset | rule)+
+ // ruleset → selector+ block
+ // block → '{' primary '}'
+ //
+ // Only at one point is the primary rule not called from the
+ // block rule: at the root level.
+ //
+ private function parsePrimary(){
+ $root = array();
+
+ while( true ){
+
+ if( $this->pos >= $this->input_len ){
+ break;
+ }
+
+ $node = $this->parseExtend(true);
+ if( $node ){
+ $root = array_merge($root,$node);
+ continue;
+ }
+
+ //$node = $this->MatchFuncs( array( 'parseMixinDefinition', 'parseRule', 'parseRuleset', 'parseMixinCall', 'parseComment', 'parseDirective'));
+ $node = $this->MatchFuncs( array( 'parseMixinDefinition', 'parseNameValue', 'parseRule', 'parseRuleset', 'parseMixinCall', 'parseComment', 'parseRulesetCall', 'parseDirective'));
+
+ if( $node ){
+ $root[] = $node;
+ }elseif( !$this->MatchReg('/\\G[\s\n;]+/') ){
+ break;
+ }
+
+ if( $this->PeekChar('}') ){
+ break;
+ }
+ }
+
+ return $root;
+ }
+
+
+
+ // We create a Comment node for CSS comments `/* */`,
+ // but keep the LeSS comments `//` silent, by just skipping
+ // over them.
+ private function parseComment(){
+
+ if( $this->input[$this->pos] !== '/' ){
+ return;
+ }
+
+ if( $this->input[$this->pos+1] === '/' ){
+ $match = $this->MatchReg('/\\G\/\/.*/');
+ return $this->NewObj4('Less_Tree_Comment',array($match[0], true, $this->pos, $this->env->currentFileInfo));
+ }
+
+ //$comment = $this->MatchReg('/\\G\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/');
+ $comment = $this->MatchReg('/\\G\/\*(?s).*?\*+\/\n?/');//not the same as less.js to prevent fatal errors
+ if( $comment ){
+ return $this->NewObj4('Less_Tree_Comment',array($comment[0], false, $this->pos, $this->env->currentFileInfo));
+ }
+ }
+
+ private function parseComments(){
+ $comments = array();
+
+ while( $this->pos < $this->input_len ){
+ $comment = $this->parseComment();
+ if( !$comment ){
+ break;
+ }
+
+ $comments[] = $comment;
+ }
+
+ return $comments;
+ }
+
+
+
+ //
+ // A string, which supports escaping " and '
+ //
+ // "milky way" 'he\'s the one!'
+ //
+ private function parseEntitiesQuoted() {
+ $j = $this->pos;
+ $e = false;
+ $index = $this->pos;
+
+ if( $this->input[$this->pos] === '~' ){
+ $j++;
+ $e = true; // Escaped strings
+ }
+
+ if( $this->input[$j] != '"' && $this->input[$j] !== "'" ){
+ return;
+ }
+
+ if ($e) {
+ $this->MatchChar('~');
+ }
+
+ // Fix for #124: match escaped newlines
+ //$str = $this->MatchReg('/\\G"((?:[^"\\\\\r\n]|\\\\.)*)"|\'((?:[^\'\\\\\r\n]|\\\\.)*)\'/');
+ $str = $this->MatchReg('/\\G"((?:[^"\\\\\r\n]|\\\\.|\\\\\r\n|\\\\[\n\r\f])*)"|\'((?:[^\'\\\\\r\n]|\\\\.|\\\\\r\n|\\\\[\n\r\f])*)\'/');
+
+ if( $str ){
+ $result = $str[0][0] == '"' ? $str[1] : $str[2];
+ return $this->NewObj5('Less_Tree_Quoted',array($str[0], $result, $e, $index, $this->env->currentFileInfo) );
+ }
+ return;
+ }
+
+
+ //
+ // A catch-all word, such as:
+ //
+ // black border-collapse
+ //
+ private function parseEntitiesKeyword(){
+
+ //$k = $this->MatchReg('/\\G[_A-Za-z-][_A-Za-z0-9-]*/');
+ $k = $this->MatchReg('/\\G%|\\G[_A-Za-z-][_A-Za-z0-9-]*/');
+ if( $k ){
+ $k = $k[0];
+ $color = $this->fromKeyword($k);
+ if( $color ){
+ return $color;
+ }
+ return $this->NewObj1('Less_Tree_Keyword',$k);
+ }
+ }
+
+ // duplicate of Less_Tree_Color::FromKeyword
+ private function FromKeyword( $keyword ){
+ $keyword = strtolower($keyword);
+
+ if( Less_Colors::hasOwnProperty($keyword) ){
+ // detect named color
+ return $this->NewObj1('Less_Tree_Color',substr(Less_Colors::color($keyword), 1));
+ }
+
+ if( $keyword === 'transparent' ){
+ return $this->NewObj3('Less_Tree_Color', array( array(0, 0, 0), 0, true));
+ }
+ }
+
+ //
+ // A function call
+ //
+ // rgb(255, 0, 255)
+ //
+ // We also try to catch IE's `alpha()`, but let the `alpha` parser
+ // deal with the details.
+ //
+ // The arguments are parsed with the `entities.arguments` parser.
+ //
+ private function parseEntitiesCall(){
+ $index = $this->pos;
+
+ if( !preg_match('/\\G([\w-]+|%|progid:[\w\.]+)\(/', $this->input, $name,0,$this->pos) ){
+ return;
+ }
+ $name = $name[1];
+ $nameLC = strtolower($name);
+
+ if ($nameLC === 'url') {
+ return null;
+ }
+
+ $this->pos += strlen($name);
+
+ if( $nameLC === 'alpha' ){
+ $alpha_ret = $this->parseAlpha();
+ if( $alpha_ret ){
+ return $alpha_ret;
+ }
+ }
+
+ $this->MatchChar('('); // Parse the '(' and consume whitespace.
+
+ $args = $this->parseEntitiesArguments();
+
+ if( !$this->MatchChar(')') ){
+ return;
+ }
+
+ if ($name) {
+ return $this->NewObj4('Less_Tree_Call',array($name, $args, $index, $this->env->currentFileInfo) );
+ }
+ }
+
+ /**
+ * Parse a list of arguments
+ *
+ * @return array
+ */
+ private function parseEntitiesArguments(){
+
+ $args = array();
+ while( true ){
+ $arg = $this->MatchFuncs( array('parseEntitiesAssignment','parseExpression') );
+ if( !$arg ){
+ break;
+ }
+
+ $args[] = $arg;
+ if( !$this->MatchChar(',') ){
+ break;
+ }
+ }
+ return $args;
+ }
+
+ private function parseEntitiesLiteral(){
+ return $this->MatchFuncs( array('parseEntitiesDimension','parseEntitiesColor','parseEntitiesQuoted','parseUnicodeDescriptor') );
+ }
+
+ // Assignments are argument entities for calls.
+ // They are present in ie filter properties as shown below.
+ //
+ // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* )
+ //
+ private function parseEntitiesAssignment() {
+
+ $key = $this->MatchReg('/\\G\w+(?=\s?=)/');
+ if( !$key ){
+ return;
+ }
+
+ if( !$this->MatchChar('=') ){
+ return;
+ }
+
+ $value = $this->parseEntity();
+ if( $value ){
+ return $this->NewObj2('Less_Tree_Assignment',array($key[0], $value));
+ }
+ }
+
+ //
+ // Parse url() tokens
+ //
+ // We use a specific rule for urls, because they don't really behave like
+ // standard function calls. The difference is that the argument doesn't have
+ // to be enclosed within a string, so it can't be parsed as an Expression.
+ //
+ private function parseEntitiesUrl(){
+
+
+ if( $this->input[$this->pos] !== 'u' || !$this->matchReg('/\\Gurl\(/') ){
+ return;
+ }
+
+ $value = $this->match( array('parseEntitiesQuoted','parseEntitiesVariable','/\\Gdata\:.*?[^\)]+/','/\\G(?:(?:\\\\[\(\)\'"])|[^\(\)\'"])+/') );
+ if( !$value ){
+ $value = '';
+ }
+
+
+ $this->expectChar(')');
+
+
+ if( isset($value->value) || $value instanceof Less_Tree_Variable ){
+ return $this->NewObj2('Less_Tree_Url',array($value, $this->env->currentFileInfo));
+ }
+
+ return $this->NewObj2('Less_Tree_Url', array( $this->NewObj1('Less_Tree_Anonymous',$value), $this->env->currentFileInfo) );
+ }
+
+
+ //
+ // A Variable entity, such as `@fink`, in
+ //
+ // width: @fink + 2px
+ //
+ // We use a different parser for variable definitions,
+ // see `parsers.variable`.
+ //
+ private function parseEntitiesVariable(){
+ $index = $this->pos;
+ if ($this->PeekChar('@') && ($name = $this->MatchReg('/\\G@@?[\w-]+/'))) {
+ return $this->NewObj3('Less_Tree_Variable', array( $name[0], $index, $this->env->currentFileInfo));
+ }
+ }
+
+
+ // A variable entity useing the protective {} e.g. @{var}
+ private function parseEntitiesVariableCurly() {
+ $index = $this->pos;
+
+ if( $this->input_len > ($this->pos+1) && $this->input[$this->pos] === '@' && ($curly = $this->MatchReg('/\\G@\{([\w-]+)\}/')) ){
+ return $this->NewObj3('Less_Tree_Variable',array('@'.$curly[1], $index, $this->env->currentFileInfo));
+ }
+ }
+
+ //
+ // A Hexadecimal color
+ //
+ // #4F3C2F
+ //
+ // `rgb` and `hsl` colors are parsed through the `entities.call` parser.
+ //
+ private function parseEntitiesColor(){
+ if ($this->PeekChar('#') && ($rgb = $this->MatchReg('/\\G#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/'))) {
+ return $this->NewObj1('Less_Tree_Color',$rgb[1]);
+ }
+ }
+
+ //
+ // A Dimension, that is, a number and a unit
+ //
+ // 0.5em 95%
+ //
+ private function parseEntitiesDimension(){
+
+ $c = @ord($this->input[$this->pos]);
+
+ //Is the first char of the dimension 0-9, '.', '+' or '-'
+ if (($c > 57 || $c < 43) || $c === 47 || $c == 44){
+ return;
+ }
+
+ $value = $this->MatchReg('/\\G([+-]?\d*\.?\d+)(%|[a-z]+)?/');
+ if( $value ){
+
+ if( isset($value[2]) ){
+ return $this->NewObj2('Less_Tree_Dimension', array($value[1],$value[2]));
+ }
+ return $this->NewObj1('Less_Tree_Dimension',$value[1]);
+ }
+ }
+
+
+ //
+ // A unicode descriptor, as is used in unicode-range
+ //
+ // U+0?? or U+00A1-00A9
+ //
+ function parseUnicodeDescriptor() {
+ $ud = $this->MatchReg('/\\G(U\+[0-9a-fA-F?]+)(\-[0-9a-fA-F?]+)?/');
+ if( $ud ){
+ return $this->NewObj1('Less_Tree_UnicodeDescriptor', $ud[0]);
+ }
+ }
+
+
+ //
+ // JavaScript code to be evaluated
+ //
+ // `window.location.href`
+ //
+ private function parseEntitiesJavascript(){
+ $e = false;
+ $j = $this->pos;
+ if( $this->input[$j] === '~' ){
+ $j++;
+ $e = true;
+ }
+ if( $this->input[$j] !== '`' ){
+ return;
+ }
+ if( $e ){
+ $this->MatchChar('~');
+ }
+ $str = $this->MatchReg('/\\G`([^`]*)`/');
+ if( $str ){
+ return $this->NewObj3('Less_Tree_Javascript', array($str[1], $this->pos, $e));
+ }
+ }
+
+
+ //
+ // The variable part of a variable definition. Used in the `rule` parser
+ //
+ // @fink:
+ //
+ private function parseVariable(){
+ if ($this->PeekChar('@') && ($name = $this->MatchReg('/\\G(@[\w-]+)\s*:/'))) {
+ return $name[1];
+ }
+ }
+
+
+ //
+ // The variable part of a variable definition. Used in the `rule` parser
+ //
+ // @fink();
+ //
+ private function parseRulesetCall(){
+
+ if( $this->input[$this->pos] === '@' && ($name = $this->MatchReg('/\\G(@[\w-]+)\s*\(\s*\)\s*;/')) ){
+ return $this->NewObj1('Less_Tree_RulesetCall', $name[1] );
+ }
+ }
+
+
+ //
+ // extend syntax - used to extend selectors
+ //
+ function parseExtend($isRule = false){
+
+ $index = $this->pos;
+ $extendList = array();
+
+
+ if( !$this->MatchReg( $isRule ? '/\\G&:extend\(/' : '/\\G:extend\(/' ) ){ return; }
+
+ do{
+ $option = null;
+ $elements = array();
+ while( true ){
+ $option = $this->MatchReg('/\\G(all)(?=\s*(\)|,))/');
+ if( $option ){ break; }
+ $e = $this->parseElement();
+ if( !$e ){ break; }
+ $elements[] = $e;
+ }
+
+ if( $option ){
+ $option = $option[1];
+ }
+
+ $extendList[] = $this->NewObj3('Less_Tree_Extend', array( $this->NewObj1('Less_Tree_Selector',$elements), $option, $index ));
+
+ }while( $this->MatchChar(",") );
+
+ $this->expect('/\\G\)/');
+
+ if( $isRule ){
+ $this->expect('/\\G;/');
+ }
+
+ return $extendList;
+ }
+
+
+ //
+ // A Mixin call, with an optional argument list
+ //
+ // #mixins > .square(#fff);
+ // .rounded(4px, black);
+ // .button;
+ //
+ // The `while` loop is there because mixins can be
+ // namespaced, but we only support the child and descendant
+ // selector for now.
+ //
+ private function parseMixinCall(){
+
+ $char = $this->input[$this->pos];
+ if( $char !== '.' && $char !== '#' ){
+ return;
+ }
+
+ $index = $this->pos;
+ $this->save(); // stop us absorbing part of an invalid selector
+
+ $elements = $this->parseMixinCallElements();
+
+ if( $elements ){
+
+ if( $this->MatchChar('(') ){
+ $returned = $this->parseMixinArgs(true);
+ $args = $returned['args'];
+ $this->expectChar(')');
+ }else{
+ $args = array();
+ }
+
+ $important = $this->parseImportant();
+
+ if( $this->parseEnd() ){
+ $this->forget();
+ return $this->NewObj5('Less_Tree_Mixin_Call', array( $elements, $args, $index, $this->env->currentFileInfo, $important));
+ }
+ }
+
+ $this->restore();
+ }
+
+
+ private function parseMixinCallElements(){
+ $elements = array();
+ $c = null;
+
+ while( true ){
+ $elemIndex = $this->pos;
+ $e = $this->MatchReg('/\\G[#.](?:[\w-]|\\\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/');
+ if( !$e ){
+ break;
+ }
+ $elements[] = $this->NewObj4('Less_Tree_Element', array($c, $e[0], $elemIndex, $this->env->currentFileInfo));
+ $c = $this->MatchChar('>');
+ }
+
+ return $elements;
+ }
+
+
+
+ /**
+ * @param boolean $isCall
+ */
+ private function parseMixinArgs( $isCall ){
+ $expressions = array();
+ $argsSemiColon = array();
+ $isSemiColonSeperated = null;
+ $argsComma = array();
+ $expressionContainsNamed = null;
+ $name = null;
+ $returner = array('args'=>array(), 'variadic'=> false);
+
+ $this->save();
+
+ while( true ){
+ if( $isCall ){
+ $arg = $this->MatchFuncs( array( 'parseDetachedRuleset','parseExpression' ) );
+ } else {
+ $this->parseComments();
+ if( $this->input[ $this->pos ] === '.' && $this->MatchReg('/\\G\.{3}/') ){
+ $returner['variadic'] = true;
+ if( $this->MatchChar(";") && !$isSemiColonSeperated ){
+ $isSemiColonSeperated = true;
+ }
+
+ if( $isSemiColonSeperated ){
+ $argsSemiColon[] = array('variadic'=>true);
+ }else{
+ $argsComma[] = array('variadic'=>true);
+ }
+ break;
+ }
+ $arg = $this->MatchFuncs( array('parseEntitiesVariable','parseEntitiesLiteral','parseEntitiesKeyword') );
+ }
+
+ if( !$arg ){
+ break;
+ }
+
+
+ $nameLoop = null;
+ if( $arg instanceof Less_Tree_Expression ){
+ $arg->throwAwayComments();
+ }
+ $value = $arg;
+ $val = null;
+
+ if( $isCall ){
+ // Variable
+ if( property_exists($arg,'value') && count($arg->value) == 1 ){
+ $val = $arg->value[0];
+ }
+ } else {
+ $val = $arg;
+ }
+
+
+ if( $val instanceof Less_Tree_Variable ){
+
+ if( $this->MatchChar(':') ){
+ if( $expressions ){
+ if( $isSemiColonSeperated ){
+ $this->Error('Cannot mix ; and , as delimiter types');
+ }
+ $expressionContainsNamed = true;
+ }
+
+ // we do not support setting a ruleset as a default variable - it doesn't make sense
+ // However if we do want to add it, there is nothing blocking it, just don't error
+ // and remove isCall dependency below
+ $value = null;
+ if( $isCall ){
+ $value = $this->parseDetachedRuleset();
+ }
+ if( !$value ){
+ $value = $this->parseExpression();
+ }
+
+ if( !$value ){
+ if( $isCall ){
+ $this->Error('could not understand value for named argument');
+ } else {
+ $this->restore();
+ $returner['args'] = array();
+ return $returner;
+ }
+ }
+
+ $nameLoop = ($name = $val->name);
+ }elseif( !$isCall && $this->MatchReg('/\\G\.{3}/') ){
+ $returner['variadic'] = true;
+ if( $this->MatchChar(";") && !$isSemiColonSeperated ){
+ $isSemiColonSeperated = true;
+ }
+ if( $isSemiColonSeperated ){
+ $argsSemiColon[] = array('name'=> $arg->name, 'variadic' => true);
+ }else{
+ $argsComma[] = array('name'=> $arg->name, 'variadic' => true);
+ }
+ break;
+ }elseif( !$isCall ){
+ $name = $nameLoop = $val->name;
+ $value = null;
+ }
+ }
+
+ if( $value ){
+ $expressions[] = $value;
+ }
+
+ $argsComma[] = array('name'=>$nameLoop, 'value'=>$value );
+
+ if( $this->MatchChar(',') ){
+ continue;
+ }
+
+ if( $this->MatchChar(';') || $isSemiColonSeperated ){
+
+ if( $expressionContainsNamed ){
+ $this->Error('Cannot mix ; and , as delimiter types');
+ }
+
+ $isSemiColonSeperated = true;
+
+ if( count($expressions) > 1 ){
+ $value = $this->NewObj1('Less_Tree_Value', $expressions);
+ }
+ $argsSemiColon[] = array('name'=>$name, 'value'=>$value );
+
+ $name = null;
+ $expressions = array();
+ $expressionContainsNamed = false;
+ }
+ }
+
+ $this->forget();
+ $returner['args'] = ($isSemiColonSeperated ? $argsSemiColon : $argsComma);
+ return $returner;
+ }
+
+
+
+ //
+ // A Mixin definition, with a list of parameters
+ //
+ // .rounded (@radius: 2px, @color) {
+ // ...
+ // }
+ //
+ // Until we have a finer grained state-machine, we have to
+ // do a look-ahead, to make sure we don't have a mixin call.
+ // See the `rule` function for more information.
+ //
+ // We start by matching `.rounded (`, and then proceed on to
+ // the argument list, which has optional default values.
+ // We store the parameters in `params`, with a `value` key,
+ // if there is a value, such as in the case of `@radius`.
+ //
+ // Once we've got our params list, and a closing `)`, we parse
+ // the `{...}` block.
+ //
+ private function parseMixinDefinition(){
+ $cond = null;
+
+ $char = $this->input[$this->pos];
+ if( ($char !== '.' && $char !== '#') || ($char === '{' && $this->PeekReg('/\\G[^{]*\}/')) ){
+ return;
+ }
+
+ $this->save();
+
+ $match = $this->MatchReg('/\\G([#.](?:[\w-]|\\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/');
+ if( $match ){
+ $name = $match[1];
+
+ $argInfo = $this->parseMixinArgs( false );
+ $params = $argInfo['args'];
+ $variadic = $argInfo['variadic'];
+
+
+ // .mixincall("@{a}");
+ // looks a bit like a mixin definition..
+ // also
+ // .mixincall(@a: {rule: set;});
+ // so we have to be nice and restore
+ if( !$this->MatchChar(')') ){
+ $this->furthest = $this->pos;
+ $this->restore();
+ return;
+ }
+
+
+ $this->parseComments();
+
+ if ($this->MatchReg('/\\Gwhen/')) { // Guard
+ $cond = $this->expect('parseConditions', 'Expected conditions');
+ }
+
+ $ruleset = $this->parseBlock();
+
+ if( is_array($ruleset) ){
+ $this->forget();
+ return $this->NewObj5('Less_Tree_Mixin_Definition', array( $name, $params, $ruleset, $cond, $variadic));
+ }
+
+ $this->restore();
+ }else{
+ $this->forget();
+ }
+ }
+
+ //
+ // Entities are the smallest recognized token,
+ // and can be found inside a rule's value.
+ //
+ private function parseEntity(){
+
+ return $this->MatchFuncs( array('parseEntitiesLiteral','parseEntitiesVariable','parseEntitiesUrl','parseEntitiesCall','parseEntitiesKeyword','parseEntitiesJavascript','parseComment') );
+ }
+
+ //
+ // A Rule terminator. Note that we use `peek()` to check for '}',
+ // because the `block` rule will be expecting it, but we still need to make sure
+ // it's there, if ';' was ommitted.
+ //
+ private function parseEnd(){
+ return $this->MatchChar(';') || $this->PeekChar('}');
+ }
+
+ //
+ // IE's alpha function
+ //
+ // alpha(opacity=88)
+ //
+ private function parseAlpha(){
+
+ if ( ! $this->MatchReg('/\\G\(opacity=/i')) {
+ return;
+ }
+
+ $value = $this->MatchReg('/\\G[0-9]+/');
+ if( $value ){
+ $value = $value[0];
+ }else{
+ $value = $this->parseEntitiesVariable();
+ if( !$value ){
+ return;
+ }
+ }
+
+ $this->expectChar(')');
+ return $this->NewObj1('Less_Tree_Alpha',$value);
+ }
+
+
+ //
+ // A Selector Element
+ //
+ // div
+ // + h1
+ // #socks
+ // input[type="text"]
+ //
+ // Elements are the building blocks for Selectors,
+ // they are made out of a `Combinator` (see combinator rule),
+ // and an element name, such as a tag a class, or `*`.
+ //
+ private function parseElement(){
+ $c = $this->parseCombinator();
+ $index = $this->pos;
+
+ $e = $this->match( array('/\\G(?:\d+\.\d+|\d+)%/', '/\\G(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/',
+ '#*', '#&', 'parseAttribute', '/\\G\([^()@]+\)/', '/\\G[\.#](?=@)/', 'parseEntitiesVariableCurly') );
+
+ if( is_null($e) ){
+ $this->save();
+ if( $this->MatchChar('(') ){
+ if( ($v = $this->parseSelector()) && $this->MatchChar(')') ){
+ $e = $this->NewObj1('Less_Tree_Paren',$v);
+ $this->forget();
+ }else{
+ $this->restore();
+ }
+ }else{
+ $this->forget();
+ }
+ }
+
+ if( !is_null($e) ){
+ return $this->NewObj4('Less_Tree_Element',array( $c, $e, $index, $this->env->currentFileInfo));
+ }
+ }
+
+ //
+ // Combinators combine elements together, in a Selector.
+ //
+ // Because our parser isn't white-space sensitive, special care
+ // has to be taken, when parsing the descendant combinator, ` `,
+ // as it's an empty space. We have to check the previous character
+ // in the input, to see if it's a ` ` character.
+ //
+ private function parseCombinator(){
+ if( $this->pos < $this->input_len ){
+ $c = $this->input[$this->pos];
+ if ($c === '>' || $c === '+' || $c === '~' || $c === '|' || $c === '^' ){
+
+ $this->pos++;
+ if( $this->input[$this->pos] === '^' ){
+ $c = '^^';
+ $this->pos++;
+ }
+
+ $this->skipWhitespace(0);
+
+ return $c;
+ }
+
+ if( $this->pos > 0 && $this->isWhitespace(-1) ){
+ return ' ';
+ }
+ }
+ }
+
+ //
+ // A CSS selector (see selector below)
+ // with less extensions e.g. the ability to extend and guard
+ //
+ private function parseLessSelector(){
+ return $this->parseSelector(true);
+ }
+
+ //
+ // A CSS Selector
+ //
+ // .class > div + h1
+ // li a:hover
+ //
+ // Selectors are made out of one or more Elements, see above.
+ //
+ private function parseSelector( $isLess = false ){
+ $elements = array();
+ $extendList = array();
+ $condition = null;
+ $when = false;
+ $extend = false;
+ $e = null;
+ $c = null;
+ $index = $this->pos;
+
+ while( ($isLess && ($extend = $this->parseExtend())) || ($isLess && ($when = $this->MatchReg('/\\Gwhen/') )) || ($e = $this->parseElement()) ){
+ if( $when ){
+ $condition = $this->expect('parseConditions', 'expected condition');
+ }elseif( $condition ){
+ //error("CSS guard can only be used at the end of selector");
+ }elseif( $extend ){
+ $extendList = array_merge($extendList,$extend);
+ }else{
+ //if( count($extendList) ){
+ //error("Extend can only be used at the end of selector");
+ //}
+ if( $this->pos < $this->input_len ){
+ $c = $this->input[ $this->pos ];
+ }
+ $elements[] = $e;
+ $e = null;
+ }
+
+ if( $c === '{' || $c === '}' || $c === ';' || $c === ',' || $c === ')') { break; }
+ }
+
+ if( $elements ){
+ return $this->NewObj5('Less_Tree_Selector',array($elements, $extendList, $condition, $index, $this->env->currentFileInfo));
+ }
+ if( $extendList ) {
+ $this->Error('Extend must be used to extend a selector, it cannot be used on its own');
+ }
+ }
+
+ private function parseTag(){
+ return ( $tag = $this->MatchReg('/\\G[A-Za-z][A-Za-z-]*[0-9]?/') ) ? $tag : $this->MatchChar('*');
+ }
+
+ private function parseAttribute(){
+
+ $val = null;
+
+ if( !$this->MatchChar('[') ){
+ return;
+ }
+
+ $key = $this->parseEntitiesVariableCurly();
+ if( !$key ){
+ $key = $this->expect('/\\G(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\\\.)+/');
+ }
+
+ $op = $this->MatchReg('/\\G[|~*$^]?=/');
+ if( $op ){
+ $val = $this->match( array('parseEntitiesQuoted','/\\G[0-9]+%/','/\\G[\w-]+/','parseEntitiesVariableCurly') );
+ }
+
+ $this->expectChar(']');
+
+ return $this->NewObj3('Less_Tree_Attribute',array( $key, $op[0], $val));
+ }
+
+ //
+ // The `block` rule is used by `ruleset` and `mixin.definition`.
+ // It's a wrapper around the `primary` rule, with added `{}`.
+ //
+ private function parseBlock(){
+ if( $this->MatchChar('{') ){
+ $content = $this->parsePrimary();
+ if( $this->MatchChar('}') ){
+ return $content;
+ }
+ }
+ }
+
+ private function parseBlockRuleset(){
+ $block = $this->parseBlock();
+
+ if( $block ){
+ $block = $this->NewObj2('Less_Tree_Ruleset',array( null, $block));
+ }
+
+ return $block;
+ }
+
+ private function parseDetachedRuleset(){
+ $blockRuleset = $this->parseBlockRuleset();
+ if( $blockRuleset ){
+ return $this->NewObj1('Less_Tree_DetachedRuleset',$blockRuleset);
+ }
+ }
+
+ //
+ // div, .class, body > p {...}
+ //
+ private function parseRuleset(){
+ $selectors = array();
+
+ $this->save();
+
+ while( true ){
+ $s = $this->parseLessSelector();
+ if( !$s ){
+ break;
+ }
+ $selectors[] = $s;
+ $this->parseComments();
+
+ if( $s->condition && count($selectors) > 1 ){
+ $this->Error('Guards are only currently allowed on a single selector.');
+ }
+
+ if( !$this->MatchChar(',') ){
+ break;
+ }
+ if( $s->condition ){
+ $this->Error('Guards are only currently allowed on a single selector.');
+ }
+ $this->parseComments();
+ }
+
+
+ if( $selectors ){
+ $rules = $this->parseBlock();
+ if( is_array($rules) ){
+ $this->forget();
+ return $this->NewObj2('Less_Tree_Ruleset',array( $selectors, $rules)); //Less_Environment::$strictImports
+ }
+ }
+
+ // Backtrack
+ $this->furthest = $this->pos;
+ $this->restore();
+ }
+
+ /**
+ * Custom less.php parse function for finding simple name-value css pairs
+ * ex: width:100px;
+ *
+ */
+ private function parseNameValue(){
+
+ $index = $this->pos;
+ $this->save();
+
+
+ //$match = $this->MatchReg('/\\G([a-zA-Z\-]+)\s*:\s*((?:\'")?[a-zA-Z0-9\-% \.,!]+?(?:\'")?)\s*([;}])/');
+ $match = $this->MatchReg('/\\G([a-zA-Z\-]+)\s*:\s*([\'"]?[#a-zA-Z0-9\-%\.,]+?[\'"]?) *(! *important)?\s*([;}])/');
+ if( $match ){
+
+ if( $match[4] == '}' ){
+ $this->pos = $index + strlen($match[0])-1;
+ }
+
+ if( $match[3] ){
+ $match[2] .= ' !important';
+ }
+
+ return $this->NewObj4('Less_Tree_NameValue',array( $match[1], $match[2], $index, $this->env->currentFileInfo));
+ }
+
+ $this->restore();
+ }
+
+
+ private function parseRule( $tryAnonymous = null ){
+
+ $merge = false;
+ $startOfRule = $this->pos;
+
+ $c = $this->input[$this->pos];
+ if( $c === '.' || $c === '#' || $c === '&' ){
+ return;
+ }
+
+ $this->save();
+ $name = $this->MatchFuncs( array('parseVariable','parseRuleProperty'));
+
+ if( $name ){
+
+ $isVariable = is_string($name);
+
+ $value = null;
+ if( $isVariable ){
+ $value = $this->parseDetachedRuleset();
+ }
+
+ $important = null;
+ if( !$value ){
+
+ // prefer to try to parse first if its a variable or we are compressing
+ // but always fallback on the other one
+ //if( !$tryAnonymous && is_string($name) && $name[0] === '@' ){
+ if( !$tryAnonymous && (Less_Parser::$options['compress'] || $isVariable) ){
+ $value = $this->MatchFuncs( array('parseValue','parseAnonymousValue'));
+ }else{
+ $value = $this->MatchFuncs( array('parseAnonymousValue','parseValue'));
+ }
+
+ $important = $this->parseImportant();
+
+ // a name returned by this.ruleProperty() is always an array of the form:
+ // [string-1, ..., string-n, ""] or [string-1, ..., string-n, "+"]
+ // where each item is a tree.Keyword or tree.Variable
+ if( !$isVariable && is_array($name) ){
+ $nm = array_pop($name);
+ if( $nm->value ){
+ $merge = $nm->value;
+ }
+ }
+ }
+
+
+ if( $value && $this->parseEnd() ){
+ $this->forget();
+ return $this->NewObj6('Less_Tree_Rule',array( $name, $value, $important, $merge, $startOfRule, $this->env->currentFileInfo));
+ }else{
+ $this->furthest = $this->pos;
+ $this->restore();
+ if( $value && !$tryAnonymous ){
+ return $this->parseRule(true);
+ }
+ }
+ }else{
+ $this->forget();
+ }
+ }
+
+ function parseAnonymousValue(){
+
+ if( preg_match('/\\G([^@+\/\'"*`(;{}-]*);/',$this->input, $match, 0, $this->pos) ){
+ $this->pos += strlen($match[1]);
+ return $this->NewObj1('Less_Tree_Anonymous',$match[1]);
+ }
+ }
+
+ //
+ // An @import directive
+ //
+ // @import "lib";
+ //
+ // Depending on our environment, importing is done differently:
+ // In the browser, it's an XHR request, in Node, it would be a
+ // file-system operation. The function used for importing is
+ // stored in `import`, which we pass to the Import constructor.
+ //
+ private function parseImport(){
+
+ $this->save();
+
+ $dir = $this->MatchReg('/\\G@import?\s+/');
+
+ if( $dir ){
+ $options = $this->parseImportOptions();
+ $path = $this->MatchFuncs( array('parseEntitiesQuoted','parseEntitiesUrl'));
+
+ if( $path ){
+ $features = $this->parseMediaFeatures();
+ if( $this->MatchChar(';') ){
+ if( $features ){
+ $features = $this->NewObj1('Less_Tree_Value',$features);
+ }
+
+ $this->forget();
+ return $this->NewObj5('Less_Tree_Import',array( $path, $features, $options, $this->pos, $this->env->currentFileInfo));
+ }
+ }
+ }
+
+ $this->restore();
+ }
+
+ private function parseImportOptions(){
+
+ $options = array();
+
+ // list of options, surrounded by parens
+ if( !$this->MatchChar('(') ){
+ return $options;
+ }
+ do{
+ $optionName = $this->parseImportOption();
+ if( $optionName ){
+ $value = true;
+ switch( $optionName ){
+ case "css":
+ $optionName = "less";
+ $value = false;
+ break;
+ case "once":
+ $optionName = "multiple";
+ $value = false;
+ break;
+ }
+ $options[$optionName] = $value;
+ if( !$this->MatchChar(',') ){ break; }
+ }
+ }while( $optionName );
+ $this->expectChar(')');
+ return $options;
+ }
+
+ private function parseImportOption(){
+ $opt = $this->MatchReg('/\\G(less|css|multiple|once|inline|reference|optional)/');
+ if( $opt ){
+ return $opt[1];
+ }
+ }
+
+ private function parseMediaFeature() {
+ $nodes = array();
+
+ do{
+ $e = $this->MatchFuncs(array('parseEntitiesKeyword','parseEntitiesVariable'));
+ if( $e ){
+ $nodes[] = $e;
+ } elseif ($this->MatchChar('(')) {
+ $p = $this->parseProperty();
+ $e = $this->parseValue();
+ if ($this->MatchChar(')')) {
+ if ($p && $e) {
+ $r = $this->NewObj7('Less_Tree_Rule', array( $p, $e, null, null, $this->pos, $this->env->currentFileInfo, true));
+ $nodes[] = $this->NewObj1('Less_Tree_Paren',$r);
+ } elseif ($e) {
+ $nodes[] = $this->NewObj1('Less_Tree_Paren',$e);
+ } else {
+ return null;
+ }
+ } else
+ return null;
+ }
+ } while ($e);
+
+ if ($nodes) {
+ return $this->NewObj1('Less_Tree_Expression',$nodes);
+ }
+ }
+
+ private function parseMediaFeatures() {
+ $features = array();
+
+ do{
+ $e = $this->parseMediaFeature();
+ if( $e ){
+ $features[] = $e;
+ if (!$this->MatchChar(',')) break;
+ }else{
+ $e = $this->parseEntitiesVariable();
+ if( $e ){
+ $features[] = $e;
+ if (!$this->MatchChar(',')) break;
+ }
+ }
+ } while ($e);
+
+ return $features ? $features : null;
+ }
+
+ private function parseMedia() {
+ if( $this->MatchReg('/\\G@media/') ){
+ $features = $this->parseMediaFeatures();
+ $rules = $this->parseBlock();
+
+ if( is_array($rules) ){
+ return $this->NewObj4('Less_Tree_Media',array( $rules, $features, $this->pos, $this->env->currentFileInfo));
+ }
+ }
+ }
+
+
+ //
+ // A CSS Directive
+ //
+ // @charset "utf-8";
+ //
+ private function parseDirective(){
+
+ if( !$this->PeekChar('@') ){
+ return;
+ }
+
+ $rules = null;
+ $index = $this->pos;
+ $hasBlock = true;
+ $hasIdentifier = false;
+ $hasExpression = false;
+ $hasUnknown = false;
+
+
+ $value = $this->MatchFuncs(array('parseImport','parseMedia'));
+ if( $value ){
+ return $value;
+ }
+
+ $this->save();
+
+ $name = $this->MatchReg('/\\G@[a-z-]+/');
+
+ if( !$name ) return;
+ $name = $name[0];
+
+
+ $nonVendorSpecificName = $name;
+ $pos = strpos($name,'-', 2);
+ if( $name[1] == '-' && $pos > 0 ){
+ $nonVendorSpecificName = "@" . substr($name, $pos + 1);
+ }
+
+
+ switch( $nonVendorSpecificName ){
+ /*
+ case "@font-face":
+ case "@viewport":
+ case "@top-left":
+ case "@top-left-corner":
+ case "@top-center":
+ case "@top-right":
+ case "@top-right-corner":
+ case "@bottom-left":
+ case "@bottom-left-corner":
+ case "@bottom-center":
+ case "@bottom-right":
+ case "@bottom-right-corner":
+ case "@left-top":
+ case "@left-middle":
+ case "@left-bottom":
+ case "@right-top":
+ case "@right-middle":
+ case "@right-bottom":
+ hasBlock = true;
+ break;
+ */
+ case "@charset":
+ $hasIdentifier = true;
+ $hasBlock = false;
+ break;
+ case "@namespace":
+ $hasExpression = true;
+ $hasBlock = false;
+ break;
+ case "@keyframes":
+ $hasIdentifier = true;
+ break;
+ case "@host":
+ case "@page":
+ case "@document":
+ case "@supports":
+ $hasUnknown = true;
+ break;
+ }
+
+ if( $hasIdentifier ){
+ $value = $this->parseEntity();
+ if( !$value ){
+ $this->error("expected " . $name . " identifier");
+ }
+ } else if( $hasExpression ){
+ $value = $this->parseExpression();
+ if( !$value ){
+ $this->error("expected " . $name. " expression");
+ }
+ } else if ($hasUnknown) {
+
+ $value = $this->MatchReg('/\\G[^{;]+/');
+ if( $value ){
+ $value = $this->NewObj1('Less_Tree_Anonymous',trim($value[0]));
+ }
+ }
+
+ if( $hasBlock ){
+ $rules = $this->parseBlockRuleset();
+ }
+
+ if( $rules || (!$hasBlock && $value && $this->MatchChar(';'))) {
+ $this->forget();
+ return $this->NewObj5('Less_Tree_Directive',array($name, $value, $rules, $index, $this->env->currentFileInfo));
+ }
+
+ $this->restore();
+ }
+
+
+ //
+ // A Value is a comma-delimited list of Expressions
+ //
+ // font-family: Baskerville, Georgia, serif;
+ //
+ // In a Rule, a Value represents everything after the `:`,
+ // and before the `;`.
+ //
+ private function parseValue(){
+ $expressions = array();
+
+ do{
+ $e = $this->parseExpression();
+ if( $e ){
+ $expressions[] = $e;
+ if (! $this->MatchChar(',')) {
+ break;
+ }
+ }
+ }while($e);
+
+ if( $expressions ){
+ return $this->NewObj1('Less_Tree_Value',$expressions);
+ }
+ }
+
+ private function parseImportant (){
+ if( $this->PeekChar('!') && $this->MatchReg('/\\G! *important/') ){
+ return ' !important';
+ }
+ }
+
+ private function parseSub (){
+
+ if( $this->MatchChar('(') ){
+ $a = $this->parseAddition();
+ if( $a ){
+ $this->expectChar(')');
+ return $this->NewObj2('Less_Tree_Expression',array( array($a), true) ); //instead of $e->parens = true so the value is cached
+ }
+ }
+ }
+
+
+ /**
+ * Parses multiplication operation
+ *
+ * @return Less_Tree_Operation|null
+ */
+ function parseMultiplication(){
+
+ $return = $m = $this->parseOperand();
+ if( $return ){
+ while( true ){
+
+ $isSpaced = $this->isWhitespace( -1 );
+
+ if( $this->PeekReg('/\\G\/[*\/]/') ){
+ break;
+ }
+
+ $op = $this->MatchChar('/');
+ if( !$op ){
+ $op = $this->MatchChar('*');
+ if( !$op ){
+ break;
+ }
+ }
+
+ $a = $this->parseOperand();
+
+ if(!$a) { break; }
+
+ $m->parensInOp = true;
+ $a->parensInOp = true;
+ $return = $this->NewObj3('Less_Tree_Operation',array( $op, array( $return, $a ), $isSpaced) );
+ }
+ }
+ return $return;
+
+ }
+
+
+ /**
+ * Parses an addition operation
+ *
+ * @return Less_Tree_Operation|null
+ */
+ private function parseAddition (){
+
+ $return = $m = $this->parseMultiplication();
+ if( $return ){
+ while( true ){
+
+ $isSpaced = $this->isWhitespace( -1 );
+
+ $op = $this->MatchReg('/\\G[-+]\s+/');
+ if( $op ){
+ $op = $op[0];
+ }else{
+ if( !$isSpaced ){
+ $op = $this->match(array('#+','#-'));
+ }
+ if( !$op ){
+ break;
+ }
+ }
+
+ $a = $this->parseMultiplication();
+ if( !$a ){
+ break;
+ }
+
+ $m->parensInOp = true;
+ $a->parensInOp = true;
+ $return = $this->NewObj3('Less_Tree_Operation',array($op, array($return, $a), $isSpaced));
+ }
+ }
+
+ return $return;
+ }
+
+
+ /**
+ * Parses the conditions
+ *
+ * @return Less_Tree_Condition|null
+ */
+ private function parseConditions() {
+ $index = $this->pos;
+ $return = $a = $this->parseCondition();
+ if( $a ){
+ while( true ){
+ if( !$this->PeekReg('/\\G,\s*(not\s*)?\(/') || !$this->MatchChar(',') ){
+ break;
+ }
+ $b = $this->parseCondition();
+ if( !$b ){
+ break;
+ }
+
+ $return = $this->NewObj4('Less_Tree_Condition',array('or', $return, $b, $index));
+ }
+ return $return;
+ }
+ }
+
+ private function parseCondition() {
+ $index = $this->pos;
+ $negate = false;
+ $c = null;
+
+ if ($this->MatchReg('/\\Gnot/')) $negate = true;
+ $this->expectChar('(');
+ $a = $this->MatchFuncs(array('parseAddition','parseEntitiesKeyword','parseEntitiesQuoted'));
+
+ if( $a ){
+ $op = $this->MatchReg('/\\G(?:>=|<=|=<|[<=>])/');
+ if( $op ){
+ $b = $this->MatchFuncs(array('parseAddition','parseEntitiesKeyword','parseEntitiesQuoted'));
+ if( $b ){
+ $c = $this->NewObj5('Less_Tree_Condition',array($op[0], $a, $b, $index, $negate));
+ } else {
+ $this->Error('Unexpected expression');
+ }
+ } else {
+ $k = $this->NewObj1('Less_Tree_Keyword','true');
+ $c = $this->NewObj5('Less_Tree_Condition',array('=', $a, $k, $index, $negate));
+ }
+ $this->expectChar(')');
+ return $this->MatchReg('/\\Gand/') ? $this->NewObj3('Less_Tree_Condition',array('and', $c, $this->parseCondition())) : $c;
+ }
+ }
+
+ /**
+ * An operand is anything that can be part of an operation,
+ * such as a Color, or a Variable
+ *
+ */
+ private function parseOperand (){
+
+ $negate = false;
+ $offset = $this->pos+1;
+ if( $offset >= $this->input_len ){
+ return;
+ }
+ $char = $this->input[$offset];
+ if( $char === '@' || $char === '(' ){
+ $negate = $this->MatchChar('-');
+ }
+
+ $o = $this->MatchFuncs(array('parseSub','parseEntitiesDimension','parseEntitiesColor','parseEntitiesVariable','parseEntitiesCall'));
+
+ if( $negate ){
+ $o->parensInOp = true;
+ $o = $this->NewObj1('Less_Tree_Negative',$o);
+ }
+
+ return $o;
+ }
+
+
+ /**
+ * Expressions either represent mathematical operations,
+ * or white-space delimited Entities.
+ *
+ * 1px solid black
+ * @var * 2
+ *
+ * @return Less_Tree_Expression|null
+ */
+ private function parseExpression (){
+ $entities = array();
+
+ do{
+ $e = $this->MatchFuncs(array('parseAddition','parseEntity'));
+ if( $e ){
+ $entities[] = $e;
+ // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here
+ if( !$this->PeekReg('/\\G\/[\/*]/') ){
+ $delim = $this->MatchChar('/');
+ if( $delim ){
+ $entities[] = $this->NewObj1('Less_Tree_Anonymous',$delim);
+ }
+ }
+ }
+ }while($e);
+
+ if( $entities ){
+ return $this->NewObj1('Less_Tree_Expression',$entities);
+ }
+ }
+
+
+ /**
+ * Parse a property
+ * eg: 'min-width', 'orientation', etc
+ *
+ * @return string
+ */
+ private function parseProperty (){
+ $name = $this->MatchReg('/\\G(\*?-?[_a-zA-Z0-9-]+)\s*:/');
+ if( $name ){
+ return $name[1];
+ }
+ }
+
+
+ /**
+ * Parse a rule property
+ * eg: 'color', 'width', 'height', etc
+ *
+ * @return string
+ */
+ private function parseRuleProperty(){
+ $offset = $this->pos;
+ $name = array();
+ $index = array();
+ $length = 0;
+
+
+ $this->rulePropertyMatch('/\\G(\*?)/', $offset, $length, $index, $name );
+ while( $this->rulePropertyMatch('/\\G((?:[\w-]+)|(?:@\{[\w-]+\}))/', $offset, $length, $index, $name )); // !
+
+ if( (count($name) > 1) && $this->rulePropertyMatch('/\\G\s*((?:\+_|\+)?)\s*:/', $offset, $length, $index, $name) ){
+ // at last, we have the complete match now. move forward,
+ // convert name particles to tree objects and return:
+ $this->skipWhitespace($length);
+
+ if( $name[0] === '' ){
+ array_shift($name);
+ array_shift($index);
+ }
+ foreach($name as $k => $s ){
+ if( !$s || $s[0] !== '@' ){
+ $name[$k] = $this->NewObj1('Less_Tree_Keyword',$s);
+ }else{
+ $name[$k] = $this->NewObj3('Less_Tree_Variable',array('@' . substr($s,2,-1), $index[$k], $this->env->currentFileInfo));
+ }
+ }
+ return $name;
+ }
+
+
+ }
+
+ private function rulePropertyMatch( $re, &$offset, &$length, &$index, &$name ){
+ preg_match($re, $this->input, $a, 0, $offset);
+ if( $a ){
+ $index[] = $this->pos + $length;
+ $length += strlen($a[0]);
+ $offset += strlen($a[0]);
+ $name[] = $a[1];
+ return true;
+ }
+ }
+
+ public static function serializeVars( $vars ){
+ $s = '';
+
+ foreach($vars as $name => $value){
+ $s .= (($name[0] === '@') ? '' : '@') . $name .': '. $value . ((substr($value,-1) === ';') ? '' : ';');
+ }
+
+ return $s;
+ }
+
+
+ /**
+ * Some versions of php have trouble with method_exists($a,$b) if $a is not an object
+ *
+ * @param string $b
+ */
+ public static function is_method($a,$b){
+ return is_object($a) && method_exists($a,$b);
+ }
+
+
+ /**
+ * Round numbers similarly to javascript
+ * eg: 1.499999 to 1 instead of 2
+ *
+ */
+ public static function round($i, $precision = 0){
+
+ $precision = pow(10,$precision);
+ $i = $i*$precision;
+
+ $ceil = ceil($i);
+ $floor = floor($i);
+ if( ($ceil - $i) <= ($i - $floor) ){
+ return $ceil/$precision;
+ }else{
+ return $floor/$precision;
+ }
+ }
+
+
+ /**
+ * Create Less_Tree_* objects and optionally generate a cache string
+ *
+ * @return mixed
+ */
+ public function NewObj0($class){
+ $obj = new $class();
+ if( $this->CacheEnabled() ){
+ $obj->cache_string = ' new '.$class.'()';
+ }
+ return $obj;
+ }
+
+ public function NewObj1($class, $arg){
+ $obj = new $class( $arg );
+ if( $this->CacheEnabled() ){
+ $obj->cache_string = ' new '.$class.'('.Less_Parser::ArgString($arg).')';
+ }
+ return $obj;
+ }
+
+ public function NewObj2($class, $args){
+ $obj = new $class( $args[0], $args[1] );
+ if( $this->CacheEnabled() ){
+ $this->ObjCache( $obj, $class, $args);
+ }
+ return $obj;
+ }
+
+ public function NewObj3($class, $args){
+ $obj = new $class( $args[0], $args[1], $args[2] );
+ if( $this->CacheEnabled() ){
+ $this->ObjCache( $obj, $class, $args);
+ }
+ return $obj;
+ }
+
+ public function NewObj4($class, $args){
+ $obj = new $class( $args[0], $args[1], $args[2], $args[3] );
+ if( $this->CacheEnabled() ){
+ $this->ObjCache( $obj, $class, $args);
+ }
+ return $obj;
+ }
+
+ public function NewObj5($class, $args){
+ $obj = new $class( $args[0], $args[1], $args[2], $args[3], $args[4] );
+ if( $this->CacheEnabled() ){
+ $this->ObjCache( $obj, $class, $args);
+ }
+ return $obj;
+ }
+
+ public function NewObj6($class, $args){
+ $obj = new $class( $args[0], $args[1], $args[2], $args[3], $args[4], $args[5] );
+ if( $this->CacheEnabled() ){
+ $this->ObjCache( $obj, $class, $args);
+ }
+ return $obj;
+ }
+
+ public function NewObj7($class, $args){
+ $obj = new $class( $args[0], $args[1], $args[2], $args[3], $args[4], $args[5], $args[6] );
+ if( $this->CacheEnabled() ){
+ $this->ObjCache( $obj, $class, $args);
+ }
+ return $obj;
+ }
+
+ //caching
+ public function ObjCache($obj, $class, $args=array()){
+ $obj->cache_string = ' new '.$class.'('. self::ArgCache($args).')';
+ }
+
+ public function ArgCache($args){
+ return implode(',',array_map( array('Less_Parser','ArgString'),$args));
+ }
+
+
+ /**
+ * Convert an argument to a string for use in the parser cache
+ *
+ * @return string
+ */
+ public static function ArgString($arg){
+
+ $type = gettype($arg);
+
+ if( $type === 'object'){
+ $string = $arg->cache_string;
+ unset($arg->cache_string);
+ return $string;
+
+ }elseif( $type === 'array' ){
+ $string = ' Array(';
+ foreach($arg as $k => $a){
+ $string .= var_export($k,true).' => '.self::ArgString($a).',';
+ }
+ return $string . ')';
+ }
+
+ return var_export($arg,true);
+ }
+
+ public function Error($msg){
+ throw new Less_Exception_Parser($msg, null, $this->furthest, $this->env->currentFileInfo);
+ }
+
+ public static function WinPath($path){
+ return str_replace('\\', '/', $path);
+ }
+
+ public function CacheEnabled(){
+ return false;
+ //return (Less_Parser::$options['cache_method'] && (Less_Cache::$cache_dir || (Less_Parser::$options['cache_method'] == 'callback')));
+ }
+
+}
+
+
+/**
+ * Utility for css colors
+ *
+ * @package Less
+ * @subpackage color
+ */
+class Less_Colors {
+
+ public static $colors = array(
+ 'aliceblue'=>'#f0f8ff',
+ 'antiquewhite'=>'#faebd7',
+ 'aqua'=>'#00ffff',
+ 'aquamarine'=>'#7fffd4',
+ 'azure'=>'#f0ffff',
+ 'beige'=>'#f5f5dc',
+ 'bisque'=>'#ffe4c4',
+ 'black'=>'#000000',
+ 'blanchedalmond'=>'#ffebcd',
+ 'blue'=>'#0000ff',
+ 'blueviolet'=>'#8a2be2',
+ 'brown'=>'#a52a2a',
+ 'burlywood'=>'#deb887',
+ 'cadetblue'=>'#5f9ea0',
+ 'chartreuse'=>'#7fff00',
+ 'chocolate'=>'#d2691e',
+ 'coral'=>'#ff7f50',
+ 'cornflowerblue'=>'#6495ed',
+ 'cornsilk'=>'#fff8dc',
+ 'crimson'=>'#dc143c',
+ 'cyan'=>'#00ffff',
+ 'darkblue'=>'#00008b',
+ 'darkcyan'=>'#008b8b',
+ 'darkgoldenrod'=>'#b8860b',
+ 'darkgray'=>'#a9a9a9',
+ 'darkgrey'=>'#a9a9a9',
+ 'darkgreen'=>'#006400',
+ 'darkkhaki'=>'#bdb76b',
+ 'darkmagenta'=>'#8b008b',
+ 'darkolivegreen'=>'#556b2f',
+ 'darkorange'=>'#ff8c00',
+ 'darkorchid'=>'#9932cc',
+ 'darkred'=>'#8b0000',
+ 'darksalmon'=>'#e9967a',
+ 'darkseagreen'=>'#8fbc8f',
+ 'darkslateblue'=>'#483d8b',
+ 'darkslategray'=>'#2f4f4f',
+ 'darkslategrey'=>'#2f4f4f',
+ 'darkturquoise'=>'#00ced1',
+ 'darkviolet'=>'#9400d3',
+ 'deeppink'=>'#ff1493',
+ 'deepskyblue'=>'#00bfff',
+ 'dimgray'=>'#696969',
+ 'dimgrey'=>'#696969',
+ 'dodgerblue'=>'#1e90ff',
+ 'firebrick'=>'#b22222',
+ 'floralwhite'=>'#fffaf0',
+ 'forestgreen'=>'#228b22',
+ 'fuchsia'=>'#ff00ff',
+ 'gainsboro'=>'#dcdcdc',
+ 'ghostwhite'=>'#f8f8ff',
+ 'gold'=>'#ffd700',
+ 'goldenrod'=>'#daa520',
+ 'gray'=>'#808080',
+ 'grey'=>'#808080',
+ 'green'=>'#008000',
+ 'greenyellow'=>'#adff2f',
+ 'honeydew'=>'#f0fff0',
+ 'hotpink'=>'#ff69b4',
+ 'indianred'=>'#cd5c5c',
+ 'indigo'=>'#4b0082',
+ 'ivory'=>'#fffff0',
+ 'khaki'=>'#f0e68c',
+ 'lavender'=>'#e6e6fa',
+ 'lavenderblush'=>'#fff0f5',
+ 'lawngreen'=>'#7cfc00',
+ 'lemonchiffon'=>'#fffacd',
+ 'lightblue'=>'#add8e6',
+ 'lightcoral'=>'#f08080',
+ 'lightcyan'=>'#e0ffff',
+ 'lightgoldenrodyellow'=>'#fafad2',
+ 'lightgray'=>'#d3d3d3',
+ 'lightgrey'=>'#d3d3d3',
+ 'lightgreen'=>'#90ee90',
+ 'lightpink'=>'#ffb6c1',
+ 'lightsalmon'=>'#ffa07a',
+ 'lightseagreen'=>'#20b2aa',
+ 'lightskyblue'=>'#87cefa',
+ 'lightslategray'=>'#778899',
+ 'lightslategrey'=>'#778899',
+ 'lightsteelblue'=>'#b0c4de',
+ 'lightyellow'=>'#ffffe0',
+ 'lime'=>'#00ff00',
+ 'limegreen'=>'#32cd32',
+ 'linen'=>'#faf0e6',
+ 'magenta'=>'#ff00ff',
+ 'maroon'=>'#800000',
+ 'mediumaquamarine'=>'#66cdaa',
+ 'mediumblue'=>'#0000cd',
+ 'mediumorchid'=>'#ba55d3',
+ 'mediumpurple'=>'#9370d8',
+ 'mediumseagreen'=>'#3cb371',
+ 'mediumslateblue'=>'#7b68ee',
+ 'mediumspringgreen'=>'#00fa9a',
+ 'mediumturquoise'=>'#48d1cc',
+ 'mediumvioletred'=>'#c71585',
+ 'midnightblue'=>'#191970',
+ 'mintcream'=>'#f5fffa',
+ 'mistyrose'=>'#ffe4e1',
+ 'moccasin'=>'#ffe4b5',
+ 'navajowhite'=>'#ffdead',
+ 'navy'=>'#000080',
+ 'oldlace'=>'#fdf5e6',
+ 'olive'=>'#808000',
+ 'olivedrab'=>'#6b8e23',
+ 'orange'=>'#ffa500',
+ 'orangered'=>'#ff4500',
+ 'orchid'=>'#da70d6',
+ 'palegoldenrod'=>'#eee8aa',
+ 'palegreen'=>'#98fb98',
+ 'paleturquoise'=>'#afeeee',
+ 'palevioletred'=>'#d87093',
+ 'papayawhip'=>'#ffefd5',
+ 'peachpuff'=>'#ffdab9',
+ 'peru'=>'#cd853f',
+ 'pink'=>'#ffc0cb',
+ 'plum'=>'#dda0dd',
+ 'powderblue'=>'#b0e0e6',
+ 'purple'=>'#800080',
+ 'red'=>'#ff0000',
+ 'rosybrown'=>'#bc8f8f',
+ 'royalblue'=>'#4169e1',
+ 'saddlebrown'=>'#8b4513',
+ 'salmon'=>'#fa8072',
+ 'sandybrown'=>'#f4a460',
+ 'seagreen'=>'#2e8b57',
+ 'seashell'=>'#fff5ee',
+ 'sienna'=>'#a0522d',
+ 'silver'=>'#c0c0c0',
+ 'skyblue'=>'#87ceeb',
+ 'slateblue'=>'#6a5acd',
+ 'slategray'=>'#708090',
+ 'slategrey'=>'#708090',
+ 'snow'=>'#fffafa',
+ 'springgreen'=>'#00ff7f',
+ 'steelblue'=>'#4682b4',
+ 'tan'=>'#d2b48c',
+ 'teal'=>'#008080',
+ 'thistle'=>'#d8bfd8',
+ 'tomato'=>'#ff6347',
+ 'turquoise'=>'#40e0d0',
+ 'violet'=>'#ee82ee',
+ 'wheat'=>'#f5deb3',
+ 'white'=>'#ffffff',
+ 'whitesmoke'=>'#f5f5f5',
+ 'yellow'=>'#ffff00',
+ 'yellowgreen'=>'#9acd32'
+ );
+
+ public static function hasOwnProperty($color) {
+ return isset(self::$colors[$color]);
+ }
+
+
+ public static function color($color) {
+ return self::$colors[$color];
+ }
+
+}
+
+
+
+/**
+ * Environment
+ *
+ * @package Less
+ * @subpackage environment
+ */
+class Less_Environment{
+
+ //public $paths = array(); // option - unmodified - paths to search for imports on
+ //public static $files = array(); // list of files that have been imported, used for import-once
+ //public $rootpath; // option - rootpath to append to URL's
+ //public static $strictImports = null; // option -
+ //public $insecure; // option - whether to allow imports from insecure ssl hosts
+ //public $processImports; // option - whether to process imports. if false then imports will not be imported
+ //public $javascriptEnabled; // option - whether JavaScript is enabled. if undefined, defaults to true
+ //public $useFileCache; // browser only - whether to use the per file session cache
+ public $currentFileInfo; // information about the current file - for error reporting and importing and making urls relative etc.
+
+ public $importMultiple = false; // whether we are currently importing multiple copies
+
+
+ /**
+ * @var array
+ */
+ public $frames = array();
+
+ /**
+ * @var array
+ */
+ public $mediaBlocks = array();
+
+ /**
+ * @var array
+ */
+ public $mediaPath = array();
+
+ public static $parensStack = 0;
+
+ public static $tabLevel = 0;
+
+ public static $lastRule = false;
+
+ public static $_outputMap;
+
+ public static $mixin_stack = 0;
+
+ /**
+ * @var array
+ */
+ public $functions = array();
+
+
+ public function Init(){
+
+ self::$parensStack = 0;
+ self::$tabLevel = 0;
+ self::$lastRule = false;
+ self::$mixin_stack = 0;
+
+ if( Less_Parser::$options['compress'] ){
+
+ Less_Environment::$_outputMap = array(
+ ',' => ',',
+ ': ' => ':',
+ '' => '',
+ ' ' => ' ',
+ ':' => ' :',
+ '+' => '+',
+ '~' => '~',
+ '>' => '>',
+ '|' => '|',
+ '^' => '^',
+ '^^' => '^^'
+ );
+
+ }else{
+
+ Less_Environment::$_outputMap = array(
+ ',' => ', ',
+ ': ' => ': ',
+ '' => '',
+ ' ' => ' ',
+ ':' => ' :',
+ '+' => ' + ',
+ '~' => ' ~ ',
+ '>' => ' > ',
+ '|' => '|',
+ '^' => ' ^ ',
+ '^^' => ' ^^ '
+ );
+
+ }
+ }
+
+
+ public function copyEvalEnv($frames = array() ){
+ $new_env = new Less_Environment();
+ $new_env->frames = $frames;
+ return $new_env;
+ }
+
+
+ public static function isMathOn(){
+ return !Less_Parser::$options['strictMath'] || Less_Environment::$parensStack;
+ }
+
+ public static function isPathRelative($path){
+ return !preg_match('/^(?:[a-z-]+:|\/)/',$path);
+ }
+
+
+ /**
+ * Canonicalize a path by resolving references to '/./', '/../'
+ * Does not remove leading "../"
+ * @param string path or url
+ * @return string Canonicalized path
+ *
+ */
+ public static function normalizePath($path){
+
+ $segments = explode('/',$path);
+ $segments = array_reverse($segments);
+
+ $path = array();
+ $path_len = 0;
+
+ while( $segments ){
+ $segment = array_pop($segments);
+ switch( $segment ) {
+
+ case '.':
+ break;
+
+ case '..':
+ if( !$path_len || ( $path[$path_len-1] === '..') ){
+ $path[] = $segment;
+ $path_len++;
+ }else{
+ array_pop($path);
+ $path_len--;
+ }
+ break;
+
+ default:
+ $path[] = $segment;
+ $path_len++;
+ break;
+ }
+ }
+
+ return implode('/',$path);
+ }
+
+
+ public function unshiftFrame($frame){
+ array_unshift($this->frames, $frame);
+ }
+
+ public function shiftFrame(){
+ return array_shift($this->frames);
+ }
+
+}
+
+
+/**
+ * Builtin functions
+ *
+ * @package Less
+ * @subpackage function
+ * @see http://lesscss.org/functions/
+ */
+class Less_Functions{
+
+ public $env;
+ public $currentFileInfo;
+
+ function __construct($env, $currentFileInfo = null ){
+ $this->env = $env;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ /**
+ * @param string $op
+ */
+ public static function operate( $op, $a, $b ){
+ switch ($op) {
+ case '+': return $a + $b;
+ case '-': return $a - $b;
+ case '*': return $a * $b;
+ case '/': return $a / $b;
+ }
+ }
+
+ public static function clamp($val, $max = 1){
+ return min( max($val, 0), $max);
+ }
+
+ public static function fround( $value ){
+
+ if( $value === 0 ){
+ return $value;
+ }
+
+ if( Less_Parser::$options['numPrecision'] ){
+ $p = pow(10, Less_Parser::$options['numPrecision']);
+ return round( $value * $p) / $p;
+ }
+ return $value;
+ }
+
+ public static function number($n){
+
+ if ($n instanceof Less_Tree_Dimension) {
+ return floatval( $n->unit->is('%') ? $n->value / 100 : $n->value);
+ } else if (is_numeric($n)) {
+ return $n;
+ } else {
+ throw new Less_Exception_Compiler("color functions take numbers as parameters");
+ }
+ }
+
+ public static function scaled($n, $size = 255 ){
+ if( $n instanceof Less_Tree_Dimension && $n->unit->is('%') ){
+ return (float)$n->value * $size / 100;
+ } else {
+ return Less_Functions::number($n);
+ }
+ }
+
+ public function rgb ($r = null, $g = null, $b = null){
+ if (is_null($r) || is_null($g) || is_null($b)) {
+ throw new Less_Exception_Compiler("rgb expects three parameters");
+ }
+ return $this->rgba($r, $g, $b, 1.0);
+ }
+
+ public function rgba($r = null, $g = null, $b = null, $a = null){
+ $rgb = array($r, $g, $b);
+ $rgb = array_map(array('Less_Functions','scaled'),$rgb);
+
+ $a = self::number($a);
+ return new Less_Tree_Color($rgb, $a);
+ }
+
+ public function hsl($h, $s, $l){
+ return $this->hsla($h, $s, $l, 1.0);
+ }
+
+ public function hsla($h, $s, $l, $a){
+
+ $h = fmod(self::number($h), 360) / 360; // Classic % operator will change float to int
+ $s = self::clamp(self::number($s));
+ $l = self::clamp(self::number($l));
+ $a = self::clamp(self::number($a));
+
+ $m2 = $l <= 0.5 ? $l * ($s + 1) : $l + $s - $l * $s;
+
+ $m1 = $l * 2 - $m2;
+
+ return $this->rgba( self::hsla_hue($h + 1/3, $m1, $m2) * 255,
+ self::hsla_hue($h, $m1, $m2) * 255,
+ self::hsla_hue($h - 1/3, $m1, $m2) * 255,
+ $a);
+ }
+
+ /**
+ * @param double $h
+ */
+ public function hsla_hue($h, $m1, $m2){
+ $h = $h < 0 ? $h + 1 : ($h > 1 ? $h - 1 : $h);
+ if ($h * 6 < 1) return $m1 + ($m2 - $m1) * $h * 6;
+ else if ($h * 2 < 1) return $m2;
+ else if ($h * 3 < 2) return $m1 + ($m2 - $m1) * (2/3 - $h) * 6;
+ else return $m1;
+ }
+
+ public function hsv($h, $s, $v) {
+ return $this->hsva($h, $s, $v, 1.0);
+ }
+
+ /**
+ * @param double $a
+ */
+ public function hsva($h, $s, $v, $a) {
+ $h = ((Less_Functions::number($h) % 360) / 360 ) * 360;
+ $s = Less_Functions::number($s);
+ $v = Less_Functions::number($v);
+ $a = Less_Functions::number($a);
+
+ $i = floor(($h / 60) % 6);
+ $f = ($h / 60) - $i;
+
+ $vs = array( $v,
+ $v * (1 - $s),
+ $v * (1 - $f * $s),
+ $v * (1 - (1 - $f) * $s));
+
+ $perm = array(array(0, 3, 1),
+ array(2, 0, 1),
+ array(1, 0, 3),
+ array(1, 2, 0),
+ array(3, 1, 0),
+ array(0, 1, 2));
+
+ return $this->rgba($vs[$perm[$i][0]] * 255,
+ $vs[$perm[$i][1]] * 255,
+ $vs[$perm[$i][2]] * 255,
+ $a);
+ }
+
+ public function hue($color = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to hue must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $c = $color->toHSL();
+ return new Less_Tree_Dimension(Less_Parser::round($c['h']));
+ }
+
+ public function saturation($color = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to saturation must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $c = $color->toHSL();
+ return new Less_Tree_Dimension(Less_Parser::round($c['s'] * 100), '%');
+ }
+
+ public function lightness($color = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to lightness must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $c = $color->toHSL();
+ return new Less_Tree_Dimension(Less_Parser::round($c['l'] * 100), '%');
+ }
+
+ public function hsvhue( $color = null ){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to hsvhue must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsv = $color->toHSV();
+ return new Less_Tree_Dimension( Less_Parser::round($hsv['h']) );
+ }
+
+
+ public function hsvsaturation( $color = null ){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to hsvsaturation must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsv = $color->toHSV();
+ return new Less_Tree_Dimension( Less_Parser::round($hsv['s'] * 100), '%' );
+ }
+
+ public function hsvvalue( $color = null ){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to hsvvalue must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsv = $color->toHSV();
+ return new Less_Tree_Dimension( Less_Parser::round($hsv['v'] * 100), '%' );
+ }
+
+ public function red($color = null) {
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to red must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return new Less_Tree_Dimension( $color->rgb[0] );
+ }
+
+ public function green($color = null) {
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to green must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return new Less_Tree_Dimension( $color->rgb[1] );
+ }
+
+ public function blue($color = null) {
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to blue must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return new Less_Tree_Dimension( $color->rgb[2] );
+ }
+
+ public function alpha($color = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to alpha must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $c = $color->toHSL();
+ return new Less_Tree_Dimension($c['a']);
+ }
+
+ public function luma ($color = null) {
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to luma must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return new Less_Tree_Dimension(Less_Parser::round( $color->luma() * $color->alpha * 100), '%');
+ }
+
+ public function luminance( $color = null ){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to luminance must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $luminance =
+ (0.2126 * $color->rgb[0] / 255)
+ + (0.7152 * $color->rgb[1] / 255)
+ + (0.0722 * $color->rgb[2] / 255);
+
+ return new Less_Tree_Dimension(Less_Parser::round( $luminance * $color->alpha * 100), '%');
+ }
+
+ public function saturate($color = null, $amount = null){
+ // filter: saturate(3.2);
+ // should be kept as is, so check for color
+ if ($color instanceof Less_Tree_Dimension) {
+ return null;
+ }
+
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to saturate must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$amount instanceof Less_Tree_Dimension) {
+ throw new Less_Exception_Compiler('The second argument to saturate must be a percentage' . ($amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsl = $color->toHSL();
+
+ $hsl['s'] += $amount->value / 100;
+ $hsl['s'] = self::clamp($hsl['s']);
+
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+ /**
+ * @param Less_Tree_Dimension $amount
+ */
+ public function desaturate($color = null, $amount = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to desaturate must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$amount instanceof Less_Tree_Dimension) {
+ throw new Less_Exception_Compiler('The second argument to desaturate must be a percentage' . ($amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsl = $color->toHSL();
+
+ $hsl['s'] -= $amount->value / 100;
+ $hsl['s'] = self::clamp($hsl['s']);
+
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+
+
+ public function lighten($color = null, $amount=null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to lighten must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$amount instanceof Less_Tree_Dimension) {
+ throw new Less_Exception_Compiler('The second argument to lighten must be a percentage' . ($amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsl = $color->toHSL();
+
+ $hsl['l'] += $amount->value / 100;
+ $hsl['l'] = self::clamp($hsl['l']);
+
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+ public function darken($color = null, $amount = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to darken must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$amount instanceof Less_Tree_Dimension) {
+ throw new Less_Exception_Compiler('The second argument to darken must be a percentage' . ($amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsl = $color->toHSL();
+ $hsl['l'] -= $amount->value / 100;
+ $hsl['l'] = self::clamp($hsl['l']);
+
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+ public function fadein($color = null, $amount = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to fadein must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$amount instanceof Less_Tree_Dimension) {
+ throw new Less_Exception_Compiler('The second argument to fadein must be a percentage' . ($amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsl = $color->toHSL();
+ $hsl['a'] += $amount->value / 100;
+ $hsl['a'] = self::clamp($hsl['a']);
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+ public function fadeout($color = null, $amount = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to fadeout must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$amount instanceof Less_Tree_Dimension) {
+ throw new Less_Exception_Compiler('The second argument to fadeout must be a percentage' . ($amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsl = $color->toHSL();
+ $hsl['a'] -= $amount->value / 100;
+ $hsl['a'] = self::clamp($hsl['a']);
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+ public function fade($color = null, $amount = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to fade must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$amount instanceof Less_Tree_Dimension) {
+ throw new Less_Exception_Compiler('The second argument to fade must be a percentage' . ($amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsl = $color->toHSL();
+
+ $hsl['a'] = $amount->value / 100;
+ $hsl['a'] = self::clamp($hsl['a']);
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+
+
+ public function spin($color = null, $amount = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to spin must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$amount instanceof Less_Tree_Dimension) {
+ throw new Less_Exception_Compiler('The second argument to spin must be a number' . ($amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsl = $color->toHSL();
+ $hue = fmod($hsl['h'] + $amount->value, 360);
+
+ $hsl['h'] = $hue < 0 ? 360 + $hue : $hue;
+
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+ //
+ // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein
+ // http://sass-lang.com
+ //
+
+ /**
+ * @param Less_Tree_Color $color1
+ */
+ public function mix($color1 = null, $color2 = null, $weight = null){
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to mix must be a color' . ($color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to mix must be a color' . ($color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$weight) {
+ $weight = new Less_Tree_Dimension('50', '%');
+ }
+ if (!$weight instanceof Less_Tree_Dimension) {
+ throw new Less_Exception_Compiler('The third argument to contrast must be a percentage' . ($weight instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $p = $weight->value / 100.0;
+ $w = $p * 2 - 1;
+ $hsl1 = $color1->toHSL();
+ $hsl2 = $color2->toHSL();
+ $a = $hsl1['a'] - $hsl2['a'];
+
+ $w1 = (((($w * $a) == -1) ? $w : ($w + $a) / (1 + $w * $a)) + 1) / 2;
+ $w2 = 1 - $w1;
+
+ $rgb = array($color1->rgb[0] * $w1 + $color2->rgb[0] * $w2,
+ $color1->rgb[1] * $w1 + $color2->rgb[1] * $w2,
+ $color1->rgb[2] * $w1 + $color2->rgb[2] * $w2);
+
+ $alpha = $color1->alpha * $p + $color2->alpha * (1 - $p);
+
+ return new Less_Tree_Color($rgb, $alpha);
+ }
+
+ public function greyscale($color){
+ return $this->desaturate($color, new Less_Tree_Dimension(100,'%'));
+ }
+
+
+ public function contrast( $color, $dark = null, $light = null, $threshold = null){
+ // filter: contrast(3.2);
+ // should be kept as is, so check for color
+ if (!$color instanceof Less_Tree_Color) {
+ return null;
+ }
+ if( !$light ){
+ $light = $this->rgba(255, 255, 255, 1.0);
+ }
+ if( !$dark ){
+ $dark = $this->rgba(0, 0, 0, 1.0);
+ }
+
+ if (!$dark instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to contrast must be a color' . ($dark instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$light instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The third argument to contrast must be a color' . ($light instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ //Figure out which is actually light and dark!
+ if( $dark->luma() > $light->luma() ){
+ $t = $light;
+ $light = $dark;
+ $dark = $t;
+ }
+ if( !$threshold ){
+ $threshold = 0.43;
+ } else {
+ $threshold = Less_Functions::number($threshold);
+ }
+
+ if( $color->luma() < $threshold ){
+ return $light;
+ } else {
+ return $dark;
+ }
+ }
+
+ public function e ($str){
+ if( is_string($str) ){
+ return new Less_Tree_Anonymous($str);
+ }
+ return new Less_Tree_Anonymous($str instanceof Less_Tree_JavaScript ? $str->expression : $str->value);
+ }
+
+ public function escape ($str){
+
+ $revert = array('%21'=>'!', '%2A'=>'*', '%27'=>"'",'%3F'=>'?','%26'=>'&','%2C'=>',','%2F'=>'/','%40'=>'@','%2B'=>'+','%24'=>'$');
+
+ return new Less_Tree_Anonymous(strtr(rawurlencode($str->value), $revert));
+ }
+
+
+ /**
+ * todo: This function will need some additional work to make it work the same as less.js
+ *
+ */
+ public function replace( $string, $pattern, $replacement, $flags = null ){
+ $result = $string->value;
+
+ $expr = '/'.str_replace('/','\\/',$pattern->value).'/';
+ if( $flags && $flags->value){
+ $expr .= self::replace_flags($flags->value);
+ }
+
+ $result = preg_replace($expr,$replacement->value,$result);
+
+
+ if( property_exists($string,'quote') ){
+ return new Less_Tree_Quoted( $string->quote, $result, $string->escaped);
+ }
+ return new Less_Tree_Quoted( '', $result );
+ }
+
+ public static function replace_flags($flags){
+ $flags = str_split($flags,1);
+ $new_flags = '';
+
+ foreach($flags as $flag){
+ switch($flag){
+ case 'e':
+ case 'g':
+ break;
+
+ default:
+ $new_flags .= $flag;
+ break;
+ }
+ }
+
+ return $new_flags;
+ }
+
+ public function _percent(){
+ $string = func_get_arg(0);
+
+ $args = func_get_args();
+ array_shift($args);
+ $result = $string->value;
+
+ foreach($args as $arg){
+ if( preg_match('/%[sda]/i',$result, $token) ){
+ $token = $token[0];
+ $value = stristr($token, 's') ? $arg->value : $arg->toCSS();
+ $value = preg_match('/[A-Z]$/', $token) ? urlencode($value) : $value;
+ $result = preg_replace('/%[sda]/i',$value, $result, 1);
+ }
+ }
+ $result = str_replace('%%', '%', $result);
+
+ return new Less_Tree_Quoted( $string->quote , $result, $string->escaped);
+ }
+
+ public function unit( $val, $unit = null) {
+ if( !($val instanceof Less_Tree_Dimension) ){
+ throw new Less_Exception_Compiler('The first argument to unit must be a number' . ($val instanceof Less_Tree_Operation ? '. Have you forgotten parenthesis?' : '.') );
+ }
+
+ if( $unit ){
+ if( $unit instanceof Less_Tree_Keyword ){
+ $unit = $unit->value;
+ } else {
+ $unit = $unit->toCSS();
+ }
+ } else {
+ $unit = "";
+ }
+ return new Less_Tree_Dimension($val->value, $unit );
+ }
+
+ public function convert($val, $unit){
+ return $val->convertTo($unit->value);
+ }
+
+ public function round($n, $f = false) {
+
+ $fraction = 0;
+ if( $f !== false ){
+ $fraction = $f->value;
+ }
+
+ return $this->_math('Less_Parser::round',null, $n, $fraction);
+ }
+
+ public function pi(){
+ return new Less_Tree_Dimension(M_PI);
+ }
+
+ public function mod($a, $b) {
+ return new Less_Tree_Dimension( $a->value % $b->value, $a->unit);
+ }
+
+
+
+ public function pow($x, $y) {
+ if( is_numeric($x) && is_numeric($y) ){
+ $x = new Less_Tree_Dimension($x);
+ $y = new Less_Tree_Dimension($y);
+ }elseif( !($x instanceof Less_Tree_Dimension) || !($y instanceof Less_Tree_Dimension) ){
+ throw new Less_Exception_Compiler('Arguments must be numbers');
+ }
+
+ return new Less_Tree_Dimension( pow($x->value, $y->value), $x->unit );
+ }
+
+ // var mathFunctions = [{name:"ce ...
+ public function ceil( $n ){ return $this->_math('ceil', null, $n); }
+ public function floor( $n ){ return $this->_math('floor', null, $n); }
+ public function sqrt( $n ){ return $this->_math('sqrt', null, $n); }
+ public function abs( $n ){ return $this->_math('abs', null, $n); }
+
+ public function tan( $n ){ return $this->_math('tan', '', $n); }
+ public function sin( $n ){ return $this->_math('sin', '', $n); }
+ public function cos( $n ){ return $this->_math('cos', '', $n); }
+
+ public function atan( $n ){ return $this->_math('atan', 'rad', $n); }
+ public function asin( $n ){ return $this->_math('asin', 'rad', $n); }
+ public function acos( $n ){ return $this->_math('acos', 'rad', $n); }
+
+ private function _math() {
+ $args = func_get_args();
+ $fn = array_shift($args);
+ $unit = array_shift($args);
+
+ if ($args[0] instanceof Less_Tree_Dimension) {
+
+ if( $unit === null ){
+ $unit = $args[0]->unit;
+ }else{
+ $args[0] = $args[0]->unify();
+ }
+ $args[0] = (float)$args[0]->value;
+ return new Less_Tree_Dimension( call_user_func_array($fn, $args), $unit);
+ } else if (is_numeric($args[0])) {
+ return call_user_func_array($fn,$args);
+ } else {
+ throw new Less_Exception_Compiler("math functions take numbers as parameters");
+ }
+ }
+
+ /**
+ * @param boolean $isMin
+ */
+ private function _minmax( $isMin, $args ){
+
+ $arg_count = count($args);
+
+ if( $arg_count < 1 ){
+ throw new Less_Exception_Compiler( 'one or more arguments required');
+ }
+
+ $j = null;
+ $unitClone = null;
+ $unitStatic = null;
+
+
+ $order = array(); // elems only contains original argument values.
+ $values = array(); // key is the unit.toString() for unified tree.Dimension values,
+ // value is the index into the order array.
+
+
+ for( $i = 0; $i < $arg_count; $i++ ){
+ $current = $args[$i];
+ if( !($current instanceof Less_Tree_Dimension) ){
+ if( is_array($args[$i]->value) ){
+ $args[] = $args[$i]->value;
+ }
+ continue;
+ }
+
+ if( $current->unit->toString() === '' && !$unitClone ){
+ $temp = new Less_Tree_Dimension($current->value, $unitClone);
+ $currentUnified = $temp->unify();
+ }else{
+ $currentUnified = $current->unify();
+ }
+
+ if( $currentUnified->unit->toString() === "" && !$unitStatic ){
+ $unit = $unitStatic;
+ }else{
+ $unit = $currentUnified->unit->toString();
+ }
+
+ if( $unit !== '' && !$unitStatic || $unit !== '' && $order[0]->unify()->unit->toString() === "" ){
+ $unitStatic = $unit;
+ }
+
+ if( $unit != '' && !$unitClone ){
+ $unitClone = $current->unit->toString();
+ }
+
+ if( isset($values['']) && $unit !== '' && $unit === $unitStatic ){
+ $j = $values[''];
+ }elseif( isset($values[$unit]) ){
+ $j = $values[$unit];
+ }else{
+
+ if( $unitStatic && $unit !== $unitStatic ){
+ throw new Less_Exception_Compiler( 'incompatible types');
+ }
+ $values[$unit] = count($order);
+ $order[] = $current;
+ continue;
+ }
+
+
+ if( $order[$j]->unit->toString() === "" && $unitClone ){
+ $temp = new Less_Tree_Dimension( $order[$j]->value, $unitClone);
+ $referenceUnified = $temp->unify();
+ }else{
+ $referenceUnified = $order[$j]->unify();
+ }
+ if( ($isMin && $currentUnified->value < $referenceUnified->value) || (!$isMin && $currentUnified->value > $referenceUnified->value) ){
+ $order[$j] = $current;
+ }
+ }
+
+ if( count($order) == 1 ){
+ return $order[0];
+ }
+ $args = array();
+ foreach($order as $a){
+ $args[] = $a->toCSS($this->env);
+ }
+ return new Less_Tree_Anonymous( ($isMin?'min(':'max(') . implode(Less_Environment::$_outputMap[','],$args).')');
+ }
+
+ public function min(){
+ $args = func_get_args();
+ return $this->_minmax( true, $args );
+ }
+
+ public function max(){
+ $args = func_get_args();
+ return $this->_minmax( false, $args );
+ }
+
+ public function getunit($n){
+ return new Less_Tree_Anonymous($n->unit);
+ }
+
+ public function argb($color) {
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to argb must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return new Less_Tree_Anonymous($color->toARGB());
+ }
+
+ public function percentage($n) {
+ return new Less_Tree_Dimension($n->value * 100, '%');
+ }
+
+ public function color($n) {
+
+ if( $n instanceof Less_Tree_Quoted ){
+ $colorCandidate = $n->value;
+ $returnColor = Less_Tree_Color::fromKeyword($colorCandidate);
+ if( $returnColor ){
+ return $returnColor;
+ }
+ if( preg_match('/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/',$colorCandidate) ){
+ return new Less_Tree_Color(substr($colorCandidate, 1));
+ }
+ throw new Less_Exception_Compiler("argument must be a color keyword or 3/6 digit hex e.g. #FFF");
+ } else {
+ throw new Less_Exception_Compiler("argument must be a string");
+ }
+ }
+
+
+ public function iscolor($n) {
+ return $this->_isa($n, 'Less_Tree_Color');
+ }
+
+ public function isnumber($n) {
+ return $this->_isa($n, 'Less_Tree_Dimension');
+ }
+
+ public function isstring($n) {
+ return $this->_isa($n, 'Less_Tree_Quoted');
+ }
+
+ public function iskeyword($n) {
+ return $this->_isa($n, 'Less_Tree_Keyword');
+ }
+
+ public function isurl($n) {
+ return $this->_isa($n, 'Less_Tree_Url');
+ }
+
+ public function ispixel($n) {
+ return $this->isunit($n, 'px');
+ }
+
+ public function ispercentage($n) {
+ return $this->isunit($n, '%');
+ }
+
+ public function isem($n) {
+ return $this->isunit($n, 'em');
+ }
+
+ /**
+ * @param string $unit
+ */
+ public function isunit( $n, $unit ){
+ return ($n instanceof Less_Tree_Dimension) && $n->unit->is( ( property_exists($unit,'value') ? $unit->value : $unit) ) ? new Less_Tree_Keyword('true') : new Less_Tree_Keyword('false');
+ }
+
+ /**
+ * @param string $type
+ */
+ private function _isa($n, $type) {
+ return is_a($n, $type) ? new Less_Tree_Keyword('true') : new Less_Tree_Keyword('false');
+ }
+
+ public function tint($color, $amount) {
+ return $this->mix( $this->rgb(255,255,255), $color, $amount);
+ }
+
+ public function shade($color, $amount) {
+ return $this->mix($this->rgb(0, 0, 0), $color, $amount);
+ }
+
+ public function extract($values, $index ){
+ $index = (int)$index->value - 1; // (1-based index)
+ // handle non-array values as an array of length 1
+ // return 'undefined' if index is invalid
+ if( property_exists($values,'value') && is_array($values->value) ){
+ if( isset($values->value[$index]) ){
+ return $values->value[$index];
+ }
+ return null;
+
+ }elseif( (int)$index === 0 ){
+ return $values;
+ }
+
+ return null;
+ }
+
+ public function length($values){
+ $n = (property_exists($values,'value') && is_array($values->value)) ? count($values->value) : 1;
+ return new Less_Tree_Dimension($n);
+ }
+
+ public function datauri($mimetypeNode, $filePathNode = null ) {
+
+ $filePath = ( $filePathNode ? $filePathNode->value : null );
+ $mimetype = $mimetypeNode->value;
+
+ $args = 2;
+ if( !$filePath ){
+ $filePath = $mimetype;
+ $args = 1;
+ }
+
+ $filePath = str_replace('\\','/',$filePath);
+ if( Less_Environment::isPathRelative($filePath) ){
+
+ if( Less_Parser::$options['relativeUrls'] ){
+ $temp = $this->currentFileInfo['currentDirectory'];
+ } else {
+ $temp = $this->currentFileInfo['entryPath'];
+ }
+
+ if( !empty($temp) ){
+ $filePath = Less_Environment::normalizePath(rtrim($temp,'/').'/'.$filePath);
+ }
+
+ }
+
+
+ // detect the mimetype if not given
+ if( $args < 2 ){
+
+ /* incomplete
+ $mime = require('mime');
+ mimetype = mime.lookup(path);
+
+ // use base 64 unless it's an ASCII or UTF-8 format
+ var charset = mime.charsets.lookup(mimetype);
+ useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0;
+ if (useBase64) mimetype += ';base64';
+ */
+
+ $mimetype = Less_Mime::lookup($filePath);
+
+ $charset = Less_Mime::charsets_lookup($mimetype);
+ $useBase64 = !in_array($charset,array('US-ASCII', 'UTF-8'));
+ if( $useBase64 ){ $mimetype .= ';base64'; }
+
+ }else{
+ $useBase64 = preg_match('/;base64$/',$mimetype);
+ }
+
+
+ if( file_exists($filePath) ){
+ $buf = @file_get_contents($filePath);
+ }else{
+ $buf = false;
+ }
+
+
+ // IE8 cannot handle a data-uri larger than 32KB. If this is exceeded
+ // and the --ieCompat flag is enabled, return a normal url() instead.
+ $DATA_URI_MAX_KB = 32;
+ $fileSizeInKB = round( strlen($buf) / 1024 );
+ if( $fileSizeInKB >= $DATA_URI_MAX_KB ){
+ $url = new Less_Tree_Url( ($filePathNode ? $filePathNode : $mimetypeNode), $this->currentFileInfo);
+ return $url->compile($this);
+ }
+
+ if( $buf ){
+ $buf = $useBase64 ? base64_encode($buf) : rawurlencode($buf);
+ $filePath = '"data:' . $mimetype . ',' . $buf . '"';
+ }
+
+ return new Less_Tree_Url( new Less_Tree_Anonymous($filePath) );
+ }
+
+ //svg-gradient
+ public function svggradient( $direction ){
+
+ $throw_message = 'svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position]';
+ $arguments = func_get_args();
+
+ if( count($arguments) < 3 ){
+ throw new Less_Exception_Compiler( $throw_message );
+ }
+
+ $stops = array_slice($arguments,1);
+ $gradientType = 'linear';
+ $rectangleDimension = 'x="0" y="0" width="1" height="1"';
+ $useBase64 = true;
+ $directionValue = $direction->toCSS();
+
+
+ switch( $directionValue ){
+ case "to bottom":
+ $gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"';
+ break;
+ case "to right":
+ $gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"';
+ break;
+ case "to bottom right":
+ $gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"';
+ break;
+ case "to top right":
+ $gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"';
+ break;
+ case "ellipse":
+ case "ellipse at center":
+ $gradientType = "radial";
+ $gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"';
+ $rectangleDimension = 'x="-50" y="-50" width="101" height="101"';
+ break;
+ default:
+ throw new Less_Exception_Compiler( "svg-gradient direction must be 'to bottom', 'to right', 'to bottom right', 'to top right' or 'ellipse at center'" );
+ }
+
+ $returner = '<?xml version="1.0" ?>' .
+ '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">' .
+ '<' . $gradientType . 'Gradient id="gradient" gradientUnits="userSpaceOnUse" ' . $gradientDirectionSvg . '>';
+
+ for( $i = 0; $i < count($stops); $i++ ){
+ if( is_object($stops[$i]) && property_exists($stops[$i],'value') ){
+ $color = $stops[$i]->value[0];
+ $position = $stops[$i]->value[1];
+ }else{
+ $color = $stops[$i];
+ $position = null;
+ }
+
+ if( !($color instanceof Less_Tree_Color) || (!(($i === 0 || $i+1 === count($stops)) && $position === null) && !($position instanceof Less_Tree_Dimension)) ){
+ throw new Less_Exception_Compiler( $throw_message );
+ }
+ if( $position ){
+ $positionValue = $position->toCSS();
+ }elseif( $i === 0 ){
+ $positionValue = '0%';
+ }else{
+ $positionValue = '100%';
+ }
+ $alpha = $color->alpha;
+ $returner .= '<stop offset="' . $positionValue . '" stop-color="' . $color->toRGB() . '"' . ($alpha < 1 ? ' stop-opacity="' . $alpha . '"' : '') . '/>';
+ }
+
+ $returner .= '</' . $gradientType . 'Gradient><rect ' . $rectangleDimension . ' fill="url(#gradient)" /></svg>';
+
+
+ if( $useBase64 ){
+ $returner = "'data:image/svg+xml;base64,".base64_encode($returner)."'";
+ }else{
+ $returner = "'data:image/svg+xml,".$returner."'";
+ }
+
+ return new Less_Tree_URL( new Less_Tree_Anonymous( $returner ) );
+ }
+
+
+ /**
+ * Php version of javascript's `encodeURIComponent` function
+ *
+ * @param string $string The string to encode
+ * @return string The encoded string
+ */
+ public static function encodeURIComponent($string){
+ $revert = array('%21' => '!', '%2A' => '*', '%27' => "'", '%28' => '(', '%29' => ')');
+ return strtr(rawurlencode($string), $revert);
+ }
+
+
+ // Color Blending
+ // ref: http://www.w3.org/TR/compositing-1
+
+ public function colorBlend( $mode, $color1, $color2 ){
+ $ab = $color1->alpha; // backdrop
+ $as = $color2->alpha; // source
+ $r = array(); // result
+
+ $ar = $as + $ab * (1 - $as);
+ for( $i = 0; $i < 3; $i++ ){
+ $cb = $color1->rgb[$i] / 255;
+ $cs = $color2->rgb[$i] / 255;
+ $cr = call_user_func( $mode, $cb, $cs );
+ if( $ar ){
+ $cr = ($as * $cs + $ab * ($cb - $as * ($cb + $cs - $cr))) / $ar;
+ }
+ $r[$i] = $cr * 255;
+ }
+
+ return new Less_Tree_Color($r, $ar);
+ }
+
+ public function multiply($color1 = null, $color2 = null ){
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to multiply must be a color' . ($color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to multiply must be a color' . ($color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return $this->colorBlend( array($this,'colorBlendMultiply'), $color1, $color2 );
+ }
+
+ private function colorBlendMultiply($cb, $cs){
+ return $cb * $cs;
+ }
+
+ public function screen($color1 = null, $color2 = null ){
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to screen must be a color' . ($color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to screen must be a color' . ($color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return $this->colorBlend( array($this,'colorBlendScreen'), $color1, $color2 );
+ }
+
+ private function colorBlendScreen( $cb, $cs){
+ return $cb + $cs - $cb * $cs;
+ }
+
+ public function overlay($color1 = null, $color2 = null){
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to overlay must be a color' . ($color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to overlay must be a color' . ($color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return $this->colorBlend( array($this,'colorBlendOverlay'), $color1, $color2 );
+ }
+
+ private function colorBlendOverlay($cb, $cs ){
+ $cb *= 2;
+ return ($cb <= 1)
+ ? $this->colorBlendMultiply($cb, $cs)
+ : $this->colorBlendScreen($cb - 1, $cs);
+ }
+
+ public function softlight($color1 = null, $color2 = null){
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to softlight must be a color' . ($color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to softlight must be a color' . ($color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return $this->colorBlend( array($this,'colorBlendSoftlight'), $color1, $color2 );
+ }
+
+ private function colorBlendSoftlight($cb, $cs ){
+ $d = 1;
+ $e = $cb;
+ if( $cs > 0.5 ){
+ $e = 1;
+ $d = ($cb > 0.25) ? sqrt($cb)
+ : ((16 * $cb - 12) * $cb + 4) * $cb;
+ }
+ return $cb - (1 - 2 * $cs) * $e * ($d - $cb);
+ }
+
+ public function hardlight($color1 = null, $color2 = null){
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to hardlight must be a color' . ($color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to hardlight must be a color' . ($color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return $this->colorBlend( array($this,'colorBlendHardlight'), $color1, $color2 );
+ }
+
+ private function colorBlendHardlight( $cb, $cs ){
+ return $this->colorBlendOverlay($cs, $cb);
+ }
+
+ public function difference($color1 = null, $color2 = null) {
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to difference must be a color' . ($color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to difference must be a color' . ($color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return $this->colorBlend( array($this,'colorBlendDifference'), $color1, $color2 );
+ }
+
+ private function colorBlendDifference( $cb, $cs ){
+ return abs($cb - $cs);
+ }
+
+ public function exclusion( $color1 = null, $color2 = null ){
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to exclusion must be a color' . ($color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to exclusion must be a color' . ($color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return $this->colorBlend( array($this,'colorBlendExclusion'), $color1, $color2 );
+ }
+
+ private function colorBlendExclusion( $cb, $cs ){
+ return $cb + $cs - 2 * $cb * $cs;
+ }
+
+ public function average($color1 = null, $color2 = null){
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to average must be a color' . ($color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to average must be a color' . ($color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return $this->colorBlend( array($this,'colorBlendAverage'), $color1, $color2 );
+ }
+
+ // non-w3c functions:
+ public function colorBlendAverage($cb, $cs ){
+ return ($cb + $cs) / 2;
+ }
+
+ public function negation($color1 = null, $color2 = null ){
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to negation must be a color' . ($color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to negation must be a color' . ($color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return $this->colorBlend( array($this,'colorBlendNegation'), $color1, $color2 );
+ }
+
+ public function colorBlendNegation($cb, $cs){
+ return 1 - abs($cb + $cs - 1);
+ }
+
+ // ~ End of Color Blending
+
+}
+
+
+/**
+ * Mime lookup
+ *
+ * @package Less
+ * @subpackage node
+ */
+class Less_Mime{
+
+ // this map is intentionally incomplete
+ // if you want more, install 'mime' dep
+ static $_types = array(
+ '.htm' => 'text/html',
+ '.html'=> 'text/html',
+ '.gif' => 'image/gif',
+ '.jpg' => 'image/jpeg',
+ '.jpeg'=> 'image/jpeg',
+ '.png' => 'image/png',
+ '.ttf' => 'application/x-font-ttf',
+ '.otf' => 'application/x-font-otf',
+ '.eot' => 'application/vnd.ms-fontobject',
+ '.woff' => 'application/x-font-woff',
+ '.svg' => 'image/svg+xml',
+ );
+
+ public static function lookup( $filepath ){
+ $parts = explode('.',$filepath);
+ $ext = '.'.strtolower(array_pop($parts));
+
+ if( !isset(self::$_types[$ext]) ){
+ return null;
+ }
+ return self::$_types[$ext];
+ }
+
+ public static function charsets_lookup( $type = null ){
+ // assumes all text types are UTF-8
+ return $type && preg_match('/^text\//',$type) ? 'UTF-8' : '';
+ }
+}
+
+
+/**
+ * Tree
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree{
+
+ public $cache_string;
+
+ public function toCSS(){
+ $output = new Less_Output();
+ $this->genCSS($output);
+ return $output->toString();
+ }
+
+
+ /**
+ * Generate CSS by adding it to the output object
+ *
+ * @param Less_Output $output The output
+ * @return void
+ */
+ public function genCSS($output){}
+
+
+ /**
+ * @param Less_Tree_Ruleset[] $rules
+ */
+ public static function outputRuleset( $output, $rules ){
+
+ $ruleCnt = count($rules);
+ Less_Environment::$tabLevel++;
+
+
+ // Compressed
+ if( Less_Parser::$options['compress'] ){
+ $output->add('{');
+ for( $i = 0; $i < $ruleCnt; $i++ ){
+ $rules[$i]->genCSS( $output );
+ }
+
+ $output->add( '}' );
+ Less_Environment::$tabLevel--;
+ return;
+ }
+
+
+ // Non-compressed
+ $tabSetStr = "\n".str_repeat( Less_Parser::$options['indentation'] , Less_Environment::$tabLevel-1 );
+ $tabRuleStr = $tabSetStr.Less_Parser::$options['indentation'];
+
+ $output->add( " {" );
+ for($i = 0; $i < $ruleCnt; $i++ ){
+ $output->add( $tabRuleStr );
+ $rules[$i]->genCSS( $output );
+ }
+ Less_Environment::$tabLevel--;
+ $output->add( $tabSetStr.'}' );
+
+ }
+
+ public function accept($visitor){}
+
+
+ public static function ReferencedArray($rules){
+ foreach($rules as $rule){
+ if( method_exists($rule, 'markReferenced') ){
+ $rule->markReferenced();
+ }
+ }
+ }
+
+
+ /**
+ * Requires php 5.3+
+ */
+ public static function __set_state($args){
+
+ $class = get_called_class();
+ $obj = new $class(null,null,null,null);
+ foreach($args as $key => $val){
+ $obj->$key = $val;
+ }
+ return $obj;
+ }
+
+}
+
+
+/**
+ * Parser output
+ *
+ * @package Less
+ * @subpackage output
+ */
+class Less_Output{
+
+ /**
+ * Output holder
+ *
+ * @var string
+ */
+ protected $strs = array();
+
+ /**
+ * Adds a chunk to the stack
+ *
+ * @param string $chunk The chunk to output
+ * @param Less_FileInfo $fileInfo The file information
+ * @param integer $index The index
+ * @param mixed $mapLines
+ */
+ public function add($chunk, $fileInfo = null, $index = 0, $mapLines = null){
+ $this->strs[] = $chunk;
+ }
+
+ /**
+ * Is the output empty?
+ *
+ * @return boolean
+ */
+ public function isEmpty(){
+ return count($this->strs) === 0;
+ }
+
+
+ /**
+ * Converts the output to string
+ *
+ * @return string
+ */
+ public function toString(){
+ return implode('',$this->strs);
+ }
+
+}
+
+/**
+ * Visitor
+ *
+ * @package Less
+ * @subpackage visitor
+ */
+class Less_Visitor{
+
+ protected $methods = array();
+ protected $_visitFnCache = array();
+
+ public function __construct(){
+ $this->_visitFnCache = get_class_methods(get_class($this));
+ $this->_visitFnCache = array_flip($this->_visitFnCache);
+ }
+
+ public function visitObj( $node ){
+
+ $funcName = 'visit'.$node->type;
+ if( isset($this->_visitFnCache[$funcName]) ){
+
+ $visitDeeper = true;
+ $this->$funcName( $node, $visitDeeper );
+
+ if( $visitDeeper ){
+ $node->accept($this);
+ }
+
+ $funcName = $funcName . "Out";
+ if( isset($this->_visitFnCache[$funcName]) ){
+ $this->$funcName( $node );
+ }
+
+ }else{
+ $node->accept($this);
+ }
+
+ return $node;
+ }
+
+ public function visitArray( $nodes ){
+
+ array_map( array($this,'visitObj'), $nodes);
+ return $nodes;
+ }
+}
+
+
+
+/**
+ * Replacing Visitor
+ *
+ * @package Less
+ * @subpackage visitor
+ */
+class Less_VisitorReplacing extends Less_Visitor{
+
+ public function visitObj( $node ){
+
+ $funcName = 'visit'.$node->type;
+ if( isset($this->_visitFnCache[$funcName]) ){
+
+ $visitDeeper = true;
+ $node = $this->$funcName( $node, $visitDeeper );
+
+ if( $node ){
+ if( $visitDeeper && is_object($node) ){
+ $node->accept($this);
+ }
+
+ $funcName = $funcName . "Out";
+ if( isset($this->_visitFnCache[$funcName]) ){
+ $this->$funcName( $node );
+ }
+ }
+
+ }else{
+ $node->accept($this);
+ }
+
+ return $node;
+ }
+
+ public function visitArray( $nodes ){
+
+ $newNodes = array();
+ foreach($nodes as $node){
+ $evald = $this->visitObj($node);
+ if( $evald ){
+ if( is_array($evald) ){
+ self::flatten($evald,$newNodes);
+ }else{
+ $newNodes[] = $evald;
+ }
+ }
+ }
+ return $newNodes;
+ }
+
+ public function flatten( $arr, &$out ){
+
+ foreach($arr as $item){
+ if( !is_array($item) ){
+ $out[] = $item;
+ continue;
+ }
+
+ foreach($item as $nestedItem){
+ if( is_array($nestedItem) ){
+ self::flatten( $nestedItem, $out);
+ }else{
+ $out[] = $nestedItem;
+ }
+ }
+ }
+
+ return $out;
+ }
+
+}
+
+
+
+
+/**
+ * Configurable
+ *
+ * @package Less
+ * @subpackage Core
+ */
+abstract class Less_Configurable {
+
+ /**
+ * Array of options
+ *
+ * @var array
+ */
+ protected $options = array();
+
+ /**
+ * Array of default options
+ *
+ * @var array
+ */
+ protected $defaultOptions = array();
+
+
+ /**
+ * Set options
+ *
+ * If $options is an object it will be converted into an array by called
+ * it's toArray method.
+ *
+ * @throws Exception
+ * @param array|object $options
+ *
+ */
+ public function setOptions($options){
+ $options = array_intersect_key($options,$this->defaultOptions);
+ $this->options = array_merge($this->defaultOptions, $this->options, $options);
+ }
+
+
+ /**
+ * Get an option value by name
+ *
+ * If the option is empty or not set a NULL value will be returned.
+ *
+ * @param string $name
+ * @param mixed $default Default value if confiuration of $name is not present
+ * @return mixed
+ */
+ public function getOption($name, $default = null){
+ if(isset($this->options[$name])){
+ return $this->options[$name];
+ }
+ return $default;
+ }
+
+
+ /**
+ * Set an option
+ *
+ * @param string $name
+ * @param mixed $value
+ */
+ public function setOption($name, $value){
+ $this->options[$name] = $value;
+ }
+
+}
+
+/**
+ * Alpha
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Alpha extends Less_Tree{
+ public $value;
+ public $type = 'Alpha';
+
+ public function __construct($val){
+ $this->value = $val;
+ }
+
+ //function accept( $visitor ){
+ // $this->value = $visitor->visit( $this->value );
+ //}
+
+ public function compile($env){
+
+ if( is_object($this->value) ){
+ $this->value = $this->value->compile($env);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+
+ $output->add( "alpha(opacity=" );
+
+ if( is_string($this->value) ){
+ $output->add( $this->value );
+ }else{
+ $this->value->genCSS( $output);
+ }
+
+ $output->add( ')' );
+ }
+
+ public function toCSS(){
+ return "alpha(opacity=" . (is_string($this->value) ? $this->value : $this->value->toCSS()) . ")";
+ }
+
+
+}
+
+/**
+ * Anonymous
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Anonymous extends Less_Tree{
+ public $value;
+ public $quote;
+ public $index;
+ public $mapLines;
+ public $currentFileInfo;
+ public $type = 'Anonymous';
+
+ /**
+ * @param integer $index
+ * @param boolean $mapLines
+ */
+ public function __construct($value, $index = null, $currentFileInfo = null, $mapLines = null ){
+ $this->value = $value;
+ $this->index = $index;
+ $this->mapLines = $mapLines;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ public function compile(){
+ return new Less_Tree_Anonymous($this->value, $this->index, $this->currentFileInfo, $this->mapLines);
+ }
+
+ public function compare($x){
+ if( !is_object($x) ){
+ return -1;
+ }
+
+ $left = $this->toCSS();
+ $right = $x->toCSS();
+
+ if( $left === $right ){
+ return 0;
+ }
+
+ return $left < $right ? -1 : 1;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( $this->value, $this->currentFileInfo, $this->index, $this->mapLines );
+ }
+
+ public function toCSS(){
+ return $this->value;
+ }
+
+}
+
+
+/**
+ * Assignment
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Assignment extends Less_Tree{
+
+ public $key;
+ public $value;
+ public $type = 'Assignment';
+
+ public function __construct($key, $val) {
+ $this->key = $key;
+ $this->value = $val;
+ }
+
+ public function accept( $visitor ){
+ $this->value = $visitor->visitObj( $this->value );
+ }
+
+ public function compile($env) {
+ return new Less_Tree_Assignment( $this->key, $this->value->compile($env));
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( $this->key . '=' );
+ $this->value->genCSS( $output );
+ }
+
+ public function toCss(){
+ return $this->key . '=' . $this->value->toCSS();
+ }
+}
+
+
+/**
+ * Attribute
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Attribute extends Less_Tree{
+
+ public $key;
+ public $op;
+ public $value;
+ public $type = 'Attribute';
+
+ public function __construct($key, $op, $value){
+ $this->key = $key;
+ $this->op = $op;
+ $this->value = $value;
+ }
+
+ public function compile($env){
+
+ $key_obj = is_object($this->key);
+ $val_obj = is_object($this->value);
+
+ if( !$key_obj && !$val_obj ){
+ return $this;
+ }
+
+ return new Less_Tree_Attribute(
+ $key_obj ? $this->key->compile($env) : $this->key ,
+ $this->op,
+ $val_obj ? $this->value->compile($env) : $this->value);
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( $this->toCSS() );
+ }
+
+ public function toCSS(){
+ $value = $this->key;
+
+ if( $this->op ){
+ $value .= $this->op;
+ $value .= (is_object($this->value) ? $this->value->toCSS() : $this->value);
+ }
+
+ return '[' . $value . ']';
+ }
+}
+
+
+/**
+ * Call
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Call extends Less_Tree{
+ public $value;
+
+ protected $name;
+ protected $args;
+ protected $index;
+ protected $currentFileInfo;
+ public $type = 'Call';
+
+ public function __construct($name, $args, $index, $currentFileInfo = null ){
+ $this->name = $name;
+ $this->args = $args;
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ public function accept( $visitor ){
+ $this->args = $visitor->visitArray( $this->args );
+ }
+
+ //
+ // When evaluating a function call,
+ // we either find the function in `tree.functions` [1],
+ // in which case we call it, passing the evaluated arguments,
+ // or we simply print it out as it appeared originally [2].
+ //
+ // The *functions.js* file contains the built-in functions.
+ //
+ // The reason why we evaluate the arguments, is in the case where
+ // we try to pass a variable to a function, like: `saturate(@color)`.
+ // The function should receive the value, not the variable.
+ //
+ public function compile($env=null){
+ $args = array();
+ foreach($this->args as $a){
+ $args[] = $a->compile($env);
+ }
+
+ $nameLC = strtolower($this->name);
+ switch($nameLC){
+ case '%':
+ $nameLC = '_percent';
+ break;
+
+ case 'get-unit':
+ $nameLC = 'getunit';
+ break;
+
+ case 'data-uri':
+ $nameLC = 'datauri';
+ break;
+
+ case 'svg-gradient':
+ $nameLC = 'svggradient';
+ break;
+ }
+
+ $result = null;
+ if( $nameLC === 'default' ){
+ $result = Less_Tree_DefaultFunc::compile();
+
+ }else{
+
+ if( method_exists('Less_Functions',$nameLC) ){ // 1.
+ try {
+
+ $func = new Less_Functions($env, $this->currentFileInfo);
+ $result = call_user_func_array( array($func,$nameLC),$args);
+
+ } catch (Exception $e) {
+ throw new Less_Exception_Compiler('error evaluating function `' . $this->name . '` '.$e->getMessage().' index: '. $this->index);
+ }
+ } elseif( isset( $env->functions[$nameLC] ) && is_callable( $env->functions[$nameLC] ) ) {
+ try {
+ $result = call_user_func_array( $env->functions[$nameLC], $args );
+ } catch (Exception $e) {
+ throw new Less_Exception_Compiler('error evaluating function `' . $this->name . '` '.$e->getMessage().' index: '. $this->index);
+ }
+ }
+ }
+
+ if( $result !== null ){
+ return $result;
+ }
+
+
+ return new Less_Tree_Call( $this->name, $args, $this->index, $this->currentFileInfo );
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+
+ $output->add( $this->name . '(', $this->currentFileInfo, $this->index );
+ $args_len = count($this->args);
+ for($i = 0; $i < $args_len; $i++ ){
+ $this->args[$i]->genCSS( $output );
+ if( $i + 1 < $args_len ){
+ $output->add( ', ' );
+ }
+ }
+
+ $output->add( ')' );
+ }
+
+
+ //public function toCSS(){
+ // return $this->compile()->toCSS();
+ //}
+
+}
+
+
+/**
+ * Color
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Color extends Less_Tree{
+ public $rgb;
+ public $alpha;
+ public $isTransparentKeyword;
+ public $type = 'Color';
+
+ public function __construct($rgb, $a = 1, $isTransparentKeyword = null ){
+
+ if( $isTransparentKeyword ){
+ $this->rgb = $rgb;
+ $this->alpha = $a;
+ $this->isTransparentKeyword = true;
+ return;
+ }
+
+ $this->rgb = array();
+ if( is_array($rgb) ){
+ $this->rgb = $rgb;
+ }else if( strlen($rgb) == 6 ){
+ foreach(str_split($rgb, 2) as $c){
+ $this->rgb[] = hexdec($c);
+ }
+ }else{
+ foreach(str_split($rgb, 1) as $c){
+ $this->rgb[] = hexdec($c.$c);
+ }
+ }
+ $this->alpha = is_numeric($a) ? $a : 1;
+ }
+
+ public function compile(){
+ return $this;
+ }
+
+ public function luma(){
+ $r = $this->rgb[0] / 255;
+ $g = $this->rgb[1] / 255;
+ $b = $this->rgb[2] / 255;
+
+ $r = ($r <= 0.03928) ? $r / 12.92 : pow((($r + 0.055) / 1.055), 2.4);
+ $g = ($g <= 0.03928) ? $g / 12.92 : pow((($g + 0.055) / 1.055), 2.4);
+ $b = ($b <= 0.03928) ? $b / 12.92 : pow((($b + 0.055) / 1.055), 2.4);
+
+ return 0.2126 * $r + 0.7152 * $g + 0.0722 * $b;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( $this->toCSS() );
+ }
+
+ public function toCSS( $doNotCompress = false ){
+ $compress = Less_Parser::$options['compress'] && !$doNotCompress;
+ $alpha = Less_Functions::fround( $this->alpha );
+
+
+ //
+ // If we have some transparency, the only way to represent it
+ // is via `rgba`. Otherwise, we use the hex representation,
+ // which has better compatibility with older browsers.
+ // Values are capped between `0` and `255`, rounded and zero-padded.
+ //
+ if( $alpha < 1 ){
+ if( ( $alpha === 0 || $alpha === 0.0 ) && isset($this->isTransparentKeyword) && $this->isTransparentKeyword ){
+ return 'transparent';
+ }
+
+ $values = array();
+ foreach($this->rgb as $c){
+ $values[] = Less_Functions::clamp( round($c), 255);
+ }
+ $values[] = $alpha;
+
+ $glue = ($compress ? ',' : ', ');
+ return "rgba(" . implode($glue, $values) . ")";
+ }else{
+
+ $color = $this->toRGB();
+
+ if( $compress ){
+
+ // Convert color to short format
+ if( $color[1] === $color[2] && $color[3] === $color[4] && $color[5] === $color[6]) {
+ $color = '#'.$color[1] . $color[3] . $color[5];
+ }
+ }
+
+ return $color;
+ }
+ }
+
+ //
+ // Operations have to be done per-channel, if not,
+ // channels will spill onto each other. Once we have
+ // our result, in the form of an integer triplet,
+ // we create a new Color node to hold the result.
+ //
+
+ /**
+ * @param string $op
+ */
+ public function operate( $op, $other) {
+ $rgb = array();
+ $alpha = $this->alpha * (1 - $other->alpha) + $other->alpha;
+ for ($c = 0; $c < 3; $c++) {
+ $rgb[$c] = Less_Functions::operate( $op, $this->rgb[$c], $other->rgb[$c]);
+ }
+ return new Less_Tree_Color($rgb, $alpha);
+ }
+
+ public function toRGB(){
+ return $this->toHex($this->rgb);
+ }
+
+ public function toHSL(){
+ $r = $this->rgb[0] / 255;
+ $g = $this->rgb[1] / 255;
+ $b = $this->rgb[2] / 255;
+ $a = $this->alpha;
+
+ $max = max($r, $g, $b);
+ $min = min($r, $g, $b);
+ $l = ($max + $min) / 2;
+ $d = $max - $min;
+
+ $h = $s = 0;
+ if( $max !== $min ){
+ $s = $l > 0.5 ? $d / (2 - $max - $min) : $d / ($max + $min);
+
+ switch ($max) {
+ case $r: $h = ($g - $b) / $d + ($g < $b ? 6 : 0); break;
+ case $g: $h = ($b - $r) / $d + 2; break;
+ case $b: $h = ($r - $g) / $d + 4; break;
+ }
+ $h /= 6;
+ }
+ return array('h' => $h * 360, 's' => $s, 'l' => $l, 'a' => $a );
+ }
+
+ //Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
+ public function toHSV() {
+ $r = $this->rgb[0] / 255;
+ $g = $this->rgb[1] / 255;
+ $b = $this->rgb[2] / 255;
+ $a = $this->alpha;
+
+ $max = max($r, $g, $b);
+ $min = min($r, $g, $b);
+
+ $v = $max;
+
+ $d = $max - $min;
+ if ($max === 0) {
+ $s = 0;
+ } else {
+ $s = $d / $max;
+ }
+
+ $h = 0;
+ if( $max !== $min ){
+ switch($max){
+ case $r: $h = ($g - $b) / $d + ($g < $b ? 6 : 0); break;
+ case $g: $h = ($b - $r) / $d + 2; break;
+ case $b: $h = ($r - $g) / $d + 4; break;
+ }
+ $h /= 6;
+ }
+ return array('h'=> $h * 360, 's'=> $s, 'v'=> $v, 'a' => $a );
+ }
+
+ public function toARGB(){
+ $argb = array_merge( (array) Less_Parser::round($this->alpha * 255), $this->rgb);
+ return $this->toHex( $argb );
+ }
+
+ public function compare($x){
+
+ if( !property_exists( $x, 'rgb' ) ){
+ return -1;
+ }
+
+
+ return ($x->rgb[0] === $this->rgb[0] &&
+ $x->rgb[1] === $this->rgb[1] &&
+ $x->rgb[2] === $this->rgb[2] &&
+ $x->alpha === $this->alpha) ? 0 : -1;
+ }
+
+ public function toHex( $v ){
+
+ $ret = '#';
+ foreach($v as $c){
+ $c = Less_Functions::clamp( Less_Parser::round($c), 255);
+ if( $c < 16 ){
+ $ret .= '0';
+ }
+ $ret .= dechex($c);
+ }
+
+ return $ret;
+ }
+
+
+ /**
+ * @param string $keyword
+ */
+ public static function fromKeyword( $keyword ){
+ $keyword = strtolower($keyword);
+
+ if( Less_Colors::hasOwnProperty($keyword) ){
+ // detect named color
+ return new Less_Tree_Color(substr(Less_Colors::color($keyword), 1));
+ }
+
+ if( $keyword === 'transparent' ){
+ return new Less_Tree_Color( array(0, 0, 0), 0, true);
+ }
+ }
+
+}
+
+
+/**
+ * Comment
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Comment extends Less_Tree{
+
+ public $value;
+ public $silent;
+ public $isReferenced;
+ public $currentFileInfo;
+ public $type = 'Comment';
+
+ public function __construct($value, $silent, $index = null, $currentFileInfo = null ){
+ $this->value = $value;
+ $this->silent = !! $silent;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ //if( $this->debugInfo ){
+ //$output->add( tree.debugInfo($env, $this), $this->currentFileInfo, $this->index);
+ //}
+ $output->add( trim($this->value) );//TODO shouldn't need to trim, we shouldn't grab the \n
+ }
+
+ public function toCSS(){
+ return Less_Parser::$options['compress'] ? '' : $this->value;
+ }
+
+ public function isSilent(){
+ $isReference = ($this->currentFileInfo && isset($this->currentFileInfo['reference']) && (!isset($this->isReferenced) || !$this->isReferenced) );
+ $isCompressed = Less_Parser::$options['compress'] && !preg_match('/^\/\*!/', $this->value);
+ return $this->silent || $isReference || $isCompressed;
+ }
+
+ public function compile(){
+ return $this;
+ }
+
+ public function markReferenced(){
+ $this->isReferenced = true;
+ }
+
+}
+
+
+/**
+ * Condition
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Condition extends Less_Tree{
+
+ public $op;
+ public $lvalue;
+ public $rvalue;
+ public $index;
+ public $negate;
+ public $type = 'Condition';
+
+ public function __construct($op, $l, $r, $i = 0, $negate = false) {
+ $this->op = trim($op);
+ $this->lvalue = $l;
+ $this->rvalue = $r;
+ $this->index = $i;
+ $this->negate = $negate;
+ }
+
+ public function accept($visitor){
+ $this->lvalue = $visitor->visitObj( $this->lvalue );
+ $this->rvalue = $visitor->visitObj( $this->rvalue );
+ }
+
+ public function compile($env) {
+ $a = $this->lvalue->compile($env);
+ $b = $this->rvalue->compile($env);
+
+ switch( $this->op ){
+ case 'and':
+ $result = $a && $b;
+ break;
+
+ case 'or':
+ $result = $a || $b;
+ break;
+
+ default:
+ if( Less_Parser::is_method($a, 'compare') ){
+ $result = $a->compare($b);
+ }elseif( Less_Parser::is_method($b, 'compare') ){
+ $result = $b->compare($a);
+ }else{
+ throw new Less_Exception_Compiler('Unable to perform comparison', null, $this->index);
+ }
+
+ switch ($result) {
+ case -1:
+ $result = $this->op === '<' || $this->op === '=<' || $this->op === '<=';
+ break;
+
+ case 0:
+ $result = $this->op === '=' || $this->op === '>=' || $this->op === '=<' || $this->op === '<=';
+ break;
+
+ case 1:
+ $result = $this->op === '>' || $this->op === '>=';
+ break;
+ }
+ break;
+ }
+
+ return $this->negate ? !$result : $result;
+ }
+
+}
+
+
+/**
+ * DefaultFunc
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_DefaultFunc{
+
+ static $error_;
+ static $value_;
+
+ public static function compile(){
+ if( self::$error_ ){
+ throw new Exception(self::$error_);
+ }
+ if( self::$value_ !== null ){
+ return self::$value_ ? new Less_Tree_Keyword('true') : new Less_Tree_Keyword('false');
+ }
+ }
+
+ public static function value( $v ){
+ self::$value_ = $v;
+ }
+
+ public static function error( $e ){
+ self::$error_ = $e;
+ }
+
+ public static function reset(){
+ self::$value_ = self::$error_ = null;
+ }
+}
+
+/**
+ * DetachedRuleset
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_DetachedRuleset extends Less_Tree{
+
+ public $ruleset;
+ public $frames;
+ public $type = 'DetachedRuleset';
+
+ public function __construct( $ruleset, $frames = null ){
+ $this->ruleset = $ruleset;
+ $this->frames = $frames;
+ }
+
+ public function accept($visitor) {
+ $this->ruleset = $visitor->visitObj($this->ruleset);
+ }
+
+ public function compile($env){
+ if( $this->frames ){
+ $frames = $this->frames;
+ }else{
+ $frames = $env->frames;
+ }
+ return new Less_Tree_DetachedRuleset($this->ruleset, $frames);
+ }
+
+ public function callEval($env) {
+ if( $this->frames ){
+ return $this->ruleset->compile( $env->copyEvalEnv( array_merge($this->frames,$env->frames) ) );
+ }
+ return $this->ruleset->compile( $env );
+ }
+}
+
+
+
+/**
+ * Dimension
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Dimension extends Less_Tree{
+
+ public $value;
+ public $unit;
+ public $type = 'Dimension';
+
+ public function __construct($value, $unit = null){
+ $this->value = floatval($value);
+
+ if( $unit && ($unit instanceof Less_Tree_Unit) ){
+ $this->unit = $unit;
+ }elseif( $unit ){
+ $this->unit = new Less_Tree_Unit( array($unit) );
+ }else{
+ $this->unit = new Less_Tree_Unit( );
+ }
+ }
+
+ public function accept( $visitor ){
+ $this->unit = $visitor->visitObj( $this->unit );
+ }
+
+ public function compile(){
+ return $this;
+ }
+
+ public function toColor() {
+ return new Less_Tree_Color(array($this->value, $this->value, $this->value));
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+
+ if( Less_Parser::$options['strictUnits'] && !$this->unit->isSingular() ){
+ throw new Less_Exception_Compiler("Multiple units in dimension. Correct the units or use the unit function. Bad unit: ".$this->unit->toString());
+ }
+
+ $value = Less_Functions::fround( $this->value );
+ $strValue = (string)$value;
+
+ if( $value !== 0 && $value < 0.000001 && $value > -0.000001 ){
+ // would be output 1e-6 etc.
+ $strValue = number_format($strValue,10);
+ $strValue = preg_replace('/\.?0+$/','', $strValue);
+ }
+
+ if( Less_Parser::$options['compress'] ){
+ // Zero values doesn't need a unit
+ if( $value === 0 && $this->unit->isLength() ){
+ $output->add( $strValue );
+ return $strValue;
+ }
+
+ // Float values doesn't need a leading zero
+ if( $value > 0 && $value < 1 && $strValue[0] === '0' ){
+ $strValue = substr($strValue,1);
+ }
+ }
+
+ $output->add( $strValue );
+ $this->unit->genCSS( $output );
+ }
+
+ public function __toString(){
+ return $this->toCSS();
+ }
+
+ // In an operation between two Dimensions,
+ // we default to the first Dimension's unit,
+ // so `1px + 2em` will yield `3px`.
+
+ /**
+ * @param string $op
+ */
+ public function operate( $op, $other){
+
+ $value = Less_Functions::operate( $op, $this->value, $other->value);
+ $unit = clone $this->unit;
+
+ if( $op === '+' || $op === '-' ){
+
+ if( !$unit->numerator && !$unit->denominator ){
+ $unit->numerator = $other->unit->numerator;
+ $unit->denominator = $other->unit->denominator;
+ }elseif( !$other->unit->numerator && !$other->unit->denominator ){
+ // do nothing
+ }else{
+ $other = $other->convertTo( $this->unit->usedUnits());
+
+ if( Less_Parser::$options['strictUnits'] && $other->unit->toString() !== $unit->toCSS() ){
+ throw new Less_Exception_Compiler("Incompatible units. Change the units or use the unit function. Bad units: '" . $unit->toString() . "' and " . $other->unit->toString() . "'.");
+ }
+
+ $value = Less_Functions::operate( $op, $this->value, $other->value);
+ }
+ }elseif( $op === '*' ){
+ $unit->numerator = array_merge($unit->numerator, $other->unit->numerator);
+ $unit->denominator = array_merge($unit->denominator, $other->unit->denominator);
+ sort($unit->numerator);
+ sort($unit->denominator);
+ $unit->cancel();
+ }elseif( $op === '/' ){
+ $unit->numerator = array_merge($unit->numerator, $other->unit->denominator);
+ $unit->denominator = array_merge($unit->denominator, $other->unit->numerator);
+ sort($unit->numerator);
+ sort($unit->denominator);
+ $unit->cancel();
+ }
+ return new Less_Tree_Dimension( $value, $unit);
+ }
+
+ public function compare($other) {
+ if ($other instanceof Less_Tree_Dimension) {
+
+ if( $this->unit->isEmpty() || $other->unit->isEmpty() ){
+ $a = $this;
+ $b = $other;
+ } else {
+ $a = $this->unify();
+ $b = $other->unify();
+ if( $a->unit->compare($b->unit) !== 0 ){
+ return -1;
+ }
+ }
+ $aValue = $a->value;
+ $bValue = $b->value;
+
+ if ($bValue > $aValue) {
+ return -1;
+ } elseif ($bValue < $aValue) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } else {
+ return -1;
+ }
+ }
+
+ public function unify() {
+ return $this->convertTo(array('length'=> 'px', 'duration'=> 's', 'angle' => 'rad' ));
+ }
+
+ public function convertTo($conversions) {
+ $value = $this->value;
+ $unit = clone $this->unit;
+
+ if( is_string($conversions) ){
+ $derivedConversions = array();
+ foreach( Less_Tree_UnitConversions::$groups as $i ){
+ if( isset(Less_Tree_UnitConversions::${$i}[$conversions]) ){
+ $derivedConversions = array( $i => $conversions);
+ }
+ }
+ $conversions = $derivedConversions;
+ }
+
+
+ foreach($conversions as $groupName => $targetUnit){
+ $group = Less_Tree_UnitConversions::${$groupName};
+
+ //numerator
+ foreach($unit->numerator as $i => $atomicUnit){
+ $atomicUnit = $unit->numerator[$i];
+ if( !isset($group[$atomicUnit]) ){
+ continue;
+ }
+
+ $value = $value * ($group[$atomicUnit] / $group[$targetUnit]);
+
+ $unit->numerator[$i] = $targetUnit;
+ }
+
+ //denominator
+ foreach($unit->denominator as $i => $atomicUnit){
+ $atomicUnit = $unit->denominator[$i];
+ if( !isset($group[$atomicUnit]) ){
+ continue;
+ }
+
+ $value = $value / ($group[$atomicUnit] / $group[$targetUnit]);
+
+ $unit->denominator[$i] = $targetUnit;
+ }
+ }
+
+ $unit->cancel();
+
+ return new Less_Tree_Dimension( $value, $unit);
+ }
+}
+
+
+/**
+ * Directive
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Directive extends Less_Tree{
+
+ public $name;
+ public $value;
+ public $rules;
+ public $index;
+ public $isReferenced;
+ public $currentFileInfo;
+ public $debugInfo;
+ public $type = 'Directive';
+
+ public function __construct($name, $value = null, $rules, $index = null, $currentFileInfo = null, $debugInfo = null ){
+ $this->name = $name;
+ $this->value = $value;
+ if( $rules ){
+ $this->rules = $rules;
+ $this->rules->allowImports = true;
+ }
+
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ $this->debugInfo = $debugInfo;
+ }
+
+
+ public function accept( $visitor ){
+ if( $this->rules ){
+ $this->rules = $visitor->visitObj( $this->rules );
+ }
+ if( $this->value ){
+ $this->value = $visitor->visitObj( $this->value );
+ }
+ }
+
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $value = $this->value;
+ $rules = $this->rules;
+ $output->add( $this->name, $this->currentFileInfo, $this->index );
+ if( $this->value ){
+ $output->add(' ');
+ $this->value->genCSS($output);
+ }
+ if( $this->rules ){
+ Less_Tree::outputRuleset( $output, array($this->rules));
+ } else {
+ $output->add(';');
+ }
+ }
+
+ public function compile($env){
+
+ $value = $this->value;
+ $rules = $this->rules;
+ if( $value ){
+ $value = $value->compile($env);
+ }
+
+ if( $rules ){
+ $rules = $rules->compile($env);
+ $rules->root = true;
+ }
+
+ return new Less_Tree_Directive( $this->name, $value, $rules, $this->index, $this->currentFileInfo, $this->debugInfo );
+ }
+
+
+ public function variable($name){
+ if( $this->rules ){
+ return $this->rules->variable($name);
+ }
+ }
+
+ public function find($selector){
+ if( $this->rules ){
+ return $this->rules->find($selector, $this);
+ }
+ }
+
+ //rulesets: function () { if (this.rules) return tree.Ruleset.prototype.rulesets.apply(this.rules); },
+
+ public function markReferenced(){
+ $this->isReferenced = true;
+ if( $this->rules ){
+ Less_Tree::ReferencedArray($this->rules->rules);
+ }
+ }
+
+}
+
+
+/**
+ * Element
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Element extends Less_Tree{
+
+ public $combinator = '';
+ public $value = '';
+ public $index;
+ public $currentFileInfo;
+ public $type = 'Element';
+
+ public $value_is_object = false;
+
+ public function __construct($combinator, $value, $index = null, $currentFileInfo = null ){
+
+ $this->value = $value;
+ $this->value_is_object = is_object($value);
+
+ if( $combinator ){
+ $this->combinator = $combinator;
+ }
+
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ public function accept( $visitor ){
+ if( $this->value_is_object ){ //object or string
+ $this->value = $visitor->visitObj( $this->value );
+ }
+ }
+
+ public function compile($env){
+
+ if( Less_Environment::$mixin_stack ){
+ return new Less_Tree_Element($this->combinator, ($this->value_is_object ? $this->value->compile($env) : $this->value), $this->index, $this->currentFileInfo );
+ }
+
+ if( $this->value_is_object ){
+ $this->value = $this->value->compile($env);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( $this->toCSS(), $this->currentFileInfo, $this->index );
+ }
+
+ public function toCSS(){
+
+ if( $this->value_is_object ){
+ $value = $this->value->toCSS();
+ }else{
+ $value = $this->value;
+ }
+
+
+ if( $value === '' && $this->combinator && $this->combinator === '&' ){
+ return '';
+ }
+
+
+ return Less_Environment::$_outputMap[$this->combinator] . $value;
+ }
+
+}
+
+
+/**
+ * Expression
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Expression extends Less_Tree{
+
+ public $value = array();
+ public $parens = false;
+ public $parensInOp = false;
+ public $type = 'Expression';
+
+ public function __construct( $value, $parens = null ){
+ $this->value = $value;
+ $this->parens = $parens;
+ }
+
+ public function accept( $visitor ){
+ $this->value = $visitor->visitArray( $this->value );
+ }
+
+ public function compile($env) {
+
+ $doubleParen = false;
+
+ if( $this->parens && !$this->parensInOp ){
+ Less_Environment::$parensStack++;
+ }
+
+ $returnValue = null;
+ if( $this->value ){
+
+ $count = count($this->value);
+
+ if( $count > 1 ){
+
+ $ret = array();
+ foreach($this->value as $e){
+ $ret[] = $e->compile($env);
+ }
+ $returnValue = new Less_Tree_Expression($ret);
+
+ }else{
+
+ if( ($this->value[0] instanceof Less_Tree_Expression) && $this->value[0]->parens && !$this->value[0]->parensInOp ){
+ $doubleParen = true;
+ }
+
+ $returnValue = $this->value[0]->compile($env);
+ }
+
+ } else {
+ $returnValue = $this;
+ }
+
+ if( $this->parens ){
+ if( !$this->parensInOp ){
+ Less_Environment::$parensStack--;
+
+ }elseif( !Less_Environment::isMathOn() && !$doubleParen ){
+ $returnValue = new Less_Tree_Paren($returnValue);
+
+ }
+ }
+ return $returnValue;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $val_len = count($this->value);
+ for( $i = 0; $i < $val_len; $i++ ){
+ $this->value[$i]->genCSS( $output );
+ if( $i + 1 < $val_len ){
+ $output->add( ' ' );
+ }
+ }
+ }
+
+ public function throwAwayComments() {
+
+ if( is_array($this->value) ){
+ $new_value = array();
+ foreach($this->value as $v){
+ if( $v instanceof Less_Tree_Comment ){
+ continue;
+ }
+ $new_value[] = $v;
+ }
+ $this->value = $new_value;
+ }
+ }
+}
+
+
+/**
+ * Extend
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Extend extends Less_Tree{
+
+ public $selector;
+ public $option;
+ public $index;
+ public $selfSelectors = array();
+ public $allowBefore;
+ public $allowAfter;
+ public $firstExtendOnThisSelectorPath;
+ public $type = 'Extend';
+ public $ruleset;
+
+
+ public $object_id;
+ public $parent_ids = array();
+
+ /**
+ * @param integer $index
+ */
+ public function __construct($selector, $option, $index){
+ static $i = 0;
+ $this->selector = $selector;
+ $this->option = $option;
+ $this->index = $index;
+
+ switch($option){
+ case "all":
+ $this->allowBefore = true;
+ $this->allowAfter = true;
+ break;
+ default:
+ $this->allowBefore = false;
+ $this->allowAfter = false;
+ break;
+ }
+
+ $this->object_id = $i++;
+ $this->parent_ids = array($this->object_id);
+ }
+
+ public function accept( $visitor ){
+ $this->selector = $visitor->visitObj( $this->selector );
+ }
+
+ public function compile( $env ){
+ Less_Parser::$has_extends = true;
+ $this->selector = $this->selector->compile($env);
+ return $this;
+ //return new Less_Tree_Extend( $this->selector->compile($env), $this->option, $this->index);
+ }
+
+ public function findSelfSelectors( $selectors ){
+ $selfElements = array();
+
+
+ for( $i = 0, $selectors_len = count($selectors); $i < $selectors_len; $i++ ){
+ $selectorElements = $selectors[$i]->elements;
+ // duplicate the logic in genCSS function inside the selector node.
+ // future TODO - move both logics into the selector joiner visitor
+ if( $i && $selectorElements && $selectorElements[0]->combinator === "") {
+ $selectorElements[0]->combinator = ' ';
+ }
+ $selfElements = array_merge( $selfElements, $selectors[$i]->elements );
+ }
+
+ $this->selfSelectors = array(new Less_Tree_Selector($selfElements));
+ }
+
+}
+
+/**
+ * CSS @import node
+ *
+ * The general strategy here is that we don't want to wait
+ * for the parsing to be completed, before we start importing
+ * the file. That's because in the context of a browser,
+ * most of the time will be spent waiting for the server to respond.
+ *
+ * On creation, we push the import path to our import queue, though
+ * `import,push`, we also pass it a callback, which it'll call once
+ * the file has been fetched, and parsed.
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Import extends Less_Tree{
+
+ public $options;
+ public $index;
+ public $path;
+ public $features;
+ public $currentFileInfo;
+ public $css;
+ public $skip;
+ public $root;
+ public $type = 'Import';
+
+ public function __construct($path, $features, $options, $index, $currentFileInfo = null ){
+ $this->options = $options;
+ $this->index = $index;
+ $this->path = $path;
+ $this->features = $features;
+ $this->currentFileInfo = $currentFileInfo;
+
+ if( is_array($options) ){
+ $this->options += array('inline'=>false);
+
+ if( isset($this->options['less']) || $this->options['inline'] ){
+ $this->css = !isset($this->options['less']) || !$this->options['less'] || $this->options['inline'];
+ } else {
+ $pathValue = $this->getPath();
+ if( $pathValue && preg_match('/css([\?;].*)?$/',$pathValue) ){
+ $this->css = true;
+ }
+ }
+ }
+ }
+
+//
+// The actual import node doesn't return anything, when converted to CSS.
+// The reason is that it's used at the evaluation stage, so that the rules
+// it imports can be treated like any other rules.
+//
+// In `eval`, we make sure all Import nodes get evaluated, recursively, so
+// we end up with a flat structure, which can easily be imported in the parent
+// ruleset.
+//
+
+ public function accept($visitor){
+
+ if( $this->features ){
+ $this->features = $visitor->visitObj($this->features);
+ }
+ $this->path = $visitor->visitObj($this->path);
+
+ if( !$this->options['inline'] && $this->root ){
+ $this->root = $visitor->visit($this->root);
+ }
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ if( $this->css ){
+
+ $output->add( '@import ', $this->currentFileInfo, $this->index );
+
+ $this->path->genCSS( $output );
+ if( $this->features ){
+ $output->add( ' ' );
+ $this->features->genCSS( $output );
+ }
+ $output->add( ';' );
+ }
+ }
+
+ public function toCSS(){
+ $features = $this->features ? ' ' . $this->features->toCSS() : '';
+
+ if ($this->css) {
+ return "@import " . $this->path->toCSS() . $features . ";\n";
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function getPath(){
+ if ($this->path instanceof Less_Tree_Quoted) {
+ $path = $this->path->value;
+ $path = ( isset($this->css) || preg_match('/(\.[a-z]*$)|([\?;].*)$/',$path)) ? $path : $path . '.less';
+ } else if ($this->path instanceof Less_Tree_URL) {
+ $path = $this->path->value->value;
+ }else{
+ return null;
+ }
+
+ //remove query string and fragment
+ return preg_replace('/[\?#][^\?]*$/','',$path);
+ }
+
+ public function compileForImport( $env ){
+ return new Less_Tree_Import( $this->path->compile($env), $this->features, $this->options, $this->index, $this->currentFileInfo);
+ }
+
+ public function compilePath($env) {
+ $path = $this->path->compile($env);
+ $rootpath = '';
+ if( $this->currentFileInfo && $this->currentFileInfo['rootpath'] ){
+ $rootpath = $this->currentFileInfo['rootpath'];
+ }
+
+
+ if( !($path instanceof Less_Tree_URL) ){
+ if( $rootpath ){
+ $pathValue = $path->value;
+ // Add the base path if the import is relative
+ if( $pathValue && Less_Environment::isPathRelative($pathValue) ){
+ $path->value = $this->currentFileInfo['uri_root'].$pathValue;
+ }
+ }
+ $path->value = Less_Environment::normalizePath($path->value);
+ }
+
+
+
+ return $path;
+ }
+
+ public function compile( $env ){
+
+ $evald = $this->compileForImport($env);
+
+ //get path & uri
+ $path_and_uri = null;
+ if( is_callable(Less_Parser::$options['import_callback']) ){
+ $path_and_uri = call_user_func(Less_Parser::$options['import_callback'],$evald);
+ }
+
+ if( !$path_and_uri ){
+ $path_and_uri = $evald->PathAndUri();
+ }
+
+ if( $path_and_uri ){
+ list($full_path, $uri) = $path_and_uri;
+ }else{
+ $full_path = $uri = $evald->getPath();
+ }
+
+
+ //import once
+ if( $evald->skip( $full_path, $env) ){
+ return array();
+ }
+
+ if( $this->options['inline'] ){
+ //todo needs to reference css file not import
+ //$contents = new Less_Tree_Anonymous($this->root, 0, array('filename'=>$this->importedFilename), true );
+
+ Less_Parser::AddParsedFile($full_path);
+ $contents = new Less_Tree_Anonymous( file_get_contents($full_path), 0, array(), true );
+
+ if( $this->features ){
+ return new Less_Tree_Media( array($contents), $this->features->value );
+ }
+
+ return array( $contents );
+ }
+
+ // optional (need to be before "CSS" to support optional CSS imports. CSS should be checked only if empty($this->currentFileInfo))
+ if( isset($this->options['optional']) && $this->options['optional'] && !file_exists($full_path) && (!$evald->css || !empty($this->currentFileInfo))) {
+ return array();
+ }
+
+
+ // css ?
+ if( $evald->css ){
+ $features = ( $evald->features ? $evald->features->compile($env) : null );
+ return new Less_Tree_Import( $this->compilePath( $env), $features, $this->options, $this->index);
+ }
+
+
+ return $this->ParseImport( $full_path, $uri, $env );
+ }
+
+
+ /**
+ * Using the import directories, get the full absolute path and uri of the import
+ *
+ * @param Less_Tree_Import $evald
+ */
+ public function PathAndUri(){
+
+ $evald_path = $this->getPath();
+
+ if( $evald_path ){
+
+ $import_dirs = array();
+
+ if( Less_Environment::isPathRelative($evald_path) ){
+ //if the path is relative, the file should be in the current directory
+ $import_dirs[ $this->currentFileInfo['currentDirectory'] ] = $this->currentFileInfo['uri_root'];
+
+ }else{
+ //otherwise, the file should be relative to the server root
+ $import_dirs[ $this->currentFileInfo['entryPath'] ] = $this->currentFileInfo['entryUri'];
+
+ //if the user supplied entryPath isn't the actual root
+ $import_dirs[ $_SERVER['DOCUMENT_ROOT'] ] = '';
+
+ }
+
+ // always look in user supplied import directories
+ $import_dirs = array_merge( $import_dirs, Less_Parser::$options['import_dirs'] );
+
+
+ foreach( $import_dirs as $rootpath => $rooturi){
+ if( is_callable($rooturi) ){
+ list($path, $uri) = call_user_func($rooturi, $evald_path);
+ if( is_string($path) ){
+ $full_path = $path;
+ return array( $full_path, $uri );
+ }
+ }elseif( !empty($rootpath) ){
+
+
+ if( $rooturi ){
+ if( strpos($evald_path,$rooturi) === 0 ){
+ $evald_path = substr( $evald_path, strlen($rooturi) );
+ }
+ }
+
+ $path = rtrim($rootpath,'/\\').'/'.ltrim($evald_path,'/\\');
+
+ if( file_exists($path) ){
+ $full_path = Less_Environment::normalizePath($path);
+ $uri = Less_Environment::normalizePath(dirname($rooturi.$evald_path));
+ return array( $full_path, $uri );
+ } elseif( file_exists($path.'.less') ){
+ $full_path = Less_Environment::normalizePath($path.'.less');
+ $uri = Less_Environment::normalizePath(dirname($rooturi.$evald_path.'.less'));
+ return array( $full_path, $uri );
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Parse the import url and return the rules
+ *
+ * @return Less_Tree_Media|array
+ */
+ public function ParseImport( $full_path, $uri, $env ){
+
+ $import_env = clone $env;
+ if( (isset($this->options['reference']) && $this->options['reference']) || isset($this->currentFileInfo['reference']) ){
+ $import_env->currentFileInfo['reference'] = true;
+ }
+
+ if( (isset($this->options['multiple']) && $this->options['multiple']) ){
+ $import_env->importMultiple = true;
+ }
+
+ $parser = new Less_Parser($import_env);
+ $root = $parser->parseFile($full_path, $uri, true);
+
+
+ $ruleset = new Less_Tree_Ruleset(array(), $root->rules );
+ $ruleset->evalImports($import_env);
+
+ return $this->features ? new Less_Tree_Media($ruleset->rules, $this->features->value) : $ruleset->rules;
+ }
+
+
+ /**
+ * Should the import be skipped?
+ *
+ * @return boolean|null
+ */
+ private function Skip($path, $env){
+
+ $path = Less_Parser::winPath(realpath($path));
+
+ if( $path && Less_Parser::FileParsed($path) ){
+
+ if( isset($this->currentFileInfo['reference']) ){
+ return true;
+ }
+
+ return !isset($this->options['multiple']) && !$env->importMultiple;
+ }
+
+ }
+}
+
+
+/**
+ * Javascript
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Javascript extends Less_Tree{
+
+ public $type = 'Javascript';
+ public $escaped;
+ public $expression;
+ public $index;
+
+ /**
+ * @param boolean $index
+ * @param boolean $escaped
+ */
+ public function __construct($string, $index, $escaped){
+ $this->escaped = $escaped;
+ $this->expression = $string;
+ $this->index = $index;
+ }
+
+ public function compile(){
+ return new Less_Tree_Anonymous('/* Sorry, can not do JavaScript evaluation in PHP... :( */');
+ }
+
+}
+
+
+/**
+ * Keyword
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Keyword extends Less_Tree{
+
+ public $value;
+ public $type = 'Keyword';
+
+ /**
+ * @param string $value
+ */
+ public function __construct($value){
+ $this->value = $value;
+ }
+
+ public function compile(){
+ return $this;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+
+ if( $this->value === '%') {
+ throw new Less_Exception_Compiler("Invalid % without number");
+ }
+
+ $output->add( $this->value );
+ }
+
+ public function compare($other) {
+ if ($other instanceof Less_Tree_Keyword) {
+ return $other->value === $this->value ? 0 : 1;
+ } else {
+ return -1;
+ }
+ }
+}
+
+
+/**
+ * Media
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Media extends Less_Tree{
+
+ public $features;
+ public $rules;
+ public $index;
+ public $currentFileInfo;
+ public $isReferenced;
+ public $type = 'Media';
+
+ public function __construct($value = array(), $features = array(), $index = null, $currentFileInfo = null ){
+
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+
+ $selectors = $this->emptySelectors();
+
+ $this->features = new Less_Tree_Value($features);
+
+ $this->rules = array(new Less_Tree_Ruleset($selectors, $value));
+ $this->rules[0]->allowImports = true;
+ }
+
+ public function accept( $visitor ){
+ $this->features = $visitor->visitObj($this->features);
+ $this->rules = $visitor->visitArray($this->rules);
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+
+ $output->add( '@media ', $this->currentFileInfo, $this->index );
+ $this->features->genCSS( $output );
+ Less_Tree::outputRuleset( $output, $this->rules);
+
+ }
+
+ public function compile($env) {
+
+ $media = new Less_Tree_Media(array(), array(), $this->index, $this->currentFileInfo );
+
+ $strictMathBypass = false;
+ if( Less_Parser::$options['strictMath'] === false) {
+ $strictMathBypass = true;
+ Less_Parser::$options['strictMath'] = true;
+ }
+
+ $media->features = $this->features->compile($env);
+
+ if( $strictMathBypass ){
+ Less_Parser::$options['strictMath'] = false;
+ }
+
+ $env->mediaPath[] = $media;
+ $env->mediaBlocks[] = $media;
+
+ array_unshift($env->frames, $this->rules[0]);
+ $media->rules = array($this->rules[0]->compile($env));
+ array_shift($env->frames);
+
+ array_pop($env->mediaPath);
+
+ return !$env->mediaPath ? $media->compileTop($env) : $media->compileNested($env);
+ }
+
+ public function variable($name) {
+ return $this->rules[0]->variable($name);
+ }
+
+ public function find($selector) {
+ return $this->rules[0]->find($selector, $this);
+ }
+
+ public function emptySelectors(){
+ $el = new Less_Tree_Element('','&', $this->index, $this->currentFileInfo );
+ $sels = array( new Less_Tree_Selector(array($el), array(), null, $this->index, $this->currentFileInfo) );
+ $sels[0]->mediaEmpty = true;
+ return $sels;
+ }
+
+ public function markReferenced(){
+ $this->rules[0]->markReferenced();
+ $this->isReferenced = true;
+ Less_Tree::ReferencedArray($this->rules[0]->rules);
+ }
+
+ // evaltop
+ public function compileTop($env) {
+ $result = $this;
+
+ if (count($env->mediaBlocks) > 1) {
+ $selectors = $this->emptySelectors();
+ $result = new Less_Tree_Ruleset($selectors, $env->mediaBlocks);
+ $result->multiMedia = true;
+ }
+
+ $env->mediaBlocks = array();
+ $env->mediaPath = array();
+
+ return $result;
+ }
+
+ public function compileNested($env) {
+ $path = array_merge($env->mediaPath, array($this));
+
+ // Extract the media-query conditions separated with `,` (OR).
+ foreach ($path as $key => $p) {
+ $value = $p->features instanceof Less_Tree_Value ? $p->features->value : $p->features;
+ $path[$key] = is_array($value) ? $value : array($value);
+ }
+
+ // Trace all permutations to generate the resulting media-query.
+ //
+ // (a, b and c) with nested (d, e) ->
+ // a and d
+ // a and e
+ // b and c and d
+ // b and c and e
+
+ $permuted = $this->permute($path);
+ $expressions = array();
+ foreach($permuted as $path){
+
+ for( $i=0, $len=count($path); $i < $len; $i++){
+ $path[$i] = Less_Parser::is_method($path[$i], 'toCSS') ? $path[$i] : new Less_Tree_Anonymous($path[$i]);
+ }
+
+ for( $i = count($path) - 1; $i > 0; $i-- ){
+ array_splice($path, $i, 0, array(new Less_Tree_Anonymous('and')));
+ }
+
+ $expressions[] = new Less_Tree_Expression($path);
+ }
+ $this->features = new Less_Tree_Value($expressions);
+
+
+
+ // Fake a tree-node that doesn't output anything.
+ return new Less_Tree_Ruleset(array(), array());
+ }
+
+ public function permute($arr) {
+ if (!$arr)
+ return array();
+
+ if (count($arr) == 1)
+ return $arr[0];
+
+ $result = array();
+ $rest = $this->permute(array_slice($arr, 1));
+ foreach ($rest as $r) {
+ foreach ($arr[0] as $a) {
+ $result[] = array_merge(
+ is_array($a) ? $a : array($a),
+ is_array($r) ? $r : array($r)
+ );
+ }
+ }
+
+ return $result;
+ }
+
+ public function bubbleSelectors($selectors) {
+
+ if( !$selectors) return;
+
+ $this->rules = array(new Less_Tree_Ruleset( $selectors, array($this->rules[0])));
+ }
+
+}
+
+
+/**
+ * A simple css name-value pair
+ * ex: width:100px;
+ *
+ * In bootstrap, there are about 600-1,000 simple name-value pairs (depending on how forgiving the match is) -vs- 6,020 dynamic rules (Less_Tree_Rule)
+ * Using the name-value object can speed up bootstrap compilation slightly, but it breaks color keyword interpretation: color:red -> color:#FF0000;
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_NameValue extends Less_Tree{
+
+ public $name;
+ public $value;
+ public $index;
+ public $currentFileInfo;
+ public $type = 'NameValue';
+ public $important = '';
+
+ public function __construct($name, $value = null, $index = null, $currentFileInfo = null ){
+ $this->name = $name;
+ $this->value = $value;
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ public function genCSS( $output ){
+
+ $output->add(
+ $this->name
+ . Less_Environment::$_outputMap[': ']
+ . $this->value
+ . $this->important
+ . (((Less_Environment::$lastRule && Less_Parser::$options['compress'])) ? "" : ";")
+ , $this->currentFileInfo, $this->index);
+ }
+
+ public function compile ($env){
+ return $this;
+ }
+
+ public function makeImportant(){
+ $new = new Less_Tree_NameValue($this->name, $this->value, $this->index, $this->currentFileInfo);
+ $new->important = ' !important';
+ return $new;
+ }
+
+
+}
+
+
+/**
+ * Negative
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Negative extends Less_Tree{
+
+ public $value;
+ public $type = 'Negative';
+
+ public function __construct($node){
+ $this->value = $node;
+ }
+
+ //function accept($visitor) {
+ // $this->value = $visitor->visit($this->value);
+ //}
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( '-' );
+ $this->value->genCSS( $output );
+ }
+
+ public function compile($env) {
+ if( Less_Environment::isMathOn() ){
+ $ret = new Less_Tree_Operation('*', array( new Less_Tree_Dimension(-1), $this->value ) );
+ return $ret->compile($env);
+ }
+ return new Less_Tree_Negative( $this->value->compile($env) );
+ }
+}
+
+/**
+ * Operation
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Operation extends Less_Tree{
+
+ public $op;
+ public $operands;
+ public $isSpaced;
+ public $type = 'Operation';
+
+ /**
+ * @param string $op
+ */
+ public function __construct($op, $operands, $isSpaced = false){
+ $this->op = trim($op);
+ $this->operands = $operands;
+ $this->isSpaced = $isSpaced;
+ }
+
+ public function accept($visitor) {
+ $this->operands = $visitor->visitArray($this->operands);
+ }
+
+ public function compile($env){
+ $a = $this->operands[0]->compile($env);
+ $b = $this->operands[1]->compile($env);
+
+
+ if( Less_Environment::isMathOn() ){
+
+ if( $a instanceof Less_Tree_Di