From 51de8ca123f3789b5a6a98852fd9a8c4b938873b Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Mon, 18 Feb 2013 14:47:52 +0000 Subject: add comments for recent settings class additions to extra.class.php --- lib/plugins/config/settings/config.metadata.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php index 22e76a013..4731ffc16 100644 --- a/lib/plugins/config/settings/config.metadata.php +++ b/lib/plugins/config/settings/config.metadata.php @@ -42,6 +42,8 @@ * 'im_convert' - as 'setting', input must exist and be an im_convert module * 'disableactions' - as 'setting' * 'compression' - no additional parameters. checks php installation supports possible compression alternatives + * 'licence' - as multichoice, selection constructed from licence strings in language files + * 'renderer' - as multichoice, selection constructed from enabled renderer plugins which canRender() * * Any setting commented or missing will use 'setting' class - text input, minimal validation, quoted output * -- cgit v1.2.3 From c89ab3e93dc9b6fadb29518a47e4b32a49666729 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Mon, 18 Feb 2013 14:49:42 +0000 Subject: remove php_strip_whitespace() alternate, no longer required as php min req't ensures its always present --- lib/plugins/config/settings/config.class.php | 94 ---------------------------- 1 file changed, 94 deletions(-) diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php index e5e09d8f8..427178c40 100644 --- a/lib/plugins/config/settings/config.class.php +++ b/lib/plugins/config/settings/config.class.php @@ -1083,97 +1083,3 @@ if (!class_exists('setting_multicheckbox')) { } } } - -/** - * Provide php_strip_whitespace (php5 function) functionality - * - * @author Chris Smith - */ -if (!function_exists('php_strip_whitespace')) { - - if (function_exists('token_get_all')) { - - if (!defined('T_ML_COMMENT')) { - define('T_ML_COMMENT', T_COMMENT); - } else { - define('T_DOC_COMMENT', T_ML_COMMENT); - } - - /** - * modified from original - * source Google Groups, php.general, by David Otton - */ - function php_strip_whitespace($file) { - if (!@is_readable($file)) return ''; - - $in = join('',@file($file)); - $out = ''; - - $tokens = token_get_all($in); - - foreach ($tokens as $token) { - if (is_string ($token)) { - $out .= $token; - } else { - list ($id, $text) = $token; - switch ($id) { - case T_COMMENT : // fall thru - case T_ML_COMMENT : // fall thru - case T_DOC_COMMENT : // fall thru - case T_WHITESPACE : - break; - default : $out .= $text; break; - } - } - } - return ($out); - } - - } else { - - function is_whitespace($c) { return (strpos("\t\n\r ",$c) !== false); } - function is_quote($c) { return (strpos("\"'",$c) !== false); } - function is_escaped($s,$i) { - $idx = $i-1; - while(($idx>=0) && ($s{$idx} == '\\')) $idx--; - return (($i - $idx + 1) % 2); - } - - function is_commentopen($str, $i) { - if ($str{$i} == '#') return "\n"; - if ($str{$i} == '/') { - if ($str{$i+1} == '/') return "\n"; - if ($str{$i+1} == '*') return "*/"; - } - - return false; - } - - function php_strip_whitespace($file) { - - if (!@is_readable($file)) return ''; - - $contents = join('',@file($file)); - $out = ''; - - $state = 0; - for ($i=0; $i Date: Mon, 18 Feb 2013 15:14:51 +0000 Subject: remove no longer used email pattern, validation is done by mail_* functions --- lib/plugins/config/settings/config.class.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php index 427178c40..ec5f73fa5 100644 --- a/lib/plugins/config/settings/config.class.php +++ b/lib/plugins/config/settings/config.class.php @@ -659,10 +659,8 @@ if (!class_exists('setting_password')) { } if (!class_exists('setting_email')) { - if (!defined('SETTING_EMAIL_PATTERN')) define('SETTING_EMAIL_PATTERN','<^'.PREG_PATTERN_VALID_EMAIL.'$>'); class setting_email extends setting_string { - var $_pattern = SETTING_EMAIL_PATTERN; // no longer required, retained for backward compatibility - FIXME, may not be necessary var $_multiple = false; var $_placeholders = false; -- cgit v1.2.3 From d110fb0d68e5a037b6db151d7bfd4881c48ccdec Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Mon, 18 Feb 2013 15:51:06 +0000 Subject: FS#2722 add settings_regex class, use it for hidepages --- lib/plugins/config/settings/config.class.php | 37 +++++++++++++++++++++++++ lib/plugins/config/settings/config.metadata.php | 8 +++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php index ec5f73fa5..bbb25b695 100644 --- a/lib/plugins/config/settings/config.class.php +++ b/lib/plugins/config/settings/config.class.php @@ -1081,3 +1081,40 @@ if (!class_exists('setting_multicheckbox')) { } } } + +if (!class_exists('setting_regex')){ + class setting_regex extends setting_string { + + var $_delimiter = '/'; // regex delimiter to be used in testing input + var $_pregflags = 'ui'; // regex pattern modifiers to be used in testing input + + /** + * update changed setting with user provided value $input + * - if changed value fails error check, save it to $this->_input (to allow echoing later) + * - if changed value passes error check, set $this->_local to the new value + * + * @param mixed $input the new value + * @return boolean true if changed, false otherwise (incl. on error) + */ + function update($input) { + + // let parent do basic checks, value, not changed, etc. + $local = $this->_local; + if (!parent::update($input)) return false; + $this->_local = $local; + + // see if the regex compiles and runs (we don't check for effectiveness) + $regex = $this->_delimiter . $input . $this->_delimiter . $this->_pregflags; + $lastError = error_get_last(); + $ok = @preg_match($regex,'testdata'); + if (preg_last_error() != PREG_NO_ERROR || error_get_last() != $lastError) { + $this->_input = $input; + $this->_error = true; + return false; + } + + $this->_local = $input; + return true; + } + } +} \ No newline at end of file diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php index 4731ffc16..5aedaa6f1 100644 --- a/lib/plugins/config/settings/config.metadata.php +++ b/lib/plugins/config/settings/config.metadata.php @@ -33,6 +33,9 @@ * 'array' - a simple (one dimensional) array of string values, shown as comma separated list in the * config manager but saved as PHP array(). Values may not contain commas themselves. * _pattern matching on the array values supported. + * 'regex' - regular expression string, normally without delimiters; as for string, in addition tested + * to see if will compile & run as a regex. in addition to _pattern, also accepts _delimiter + * (default '/') and _pregflags (default 'ui') * * Single Setting (source: settings/extra.class.php) * ------------------------------------------------- @@ -60,6 +63,9 @@ * '_code' - encoding method to use, accepted values: 'base64','uuencode','plain'. defaults to plain. * '_min' - minimum numeric value, optional for 'numeric' and 'numericopt', ignored by others * '_max' - maximum numeric value, optional for 'numeric' and 'numericopt', ignored by others + * '_delimiter' - string, default '/', a single character used as a delimiter for testing regex input values + * '_pregflags' - string, default 'ui', valid preg pattern modifiers used when testing regex input values, for more + * information see http://uk1.php.net/manual/en/reference.pcre.pattern.modifiers.php * * @author Chris Smith */ @@ -115,7 +121,7 @@ $meta['camelcase'] = array('onoff'); $meta['deaccent'] = array('multichoice','_choices' => array(0,1,2)); $meta['useheading'] = array('multichoice','_choices' => array(0,'navigation','content',1)); $meta['sneaky_index'] = array('onoff'); -$meta['hidepages'] = array('string'); +$meta['hidepages'] = array('regex'); $meta['_authentication'] = array('fieldset'); $meta['useacl'] = array('onoff'); -- cgit v1.2.3 From d433710d8084d65218569a93034cec1e28bbeb43 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Mon, 18 Feb 2013 17:32:13 +0000 Subject: fix security caution for 'remote' setting (was 'xmlrpc') --- lib/plugins/config/settings/config.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php index bbb25b695..f7ab6606b 100644 --- a/lib/plugins/config/settings/config.class.php +++ b/lib/plugins/config/settings/config.class.php @@ -370,7 +370,7 @@ if (!class_exists('setting')) { var $_cautionList = array( 'basedir' => 'danger', 'baseurl' => 'danger', 'savedir' => 'danger', 'cookiedir' => 'danger', 'useacl' => 'danger', 'authtype' => 'danger', 'superuser' => 'danger', 'userewrite' => 'danger', 'start' => 'warning', 'camelcase' => 'warning', 'deaccent' => 'warning', 'sepchar' => 'warning', 'compression' => 'warning', 'xsendfile' => 'warning', 'renderer_xhtml' => 'warning', 'fnencode' => 'warning', - 'allowdebug' => 'security', 'htmlok' => 'security', 'phpok' => 'security', 'iexssprotect' => 'security', 'xmlrpc' => 'security', 'fullpath' => 'security' + 'allowdebug' => 'security', 'htmlok' => 'security', 'phpok' => 'security', 'iexssprotect' => 'security', 'remote' => 'security', 'fullpath' => 'security' ); function setting($key, $params=null) { -- cgit v1.2.3 From 9dc3b8ab758eb9236e8f1933309f2bc539cf3f5e Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Mon, 18 Feb 2013 17:51:45 +0000 Subject: replace preset _cautionList property with _caution config metadata parameter, plugins can now easily set cautions on their settings --- lib/plugins/config/settings/config.class.php | 27 +++++++++++---- lib/plugins/config/settings/config.metadata.php | 45 +++++++++++++------------ 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php index f7ab6606b..1c7d8f680 100644 --- a/lib/plugins/config/settings/config.class.php +++ b/lib/plugins/config/settings/config.class.php @@ -366,12 +366,11 @@ if (!class_exists('setting')) { var $_pattern = ''; var $_error = false; // only used by those classes which error check var $_input = null; // only used by those classes which error check + var $_caution = null; // used by any setting to provide an alert along with the setting + // valid alerts, 'warning', 'danger', 'security' + // images matching the alerts are in the plugin's images directory - var $_cautionList = array( - 'basedir' => 'danger', 'baseurl' => 'danger', 'savedir' => 'danger', 'cookiedir' => 'danger', 'useacl' => 'danger', 'authtype' => 'danger', 'superuser' => 'danger', 'userewrite' => 'danger', - 'start' => 'warning', 'camelcase' => 'warning', 'deaccent' => 'warning', 'sepchar' => 'warning', 'compression' => 'warning', 'xsendfile' => 'warning', 'renderer_xhtml' => 'warning', 'fnencode' => 'warning', - 'allowdebug' => 'security', 'htmlok' => 'security', 'phpok' => 'security', 'iexssprotect' => 'security', 'remote' => 'security', 'fullpath' => 'security' - ); + static protected $_validCautions = array('warning','danger','security'); function setting($key, $params=null) { $this->_key = $key; @@ -473,8 +472,22 @@ if (!class_exists('setting')) { function error() { return $this->_error; } function caution() { - if (!array_key_exists($this->_key, $this->_cautionList)) return false; - return $this->_cautionList[$this->_key]; + if (!empty($this->_caution)) { + if (!in_array($this->_caution, setting::$_validCautions)) { + trigger_error('Invalid caution string ('.$this->_caution.') in metadata for setting "'.$this->_key.'"', E_USER_WARNING); + return false; + } + return $this->_caution; + } + // compatibility with previous cautionList + // TODO: check if any plugins use; remove + if (!empty($this->_cautionList[$this->_key])) { + $this->_caution = $this->_cautionList[$this->_key]; + unset($this->_cautionList); + + return $this->caution(); + } + return false; } function _out_key($pretty=false,$url=false) { diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php index 5aedaa6f1..08003a3e4 100644 --- a/lib/plugins/config/settings/config.metadata.php +++ b/lib/plugins/config/settings/config.metadata.php @@ -51,6 +51,7 @@ * Any setting commented or missing will use 'setting' class - text input, minimal validation, quoted output * * Defined parameters: + * '_caution' - no value (default) or 'warning', 'danger', 'security'. display an alert along with the setting * '_pattern' - string, a preg pattern. input is tested against this pattern before being accepted * optional all classes, except onoff & multichoice which ignore it * '_choices' - array of choices. used to populate a selection box. choice will be replaced by a localised @@ -89,26 +90,26 @@ $config['heading'] = 'Dokuwiki\'s Main Configuration File - Local Settings'; $meta['_basic'] = array('fieldset'); $meta['title'] = array('string'); -$meta['start'] = array('string','_pattern' => '!^[^:;/]+$!'); // don't accept namespaces +$meta['start'] = array('string','_caution' => 'warning','_pattern' => '!^[^:;/]+$!'); // don't accept namespaces $meta['lang'] = array('dirchoice','_dir' => DOKU_INC.'inc/lang/'); $meta['template'] = array('dirchoice','_dir' => DOKU_INC.'lib/tpl/','_pattern' => '/^[\w-]+$/'); $meta['tagline'] = array('string'); $meta['sidebar'] = array('string'); $meta['license'] = array('license'); -$meta['savedir'] = array('savedir'); -$meta['basedir'] = array('string'); -$meta['baseurl'] = array('string'); -$meta['cookiedir'] = array('string'); +$meta['savedir'] = array('savedir','_caution' => 'danger'); +$meta['basedir'] = array('string','_caution' => 'danger'); +$meta['baseurl'] = array('string','_caution' => 'danger'); +$meta['cookiedir'] = array('string','_caution' => 'danger'); $meta['dmode'] = array('numeric','_pattern' => '/0[0-7]{3,4}/'); // only accept octal representation $meta['fmode'] = array('numeric','_pattern' => '/0[0-7]{3,4}/'); // only accept octal representation -$meta['allowdebug'] = array('onoff'); +$meta['allowdebug'] = array('onoff','_caution' => 'security'); $meta['_display'] = array('fieldset'); $meta['recent'] = array('numeric'); $meta['recent_days'] = array('numeric'); $meta['breadcrumbs'] = array('numeric','_min' => 0); $meta['youarehere'] = array('onoff'); -$meta['fullpath'] = array('onoff'); +$meta['fullpath'] = array('onoff','_caution' => 'security'); $meta['typography'] = array('multichoice','_choices' => array(0,1,2)); $meta['dformat'] = array('string'); $meta['signature'] = array('string'); @@ -117,19 +118,19 @@ $meta['toptoclevel'] = array('multichoice','_choices' => array(1,2,3,4,5)); // $meta['tocminheads'] = array('multichoice','_choices' => array(0,1,2,3,4,5,10,15,20)); $meta['maxtoclevel'] = array('multichoice','_choices' => array(0,1,2,3,4,5)); $meta['maxseclevel'] = array('multichoice','_choices' => array(0,1,2,3,4,5)); // 0 for no sec edit buttons -$meta['camelcase'] = array('onoff'); -$meta['deaccent'] = array('multichoice','_choices' => array(0,1,2)); +$meta['camelcase'] = array('onoff','_caution' => 'warning'); +$meta['deaccent'] = array('multichoice','_choices' => array(0,1,2),'_caution' => 'warning'); $meta['useheading'] = array('multichoice','_choices' => array(0,'navigation','content',1)); $meta['sneaky_index'] = array('onoff'); $meta['hidepages'] = array('regex'); $meta['_authentication'] = array('fieldset'); -$meta['useacl'] = array('onoff'); +$meta['useacl'] = array('onoff','_caution' => 'danger'); $meta['autopasswd'] = array('onoff'); -$meta['authtype'] = array('authtype'); +$meta['authtype'] = array('authtype','_caution' => 'danger'); $meta['passcrypt'] = array('multichoice','_choices' => array('smd5','md5','apr1','sha1','ssha','lsmd5','crypt','mysql','my411','kmd5','pmd5','hmd5','mediawiki','bcrypt','djangomd5','djangosha1','sha512')); $meta['defaultgroup']= array('string'); -$meta['superuser'] = array('string'); +$meta['superuser'] = array('string','_caution' => 'danger'); $meta['manager'] = array('string'); $meta['profileconfirm'] = array('onoff'); $meta['rememberme'] = array('onoff'); @@ -138,7 +139,7 @@ $meta['disableactions'] = array('disableactions', '_combine' => array('subscription' => array('subscribe','unsubscribe'), 'wikicode' => array('source','export_raw'))); $meta['auth_security_timeout'] = array('numeric'); $meta['securecookie'] = array('onoff'); -$meta['remote'] = array('onoff'); +$meta['remote'] = array('onoff','_caution' => 'security'); $meta['remoteuser'] = array('string'); $meta['_anti_spam'] = array('fieldset'); @@ -146,12 +147,12 @@ $meta['usewordblock']= array('onoff'); $meta['relnofollow'] = array('onoff'); $meta['indexdelay'] = array('numeric'); $meta['mailguard'] = array('multichoice','_choices' => array('visible','hex','none')); -$meta['iexssprotect']= array('onoff'); +$meta['iexssprotect']= array('onoff','_caution' => 'security'); $meta['_editing'] = array('fieldset'); $meta['usedraft'] = array('onoff'); -$meta['htmlok'] = array('onoff'); -$meta['phpok'] = array('onoff'); +$meta['htmlok'] = array('onoff','_caution' => 'security'); +$meta['phpok'] = array('onoff','_caution' => 'security'); $meta['locktime'] = array('numeric'); $meta['cachetime'] = array('numeric'); @@ -191,20 +192,20 @@ $meta['rss_show_summary'] = array('onoff'); $meta['_advanced'] = array('fieldset'); $meta['updatecheck'] = array('onoff'); -$meta['userewrite'] = array('multichoice','_choices' => array(0,1,2)); +$meta['userewrite'] = array('multichoice','_choices' => array(0,1,2),'_caution' => 'danger'); $meta['useslash'] = array('onoff'); -$meta['sepchar'] = array('sepchar'); +$meta['sepchar'] = array('sepchar','_caution' => 'warning'); $meta['canonical'] = array('onoff'); -$meta['fnencode'] = array('multichoice','_choices' => array('url','safe','utf-8')); +$meta['fnencode'] = array('multichoice','_choices' => array('url','safe','utf-8'),'_caution' => 'warning'); $meta['autoplural'] = array('onoff'); $meta['compress'] = array('onoff'); $meta['cssdatauri'] = array('numeric','_pattern' => '/^\d+$/'); $meta['gzip_output'] = array('onoff'); $meta['send404'] = array('onoff'); -$meta['compression'] = array('compression'); +$meta['compression'] = array('compression','_caution' => 'warning'); $meta['broken_iua'] = array('onoff'); -$meta['xsendfile'] = array('multichoice','_choices' => array(0,1,2,3)); -$meta['renderer_xhtml'] = array('renderer','_format' => 'xhtml','_choices' => array('xhtml')); +$meta['xsendfile'] = array('multichoice','_choices' => array(0,1,2,3),'_caution' => 'warning'); +$meta['renderer_xhtml'] = array('renderer','_format' => 'xhtml','_choices' => array('xhtml'),'_caution' => 'warning'); $meta['readdircache'] = array('numeric'); $meta['_network'] = array('fieldset'); -- cgit v1.2.3 From 64b85cca2e8112341456bb9413ed2dc33050b607 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Mon, 18 Feb 2013 18:51:01 +0000 Subject: change tpl_actiondropdown request method to 'get' --- inc/template.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/template.php b/inc/template.php index a5bcabf1e..e9c0f1699 100644 --- a/inc/template.php +++ b/inc/template.php @@ -1373,7 +1373,7 @@ function tpl_actiondropdown($empty = '', $button = '>') { global $REV; global $lang; - echo '
'; + echo ''; echo '
'; echo ''; if($REV) echo ''; -- cgit v1.2.3 From f2cf18dae6f9e86142c9c20294266562f69fe641 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Mon, 18 Feb 2013 18:55:33 +0000 Subject: remove security token from tpl_actiondropdown - its not necessary, we're not posting any system change --- inc/template.php | 1 - 1 file changed, 1 deletion(-) diff --git a/inc/template.php b/inc/template.php index e9c0f1699..1734b08a0 100644 --- a/inc/template.php +++ b/inc/template.php @@ -1377,7 +1377,6 @@ function tpl_actiondropdown($empty = '', $button = '>') { echo '
'; echo ''; if($REV) echo ''; - echo ''; echo ''; if($REV) echo ''; + if ($_SERVER['REMOTE_USER']) { + echo ''; + } echo ''; -- cgit v1.2.3 From b6235013d0c936d6852299af46d0f6a7eb907665 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Wed, 20 Feb 2013 19:43:29 +0100 Subject: Fix handling of failed authentication loading In the case of a failed authentication initialization, the authentication setup was simply continued with an unset $auth object. This restores the previous behavior (before merging #141) of simply returning after unsetting $auth. Furthermore this re-introduces the check if $auth is set before checking $auth and removes a useless check if $auth is true (could never be false). --- inc/auth.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/inc/auth.php b/inc/auth.php index d82b8b5dd..92a56e163 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -54,16 +54,17 @@ function auth_setup() { } } - if(!$auth){ + if(!isset($auth) || !$auth){ msg($lang['authtempfail'], -1); return false; } - if ($auth && $auth->success == false) { + if ($auth->success == false) { // degrade to unauthenticated user unset($auth); auth_logoff(); msg($lang['authtempfail'], -1); + return false; } // do the login either by cookie or provided credentials XXX -- cgit v1.2.3 From e8baa2279f46cfaaf18a54d75c1329d266a4ca47 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Wed, 20 Feb 2013 20:18:59 +0100 Subject: Revert the search depth behavior changes from #154 This reverts parts of the changes from #154: Before merging the pull request, a depth of 1 returned just the pages in the root namespace. With the changes in the pull request, a depth of 1 also returned pages in subnamespaces of the root namespace (as it was also tested in the test case). This reverts this part of the changes and a depth of 1 returns just the pages in the root namespace again. --- _test/tests/inc/search/search.test.php | 4 ++-- inc/search.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/_test/tests/inc/search/search.test.php b/_test/tests/inc/search/search.test.php index 9c854a661..33d4e9d8d 100644 --- a/_test/tests/inc/search/search.test.php +++ b/_test/tests/inc/search/search.test.php @@ -22,9 +22,9 @@ class search_test extends DokuWikiTest { search($data, dirname(__FILE__) . '/data', 'search_allpages', array('depth' => 1), 'ns1/ns3'); $this->assertEquals(0, count($data)); - //depth is 1 so I should get only pages from ns1 + //depth is 2 so I should get only pages from ns1 $data = array(); - search($data, dirname(__FILE__) . '/data', 'search_allpages', array('depth' => 1), 'ns1'); + search($data, dirname(__FILE__) . '/data', 'search_allpages', array('depth' => 2), 'ns1'); $this->assertEquals(2, count($data)); } diff --git a/inc/search.php b/inc/search.php index e4aa3b9eb..6927fff5f 100644 --- a/inc/search.php +++ b/inc/search.php @@ -243,8 +243,8 @@ function search_pagename(&$data,$base,$file,$type,$lvl,$opts){ function search_allpages(&$data,$base,$file,$type,$lvl,$opts){ if(isset($opts['depth']) && $opts['depth']){ $parts = explode('/',ltrim($file,'/')); - if(($type == 'd' && count($parts) > $opts['depth']) - || ($type != 'd' && count($parts) > $opts['depth'] + 1)){ + if(($type == 'd' && count($parts) >= $opts['depth']) + || ($type != 'd' && count($parts) > $opts['depth'])){ return false; // depth reached } } -- cgit v1.2.3 From 9507770d8c13e47b975bf35fe25264448da3f28a Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Wed, 20 Feb 2013 20:26:05 +0100 Subject: Fix remaining missing $INPUT uses FS#2577 This adds $INPUT in all places where it was still missing and available. $INPUT is now also used in places where using $_REQUEST/... was okay in order to make the code consistent. --- doku.php | 2 +- inc/auth.php | 2 +- lib/plugins/authad/auth.php | 5 +++-- lib/plugins/plugin/admin.php | 3 ++- lib/plugins/revert/admin.php | 13 +++++++------ lib/plugins/usermanager/admin.php | 25 +++++++++++++------------ 6 files changed, 27 insertions(+), 23 deletions(-) diff --git a/doku.php b/doku.php index 607303ca4..68976ebb3 100644 --- a/doku.php +++ b/doku.php @@ -29,7 +29,7 @@ if(isset($_SERVER['HTTP_X_DOKUWIKI_DO'])) { require_once(DOKU_INC.'inc/init.php'); //import variables -$_REQUEST['id'] = str_replace("\xC2\xAD", '', $INPUT->str('id')); //soft-hyphen +$INPUT->set('id', str_replace("\xC2\xAD", '', $INPUT->str('id'))); //soft-hyphen $QUERY = trim($INPUT->str('id')); $ID = getID(); diff --git a/inc/auth.php b/inc/auth.php index 92a56e163..68b6b438d 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -92,7 +92,7 @@ function auth_setup() { // apply cleaning if (true === $auth->success) { - $_REQUEST['u'] = $auth->cleanUser($_REQUEST['u']); + $INPUT->set('u', $auth->cleanUser($INPUT->str('u'))); } if($INPUT->str('authtok')) { diff --git a/lib/plugins/authad/auth.php b/lib/plugins/authad/auth.php index f651d87a1..6c49eafbb 100644 --- a/lib/plugins/authad/auth.php +++ b/lib/plugins/authad/auth.php @@ -71,6 +71,7 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin { * Constructor */ public function __construct() { + global $INPUT; parent::__construct(); // we load the config early to modify it a bit here @@ -99,8 +100,8 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin { // we need to simulate a login if(empty($_COOKIE[DOKU_COOKIE])) { - $_REQUEST['u'] = $_SERVER['REMOTE_USER']; - $_REQUEST['p'] = 'sso_only'; + $INPUT->set('u', $_SERVER['REMOTE_USER']); + $INPUT->set('p', 'sso_only'); } } diff --git a/lib/plugins/plugin/admin.php b/lib/plugins/plugin/admin.php index 8b1ee3c7d..de4de6aef 100644 --- a/lib/plugins/plugin/admin.php +++ b/lib/plugins/plugin/admin.php @@ -61,11 +61,12 @@ class admin_plugin_plugin extends DokuWiki_Admin_Plugin { * handle user request */ function handle() { + global $INPUT; // enable direct access to language strings $this->setupLocale(); - $fn = $_REQUEST['fn']; + $fn = $INPUT->param('fn'); if (is_array($fn)) { $this->cmd = key($fn); $this->plugin = is_array($fn[$this->cmd]) ? key($fn[$this->cmd]) : null; diff --git a/lib/plugins/revert/admin.php b/lib/plugins/revert/admin.php index fcdaa230d..847e38876 100644 --- a/lib/plugins/revert/admin.php +++ b/lib/plugins/revert/admin.php @@ -44,15 +44,16 @@ class admin_plugin_revert extends DokuWiki_Admin_Plugin { * output appropriate html */ function html() { + global $INPUT; echo $this->plugin_locale_xhtml('intro'); $this->_searchform(); - if(is_array($_REQUEST['revert']) && checkSecurityToken()){ - $this->_revert($_REQUEST['revert'],$_REQUEST['filter']); - }elseif(isset($_REQUEST['filter'])){ - $this->_list($_REQUEST['filter']); + if(is_array($INPUT->param('revert')) && checkSecurityToken()){ + $this->_revert($INPUT->arr('revert'),$INPUT->str('filter')); + }elseif($INPUT->has('filter')){ + $this->_list($INPUT->str('filter')); } } @@ -60,10 +61,10 @@ class admin_plugin_revert extends DokuWiki_Admin_Plugin { * Display the form for searching spam pages */ function _searchform(){ - global $lang; + global $lang, $INPUT; echo '
'; echo ''; - echo ''; + echo ''; echo ' '; echo ' '.$this->getLang('note1').''; echo '


'; diff --git a/lib/plugins/usermanager/admin.php b/lib/plugins/usermanager/admin.php index cf8963e64..01f4a4cdb 100644 --- a/lib/plugins/usermanager/admin.php +++ b/lib/plugins/usermanager/admin.php @@ -73,11 +73,12 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { * handle user request */ function handle() { + global $INPUT; if (is_null($this->_auth)) return false; // extract the command and any specific parameters // submit button name is of the form - fn[cmd][param(s)] - $fn = $_REQUEST['fn']; + $fn = $INPUT->param('fn'); if (is_array($fn)) { $cmd = key($fn); @@ -88,8 +89,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { } if ($cmd != "search") { - if (!empty($_REQUEST['start'])) - $this->_start = $_REQUEST['start']; + $this->_start = $INPUT->int('start', 0); $this->_filter = $this->_retrieveFilter(); } @@ -345,6 +345,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { } function _addUser(){ + global $INPUT; if (!checkSecurityToken()) return false; if (!$this->_auth->canDo('addUser')) return false; @@ -353,7 +354,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { if ($this->_auth->canDo('modPass')){ if (empty($pass)){ - if(!empty($_REQUEST['usernotify'])){ + if($INPUT->has('usernotify')){ $pass = auth_pwgen(); } else { msg($this->lang['add_fail'], -1); @@ -393,7 +394,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { msg($this->lang['add_ok'], 1); - if (!empty($_REQUEST['usernotify']) && $pass) { + if ($INPUT->has('usernotify') && $pass) { $this->_notifyUser($user,$pass); } } else { @@ -407,13 +408,13 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { * Delete user */ function _deleteUser(){ - global $conf; + global $conf, $INPUT; if (!checkSecurityToken()) return false; if (!$this->_auth->canDo('delUser')) return false; - $selected = $_REQUEST['delete']; - if (!is_array($selected) || empty($selected)) return false; + $selected = $INPUT->arr('delete'); + if (empty($selected)) return false; $selected = array_keys($selected); if(in_array($_SERVER['REMOTE_USER'], $selected)) { @@ -463,13 +464,13 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { * Modify user (modified user data has been recieved) */ function _modifyUser(){ - global $conf; + global $conf, $INPUT; if (!checkSecurityToken()) return false; if (!$this->_auth->canDo('UserMod')) return false; // get currently valid user data - $olduser = cleanID(preg_replace('/.*:/','',$_REQUEST['userid_old'])); + $olduser = cleanID(preg_replace('/.*:/','',$INPUT->str('userid_old'))); $oldinfo = $this->_auth->getUserData($olduser); // get new user data subject to change @@ -494,7 +495,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { } // generate password if left empty and notification is on - if(!empty($_REQUEST['usernotify']) && empty($newpass)){ + if($INPUT->has('usernotify') && empty($newpass)){ $newpass = auth_pwgen(); } @@ -510,7 +511,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { if ($ok = $this->_auth->triggerUserMod('modify', array($olduser, $changes))) { msg($this->lang['update_ok'],1); - if (!empty($_REQUEST['usernotify']) && $newpass) { + if ($INPUT->has('usernotify') && $newpass) { $notify = empty($changes['user']) ? $olduser : $newuser; $this->_notifyUser($notify,$newpass); } -- cgit v1.2.3 From 5ab3b7775958f5a1f8db8c791eed4c4a035c284a Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Thu, 21 Feb 2013 21:59:05 +0000 Subject: add unit test for pageinfo() --- _test/tests/inc/common_pageinfo.test.php | 299 +++++++++++++++++++++++++++++++ 1 file changed, 299 insertions(+) create mode 100644 _test/tests/inc/common_pageinfo.test.php diff --git a/_test/tests/inc/common_pageinfo.test.php b/_test/tests/inc/common_pageinfo.test.php new file mode 100644 index 000000000..c54fbce26 --- /dev/null +++ b/_test/tests/inc/common_pageinfo.test.php @@ -0,0 +1,299 @@ + + */ +class common_pageinfo_test extends DokuWikiTest { + + function setup(){ + parent::setup(); + + global $USERINFO; + $USERINFO = array( + 'pass' => '179ad45c6ce2cb97cf1029e212046e81', + 'name' => 'Arthur Dent', + 'mail' => 'arthur@example.com', + 'grps' => array ('admin','user'), + ); + $_SERVER['REMOTE_USER'] = 'testuser'; + $_SERVER['REMOTE_ADDR'] = '1.2.3.4'; + } + + function _get_expected_pageinfo() { + global $USERINFO; + $info = array ( + 'isadmin' => true, + 'ismanager' => true, + 'userinfo' => $USERINFO, + 'perm' => 255, + 'namespace' => false, + 'ismobile' => false, + 'client' => 'testuser', + ); + $info['rev'] = null; + $info['subscribed'] = false; + $info['locked'] = false; + $info['exists'] = false; + $info['writable'] = true; + $info['editable'] = true; + $info['lastmod'] = false; + $info['meta'] = array(); + $info['ip'] = null; + $info['user'] = null; + $info['sum'] = null; + $info['editor'] = null; + + return $info; + } + + /** + * check info keys and values for a non-existent page & admin user + */ + function test_basic_nonexistentpage(){ + global $ID,$conf; + $ID = 'wiki:start'; + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:start'; + $info['namespace'] = 'wiki'; + $info['filepath'] = $conf['datadir'].'/wiki/start.txt'; + + $this->assertEquals($info, pageinfo()); + } + + /** + * check info keys and values for a existing page & admin user + */ + function test_basic_existingpage(){ + global $ID,$conf; + $ID = 'wiki:syntax'; + $filename = $conf['datadir'].'/wiki/syntax.txt'; + $rev = filemtime($filename); + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:syntax'; + $info['namespace'] = 'wiki'; + $info['filepath'] = $filename; + $info['exists'] = true; + $info['lastmod'] = $rev; + $info['meta'] = p_get_metadata($ID); + + $this->assertEquals($info, pageinfo()); + } + + /** + * check info keys and values for anonymous user + */ + function test_anonymoususer(){ + global $ID,$conf,$REV; + + unset($_SERVER['REMOTE_USER']); + global $USERINFO; $USERINFO = array(); + + $ID = 'wiki:syntax'; + $filename = $conf['datadir'].'/wiki/syntax.txt'; + $rev = filemtime($filename); + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:syntax'; + $info['namespace'] = 'wiki'; + $info['filepath'] = $filename; + $info['exists'] = true; + $info['lastmod'] = $rev; + $info['meta'] = p_get_metadata($ID); + $info['rev'] = ''; + + $info = array_merge($info, array( + 'isadmin' => false, + 'ismanager' => false, + 'perm' => 8, + 'client' => '1.2.3.4', + )); + unset($info['userinfo']); + $this->assertEquals($info, pageinfo()); + } + + /** + * check info keys and values with $REV + * (also see $RANGE tests) + */ + function test_rev(){ + global $ID,$conf,$REV; + + $ID = 'wiki:syntax'; + $filename = $conf['datadir'].'/wiki/syntax.txt'; + $rev = filemtime($filename); + $REV = $rev - 100; + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:syntax'; + $info['namespace'] = 'wiki'; + $info['meta'] = p_get_metadata($ID); + $info['rev'] = $REV; + $info['filepath'] = str_replace('pages','attic',substr($filename,0,-3).$REV.'.txt.gz'); + + $this->assertEquals($info, pageinfo()); + $this->assertEquals($rev-100, $REV); + } + + /** + * check info keys and values with $RANGE + */ + function test_range(){ + global $ID,$conf,$REV,$RANGE; + + $ID = 'wiki:syntax'; + $filename = $conf['datadir'].'/wiki/syntax.txt'; + $rev = filemtime($filename); + $range = '1000-2000'; + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:syntax'; + $info['namespace'] = 'wiki'; + $info['exists'] = true; + $info['lastmod'] = $rev; + $info['meta'] = p_get_metadata($ID); + $info['filepath'] = $filename; + + // check $RANGE without $REV + // expected result $RANGE unchanged + $RANGE = $range; + + $this->assertEquals($info, pageinfo()); + $this->assertFalse(isset($REV)); + $this->assertEquals($range,$RANGE); + + // check $RANGE with $REV = current + // expected result: $RANGE unchanged, $REV cleared + $REV = $rev; + $info['rev'] = ''; + + $this->assertEquals($info, pageinfo()); + $this->assertEquals('',$REV); + $this->assertEquals($range,$RANGE); + + // check with a real $REV + // expected result: $REV and $RANGE are cleared + $REV = $rev - 100; + + $this->assertEquals($info, pageinfo()); + $this->assertEquals('',$REV); + $this->assertEquals('',$RANGE); + } + + /** + * test editor entry and external edit + */ + function test_editor_and_externaledits(){ + global $ID,$conf; + $ID = 'wiki:syntax'; + $filename = $conf['datadir'].'/wiki/syntax.txt'; + $rev = filemtime($filename); + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:syntax'; + $info['namespace'] = 'wiki'; + $info['filepath'] = $filename; + $info['exists'] = true; + $info['lastmod'] = $rev; + $info['meta'] = p_get_metadata($ID); // need $INFO set correctly for addLogEntry() + + global $INFO; + $INFO = $info; + + // add an editor for the current version of $ID + addLogEntry($rev, $ID); + + $info['meta'] = p_get_metadata($ID); + $info['editor'] = $_SERVER['REMOTE_USER']; + $info['user'] = $_SERVER['REMOTE_USER']; + $info['ip'] = $_SERVER['REMOTE_ADDR']; + $info['sum'] = ''; + + // with an editor ... + $this->assertEquals($info, pageinfo()); + + // clear the meta['last_change'] value, pageinfo should restore it + p_set_metadata($ID,array('last_change' => false)); + + $this->assertEquals($info, pageinfo()); + $this->assertEquals($info['meta']['last_change'], p_get_metadata($ID,'last_change')); + + // fake an external edit, pageinfo should clear the last change from meta data + // and not return any editor data + $now = time()+10; + touch($filename,$now); + + $info['lastmod'] = $now; + $info['meta']['last_change'] = false; + $info['ip'] = null; + $info['user'] = null; + $info['sum'] = null; + $info['editor'] = null; + + $this->assertEquals($info, pageinfo()); + $this->assertEquals($info['meta'], p_get_metadata($ID)); // check metadata has been updated correctly + } + + /** + * check draft + */ + function test_draft(){ + global $ID,$conf; + $ID = 'wiki:syntax'; + $filename = $conf['datadir'].'/wiki/syntax.txt'; + $rev = filemtime($filename); + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:syntax'; + $info['namespace'] = 'wiki'; + $info['filepath'] = $filename; + $info['exists'] = true; + $info['lastmod'] = $rev; + $info['meta'] = p_get_metadata($ID); + + // setup a draft, make it more recent than the current page + // - pageinfo should recognise it and keep it + $draft = getCacheName($info['client'].$ID,'.draft'); + touch($draft,$rev + 10); + + $info['draft'] = $draft; + + $this->assertEquals($info, pageinfo()); + $this->assertFileExists($draft); + + // make the draft older than the current page + // - pageinfo should remove it and not return the 'draft' key + touch($draft,$rev - 10); + unset($info['draft']); + + $this->assertEquals($info, pageinfo()); + $this->assertFalse(file_exists($draft)); + } + + /** + * check ismobile + */ + function test_ismobile(){ + global $ID,$conf; + $ID = 'wiki:start'; + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:start'; + $info['namespace'] = 'wiki'; + $info['filepath'] = $conf['datadir'].'/wiki/start.txt'; + + // overkill, ripped from clientismobile() as we aren't testing detection - but forcing it + $_SERVER['HTTP_X_WAP_PROFILE'] = 'a fake url'; + $_SERVER['HTTP_ACCEPT'] .= ';wap'; + $_SERVER['HTTP_USER_AGENT'] = 'blackberry,symbian,hand,mobi,phone'; + + $info['ismobile'] = clientismobile(); + + $this->assertTrue(clientismobile()); // ensure THIS test fails if clientismobile() returns false + $this->assertEquals($info, pageinfo()); // it would be a test failure not a pageinfo failure. + } +} + +//Setup VIM: ex: et ts=4 : -- cgit v1.2.3 From 11a53a83f01bf75d24afb7f184a4030d596958b4 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Fri, 22 Feb 2013 09:46:43 +0100 Subject: little change to syntax we had on the life site --- data/pages/wiki/syntax.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/pages/wiki/syntax.txt b/data/pages/wiki/syntax.txt index 55bbabab2..f2c2864ed 100644 --- a/data/pages/wiki/syntax.txt +++ b/data/pages/wiki/syntax.txt @@ -83,9 +83,9 @@ Windows shares like [[\\server\share|this]] are recognized, too. Please note tha Notes: * For security reasons direct browsing of windows shares only works in Microsoft Internet Explorer per default (and only in the "local zone"). - * For Mozilla and Firefox it can be enabled through different workaround mentioned in the [[http://kb.mozillazine.org/Links_to_local_pages_do_not_work|Mozilla Knowledge Base]]. However, there will still be a JavaScript warning about trying to open a Windows Share. To remove this warning (for all users), put the following line in ''conf/local.protected.php'': + * For Mozilla and Firefox it can be enabled through different workaround mentioned in the [[http://kb.mozillazine.org/Links_to_local_pages_do_not_work|Mozilla Knowledge Base]]. However, there will still be a JavaScript warning about trying to open a Windows Share. To remove this warning (for all users), put the following line in ''conf/userscript.js'': - $lang['js']['nosmblinks'] = ''; + LANG.nosmblinks = ''; ==== Image Links ==== -- cgit v1.2.3 From 64e8e116217f7559802d6cab15365d167714f191 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Sat, 23 Feb 2013 12:35:57 +0100 Subject: Fix double encoding in rss syntax FS#2731 --- inc/parser/xhtml.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/parser/xhtml.php b/inc/parser/xhtml.php index 4dd8c5e78..84a999e56 100644 --- a/inc/parser/xhtml.php +++ b/inc/parser/xhtml.php @@ -889,7 +889,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { // title is escaped by SimplePie, we unescape here because it // is escaped again in externallink() FS#1705 $this->externallink($item->get_permalink(), - htmlspecialchars_decode($item->get_title())); + html_entity_decode($item->get_title(), ENT_QUOTES, 'UTF-8')); }else{ $this->doc .= ' '.$item->get_title(); } -- cgit v1.2.3 From a4655683f1e9b4bf77a25334cd447b4b50e1c151 Mon Sep 17 00:00:00 2001 From: Lorenzo Radaelli Date: Sun, 24 Feb 2013 10:36:18 +0100 Subject: Italian language update --- inc/lang/it/lang.php | 8 ++++++++ lib/plugins/authad/lang/it/settings.php | 5 +++++ lib/plugins/authldap/lang/it/settings.php | 5 +++++ lib/plugins/authmysql/lang/it/settings.php | 5 +++++ lib/plugins/authpgsql/lang/it/settings.php | 5 +++++ lib/plugins/config/lang/it/lang.php | 1 + 6 files changed, 29 insertions(+) create mode 100644 lib/plugins/authad/lang/it/settings.php create mode 100644 lib/plugins/authldap/lang/it/settings.php create mode 100644 lib/plugins/authmysql/lang/it/settings.php create mode 100644 lib/plugins/authpgsql/lang/it/settings.php diff --git a/inc/lang/it/lang.php b/inc/lang/it/lang.php index 307e7292f..92bf5fea8 100644 --- a/inc/lang/it/lang.php +++ b/inc/lang/it/lang.php @@ -205,6 +205,7 @@ $lang['mail_new_user'] = 'nuovo utente:'; $lang['mail_upload'] = 'file caricato:'; $lang['changes_type'] = 'Guarda cambiamenti di'; $lang['pages_changes'] = 'Pagine'; +$lang['media_changes'] = 'File multimediali'; $lang['both_changes'] = 'Sia pagine che media files'; $lang['qb_bold'] = 'Grassetto'; $lang['qb_italic'] = 'Corsivo'; @@ -263,6 +264,8 @@ $lang['subscr_m_unsubscribe'] = 'Rimuovi sottoscrizione'; $lang['subscr_m_subscribe'] = 'Sottoscrivi'; $lang['subscr_m_receive'] = 'Ricevi'; $lang['subscr_style_every'] = 'email per ogni modifica'; +$lang['subscr_style_digest'] = 'email di riassunto dei cambiamenti per ogni pagina (ogni %.2f giorni)'; +$lang['subscr_style_list'] = 'lista delle pagine cambiate dall\'ultima email (ogni %.2f giorni)'; $lang['authmodfailed'] = 'La configurazione dell\'autenticazione non è corretta. Informa l\'amministratore di questo wiki.'; $lang['authtempfail'] = 'L\'autenticazione è temporaneamente non disponibile. Se questa situazione persiste, informa l\'amministratore di questo wiki.'; $lang['authpwdexpire'] = 'La tua password scadrà in %d giorni, dovresti cambiarla quanto prima.'; @@ -290,6 +293,9 @@ $lang['i_pol1'] = 'Wiki Pubblico (lettura per tutti, scrittura e $lang['i_pol2'] = 'Wiki Chiuso (lettura, scrittura, caricamento file solamente per gli utenti registrati)'; $lang['i_retry'] = 'Riprova'; $lang['i_license'] = 'Per favore scegli la licenza sotto cui vuoi rilasciare il contenuto:'; +$lang['i_license_none'] = 'Non mostrare informazioni sulla licenza'; +$lang['i_pop_field'] = 'Per favore, aiutaci ad incrementare la conoscenza di DokuWiki:'; +$lang['i_pop_label'] = 'Mensilmente invia una statistica d\'uso anonima di DokuWiki agli sviluppatori'; $lang['recent_global'] = 'Stai attualmente vedendo le modifiche effettuate nell\'area %s. Puoi anche vedere le modifiche recenti dell\'intero wiki.'; $lang['years'] = '%d anni fa'; $lang['months'] = '%d mesi fa'; @@ -314,8 +320,10 @@ $lang['media_files'] = 'File in %s'; $lang['media_upload'] = 'Upload al %s'; $lang['media_search'] = 'Cerca in %s'; $lang['media_view'] = '%s'; +$lang['media_viewold'] = '%s a %s'; $lang['media_edit'] = 'Modifica %s'; $lang['media_history'] = 'Storia di %s'; +$lang['media_meta_edited'] = 'metadata modificati'; $lang['media_perm_read'] = 'Spiacente, non hai abbastanza privilegi per leggere i files.'; $lang['media_perm_upload'] = 'Spiacente, non hai abbastanza privilegi per caricare files.'; $lang['media_update'] = 'Carica nuova versione'; diff --git a/lib/plugins/authad/lang/it/settings.php b/lib/plugins/authad/lang/it/settings.php new file mode 100644 index 000000000..10ae72f87 --- /dev/null +++ b/lib/plugins/authad/lang/it/settings.php @@ -0,0 +1,5 @@ + Date: Sun, 24 Feb 2013 10:37:45 +0100 Subject: Simplified Chinese language update --- inc/lang/zh/lang.php | 3 +++ lib/plugins/authad/lang/zh/settings.php | 18 ++++++++++++++ lib/plugins/authldap/lang/zh/settings.php | 20 +++++++++++++++ lib/plugins/authmysql/lang/zh/settings.php | 40 ++++++++++++++++++++++++++++++ lib/plugins/authpgsql/lang/zh/settings.php | 37 +++++++++++++++++++++++++++ 5 files changed, 118 insertions(+) create mode 100644 lib/plugins/authad/lang/zh/settings.php create mode 100644 lib/plugins/authldap/lang/zh/settings.php create mode 100644 lib/plugins/authmysql/lang/zh/settings.php create mode 100644 lib/plugins/authpgsql/lang/zh/settings.php diff --git a/inc/lang/zh/lang.php b/inc/lang/zh/lang.php index e6e568cb5..f404010ba 100644 --- a/inc/lang/zh/lang.php +++ b/inc/lang/zh/lang.php @@ -298,6 +298,9 @@ $lang['i_pol1'] = '公共的维基(任何人都有读的权限 $lang['i_pol2'] = '关闭的维基(只有注册用户才有读、写、上传的权限)'; $lang['i_retry'] = '重试'; $lang['i_license'] = '请选择您希望的内容发布许可协议:'; +$lang['i_license_none'] = '不要显示任何许可协议信息'; +$lang['i_pop_field'] = '请帮助我们改进 Dokuwiki 的体验:'; +$lang['i_pop_label'] = '每个月向 Dokuwiki 开发者发送匿名的使用数据'; $lang['recent_global'] = '您当前看到的是%s 名称空间的变动。你还可以在查看整个维基的近期变动。'; $lang['years'] = '%d年前'; $lang['months'] = '%d月前'; diff --git a/lib/plugins/authad/lang/zh/settings.php b/lib/plugins/authad/lang/zh/settings.php new file mode 100644 index 000000000..9fd3c4e35 --- /dev/null +++ b/lib/plugins/authad/lang/zh/settings.php @@ -0,0 +1,18 @@ + + */ +$lang['account_suffix'] = '您的账户后缀。例如 @my.domain.org'; +$lang['base_dn'] = '您的基本分辨名。例如 DC=my,DC=domain,DC=org'; +$lang['domain_controllers'] = '逗号分隔的域名控制器列表。例如 srv1.domain.org,srv2.domain.org'; +$lang['ad_username'] = '一个活动目录的特权用户,可以查看其他所有用户的数据。可选,但对某些活动例如发送订阅邮件是必须的。'; +$lang['ad_password'] = '上述用户的密码。'; +$lang['sso'] = '是否使用经由 Kerberos 和 NTLM 的 Single-Sign-On?'; +$lang['real_primarygroup'] = ' 是否解析真实的主要组,而不是假设为“域用户” (较慢)'; +$lang['use_ssl'] = '使用 SSL 连接?如果是,不要激活下面的 TLS。'; +$lang['use_tls'] = '使用 TLS 连接?如果是 ,不要激活上面的 SSL。'; +$lang['debug'] = '有错误时显示额外的调试信息?'; +$lang['expirywarn'] = '提前多少天警告用户密码即将到期。0 则禁用。'; +$lang['additional'] = '需要从用户数据中获取的额外 AD 属性的列表,以逗号分隔。用于某些插件。'; diff --git a/lib/plugins/authldap/lang/zh/settings.php b/lib/plugins/authldap/lang/zh/settings.php new file mode 100644 index 000000000..e84511b42 --- /dev/null +++ b/lib/plugins/authldap/lang/zh/settings.php @@ -0,0 +1,20 @@ + + */ +$lang['server'] = '您的 LDAP 服务器。填写主机名 (localhost) 或者完整的 URL (ldap://server.tld:389)'; +$lang['port'] = 'LDAP 服务器端口 (如果上面没有给出完整的 URL)'; +$lang['usertree'] = '何处查找用户账户。例如 ou=People, dc=server, dc=tld'; +$lang['grouptree'] = '何处查找用户组。例如 ou=Group, dc=server, dc=tld'; +$lang['userfilter'] = '用于搜索用户账户的 LDAP 筛选器。例如 (&(uid=%{user})(objectClass=posixAccount))'; +$lang['groupfilter'] = '用于搜索组的 LDAP 筛选器。例如 (&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))'; +$lang['version'] = '使用的协议版本。您或许需要设置为 3'; +$lang['starttls'] = '使用 TLS 连接?'; +$lang['referrals'] = '是否允许引用 (referrals)?'; +$lang['binddn'] = '一个可选的绑定用户的 DN (如果匿名绑定不满足要求)。例如 Eg. cn=admin, dc=my, dc=home'; +$lang['bindpw'] = '上述用户的密码'; +$lang['userscope'] = '限制用户搜索的范围'; +$lang['groupscope'] = '限制组搜索的范围'; +$lang['debug'] = '有错误时显示额外的调试信息'; diff --git a/lib/plugins/authmysql/lang/zh/settings.php b/lib/plugins/authmysql/lang/zh/settings.php new file mode 100644 index 000000000..43cfbb3c0 --- /dev/null +++ b/lib/plugins/authmysql/lang/zh/settings.php @@ -0,0 +1,40 @@ + + */ +$lang['server'] = '您的 MySQL 服务器'; +$lang['user'] = 'MySQL 用户名'; +$lang['password'] = '上述用户的密码'; +$lang['database'] = '使用的数据库'; +$lang['debug'] = '显示额外调试信息'; +$lang['forwardClearPass'] = '将用户密码以明文形式传送给下面的 SQL 语句,而不使用 passcrypt 密码加密选项'; +$lang['TablesToLock'] = '在写操作时需要锁定的数据表列表,以逗号分隔'; +$lang['checkPass'] = '检查密码的 SQL 语句'; +$lang['getUserInfo'] = '获取用户信息的 SQL 语句'; +$lang['getGroups'] = '或许用户的组成员身份的 SQL 语句'; +$lang['getUsers'] = '列出所有用户的 SQL 语句'; +$lang['FilterLogin'] = '根据登录名筛选用户的 SQL 子句'; +$lang['FilterName'] = '根据全名筛选用户的 SQL 子句'; +$lang['FilterEmail'] = '根据电子邮件地址筛选用户的 SQL 子句'; +$lang['FilterGroup'] = '根据组成员身份筛选用户的 SQL 子句'; +$lang['SortOrder'] = '对用户排序的 SQL 子句'; +$lang['addUser'] = '添加新用户的 SQL 语句'; +$lang['addGroup'] = '添加新组的 SQL 语句'; +$lang['addUserGroup'] = '将用户添加到现有组的 SQL 语句'; +$lang['delGroup'] = '删除组的 SQL 语句'; +$lang['getUserID'] = '获取用户主键的 SQL 语句'; +$lang['delUser'] = '删除用户的 SQL 语句'; +$lang['delUserRefs'] = '从所有组中删除一个用户的 SQL 语句'; +$lang['updateUser'] = '更新用户信息的 SQL 语句'; +$lang['UpdateLogin'] = '更新用户登录名的 Update 子句'; +$lang['UpdatePass'] = '更新用户密码的 Update 子句'; +$lang['UpdateEmail'] = '更新用户电子邮件地址的 Update 子句'; +$lang['UpdateName'] = '更新用户全名的 Update 子句'; +$lang['UpdateTarget'] = '更新时识别用户的 Limit 子句'; +$lang['delUserGroup'] = '从指定组删除用户的 SQL 语句'; +$lang['getGroupID'] = '获取指定组主键的 SQL 语句'; +$lang['debug_o_0'] = '无'; +$lang['debug_o_1'] = '仅在有错误时'; +$lang['debug_o_2'] = '所有 SQL 查询'; diff --git a/lib/plugins/authpgsql/lang/zh/settings.php b/lib/plugins/authpgsql/lang/zh/settings.php new file mode 100644 index 000000000..dc7223d89 --- /dev/null +++ b/lib/plugins/authpgsql/lang/zh/settings.php @@ -0,0 +1,37 @@ + + */ +$lang['server'] = '您的 PostgreSQL 服务器'; +$lang['port'] = '您的 PostgreSQL 服务器端口'; +$lang['user'] = 'PostgreSQL 用户名'; +$lang['password'] = '上述用户的密码'; +$lang['database'] = '使用的数据库'; +$lang['debug'] = '显示额外调试信息'; +$lang['forwardClearPass'] = '将用户密码以明文形式传送给下面的 SQL 语句,而不使用 passcrypt 密码加密选项'; +$lang['checkPass'] = '检查密码的 SQL 语句'; +$lang['getUserInfo'] = '获取用户信息的 SQL 语句'; +$lang['getGroups'] = '获取用户的组成员身份的 SQL 语句'; +$lang['getUsers'] = '列出所有用户的 SQL 语句'; +$lang['FilterLogin'] = '根据登录名筛选用户的 SQL 子句'; +$lang['FilterName'] = '根据全名筛选用户的 SQL 子句'; +$lang['FilterEmail'] = '根据电子邮件地址筛选用户的 SQL 子句'; +$lang['FilterGroup'] = '根据组成员身份筛选用户的 SQL 子句'; +$lang['SortOrder'] = '对用户排序的 SQL 子句'; +$lang['addUser'] = '添加新用户的 SQL 语句'; +$lang['addGroup'] = '添加新组的 SQL 语句'; +$lang['addUserGroup'] = '将用户添加到现有组的 SQL 语句'; +$lang['delGroup'] = '删除组的 SQL 语句'; +$lang['getUserID'] = '获取用户主键的 SQL 语句'; +$lang['delUser'] = '删除用户的 SQL 语句'; +$lang['delUserRefs'] = '从所有组中删除一个用户的 SQL 语句'; +$lang['updateUser'] = '更新用户信息的 SQL 语句'; +$lang['UpdateLogin'] = '更新用户登录名的 Update 子句'; +$lang['UpdatePass'] = '更新用户密码的 Update 子句'; +$lang['UpdateEmail'] = '更新用户电子邮件地址的 Update 子句'; +$lang['UpdateName'] = '更新用户全名的 Update 子句'; +$lang['UpdateTarget'] = '更新时识别用户的 Limit 子句'; +$lang['delUserGroup'] = '从指定组删除用户的 SQL 语句'; +$lang['getGroupID'] = '获取指定组主键的 SQL 语句'; -- cgit v1.2.3 From bdac741579f8c6f00248d5d3ec635d4c2e08fb1e Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Sun, 24 Feb 2013 10:39:52 +0100 Subject: fixed typos --- lib/plugins/authldap/lang/en/settings.php | 4 ++-- lib/plugins/authpgsql/lang/en/settings.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/plugins/authldap/lang/en/settings.php b/lib/plugins/authldap/lang/en/settings.php index 0bb397be5..ddedf8ae3 100644 --- a/lib/plugins/authldap/lang/en/settings.php +++ b/lib/plugins/authldap/lang/en/settings.php @@ -1,14 +1,14 @@ localhost) or full qualified URL (ldap://server.tld:389)'; $lang['port'] = 'LDAP server port if no full URL was given above'; -$lang['usertree'] = 'Where to finde the user accounts. Eg. ou=People, dc=server, dc=tld'; +$lang['usertree'] = 'Where to find the user accounts. Eg. ou=People, dc=server, dc=tld'; $lang['grouptree'] = 'Where to find the user groups. Eg. ou=Group, dc=server, dc=tld'; $lang['userfilter'] = 'LDAP filter to search for user accounts. Eg. (&(uid=%{user})(objectClass=posixAccount))'; $lang['groupfilter'] = 'LDAP filter to search for groups. Eg. (&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))'; $lang['version'] = 'The protocol version to use. You may need to set this to 3'; $lang['starttls'] = 'Use TLS connections?'; $lang['referrals'] = 'Shall referrals be followed?'; -$lang['binddn'] = 'DN of an ptional bind user if anonymous bind is not sufficient. Eg. cn=admin, dc=my, dc=home'; +$lang['binddn'] = 'DN of an optional bind user if anonymous bind is not sufficient. Eg. cn=admin, dc=my, dc=home'; $lang['bindpw'] = 'Password of above user'; $lang['userscope'] = 'Limit search scope for user search'; $lang['groupscope'] = 'Limit search scope for group search'; diff --git a/lib/plugins/authpgsql/lang/en/settings.php b/lib/plugins/authpgsql/lang/en/settings.php index 74a1c1cc9..8c048fa0f 100644 --- a/lib/plugins/authpgsql/lang/en/settings.php +++ b/lib/plugins/authpgsql/lang/en/settings.php @@ -20,7 +20,7 @@ $lang['addUser'] = 'SQL statement to add a new user'; $lang['addGroup'] = 'SQL statement to add a new group'; $lang['addUserGroup'] = 'SQL statment to add a user to an existing group'; $lang['delGroup'] = 'SQL statement to remove a group'; -$lang['getUserID'] = 'SQL statement to get the primary ey of a user'; +$lang['getUserID'] = 'SQL statement to get the primary key of a user'; $lang['delUser'] = 'SQL statement to delete a user'; $lang['delUserRefs'] = 'SQL statement to remove a user from all groups'; $lang['updateUser'] = 'SQL statement to update a user profile'; -- cgit v1.2.3 From ba9015b07d229ba195e7a9a3f23c3b038374c88c Mon Sep 17 00:00:00 2001 From: Klap-in Date: Tue, 21 May 2013 21:32:54 +0200 Subject: tests for fetch.php of external files --- .../lib/exe/fetch_statuscodes_external.test.php | 116 +++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 _test/tests/lib/exe/fetch_statuscodes_external.test.php diff --git a/_test/tests/lib/exe/fetch_statuscodes_external.test.php b/_test/tests/lib/exe/fetch_statuscodes_external.test.php new file mode 100644 index 000000000..1a2164828 --- /dev/null +++ b/_test/tests/lib/exe/fetch_statuscodes_external.test.php @@ -0,0 +1,116 @@ +markTestSkipped('headers not returned, perhaps your sapi does not return headers, try xdebug'); + } else { + header_remove('X-Test'); + } + + parent::setUp(); + + global $conf; + $conf['fetchsize'] = 500*1024; //500kb + $conf['xsendfile'] = 0; + + global $MIME, $EXT, $CACHE, $INPUT; // variables fetch creates in global scope -- should this be in fetch? + } + + function getUri($hash=null) { + $w = $this->width ? 'w='.$this->width.'&' : ''; + $h = $this->height ? 'h='.$this->height.'&' : ''; + if($hash === null) { + $hash = 'hash='.substr(md5(auth_cookiesalt().$this->media), 0, 6).'&'; + } + + return '/lib/exe/fetch.php?'.$hash.$w.$h.'{%token%}media='.rawurlencode($this->media); + } + + function fetchResponse($token, $hash=null){ + $request = new TestRequest(); + return $request->get(array(),str_replace('{%token%}',$token,$this->getUri($hash))); + } + + /** + * modified image request with invalid hash + * expect: 412 status code + */ + function test_invalid_hash() { + $invalid_hash = 'hash='.substr(md5(auth_cookiesalt().'junk'), 0, 6).'&'; + $token = 'tok='.media_get_token($this->media, $this->width, $this->height).'&'; + + $this->assertEquals(412,$this->fetchResponse($token, $invalid_hash)->getStatusCode()); + + } + + /** + * modified image request with valid token + * expect: header with mime-type + * expect: content + * expect: no error response + */ + function test_valid_token(){ + $valid_token = 'tok='.media_get_token($this->media, $this->width, $this->height).'&'; + + $response = $this->fetchResponse($valid_token); + $this->assertTrue((bool)$response->getHeader('Content-Type')); + $this->assertTrue((bool)($response->getContent())); + + $status_code = $response->getStatusCode(); + $this->assertTrue(is_null($status_code) || (200 == $status_code)); + } + + /** + * modified image request with invalid token + * expect: 412 status code + */ + function test_invalid_token(){ + $invalid_token = 'tok='.media_get_token('junk',200,100).'&'; + $this->assertEquals(412,$this->fetchResponse($invalid_token)->getStatusCode()); + } + + /** + * modified image request with no token + * expect: 412 status code + */ + function test_missing_token(){ + $no_token = ''; + $this->assertEquals(412,$this->fetchResponse($no_token)->getStatusCode()); + } + + /** + * native image request which doesn't require a token + * try: with a token & without a token + * expect: (for both) header with mime-type, content matching source image filesize & no error response + */ + function test_no_token_required(){ + $this->width = $this->height = 0; // no width & height, means image request at native dimensions + $any_token = 'tok='.media_get_token('junk',200,100).'&'; + $no_token = ''; + $file = media_get_from_URL($this->media,'png', -1); + $bytes = filesize($file); + + foreach(array($any_token, $no_token) as $token) { + $response = $this->fetchResponse($token); + $this->assertTrue((bool)$response->getHeader('Content-Type')); + $this->assertEquals(strlen($response->getContent()), $bytes); + + $status_code = $response->getStatusCode(); + $this->assertTrue(is_null($status_code) || (200 == $status_code)); + } + } + +} +//Setup VIM: ex: et ts=4 : -- cgit v1.2.3 From d572baf83c5a6d61a7f97aa4d115eba76c5f106c Mon Sep 17 00:00:00 2001 From: Klap-in Date: Tue, 21 May 2013 21:40:37 +0200 Subject: Add check for token when resizing and caching external images --- inc/fetch.functions.php | 4 ++++ lib/exe/fetch.php | 1 + 2 files changed, 5 insertions(+) diff --git a/inc/fetch.functions.php b/inc/fetch.functions.php index 5801e96fa..59a76a798 100644 --- a/inc/fetch.functions.php +++ b/inc/fetch.functions.php @@ -108,6 +108,10 @@ function checkFileStatus(&$media, &$file, $rev = '', $width=0, $height=0) { //download failed - redirect to original URL return array(302, $media); } + // check token for resized and cached images + if (($width || $height) && media_get_token($media, $width, $height) !== $INPUT->str('tok')) { + return array(412, 'Precondition Failed'); + } } else { $media = cleanID($media); if(empty($media)) { diff --git a/lib/exe/fetch.php b/lib/exe/fetch.php index 7a2250373..5967494bf 100644 --- a/lib/exe/fetch.php +++ b/lib/exe/fetch.php @@ -60,6 +60,7 @@ if (defined('SIMPLE_TEST')) { if($evt->advise_before()) { // redirects if($data['status'] > 300 && $data['status'] <= 304) { + if (defined('SIMPLE_TEST')) return; //TestResponse doesn't recognize redirects send_redirect($data['statusmessage']); } // send any non 200 status -- cgit v1.2.3 From a38a6f25d7e46f47a8f358bb16c766f5b96dae45 Mon Sep 17 00:00:00 2001 From: Klap-in Date: Tue, 21 May 2013 21:41:40 +0200 Subject: fix some minor typos in fetch_imagetoken.test.php --- _test/tests/lib/exe/fetch_imagetoken.test.php | 44 +++++++++++++-------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/_test/tests/lib/exe/fetch_imagetoken.test.php b/_test/tests/lib/exe/fetch_imagetoken.test.php index 9e5b6e4a2..99e642557 100644 --- a/_test/tests/lib/exe/fetch_imagetoken.test.php +++ b/_test/tests/lib/exe/fetch_imagetoken.test.php @@ -23,10 +23,10 @@ class fetch_imagetoken_test extends DokuWikiTest { parent::setUp(); global $conf; - $conf['sendfile'] = 0; + $conf['xsendfile'] = 0; global $MIME, $EXT, $CACHE, $INPUT; // variables fetch creates in global scope -- should this be in fetch? - } + } function getUri() { $w = $this->width ? 'w='.$this->width.'&' : ''; @@ -39,14 +39,14 @@ class fetch_imagetoken_test extends DokuWikiTest { $request = new TestRequest(); return $request->get(array(),str_replace('{%token%}',$token,$this->getUri())); } - - /** + + /** * modified image request with valid token * expect: header with mime-type * expect: content * expect: no error response - */ - function test_valid_token(){ + */ + function test_valid_token(){ $valid_token = 'tok='.media_get_token($this->media, $this->width, $this->height).'&'; $response = $this->fetchResponse($valid_token); $this->assertTrue((bool)$response->getHeader('Content-Type')); @@ -54,24 +54,24 @@ class fetch_imagetoken_test extends DokuWikiTest { $status_code = $response->getStatusCode(); $this->assertTrue(is_null($status_code) || (200 == $status_code)); - } - - /** + } + + /** * modified image request with invalid token - * expect: 412 status code - */ - function test_invalid_token(){ - $invalid_token = 'tok='.media_get_token('junk',200,100).'&'; - $this->assertEquals(412,$this->fetchResponse($invalid_token)->getStatusCode()); - } - - /** - * modified image request with no token * expect: 412 status code - */ - function test_missing_token(){ - $no_token = ''; - $this->assertEquals(412,$this->fetchResponse($notoken)->getStatusCode()); + */ + function test_invalid_token(){ + $invalid_token = 'tok='.media_get_token('junk',200,100).'&'; + $this->assertEquals(412,$this->fetchResponse($invalid_token)->getStatusCode()); + } + + /** + * modified image request with no token + * expect: 412 status code + */ + function test_missing_token(){ + $no_token = ''; + $this->assertEquals(412,$this->fetchResponse($no_token)->getStatusCode()); } /** -- cgit v1.2.3 From fa3ed26bfbafa4d05ec77a799259d4a46baadd9a Mon Sep 17 00:00:00 2001 From: Klap-in Date: Sun, 9 Jun 2013 22:16:08 +0200 Subject: update hashes in tests --- _test/tests/lib/exe/fetch_statuscodes_external.test.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/_test/tests/lib/exe/fetch_statuscodes_external.test.php b/_test/tests/lib/exe/fetch_statuscodes_external.test.php index 1a2164828..bd7b2f93b 100644 --- a/_test/tests/lib/exe/fetch_statuscodes_external.test.php +++ b/_test/tests/lib/exe/fetch_statuscodes_external.test.php @@ -32,9 +32,8 @@ class fetch_statuscodes_external_test extends DokuWikiTest { $w = $this->width ? 'w='.$this->width.'&' : ''; $h = $this->height ? 'h='.$this->height.'&' : ''; if($hash === null) { - $hash = 'hash='.substr(md5(auth_cookiesalt().$this->media), 0, 6).'&'; + $hash = 'hash='.substr(PassHash::hmac('md5', $this->media, auth_cookiesalt()), 0, 6).'&'; } - return '/lib/exe/fetch.php?'.$hash.$w.$h.'{%token%}media='.rawurlencode($this->media); } @@ -48,7 +47,7 @@ class fetch_statuscodes_external_test extends DokuWikiTest { * expect: 412 status code */ function test_invalid_hash() { - $invalid_hash = 'hash='.substr(md5(auth_cookiesalt().'junk'), 0, 6).'&'; + $invalid_hash = 'hash='.substr(PassHash::hmac('md5', 'junk', auth_cookiesalt()), 0, 6).'&'; $token = 'tok='.media_get_token($this->media, $this->width, $this->height).'&'; $this->assertEquals(412,$this->fetchResponse($token, $invalid_hash)->getStatusCode()); -- cgit v1.2.3 From 935ecb0ef751ac1d658932316e06410e70c483e0 Mon Sep 17 00:00:00 2001 From: haobug Date: Fri, 28 Jun 2013 05:18:19 +0800 Subject: Improve Linkwizard, make it can be used more than once. As reported in https://forum.dokuwiki.org/thread/9988 the previous implementation can not handle the situation of use the linkwiz more than once. Now you can use in you toolbar plugin 'type' => 'linkwiz' to make use of the handy Linkwizard for choosing the wiki pages. --- lib/scripts/linkwiz.js | 24 ++++++++++++++++++------ lib/scripts/toolbar.js | 5 +++-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/lib/scripts/linkwiz.js b/lib/scripts/linkwiz.js index c55650d68..875d4a995 100644 --- a/lib/scripts/linkwiz.js +++ b/lib/scripts/linkwiz.js @@ -22,6 +22,8 @@ var dw_linkwiz = { var pos = $editor.position(); // create HTML Structure + if(dw_linkwiz.$wiz) + return; dw_linkwiz.$wiz = jQuery(document.createElement('div')) .dialog({ autoOpen: false, @@ -235,15 +237,25 @@ var dw_linkwiz = { link = ':' + link; } - var so = link.length+3; - link = '[['+link+'|'; - if(stxt) { - link += stxt; + var so = link.length; + var eo = 0; + if(dw_linkwiz.val){ + if(dw_linkwiz.val.open) { + so += dw_linkwiz.val.open.length; + link = dw_linkwiz.val.open+link; + } + if(stxt) { + link += '|'+stxt; + so += 1; + } + if(dw_linkwiz.val.close) { + link += dw_linkwiz.val.close; + eo = dw_linkwiz.val.close.length; + } } - link += ']]'; - pasteText(sel,link,{startofs: so, endofs: 2}); + pasteText(sel,link,{startofs: so, endofs: eo}); dw_linkwiz.hide(); // reset the entry to the parent namespace diff --git a/lib/scripts/toolbar.js b/lib/scripts/toolbar.js index 6d75215e0..e33fa8677 100644 --- a/lib/scripts/toolbar.js +++ b/lib/scripts/toolbar.js @@ -211,9 +211,10 @@ function addBtnActionPicker($btn, props, edid) { * @return boolean If button should be appended * @author Andreas Gohr */ -function addBtnActionLinkwiz(btn, props, edid) { +function addBtnActionLinkwiz($btn, props, edid) { dw_linkwiz.init(jQuery('#'+edid)); - jQuery(btn).click(function(){ + jQuery($btn).click(function(){ + dw_linkwiz.val = props; dw_linkwiz.toggle(); return false; }); -- cgit v1.2.3 From d4a1ece8f011dd69db05b83d2f98e3207f1a7e48 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Mon, 29 Jul 2013 20:06:01 +0200 Subject: add LESS support still needs testing --- inc/load.php | 1 + lib/exe/css.php | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/inc/load.php b/inc/load.php index 5ca9b4cd8..258713e88 100644 --- a/inc/load.php +++ b/inc/load.php @@ -82,6 +82,7 @@ function load_autoload($name){ 'RemoteAPI' => DOKU_INC.'inc/remote.php', 'RemoteAPICore' => DOKU_INC.'inc/RemoteAPICore.php', 'Subscription' => DOKU_INC.'inc/subscription.php', + 'lessc' => DOKU_INC.'inc/lessc.inc.php', 'DokuWiki_Action_Plugin' => DOKU_PLUGIN.'action.php', 'DokuWiki_Admin_Plugin' => DOKU_PLUGIN.'admin.php', diff --git a/lib/exe/css.php b/lib/exe/css.php index 1e662c64a..4a9c825c1 100644 --- a/lib/exe/css.php +++ b/lib/exe/css.php @@ -154,7 +154,11 @@ function css_out(){ // apply style replacements $css = css_applystyle($css,$tplinc); - // place all @import statements at the top of the file + // parse LESS + $less = new lessc(); + $css = $less->compile($css); + + // place all remaining @import statements at the top of the file $css = css_moveimports($css); // compress whitespace and comments @@ -175,6 +179,9 @@ function css_out(){ * Does placeholder replacements in the style according to * the ones defined in a templates style.ini file * + * This also adds the ini defined placeholders as less variables + * (sans the surrounding __ and with a ini_ prefix) + * * @author Andreas Gohr */ function css_applystyle($css,$tplinc){ @@ -182,6 +189,13 @@ function css_applystyle($css,$tplinc){ if($styleini){ $css = strtr($css,$styleini['replacements']); + + $less = ''; + foreach($styleini as $key => $value){ + $key = trim($key, '_'); + $key = '@ini_'.$key; + $less .= "$key: $value\n"; + } } return $css; } @@ -333,14 +347,17 @@ function css_pluginstyles($mediatype='screen'){ $plugins = plugin_list(); foreach ($plugins as $p){ $list[DOKU_PLUGIN."$p/$mediatype.css"] = DOKU_BASE."lib/plugins/$p/"; + $list[DOKU_PLUGIN."$p/$mediatype.less"] = DOKU_BASE."lib/plugins/$p/"; // alternative for screen.css if ($mediatype=='screen') { $list[DOKU_PLUGIN."$p/style.css"] = DOKU_BASE."lib/plugins/$p/"; + $list[DOKU_PLUGIN."$p/style.less"] = DOKU_BASE."lib/plugins/$p/"; } // @deprecated 2012-04-09: rtl will cease to be a mode of its own, // please use "[dir=rtl]" in any css file in all, screen or print mode instead if($lang['direction'] == 'rtl'){ $list[DOKU_PLUGIN."$p/rtl.css"] = DOKU_BASE."lib/plugins/$p/"; + $list[DOKU_PLUGIN."$p/rtl.less"] = DOKU_BASE."lib/plugins/$p/"; } } return $list; -- cgit v1.2.3 From 559615acce5ffe51bd54e87dc1ab02dd5769b0ff Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Tue, 30 Jul 2013 10:38:06 +0200 Subject: added missing lessc library --- inc/lessc.inc.php | 3481 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3481 insertions(+) create mode 100644 inc/lessc.inc.php diff --git a/inc/lessc.inc.php b/inc/lessc.inc.php new file mode 100644 index 000000000..5c81ad2a9 --- /dev/null +++ b/inc/lessc.inc.php @@ -0,0 +1,3481 @@ + + * Licensed under MIT or GPLv3, see LICENSE + */ + + +/** + * The less compiler and parser. + * + * Converting LESS to CSS is a three stage process. The incoming file is parsed + * by `lessc_parser` into a syntax tree, then it is compiled into another tree + * representing the CSS structure by `lessc`. The CSS tree is fed into a + * formatter, like `lessc_formatter` which then outputs CSS as a string. + * + * During the first compile, all values are *reduced*, which means that their + * types are brought to the lowest form before being dump as strings. This + * handles math equations, variable dereferences, and the like. + * + * The `parse` function of `lessc` is the entry point. + * + * In summary: + * + * The `lessc` class creates an intstance of the parser, feeds it LESS code, + * then transforms the resulting tree to a CSS tree. This class also holds the + * evaluation context, such as all available mixins and variables at any given + * time. + * + * The `lessc_parser` class is only concerned with parsing its input. + * + * The `lessc_formatter` takes a CSS tree, and dumps it to a formatted string, + * handling things like indentation. + */ +class lessc { + static public $VERSION = "v0.3.9"; + static protected $TRUE = array("keyword", "true"); + static protected $FALSE = array("keyword", "false"); + + protected $libFunctions = array(); + protected $registeredVars = array(); + protected $preserveComments = false; + + public $vPrefix = '@'; // prefix of abstract properties + public $mPrefix = '$'; // prefix of abstract blocks + public $parentSelector = '&'; + + public $importDisabled = false; + public $importDir = ''; + + protected $numberPrecision = null; + + // set to the parser that generated the current line when compiling + // so we know how to create error messages + protected $sourceParser = null; + protected $sourceLoc = null; + + static public $defaultValue = array("keyword", ""); + + static protected $nextImportId = 0; // uniquely identify imports + + // attempts to find the path of an import url, returns null for css files + protected function findImport($url) { + foreach ((array)$this->importDir as $dir) { + $full = $dir.(substr($dir, -1) != '/' ? '/' : '').$url; + if ($this->fileExists($file = $full.'.less') || $this->fileExists($file = $full)) { + return $file; + } + } + + return null; + } + + protected function fileExists($name) { + return is_file($name); + } + + static public function compressList($items, $delim) { + if (!isset($items[1]) && isset($items[0])) return $items[0]; + else return array('list', $delim, $items); + } + + static public function preg_quote($what) { + return preg_quote($what, '/'); + } + + protected function tryImport($importPath, $parentBlock, $out) { + if ($importPath[0] == "function" && $importPath[1] == "url") { + $importPath = $this->flattenList($importPath[2]); + } + + $str = $this->coerceString($importPath); + if ($str === null) return false; + + $url = $this->compileValue($this->lib_e($str)); + + // don't import if it ends in css + if (substr_compare($url, '.css', -4, 4) === 0) return false; + + $realPath = $this->findImport($url); + if ($realPath === null) return false; + + if ($this->importDisabled) { + return array(false, "/* import disabled */"); + } + + $this->addParsedFile($realPath); + $parser = $this->makeParser($realPath); + $root = $parser->parse(file_get_contents($realPath)); + + // set the parents of all the block props + foreach ($root->props as $prop) { + if ($prop[0] == "block") { + $prop[1]->parent = $parentBlock; + } + } + + // copy mixins into scope, set their parents + // bring blocks from import into current block + // TODO: need to mark the source parser these came from this file + foreach ($root->children as $childName => $child) { + if (isset($parentBlock->children[$childName])) { + $parentBlock->children[$childName] = array_merge( + $parentBlock->children[$childName], + $child); + } else { + $parentBlock->children[$childName] = $child; + } + } + + $pi = pathinfo($realPath); + $dir = $pi["dirname"]; + + list($top, $bottom) = $this->sortProps($root->props, true); + $this->compileImportedProps($top, $parentBlock, $out, $parser, $dir); + + return array(true, $bottom, $parser, $dir); + } + + protected function compileImportedProps($props, $block, $out, $sourceParser, $importDir) { + $oldSourceParser = $this->sourceParser; + + $oldImport = $this->importDir; + + // TODO: this is because the importDir api is stupid + $this->importDir = (array)$this->importDir; + array_unshift($this->importDir, $importDir); + + foreach ($props as $prop) { + $this->compileProp($prop, $block, $out); + } + + $this->importDir = $oldImport; + $this->sourceParser = $oldSourceParser; + } + + /** + * Recursively compiles a block. + * + * A block is analogous to a CSS block in most cases. A single LESS document + * is encapsulated in a block when parsed, but it does not have parent tags + * so all of it's children appear on the root level when compiled. + * + * Blocks are made up of props and children. + * + * Props are property instructions, array tuples which describe an action + * to be taken, eg. write a property, set a variable, mixin a block. + * + * The children of a block are just all the blocks that are defined within. + * This is used to look up mixins when performing a mixin. + * + * Compiling the block involves pushing a fresh environment on the stack, + * and iterating through the props, compiling each one. + * + * See lessc::compileProp() + * + */ + protected function compileBlock($block) { + switch ($block->type) { + case "root": + $this->compileRoot($block); + break; + case null: + $this->compileCSSBlock($block); + break; + case "media": + $this->compileMedia($block); + break; + case "directive": + $name = "@" . $block->name; + if (!empty($block->value)) { + $name .= " " . $this->compileValue($this->reduce($block->value)); + } + + $this->compileNestedBlock($block, array($name)); + break; + default: + $this->throwError("unknown block type: $block->type\n"); + } + } + + protected function compileCSSBlock($block) { + $env = $this->pushEnv(); + + $selectors = $this->compileSelectors($block->tags); + $env->selectors = $this->multiplySelectors($selectors); + $out = $this->makeOutputBlock(null, $env->selectors); + + $this->scope->children[] = $out; + $this->compileProps($block, $out); + + $block->scope = $env; // mixins carry scope with them! + $this->popEnv(); + } + + protected function compileMedia($media) { + $env = $this->pushEnv($media); + $parentScope = $this->mediaParent($this->scope); + + $query = $this->compileMediaQuery($this->multiplyMedia($env)); + + $this->scope = $this->makeOutputBlock($media->type, array($query)); + $parentScope->children[] = $this->scope; + + $this->compileProps($media, $this->scope); + + if (count($this->scope->lines) > 0) { + $orphanSelelectors = $this->findClosestSelectors(); + if (!is_null($orphanSelelectors)) { + $orphan = $this->makeOutputBlock(null, $orphanSelelectors); + $orphan->lines = $this->scope->lines; + array_unshift($this->scope->children, $orphan); + $this->scope->lines = array(); + } + } + + $this->scope = $this->scope->parent; + $this->popEnv(); + } + + protected function mediaParent($scope) { + while (!empty($scope->parent)) { + if (!empty($scope->type) && $scope->type != "media") { + break; + } + $scope = $scope->parent; + } + + return $scope; + } + + protected function compileNestedBlock($block, $selectors) { + $this->pushEnv($block); + $this->scope = $this->makeOutputBlock($block->type, $selectors); + $this->scope->parent->children[] = $this->scope; + + $this->compileProps($block, $this->scope); + + $this->scope = $this->scope->parent; + $this->popEnv(); + } + + protected function compileRoot($root) { + $this->pushEnv(); + $this->scope = $this->makeOutputBlock($root->type); + $this->compileProps($root, $this->scope); + $this->popEnv(); + } + + protected function compileProps($block, $out) { + foreach ($this->sortProps($block->props) as $prop) { + $this->compileProp($prop, $block, $out); + } + } + + protected function sortProps($props, $split = false) { + $vars = array(); + $imports = array(); + $other = array(); + + foreach ($props as $prop) { + switch ($prop[0]) { + case "assign": + if (isset($prop[1][0]) && $prop[1][0] == $this->vPrefix) { + $vars[] = $prop; + } else { + $other[] = $prop; + } + break; + case "import": + $id = self::$nextImportId++; + $prop[] = $id; + $imports[] = $prop; + $other[] = array("import_mixin", $id); + break; + default: + $other[] = $prop; + } + } + + if ($split) { + return array(array_merge($vars, $imports), $other); + } else { + return array_merge($vars, $imports, $other); + } + } + + protected function compileMediaQuery($queries) { + $compiledQueries = array(); + foreach ($queries as $query) { + $parts = array(); + foreach ($query as $q) { + switch ($q[0]) { + case "mediaType": + $parts[] = implode(" ", array_slice($q, 1)); + break; + case "mediaExp": + if (isset($q[2])) { + $parts[] = "($q[1]: " . + $this->compileValue($this->reduce($q[2])) . ")"; + } else { + $parts[] = "($q[1])"; + } + break; + case "variable": + $parts[] = $this->compileValue($this->reduce($q)); + break; + } + } + + if (count($parts) > 0) { + $compiledQueries[] = implode(" and ", $parts); + } + } + + $out = "@media"; + if (!empty($parts)) { + $out .= " " . + implode($this->formatter->selectorSeparator, $compiledQueries); + } + return $out; + } + + protected function multiplyMedia($env, $childQueries = null) { + if (is_null($env) || + !empty($env->block->type) && $env->block->type != "media") + { + return $childQueries; + } + + // plain old block, skip + if (empty($env->block->type)) { + return $this->multiplyMedia($env->parent, $childQueries); + } + + $out = array(); + $queries = $env->block->queries; + if (is_null($childQueries)) { + $out = $queries; + } else { + foreach ($queries as $parent) { + foreach ($childQueries as $child) { + $out[] = array_merge($parent, $child); + } + } + } + + return $this->multiplyMedia($env->parent, $out); + } + + protected function expandParentSelectors(&$tag, $replace) { + $parts = explode("$&$", $tag); + $count = 0; + foreach ($parts as &$part) { + $part = str_replace($this->parentSelector, $replace, $part, $c); + $count += $c; + } + $tag = implode($this->parentSelector, $parts); + return $count; + } + + protected function findClosestSelectors() { + $env = $this->env; + $selectors = null; + while ($env !== null) { + if (isset($env->selectors)) { + $selectors = $env->selectors; + break; + } + $env = $env->parent; + } + + return $selectors; + } + + + // multiply $selectors against the nearest selectors in env + protected function multiplySelectors($selectors) { + // find parent selectors + + $parentSelectors = $this->findClosestSelectors(); + if (is_null($parentSelectors)) { + // kill parent reference in top level selector + foreach ($selectors as &$s) { + $this->expandParentSelectors($s, ""); + } + + return $selectors; + } + + $out = array(); + foreach ($parentSelectors as $parent) { + foreach ($selectors as $child) { + $count = $this->expandParentSelectors($child, $parent); + + // don't prepend the parent tag if & was used + if ($count > 0) { + $out[] = trim($child); + } else { + $out[] = trim($parent . ' ' . $child); + } + } + } + + return $out; + } + + // reduces selector expressions + protected function compileSelectors($selectors) { + $out = array(); + + foreach ($selectors as $s) { + if (is_array($s)) { + list(, $value) = $s; + $out[] = trim($this->compileValue($this->reduce($value))); + } else { + $out[] = $s; + } + } + + return $out; + } + + protected function eq($left, $right) { + return $left == $right; + } + + protected function patternMatch($block, $callingArgs) { + // match the guards if it has them + // any one of the groups must have all its guards pass for a match + if (!empty($block->guards)) { + $groupPassed = false; + foreach ($block->guards as $guardGroup) { + foreach ($guardGroup as $guard) { + $this->pushEnv(); + $this->zipSetArgs($block->args, $callingArgs); + + $negate = false; + if ($guard[0] == "negate") { + $guard = $guard[1]; + $negate = true; + } + + $passed = $this->reduce($guard) == self::$TRUE; + if ($negate) $passed = !$passed; + + $this->popEnv(); + + if ($passed) { + $groupPassed = true; + } else { + $groupPassed = false; + break; + } + } + + if ($groupPassed) break; + } + + if (!$groupPassed) { + return false; + } + } + + $numCalling = count($callingArgs); + + if (empty($block->args)) { + return $block->isVararg || $numCalling == 0; + } + + $i = -1; // no args + // try to match by arity or by argument literal + foreach ($block->args as $i => $arg) { + switch ($arg[0]) { + case "lit": + if (empty($callingArgs[$i]) || !$this->eq($arg[1], $callingArgs[$i])) { + return false; + } + break; + case "arg": + // no arg and no default value + if (!isset($callingArgs[$i]) && !isset($arg[2])) { + return false; + } + break; + case "rest": + $i--; // rest can be empty + break 2; + } + } + + if ($block->isVararg) { + return true; // not having enough is handled above + } else { + $numMatched = $i + 1; + // greater than becuase default values always match + return $numMatched >= $numCalling; + } + } + + protected function patternMatchAll($blocks, $callingArgs) { + $matches = null; + foreach ($blocks as $block) { + if ($this->patternMatch($block, $callingArgs)) { + $matches[] = $block; + } + } + + return $matches; + } + + // attempt to find blocks matched by path and args + protected function findBlocks($searchIn, $path, $args, $seen=array()) { + if ($searchIn == null) return null; + if (isset($seen[$searchIn->id])) return null; + $seen[$searchIn->id] = true; + + $name = $path[0]; + + if (isset($searchIn->children[$name])) { + $blocks = $searchIn->children[$name]; + if (count($path) == 1) { + $matches = $this->patternMatchAll($blocks, $args); + if (!empty($matches)) { + // This will return all blocks that match in the closest + // scope that has any matching block, like lessjs + return $matches; + } + } else { + $matches = array(); + foreach ($blocks as $subBlock) { + $subMatches = $this->findBlocks($subBlock, + array_slice($path, 1), $args, $seen); + + if (!is_null($subMatches)) { + foreach ($subMatches as $sm) { + $matches[] = $sm; + } + } + } + + return count($matches) > 0 ? $matches : null; + } + } + + if ($searchIn->parent === $searchIn) return null; + return $this->findBlocks($searchIn->parent, $path, $args, $seen); + } + + // sets all argument names in $args to either the default value + // or the one passed in through $values + protected function zipSetArgs($args, $values) { + $i = 0; + $assignedValues = array(); + foreach ($args as $a) { + if ($a[0] == "arg") { + if ($i < count($values) && !is_null($values[$i])) { + $value = $values[$i]; + } elseif (isset($a[2])) { + $value = $a[2]; + } else $value = null; + + $value = $this->reduce($value); + $this->set($a[1], $value); + $assignedValues[] = $value; + } + $i++; + } + + // check for a rest + $last = end($args); + if ($last[0] == "rest") { + $rest = array_slice($values, count($args) - 1); + $this->set($last[1], $this->reduce(array("list", " ", $rest))); + } + + $this->env->arguments = $assignedValues; + } + + // compile a prop and update $lines or $blocks appropriately + protected function compileProp($prop, $block, $out) { + // set error position context + $this->sourceLoc = isset($prop[-1]) ? $prop[-1] : -1; + + switch ($prop[0]) { + case 'assign': + list(, $name, $value) = $prop; + if ($name[0] == $this->vPrefix) { + $this->set($name, $value); + } else { + $out->lines[] = $this->formatter->property($name, + $this->compileValue($this->reduce($value))); + } + break; + case 'block': + list(, $child) = $prop; + $this->compileBlock($child); + break; + case 'mixin': + list(, $path, $args, $suffix) = $prop; + + $args = array_map(array($this, "reduce"), (array)$args); + $mixins = $this->findBlocks($block, $path, $args); + + if ($mixins === null) { + // fwrite(STDERR,"failed to find block: ".implode(" > ", $path)."\n"); + break; // throw error here?? + } + + foreach ($mixins as $mixin) { + if ($mixin === $block && !$args) { + continue; + } + + $haveScope = false; + if (isset($mixin->parent->scope)) { + $haveScope = true; + $mixinParentEnv = $this->pushEnv(); + $mixinParentEnv->storeParent = $mixin->parent->scope; + } + + $haveArgs = false; + if (isset($mixin->args)) { + $haveArgs = true; + $this->pushEnv(); + $this->zipSetArgs($mixin->args, $args); + } + + $oldParent = $mixin->parent; + if ($mixin != $block) $mixin->parent = $block; + + foreach ($this->sortProps($mixin->props) as $subProp) { + if ($suffix !== null && + $subProp[0] == "assign" && + is_string($subProp[1]) && + $subProp[1]{0} != $this->vPrefix) + { + $subProp[2] = array( + 'list', ' ', + array($subProp[2], array('keyword', $suffix)) + ); + } + + $this->compileProp($subProp, $mixin, $out); + } + + $mixin->parent = $oldParent; + + if ($haveArgs) $this->popEnv(); + if ($haveScope) $this->popEnv(); + } + + break; + case 'raw': + $out->lines[] = $prop[1]; + break; + case "directive": + list(, $name, $value) = $prop; + $out->lines[] = "@$name " . $this->compileValue($this->reduce($value)).';'; + break; + case "comment": + $out->lines[] = $prop[1]; + break; + case "import"; + list(, $importPath, $importId) = $prop; + $importPath = $this->reduce($importPath); + + if (!isset($this->env->imports)) { + $this->env->imports = array(); + } + + $result = $this->tryImport($importPath, $block, $out); + + $this->env->imports[$importId] = $result === false ? + array(false, "@import " . $this->compileValue($importPath).";") : + $result; + + break; + case "import_mixin": + list(,$importId) = $prop; + $import = $this->env->imports[$importId]; + if ($import[0] === false) { + $out->lines[] = $import[1]; + } else { + list(, $bottom, $parser, $importDir) = $import; + $this->compileImportedProps($bottom, $block, $out, $parser, $importDir); + } + + break; + default: + $this->throwError("unknown op: {$prop[0]}\n"); + } + } + + + /** + * Compiles a primitive value into a CSS property value. + * + * Values in lessphp are typed by being wrapped in arrays, their format is + * typically: + * + * array(type, contents [, additional_contents]*) + * + * The input is expected to be reduced. This function will not work on + * things like expressions and variables. + */ + protected function compileValue($value) { + switch ($value[0]) { + case 'list': + // [1] - delimiter + // [2] - array of values + return implode($value[1], array_map(array($this, 'compileValue'), $value[2])); + case 'raw_color': + if (!empty($this->formatter->compressColors)) { + return $this->compileValue($this->coerceColor($value)); + } + return $value[1]; + case 'keyword': + // [1] - the keyword + return $value[1]; + case 'number': + list(, $num, $unit) = $value; + // [1] - the number + // [2] - the unit + if ($this->numberPrecision !== null) { + $num = round($num, $this->numberPrecision); + } + return $num . $unit; + case 'string': + // [1] - contents of string (includes quotes) + list(, $delim, $content) = $value; + foreach ($content as &$part) { + if (is_array($part)) { + $part = $this->compileValue($part); + } + } + return $delim . implode($content) . $delim; + case 'color': + // [1] - red component (either number or a %) + // [2] - green component + // [3] - blue component + // [4] - optional alpha component + list(, $r, $g, $b) = $value; + $r = round($r); + $g = round($g); + $b = round($b); + + if (count($value) == 5 && $value[4] != 1) { // rgba + return 'rgba('.$r.','.$g.','.$b.','.$value[4].')'; + } + + $h = sprintf("#%02x%02x%02x", $r, $g, $b); + + if (!empty($this->formatter->compressColors)) { + // Converting hex color to short notation (e.g. #003399 to #039) + if ($h[1] === $h[2] && $h[3] === $h[4] && $h[5] === $h[6]) { + $h = '#' . $h[1] . $h[3] . $h[5]; + } + } + + return $h; + + case 'function': + list(, $name, $args) = $value; + return $name.'('.$this->compileValue($args).')'; + default: // assumed to be unit + $this->throwError("unknown value type: $value[0]"); + } + } + + protected function lib_isnumber($value) { + return $this->toBool($value[0] == "number"); + } + + protected function lib_isstring($value) { + return $this->toBool($value[0] == "string"); + } + + protected function lib_iscolor($value) { + return $this->toBool($this->coerceColor($value)); + } + + protected function lib_iskeyword($value) { + return $this->toBool($value[0] == "keyword"); + } + + protected function lib_ispixel($value) { + return $this->toBool($value[0] == "number" && $value[2] == "px"); + } + + protected function lib_ispercentage($value) { + return $this->toBool($value[0] == "number" && $value[2] == "%"); + } + + protected function lib_isem($value) { + return $this->toBool($value[0] == "number" && $value[2] == "em"); + } + + protected function lib_isrem($value) { + return $this->toBool($value[0] == "number" && $value[2] == "rem"); + } + + protected function lib_rgbahex($color) { + $color = $this->coerceColor($color); + if (is_null($color)) + $this->throwError("color expected for rgbahex"); + + return sprintf("#%02x%02x%02x%02x", + isset($color[4]) ? $color[4]*255 : 255, + $color[1],$color[2], $color[3]); + } + + protected function lib_argb($color){ + return $this->lib_rgbahex($color); + } + + // utility func to unquote a string + protected function lib_e($arg) { + switch ($arg[0]) { + case "list": + $items = $arg[2]; + if (isset($items[0])) { + return $this->lib_e($items[0]); + } + return self::$defaultValue; + case "string": + $arg[1] = ""; + return $arg; + case "keyword": + return $arg; + default: + return array("keyword", $this->compileValue($arg)); + } + } + + protected function lib__sprintf($args) { + if ($args[0] != "list") return $args; + $values = $args[2]; + $string = array_shift($values); + $template = $this->compileValue($this->lib_e($string)); + + $i = 0; + if (preg_match_all('/%[dsa]/', $template, $m)) { + foreach ($m[0] as $match) { + $val = isset($values[$i]) ? + $this->reduce($values[$i]) : array('keyword', ''); + + // lessjs compat, renders fully expanded color, not raw color + if ($color = $this->coerceColor($val)) { + $val = $color; + } + + $i++; + $rep = $this->compileValue($this->lib_e($val)); + $template = preg_replace('/'.self::preg_quote($match).'/', + $rep, $template, 1); + } + } + + $d = $string[0] == "string" ? $string[1] : '"'; + return array("string", $d, array($template)); + } + + protected function lib_floor($arg) { + $value = $this->assertNumber($arg); + return array("number", floor($value), $arg[2]); + } + + protected function lib_ceil($arg) { + $value = $this->assertNumber($arg); + return array("number", ceil($value), $arg[2]); + } + + protected function lib_round($arg) { + $value = $this->assertNumber($arg); + return array("number", round($value), $arg[2]); + } + + protected function lib_unit($arg) { + if ($arg[0] == "list") { + list($number, $newUnit) = $arg[2]; + return array("number", $this->assertNumber($number), + $this->compileValue($this->lib_e($newUnit))); + } else { + return array("number", $this->assertNumber($arg), ""); + } + } + + /** + * Helper function to get arguments for color manipulation functions. + * takes a list that contains a color like thing and a percentage + */ + protected function colorArgs($args) { + if ($args[0] != 'list' || count($args[2]) < 2) { + return array(array('color', 0, 0, 0), 0); + } + list($color, $delta) = $args[2]; + $color = $this->assertColor($color); + $delta = floatval($delta[1]); + + return array($color, $delta); + } + + protected function lib_darken($args) { + list($color, $delta) = $this->colorArgs($args); + + $hsl = $this->toHSL($color); + $hsl[3] = $this->clamp($hsl[3] - $delta, 100); + return $this->toRGB($hsl); + } + + protected function lib_lighten($args) { + list($color, $delta) = $this->colorArgs($args); + + $hsl = $this->toHSL($color); + $hsl[3] = $this->clamp($hsl[3] + $delta, 100); + return $this->toRGB($hsl); + } + + protected function lib_saturate($args) { + list($color, $delta) = $this->colorArgs($args); + + $hsl = $this->toHSL($color); + $hsl[2] = $this->clamp($hsl[2] + $delta, 100); + return $this->toRGB($hsl); + } + + protected function lib_desaturate($args) { + list($color, $delta) = $this->colorArgs($args); + + $hsl = $this->toHSL($color); + $hsl[2] = $this->clamp($hsl[2] - $delta, 100); + return $this->toRGB($hsl); + } + + protected function lib_spin($args) { + list($color, $delta) = $this->colorArgs($args); + + $hsl = $this->toHSL($color); + + $hsl[1] = $hsl[1] + $delta % 360; + if ($hsl[1] < 0) $hsl[1] += 360; + + return $this->toRGB($hsl); + } + + protected function lib_fadeout($args) { + list($color, $delta) = $this->colorArgs($args); + $color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) - $delta/100); + return $color; + } + + protected function lib_fadein($args) { + list($color, $delta) = $this->colorArgs($args); + $color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) + $delta/100); + return $color; + } + + protected function lib_hue($color) { + $hsl = $this->toHSL($this->assertColor($color)); + return round($hsl[1]); + } + + protected function lib_saturation($color) { + $hsl = $this->toHSL($this->assertColor($color)); + return round($hsl[2]); + } + + protected function lib_lightness($color) { + $hsl = $this->toHSL($this->assertColor($color)); + return round($hsl[3]); + } + + // get the alpha of a color + // defaults to 1 for non-colors or colors without an alpha + protected function lib_alpha($value) { + if (!is_null($color = $this->coerceColor($value))) { + return isset($color[4]) ? $color[4] : 1; + } + } + + // set the alpha of the color + protected function lib_fade($args) { + list($color, $alpha) = $this->colorArgs($args); + $color[4] = $this->clamp($alpha / 100.0); + return $color; + } + + protected function lib_percentage($arg) { + $num = $this->assertNumber($arg); + return array("number", $num*100, "%"); + } + + // mixes two colors by weight + // mix(@color1, @color2, [@weight: 50%]); + // http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method + protected function lib_mix($args) { + if ($args[0] != "list" || count($args[2]) < 2) + $this->throwError("mix expects (color1, color2, weight)"); + + list($first, $second) = $args[2]; + $first = $this->assertColor($first); + $second = $this->assertColor($second); + + $first_a = $this->lib_alpha($first); + $second_a = $this->lib_alpha($second); + + if (isset($args[2][2])) { + $weight = $args[2][2][1] / 100.0; + } else { + $weight = 0.5; + } + + $w = $weight * 2 - 1; + $a = $first_a - $second_a; + + $w1 = (($w * $a == -1 ? $w : ($w + $a)/(1 + $w * $a)) + 1) / 2.0; + $w2 = 1.0 - $w1; + + $new = array('color', + $w1 * $first[1] + $w2 * $second[1], + $w1 * $first[2] + $w2 * $second[2], + $w1 * $first[3] + $w2 * $second[3], + ); + + if ($first_a != 1.0 || $second_a != 1.0) { + $new[] = $first_a * $weight + $second_a * ($weight - 1); + } + + return $this->fixColor($new); + } + + protected function lib_contrast($args) { + if ($args[0] != 'list' || count($args[2]) < 3) { + return array(array('color', 0, 0, 0), 0); + } + + list($inputColor, $darkColor, $lightColor) = $args[2]; + + $inputColor = $this->assertColor($inputColor); + $darkColor = $this->assertColor($darkColor); + $lightColor = $this->assertColor($lightColor); + $hsl = $this->toHSL($inputColor); + + if ($hsl[3] > 50) { + return $darkColor; + } + + return $lightColor; + } + + protected function assertColor($value, $error = "expected color value") { + $color = $this->coerceColor($value); + if (is_null($color)) $this->throwError($error); + return $color; + } + + protected function assertNumber($value, $error = "expecting number") { + if ($value[0] == "number") return $value[1]; + $this->throwError($error); + } + + protected function toHSL($color) { + if ($color[0] == 'hsl') return $color; + + $r = $color[1] / 255; + $g = $color[2] / 255; + $b = $color[3] / 255; + + $min = min($r, $g, $b); + $max = max($r, $g, $b); + + $L = ($min + $max) / 2; + if ($min == $max) { + $S = $H = 0; + } else { + if ($L < 0.5) + $S = ($max - $min)/($max + $min); + else + $S = ($max - $min)/(2.0 - $max - $min); + + if ($r == $max) $H = ($g - $b)/($max - $min); + elseif ($g == $max) $H = 2.0 + ($b - $r)/($max - $min); + elseif ($b == $max) $H = 4.0 + ($r - $g)/($max - $min); + + } + + $out = array('hsl', + ($H < 0 ? $H + 6 : $H)*60, + $S*100, + $L*100, + ); + + if (count($color) > 4) $out[] = $color[4]; // copy alpha + return $out; + } + + protected function toRGB_helper($comp, $temp1, $temp2) { + if ($comp < 0) $comp += 1.0; + elseif ($comp > 1) $comp -= 1.0; + + if (6 * $comp < 1) return $temp1 + ($temp2 - $temp1) * 6 * $comp; + if (2 * $comp < 1) return $temp2; + if (3 * $comp < 2) return $temp1 + ($temp2 - $temp1)*((2/3) - $comp) * 6; + + return $temp1; + } + + /** + * Converts a hsl array into a color value in rgb. + * Expects H to be in range of 0 to 360, S and L in 0 to 100 + */ + protected function toRGB($color) { + if ($color[0] == 'color') return $color; + + $H = $color[1] / 360; + $S = $color[2] / 100; + $L = $color[3] / 100; + + if ($S == 0) { + $r = $g = $b = $L; + } else { + $temp2 = $L < 0.5 ? + $L*(1.0 + $S) : + $L + $S - $L * $S; + + $temp1 = 2.0 * $L - $temp2; + + $r = $this->toRGB_helper($H + 1/3, $temp1, $temp2); + $g = $this->toRGB_helper($H, $temp1, $temp2); + $b = $this->toRGB_helper($H - 1/3, $temp1, $temp2); + } + + // $out = array('color', round($r*255), round($g*255), round($b*255)); + $out = array('color', $r*255, $g*255, $b*255); + if (count($color) > 4) $out[] = $color[4]; // copy alpha + return $out; + } + + protected function clamp($v, $max = 1, $min = 0) { + return min($max, max($min, $v)); + } + + /** + * Convert the rgb, rgba, hsl color literals of function type + * as returned by the parser into values of color type. + */ + protected function funcToColor($func) { + $fname = $func[1]; + if ($func[2][0] != 'list') return false; // need a list of arguments + $rawComponents = $func[2][2]; + + if ($fname == 'hsl' || $fname == 'hsla') { + $hsl = array('hsl'); + $i = 0; + foreach ($rawComponents as $c) { + $val = $this->reduce($c); + $val = isset($val[1]) ? floatval($val[1]) : 0; + + if ($i == 0) $clamp = 360; + elseif ($i < 3) $clamp = 100; + else $clamp = 1; + + $hsl[] = $this->clamp($val, $clamp); + $i++; + } + + while (count($hsl) < 4) $hsl[] = 0; + return $this->toRGB($hsl); + + } elseif ($fname == 'rgb' || $fname == 'rgba') { + $components = array(); + $i = 1; + foreach ($rawComponents as $c) { + $c = $this->reduce($c); + if ($i < 4) { + if ($c[0] == "number" && $c[2] == "%") { + $components[] = 255 * ($c[1] / 100); + } else { + $components[] = floatval($c[1]); + } + } elseif ($i == 4) { + if ($c[0] == "number" && $c[2] == "%") { + $components[] = 1.0 * ($c[1] / 100); + } else { + $components[] = floatval($c[1]); + } + } else break; + + $i++; + } + while (count($components) < 3) $components[] = 0; + array_unshift($components, 'color'); + return $this->fixColor($components); + } + + return false; + } + + protected function reduce($value, $forExpression = false) { + switch ($value[0]) { + case "interpolate": + $reduced = $this->reduce($value[1]); + $var = $this->compileValue($reduced); + $res = $this->reduce(array("variable", $this->vPrefix . $var)); + + if (empty($value[2])) $res = $this->lib_e($res); + + return $res; + case "variable": + $key = $value[1]; + if (is_array($key)) { + $key = $this->reduce($key); + $key = $this->vPrefix . $this->compileValue($this->lib_e($key)); + } + + $seen =& $this->env->seenNames; + + if (!empty($seen[$key])) { + $this->throwError("infinite loop detected: $key"); + } + + $seen[$key] = true; + $out = $this->reduce($this->get($key, self::$defaultValue)); + $seen[$key] = false; + return $out; + case "list": + foreach ($value[2] as &$item) { + $item = $this->reduce($item, $forExpression); + } + return $value; + case "expression": + return $this->evaluate($value); + case "string": + foreach ($value[2] as &$part) { + if (is_array($part)) { + $strip = $part[0] == "variable"; + $part = $this->reduce($part); + if ($strip) $part = $this->lib_e($part); + } + } + return $value; + case "escape": + list(,$inner) = $value; + return $this->lib_e($this->reduce($inner)); + case "function": + $color = $this->funcToColor($value); + if ($color) return $color; + + list(, $name, $args) = $value; + if ($name == "%") $name = "_sprintf"; + $f = isset($this->libFunctions[$name]) ? + $this->libFunctions[$name] : array($this, 'lib_'.$name); + + if (is_callable($f)) { + if ($args[0] == 'list') + $args = self::compressList($args[2], $args[1]); + + $ret = call_user_func($f, $this->reduce($args, true), $this); + + if (is_null($ret)) { + return array("string", "", array( + $name, "(", $args, ")" + )); + } + + // convert to a typed value if the result is a php primitive + if (is_numeric($ret)) $ret = array('number', $ret, ""); + elseif (!is_array($ret)) $ret = array('keyword', $ret); + + return $ret; + } + + // plain function, reduce args + $value[2] = $this->reduce($value[2]); + return $value; + case "unary": + list(, $op, $exp) = $value; + $exp = $this->reduce($exp); + + if ($exp[0] == "number") { + switch ($op) { + case "+": + return $exp; + case "-": + $exp[1] *= -1; + return $exp; + } + } + return array("string", "", array($op, $exp)); + } + + if ($forExpression) { + switch ($value[0]) { + case "keyword": + if ($color = $this->coerceColor($value)) { + return $color; + } + break; + case "raw_color": + return $this->coerceColor($value); + } + } + + return $value; + } + + + // coerce a value for use in color operation + protected function coerceColor($value) { + switch($value[0]) { + case 'color': return $value; + case 'raw_color': + $c = array("color", 0, 0, 0); + $colorStr = substr($value[1], 1); + $num = hexdec($colorStr); + $width = strlen($colorStr) == 3 ? 16 : 256; + + for ($i = 3; $i > 0; $i--) { // 3 2 1 + $t = $num % $width; + $num /= $width; + + $c[$i] = $t * (256/$width) + $t * floor(16/$width); + } + + return $c; + case 'keyword': + $name = $value[1]; + if (isset(self::$cssColors[$name])) { + $rgba = explode(',', self::$cssColors[$name]); + + if(isset($rgba[3])) + return array('color', $rgba[0], $rgba[1], $rgba[2], $rgba[3]); + + return array('color', $rgba[0], $rgba[1], $rgba[2]); + } + return null; + } + } + + // make something string like into a string + protected function coerceString($value) { + switch ($value[0]) { + case "string": + return $value; + case "keyword": + return array("string", "", array($value[1])); + } + return null; + } + + // turn list of length 1 into value type + protected function flattenList($value) { + if ($value[0] == "list" && count($value[2]) == 1) { + return $this->flattenList($value[2][0]); + } + return $value; + } + + protected function toBool($a) { + if ($a) return self::$TRUE; + else return self::$FALSE; + } + + // evaluate an expression + protected function evaluate($exp) { + list(, $op, $left, $right, $whiteBefore, $whiteAfter) = $exp; + + $left = $this->reduce($left, true); + $right = $this->reduce($right, true); + + if ($leftColor = $this->coerceColor($left)) { + $left = $leftColor; + } + + if ($rightColor = $this->coerceColor($right)) { + $right = $rightColor; + } + + $ltype = $left[0]; + $rtype = $right[0]; + + // operators that work on all types + if ($op == "and") { + return $this->toBool($left == self::$TRUE && $right == self::$TRUE); + } + + if ($op == "=") { + return $this->toBool($this->eq($left, $right) ); + } + + if ($op == "+" && !is_null($str = $this->stringConcatenate($left, $right))) { + return $str; + } + + // type based operators + $fname = "op_${ltype}_${rtype}"; + if (is_callable(array($this, $fname))) { + $out = $this->$fname($op, $left, $right); + if (!is_null($out)) return $out; + } + + // make the expression look it did before being parsed + $paddedOp = $op; + if ($whiteBefore) $paddedOp = " " . $paddedOp; + if ($whiteAfter) $paddedOp .= " "; + + return array("string", "", array($left, $paddedOp, $right)); + } + + protected function stringConcatenate($left, $right) { + if ($strLeft = $this->coerceString($left)) { + if ($right[0] == "string") { + $right[1] = ""; + } + $strLeft[2][] = $right; + return $strLeft; + } + + if ($strRight = $this->coerceString($right)) { + array_unshift($strRight[2], $left); + return $strRight; + } + } + + + // make sure a color's components don't go out of bounds + protected function fixColor($c) { + foreach (range(1, 3) as $i) { + if ($c[$i] < 0) $c[$i] = 0; + if ($c[$i] > 255) $c[$i] = 255; + } + + return $c; + } + + protected function op_number_color($op, $lft, $rgt) { + if ($op == '+' || $op == '*') { + return $this->op_color_number($op, $rgt, $lft); + } + } + + protected function op_color_number($op, $lft, $rgt) { + if ($rgt[0] == '%') $rgt[1] /= 100; + + return $this->op_color_color($op, $lft, + array_fill(1, count($lft) - 1, $rgt[1])); + } + + protected function op_color_color($op, $left, $right) { + $out = array('color'); + $max = count($left) > count($right) ? count($left) : count($right); + foreach (range(1, $max - 1) as $i) { + $lval = isset($left[$i]) ? $left[$i] : 0; + $rval = isset($right[$i]) ? $right[$i] : 0; + switch ($op) { + case '+': + $out[] = $lval + $rval; + break; + case '-': + $out[] = $lval - $rval; + break; + case '*': + $out[] = $lval * $rval; + break; + case '%': + $out[] = $lval % $rval; + break; + case '/': + if ($rval == 0) $this->throwError("evaluate error: can't divide by zero"); + $out[] = $lval / $rval; + break; + default: + $this->throwError('evaluate error: color op number failed on op '.$op); + } + } + return $this->fixColor($out); + } + + function lib_red($color){ + $color = $this->coerceColor($color); + if (is_null($color)) { + $this->throwError('color expected for red()'); + } + + return $color[1]; + } + + function lib_green($color){ + $color = $this->coerceColor($color); + if (is_null($color)) { + $this->throwError('color expected for green()'); + } + + return $color[2]; + } + + function lib_blue($color){ + $color = $this->coerceColor($color); + if (is_null($color)) { + $this->throwError('color expected for blue()'); + } + + return $color[3]; + } + + + // operator on two numbers + protected function op_number_number($op, $left, $right) { + $unit = empty($left[2]) ? $right[2] : $left[2]; + + $value = 0; + switch ($op) { + case '+': + $value = $left[1] + $right[1]; + break; + case '*': + $value = $left[1] * $right[1]; + break; + case '-': + $value = $left[1] - $right[1]; + break; + case '%': + $value = $left[1] % $right[1]; + break; + case '/': + if ($right[1] == 0) $this->throwError('parse error: divide by zero'); + $value = $left[1] / $right[1]; + break; + case '<': + return $this->toBool($left[1] < $right[1]); + case '>': + return $this->toBool($left[1] > $right[1]); + case '>=': + return $this->toBool($left[1] >= $right[1]); + case '=<': + return $this->toBool($left[1] <= $right[1]); + default: + $this->throwError('parse error: unknown number operator: '.$op); + } + + return array("number", $value, $unit); + } + + + /* environment functions */ + + protected function makeOutputBlock($type, $selectors = null) { + $b = new stdclass; + $b->lines = array(); + $b->children = array(); + $b->selectors = $selectors; + $b->type = $type; + $b->parent = $this->scope; + return $b; + } + + // the state of execution + protected function pushEnv($block = null) { + $e = new stdclass; + $e->parent = $this->env; + $e->store = array(); + $e->block = $block; + + $this->env = $e; + return $e; + } + + // pop something off the stack + protected function popEnv() { + $old = $this->env; + $this->env = $this->env->parent; + return $old; + } + + // set something in the current env + protected function set($name, $value) { + $this->env->store[$name] = $value; + } + + + // get the highest occurrence entry for a name + protected function get($name, $default=null) { + $current = $this->env; + + $isArguments = $name == $this->vPrefix . 'arguments'; + while ($current) { + if ($isArguments && isset($current->arguments)) { + return array('list', ' ', $current->arguments); + } + + if (isset($current->store[$name])) + return $current->store[$name]; + else { + $current = isset($current->storeParent) ? + $current->storeParent : $current->parent; + } + } + + return $default; + } + + // inject array of unparsed strings into environment as variables + protected function injectVariables($args) { + $this->pushEnv(); + $parser = new lessc_parser($this, __METHOD__); + foreach ($args as $name => $strValue) { + if ($name{0} != '@') $name = '@'.$name; + $parser->count = 0; + $parser->buffer = (string)$strValue; + if (!$parser->propertyValue($value)) { + throw new Exception("failed to parse passed in variable $name: $strValue"); + } + + $this->set($name, $value); + } + } + + /** + * Initialize any static state, can initialize parser for a file + * $opts isn't used yet + */ + public function __construct($fname = null) { + if ($fname !== null) { + // used for deprecated parse method + $this->_parseFile = $fname; + } + } + + public function compile($string, $name = null) { + $locale = setlocale(LC_NUMERIC, 0); + setlocale(LC_NUMERIC, "C"); + + $this->parser = $this->makeParser($name); + $root = $this->parser->parse($string); + + $this->env = null; + $this->scope = null; + + $this->formatter = $this->newFormatter(); + + if (!empty($this->registeredVars)) { + $this->injectVariables($this->registeredVars); + } + + $this->sourceParser = $this->parser; // used for error messages + $this->compileBlock($root); + + ob_start(); + $this->formatter->block($this->scope); + $out = ob_get_clean(); + setlocale(LC_NUMERIC, $locale); + return $out; + } + + public function compileFile($fname, $outFname = null) { + if (!is_readable($fname)) { + throw new Exception('load error: failed to find '.$fname); + } + + $pi = pathinfo($fname); + + $oldImport = $this->importDir; + + $this->importDir = (array)$this->importDir; + $this->importDir[] = $pi['dirname'].'/'; + + $this->allParsedFiles = array(); + $this->addParsedFile($fname); + + $out = $this->compile(file_get_contents($fname), $fname); + + $this->importDir = $oldImport; + + if ($outFname !== null) { + return file_put_contents($outFname, $out); + } + + return $out; + } + + // compile only if changed input has changed or output doesn't exist + public function checkedCompile($in, $out) { + if (!is_file($out) || filemtime($in) > filemtime($out)) { + $this->compileFile($in, $out); + return true; + } + return false; + } + + /** + * Execute lessphp on a .less file or a lessphp cache structure + * + * The lessphp cache structure contains information about a specific + * less file having been parsed. It can be used as a hint for future + * calls to determine whether or not a rebuild is required. + * + * The cache structure contains two important keys that may be used + * externally: + * + * compiled: The final compiled CSS + * updated: The time (in seconds) the CSS was last compiled + * + * The cache structure is a plain-ol' PHP associative array and can + * be serialized and unserialized without a hitch. + * + * @param mixed $in Input + * @param bool $force Force rebuild? + * @return array lessphp cache structure + */ + public function cachedCompile($in, $force = false) { + // assume no root + $root = null; + + if (is_string($in)) { + $root = $in; + } elseif (is_array($in) and isset($in['root'])) { + if ($force or ! isset($in['files'])) { + // If we are forcing a recompile or if for some reason the + // structure does not contain any file information we should + // specify the root to trigger a rebuild. + $root = $in['root']; + } elseif (isset($in['files']) and is_array($in['files'])) { + foreach ($in['files'] as $fname => $ftime ) { + if (!file_exists($fname) or filemtime($fname) > $ftime) { + // One of the files we knew about previously has changed + // so we should look at our incoming root again. + $root = $in['root']; + break; + } + } + } + } else { + // TODO: Throw an exception? We got neither a string nor something + // that looks like a compatible lessphp cache structure. + return null; + } + + if ($root !== null) { + // If we have a root value which means we should rebuild. + $out = array(); + $out['root'] = $root; + $out['compiled'] = $this->compileFile($root); + $out['files'] = $this->allParsedFiles(); + $out['updated'] = time(); + return $out; + } else { + // No changes, pass back the structure + // we were given initially. + return $in; + } + + } + + // parse and compile buffer + // This is deprecated + public function parse($str = null, $initialVariables = null) { + if (is_array($str)) { + $initialVariables = $str; + $str = null; + } + + $oldVars = $this->registeredVars; + if ($initialVariables !== null) { + $this->setVariables($initialVariables); + } + + if ($str == null) { + if (empty($this->_parseFile)) { + throw new exception("nothing to parse"); + } + + $out = $this->compileFile($this->_parseFile); + } else { + $out = $this->compile($str); + } + + $this->registeredVars = $oldVars; + return $out; + } + + protected function makeParser($name) { + $parser = new lessc_parser($this, $name); + $parser->writeComments = $this->preserveComments; + + return $parser; + } + + public function setFormatter($name) { + $this->formatterName = $name; + } + + protected function newFormatter() { + $className = "lessc_formatter_lessjs"; + if (!empty($this->formatterName)) { + if (!is_string($this->formatterName)) + return $this->formatterName; + $className = "lessc_formatter_$this->formatterName"; + } + + return new $className; + } + + public function setPreserveComments($preserve) { + $this->preserveComments = $preserve; + } + + public function registerFunction($name, $func) { + $this->libFunctions[$name] = $func; + } + + public function unregisterFunction($name) { + unset($this->libFunctions[$name]); + } + + public function setVariables($variables) { + $this->registeredVars = array_merge($this->registeredVars, $variables); + } + + public function unsetVariable($name) { + unset($this->registeredVars[$name]); + } + + public function setImportDir($dirs) { + $this->importDir = (array)$dirs; + } + + public function addImportDir($dir) { + $this->importDir = (array)$this->importDir; + $this->importDir[] = $dir; + } + + public function allParsedFiles() { + return $this->allParsedFiles; + } + + protected function addParsedFile($file) { + $this->allParsedFiles[realpath($file)] = filemtime($file); + } + + /** + * Uses the current value of $this->count to show line and line number + */ + protected function throwError($msg = null) { + if ($this->sourceLoc >= 0) { + $this->sourceParser->throwError($msg, $this->sourceLoc); + } + throw new exception($msg); + } + + // compile file $in to file $out if $in is newer than $out + // returns true when it compiles, false otherwise + public static function ccompile($in, $out, $less = null) { + if ($less === null) { + $less = new self; + } + return $less->checkedCompile($in, $out); + } + + public static function cexecute($in, $force = false, $less = null) { + if ($less === null) { + $less = new self; + } + return $less->cachedCompile($in, $force); + } + + static protected $cssColors = array( + 'aliceblue' => '240,248,255', + 'antiquewhite' => '250,235,215', + 'aqua' => '0,255,255', + 'aquamarine' => '127,255,212', + 'azure' => '240,255,255', + 'beige' => '245,245,220', + 'bisque' => '255,228,196', + 'black' => '0,0,0', + 'blanchedalmond' => '255,235,205', + 'blue' => '0,0,255', + 'blueviolet' => '138,43,226', + 'brown' => '165,42,42', + 'burlywood' => '222,184,135', + 'cadetblue' => '95,158,160', + 'chartreuse' => '127,255,0', + 'chocolate' => '210,105,30', + 'coral' => '255,127,80', + 'cornflowerblue' => '100,149,237', + 'cornsilk' => '255,248,220', + 'crimson' => '220,20,60', + 'cyan' => '0,255,255', + 'darkblue' => '0,0,139', + 'darkcyan' => '0,139,139', + 'darkgoldenrod' => '184,134,11', + 'darkgray' => '169,169,169', + 'darkgreen' => '0,100,0', + 'darkgrey' => '169,169,169', + 'darkkhaki' => '189,183,107', + 'darkmagenta' => '139,0,139', + 'darkolivegreen' => '85,107,47', + 'darkorange' => '255,140,0', + 'darkorchid' => '153,50,204', + 'darkred' => '139,0,0', + 'darksalmon' => '233,150,122', + 'darkseagreen' => '143,188,143', + 'darkslateblue' => '72,61,139', + 'darkslategray' => '47,79,79', + 'darkslategrey' => '47,79,79', + 'darkturquoise' => '0,206,209', + 'darkviolet' => '148,0,211', + 'deeppink' => '255,20,147', + 'deepskyblue' => '0,191,255', + 'dimgray' => '105,105,105', + 'dimgrey' => '105,105,105', + 'dodgerblue' => '30,144,255', + 'firebrick' => '178,34,34', + 'floralwhite' => '255,250,240', + 'forestgreen' => '34,139,34', + 'fuchsia' => '255,0,255', + 'gainsboro' => '220,220,220', + 'ghostwhite' => '248,248,255', + 'gold' => '255,215,0', + 'goldenrod' => '218,165,32', + 'gray' => '128,128,128', + 'green' => '0,128,0', + 'greenyellow' => '173,255,47', + 'grey' => '128,128,128', + 'honeydew' => '240,255,240', + 'hotpink' => '255,105,180', + 'indianred' => '205,92,92', + 'indigo' => '75,0,130', + 'ivory' => '255,255,240', + 'khaki' => '240,230,140', + 'lavender' => '230,230,250', + 'lavenderblush' => '255,240,245', + 'lawngreen' => '124,252,0', + 'lemonchiffon' => '255,250,205', + 'lightblue' => '173,216,230', + 'lightcoral' => '240,128,128', + 'lightcyan' => '224,255,255', + 'lightgoldenrodyellow' => '250,250,210', + 'lightgray' => '211,211,211', + 'lightgreen' => '144,238,144', + 'lightgrey' => '211,211,211', + 'lightpink' => '255,182,193', + 'lightsalmon' => '255,160,122', + 'lightseagreen' => '32,178,170', + 'lightskyblue' => '135,206,250', + 'lightslategray' => '119,136,153', + 'lightslategrey' => '119,136,153', + 'lightsteelblue' => '176,196,222', + 'lightyellow' => '255,255,224', + 'lime' => '0,255,0', + 'limegreen' => '50,205,50', + 'linen' => '250,240,230', + 'magenta' => '255,0,255', + 'maroon' => '128,0,0', + 'mediumaquamarine' => '102,205,170', + 'mediumblue' => '0,0,205', + 'mediumorchid' => '186,85,211', + 'mediumpurple' => '147,112,219', + 'mediumseagreen' => '60,179,113', + 'mediumslateblue' => '123,104,238', + 'mediumspringgreen' => '0,250,154', + 'mediumturquoise' => '72,209,204', + 'mediumvioletred' => '199,21,133', + 'midnightblue' => '25,25,112', + 'mintcream' => '245,255,250', + 'mistyrose' => '255,228,225', + 'moccasin' => '255,228,181', + 'navajowhite' => '255,222,173', + 'navy' => '0,0,128', + 'oldlace' => '253,245,230', + 'olive' => '128,128,0', + 'olivedrab' => '107,142,35', + 'orange' => '255,165,0', + 'orangered' => '255,69,0', + 'orchid' => '218,112,214', + 'palegoldenrod' => '238,232,170', + 'palegreen' => '152,251,152', + 'paleturquoise' => '175,238,238', + 'palevioletred' => '219,112,147', + 'papayawhip' => '255,239,213', + 'peachpuff' => '255,218,185', + 'peru' => '205,133,63', + 'pink' => '255,192,203', + 'plum' => '221,160,221', + 'powderblue' => '176,224,230', + 'purple' => '128,0,128', + 'red' => '255,0,0', + 'rosybrown' => '188,143,143', + 'royalblue' => '65,105,225', + 'saddlebrown' => '139,69,19', + 'salmon' => '250,128,114', + 'sandybrown' => '244,164,96', + 'seagreen' => '46,139,87', + 'seashell' => '255,245,238', + 'sienna' => '160,82,45', + 'silver' => '192,192,192', + 'skyblue' => '135,206,235', + 'slateblue' => '106,90,205', + 'slategray' => '112,128,144', + 'slategrey' => '112,128,144', + 'snow' => '255,250,250', + 'springgreen' => '0,255,127', + 'steelblue' => '70,130,180', + 'tan' => '210,180,140', + 'teal' => '0,128,128', + 'thistle' => '216,191,216', + 'tomato' => '255,99,71', + 'transparent' => '0,0,0,0', + 'turquoise' => '64,224,208', + 'violet' => '238,130,238', + 'wheat' => '245,222,179', + 'white' => '255,255,255', + 'whitesmoke' => '245,245,245', + 'yellow' => '255,255,0', + 'yellowgreen' => '154,205,50' + ); +} + +// responsible for taking a string of LESS code and converting it into a +// syntax tree +class lessc_parser { + static protected $nextBlockId = 0; // used to uniquely identify blocks + + static protected $precedence = array( + '=<' => 0, + '>=' => 0, + '=' => 0, + '<' => 0, + '>' => 0, + + '+' => 1, + '-' => 1, + '*' => 2, + '/' => 2, + '%' => 2, + ); + + static protected $whitePattern; + static protected $commentMulti; + + static protected $commentSingle = "//"; + static protected $commentMultiLeft = "/*"; + static protected $commentMultiRight = "*/"; + + // regex string to match any of the operators + static protected $operatorString; + + // these properties will supress division unless it's inside parenthases + static protected $supressDivisionProps = + array('/border-radius$/i', '/^font$/i'); + + protected $blockDirectives = array("font-face", "keyframes", "page", "-moz-document", "viewport", "-moz-viewport", "-o-viewport", "-ms-viewport"); + protected $lineDirectives = array("charset"); + + /** + * if we are in parens we can be more liberal with whitespace around + * operators because it must evaluate to a single value and thus is less + * ambiguous. + * + * Consider: + * property1: 10 -5; // is two numbers, 10 and -5 + * property2: (10 -5); // should evaluate to 5 + */ + protected $inParens = false; + + // caches preg escaped literals + static protected $literalCache = array(); + + public function __construct($lessc, $sourceName = null) { + $this->eatWhiteDefault = true; + // reference to less needed for vPrefix, mPrefix, and parentSelector + $this->lessc = $lessc; + + $this->sourceName = $sourceName; // name used for error messages + + $this->writeComments = false; + + if (!self::$operatorString) { + self::$operatorString = + '('.implode('|', array_map(array('lessc', 'preg_quote'), + array_keys(self::$precedence))).')'; + + $commentSingle = lessc::preg_quote(self::$commentSingle); + $commentMultiLeft = lessc::preg_quote(self::$commentMultiLeft); + $commentMultiRight = lessc::preg_quote(self::$commentMultiRight); + + self::$commentMulti = $commentMultiLeft.'.*?'.$commentMultiRight; + self::$whitePattern = '/'.$commentSingle.'[^\n]*\s*|('.self::$commentMulti.')\s*|\s+/Ais'; + } + } + + public function parse($buffer) { + $this->count = 0; + $this->line = 1; + + $this->env = null; // block stack + $this->buffer = $this->writeComments ? $buffer : $this->removeComments($buffer); + $this->pushSpecialBlock("root"); + $this->eatWhiteDefault = true; + $this->seenComments = array(); + + // trim whitespace on head + // if (preg_match('/^\s+/', $this->buffer, $m)) { + // $this->line += substr_count($m[0], "\n"); + // $this->buffer = ltrim($this->buffer); + // } + $this->whitespace(); + + // parse the entire file + $lastCount = $this->count; + while (false !== $this->parseChunk()); + + if ($this->count != strlen($this->buffer)) + $this->throwError(); + + // TODO report where the block was opened + if (!is_null($this->env->parent)) + throw new exception('parse error: unclosed block'); + + return $this->env; + } + + /** + * Parse a single chunk off the head of the buffer and append it to the + * current parse environment. + * Returns false when the buffer is empty, or when there is an error. + * + * This function is called repeatedly until the entire document is + * parsed. + * + * This parser is most similar to a recursive descent parser. Single + * functions represent discrete grammatical rules for the language, and + * they are able to capture the text that represents those rules. + * + * Consider the function lessc::keyword(). (all parse functions are + * structured the same) + * + * The function takes a single reference argument. When calling the + * function it will attempt to match a keyword on the head of the buffer. + * If it is successful, it will place the keyword in the referenced + * argument, advance the position in the buffer, and return true. If it + * fails then it won't advance the buffer and it will return false. + * + * All of these parse functions are powered by lessc::match(), which behaves + * the same way, but takes a literal regular expression. Sometimes it is + * more convenient to use match instead of creating a new function. + * + * Because of the format of the functions, to parse an entire string of + * grammatical rules, you can chain them together using &&. + * + * But, if some of the rules in the chain succeed before one fails, then + * the buffer position will be left at an invalid state. In order to + * avoid this, lessc::seek() is used to remember and set buffer positions. + * + * Before parsing a chain, use $s = $this->seek() to remember the current + * position into $s. Then if a chain fails, use $this->seek($s) to + * go back where we started. + */ + protected function parseChunk() { + if (empty($this->buffer)) return false; + $s = $this->seek(); + + // setting a property + if ($this->keyword($key) && $this->assign() && + $this->propertyValue($value, $key) && $this->end()) + { + $this->append(array('assign', $key, $value), $s); + return true; + } else { + $this->seek($s); + } + + + // look for special css blocks + if ($this->literal('@', false)) { + $this->count--; + + // media + if ($this->literal('@media')) { + if (($this->mediaQueryList($mediaQueries) || true) + && $this->literal('{')) + { + $media = $this->pushSpecialBlock("media"); + $media->queries = is_null($mediaQueries) ? array() : $mediaQueries; + return true; + } else { + $this->seek($s); + return false; + } + } + + if ($this->literal("@", false) && $this->keyword($dirName)) { + if ($this->isDirective($dirName, $this->blockDirectives)) { + if (($this->openString("{", $dirValue, null, array(";")) || true) && + $this->literal("{")) + { + $dir = $this->pushSpecialBlock("directive"); + $dir->name = $dirName; + if (isset($dirValue)) $dir->value = $dirValue; + return true; + } + } elseif ($this->isDirective($dirName, $this->lineDirectives)) { + if ($this->propertyValue($dirValue) && $this->end()) { + $this->append(array("directive", $dirName, $dirValue)); + return true; + } + } + } + + $this->seek($s); + } + + // setting a variable + if ($this->variable($var) && $this->assign() && + $this->propertyValue($value) && $this->end()) + { + $this->append(array('assign', $var, $value), $s); + return true; + } else { + $this->seek($s); + } + + if ($this->import($importValue)) { + $this->append($importValue, $s); + return true; + } + + // opening parametric mixin + if ($this->tag($tag, true) && $this->argumentDef($args, $isVararg) && + ($this->guards($guards) || true) && + $this->literal('{')) + { + $block = $this->pushBlock($this->fixTags(array($tag))); + $block->args = $args; + $block->isVararg = $isVararg; + if (!empty($guards)) $block->guards = $guards; + return true; + } else { + $this->seek($s); + } + + // opening a simple block + if ($this->tags($tags) && $this->literal('{')) { + $tags = $this->fixTags($tags); + $this->pushBlock($tags); + return true; + } else { + $this->seek($s); + } + + // closing a block + if ($this->literal('}', false)) { + try { + $block = $this->pop(); + } catch (exception $e) { + $this->seek($s); + $this->throwError($e->getMessage()); + } + + $hidden = false; + if (is_null($block->type)) { + $hidden = true; + if (!isset($block->args)) { + foreach ($block->tags as $tag) { + if (!is_string($tag) || $tag{0} != $this->lessc->mPrefix) { + $hidden = false; + break; + } + } + } + + foreach ($block->tags as $tag) { + if (is_string($tag)) { + $this->env->children[$tag][] = $block; + } + } + } + + if (!$hidden) { + $this->append(array('block', $block), $s); + } + + // this is done here so comments aren't bundled into he block that + // was just closed + $this->whitespace(); + return true; + } + + // mixin + if ($this->mixinTags($tags) && + ($this->argumentValues($argv) || true) && + ($this->keyword($suffix) || true) && $this->end()) + { + $tags = $this->fixTags($tags); + $this->append(array('mixin', $tags, $argv, $suffix), $s); + return true; + } else { + $this->seek($s); + } + + // spare ; + if ($this->literal(';')) return true; + + return false; // got nothing, throw error + } + + protected function isDirective($dirname, $directives) { + // TODO: cache pattern in parser + $pattern = implode("|", + array_map(array("lessc", "preg_quote"), $directives)); + $pattern = '/^(-[a-z-]+-)?(' . $pattern . ')$/i'; + + return preg_match($pattern, $dirname); + } + + protected function fixTags($tags) { + // move @ tags out of variable namespace + foreach ($tags as &$tag) { + if ($tag{0} == $this->lessc->vPrefix) + $tag[0] = $this->lessc->mPrefix; + } + return $tags; + } + + // a list of expressions + protected function expressionList(&$exps) { + $values = array(); + + while ($this->expression($exp)) { + $values[] = $exp; + } + + if (count($values) == 0) return false; + + $exps = lessc::compressList($values, ' '); + return true; + } + + /** + * Attempt to consume an expression. + * @link http://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudo-code + */ + protected function expression(&$out) { + if ($this->value($lhs)) { + $out = $this->expHelper($lhs, 0); + + // look for / shorthand + if (!empty($this->env->supressedDivision)) { + unset($this->env->supressedDivision); + $s = $this->seek(); + if ($this->literal("/") && $this->value($rhs)) { + $out = array("list", "", + array($out, array("keyword", "/"), $rhs)); + } else { + $this->seek($s); + } + } + + return true; + } + return false; + } + + /** + * recursively parse infix equation with $lhs at precedence $minP + */ + protected function expHelper($lhs, $minP) { + $this->inExp = true; + $ss = $this->seek(); + + while (true) { + $whiteBefore = isset($this->buffer[$this->count - 1]) && + ctype_space($this->buffer[$this->count - 1]); + + // If there is whitespace before the operator, then we require + // whitespace after the operator for it to be an expression + $needWhite = $whiteBefore && !$this->inParens; + + if ($this->match(self::$operatorString.($needWhite ? '\s' : ''), $m) && self::$precedence[$m[1]] >= $minP) { + if (!$this->inParens && isset($this->env->currentProperty) && $m[1] == "/" && empty($this->env->supressedDivision)) { + foreach (self::$supressDivisionProps as $pattern) { + if (preg_match($pattern, $this->env->currentProperty)) { + $this->env->supressedDivision = true; + break 2; + } + } + } + + + $whiteAfter = isset($this->buffer[$this->count - 1]) && + ctype_space($this->buffer[$this->count - 1]); + + if (!$this->value($rhs)) break; + + // peek for next operator to see what to do with rhs + if ($this->peek(self::$operatorString, $next) && self::$precedence[$next[1]] > self::$precedence[$m[1]]) { + $rhs = $this->expHelper($rhs, self::$precedence[$next[1]]); + } + + $lhs = array('expression', $m[1], $lhs, $rhs, $whiteBefore, $whiteAfter); + $ss = $this->seek(); + + continue; + } + + break; + } + + $this->seek($ss); + + return $lhs; + } + + // consume a list of values for a property + public function propertyValue(&$value, $keyName = null) { + $values = array(); + + if ($keyName !== null) $this->env->currentProperty = $keyName; + + $s = null; + while ($this->expressionList($v)) { + $values[] = $v; + $s = $this->seek(); + if (!$this->literal(',')) break; + } + + if ($s) $this->seek($s); + + if ($keyName !== null) unset($this->env->currentProperty); + + if (count($values) == 0) return false; + + $value = lessc::compressList($values, ', '); + return true; + } + + protected function parenValue(&$out) { + $s = $this->seek(); + + // speed shortcut + if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "(") { + return false; + } + + $inParens = $this->inParens; + if ($this->literal("(") && + ($this->inParens = true) && $this->expression($exp) && + $this->literal(")")) + { + $out = $exp; + $this->inParens = $inParens; + return true; + } else { + $this->inParens = $inParens; + $this->seek($s); + } + + return false; + } + + // a single value + protected function value(&$value) { + $s = $this->seek(); + + // speed shortcut + if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "-") { + // negation + if ($this->literal("-", false) && + (($this->variable($inner) && $inner = array("variable", $inner)) || + $this->unit($inner) || + $this->parenValue($inner))) + { + $value = array("unary", "-", $inner); + return true; + } else { + $this->seek($s); + } + } + + if ($this->parenValue($value)) return true; + if ($this->unit($value)) return true; + if ($this->color($value)) return true; + if ($this->func($value)) return true; + if ($this->string($value)) return true; + + if ($this->keyword($word)) { + $value = array('keyword', $word); + return true; + } + + // try a variable + if ($this->variable($var)) { + $value = array('variable', $var); + return true; + } + + // unquote string (should this work on any type? + if ($this->literal("~") && $this->string($str)) { + $value = array("escape", $str); + return true; + } else { + $this->seek($s); + } + + // css hack: \0 + if ($this->literal('\\') && $this->match('([0-9]+)', $m)) { + $value = array('keyword', '\\'.$m[1]); + return true; + } else { + $this->seek($s); + } + + return false; + } + + // an import statement + protected function import(&$out) { + $s = $this->seek(); + if (!$this->literal('@import')) return false; + + // @import "something.css" media; + // @import url("something.css") media; + // @import url(something.css) media; + + if ($this->propertyValue($value)) { + $out = array("import", $value); + return true; + } + } + + protected function mediaQueryList(&$out) { + if ($this->genericList($list, "mediaQuery", ",", false)) { + $out = $list[2]; + return true; + } + return false; + } + + protected function mediaQuery(&$out) { + $s = $this->seek(); + + $expressions = null; + $parts = array(); + + if (($this->literal("only") && ($only = true) || $this->literal("not") && ($not = true) || true) && $this->keyword($mediaType)) { + $prop = array("mediaType"); + if (isset($only)) $prop[] = "only"; + if (isset($not)) $prop[] = "not"; + $prop[] = $mediaType; + $parts[] = $prop; + } else { + $this->seek($s); + } + + + if (!empty($mediaType) && !$this->literal("and")) { + // ~ + } else { + $this->genericList($expressions, "mediaExpression", "and", false); + if (is_array($expressions)) $parts = array_merge($parts, $expressions[2]); + } + + if (count($parts) == 0) { + $this->seek($s); + return false; + } + + $out = $parts; + return true; + } + + protected function mediaExpression(&$out) { + $s = $this->seek(); + $value = null; + if ($this->literal("(") && + $this->keyword($feature) && + ($this->literal(":") && $this->expression($value) || true) && + $this->literal(")")) + { + $out = array("mediaExp", $feature); + if ($value) $out[] = $value; + return true; + } elseif ($this->variable($variable)) { + $out = array('variable', $variable); + return true; + } + + $this->seek($s); + return false; + } + + // an unbounded string stopped by $end + protected function openString($end, &$out, $nestingOpen=null, $rejectStrs = null) { + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = false; + + $stop = array("'", '"', "@{", $end); + $stop = array_map(array("lessc", "preg_quote"), $stop); + // $stop[] = self::$commentMulti; + + if (!is_null($rejectStrs)) { + $stop = array_merge($stop, $rejectStrs); + } + + $patt = '(.*?)('.implode("|", $stop).')'; + + $nestingLevel = 0; + + $content = array(); + while ($this->match($patt, $m, false)) { + if (!empty($m[1])) { + $content[] = $m[1]; + if ($nestingOpen) { + $nestingLevel += substr_count($m[1], $nestingOpen); + } + } + + $tok = $m[2]; + + $this->count-= strlen($tok); + if ($tok == $end) { + if ($nestingLevel == 0) { + break; + } else { + $nestingLevel--; + } + } + + if (($tok == "'" || $tok == '"') && $this->string($str)) { + $content[] = $str; + continue; + } + + if ($tok == "@{" && $this->interpolation($inter)) { + $content[] = $inter; + continue; + } + + if (!empty($rejectStrs) && in_array($tok, $rejectStrs)) { + break; + } + + $content[] = $tok; + $this->count+= strlen($tok); + } + + $this->eatWhiteDefault = $oldWhite; + + if (count($content) == 0) return false; + + // trim the end + if (is_string(end($content))) { + $content[count($content) - 1] = rtrim(end($content)); + } + + $out = array("string", "", $content); + return true; + } + + protected function string(&$out) { + $s = $this->seek(); + if ($this->literal('"', false)) { + $delim = '"'; + } elseif ($this->literal("'", false)) { + $delim = "'"; + } else { + return false; + } + + $content = array(); + + // look for either ending delim , escape, or string interpolation + $patt = '([^\n]*?)(@\{|\\\\|' . + lessc::preg_quote($delim).')'; + + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = false; + + while ($this->match($patt, $m, false)) { + $content[] = $m[1]; + if ($m[2] == "@{") { + $this->count -= strlen($m[2]); + if ($this->interpolation($inter, false)) { + $content[] = $inter; + } else { + $this->count += strlen($m[2]); + $content[] = "@{"; // ignore it + } + } elseif ($m[2] == '\\') { + $content[] = $m[2]; + if ($this->literal($delim, false)) { + $content[] = $delim; + } + } else { + $this->count -= strlen($delim); + break; // delim + } + } + + $this->eatWhiteDefault = $oldWhite; + + if ($this->literal($delim)) { + $out = array("string", $delim, $content); + return true; + } + + $this->seek($s); + return false; + } + + protected function interpolation(&$out) { + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = true; + + $s = $this->seek(); + if ($this->literal("@{") && + $this->openString("}", $interp, null, array("'", '"', ";")) && + $this->literal("}", false)) + { + $out = array("interpolate", $interp); + $this->eatWhiteDefault = $oldWhite; + if ($this->eatWhiteDefault) $this->whitespace(); + return true; + } + + $this->eatWhiteDefault = $oldWhite; + $this->seek($s); + return false; + } + + protected function unit(&$unit) { + // speed shortcut + if (isset($this->buffer[$this->count])) { + $char = $this->buffer[$this->count]; + if (!ctype_digit($char) && $char != ".") return false; + } + + if ($this->match('([0-9]+(?:\.[0-9]*)?|\.[0-9]+)([%a-zA-Z]+)?', $m)) { + $unit = array("number", $m[1], empty($m[2]) ? "" : $m[2]); + return true; + } + return false; + } + + // a # color + protected function color(&$out) { + if ($this->match('(#(?:[0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3}))', $m)) { + if (strlen($m[1]) > 7) { + $out = array("string", "", array($m[1])); + } else { + $out = array("raw_color", $m[1]); + } + return true; + } + + return false; + } + + // consume a list of property values delimited by ; and wrapped in () + protected function argumentValues(&$args, $delim = ',') { + $s = $this->seek(); + if (!$this->literal('(')) return false; + + $values = array(); + while (true) { + if ($this->expressionList($value)) $values[] = $value; + if (!$this->literal($delim)) break; + else { + if ($value == null) $values[] = null; + $value = null; + } + } + + if (!$this->literal(')')) { + $this->seek($s); + return false; + } + + $args = $values; + return true; + } + + // consume an argument definition list surrounded by () + // each argument is a variable name with optional value + // or at the end a ... or a variable named followed by ... + protected function argumentDef(&$args, &$isVararg, $delim = ',') { + $s = $this->seek(); + if (!$this->literal('(')) return false; + + $values = array(); + + $isVararg = false; + while (true) { + if ($this->literal("...")) { + $isVararg = true; + break; + } + + if ($this->variable($vname)) { + $arg = array("arg", $vname); + $ss = $this->seek(); + if ($this->assign() && $this->expressionList($value)) { + $arg[] = $value; + } else { + $this->seek($ss); + if ($this->literal("...")) { + $arg[0] = "rest"; + $isVararg = true; + } + } + $values[] = $arg; + if ($isVararg) break; + continue; + } + + if ($this->value($literal)) { + $values[] = array("lit", $literal); + } + + if (!$this->literal($delim)) break; + } + + if (!$this->literal(')')) { + $this->seek($s); + return false; + } + + $args = $values; + + return true; + } + + // consume a list of tags + // this accepts a hanging delimiter + protected function tags(&$tags, $simple = false, $delim = ',') { + $tags = array(); + while ($this->tag($tt, $simple)) { + $tags[] = $tt; + if (!$this->literal($delim)) break; + } + if (count($tags) == 0) return false; + + return true; + } + + // list of tags of specifying mixin path + // optionally separated by > (lazy, accepts extra >) + protected function mixinTags(&$tags) { + $s = $this->seek(); + $tags = array(); + while ($this->tag($tt, true)) { + $tags[] = $tt; + $this->literal(">"); + } + + if (count($tags) == 0) return false; + + return true; + } + + // a bracketed value (contained within in a tag definition) + protected function tagBracket(&$value) { + // speed shortcut + if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "[") { + return false; + } + + $s = $this->seek(); + if ($this->literal('[') && $this->to(']', $c, true) && $this->literal(']', false)) { + $value = '['.$c.']'; + // whitespace? + if ($this->whitespace()) $value .= " "; + + // escape parent selector, (yuck) + $value = str_replace($this->lessc->parentSelector, "$&$", $value); + return true; + } + + $this->seek($s); + return false; + } + + protected function tagExpression(&$value) { + $s = $this->seek(); + if ($this->literal("(") && $this->expression($exp) && $this->literal(")")) { + $value = array('exp', $exp); + return true; + } + + $this->seek($s); + return false; + } + + // a space separated list of selectors + protected function tag(&$tag, $simple = false) { + if ($simple) + $chars = '^@,:;{}\][>\(\) "\''; + else + $chars = '^@,;{}["\''; + + $s = $this->seek(); + + if (!$simple && $this->tagExpression($tag)) { + return true; + } + + $hasExpression = false; + $parts = array(); + while ($this->tagBracket($first)) $parts[] = $first; + + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = false; + + while (true) { + if ($this->match('(['.$chars.'0-9]['.$chars.']*)', $m)) { + $parts[] = $m[1]; + if ($simple) break; + + while ($this->tagBracket($brack)) { + $parts[] = $brack; + } + continue; + } + + if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "@") { + if ($this->interpolation($interp)) { + $hasExpression = true; + $interp[2] = true; // don't unescape + $parts[] = $interp; + continue; + } + + if ($this->literal("@")) { + $parts[] = "@"; + continue; + } + } + + if ($this->unit($unit)) { // for keyframes + $parts[] = $unit[1]; + $parts[] = $unit[2]; + continue; + } + + break; + } + + $this->eatWhiteDefault = $oldWhite; + if (!$parts) { + $this->seek($s); + return false; + } + + if ($hasExpression) { + $tag = array("exp", array("string", "", $parts)); + } else { + $tag = trim(implode($parts)); + } + + $this->whitespace(); + return true; + } + + // a css function + protected function func(&$func) { + $s = $this->seek(); + + if ($this->match('(%|[\w\-_][\w\-_:\.]+|[\w_])', $m) && $this->literal('(')) { + $fname = $m[1]; + + $sPreArgs = $this->seek(); + + $args = array(); + while (true) { + $ss = $this->seek(); + // this ugly nonsense is for ie filter properties + if ($this->keyword($name) && $this->literal('=') && $this->expressionList($value)) { + $args[] = array("string", "", array($name, "=", $value)); + } else { + $this->seek($ss); + if ($this->expressionList($value)) { + $args[] = $value; + } + } + + if (!$this->literal(',')) break; + } + $args = array('list', ',', $args); + + if ($this->literal(')')) { + $func = array('function', $fname, $args); + return true; + } elseif ($fname == 'url') { + // couldn't parse and in url? treat as string + $this->seek($sPreArgs); + if ($this->openString(")", $string) && $this->literal(")")) { + $func = array('function', $fname, $string); + return true; + } + } + } + + $this->seek($s); + return false; + } + + // consume a less variable + protected function variable(&$name) { + $s = $this->seek(); + if ($this->literal($this->lessc->vPrefix, false) && + ($this->variable($sub) || $this->keyword($name))) + { + if (!empty($sub)) { + $name = array('variable', $sub); + } else { + $name = $this->lessc->vPrefix.$name; + } + return true; + } + + $name = null; + $this->seek($s); + return false; + } + + /** + * Consume an assignment operator + * Can optionally take a name that will be set to the current property name + */ + protected function assign($name = null) { + if ($name) $this->currentProperty = $name; + return $this->literal(':') || $this->literal('='); + } + + // consume a keyword + protected function keyword(&$word) { + if ($this->match('([\w_\-\*!"][\w\-_"]*)', $m)) { + $word = $m[1]; + return true; + } + return false; + } + + // consume an end of statement delimiter + protected function end() { + if ($this->literal(';')) { + return true; + } elseif ($this->count == strlen($this->buffer) || $this->buffer[$this->count] == '}') { + // if there is end of file or a closing block next then we don't need a ; + return true; + } + return false; + } + + protected function guards(&$guards) { + $s = $this->seek(); + + if (!$this->literal("when")) { + $this->seek($s); + return false; + } + + $guards = array(); + + while ($this->guardGroup($g)) { + $guards[] = $g; + if (!$this->literal(",")) break; + } + + if (count($guards) == 0) { + $guards = null; + $this->seek($s); + return false; + } + + return true; + } + + // a bunch of guards that are and'd together + // TODO rename to guardGroup + protected function guardGroup(&$guardGroup) { + $s = $this->seek(); + $guardGroup = array(); + while ($this->guard($guard)) { + $guardGroup[] = $guard; + if (!$this->literal("and")) break; + } + + if (count($guardGroup) == 0) { + $guardGroup = null; + $this->seek($s); + return false; + } + + return true; + } + + protected function guard(&$guard) { + $s = $this->seek(); + $negate = $this->literal("not"); + + if ($this->literal("(") && $this->expression($exp) && $this->literal(")")) { + $guard = $exp; + if ($negate) $guard = array("negate", $guard); + return true; + } + + $this->seek($s); + return false; + } + + /* raw parsing functions */ + + protected function literal($what, $eatWhitespace = null) { + if ($eatWhitespace === null) $eatWhitespace = $this->eatWhiteDefault; + + // shortcut on single letter + if (!isset($what[1]) && isset($this->buffer[$this->count])) { + if ($this->buffer[$this->count] == $what) { + if (!$eatWhitespace) { + $this->count++; + return true; + } + // goes below... + } else { + return false; + } + } + + if (!isset(self::$literalCache[$what])) { + self::$literalCache[$what] = lessc::preg_quote($what); + } + + return $this->match(self::$literalCache[$what], $m, $eatWhitespace); + } + + protected function genericList(&$out, $parseItem, $delim="", $flatten=true) { + $s = $this->seek(); + $items = array(); + while ($this->$parseItem($value)) { + $items[] = $value; + if ($delim) { + if (!$this->literal($delim)) break; + } + } + + if (count($items) == 0) { + $this->seek($s); + return false; + } + + if ($flatten && count($items) == 1) { + $out = $items[0]; + } else { + $out = array("list", $delim, $items); + } + + return true; + } + + + // advance counter to next occurrence of $what + // $until - don't include $what in advance + // $allowNewline, if string, will be used as valid char set + protected function to($what, &$out, $until = false, $allowNewline = false) { + if (is_string($allowNewline)) { + $validChars = $allowNewline; + } else { + $validChars = $allowNewline ? "." : "[^\n]"; + } + if (!$this->match('('.$validChars.'*?)'.lessc::preg_quote($what), $m, !$until)) return false; + if ($until) $this->count -= strlen($what); // give back $what + $out = $m[1]; + return true; + } + + // try to match something on head of buffer + protected function match($regex, &$out, $eatWhitespace = null) { + if ($eatWhitespace === null) $eatWhitespace = $this->eatWhiteDefault; + + $r = '/'.$regex.($eatWhitespace && !$this->writeComments ? '\s*' : '').'/Ais'; + if (preg_match($r, $this->buffer, $out, null, $this->count)) { + $this->count += strlen($out[0]); + if ($eatWhitespace && $this->writeComments) $this->whitespace(); + return true; + } + return false; + } + + // match some whitespace + protected function whitespace() { + if ($this->writeComments) { + $gotWhite = false; + while (preg_match(self::$whitePattern, $this->buffer, $m, null, $this->count)) { + if (isset($m[1]) && empty($this->commentsSeen[$this->count])) { + $this->append(array("comment", $m[1])); + $this->commentsSeen[$this->count] = true; + } + $this->count += strlen($m[0]); + $gotWhite = true; + } + return $gotWhite; + } else { + $this->match("", $m); + return strlen($m[0]) > 0; + } + } + + // match something without consuming it + protected function peek($regex, &$out = null, $from=null) { + if (is_null($from)) $from = $this->count; + $r = '/'.$regex.'/Ais'; + $result = preg_match($r, $this->buffer, $out, null, $from); + + return $result; + } + + // seek to a spot in the buffer or return where we are on no argument + protected function seek($where = null) { + if ($where === null) return $this->count; + else $this->count = $where; + return true; + } + + /* misc functions */ + + public function throwError($msg = "parse error", $count = null) { + $count = is_null($count) ? $this->count : $count; + + $line = $this->line + + substr_count(substr($this->buffer, 0, $count), "\n"); + + if (!empty($this->sourceName)) { + $loc = "$this->sourceName on line $line"; + } else { + $loc = "line: $line"; + } + + // TODO this depends on $this->count + if ($this->peek("(.*?)(\n|$)", $m, $count)) { + throw new exception("$msg: failed at `$m[1]` $loc"); + } else { + throw new exception("$msg: $loc"); + } + } + + protected function pushBlock($selectors=null, $type=null) { + $b = new stdclass; + $b->parent = $this->env; + + $b->type = $type; + $b->id = self::$nextBlockId++; + + $b->isVararg = false; // TODO: kill me from here + $b->tags = $selectors; + + $b->props = array(); + $b->children = array(); + + $this->env = $b; + return $b; + } + + // push a block that doesn't multiply tags + protected function pushSpecialBlock($type) { + return $this->pushBlock(null, $type); + } + + // append a property to the current block + protected function append($prop, $pos = null) { + if ($pos !== null) $prop[-1] = $pos; + $this->env->props[] = $prop; + } + + // pop something off the stack + protected function pop() { + $old = $this->env; + $this->env = $this->env->parent; + return $old; + } + + // remove comments from $text + // todo: make it work for all functions, not just url + protected function removeComments($text) { + $look = array( + 'url(', '//', '/*', '"', "'" + ); + + $out = ''; + $min = null; + while (true) { + // find the next item + foreach ($look as $token) { + $pos = strpos($text, $token); + if ($pos !== false) { + if (!isset($min) || $pos < $min[1]) $min = array($token, $pos); + } + } + + if (is_null($min)) break; + + $count = $min[1]; + $skip = 0; + $newlines = 0; + switch ($min[0]) { + case 'url(': + if (preg_match('/url\(.*?\)/', $text, $m, 0, $count)) + $count += strlen($m[0]) - strlen($min[0]); + break; + case '"': + case "'": + if (preg_match('/'.$min[0].'.*?'.$min[0].'/', $text, $m, 0, $count)) + $count += strlen($m[0]) - 1; + break; + case '//': + $skip = strpos($text, "\n", $count); + if ($skip === false) $skip = strlen($text) - $count; + else $skip -= $count; + break; + case '/*': + if (preg_match('/\/\*.*?\*\//s', $text, $m, 0, $count)) { + $skip = strlen($m[0]); + $newlines = substr_count($m[0], "\n"); + } + break; + } + + if ($skip == 0) $count += strlen($min[0]); + + $out .= substr($text, 0, $count).str_repeat("\n", $newlines); + $text = substr($text, $count + $skip); + + $min = null; + } + + return $out.$text; + } + +} + +class lessc_formatter_classic { + public $indentChar = " "; + + public $break = "\n"; + public $open = " {"; + public $close = "}"; + public $selectorSeparator = ", "; + public $assignSeparator = ":"; + + public $openSingle = " { "; + public $closeSingle = " }"; + + public $disableSingle = false; + public $breakSelectors = false; + + public $compressColors = false; + + public function __construct() { + $this->indentLevel = 0; + } + + public function indentStr($n = 0) { + return str_repeat($this->indentChar, max($this->indentLevel + $n, 0)); + } + + public function property($name, $value) { + return $name . $this->assignSeparator . $value . ";"; + } + + protected function isEmpty($block) { + if (empty($block->lines)) { + foreach ($block->children as $child) { + if (!$this->isEmpty($child)) return false; + } + + return true; + } + return false; + } + + public function block($block) { + if ($this->isEmpty($block)) return; + + $inner = $pre = $this->indentStr(); + + $isSingle = !$this->disableSingle && + is_null($block->type) && count($block->lines) == 1; + + if (!empty($block->selectors)) { + $this->indentLevel++; + + if ($this->breakSelectors) { + $selectorSeparator = $this->selectorSeparator . $this->break . $pre; + } else { + $selectorSeparator = $this->selectorSeparator; + } + + echo $pre . + implode($selectorSeparator, $block->selectors); + if ($isSingle) { + echo $this->openSingle; + $inner = ""; + } else { + echo $this->open . $this->break; + $inner = $this->indentStr(); + } + + } + + if (!empty($block->lines)) { + $glue = $this->break.$inner; + echo $inner . implode($glue, $block->lines); + if (!$isSingle && !empty($block->children)) { + echo $this->break; + } + } + + foreach ($block->children as $child) { + $this->block($child); + } + + if (!empty($block->selectors)) { + if (!$isSingle && empty($block->children)) echo $this->break; + + if ($isSingle) { + echo $this->closeSingle . $this->break; + } else { + echo $pre . $this->close . $this->break; + } + + $this->indentLevel--; + } + } +} + +class lessc_formatter_compressed extends lessc_formatter_classic { + public $disableSingle = true; + public $open = "{"; + public $selectorSeparator = ","; + public $assignSeparator = ":"; + public $break = ""; + public $compressColors = true; + + public function indentStr($n = 0) { + return ""; + } +} + +class lessc_formatter_lessjs extends lessc_formatter_classic { + public $disableSingle = true; + public $breakSelectors = true; + public $assignSeparator = ": "; + public $selectorSeparator = ","; +} + + -- cgit v1.2.3 From c51b334ee77310dc0055311092f224be0342cd65 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Tue, 30 Jul 2013 12:07:15 +0200 Subject: fixed ini replacement to less variables stuff --- lib/exe/css.php | 6 +- lib/tpl/dokuwiki/css/design.css | 405 --------------------------------------- lib/tpl/dokuwiki/css/design.less | 405 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 409 insertions(+), 407 deletions(-) delete mode 100644 lib/tpl/dokuwiki/css/design.css create mode 100644 lib/tpl/dokuwiki/css/design.less diff --git a/lib/exe/css.php b/lib/exe/css.php index 4a9c825c1..04516e8ba 100644 --- a/lib/exe/css.php +++ b/lib/exe/css.php @@ -191,11 +191,13 @@ function css_applystyle($css,$tplinc){ $css = strtr($css,$styleini['replacements']); $less = ''; - foreach($styleini as $key => $value){ + foreach($styleini['replacements'] as $key => $value){ $key = trim($key, '_'); $key = '@ini_'.$key; - $less .= "$key: $value\n"; + $less .= "$key: $value;\n"; } + + $css = $less.$css; } return $css; } diff --git a/lib/tpl/dokuwiki/css/design.css b/lib/tpl/dokuwiki/css/design.css deleted file mode 100644 index 457414839..000000000 --- a/lib/tpl/dokuwiki/css/design.css +++ /dev/null @@ -1,405 +0,0 @@ -/** - * This file provides the main design styles for the - * bits that surround the content. - * - * @author Anika Henke - * @author Andreas Gohr - * @author Clarence Lee - */ - -/* header -********************************************************************/ - -#dokuwiki__header { - padding: 2em 0 1.5em; -} - -#dokuwiki__header .headings, -#dokuwiki__header .tools { - margin-bottom: 1.5em; - width: 49%; -} -#dokuwiki__header h1 img { - float: left; - margin-right: .5em; -} -[dir=rtl] #dokuwiki__header h1 img { - float: right; - margin-left: .5em; - margin-right: 0; -} -#dokuwiki__header h1 span { - display: block; - padding-top: 10px; -} -#dokuwiki__header h1 { - margin: 0; - font-size: 1.5em; - font-weight: normal; -} -#dokuwiki__header h1 a { - text-decoration: none; - color: __text__; - background-color: inherit; -} -#dokuwiki__header h1 a:hover, -#dokuwiki__header h1 a:active, -#dokuwiki__header h1 a:focus { -} -#dokuwiki__header p.claim { - margin-bottom: 0; - font-size: 0.875em; -} - -#dokuwiki__header .tools { - margin-top: .2em; -} - - -/* tools -********************************************************************/ - -/* highlight selected tool */ -.mode_admin a.action.admin, -.mode_login a.action.login, -.mode_register a.action.register, -.mode_profile a.action.profile, -.mode_recent a.action.recent, -.mode_index a.action.index, -.mode_media a.action.media, -.mode_revisions a.action.revs, -.mode_backlink a.action.backlink, -.mode_subscribe a.action.subscribe { - font-weight: bold; -} - -#dokuwiki__header .tools ul { - padding-left: 0; - margin-bottom: 0; -} -#dokuwiki__header .tools li { - font-size: 0.875em; - margin-left: 1em; - list-style: none; - display: inline; -} -[dir=rtl] #dokuwiki__header .tools li { - margin-right: 1em; - margin-left: 0; -} -#dokuwiki__header .tools form.search div.ajax_qsearch li { - font-size: 1em; - margin-left: 0; - display: block; - overflow: hidden; - text-overflow: ellipsis; -} - -#dokuwiki__usertools a.action { - padding-left: 20px; - background: transparent url(images/usertools.png) no-repeat 0 0; -} -[dir=rtl] #dokuwiki__usertools a.action { - padding-left: 0; - padding-right: 20px; -} -[dir=rtl] #IE7 #dokuwiki__usertools a.action { - display: inline-block; -} - - -#dokuwiki__header .mobileTools { - display: none; /* hide mobile tools dropdown to only show in mobile view */ -} - -/*____________ user tools ____________*/ - -#dokuwiki__usertools { - position: absolute; - top: .5em; - right: .5em; - text-align: right; - width: 100%; -} -[dir=rtl] #dokuwiki__usertools { - text-align: left; - left: 40px; - right: auto; -} -#dokuwiki__usertools ul { - margin: 0 auto; - padding: 0; - max-width: __site_width__; -} -#dokuwiki__usertools ul li.user { -} - -#dokuwiki__usertools a.action.admin { - background-position: left 0; -} -[dir=rtl] #dokuwiki__usertools a.action.admin { - background-position: right 0; -} -#dokuwiki__usertools a.action.profile { - background-position: left -32px; -} -[dir=rtl] #dokuwiki__usertools a.action.profile { - background-position: right -32px; -} -#dokuwiki__usertools a.action.register { - background-position: left -64px; -} -[dir=rtl] #dokuwiki__usertools a.action.register { - background-position: right -64px; -} -#dokuwiki__usertools a.action.login { - background-position: left -96px; -} -[dir=rtl] #dokuwiki__usertools a.action.login { - background-position: right -96px; -} -#dokuwiki__usertools a.action.logout { - background-position: left -128px; -} -[dir=rtl] #dokuwiki__usertools a.action.logout { - background-position: right -128px; -} - - -/*____________ site tools ____________*/ - -#dokuwiki__sitetools { - text-align: right; -} -[dir=rtl] #dokuwiki__sitetools { - text-align: left; -} - -#dokuwiki__sitetools form.search { - display: block; - font-size: 0.875em; - position: relative; -} -#IE7 #dokuwiki__sitetools form.search { - min-height: 1px; - z-index: 21; -} -#dokuwiki__sitetools form.search input.edit { - width: 18em; - padding: .35em 22px .35em .1em; -} -[dir=rtl] #dokuwiki__sitetools form.search input.edit { - padding: .35em .1em .35em 22px; -} -#dokuwiki__sitetools form.search input.button { - background: transparent url(images/search.png) no-repeat 0 0; - border-width: 0; - width: 19px; - height: 14px; - text-indent: -99999px; - margin-left: -20px; - box-shadow: none; - padding: 0; -} -[dir=rtl] #dokuwiki__sitetools form.search input.button { - background-position: 5px 0; - margin-left: 0; - margin-right: -20px; - position: relative; -} - -#dokuwiki__sitetools ul { - margin-top: 0.5em; -} -#dokuwiki__sitetools li { -} - -/*____________ breadcrumbs ____________*/ - -.dokuwiki div.breadcrumbs { - border-top: 1px solid __border__; - border-bottom: 1px solid __background__; - margin-bottom: .5em; - font-size: 0.875em; - clear: both; -} -.dokuwiki div.breadcrumbs div { - padding: .1em .35em; -} - -.dokuwiki div.breadcrumbs div:only-child { - border-top: 1px solid __background__; - border-bottom: 1px solid __border__; -} -.dokuwiki div.breadcrumbs div:first-child { - border-top: 1px solid __background__; -} -#IE7 .dokuwiki div.breadcrumbs div, -#IE8 .dokuwiki div.breadcrumbs div { - border-bottom: 1px solid __border__; -} -.dokuwiki div.breadcrumbs div:last-child { - border-bottom: 1px solid __border__; -} - -.dokuwiki div.breadcrumbs a { - color: __link__; - background-color: inherit; -} -.dokuwiki div.breadcrumbs .bcsep { - font-size: 0.75em; -} - - -/* sidebar -********************************************************************/ - -#dokuwiki__aside { -} -#dokuwiki__aside > .pad { - font-size: 0.875em; - overflow: hidden; - word-wrap: break-word; -} - -/* make sidebar more condensed */ - -#dokuwiki__aside h1 { - font-size: 1.714em; - margin-bottom: .292em; -} -#dokuwiki__aside h2 { - margin-bottom: .333em; -} -#dokuwiki__aside h3 { - margin-bottom: .444em; -} -#dokuwiki__aside h4 { - margin-bottom: .5em; -} -#dokuwiki__aside h5 { - margin-bottom: .5714em; -} - -#dokuwiki__aside p, -#dokuwiki__aside ul, -#dokuwiki__aside ol, -#dokuwiki__aside dl, -#dokuwiki__aside pre, -#dokuwiki__aside table, -#dokuwiki__aside fieldset, -#dokuwiki__aside hr, -#dokuwiki__aside blockquote, -#dokuwiki__aside address { - margin-bottom: .7em; -} - -#dokuwiki__aside ul, -#dokuwiki__aside ol { - padding-left: .5em; -} -[dir=rtl] #dokuwiki__aside ul, -[dir=rtl] #dokuwiki__aside ol { - padding-right: .5em; -} -#dokuwiki__aside li ul, -#dokuwiki__aside li ol { - margin-bottom: 0; - padding: 0; -} - -#dokuwiki__aside a:link, -#dokuwiki__aside a:visited { - color: __link__; - background-color: inherit; -} - - -/* content -********************************************************************/ - -#dokuwiki__content { -} - -.dokuwiki .pageId { - position: absolute; - top: -2.3em; - right: -1em; - overflow: hidden; - padding: 1em 1em 0; -} -[dir=rtl] .dokuwiki .pageId { - right: auto; - left: -1em; -} -.dokuwiki .pageId span { - font-size: 0.875em; - border: solid __background_alt__; - border-width: 1px 1px 0; - background-color: __background__; - color: __text_alt__; - padding: .1em .35em; - border-top-left-radius: 2px; - border-top-right-radius: 2px; - box-shadow: 0 0 .5em __text_alt__; - display: block; -} - -.dokuwiki div.page { - background: __background__; - color: inherit; - border: 1px solid __background_alt__; - box-shadow: 0 0 .5em __text_alt__; - border-radius: 2px; - padding: 1.556em 2em 2em; - margin-bottom: .5em; - overflow: hidden; - word-wrap: break-word; -} - -.dokuwiki .docInfo { - font-size: 0.875em; - text-align: right; -} -[dir=rtl] .dokuwiki .docInfo { - text-align: left; -} - -/* license note under edit window */ -.dokuwiki div.license { - font-size: 93.75%; -} - - -/* footer -********************************************************************/ - -.dokuwiki .wrapper { - margin-bottom: 1.4em; -} - -#dokuwiki__footer { - margin-bottom: 1em; - text-align: center; -} -#dokuwiki__footer > .pad { - font-size: 0.875em; -} - -#dokuwiki__footer div.license { - margin-bottom: 0.5em; - font-size: 100%; -} - -[dir=rtl] #dokuwiki__footer .license img { - margin: 0 0 0 .5em; -} - -#dokuwiki__footer div.buttons a img { - opacity: 0.5; -} -#dokuwiki__footer div.buttons a:hover img, -#dokuwiki__footer div.buttons a:active img, -#dokuwiki__footer div.buttons a:focus img { - opacity: 1; -} diff --git a/lib/tpl/dokuwiki/css/design.less b/lib/tpl/dokuwiki/css/design.less new file mode 100644 index 000000000..457414839 --- /dev/null +++ b/lib/tpl/dokuwiki/css/design.less @@ -0,0 +1,405 @@ +/** + * This file provides the main design styles for the + * bits that surround the content. + * + * @author Anika Henke + * @author Andreas Gohr + * @author Clarence Lee + */ + +/* header +********************************************************************/ + +#dokuwiki__header { + padding: 2em 0 1.5em; +} + +#dokuwiki__header .headings, +#dokuwiki__header .tools { + margin-bottom: 1.5em; + width: 49%; +} +#dokuwiki__header h1 img { + float: left; + margin-right: .5em; +} +[dir=rtl] #dokuwiki__header h1 img { + float: right; + margin-left: .5em; + margin-right: 0; +} +#dokuwiki__header h1 span { + display: block; + padding-top: 10px; +} +#dokuwiki__header h1 { + margin: 0; + font-size: 1.5em; + font-weight: normal; +} +#dokuwiki__header h1 a { + text-decoration: none; + color: __text__; + background-color: inherit; +} +#dokuwiki__header h1 a:hover, +#dokuwiki__header h1 a:active, +#dokuwiki__header h1 a:focus { +} +#dokuwiki__header p.claim { + margin-bottom: 0; + font-size: 0.875em; +} + +#dokuwiki__header .tools { + margin-top: .2em; +} + + +/* tools +********************************************************************/ + +/* highlight selected tool */ +.mode_admin a.action.admin, +.mode_login a.action.login, +.mode_register a.action.register, +.mode_profile a.action.profile, +.mode_recent a.action.recent, +.mode_index a.action.index, +.mode_media a.action.media, +.mode_revisions a.action.revs, +.mode_backlink a.action.backlink, +.mode_subscribe a.action.subscribe { + font-weight: bold; +} + +#dokuwiki__header .tools ul { + padding-left: 0; + margin-bottom: 0; +} +#dokuwiki__header .tools li { + font-size: 0.875em; + margin-left: 1em; + list-style: none; + display: inline; +} +[dir=rtl] #dokuwiki__header .tools li { + margin-right: 1em; + margin-left: 0; +} +#dokuwiki__header .tools form.search div.ajax_qsearch li { + font-size: 1em; + margin-left: 0; + display: block; + overflow: hidden; + text-overflow: ellipsis; +} + +#dokuwiki__usertools a.action { + padding-left: 20px; + background: transparent url(images/usertools.png) no-repeat 0 0; +} +[dir=rtl] #dokuwiki__usertools a.action { + padding-left: 0; + padding-right: 20px; +} +[dir=rtl] #IE7 #dokuwiki__usertools a.action { + display: inline-block; +} + + +#dokuwiki__header .mobileTools { + display: none; /* hide mobile tools dropdown to only show in mobile view */ +} + +/*____________ user tools ____________*/ + +#dokuwiki__usertools { + position: absolute; + top: .5em; + right: .5em; + text-align: right; + width: 100%; +} +[dir=rtl] #dokuwiki__usertools { + text-align: left; + left: 40px; + right: auto; +} +#dokuwiki__usertools ul { + margin: 0 auto; + padding: 0; + max-width: __site_width__; +} +#dokuwiki__usertools ul li.user { +} + +#dokuwiki__usertools a.action.admin { + background-position: left 0; +} +[dir=rtl] #dokuwiki__usertools a.action.admin { + background-position: right 0; +} +#dokuwiki__usertools a.action.profile { + background-position: left -32px; +} +[dir=rtl] #dokuwiki__usertools a.action.profile { + background-position: right -32px; +} +#dokuwiki__usertools a.action.register { + background-position: left -64px; +} +[dir=rtl] #dokuwiki__usertools a.action.register { + background-position: right -64px; +} +#dokuwiki__usertools a.action.login { + background-position: left -96px; +} +[dir=rtl] #dokuwiki__usertools a.action.login { + background-position: right -96px; +} +#dokuwiki__usertools a.action.logout { + background-position: left -128px; +} +[dir=rtl] #dokuwiki__usertools a.action.logout { + background-position: right -128px; +} + + +/*____________ site tools ____________*/ + +#dokuwiki__sitetools { + text-align: right; +} +[dir=rtl] #dokuwiki__sitetools { + text-align: left; +} + +#dokuwiki__sitetools form.search { + display: block; + font-size: 0.875em; + position: relative; +} +#IE7 #dokuwiki__sitetools form.search { + min-height: 1px; + z-index: 21; +} +#dokuwiki__sitetools form.search input.edit { + width: 18em; + padding: .35em 22px .35em .1em; +} +[dir=rtl] #dokuwiki__sitetools form.search input.edit { + padding: .35em .1em .35em 22px; +} +#dokuwiki__sitetools form.search input.button { + background: transparent url(images/search.png) no-repeat 0 0; + border-width: 0; + width: 19px; + height: 14px; + text-indent: -99999px; + margin-left: -20px; + box-shadow: none; + padding: 0; +} +[dir=rtl] #dokuwiki__sitetools form.search input.button { + background-position: 5px 0; + margin-left: 0; + margin-right: -20px; + position: relative; +} + +#dokuwiki__sitetools ul { + margin-top: 0.5em; +} +#dokuwiki__sitetools li { +} + +/*____________ breadcrumbs ____________*/ + +.dokuwiki div.breadcrumbs { + border-top: 1px solid __border__; + border-bottom: 1px solid __background__; + margin-bottom: .5em; + font-size: 0.875em; + clear: both; +} +.dokuwiki div.breadcrumbs div { + padding: .1em .35em; +} + +.dokuwiki div.breadcrumbs div:only-child { + border-top: 1px solid __background__; + border-bottom: 1px solid __border__; +} +.dokuwiki div.breadcrumbs div:first-child { + border-top: 1px solid __background__; +} +#IE7 .dokuwiki div.breadcrumbs div, +#IE8 .dokuwiki div.breadcrumbs div { + border-bottom: 1px solid __border__; +} +.dokuwiki div.breadcrumbs div:last-child { + border-bottom: 1px solid __border__; +} + +.dokuwiki div.breadcrumbs a { + color: __link__; + background-color: inherit; +} +.dokuwiki div.breadcrumbs .bcsep { + font-size: 0.75em; +} + + +/* sidebar +********************************************************************/ + +#dokuwiki__aside { +} +#dokuwiki__aside > .pad { + font-size: 0.875em; + overflow: hidden; + word-wrap: break-word; +} + +/* make sidebar more condensed */ + +#dokuwiki__aside h1 { + font-size: 1.714em; + margin-bottom: .292em; +} +#dokuwiki__aside h2 { + margin-bottom: .333em; +} +#dokuwiki__aside h3 { + margin-bottom: .444em; +} +#dokuwiki__aside h4 { + margin-bottom: .5em; +} +#dokuwiki__aside h5 { + margin-bottom: .5714em; +} + +#dokuwiki__aside p, +#dokuwiki__aside ul, +#dokuwiki__aside ol, +#dokuwiki__aside dl, +#dokuwiki__aside pre, +#dokuwiki__aside table, +#dokuwiki__aside fieldset, +#dokuwiki__aside hr, +#dokuwiki__aside blockquote, +#dokuwiki__aside address { + margin-bottom: .7em; +} + +#dokuwiki__aside ul, +#dokuwiki__aside ol { + padding-left: .5em; +} +[dir=rtl] #dokuwiki__aside ul, +[dir=rtl] #dokuwiki__aside ol { + padding-right: .5em; +} +#dokuwiki__aside li ul, +#dokuwiki__aside li ol { + margin-bottom: 0; + padding: 0; +} + +#dokuwiki__aside a:link, +#dokuwiki__aside a:visited { + color: __link__; + background-color: inherit; +} + + +/* content +********************************************************************/ + +#dokuwiki__content { +} + +.dokuwiki .pageId { + position: absolute; + top: -2.3em; + right: -1em; + overflow: hidden; + padding: 1em 1em 0; +} +[dir=rtl] .dokuwiki .pageId { + right: auto; + left: -1em; +} +.dokuwiki .pageId span { + font-size: 0.875em; + border: solid __background_alt__; + border-width: 1px 1px 0; + background-color: __background__; + color: __text_alt__; + padding: .1em .35em; + border-top-left-radius: 2px; + border-top-right-radius: 2px; + box-shadow: 0 0 .5em __text_alt__; + display: block; +} + +.dokuwiki div.page { + background: __background__; + color: inherit; + border: 1px solid __background_alt__; + box-shadow: 0 0 .5em __text_alt__; + border-radius: 2px; + padding: 1.556em 2em 2em; + margin-bottom: .5em; + overflow: hidden; + word-wrap: break-word; +} + +.dokuwiki .docInfo { + font-size: 0.875em; + text-align: right; +} +[dir=rtl] .dokuwiki .docInfo { + text-align: left; +} + +/* license note under edit window */ +.dokuwiki div.license { + font-size: 93.75%; +} + + +/* footer +********************************************************************/ + +.dokuwiki .wrapper { + margin-bottom: 1.4em; +} + +#dokuwiki__footer { + margin-bottom: 1em; + text-align: center; +} +#dokuwiki__footer > .pad { + font-size: 0.875em; +} + +#dokuwiki__footer div.license { + margin-bottom: 0.5em; + font-size: 100%; +} + +[dir=rtl] #dokuwiki__footer .license img { + margin: 0 0 0 .5em; +} + +#dokuwiki__footer div.buttons a img { + opacity: 0.5; +} +#dokuwiki__footer div.buttons a:hover img, +#dokuwiki__footer div.buttons a:active img, +#dokuwiki__footer div.buttons a:focus img { + opacity: 1; +} -- cgit v1.2.3 From c19c611efcf1cdfe0c1798defdda02809fb19be9 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Tue, 30 Jul 2013 12:09:59 +0200 Subject: lessyfied the first of template's CSS files --- lib/tpl/dokuwiki/css/design.less | 582 +++++++++++++++++++++------------------ lib/tpl/dokuwiki/style.ini | 2 +- 2 files changed, 311 insertions(+), 273 deletions(-) diff --git a/lib/tpl/dokuwiki/css/design.less b/lib/tpl/dokuwiki/css/design.less index 457414839..aba9c9c7b 100644 --- a/lib/tpl/dokuwiki/css/design.less +++ b/lib/tpl/dokuwiki/css/design.less @@ -12,49 +12,49 @@ #dokuwiki__header { padding: 2em 0 1.5em; -} -#dokuwiki__header .headings, -#dokuwiki__header .tools { - margin-bottom: 1.5em; - width: 49%; -} -#dokuwiki__header h1 img { - float: left; - margin-right: .5em; + .headings, + .tools { + margin-bottom: 1.5em; + width: 49%; + } + .tools { + margin-top: .2em; + } + + h1 { + margin: 0; + font-size: 1.5em; + font-weight: normal; + + img { + float: left; + margin-right: .5em; + } + + span { + display: block; + padding-top: 10px; + } + + a { + text-decoration: none; + color: @ini_text; + background-color: inherit; + } + } + + p.claim { + margin-bottom: 0; + font-size: 0.875em; + } } + [dir=rtl] #dokuwiki__header h1 img { float: right; margin-left: .5em; margin-right: 0; } -#dokuwiki__header h1 span { - display: block; - padding-top: 10px; -} -#dokuwiki__header h1 { - margin: 0; - font-size: 1.5em; - font-weight: normal; -} -#dokuwiki__header h1 a { - text-decoration: none; - color: __text__; - background-color: inherit; -} -#dokuwiki__header h1 a:hover, -#dokuwiki__header h1 a:active, -#dokuwiki__header h1 a:focus { -} -#dokuwiki__header p.claim { - margin-bottom: 0; - font-size: 0.875em; -} - -#dokuwiki__header .tools { - margin-top: .2em; -} - /* tools ********************************************************************/ @@ -73,41 +73,49 @@ font-weight: bold; } -#dokuwiki__header .tools ul { - padding-left: 0; - margin-bottom: 0; -} -#dokuwiki__header .tools li { - font-size: 0.875em; - margin-left: 1em; - list-style: none; - display: inline; +#dokuwiki__header .tools { + ul { + padding-left: 0; + margin-bottom: 0; + } + + li { + font-size: 0.875em; + margin-left: 1em; + list-style: none; + display: inline; + } + + form.search div.ajax_qsearch li { + font-size: 1em; + margin-left: 0; + display: block; + overflow: hidden; + text-overflow: ellipsis; + } } + [dir=rtl] #dokuwiki__header .tools li { margin-right: 1em; margin-left: 0; } -#dokuwiki__header .tools form.search div.ajax_qsearch li { - font-size: 1em; - margin-left: 0; - display: block; - overflow: hidden; - text-overflow: ellipsis; -} -#dokuwiki__usertools a.action { - padding-left: 20px; - background: transparent url(images/usertools.png) no-repeat 0 0; +#dokuwiki__usertools { + a.action { + padding-left: 20px; + background: transparent url(images/usertools.png) no-repeat 0 0; + } } + [dir=rtl] #dokuwiki__usertools a.action { padding-left: 0; padding-right: 20px; } + [dir=rtl] #IE7 #dokuwiki__usertools a.action { display: inline-block; } - #dokuwiki__header .mobileTools { display: none; /* hide mobile tools dropdown to only show in mobile view */ } @@ -120,257 +128,285 @@ right: .5em; text-align: right; width: 100%; + + ul { + margin: 0 auto; + padding: 0; + max-width: @ini_site_width; + } + + a.action.admin { + background-position: left 0; + } + + a.action.profile { + background-position: left -32px; + } + + a.action.register { + background-position: left -64px; + } + + a.action.login { + background-position: left -96px; + } + + a.action.logout { + background-position: left -128px; + } } + [dir=rtl] #dokuwiki__usertools { text-align: left; left: 40px; right: auto; -} -#dokuwiki__usertools ul { - margin: 0 auto; - padding: 0; - max-width: __site_width__; -} -#dokuwiki__usertools ul li.user { -} -#dokuwiki__usertools a.action.admin { - background-position: left 0; -} -[dir=rtl] #dokuwiki__usertools a.action.admin { - background-position: right 0; -} -#dokuwiki__usertools a.action.profile { - background-position: left -32px; -} -[dir=rtl] #dokuwiki__usertools a.action.profile { - background-position: right -32px; -} -#dokuwiki__usertools a.action.register { - background-position: left -64px; -} -[dir=rtl] #dokuwiki__usertools a.action.register { - background-position: right -64px; -} -#dokuwiki__usertools a.action.login { - background-position: left -96px; -} -[dir=rtl] #dokuwiki__usertools a.action.login { - background-position: right -96px; -} -#dokuwiki__usertools a.action.logout { - background-position: left -128px; -} -[dir=rtl] #dokuwiki__usertools a.action.logout { - background-position: right -128px; -} + a.action.admin { + background-position: right 0; + } + + a.action.profile { + background-position: right -32px; + } + a.action.register { + background-position: right -64px; + } + + a.action.login { + background-position: right -96px; + } + + a.action.logout { + background-position: right -128px; + } +} /*____________ site tools ____________*/ #dokuwiki__sitetools { text-align: right; + + form.search { + display: block; + font-size: 0.875em; + position: relative; + + input.edit { + width: 18em; + padding: .35em 22px .35em .1em; + } + + input.button { + background: transparent url(images/search.png) no-repeat 0 0; + border-width: 0; + width: 19px; + height: 14px; + text-indent: -99999px; + margin-left: -20px; + box-shadow: none; + padding: 0; + } + } + + ul { + margin-top: 0.5em; + } } + [dir=rtl] #dokuwiki__sitetools { text-align: left; -} -#dokuwiki__sitetools form.search { - display: block; - font-size: 0.875em; - position: relative; + form.search { + input.edit { + padding: .35em .1em .35em 22px; + } + + input.button { + background-position: 5px 0; + margin-left: 0; + margin-right: -20px; + position: relative; + } + } } + #IE7 #dokuwiki__sitetools form.search { min-height: 1px; z-index: 21; } -#dokuwiki__sitetools form.search input.edit { - width: 18em; - padding: .35em 22px .35em .1em; -} -[dir=rtl] #dokuwiki__sitetools form.search input.edit { - padding: .35em .1em .35em 22px; -} -#dokuwiki__sitetools form.search input.button { - background: transparent url(images/search.png) no-repeat 0 0; - border-width: 0; - width: 19px; - height: 14px; - text-indent: -99999px; - margin-left: -20px; - box-shadow: none; - padding: 0; -} -[dir=rtl] #dokuwiki__sitetools form.search input.button { - background-position: 5px 0; - margin-left: 0; - margin-right: -20px; - position: relative; -} - -#dokuwiki__sitetools ul { - margin-top: 0.5em; -} -#dokuwiki__sitetools li { -} /*____________ breadcrumbs ____________*/ .dokuwiki div.breadcrumbs { - border-top: 1px solid __border__; - border-bottom: 1px solid __background__; + border-top: 1px solid @ini_border; + border-bottom: 1px solid @ini_background; margin-bottom: .5em; font-size: 0.875em; clear: both; -} -.dokuwiki div.breadcrumbs div { - padding: .1em .35em; -} -.dokuwiki div.breadcrumbs div:only-child { - border-top: 1px solid __background__; - border-bottom: 1px solid __border__; -} -.dokuwiki div.breadcrumbs div:first-child { - border-top: 1px solid __background__; + div { + padding: .1em .35em; + } + + div:only-child { + border-top: 1px solid @ini_background; + border-bottom: 1px solid @ini_border; + } + + div:first-child { + border-top: 1px solid @ini_background; + } + + div:last-child { + border-bottom: 1px solid @ini_border; + } + + a { + color: @ini_link; + background-color: inherit; + } + + .bcsep { + font-size: 0.75em; + } } + #IE7 .dokuwiki div.breadcrumbs div, #IE8 .dokuwiki div.breadcrumbs div { - border-bottom: 1px solid __border__; -} -.dokuwiki div.breadcrumbs div:last-child { - border-bottom: 1px solid __border__; -} - -.dokuwiki div.breadcrumbs a { - color: __link__; - background-color: inherit; -} -.dokuwiki div.breadcrumbs .bcsep { - font-size: 0.75em; + border-bottom: 1px solid @ini_border; } - /* sidebar ********************************************************************/ #dokuwiki__aside { -} -#dokuwiki__aside > .pad { - font-size: 0.875em; - overflow: hidden; - word-wrap: break-word; -} -/* make sidebar more condensed */ - -#dokuwiki__aside h1 { - font-size: 1.714em; - margin-bottom: .292em; -} -#dokuwiki__aside h2 { - margin-bottom: .333em; -} -#dokuwiki__aside h3 { - margin-bottom: .444em; -} -#dokuwiki__aside h4 { - margin-bottom: .5em; -} -#dokuwiki__aside h5 { - margin-bottom: .5714em; -} - -#dokuwiki__aside p, -#dokuwiki__aside ul, -#dokuwiki__aside ol, -#dokuwiki__aside dl, -#dokuwiki__aside pre, -#dokuwiki__aside table, -#dokuwiki__aside fieldset, -#dokuwiki__aside hr, -#dokuwiki__aside blockquote, -#dokuwiki__aside address { - margin-bottom: .7em; + > .pad { + font-size: 0.875em; + overflow: hidden; + word-wrap: break-word; + } + + /* make sidebar more condensed */ + + h1 { + font-size: 1.714em; + margin-bottom: .292em; + } + + h2 { + margin-bottom: .333em; + } + + h3 { + margin-bottom: .444em; + } + + h4 { + margin-bottom: .5em; + } + + h5 { + margin-bottom: .5714em; + } + + p, + ul, + ol, + dl, + pre, + table, + fieldset, + hr, + blockquote, + address { + margin-bottom: .7em; + } + + ul, + ol { + padding-left: .5em; + } + + li ul, + li ol { + margin-bottom: 0; + padding: 0; + } + + a:link, + a:visited { + color: @ini_link; + background-color: inherit; + } } -#dokuwiki__aside ul, -#dokuwiki__aside ol { - padding-left: .5em; -} [dir=rtl] #dokuwiki__aside ul, [dir=rtl] #dokuwiki__aside ol { padding-right: .5em; } -#dokuwiki__aside li ul, -#dokuwiki__aside li ol { - margin-bottom: 0; - padding: 0; -} - -#dokuwiki__aside a:link, -#dokuwiki__aside a:visited { - color: __link__; - background-color: inherit; -} - /* content ********************************************************************/ -#dokuwiki__content { -} - -.dokuwiki .pageId { - position: absolute; - top: -2.3em; - right: -1em; - overflow: hidden; - padding: 1em 1em 0; -} -[dir=rtl] .dokuwiki .pageId { - right: auto; - left: -1em; -} -.dokuwiki .pageId span { - font-size: 0.875em; - border: solid __background_alt__; - border-width: 1px 1px 0; - background-color: __background__; - color: __text_alt__; - padding: .1em .35em; - border-top-left-radius: 2px; - border-top-right-radius: 2px; - box-shadow: 0 0 .5em __text_alt__; - display: block; -} - -.dokuwiki div.page { - background: __background__; - color: inherit; - border: 1px solid __background_alt__; - box-shadow: 0 0 .5em __text_alt__; - border-radius: 2px; - padding: 1.556em 2em 2em; - margin-bottom: .5em; - overflow: hidden; - word-wrap: break-word; -} - -.dokuwiki .docInfo { - font-size: 0.875em; - text-align: right; -} -[dir=rtl] .dokuwiki .docInfo { - text-align: left; -} - -/* license note under edit window */ -.dokuwiki div.license { - font-size: 93.75%; +.dokuwiki { + + .pageId { + position: absolute; + top: -2.3em; + right: -1em; + overflow: hidden; + padding: 1em 1em 0; + } + + .pageId span { + font-size: 0.875em; + border: solid @ini_background_alt; + border-width: 1px 1px 0; + background-color: @ini_background; + color: @ini_text_alt; + padding: .1em .35em; + border-top-left-radius: 2px; + border-top-right-radius: 2px; + box-shadow: 0 0 .5em @ini_text_alt; + display: block; + } + + div.page { + background: @ini_background; + color: inherit; + border: 1px solid @ini_background_alt; + box-shadow: 0 0 .5em @ini_text_alt; + border-radius: 2px; + padding: 1.556em 2em 2em; + margin-bottom: .5em; + overflow: hidden; + word-wrap: break-word; + } + + .docInfo { + font-size: 0.875em; + text-align: right; + } + + /* license note under edit window */ + div.license { + font-size: 93.75%; + } +} + +[dir=rtl] .dokuwiki { + .docInfo { + text-align: left; + } + + .pageId { + right: auto; + left: -1em; + } } - /* footer ********************************************************************/ @@ -381,25 +417,27 @@ #dokuwiki__footer { margin-bottom: 1em; text-align: center; -} -#dokuwiki__footer > .pad { - font-size: 0.875em; -} -#dokuwiki__footer div.license { - margin-bottom: 0.5em; - font-size: 100%; + > .pad { + font-size: 0.875em; + } + + div.license { + margin-bottom: 0.5em; + font-size: 100%; + } + + div.buttons a img { + opacity: 0.5; + } + + div.buttons a:hover img, + div.buttons a:active img, + div.buttons a:focus img { + opacity: 1; + } } [dir=rtl] #dokuwiki__footer .license img { margin: 0 0 0 .5em; } - -#dokuwiki__footer div.buttons a img { - opacity: 0.5; -} -#dokuwiki__footer div.buttons a:hover img, -#dokuwiki__footer div.buttons a:active img, -#dokuwiki__footer div.buttons a:focus img { - opacity: 1; -} diff --git a/lib/tpl/dokuwiki/style.ini b/lib/tpl/dokuwiki/style.ini index 77bb98236..e4725a4fd 100644 --- a/lib/tpl/dokuwiki/style.ini +++ b/lib/tpl/dokuwiki/style.ini @@ -29,7 +29,7 @@ css/_modal.css = screen css/_forms.css = screen css/_admin.css = screen css/structure.css = screen -css/design.css = screen +css/design.less = screen css/pagetools.css = screen css/content.css = screen css/includes.css = screen -- cgit v1.2.3 From bd9a4965eaaebb5de8ad1c502d2af32c6897e6f1 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Tue, 30 Jul 2013 13:24:13 +0200 Subject: lessyfied another one --- lib/tpl/dokuwiki/css/content.css | 362 ----------------------------------- lib/tpl/dokuwiki/css/content.less | 391 ++++++++++++++++++++++++++++++++++++++ lib/tpl/dokuwiki/css/mixins.less | 15 ++ lib/tpl/dokuwiki/style.ini | 2 + 4 files changed, 408 insertions(+), 362 deletions(-) delete mode 100644 lib/tpl/dokuwiki/css/content.css create mode 100644 lib/tpl/dokuwiki/css/content.less create mode 100644 lib/tpl/dokuwiki/css/mixins.less diff --git a/lib/tpl/dokuwiki/css/content.css b/lib/tpl/dokuwiki/css/content.css deleted file mode 100644 index b1498d4de..000000000 --- a/lib/tpl/dokuwiki/css/content.css +++ /dev/null @@ -1,362 +0,0 @@ -/** - * This file provides the main design styles for the page content. - * - * @author Anika Henke - * @author Andreas Gohr - * @author Clarence Lee - */ - -/*____________ section indenting ____________ - -.dokuwiki .page h1 {margin-left: 0;} -.dokuwiki .page h2 {margin-left: .666em;} -.dokuwiki .page h3 {margin-left: 1.776em;} -.dokuwiki .page h4 {margin-left: 3em;} -.dokuwiki .page h5 {margin-left: 4.5712em;} -.dokuwiki .page div.level1 {margin-left: 0;} -.dokuwiki .page div.level2 {margin-left: 1em;} -.dokuwiki .page div.level3 {margin-left: 2em;} -.dokuwiki .page div.level4 {margin-left: 3em;} -.dokuwiki .page div.level5 {margin-left: 4em;} - -[dir=rtl] .dokuwiki .page h1 {margin-left: 0; margin-right: 0;} -[dir=rtl] .dokuwiki .page h2 {margin-left: 0; margin-right: .666em;} -[dir=rtl] .dokuwiki .page h3 {margin-left: 0; margin-right: 1.776em;} -[dir=rtl] .dokuwiki .page h4 {margin-left: 0; margin-right: 3em;} -[dir=rtl] .dokuwiki .page h5 {margin-left: 0; margin-right: 4.5712em;} -[dir=rtl] .dokuwiki .page div.level1 {margin-left: 0; margin-right: 0;} -[dir=rtl] .dokuwiki .page div.level2 {margin-left: 0; margin-right: 1em;} -[dir=rtl] .dokuwiki .page div.level3 {margin-left: 0; margin-right: 2em;} -[dir=rtl] .dokuwiki .page div.level4 {margin-left: 0; margin-right: 3em;} -[dir=rtl] .dokuwiki .page div.level5 {margin-left: 0; margin-right: 4em;} -*/ -/* hx margin-left = (1 / font-size) * .levelx-margin */ - - -/*____________ links to wiki pages (addition to _links) ____________*/ - -/* existing wikipage */ -.dokuwiki a.wikilink1 { - color: __existing__; - background-color: inherit; -} -/* not existing wikipage */ -.dokuwiki a.wikilink2 { - color: __missing__; - background-color: inherit; -} - - -/*____________ images ____________*/ - -/* embedded images (styles are already partly set in lib/styles/all.css) */ -.dokuwiki img.media { - margin: .2em 0; -} -.dokuwiki img.medialeft { - margin: .2em 1em .2em 0; -} -.dokuwiki img.mediaright { - margin: .2em 0 .2em 1em; -} -.dokuwiki img.mediacenter { - margin: .2em auto; -} - - -/*____________ lists ____________*/ - -#dokuwiki__content ul li, -#dokuwiki__aside ul li { - color: __text_alt__; -} -#dokuwiki__content ol li, -#dokuwiki__aside ol li { - color: __text_neu__; -} -#dokuwiki__content li .li, -#dokuwiki__aside li .li { - color: __text__; -} - - -/*____________ tables ____________*/ - -/* div around each table */ -.dokuwiki div.table { - overflow-x: auto; - margin-bottom: 1.4em; -} -.dokuwiki div.table table { - margin-bottom: 0; -} - -.dokuwiki table.inline { - min-width: 50%; -} -.dokuwiki table.inline tr:hover td { - background-color: __background_alt__; -} -.dokuwiki table.inline tr:hover th { - background-color: __border__; -} - - -/*____________ code ____________*/ - -/* fix if background-color hides underlining */ -.dokuwiki em.u code { - text-decoration: underline; -} - -/* for code in */ -.dokuwiki pre.file { -} - -/* filenames for downloadable file and code blocks */ -.dokuwiki dl.code, -.dokuwiki dl.file { -} - -.dokuwiki dl.code dt, -.dokuwiki dl.file dt { - background-color: __background_site__; - background: -moz-linear-gradient( top, __background_alt__ 0%, __background_site__ 100%); - background: -webkit-linear-gradient(top, __background_alt__ 0%, __background_site__ 100%); - background: -o-linear-gradient( top, __background_alt__ 0%, __background_site__ 100%); - background: -ms-linear-gradient( top, __background_alt__ 0%, __background_site__ 100%); - background: linear-gradient( top, __background_alt__ 0%, __background_site__ 100%); - color: inherit; - border: 1px solid __border__; - border-bottom-color: __background_site__; - border-top-left-radius: .3em; - border-top-right-radius: .3em; - padding: .3em .6em .1em; - margin-bottom: -1px; - float: left; -} -[dir=rtl] .dokuwiki dl.code dt, -[dir=rtl] .dokuwiki dl.file dt { - float: right; -} -.dokuwiki dl.code dt a, -.dokuwiki dl.file dt a { - background-color: transparent; - font-size: 0.875em; - font-weight: normal; - display: block; - min-height: 16px; -} - -.dokuwiki dl.code dd, -.dokuwiki dl.file dd { - margin: 0; - clear: left; - min-height: 1px; /* for IE7 */ -} -[dir=rtl] .dokuwiki dl.code dd, -[dir=rtl] .dokuwiki dl.file dd { - clear: right; -} - -.dokuwiki dl.code pre, -.dokuwiki dl.file pre { - box-shadow: inset -4px -4px .5em -.3em __border__; -} - - -/*____________ JS popup ____________*/ - -.JSpopup { - background-color: __background__; - color: __text__; - border: 1px solid __border__; - box-shadow: .1em .1em .1em __border__; - border-radius: 2px; - padding: .3em .5em; - font-size: .9em; -} -.dokuwiki form.search div.ajax_qsearch { - top: -.35em; - font-size: 1em; - text-overflow: ellipsis; -} - -.JSpopup ul, -.JSpopup ol { - padding-left: 0; -} -[dir=rtl] .JSpopup ul, -[dir=rtl] .JSpopup ol { - padding-right: 0; -} - - -/* changes to underscored CSS files -********************************************************************/ - -#acl__tree li { - margin: 0; -} - -#dokuwiki__content span.curid a { - font-weight: normal; -} -#dokuwiki__content strong span.curid a { - font-weight: bold; -} - - -/*____________ changes to _edit ____________*/ - -.dokuwiki div.toolbar button.toolbutton { - border-radius: 0; - border-left-width: 0; - padding: .1em .35em; -} -.dokuwiki div.toolbar button.toolbutton:first-child { - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; - border-left-width: 1px; -} -[dir=rtl] .dokuwiki div.toolbar button.toolbutton:first-child { - border-top-left-radius: 0; - border-bottom-left-radius: 0; - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; - border-left-width: 0; - border-right-width: 1px; -} -.dokuwiki div.toolbar button.toolbutton:last-child { - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; -} -[dir=rtl] .dokuwiki div.toolbar button.toolbutton:last-child { - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; - border-top-right-radius: 0; - border-bottom-right-radius: 0; - border-left-width: 1px; -} - -.dokuwiki div.section_highlight { - margin: 0 -2em; - padding: 0 1em; - border-width: 0 1em; -} - -.dokuwiki textarea.edit { - font-family: Consolas, "Andale Mono WT", "Andale Mono", "Bitstream Vera Sans Mono", "Nimbus Mono L", Monaco, "Courier New", monospace; -} - -.dokuwiki div.preview { - margin: 0 -2em; - padding: 0 2em; -} -.dokuwiki.hasSidebar div.preview { - border-right: __sidebar_width__ solid __background_alt__; -} -[dir=rtl] .dokuwiki.hasSidebar div.preview { - border-right-width: 0; - border-left: __sidebar_width__ solid __background_alt__; -} -.dokuwiki div.preview div.pad { - padding: 1.556em 0 2em; -} - - -/*____________ changes to _toc ____________*/ - -#dw__toc { - margin: -1.556em -2em .5em 1.4em; - width: __sidebar_width__; - border-left: 1px solid __border__; - background: __background__; - color: inherit; -} -[dir=rtl] #dw__toc { - margin: -1.556em 1.4em .5em -2em; - border-left-width: 0; - border-right: 1px solid __border__; -} - -.dokuwiki h3.toggle { - padding: .5em 1em; - margin-bottom: 0; - font-size: .875em; - letter-spacing: .1em; -} -#dokuwiki__aside h3.toggle { - display: none; -} - -.dokuwiki .toggle strong { - background: transparent url(images/toc-arrows.png) 0 0; - width: 8px; - height: 5px; - margin: .4em 0 0; -} -.dokuwiki .toggle.closed strong { - background-position: 0 -5px; -} - -.dokuwiki .toggle strong span { - display: none; -} - - -#dw__toc > div { - font-size: 0.875em; - padding: .5em 1em 1em; -} -#dw__toc ul { - padding: 0 0 0 1.2em; -} -[dir=rtl] #dw__toc ul { - padding: 0 1.5em 0 0; -} -#dw__toc ul li { - list-style-image: url(images/toc-bullet.png); -} -#dw__toc ul li.clear { - list-style: none; -} -#dw__toc ul li div.li { - padding: .2em 0; -} - - -/*____________ changes to _imgdetail ____________*/ - -#dokuwiki__detail { - padding: 0; -} -#dokuwiki__detail img { - float: none; - margin-bottom: 1.4em; -} -#dokuwiki__detail div.img_detail { - float: none; -} - -#dokuwiki__detail div.img_detail dl { - overflow: hidden; -} -#dokuwiki__detail div.img_detail dl dt { - float: left; - width: 9em; - text-align: right; - clear: left; -} -[dir=rtl] #dokuwiki__detail div.img_detail dl dt { - float: right; - text-align: left; - clear: right; -} -#dokuwiki__detail div.img_detail dl dd { - margin-left: 9.5em; -} -[dir=rtl] #dokuwiki__detail div.img_detail dl dd { - margin-left: 0; - margin-right: 9.5em; -} diff --git a/lib/tpl/dokuwiki/css/content.less b/lib/tpl/dokuwiki/css/content.less new file mode 100644 index 000000000..f6022b4e9 --- /dev/null +++ b/lib/tpl/dokuwiki/css/content.less @@ -0,0 +1,391 @@ +/** + * This file provides the main design styles for the page content. + * + * @author Anika Henke + * @author Andreas Gohr + * @author Clarence Lee + */ + +/*____________ section indenting ____________ + +.dokuwiki .page h1 {margin-left: 0;} +.dokuwiki .page h2 {margin-left: .666em;} +.dokuwiki .page h3 {margin-left: 1.776em;} +.dokuwiki .page h4 {margin-left: 3em;} +.dokuwiki .page h5 {margin-left: 4.5712em;} +.dokuwiki .page div.level1 {margin-left: 0;} +.dokuwiki .page div.level2 {margin-left: 1em;} +.dokuwiki .page div.level3 {margin-left: 2em;} +.dokuwiki .page div.level4 {margin-left: 3em;} +.dokuwiki .page div.level5 {margin-left: 4em;} + +[dir=rtl] .dokuwiki .page h1 {margin-left: 0; margin-right: 0;} +[dir=rtl] .dokuwiki .page h2 {margin-left: 0; margin-right: .666em;} +[dir=rtl] .dokuwiki .page h3 {margin-left: 0; margin-right: 1.776em;} +[dir=rtl] .dokuwiki .page h4 {margin-left: 0; margin-right: 3em;} +[dir=rtl] .dokuwiki .page h5 {margin-left: 0; margin-right: 4.5712em;} +[dir=rtl] .dokuwiki .page div.level1 {margin-left: 0; margin-right: 0;} +[dir=rtl] .dokuwiki .page div.level2 {margin-left: 0; margin-right: 1em;} +[dir=rtl] .dokuwiki .page div.level3 {margin-left: 0; margin-right: 2em;} +[dir=rtl] .dokuwiki .page div.level4 {margin-left: 0; margin-right: 3em;} +[dir=rtl] .dokuwiki .page div.level5 {margin-left: 0; margin-right: 4em;} +*/ +/* hx margin-left = (1 / font-size) * .levelx-margin */ + +/*____________ links to wiki pages (addition to _links) ____________*/ + +/* existing wikipage */ +.dokuwiki a.wikilink1 { + color: @ini_existing; + background-color: inherit; +} + +/* not existing wikipage */ +.dokuwiki a.wikilink2 { + color: @ini_missing; + background-color: inherit; +} + +/*____________ images ____________*/ + +/* embedded images (styles are already partly set in lib/styles/all.css) */ +.dokuwiki img.media { + margin: .2em 0; +} + +.dokuwiki img.medialeft { + margin: .2em 1em .2em 0; +} + +.dokuwiki img.mediaright { + margin: .2em 0 .2em 1em; +} + +.dokuwiki img.mediacenter { + margin: .2em auto; +} + +/*____________ lists ____________*/ + +#dokuwiki__content ul li, +#dokuwiki__aside ul li { + color: @ini_text_alt; +} + +#dokuwiki__content ol li, +#dokuwiki__aside ol li { + color: @ini_text_neu; +} + +#dokuwiki__content li .li, +#dokuwiki__aside li .li { + color: @ini_text; +} + +/*____________ tables ____________*/ + +/* div around each table */ +.dokuwiki div.table { + overflow-x: auto; + margin-bottom: 1.4em; +} + +.dokuwiki div.table table { + margin-bottom: 0; +} + +.dokuwiki table.inline { + min-width: 50%; +} + +.dokuwiki table.inline tr:hover td { + background-color: @ini_background_alt; +} + +.dokuwiki table.inline tr:hover th { + background-color: @ini_border; +} + +/*____________ code ____________*/ + +/* fix if background-color hides underlining */ +.dokuwiki em.u code { + text-decoration: underline; +} + +/* for code in */ +.dokuwiki pre.file { +} + +/* filenames for downloadable file and code blocks */ +.dokuwiki dl.code, +.dokuwiki dl.file { + dt, + dt { + .linear-gradient(@ini_background_site, @ini_background_alt, @ini_background_site); + color: inherit; + border: 1px solid @ini_border; + border-bottom-color: @ini_background_site; + border-top-left-radius: .3em; + border-top-right-radius: .3em; + padding: .3em .6em .1em; + margin-bottom: -1px; + float: left; + } + dt a, + dt a { + background-color: transparent; + font-size: 0.875em; + font-weight: normal; + display: block; + min-height: 16px; + } + + dd, + dd { + margin: 0; + clear: left; + min-height: 1px; /* for IE7 */ + } + + pre, + pre { + box-shadow: inset -4px -4px .5em -.3em @ini_border; + } +} + +[dir=rtl] .dokuwiki dl.code, +[dir=rtl] .dokuwiki dl.file { + dt, + dt { + float: right; + } + + dd, + dd { + clear: right; + } +} + +/*____________ JS popup ____________*/ + +.JSpopup { + background-color: @ini_background; + color: @ini_text; + border: 1px solid @ini_border; + box-shadow: .1em .1em .1em @ini_border; + border-radius: 2px; + padding: .3em .5em; + font-size: .9em; +} + +.dokuwiki form.search div.ajax_qsearch { + top: -.35em; + font-size: 1em; + text-overflow: ellipsis; +} + +.JSpopup ul, +.JSpopup ol { + padding-left: 0; +} + +[dir=rtl] .JSpopup ul, +[dir=rtl] .JSpopup ol { + padding-right: 0; +} + +/* changes to underscored CSS files +********************************************************************/ + +#acl__tree li { + margin: 0; +} + +#dokuwiki__content span.curid a { + font-weight: normal; +} + +#dokuwiki__content strong span.curid a { + font-weight: bold; +} + +/*____________ changes to _edit ____________*/ + +.dokuwiki div.toolbar { + button.toolbutton { + border-radius: 0; + border-left-width: 0; + padding: .1em .35em; + } + + button.toolbutton:first-child { + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + border-left-width: 1px; + } + + button.toolbutton:last-child { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + } +} + +[dir=rtl] .dokuwiki div.toolbar { + button.toolbutton:last-child { + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-left-width: 1px; + } + + button.toolbutton:first-child { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + border-left-width: 0; + border-right-width: 1px; + } +} + +.dokuwiki div.section_highlight { + margin: 0 -2em; + padding: 0 1em; + border-width: 0 1em; +} + +.dokuwiki textarea.edit { + font-family: Consolas, "Andale Mono WT", "Andale Mono", "Bitstream Vera Sans Mono", "Nimbus Mono L", Monaco, "Courier New", monospace; +} + +.dokuwiki div.preview { + margin: 0 -2em; + padding: 0 2em; +} + +.dokuwiki.hasSidebar div.preview { + border-right: @ini_sidebar_width solid @ini_background_alt; +} + +[dir=rtl] .dokuwiki.hasSidebar div.preview { + border-right-width: 0; + border-left: @ini_sidebar_width solid @ini_background_alt; +} + +.dokuwiki div.preview div.pad { + padding: 1.556em 0 2em; +} + +/*____________ changes to _toc ____________*/ + +#dw__toc { + margin: -1.556em -2em .5em 1.4em; + width: @ini_sidebar_width; + border-left: 1px solid @ini_border; + background: @ini_background; + color: inherit; +} + +[dir=rtl] #dw__toc { + margin: -1.556em 1.4em .5em -2em; + border-left-width: 0; + border-right: 1px solid @ini_border; +} + +.dokuwiki h3.toggle { + padding: .5em 1em; + margin-bottom: 0; + font-size: .875em; + letter-spacing: .1em; +} + +#dokuwiki__aside h3.toggle { + display: none; +} + +.dokuwiki .toggle strong { + background: transparent url(images/toc-arrows.png) 0 0; + width: 8px; + height: 5px; + margin: .4em 0 0; +} + +.dokuwiki .toggle.closed strong { + background-position: 0 -5px; +} + +.dokuwiki .toggle strong span { + display: none; +} + +#dw__toc { + > div { + font-size: 0.875em; + padding: .5em 1em 1em; + } + + ul { + padding: 0 0 0 1.2em; + } + + ul li { + list-style-image: url(images/toc-bullet.png); + } + + ul li.clear { + list-style: none; + } + + ul li div.li { + padding: .2em 0; + } +} + +[dir=rtl] #dw__toc ul { + padding: 0 1.5em 0 0; +} + +/*____________ changes to _imgdetail ____________*/ + +#dokuwiki__detail { + padding: 0; + + img { + float: none; + margin-bottom: 1.4em; + } + + div.img_detail { + float: none; + } + + div.img_detail dl { + overflow: hidden; + } + + div.img_detail dl dt { + float: left; + width: 9em; + text-align: right; + clear: left; + } + + div.img_detail dl dd { + margin-left: 9.5em; + } +} + +[dir=rtl] #dokuwiki__detail div.img_detail { + dl dt { + float: right; + text-align: left; + clear: right; + } + + dl dd { + margin-left: 0; + margin-right: 9.5em; + } +} \ No newline at end of file diff --git a/lib/tpl/dokuwiki/css/mixins.less b/lib/tpl/dokuwiki/css/mixins.less new file mode 100644 index 000000000..7ecae4a0b --- /dev/null +++ b/lib/tpl/dokuwiki/css/mixins.less @@ -0,0 +1,15 @@ +/** + * linear gradient x-browser support + * + * @param color fallback background color + * @param start start color + * @param stop end color + */ +.linear-gradient(@color: #F5F5F5, @start: #EEE, @stop: #FFF) { + background: @color; + background: -moz-linear-gradient( top, @start 0%, @stop 100%); + background: -webkit-linear-gradient(top, @start 0%, @stop 100%); + background: -o-linear-gradient( top, @start 0%, @stop 100%); + background: -ms-linear-gradient( top, @start 0%, @stop 100%); + background: linear-gradient( top, @start 0%, @stop 100%); +} \ No newline at end of file diff --git a/lib/tpl/dokuwiki/style.ini b/lib/tpl/dokuwiki/style.ini index e4725a4fd..9cf6cb64f 100644 --- a/lib/tpl/dokuwiki/style.ini +++ b/lib/tpl/dokuwiki/style.ini @@ -12,6 +12,8 @@ [stylesheets] +css/mixins.less = screen + css/basic.css = screen css/_imgdetail.css = screen css/_media_popup.css = screen -- cgit v1.2.3 From 45d3363005120ca17df1184280e1a9df0fddc062 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Tue, 30 Jul 2013 14:48:06 +0200 Subject: lessified more files --- lib/tpl/dokuwiki/css/basic.css | 468 ------------------------------------ lib/tpl/dokuwiki/css/basic.less | 460 +++++++++++++++++++++++++++++++++++ lib/tpl/dokuwiki/css/content.less | 3 +- lib/tpl/dokuwiki/css/includes.css | 4 - lib/tpl/dokuwiki/css/mixins.less | 17 +- lib/tpl/dokuwiki/css/mobile.css | 288 ---------------------- lib/tpl/dokuwiki/css/mobile.less | 288 ++++++++++++++++++++++ lib/tpl/dokuwiki/css/pagetools.css | 421 -------------------------------- lib/tpl/dokuwiki/css/pagetools.less | 421 ++++++++++++++++++++++++++++++++ lib/tpl/dokuwiki/css/structure.css | 81 ------- lib/tpl/dokuwiki/css/structure.less | 94 ++++++++ lib/tpl/dokuwiki/style.ini | 14 +- 12 files changed, 1280 insertions(+), 1279 deletions(-) delete mode 100644 lib/tpl/dokuwiki/css/basic.css create mode 100644 lib/tpl/dokuwiki/css/basic.less delete mode 100644 lib/tpl/dokuwiki/css/includes.css delete mode 100644 lib/tpl/dokuwiki/css/mobile.css create mode 100644 lib/tpl/dokuwiki/css/mobile.less delete mode 100644 lib/tpl/dokuwiki/css/pagetools.css create mode 100644 lib/tpl/dokuwiki/css/pagetools.less delete mode 100644 lib/tpl/dokuwiki/css/structure.css create mode 100644 lib/tpl/dokuwiki/css/structure.less diff --git a/lib/tpl/dokuwiki/css/basic.css b/lib/tpl/dokuwiki/css/basic.css deleted file mode 100644 index ad04f7c41..000000000 --- a/lib/tpl/dokuwiki/css/basic.css +++ /dev/null @@ -1,468 +0,0 @@ -/** - * This file provides the most basic styles. - * - * If you integrate DokuWiki into another project, you might either - * want to integrate this file into the other project as well, or use - * the other project's basic CSS for DokuWiki instead of this one. - * - * @author Anika Henke - */ - -html { - overflow-x: auto; - overflow-y: scroll; -} -html, -body { - color: __text__; - background: __background_site__ url(images/page-gradient.png) top left repeat-x; - margin: 0; - padding: 0; -} -body { - font: normal 87.5%/1.4 Arial, sans-serif; - /* default font size: 100% => 16px; 93.75% => 15px; 87.5% => 14px; 81.25% => 13px; 75% => 12px */ - -webkit-text-size-adjust: 100%; -} - - -/*____________ headers ____________*/ - -caption, -figcaption, -summary, -legend { - padding: 0; - margin: 0 0 .35em; - line-height: 1.2; -} -h1, -h2, -h3, -h4, -h5, -h6 { - font-weight: bold; - padding: 0; - line-height: 1.2; - clear: left; /* ideally 'both', but problems with toc */ -} -[dir=rtl] h1, -[dir=rtl] h2, -[dir=rtl] h3, -[dir=rtl] h4, -[dir=rtl] h5, -[dir=rtl] h6 { - clear: right; -} - -h1 { - font-size: 2em; - margin: 0 0 0.444em; -} -h2 { - font-size: 1.5em; - margin: 0 0 0.666em; -} -h3 { - font-size: 1.125em; - margin: 0 0 0.888em; -} -h4 { - font-size: 1em; - margin: 0 0 1.0em; -} -h5 { - font-size: .875em; - margin: 0 0 1.1428em; -} -h6 { - font-size: .75em; - margin: 0 0 1.333em; -} -/* bottom margin = 1 / font-size */ - - -/*____________ basic margins and paddings ____________*/ - -p, -ul, -ol, -dl, -pre, -table, -hr, -blockquote, -figure, -details, -fieldset, -address { - margin: 0 0 1.4em 0; /* bottom margin = line-height */ - padding: 0; -} - -div { - margin: 0; - padding: 0; -} - - -/*____________ lists ____________*/ - -ul, -ol { - padding: 0 0 0 1.5em; -} -[dir=rtl] ul, -[dir=rtl] ol { - padding: 0 1.5em 0 0; -} - -li, -dd { - padding: 0; - margin: 0 0 0 1.5em; -} -[dir=rtl] li, -[dir=rtl] dd { - margin: 0 1.5em 0 0; -} -dt { - font-weight: bold; - margin: 0; - padding: 0; -} - -li ul, -li ol, -li dl, -dl ul, -dl ol, -dl dl { - margin-bottom: 0; - padding: 0; -} -li li { - font-size: 100%; -} - -ul { list-style: square outside; } -ol { list-style: decimal outside; } -ol ol { list-style-type: lower-alpha; } -ol ol ol { list-style-type: upper-roman; } -ol ol ol ol { list-style-type: upper-alpha; } -ol ol ol ol ol { list-style-type: lower-roman; } - - -/*____________ tables ____________*/ - -table { - border-collapse: collapse; - empty-cells: show; - border-spacing: 0; - border: 1px solid __border__; -} - -caption { - caption-side: top; - text-align: left; -} -[dir=rtl] caption { - text-align: right; -} - -th, -td { - padding: .3em .5em; - margin: 0; - vertical-align: top; - border: 1px solid __border__; -} -th { - font-weight: bold; - background-color: __background_alt__; - text-align: left; -} -[dir=rtl] th { - text-align: right; -} - - -/*____________ links ____________*/ - -a { - outline: none; -} -a:link, -a:visited { - text-decoration: none; - color: __link__; -} -a:link:hover, -a:visited:hover, -a:link:focus, -a:visited:focus, -a:link:active, -a:visited:active { - text-decoration: underline; -} - - -/*____________ misc ____________*/ - -img { - border-width: 0; - vertical-align: middle; - color: #666; - background-color: transparent; - font-style: italic; - height: auto; -} -img, -object, -embed, -iframe, -video, -audio { - max-width: 100%; -} -#IE7 img, -#IE8 img, -button img { - max-width: none; -} - -hr { - border-top: solid __border__; - border-bottom: solid __background__; - border-width: 1px 0; - height: 0; - text-align: center; - clear: both; -} - -acronym, -abbr { - cursor: help; - border-bottom: 1px dotted; - font-style: normal; -} -em acronym, -em abbr { - font-style: italic; -} - -mark { - background-color: __highlight__; - color: inherit; -} - -pre, -code, -samp, -kbd { - font-family: Consolas, "Andale Mono WT", "Andale Mono", "Bitstream Vera Sans Mono", "Nimbus Mono L", Monaco, "Courier New", monospace; - /* same font stack should be used for ".dokuwiki table.diff td" in _diff.css */ - font-size: 1em; - direction: ltr; - text-align: left; - background-color: __background_site__; - color: __text__; - box-shadow: inset 0 0 .3em __border__; - border-radius: 2px; -} -pre { - overflow: auto; - word-wrap: normal; - border: 1px solid __border__; - border-radius: 2px; - box-shadow: inset 0 0 .5em __border__; - padding: .7em 1em; -} - -blockquote { - padding: 0 .5em; - border: solid __border__; - border-width: 0 0 0 .25em; -} -[dir=rtl] blockquote { - border-width: 0 .25em 0 0; -} -q:before, -q:after { - content: ''; -} - -sub, -sup { - font-size: .8em; - line-height: 1; -} -sub { - vertical-align: sub; -} -sup { - vertical-align: super; -} - -small { - font-size: .8em; -} - -/*____________ forms ____________*/ - -/* for all of the form styles, style.ini colours are not used on purpose (except for fieldset border) */ - -form { - display: inline; - margin: 0; - padding: 0; -} -fieldset { - padding: .7em 1em 0; - padding: .7rem 1rem; /* for those browsers understanding :last-child */ - border: 1px solid __text_alt__; -} -fieldset > :last-child { - margin-bottom: 0; -} -legend { - margin: 0; - padding: 0 .1em; -} -label { - vertical-align: middle; - cursor: pointer; -} - -input, -textarea, -button, -select, -optgroup, -option, -keygen, -output, -meter, -progress { - font: inherit; - font-weight: normal; - color: #333; - background-color: #fff; - line-height: normal; - margin: 0; - vertical-align: middle; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; -} - -optgroup { - font-style: italic; - font-weight: bold; -} -option { - font-style: normal; - font-weight: normal; -} - -input, -textarea, -select, -keygen { - border: 1px solid #ccc; - box-shadow: inset 0 0 1px #eee; - border-radius: 2px; -} -input:active, -input:focus, -textarea:active, -textarea:focus, -select:active, -select:focus, -keygen:active, -keygen:focus { - border-color: #999; -} -input[type=radio], -input[type=checkbox], -input[type=image] { - padding: 0; - border-style: none; - box-shadow: none; -} - -/* all types of buttons */ -input[type=submit], -input[type=button], -input[type=reset], -input.button, -a.button, -button, -.qq-upload-button { - color: #333; - background-color: #eee; - background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPgo8bGluZWFyR3JhZGllbnQgaWQ9Imc4MjQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+CjxzdG9wIHN0b3AtY29sb3I9IiNGRkZGRkYiIG9mZnNldD0iMCIvPjxzdG9wIHN0b3AtY29sb3I9IiNGNEY0RjQiIG9mZnNldD0iMC4zIi8+PHN0b3Agc3RvcC1jb2xvcj0iI0VFRUVFRSIgb2Zmc2V0PSIwLjk5Ii8+PHN0b3Agc3RvcC1jb2xvcj0iI0NDQ0NDQyIgb2Zmc2V0PSIuOTkiLz4KPC9saW5lYXJHcmFkaWVudD4KPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNnODI0KSIgLz4KPC9zdmc+); - background: -moz-linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #eeeeee 99%, #cccccc 99%); - background: -webkit-linear-gradient(top, #ffffff 0%, #f4f4f4 30%, #eeeeee 99%, #cccccc 99%); - background: -o-linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #eeeeee 99%, #cccccc 99%); - background: -ms-linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #eeeeee 99%, #cccccc 99%); - background: linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #eeeeee 99%, #cccccc 99%); - border: 1px solid #ccc; - border-radius: 2px; - padding: .1em .5em; - cursor: pointer; -} -#IE7 input.button, -#IE7 button { - line-height: 1.4; - overflow: visible; -} - -input[type=submit]:hover, -input[type=submit]:active, -input[type=submit]:focus, -input[type=button]:hover, -input[type=button]:active, -input[type=button]:hover, -input[type=reset]:hover, -input[type=reset]:active, -input[type=reset]:hover, -input.button:hover, -input.button:active, -input.button:focus, -a.button:hover, -a.button:active, -a.button:focus, -button:hover, -button:active, -button:focus, -.qq-upload-button:hover { - border-color: #999; - background-color: #ddd; - background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPgo8bGluZWFyR3JhZGllbnQgaWQ9Imc2NzAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+CjxzdG9wIHN0b3AtY29sb3I9IiNGRkZGRkYiIG9mZnNldD0iMCIvPjxzdG9wIHN0b3AtY29sb3I9IiNGNEY0RjQiIG9mZnNldD0iMC4zIi8+PHN0b3Agc3RvcC1jb2xvcj0iI0RERERERCIgb2Zmc2V0PSIwLjk5Ii8+PHN0b3Agc3RvcC1jb2xvcj0iI0JCQkJCQiIgb2Zmc2V0PSIuOTkiLz4KPC9saW5lYXJHcmFkaWVudD4KPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNnNjcwKSIgLz4KPC9zdmc+); - background: -moz-linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #dddddd 99%, #bbbbbb 99%); - background: -webkit-linear-gradient(top, #ffffff 0%, #f4f4f4 30%, #dddddd 99%, #bbbbbb 99%); - background: -o-linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #dddddd 99%, #bbbbbb 99%); - background: -ms-linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #dddddd 99%, #bbbbbb 99%); - background: linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #dddddd 99%, #bbbbbb 99%); -} - -input::-moz-focus-inner, -button::-moz-focus-inner { - border: 0; - padding: 0; -} - -input[disabled], -button[disabled], -select[disabled], -textarea[disabled], -input[readonly], -button[readonly], -select[readonly], -textarea[readonly] { - cursor: auto; - opacity: .5; - background-color: #eee; -} diff --git a/lib/tpl/dokuwiki/css/basic.less b/lib/tpl/dokuwiki/css/basic.less new file mode 100644 index 000000000..1dd56813e --- /dev/null +++ b/lib/tpl/dokuwiki/css/basic.less @@ -0,0 +1,460 @@ +/** + * This file provides the most basic styles. + * + * If you integrate DokuWiki into another project, you might either + * want to integrate this file into the other project as well, or use + * the other project's basic CSS for DokuWiki instead of this one. + * + * @author Anika Henke + */ + +html { + overflow-x: auto; + overflow-y: scroll; +} +html, +body { + color: @ini_text; + background: @ini_background_site url(images/page-gradient.png) top left repeat-x; + margin: 0; + padding: 0; +} +body { + font: normal 87.5%/1.4 Arial, sans-serif; + /* default font size: 100% => 16px; 93.75% => 15px; 87.5% => 14px; 81.25% => 13px; 75% => 12px */ + -webkit-text-size-adjust: 100%; +} + + +/*____________ headers ____________*/ + +caption, +figcaption, +summary, +legend { + padding: 0; + margin: 0 0 .35em; + line-height: 1.2; +} +h1, +h2, +h3, +h4, +h5, +h6 { + font-weight: bold; + padding: 0; + line-height: 1.2; + clear: left; /* ideally 'both', but problems with toc */ +} +[dir=rtl] h1, +[dir=rtl] h2, +[dir=rtl] h3, +[dir=rtl] h4, +[dir=rtl] h5, +[dir=rtl] h6 { + clear: right; +} + +h1 { + font-size: 2em; + margin: 0 0 0.444em; +} +h2 { + font-size: 1.5em; + margin: 0 0 0.666em; +} +h3 { + font-size: 1.125em; + margin: 0 0 0.888em; +} +h4 { + font-size: 1em; + margin: 0 0 1.0em; +} +h5 { + font-size: .875em; + margin: 0 0 1.1428em; +} +h6 { + font-size: .75em; + margin: 0 0 1.333em; +} +/* bottom margin = 1 / font-size */ + + +/*____________ basic margins and paddings ____________*/ + +p, +ul, +ol, +dl, +pre, +table, +hr, +blockquote, +figure, +details, +fieldset, +address { + margin: 0 0 1.4em 0; /* bottom margin = line-height */ + padding: 0; +} + +div { + margin: 0; + padding: 0; +} + + +/*____________ lists ____________*/ + +ul, +ol { + padding: 0 0 0 1.5em; +} +[dir=rtl] ul, +[dir=rtl] ol { + padding: 0 1.5em 0 0; +} + +li, +dd { + padding: 0; + margin: 0 0 0 1.5em; +} +[dir=rtl] li, +[dir=rtl] dd { + margin: 0 1.5em 0 0; +} +dt { + font-weight: bold; + margin: 0; + padding: 0; +} + +li ul, +li ol, +li dl, +dl ul, +dl ol, +dl dl { + margin-bottom: 0; + padding: 0; +} +li li { + font-size: 100%; +} + +ul { list-style: square outside; } +ol { list-style: decimal outside; } +ol ol { list-style-type: lower-alpha; } +ol ol ol { list-style-type: upper-roman; } +ol ol ol ol { list-style-type: upper-alpha; } +ol ol ol ol ol { list-style-type: lower-roman; } + + +/*____________ tables ____________*/ + +table { + border-collapse: collapse; + empty-cells: show; + border-spacing: 0; + border: 1px solid @ini_border; +} + +caption { + caption-side: top; + text-align: left; +} +[dir=rtl] caption { + text-align: right; +} + +th, +td { + padding: .3em .5em; + margin: 0; + vertical-align: top; + border: 1px solid @ini_border; +} +th { + font-weight: bold; + background-color: @ini_background_alt; + text-align: left; +} +[dir=rtl] th { + text-align: right; +} + + +/*____________ links ____________*/ + +a { + outline: none; +} +a:link, +a:visited { + text-decoration: none; + color: @ini_link; +} +a:link:hover, +a:visited:hover, +a:link:focus, +a:visited:focus, +a:link:active, +a:visited:active { + text-decoration: underline; +} + + +/*____________ misc ____________*/ + +img { + border-width: 0; + vertical-align: middle; + color: #666; + background-color: transparent; + font-style: italic; + height: auto; +} +img, +object, +embed, +iframe, +video, +audio { + max-width: 100%; +} +#IE7 img, +#IE8 img, +button img { + max-width: none; +} + +hr { + border-top: solid @ini_border; + border-bottom: solid @ini_background; + border-width: 1px 0; + height: 0; + text-align: center; + clear: both; +} + +acronym, +abbr { + cursor: help; + border-bottom: 1px dotted; + font-style: normal; +} +em acronym, +em abbr { + font-style: italic; +} + +mark { + background-color: @ini_highlight; + color: inherit; +} + +pre, +code, +samp, +kbd { + font-family: Consolas, "Andale Mono WT", "Andale Mono", "Bitstream Vera Sans Mono", "Nimbus Mono L", Monaco, "Courier New", monospace; + /* same font stack should be used for ".dokuwiki table.diff td" in _diff.css */ + font-size: 1em; + direction: ltr; + text-align: left; + background-color: @ini_background_site; + color: @ini_text; + box-shadow: inset 0 0 .3em @ini_border; + border-radius: 2px; +} +pre { + overflow: auto; + word-wrap: normal; + border: 1px solid @ini_border; + border-radius: 2px; + box-shadow: inset 0 0 .5em @ini_border; + padding: .7em 1em; +} + +blockquote { + padding: 0 .5em; + border: solid @ini_border; + border-width: 0 0 0 .25em; +} +[dir=rtl] blockquote { + border-width: 0 .25em 0 0; +} +q:before, +q:after { + content: ''; +} + +sub, +sup { + font-size: .8em; + line-height: 1; +} +sub { + vertical-align: sub; +} +sup { + vertical-align: super; +} + +small { + font-size: .8em; +} + +/*____________ forms ____________*/ + +/* for all of the form styles, style.ini colours are not used on purpose (except for fieldset border) */ + +form { + display: inline; + margin: 0; + padding: 0; +} +fieldset { + padding: .7em 1em 0; + padding: .7rem 1rem; /* for those browsers understanding :last-child */ + border: 1px solid @ini_text_alt; +} +fieldset > :last-child { + margin-bottom: 0; +} +legend { + margin: 0; + padding: 0 .1em; +} +label { + vertical-align: middle; + cursor: pointer; +} + +input, +textarea, +button, +select, +optgroup, +option, +keygen, +output, +meter, +progress { + font: inherit; + font-weight: normal; + color: #333; + background-color: #fff; + line-height: normal; + margin: 0; + vertical-align: middle; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +optgroup { + font-style: italic; + font-weight: bold; +} +option { + font-style: normal; + font-weight: normal; +} + +input, +textarea, +select, +keygen { + border: 1px solid #ccc; + box-shadow: inset 0 0 1px #eee; + border-radius: 2px; +} +input:active, +input:focus, +textarea:active, +textarea:focus, +select:active, +select:focus, +keygen:active, +keygen:focus { + border-color: #999; +} +input[type=radio], +input[type=checkbox], +input[type=image] { + padding: 0; + border-style: none; + box-shadow: none; +} + +/* all types of buttons */ +input[type=submit], +input[type=button], +input[type=reset], +input.button, +a.button, +button, +.qq-upload-button { + color: #333; + background-color: #eee; + background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPgo8bGluZWFyR3JhZGllbnQgaWQ9Imc4MjQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+CjxzdG9wIHN0b3AtY29sb3I9IiNGRkZGRkYiIG9mZnNldD0iMCIvPjxzdG9wIHN0b3AtY29sb3I9IiNGNEY0RjQiIG9mZnNldD0iMC4zIi8+PHN0b3Agc3RvcC1jb2xvcj0iI0VFRUVFRSIgb2Zmc2V0PSIwLjk5Ii8+PHN0b3Agc3RvcC1jb2xvcj0iI0NDQ0NDQyIgb2Zmc2V0PSIuOTkiLz4KPC9saW5lYXJHcmFkaWVudD4KPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNnODI0KSIgLz4KPC9zdmc+); + .linear-gradient("top, #ffffff 0%, #f4f4f4 30%, #eeeeee 99%, #cccccc 99%"); + border: 1px solid #ccc; + border-radius: 2px; + padding: .1em .5em; + cursor: pointer; +} +#IE7 input.button, +#IE7 button { + line-height: 1.4; + overflow: visible; +} + +input[type=submit]:hover, +input[type=submit]:active, +input[type=submit]:focus, +input[type=button]:hover, +input[type=button]:active, +input[type=button]:hover, +input[type=reset]:hover, +input[type=reset]:active, +input[type=reset]:hover, +input.button:hover, +input.button:active, +input.button:focus, +a.button:hover, +a.button:active, +a.button:focus, +button:hover, +button:active, +button:focus, +.qq-upload-button:hover { + border-color: #999; + background-color: #ddd; + background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPgo8bGluZWFyR3JhZGllbnQgaWQ9Imc2NzAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+CjxzdG9wIHN0b3AtY29sb3I9IiNGRkZGRkYiIG9mZnNldD0iMCIvPjxzdG9wIHN0b3AtY29sb3I9IiNGNEY0RjQiIG9mZnNldD0iMC4zIi8+PHN0b3Agc3RvcC1jb2xvcj0iI0RERERERCIgb2Zmc2V0PSIwLjk5Ii8+PHN0b3Agc3RvcC1jb2xvcj0iI0JCQkJCQiIgb2Zmc2V0PSIuOTkiLz4KPC9saW5lYXJHcmFkaWVudD4KPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNnNjcwKSIgLz4KPC9zdmc+); + .linear-gradient("top, #ffffff 0%, #f4f4f4 30%, #dddddd 99%, #bbbbbb 99%"); +} + +input::-moz-focus-inner, +button::-moz-focus-inner { + border: 0; + padding: 0; +} + +input[disabled], +button[disabled], +select[disabled], +textarea[disabled], +input[readonly], +button[readonly], +select[readonly], +textarea[readonly] { + cursor: auto; + opacity: .5; + background-color: #eee; +} diff --git a/lib/tpl/dokuwiki/css/content.less b/lib/tpl/dokuwiki/css/content.less index f6022b4e9..ae97d7d5e 100644 --- a/lib/tpl/dokuwiki/css/content.less +++ b/lib/tpl/dokuwiki/css/content.less @@ -122,7 +122,8 @@ .dokuwiki dl.file { dt, dt { - .linear-gradient(@ini_background_site, @ini_background_alt, @ini_background_site); + background-color: @ini_background_site; + .linear-gradient(~"top, @{ini_background_alt} 0%, @{ini_background_site} 100%"); color: inherit; border: 1px solid @ini_border; border-bottom-color: @ini_background_site; diff --git a/lib/tpl/dokuwiki/css/includes.css b/lib/tpl/dokuwiki/css/includes.css deleted file mode 100644 index bc189962f..000000000 --- a/lib/tpl/dokuwiki/css/includes.css +++ /dev/null @@ -1,4 +0,0 @@ -/** - * This file provides styles for included seperate html files - * (added through "include hooks"). - */ diff --git a/lib/tpl/dokuwiki/css/mixins.less b/lib/tpl/dokuwiki/css/mixins.less index 7ecae4a0b..a88767e97 100644 --- a/lib/tpl/dokuwiki/css/mixins.less +++ b/lib/tpl/dokuwiki/css/mixins.less @@ -1,15 +1,10 @@ /** * linear gradient x-browser support - * - * @param color fallback background color - * @param start start color - * @param stop end color */ -.linear-gradient(@color: #F5F5F5, @start: #EEE, @stop: #FFF) { - background: @color; - background: -moz-linear-gradient( top, @start 0%, @stop 100%); - background: -webkit-linear-gradient(top, @start 0%, @stop 100%); - background: -o-linear-gradient( top, @start 0%, @stop 100%); - background: -ms-linear-gradient( top, @start 0%, @stop 100%); - background: linear-gradient( top, @start 0%, @stop 100%); +.linear-gradient(@declaration: 0) { + background: -moz-linear-gradient( @declaration); + background: -webkit-linear-gradient(@declaration); + background: -o-linear-gradient( @declaration); + background: -ms-linear-gradient( @declaration); + background: linear-gradient( @declaration); } \ No newline at end of file diff --git a/lib/tpl/dokuwiki/css/mobile.css b/lib/tpl/dokuwiki/css/mobile.css deleted file mode 100644 index 71f80599d..000000000 --- a/lib/tpl/dokuwiki/css/mobile.css +++ /dev/null @@ -1,288 +0,0 @@ -/** - * This file provides styles for mobile devices - * and smaller screens (up to 480px and 768px width). - * - * @author Anika Henke - */ - -/* for detecting media queries in JavaScript (see script.js): */ -#screen__mode { - position: relative; - z-index: 0; -} - -/* for screen widths in the tablet range -********************************************************************/ -@media only screen and (max-width: __tablet_width__) { - -#screen__mode { - z-index: 1; /* for detecting media queries in JavaScript (see script.js) */ -} - -/* structure */ -#dokuwiki__aside { - width: 100%; - float: none; -} - -#dokuwiki__aside > .pad, -[dir=rtl] #dokuwiki__aside > .pad { - margin: 0 0 .5em; - /* style like .page */ - background: __background__; - color: inherit; - border: 1px solid #eee; - box-shadow: 0 0 .5em __text_alt__; - border-radius: 2px; - padding: 1em; - margin-bottom: .5em; -} - -#dokuwiki__aside h3.toggle { - font-size: 1em; -} -#dokuwiki__aside h3.toggle.closed { - margin-bottom: 0; - padding-bottom: 0; -} -#dokuwiki__aside h3.toggle.open { - border-bottom: 1px solid __border__; -} - -.showSidebar #dokuwiki__content { - float: none; - margin-left: 0; - width: 100%; -} -.showSidebar #dokuwiki__content > .pad { - margin-left: 0; -} - -[dir=rtl] .showSidebar #dokuwiki__content, -[dir=rtl] .showSidebar #dokuwiki__content > .pad { - margin-right: 0; -} - -/* toc */ -#dw__toc { - float: none; - margin: 0 0 1em 0; - width: auto; - border-left-width: 0; - border-bottom: 1px solid __border__; -} -[dir=rtl] #dw__toc { - float: none; - margin: 0 0 1em 0; - border-right-width: 0; -} - -.dokuwiki h3.toggle { - padding: 0 .5em .5em 0; -} -#dw__toc > div, -#dokuwiki__aside div.content { - padding: .2em 0 .5em; -} - -/* page */ -.dokuwiki div.page { - padding: 1em; -} -/* enable horizontal scrolling in media manager */ -.mode_media div.page { - overflow: auto; -} - -/* _edit */ -.dokuwiki div.section_highlight { - margin: 0 -1em; - padding: 0 .5em; - border-width: 0 .5em; -} -.dokuwiki div.preview { - margin: 0 -1em; - padding: 1em; -} - -/* _recent */ -.dokuwiki form.changes ul { - padding-left: 0; -} -[dir=rtl] .dokuwiki form.changes ul { - padding-right: 0; -} - - -} /* /@media */ - - -/* for screen widths in the smartphone range -********************************************************************/ -@media only screen and (max-width: __phone_width__) { - -#screen__mode { - z-index: 2; /* for detecting media queries in JavaScript (see script.js) */ -} - -body { - font-size: 100%; -} - -/*____________ structure ____________*/ - -#dokuwiki__site { - max-width: 100%; -} -#dokuwiki__site > .site { - padding: 0 .5em; -} -#dokuwiki__header { - padding: .5em 0; -} - - -/*____________ header ____________*/ - -#dokuwiki__header ul.a11y.skip { - position: static !important; - left: 0 !important; - width: auto !important; - height: auto !important; - float: right; - font-size: 0.875em; - list-style: none; - padding-left: 0; - margin: 0; -} -[dir=rtl] #dokuwiki__header ul.a11y.skip { - left: auto !important; - right: 0 !important; - float: left; - padding-right: 0; -} -#dokuwiki__header ul.a11y.skip li { - margin-left: .35em; - display: inline; -} -[dir=rtl] #dokuwiki__header ul.a11y.skip li { - margin: 0 .35em 0 0; -} - -#dokuwiki__header .headings, -#dokuwiki__header .tools { - float: none; - text-align: left; - width: auto; - margin-bottom: .5em; -} -[dir=rtl] #dokuwiki__header .headings, -[dir=rtl] #dokuwiki__header .tools { - float: none; - text-align: right; - width: auto; -} -#dokuwiki__sitetools { - text-align: left; -} -[dir=rtl] #dokuwiki__sitetools { - text-align: right; -} -#dokuwiki__usertools, -#dokuwiki__sitetools ul, -#dokuwiki__sitetools h3, -#dokuwiki__pagetools, -.dokuwiki div.breadcrumbs, /* @todo: maybe move breadcrumbs to the bottom? */ -.dokuwiki .pageId { - display: none; -} - -/* search form */ -#dokuwiki__sitetools form.search { - float: left; - margin: 0 .2em .2em 0; - width: 49%; -} -[dir=rtl] #dokuwiki__sitetools form.search { - float: right; - margin: 0 0 .2em .2em; -} - -#dokuwiki__sitetools form.search input.edit { - width: 100% !important; -} -.dokuwiki form.search div.ajax_qsearch { - display: none !important; -} - -/* action dropdown is alternative for all hidden tools */ -#dokuwiki__header .mobileTools { - display: block; - font-size: 0.875em; - margin: 0 0 .2em 0; - float: right; - width: 49%; -} -[dir=rtl] #dokuwiki__header .mobileTools { - float: left; -} -#dokuwiki__header .mobileTools select { - padding: .3em .1em; - width: 100% !important; -} - -/* force same height on search input and tools select */ -#dokuwiki__sitetools form.search input.edit, -#dokuwiki__header .mobileTools select { - height: 2.1em; - line-height: 2.1em; - overflow: visible; -} - - -/*____________ content ____________*/ - -#dokuwiki__aside > .pad, -.dokuwiki div.page { - padding: .5em; -} - -/* form elements */ -#config__manager fieldset td.value, -#config__manager td .input, -.dokuwiki fieldset, -.dokuwiki input.edit, -.dokuwiki textarea, -.dokuwiki select { - width: auto !important; - max-width: 100% !important; -} -#config__manager fieldset { - margin-left: 0; - margin-right: 0; -} - -.dokuwiki label.block { - text-align: left; -} -[dir=rtl] .dokuwiki label.block { - text-align: right; -} -.dokuwiki label.block span { - display: block; -} - -/* _edit */ -.dokuwiki div.section_highlight { - margin: 0; - padding: 0; - border-width: 0; -} -.dokuwiki div.preview { - margin: 0 -.5em; - padding: .5em; -} - - - -} /* /@media */ diff --git a/lib/tpl/dokuwiki/css/mobile.less b/lib/tpl/dokuwiki/css/mobile.less new file mode 100644 index 000000000..4362656a1 --- /dev/null +++ b/lib/tpl/dokuwiki/css/mobile.less @@ -0,0 +1,288 @@ +/** + * This file provides styles for mobile devices + * and smaller screens (up to 480px and 768px width). + * + * @author Anika Henke + */ + +/* for detecting media queries in JavaScript (see script.js): */ +#screen__mode { + position: relative; + z-index: 0; +} + +/* for screen widths in the tablet range +********************************************************************/ +@media only screen and (max-width: @ini_tablet_width) { + +#screen__mode { + z-index: 1; /* for detecting media queries in JavaScript (see script.js) */ +} + +/* structure */ +#dokuwiki__aside { + width: 100%; + float: none; +} + +#dokuwiki__aside > .pad, +[dir=rtl] #dokuwiki__aside > .pad { + margin: 0 0 .5em; + /* style like .page */ + background: @ini_background; + color: inherit; + border: 1px solid #eee; + box-shadow: 0 0 .5em @ini_text_alt; + border-radius: 2px; + padding: 1em; + margin-bottom: .5em; +} + +#dokuwiki__aside h3.toggle { + font-size: 1em; +} +#dokuwiki__aside h3.toggle.closed { + margin-bottom: 0; + padding-bottom: 0; +} +#dokuwiki__aside h3.toggle.open { + border-bottom: 1px solid @ini_border; +} + +.showSidebar #dokuwiki__content { + float: none; + margin-left: 0; + width: 100%; +} +.showSidebar #dokuwiki__content > .pad { + margin-left: 0; +} + +[dir=rtl] .showSidebar #dokuwiki__content, +[dir=rtl] .showSidebar #dokuwiki__content > .pad { + margin-right: 0; +} + +/* toc */ +#dw__toc { + float: none; + margin: 0 0 1em 0; + width: auto; + border-left-width: 0; + border-bottom: 1px solid @ini_border; +} +[dir=rtl] #dw__toc { + float: none; + margin: 0 0 1em 0; + border-right-width: 0; +} + +.dokuwiki h3.toggle { + padding: 0 .5em .5em 0; +} +#dw__toc > div, +#dokuwiki__aside div.content { + padding: .2em 0 .5em; +} + +/* page */ +.dokuwiki div.page { + padding: 1em; +} +/* enable horizontal scrolling in media manager */ +.mode_media div.page { + overflow: auto; +} + +/* _edit */ +.dokuwiki div.section_highlight { + margin: 0 -1em; + padding: 0 .5em; + border-width: 0 .5em; +} +.dokuwiki div.preview { + margin: 0 -1em; + padding: 1em; +} + +/* _recent */ +.dokuwiki form.changes ul { + padding-left: 0; +} +[dir=rtl] .dokuwiki form.changes ul { + padding-right: 0; +} + + +} /* /@media */ + + +/* for screen widths in the smartphone range +********************************************************************/ +@media only screen and (max-width: @ini_phone_width) { + +#screen__mode { + z-index: 2; /* for detecting media queries in JavaScript (see script.js) */ +} + +body { + font-size: 100%; +} + +/*____________ structure ____________*/ + +#dokuwiki__site { + max-width: 100%; +} +#dokuwiki__site > .site { + padding: 0 .5em; +} +#dokuwiki__header { + padding: .5em 0; +} + + +/*____________ header ____________*/ + +#dokuwiki__header ul.a11y.skip { + position: static !important; + left: 0 !important; + width: auto !important; + height: auto !important; + float: right; + font-size: 0.875em; + list-style: none; + padding-left: 0; + margin: 0; +} +[dir=rtl] #dokuwiki__header ul.a11y.skip { + left: auto !important; + right: 0 !important; + float: left; + padding-right: 0; +} +#dokuwiki__header ul.a11y.skip li { + margin-left: .35em; + display: inline; +} +[dir=rtl] #dokuwiki__header ul.a11y.skip li { + margin: 0 .35em 0 0; +} + +#dokuwiki__header .headings, +#dokuwiki__header .tools { + float: none; + text-align: left; + width: auto; + margin-bottom: .5em; +} +[dir=rtl] #dokuwiki__header .headings, +[dir=rtl] #dokuwiki__header .tools { + float: none; + text-align: right; + width: auto; +} +#dokuwiki__sitetools { + text-align: left; +} +[dir=rtl] #dokuwiki__sitetools { + text-align: right; +} +#dokuwiki__usertools, +#dokuwiki__sitetools ul, +#dokuwiki__sitetools h3, +#dokuwiki__pagetools, +.dokuwiki div.breadcrumbs, /* @todo: maybe move breadcrumbs to the bottom? */ +.dokuwiki .pageId { + display: none; +} + +/* search form */ +#dokuwiki__sitetools form.search { + float: left; + margin: 0 .2em .2em 0; + width: 49%; +} +[dir=rtl] #dokuwiki__sitetools form.search { + float: right; + margin: 0 0 .2em .2em; +} + +#dokuwiki__sitetools form.search input.edit { + width: 100% !important; +} +.dokuwiki form.search div.ajax_qsearch { + display: none !important; +} + +/* action dropdown is alternative for all hidden tools */ +#dokuwiki__header .mobileTools { + display: block; + font-size: 0.875em; + margin: 0 0 .2em 0; + float: right; + width: 49%; +} +[dir=rtl] #dokuwiki__header .mobileTools { + float: left; +} +#dokuwiki__header .mobileTools select { + padding: .3em .1em; + width: 100% !important; +} + +/* force same height on search input and tools select */ +#dokuwiki__sitetools form.search input.edit, +#dokuwiki__header .mobileTools select { + height: 2.1em; + line-height: 2.1em; + overflow: visible; +} + + +/*____________ content ____________*/ + +#dokuwiki__aside > .pad, +.dokuwiki div.page { + padding: .5em; +} + +/* form elements */ +#config__manager fieldset td.value, +#config__manager td .input, +.dokuwiki fieldset, +.dokuwiki input.edit, +.dokuwiki textarea, +.dokuwiki select { + width: auto !important; + max-width: 100% !important; +} +#config__manager fieldset { + margin-left: 0; + margin-right: 0; +} + +.dokuwiki label.block { + text-align: left; +} +[dir=rtl] .dokuwiki label.block { + text-align: right; +} +.dokuwiki label.block span { + display: block; +} + +/* _edit */ +.dokuwiki div.section_highlight { + margin: 0; + padding: 0; + border-width: 0; +} +.dokuwiki div.preview { + margin: 0 -.5em; + padding: .5em; +} + + + +} /* /@media */ diff --git a/lib/tpl/dokuwiki/css/pagetools.css b/lib/tpl/dokuwiki/css/pagetools.css deleted file mode 100644 index 21e5c13ec..000000000 --- a/lib/tpl/dokuwiki/css/pagetools.css +++ /dev/null @@ -1,421 +0,0 @@ -/** - * This file provides the styles for the page tools - * (fly out navigation beside the page to edit, etc). - * - * @author Anika Henke - * @author Andreas Gohr - */ - -#dokuwiki__site > .site { - /* give space to the right so the tools won't disappear on smaller screens */ - /* it's 40px because the 30px wide icons will have 5px more spacing to the left and right */ - padding-right: 40px; - /* give the same space to the left to balance it out */ - padding-left: 40px; -} -.dokuwiki div.page { - height: 190px; - min-height: 190px; /* 30 (= height of icons) x 6 (= maximum number of possible tools) + 2x5 */ - height: auto; -} -#dokuwiki__usertools { - /* move the tools just outside of the site */ - right: 40px; -} -[dir=rtl] #dokuwiki__usertools { - right: auto; - left: 40px; -} - - -#dokuwiki__pagetools { - position: absolute; - right: -40px; - /* on same vertical level as first headline, because .page has 2em padding */ - top: 2em; - width: 40px; -} -[dir=rtl] #dokuwiki__pagetools { - right: auto; - left: -40px; -} - -#dokuwiki__pagetools div.tools { - position: fixed; - width: 40px; -} - -#dokuwiki__pagetools ul { - position: absolute; - right: 0; - text-align: right; - margin: 0; - padding: 0; - /* add transparent border to prevent jumping when proper border is added on hover */ - border: 1px solid transparent; - z-index: 10; -} -[dir=rtl] #dokuwiki__pagetools ul { - right: auto; - left: 0; - text-align: left; -} - -#dokuwiki__pagetools ul li { - padding: 0; - margin: 0; - list-style: none; - font-size: 0.875em; -} - -#dokuwiki__pagetools ul li a { - display: block; - min-height: 20px; /* 30 - 2x5 */ - line-height: 20px; - padding: 0; - background-position: right 0; - background-repeat: no-repeat; - /* add transparent border to prevent jumping when proper border is added on focus */ - border: 1px solid transparent; - white-space: nowrap; - width: 30px; - height: 30px; - overflow: hidden; - margin-left: auto; /* align right if the ul is larger because one item is focused */ -} - -#dokuwiki__pagetools ul li a:before { - content: url(images/pagetools-sprite.png); - display: inline-block; - font-size: 0; - line-height: 0; -} - -[dir=rtl] #dokuwiki__pagetools ul li a { - background-position: left 0; - margin-right: auto; - margin-left: 0; -} - -/* show all tools on hover and individual tools on focus */ -#dokuwiki__pagetools:hover ul, -#dokuwiki__pagetools ul li a:focus, -#dokuwiki__pagetools ul li a:active { - background-color: __background__; - border-color: __border__; - border-radius: 2px; - box-shadow: 2px 2px 2px __text_alt__; -} - -#dokuwiki__pagetools:hover ul li a, -#dokuwiki__pagetools ul li a:focus, -#dokuwiki__pagetools ul li a:active { - width: auto; - height: auto; - overflow: visible; - padding: 5px 40px 5px 5px; - background-image: url(images/pagetools-sprite.png); -} - -#dokuwiki__pagetools:hover ul li a:before, -#dokuwiki__pagetools ul li a:focus:before { - content: none; -} - -[dir=rtl] #dokuwiki__pagetools:hover ul, -[dir=rtl] #dokuwiki__pagetools ul li a:focus { - box-shadow: -2px 2px 2px __text_alt__; -} - -[dir=rtl] #dokuwiki__pagetools:hover li a, -[dir=rtl] #dokuwiki__pagetools ul li a:focus, -[dir=rtl] #dokuwiki__pagetools ul li a:active { - padding: 5px 5px 5px 40px; -} - -/* IE7 fixes, doesn't work without images */ - -#IE7 #dokuwiki__pagetools ul li a { - background-image: url(images/pagetools-sprite.png); -} - -#IE7 #dokuwiki__pagetools:hover ul li a span, -#IE7 #dokuwiki__pagetools ul li a:focus span, -#IE7 #dokuwiki__pagetools ul li a:active span { - clip: auto; - display: inline; - position: static; -} - -#IE7 #dokuwiki__pagetools ul li a span { - clip: rect(0 0 0 0); - position: absolute; -} - -#dokuwiki__pagetools ul li a:hover, -#dokuwiki__pagetools ul li a:active, -#dokuwiki__pagetools ul li a:focus { - text-decoration: none; -} -#dokuwiki__pagetools ul li a:hover { - background-color: __background_alt__; -} - -/*____________ all available icons in sprite ____________*/ - -#dokuwiki__pagetools ul li a.edit { - background-position: right 0; -} -#dokuwiki__pagetools ul li a.edit:hover, -#dokuwiki__pagetools ul li a.edit:active, -#dokuwiki__pagetools ul li a.edit:focus { - background-position: right -45px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.edit { - background-position: left 0; -} -[dir=rtl] #dokuwiki__pagetools ul li a.edit:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.edit:active, -[dir=rtl] #dokuwiki__pagetools ul li a.edit:focus { - background-position: left -45px; -} - -#dokuwiki__pagetools ul li a.create:before { - margin-top: -90px; -} -#dokuwiki__pagetools ul li a.create { - background-position: right -90px; -} -#dokuwiki__pagetools ul li a.create:hover, -#dokuwiki__pagetools ul li a.create:active, -#dokuwiki__pagetools ul li a.create:focus { - background-position: right -135px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.create { - background-position: left -90px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.create:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.create:active, -[dir=rtl] #dokuwiki__pagetools ul li a.create:focus { - background-position: left -135px; -} - -#dokuwiki__pagetools ul li a.show { - background-position: right -270px; -} -#dokuwiki__pagetools ul li a.show:before { - margin-top: -270px; -} -#dokuwiki__pagetools ul li a.show:hover, -#dokuwiki__pagetools ul li a.show:active, -#dokuwiki__pagetools ul li a.show:focus { - background-position: right -315px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.show { - background-position: left -270px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.show:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.show:active, -[dir=rtl] #dokuwiki__pagetools ul li a.show:focus { - background-position: left -315px; -} - -#dokuwiki__pagetools ul li a.source { - background-position: right -360px; -} -#dokuwiki__pagetools ul li a.source:before { - margin-top: -360px; -} -#dokuwiki__pagetools ul li a.source:hover, -#dokuwiki__pagetools ul li a.source:active, -#dokuwiki__pagetools ul li a.source:focus { - background-position: right -405px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.source { - background-position: left -360px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.source:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.source:active, -[dir=rtl] #dokuwiki__pagetools ul li a.source:focus { - background-position: left -405px; -} - -#dokuwiki__pagetools ul li a.draft { - background-position: right -180px; -} -#dokuwiki__pagetools ul li a.draft:before { - margin-top: -180px; -} -#dokuwiki__pagetools ul li a.draft:hover, -#dokuwiki__pagetools ul li a.draft:active, -#dokuwiki__pagetools ul li a.draft:focus { - background-position: right -225px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.draft { - background-position: left -180px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.draft:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.draft:active, -[dir=rtl] #dokuwiki__pagetools ul li a.draft:focus { - background-position: left -225px; -} - -#dokuwiki__pagetools ul li a.revs { - background-position: right -540px; -} -#dokuwiki__pagetools ul li a.revs:before { - margin-top: -540px; -} -#dokuwiki__pagetools ul li a.revs:hover, -#dokuwiki__pagetools ul li a.revs:active, -#dokuwiki__pagetools ul li a.revs:focus, -.mode_revisions #dokuwiki__pagetools ul li a.revs { - background-position: right -585px; -} -.mode_revisions #dokuwiki__pagetools ul li a.revs:before { - margin-top: -585px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.revs { - background-position: left -540px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.revs:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.revs:active, -[dir=rtl] #dokuwiki__pagetools ul li a.revs:focus, -[dir=rtl] .mode_revisions #dokuwiki__pagetools ul li a.revs { - background-position: left -585px; -} - -#dokuwiki__pagetools ul li a.backlink { - background-position: right -630px; -} -#dokuwiki__pagetools ul li a.backlink:before { - margin-top: -630px; -} -#dokuwiki__pagetools ul li a.backlink:hover, -#dokuwiki__pagetools ul li a.backlink:active, -#dokuwiki__pagetools ul li a.backlink:focus, -.mode_backlink #dokuwiki__pagetools ul li a.backlink { - background-position: right -675px; -} -.mode_backlink #dokuwiki__pagetools ul li a.backlink:before { - margin-top: -675px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.backlink { - background-position: left -630px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.backlink:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.backlink:active, -[dir=rtl] #dokuwiki__pagetools ul li a.backlink:focus, -[dir=rtl] .mode_backlink #dokuwiki__pagetools ul li a.backlink { - background-position: left -675px; -} - -#dokuwiki__pagetools ul li a.top { - background-position: right -810px; -} -#dokuwiki__pagetools ul li a.top:before{ - margin-top: -810px; -} -#dokuwiki__pagetools ul li a.top:hover, -#dokuwiki__pagetools ul li a.top:active, -#dokuwiki__pagetools ul li a.top:focus { - background-position: right -855px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.top { - background-position: left -810px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.top:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.top:active, -[dir=rtl] #dokuwiki__pagetools ul li a.top:focus { - background-position: left -855px; -} - -#dokuwiki__pagetools ul li a.revert { - background-position: right -450px; -} -#dokuwiki__pagetools ul li a.revert:before { - margin-top: -450px; -} -#dokuwiki__pagetools ul li a.revert:hover, -#dokuwiki__pagetools ul li a.revert:active, -#dokuwiki__pagetools ul li a.revert:focus, -.mode_revert #dokuwiki__pagetools ul li a.revert { - background-position: right -495px; -} -.mode_revert #dokuwiki__pagetools ul li a.revert:before { - margin-top: -450px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.revert { - background-position: left -450px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.revert:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.revert:active, -[dir=rtl] #dokuwiki__pagetools ul li a.revert:focus, -[dir=rtl] .mode_revert #dokuwiki__pagetools ul li a.revert { - background-position: left -495px; -} - -#dokuwiki__pagetools ul li a.subscribe { - background-position: right -720px; -} -#dokuwiki__pagetools ul li a.subscribe:before { - margin-top: -720px; -} -#dokuwiki__pagetools ul li a.subscribe:hover, -#dokuwiki__pagetools ul li a.subscribe:active, -#dokuwiki__pagetools ul li a.subscribe:focus, -.mode_subscribe #dokuwiki__pagetools ul li a.subscribe { - background-position: right -765px; -} -.mode_subscribe #dokuwiki__pagetools ul li a.subscribe:before { - margin-top: -765px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.subscribe { - background-position: left -720px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.subscribe:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.subscribe:active, -[dir=rtl] #dokuwiki__pagetools ul li a.subscribe:focus, -[dir=rtl] .mode_subscribe #dokuwiki__pagetools ul li a.subscribe { - background-position: left -765px; -} - -#dokuwiki__pagetools ul li a.mediaManager { - background-position: right -900px; -} -#dokuwiki__pagetools ul li a.mediaManager:before { - margin-top: -900px; -} -#dokuwiki__pagetools ul li a.mediaManager:hover, -#dokuwiki__pagetools ul li a.mediaManager:active, -#dokuwiki__pagetools ul li a.mediaManager:focus { - background-position: right -945px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.mediaManager { - background-position: left -900px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.mediaManager:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.mediaManager:active, -[dir=rtl] #dokuwiki__pagetools ul li a.mediaManager:focus { - background-position: left -945px; -} - -#dokuwiki__pagetools ul li a.back { - background-position: right -990px; -} -#dokuwiki__pagetools ul li a.back { - margin-top: -990px; -} -#dokuwiki__pagetools ul li a.back:hover, -#dokuwiki__pagetools ul li a.back:active, -#dokuwiki__pagetools ul li a.back:focus { - background-position: right -1035px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.back { - background-position: left -990px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.back:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.back:active, -[dir=rtl] #dokuwiki__pagetools ul li a.back:focus { - background-position: left -1035px; -} diff --git a/lib/tpl/dokuwiki/css/pagetools.less b/lib/tpl/dokuwiki/css/pagetools.less new file mode 100644 index 000000000..21e5c13ec --- /dev/null +++ b/lib/tpl/dokuwiki/css/pagetools.less @@ -0,0 +1,421 @@ +/** + * This file provides the styles for the page tools + * (fly out navigation beside the page to edit, etc). + * + * @author Anika Henke + * @author Andreas Gohr + */ + +#dokuwiki__site > .site { + /* give space to the right so the tools won't disappear on smaller screens */ + /* it's 40px because the 30px wide icons will have 5px more spacing to the left and right */ + padding-right: 40px; + /* give the same space to the left to balance it out */ + padding-left: 40px; +} +.dokuwiki div.page { + height: 190px; + min-height: 190px; /* 30 (= height of icons) x 6 (= maximum number of possible tools) + 2x5 */ + height: auto; +} +#dokuwiki__usertools { + /* move the tools just outside of the site */ + right: 40px; +} +[dir=rtl] #dokuwiki__usertools { + right: auto; + left: 40px; +} + + +#dokuwiki__pagetools { + position: absolute; + right: -40px; + /* on same vertical level as first headline, because .page has 2em padding */ + top: 2em; + width: 40px; +} +[dir=rtl] #dokuwiki__pagetools { + right: auto; + left: -40px; +} + +#dokuwiki__pagetools div.tools { + position: fixed; + width: 40px; +} + +#dokuwiki__pagetools ul { + position: absolute; + right: 0; + text-align: right; + margin: 0; + padding: 0; + /* add transparent border to prevent jumping when proper border is added on hover */ + border: 1px solid transparent; + z-index: 10; +} +[dir=rtl] #dokuwiki__pagetools ul { + right: auto; + left: 0; + text-align: left; +} + +#dokuwiki__pagetools ul li { + padding: 0; + margin: 0; + list-style: none; + font-size: 0.875em; +} + +#dokuwiki__pagetools ul li a { + display: block; + min-height: 20px; /* 30 - 2x5 */ + line-height: 20px; + padding: 0; + background-position: right 0; + background-repeat: no-repeat; + /* add transparent border to prevent jumping when proper border is added on focus */ + border: 1px solid transparent; + white-space: nowrap; + width: 30px; + height: 30px; + overflow: hidden; + margin-left: auto; /* align right if the ul is larger because one item is focused */ +} + +#dokuwiki__pagetools ul li a:before { + content: url(images/pagetools-sprite.png); + display: inline-block; + font-size: 0; + line-height: 0; +} + +[dir=rtl] #dokuwiki__pagetools ul li a { + background-position: left 0; + margin-right: auto; + margin-left: 0; +} + +/* show all tools on hover and individual tools on focus */ +#dokuwiki__pagetools:hover ul, +#dokuwiki__pagetools ul li a:focus, +#dokuwiki__pagetools ul li a:active { + background-color: __background__; + border-color: __border__; + border-radius: 2px; + box-shadow: 2px 2px 2px __text_alt__; +} + +#dokuwiki__pagetools:hover ul li a, +#dokuwiki__pagetools ul li a:focus, +#dokuwiki__pagetools ul li a:active { + width: auto; + height: auto; + overflow: visible; + padding: 5px 40px 5px 5px; + background-image: url(images/pagetools-sprite.png); +} + +#dokuwiki__pagetools:hover ul li a:before, +#dokuwiki__pagetools ul li a:focus:before { + content: none; +} + +[dir=rtl] #dokuwiki__pagetools:hover ul, +[dir=rtl] #dokuwiki__pagetools ul li a:focus { + box-shadow: -2px 2px 2px __text_alt__; +} + +[dir=rtl] #dokuwiki__pagetools:hover li a, +[dir=rtl] #dokuwiki__pagetools ul li a:focus, +[dir=rtl] #dokuwiki__pagetools ul li a:active { + padding: 5px 5px 5px 40px; +} + +/* IE7 fixes, doesn't work without images */ + +#IE7 #dokuwiki__pagetools ul li a { + background-image: url(images/pagetools-sprite.png); +} + +#IE7 #dokuwiki__pagetools:hover ul li a span, +#IE7 #dokuwiki__pagetools ul li a:focus span, +#IE7 #dokuwiki__pagetools ul li a:active span { + clip: auto; + display: inline; + position: static; +} + +#IE7 #dokuwiki__pagetools ul li a span { + clip: rect(0 0 0 0); + position: absolute; +} + +#dokuwiki__pagetools ul li a:hover, +#dokuwiki__pagetools ul li a:active, +#dokuwiki__pagetools ul li a:focus { + text-decoration: none; +} +#dokuwiki__pagetools ul li a:hover { + background-color: __background_alt__; +} + +/*____________ all available icons in sprite ____________*/ + +#dokuwiki__pagetools ul li a.edit { + background-position: right 0; +} +#dokuwiki__pagetools ul li a.edit:hover, +#dokuwiki__pagetools ul li a.edit:active, +#dokuwiki__pagetools ul li a.edit:focus { + background-position: right -45px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.edit { + background-position: left 0; +} +[dir=rtl] #dokuwiki__pagetools ul li a.edit:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.edit:active, +[dir=rtl] #dokuwiki__pagetools ul li a.edit:focus { + background-position: left -45px; +} + +#dokuwiki__pagetools ul li a.create:before { + margin-top: -90px; +} +#dokuwiki__pagetools ul li a.create { + background-position: right -90px; +} +#dokuwiki__pagetools ul li a.create:hover, +#dokuwiki__pagetools ul li a.create:active, +#dokuwiki__pagetools ul li a.create:focus { + background-position: right -135px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.create { + background-position: left -90px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.create:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.create:active, +[dir=rtl] #dokuwiki__pagetools ul li a.create:focus { + background-position: left -135px; +} + +#dokuwiki__pagetools ul li a.show { + background-position: right -270px; +} +#dokuwiki__pagetools ul li a.show:before { + margin-top: -270px; +} +#dokuwiki__pagetools ul li a.show:hover, +#dokuwiki__pagetools ul li a.show:active, +#dokuwiki__pagetools ul li a.show:focus { + background-position: right -315px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.show { + background-position: left -270px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.show:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.show:active, +[dir=rtl] #dokuwiki__pagetools ul li a.show:focus { + background-position: left -315px; +} + +#dokuwiki__pagetools ul li a.source { + background-position: right -360px; +} +#dokuwiki__pagetools ul li a.source:before { + margin-top: -360px; +} +#dokuwiki__pagetools ul li a.source:hover, +#dokuwiki__pagetools ul li a.source:active, +#dokuwiki__pagetools ul li a.source:focus { + background-position: right -405px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.source { + background-position: left -360px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.source:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.source:active, +[dir=rtl] #dokuwiki__pagetools ul li a.source:focus { + background-position: left -405px; +} + +#dokuwiki__pagetools ul li a.draft { + background-position: right -180px; +} +#dokuwiki__pagetools ul li a.draft:before { + margin-top: -180px; +} +#dokuwiki__pagetools ul li a.draft:hover, +#dokuwiki__pagetools ul li a.draft:active, +#dokuwiki__pagetools ul li a.draft:focus { + background-position: right -225px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.draft { + background-position: left -180px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.draft:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.draft:active, +[dir=rtl] #dokuwiki__pagetools ul li a.draft:focus { + background-position: left -225px; +} + +#dokuwiki__pagetools ul li a.revs { + background-position: right -540px; +} +#dokuwiki__pagetools ul li a.revs:before { + margin-top: -540px; +} +#dokuwiki__pagetools ul li a.revs:hover, +#dokuwiki__pagetools ul li a.revs:active, +#dokuwiki__pagetools ul li a.revs:focus, +.mode_revisions #dokuwiki__pagetools ul li a.revs { + background-position: right -585px; +} +.mode_revisions #dokuwiki__pagetools ul li a.revs:before { + margin-top: -585px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.revs { + background-position: left -540px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.revs:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.revs:active, +[dir=rtl] #dokuwiki__pagetools ul li a.revs:focus, +[dir=rtl] .mode_revisions #dokuwiki__pagetools ul li a.revs { + background-position: left -585px; +} + +#dokuwiki__pagetools ul li a.backlink { + background-position: right -630px; +} +#dokuwiki__pagetools ul li a.backlink:before { + margin-top: -630px; +} +#dokuwiki__pagetools ul li a.backlink:hover, +#dokuwiki__pagetools ul li a.backlink:active, +#dokuwiki__pagetools ul li a.backlink:focus, +.mode_backlink #dokuwiki__pagetools ul li a.backlink { + background-position: right -675px; +} +.mode_backlink #dokuwiki__pagetools ul li a.backlink:before { + margin-top: -675px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.backlink { + background-position: left -630px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.backlink:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.backlink:active, +[dir=rtl] #dokuwiki__pagetools ul li a.backlink:focus, +[dir=rtl] .mode_backlink #dokuwiki__pagetools ul li a.backlink { + background-position: left -675px; +} + +#dokuwiki__pagetools ul li a.top { + background-position: right -810px; +} +#dokuwiki__pagetools ul li a.top:before{ + margin-top: -810px; +} +#dokuwiki__pagetools ul li a.top:hover, +#dokuwiki__pagetools ul li a.top:active, +#dokuwiki__pagetools ul li a.top:focus { + background-position: right -855px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.top { + background-position: left -810px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.top:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.top:active, +[dir=rtl] #dokuwiki__pagetools ul li a.top:focus { + background-position: left -855px; +} + +#dokuwiki__pagetools ul li a.revert { + background-position: right -450px; +} +#dokuwiki__pagetools ul li a.revert:before { + margin-top: -450px; +} +#dokuwiki__pagetools ul li a.revert:hover, +#dokuwiki__pagetools ul li a.revert:active, +#dokuwiki__pagetools ul li a.revert:focus, +.mode_revert #dokuwiki__pagetools ul li a.revert { + background-position: right -495px; +} +.mode_revert #dokuwiki__pagetools ul li a.revert:before { + margin-top: -450px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.revert { + background-position: left -450px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.revert:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.revert:active, +[dir=rtl] #dokuwiki__pagetools ul li a.revert:focus, +[dir=rtl] .mode_revert #dokuwiki__pagetools ul li a.revert { + background-position: left -495px; +} + +#dokuwiki__pagetools ul li a.subscribe { + background-position: right -720px; +} +#dokuwiki__pagetools ul li a.subscribe:before { + margin-top: -720px; +} +#dokuwiki__pagetools ul li a.subscribe:hover, +#dokuwiki__pagetools ul li a.subscribe:active, +#dokuwiki__pagetools ul li a.subscribe:focus, +.mode_subscribe #dokuwiki__pagetools ul li a.subscribe { + background-position: right -765px; +} +.mode_subscribe #dokuwiki__pagetools ul li a.subscribe:before { + margin-top: -765px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.subscribe { + background-position: left -720px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.subscribe:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.subscribe:active, +[dir=rtl] #dokuwiki__pagetools ul li a.subscribe:focus, +[dir=rtl] .mode_subscribe #dokuwiki__pagetools ul li a.subscribe { + background-position: left -765px; +} + +#dokuwiki__pagetools ul li a.mediaManager { + background-position: right -900px; +} +#dokuwiki__pagetools ul li a.mediaManager:before { + margin-top: -900px; +} +#dokuwiki__pagetools ul li a.mediaManager:hover, +#dokuwiki__pagetools ul li a.mediaManager:active, +#dokuwiki__pagetools ul li a.mediaManager:focus { + background-position: right -945px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.mediaManager { + background-position: left -900px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.mediaManager:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.mediaManager:active, +[dir=rtl] #dokuwiki__pagetools ul li a.mediaManager:focus { + background-position: left -945px; +} + +#dokuwiki__pagetools ul li a.back { + background-position: right -990px; +} +#dokuwiki__pagetools ul li a.back { + margin-top: -990px; +} +#dokuwiki__pagetools ul li a.back:hover, +#dokuwiki__pagetools ul li a.back:active, +#dokuwiki__pagetools ul li a.back:focus { + background-position: right -1035px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.back { + background-position: left -990px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.back:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.back:active, +[dir=rtl] #dokuwiki__pagetools ul li a.back:focus { + background-position: left -1035px; +} diff --git a/lib/tpl/dokuwiki/css/structure.css b/lib/tpl/dokuwiki/css/structure.css deleted file mode 100644 index 00642e90b..000000000 --- a/lib/tpl/dokuwiki/css/structure.css +++ /dev/null @@ -1,81 +0,0 @@ -/** - * This file provides styles for the general layout structure. - * - * @author Anika Henke - */ - -body { - margin: 0 auto; -} -#dokuwiki__site { - margin: 0 auto; - max-width: __site_width__; -} -#dokuwiki__site > .site { - padding: 0 .5em; -} - -#dokuwiki__header { - width: 100%; -} -#dokuwiki__header > .pad { -} - #dokuwiki__header .headings { - float: left; - } - [dir=rtl] #dokuwiki__header .headings { - float: right; - text-align: right; - } - #dokuwiki__header .tools { - float: right; - text-align: right; - } - [dir=rtl] #dokuwiki__header .tools { - float: left; - text-align: left; - } - -#dokuwiki__site .wrapper { - position: relative; -} - - #dokuwiki__aside { - width: __sidebar_width__; - float: left; - position: relative; - display: block; - } - [dir=rtl] #dokuwiki__aside { - float: right; - } - #dokuwiki__aside > .pad { - margin: 0 1.5em 0 0; - } - [dir=rtl] #dokuwiki__aside > .pad { - margin: 0 0 0 1.5em; - } - - .showSidebar #dokuwiki__content { - float: right; - margin-left: -__sidebar_width__; - width: 100%; - } - [dir=rtl] .showSidebar #dokuwiki__content { - float: left; - margin-left: 0; - margin-right: -__sidebar_width__; - } - .showSidebar #dokuwiki__content > .pad { - margin-left: __sidebar_width__; - } - [dir=rtl] .showSidebar #dokuwiki__content > .pad { - margin-left: 0; - margin-right: __sidebar_width__; - } - -#dokuwiki__footer { - clear: both; -} -#dokuwiki__footer > .pad { -} diff --git a/lib/tpl/dokuwiki/css/structure.less b/lib/tpl/dokuwiki/css/structure.less new file mode 100644 index 000000000..3f22f57e3 --- /dev/null +++ b/lib/tpl/dokuwiki/css/structure.less @@ -0,0 +1,94 @@ +/** + * This file provides styles for the general layout structure. + * + * @author Anika Henke + */ +body { + margin: 0 auto; +} + +#dokuwiki__site { + margin: 0 auto; + max-width: @ini_site_width; +} + +#dokuwiki__site > .site { + padding: 0 .5em; +} + +#dokuwiki__header { + width: 100%; +} + +#dokuwiki__header > .pad { +} + +#dokuwiki__header .headings { + float: left; +} + +[dir=rtl] #dokuwiki__header .headings { + float: right; + text-align: right; +} + +#dokuwiki__header .tools { + float: right; + text-align: right; +} + +[dir=rtl] #dokuwiki__header .tools { + float: left; + text-align: left; +} + +#dokuwiki__site .wrapper { + position: relative; +} + +#dokuwiki__aside { + width: @ini_sidebar_width; + float: left; + position: relative; + display: block; +} + +[dir=rtl] #dokuwiki__aside { + float: right; +} + +#dokuwiki__aside > .pad { + margin: 0 1.5em 0 0; +} + +[dir=rtl] #dokuwiki__aside > .pad { + margin: 0 0 0 1.5em; +} + +.showSidebar #dokuwiki__content { + float: right; + margin-left: -@ini_sidebar_width; + width: 100%; +} + +[dir=rtl] .showSidebar #dokuwiki__content { + float: left; + margin-left: 0; + margin-right: -@ini_sidebar_width; +} + +.showSidebar #dokuwiki__content > .pad { + margin-left: @ini_sidebar_width; +} + +[dir=rtl] .showSidebar #dokuwiki__content > .pad { + margin-left: 0; + margin-right: @ini_sidebar_width; +} + +#dokuwiki__footer { + clear: both; +} + +#dokuwiki__footer > .pad { +} diff --git a/lib/tpl/dokuwiki/style.ini b/lib/tpl/dokuwiki/style.ini index 9cf6cb64f..c6962fcd2 100644 --- a/lib/tpl/dokuwiki/style.ini +++ b/lib/tpl/dokuwiki/style.ini @@ -9,12 +9,15 @@ ; Define the stylesheets your template uses here. The second value ; defines for which output media the style should be loaded. Currently ; print, screen and all are supported. +; You can reference CSS and LESS files here. Files referenced here will +; be checked for updates when considering a cache rebuild while files +; included through LESS' @import statements are not [stylesheets] css/mixins.less = screen -css/basic.css = screen +css/basic.less = screen css/_imgdetail.css = screen css/_media_popup.css = screen css/_media_fullscreen.css = screen @@ -32,17 +35,18 @@ css/_forms.css = screen css/_admin.css = screen css/structure.css = screen css/design.less = screen -css/pagetools.css = screen -css/content.css = screen -css/includes.css = screen +css/pagetools.less = screen +css/content.less = screen -css/mobile.css = all +css/mobile.less = all css/print.css = print ; This section is used to configure some placeholder values used in ; the stylesheets. Changing this file is the simplest method to ; give your wiki a new look. +; Placeholders defined here will also be made available as LESS variables +; (with surrounding underscores removed, and the prefix @ini_ added) [replacements] -- cgit v1.2.3 From b0df08e2753e34829c2d27f82d25807a4f5bd4b8 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Tue, 30 Jul 2013 15:55:34 +0200 Subject: make sure calculations are correct --- lib/tpl/dokuwiki/css/structure.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tpl/dokuwiki/css/structure.less b/lib/tpl/dokuwiki/css/structure.less index 3f22f57e3..f24440f08 100644 --- a/lib/tpl/dokuwiki/css/structure.less +++ b/lib/tpl/dokuwiki/css/structure.less @@ -67,14 +67,14 @@ body { .showSidebar #dokuwiki__content { float: right; - margin-left: -@ini_sidebar_width; + margin-left: (-1 * @ini_sidebar_width); width: 100%; } [dir=rtl] .showSidebar #dokuwiki__content { float: left; margin-left: 0; - margin-right: -@ini_sidebar_width; + margin-right: (-1 * @ini_sidebar_width); } .showSidebar #dokuwiki__content > .pad { -- cgit v1.2.3 From cbe37079b2519e6a79696ab6525a61498ab3c3a6 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Tue, 30 Jul 2013 15:56:29 +0200 Subject: convert ini replacements to less vars first This makes it possible to safely overwrite ini replacements from within any less file --- lib/exe/css.php | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/exe/css.php b/lib/exe/css.php index 04516e8ba..0157e6a40 100644 --- a/lib/exe/css.php +++ b/lib/exe/css.php @@ -154,6 +154,9 @@ function css_out(){ // apply style replacements $css = css_applystyle($css,$tplinc); + print $css; + + // parse LESS $less = new lessc(); $css = $less->compile($css); @@ -188,15 +191,21 @@ function css_applystyle($css,$tplinc){ $styleini = css_styleini($tplinc); if($styleini){ - $css = strtr($css,$styleini['replacements']); - + // we convert ini replacements to LESS variable names + // and build a list of variable: value; pairs $less = ''; foreach($styleini['replacements'] as $key => $value){ - $key = trim($key, '_'); - $key = '@ini_'.$key; - $less .= "$key: $value;\n"; + $lkey = trim($key, '_'); + $lkey = '@ini_'.$lkey; + $less .= "$lkey: $value;\n"; + + $styleini['replacements'][$key] = $lkey; } + // we now replace all old ini replacements with LESS variables + $css = strtr($css, $styleini['replacements']); + + // now prepend the list of LESS variables as the very first thing $css = $less.$css; } return $css; -- cgit v1.2.3 From fbaa87779929e23ede8a79fd3890ef493fdb1d81 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Tue, 30 Jul 2013 16:00:28 +0200 Subject: removed debug statement. sorry --- lib/exe/css.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/exe/css.php b/lib/exe/css.php index 0157e6a40..cd531ef35 100644 --- a/lib/exe/css.php +++ b/lib/exe/css.php @@ -154,9 +154,6 @@ function css_out(){ // apply style replacements $css = css_applystyle($css,$tplinc); - print $css; - - // parse LESS $less = new lessc(); $css = $less->compile($css); -- cgit v1.2.3 From ea9bf4168ca264f9e7ca66fe468f61b9df1fc62a Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Tue, 30 Jul 2013 17:23:55 +0100 Subject: fixed broken structure --- lib/tpl/dokuwiki/style.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tpl/dokuwiki/style.ini b/lib/tpl/dokuwiki/style.ini index c6962fcd2..24faffdb3 100644 --- a/lib/tpl/dokuwiki/style.ini +++ b/lib/tpl/dokuwiki/style.ini @@ -33,7 +33,7 @@ css/_edit.css = screen css/_modal.css = screen css/_forms.css = screen css/_admin.css = screen -css/structure.css = screen +css/structure.less = screen css/design.less = screen css/pagetools.less = screen css/content.less = screen -- cgit v1.2.3 From b0a0b422439fd5c86ced0c8a7f89bb2b93a11564 Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Tue, 30 Jul 2013 17:24:54 +0100 Subject: unlessified and lessified a few more css --- lib/tpl/dokuwiki/css/content.less | 27 +++++------ lib/tpl/dokuwiki/css/design.less | 94 ++++++++++++++++++------------------- lib/tpl/dokuwiki/css/mobile.less | 52 +++++++++++--------- lib/tpl/dokuwiki/css/structure.less | 67 ++++++++++++-------------- 4 files changed, 116 insertions(+), 124 deletions(-) diff --git a/lib/tpl/dokuwiki/css/content.less b/lib/tpl/dokuwiki/css/content.less index ae97d7d5e..56551fe3b 100644 --- a/lib/tpl/dokuwiki/css/content.less +++ b/lib/tpl/dokuwiki/css/content.less @@ -120,7 +120,6 @@ /* filenames for downloadable file and code blocks */ .dokuwiki dl.code, .dokuwiki dl.file { - dt, dt { background-color: @ini_background_site; .linear-gradient(~"top, @{ini_background_alt} 0%, @{ini_background_site} 100%"); @@ -132,24 +131,22 @@ padding: .3em .6em .1em; margin-bottom: -1px; float: left; - } - dt a, - dt a { - background-color: transparent; - font-size: 0.875em; - font-weight: normal; - display: block; - min-height: 16px; + + a { + background-color: transparent; + font-size: 0.875em; + font-weight: normal; + display: block; + min-height: 16px; + } } - dd, dd { margin: 0; clear: left; min-height: 1px; /* for IE7 */ } - pre, pre { box-shadow: inset -4px -4px .5em -.3em @ini_border; } @@ -157,12 +154,10 @@ [dir=rtl] .dokuwiki dl.code, [dir=rtl] .dokuwiki dl.file { - dt, dt { float: right; } - dd, dd { clear: right; } @@ -329,10 +324,10 @@ ul { padding: 0 0 0 1.2em; - } - ul li { - list-style-image: url(images/toc-bullet.png); + li { + list-style-image: url(images/toc-bullet.png); + } } ul li.clear { diff --git a/lib/tpl/dokuwiki/css/design.less b/lib/tpl/dokuwiki/css/design.less index aba9c9c7b..42292de49 100644 --- a/lib/tpl/dokuwiki/css/design.less +++ b/lib/tpl/dokuwiki/css/design.less @@ -100,11 +100,9 @@ margin-left: 0; } -#dokuwiki__usertools { - a.action { - padding-left: 20px; - background: transparent url(images/usertools.png) no-repeat 0 0; - } +#dokuwiki__usertools a.action { + padding-left: 20px; + background: transparent url(images/usertools.png) no-repeat 0 0; } [dir=rtl] #dokuwiki__usertools a.action { @@ -350,17 +348,14 @@ /* content ********************************************************************/ -.dokuwiki { - - .pageId { - position: absolute; - top: -2.3em; - right: -1em; - overflow: hidden; - padding: 1em 1em 0; - } +.dokuwiki .pageId { + position: absolute; + top: -2.3em; + right: -1em; + overflow: hidden; + padding: 1em 1em 0; - .pageId span { + span { font-size: 0.875em; border: solid @ini_background_alt; border-width: 1px 1px 0; @@ -372,39 +367,37 @@ box-shadow: 0 0 .5em @ini_text_alt; display: block; } +} - div.page { - background: @ini_background; - color: inherit; - border: 1px solid @ini_background_alt; - box-shadow: 0 0 .5em @ini_text_alt; - border-radius: 2px; - padding: 1.556em 2em 2em; - margin-bottom: .5em; - overflow: hidden; - word-wrap: break-word; - } +.dokuwiki div.page { + background: @ini_background; + color: inherit; + border: 1px solid @ini_background_alt; + box-shadow: 0 0 .5em @ini_text_alt; + border-radius: 2px; + padding: 1.556em 2em 2em; + margin-bottom: .5em; + overflow: hidden; + word-wrap: break-word; +} - .docInfo { - font-size: 0.875em; - text-align: right; - } +.dokuwiki .docInfo { + font-size: 0.875em; + text-align: right; +} - /* license note under edit window */ - div.license { - font-size: 93.75%; - } +/* license note under edit window */ +.dokuwiki div.license { + font-size: 93.75%; } -[dir=rtl] .dokuwiki { - .docInfo { - text-align: left; - } +[dir=rtl] .dokuwiki .docInfo { + text-align: left; +} - .pageId { - right: auto; - left: -1em; - } +[dir=rtl] .dokuwiki .pageId { + right: auto; + left: -1em; } /* footer @@ -427,15 +420,18 @@ font-size: 100%; } - div.buttons a img { - opacity: 0.5; - } + div.buttons a { + img { + opacity: 0.5; + } - div.buttons a:hover img, - div.buttons a:active img, - div.buttons a:focus img { - opacity: 1; + &:hover img, + &:active img, + &:focus img { + opacity: 1; + } } + } [dir=rtl] #dokuwiki__footer .license img { diff --git a/lib/tpl/dokuwiki/css/mobile.less b/lib/tpl/dokuwiki/css/mobile.less index 4362656a1..289f5afa3 100644 --- a/lib/tpl/dokuwiki/css/mobile.less +++ b/lib/tpl/dokuwiki/css/mobile.less @@ -40,22 +40,24 @@ #dokuwiki__aside h3.toggle { font-size: 1em; -} -#dokuwiki__aside h3.toggle.closed { - margin-bottom: 0; - padding-bottom: 0; -} -#dokuwiki__aside h3.toggle.open { - border-bottom: 1px solid @ini_border; + + &.closed { + margin-bottom: 0; + padding-bottom: 0; + } + &.open { + border-bottom: 1px solid @ini_border; + } } .showSidebar #dokuwiki__content { float: none; margin-left: 0; width: 100%; -} -.showSidebar #dokuwiki__content > .pad { - margin-left: 0; + + > .pad { + margin-left: 0; + } } [dir=rtl] .showSidebar #dokuwiki__content, @@ -133,9 +135,10 @@ body { #dokuwiki__site { max-width: 100%; -} -#dokuwiki__site > .site { - padding: 0 .5em; + + > .site { + padding: 0 .5em; + } } #dokuwiki__header { padding: .5em 0; @@ -154,19 +157,21 @@ body { list-style: none; padding-left: 0; margin: 0; + + li { + margin-left: .35em; + display: inline; + } } [dir=rtl] #dokuwiki__header ul.a11y.skip { left: auto !important; right: 0 !important; float: left; padding-right: 0; -} -#dokuwiki__header ul.a11y.skip li { - margin-left: .35em; - display: inline; -} -[dir=rtl] #dokuwiki__header ul.a11y.skip li { - margin: 0 .35em 0 0; + + li { + margin: 0 .35em 0 0; + } } #dokuwiki__header .headings, @@ -264,13 +269,14 @@ body { .dokuwiki label.block { text-align: left; + + span { + display: block; + } } [dir=rtl] .dokuwiki label.block { text-align: right; } -.dokuwiki label.block span { - display: block; -} /* _edit */ .dokuwiki div.section_highlight { diff --git a/lib/tpl/dokuwiki/css/structure.less b/lib/tpl/dokuwiki/css/structure.less index f24440f08..3ea2f83eb 100644 --- a/lib/tpl/dokuwiki/css/structure.less +++ b/lib/tpl/dokuwiki/css/structure.less @@ -18,28 +18,27 @@ body { #dokuwiki__header { width: 100%; -} -#dokuwiki__header > .pad { -} + .headings { + float: left; + } -#dokuwiki__header .headings { - float: left; + .tools { + float: right; + text-align: right; + } } -[dir=rtl] #dokuwiki__header .headings { - float: right; - text-align: right; -} +[dir=rtl] #dokuwiki__header { + .headings { + float: right; + text-align: right; + } -#dokuwiki__header .tools { - float: right; - text-align: right; -} - -[dir=rtl] #dokuwiki__header .tools { - float: left; - text-align: left; + .tools { + float: left; + text-align: left; + } } #dokuwiki__site .wrapper { @@ -51,44 +50,40 @@ body { float: left; position: relative; display: block; + + > .pad { + margin: 0 1.5em 0 0; + } } [dir=rtl] #dokuwiki__aside { float: right; -} - -#dokuwiki__aside > .pad { - margin: 0 1.5em 0 0; -} - -[dir=rtl] #dokuwiki__aside > .pad { - margin: 0 0 0 1.5em; + > .pad { + margin: 0 0 0 1.5em; + } } .showSidebar #dokuwiki__content { float: right; margin-left: (-1 * @ini_sidebar_width); width: 100%; + + > .pad { + margin-left: @ini_sidebar_width; + } } [dir=rtl] .showSidebar #dokuwiki__content { float: left; margin-left: 0; margin-right: (-1 * @ini_sidebar_width); -} -.showSidebar #dokuwiki__content > .pad { - margin-left: @ini_sidebar_width; -} - -[dir=rtl] .showSidebar #dokuwiki__content > .pad { - margin-left: 0; - margin-right: @ini_sidebar_width; + > .pad { + margin-left: 0; + margin-right: @ini_sidebar_width; + } } #dokuwiki__footer { clear: both; } - -#dokuwiki__footer > .pad { -} -- cgit v1.2.3 From e8e5221c8fef184d755602564343787c9e3196d9 Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Wed, 31 Jul 2013 11:56:08 +0100 Subject: switched to LESS variables in rest of template's css files --- lib/tpl/dokuwiki/css/_admin.css | 2 +- lib/tpl/dokuwiki/css/_diff.css | 2 +- lib/tpl/dokuwiki/css/_edit.css | 12 ++++----- lib/tpl/dokuwiki/css/_fileuploader.css | 8 +++--- lib/tpl/dokuwiki/css/_footnotes.css | 2 +- lib/tpl/dokuwiki/css/_forms.css | 2 +- lib/tpl/dokuwiki/css/_media_fullscreen.css | 40 +++++++++++++++--------------- lib/tpl/dokuwiki/css/_media_popup.css | 12 ++++----- lib/tpl/dokuwiki/css/_modal.css | 10 ++++---- lib/tpl/dokuwiki/css/_search.css | 6 ++--- lib/tpl/dokuwiki/css/_tabs.css | 14 +++++------ lib/tpl/dokuwiki/css/_toc.css | 2 +- lib/tpl/dokuwiki/css/pagetools.less | 10 ++++---- lib/tpl/dokuwiki/style.ini | 32 ++++++++++++------------ 14 files changed, 77 insertions(+), 77 deletions(-) diff --git a/lib/tpl/dokuwiki/css/_admin.css b/lib/tpl/dokuwiki/css/_admin.css index c8f3694b5..a9518d0ed 100644 --- a/lib/tpl/dokuwiki/css/_admin.css +++ b/lib/tpl/dokuwiki/css/_admin.css @@ -50,7 +50,7 @@ .dokuwiki #admin__version { clear: left; float: right; - color: __text_neu__; + color: @ini_text_neu; background-color: inherit; } [dir=rtl] .dokuwiki #admin__version { diff --git a/lib/tpl/dokuwiki/css/_diff.css b/lib/tpl/dokuwiki/css/_diff.css index 58c24b5c7..b7c82d829 100644 --- a/lib/tpl/dokuwiki/css/_diff.css +++ b/lib/tpl/dokuwiki/css/_diff.css @@ -19,7 +19,7 @@ /* table header */ .dokuwiki table.diff th { - border-bottom: 1px solid __border__; + border-bottom: 1px solid @ini_border; font-size: 110%; font-weight: normal; } diff --git a/lib/tpl/dokuwiki/css/_edit.css b/lib/tpl/dokuwiki/css/_edit.css index 92ce62126..f40aaa891 100644 --- a/lib/tpl/dokuwiki/css/_edit.css +++ b/lib/tpl/dokuwiki/css/_edit.css @@ -16,7 +16,7 @@ } #draft__status { float: right; - color: __text_alt__; + color: @ini_text_alt; background-color: inherit; } [dir=rtl] #draft__status { @@ -35,8 +35,8 @@ /* picker popups (outside of .dokuwiki) */ div.picker { width: 300px; - border: 1px solid __border__; - background-color: __background_alt__; + border: 1px solid @ini_border; + background-color: @ini_background_alt; color: inherit; } /* picker for headlines */ @@ -106,7 +106,7 @@ div.picker button.toolbutton { } /* change background colour if summary is missing */ .dokuwiki .editBar .summary input.missing { - color: __text__; + color: @ini_text; background-color: #ffcccc; } @@ -114,7 +114,7 @@ div.picker button.toolbutton { ********************************************************************/ .dokuwiki div.preview { - border: dotted __border__; + border: dotted @ini_border; border-width: .2em 0; padding: 1.4em 0; margin-bottom: 1.4em; @@ -138,6 +138,6 @@ div.picker button.toolbutton { .dokuwiki div.section_highlight { margin: 0 -1em; /* negative side margin = side padding + side border */ padding: 0 .5em; - border: solid __background_alt__; + border: solid @ini_background_alt; border-width: 0 .5em; } diff --git a/lib/tpl/dokuwiki/css/_fileuploader.css b/lib/tpl/dokuwiki/css/_fileuploader.css index 42004de28..3c2cd4683 100644 --- a/lib/tpl/dokuwiki/css/_fileuploader.css +++ b/lib/tpl/dokuwiki/css/_fileuploader.css @@ -42,8 +42,8 @@ height: 100%; min-height: 70px; z-index: 2; - background: __background_neu__; - color: __text__; + background: @ini_background_neu; + color: @ini_text; text-align: center; } @@ -57,7 +57,7 @@ } .qq-upload-drop-area-active { - background: __background_alt__; + background: @ini_background_alt; } /* list of files to upload */ @@ -70,7 +70,7 @@ div.qq-uploader ul { .qq-uploader li { margin: 0 0 5px; - color: __text__; + color: @ini_text; } .qq-uploader li span, diff --git a/lib/tpl/dokuwiki/css/_footnotes.css b/lib/tpl/dokuwiki/css/_footnotes.css index a20f2964e..5d5f7ca30 100644 --- a/lib/tpl/dokuwiki/css/_footnotes.css +++ b/lib/tpl/dokuwiki/css/_footnotes.css @@ -16,7 +16,7 @@ div.insitu-footnote { /*____________ footnotes at the bottom of the page ____________*/ .dokuwiki div.footnotes { - border-top: 1px solid __border__; + border-top: 1px solid @ini_border; padding: .5em 0 0 0; margin: 1em 0 0 0; clear: both; diff --git a/lib/tpl/dokuwiki/css/_forms.css b/lib/tpl/dokuwiki/css/_forms.css index 6744750ba..940a27f80 100644 --- a/lib/tpl/dokuwiki/css/_forms.css +++ b/lib/tpl/dokuwiki/css/_forms.css @@ -48,7 +48,7 @@ .dokuwiki fieldset { width: 400px; text-align: center; - border: 1px solid __border__; + border: 1px solid @ini_border; padding: 0.5em; margin: auto; } diff --git a/lib/tpl/dokuwiki/css/_media_fullscreen.css b/lib/tpl/dokuwiki/css/_media_fullscreen.css index 8d5e1e8ca..28e347882 100644 --- a/lib/tpl/dokuwiki/css/_media_fullscreen.css +++ b/lib/tpl/dokuwiki/css/_media_fullscreen.css @@ -38,7 +38,7 @@ } #mediamanager__page .panelHeader { - background-color: __background_alt__; + background-color: @ini_background_alt; margin: 0 10px 10px 0; padding: 10px 10px 8px; text-align: left; @@ -68,7 +68,7 @@ background: transparent url(../../images/resizecol.png) center center no-repeat; } #mediamanager__page .ui-resizable-e:hover { - background-color: __background_alt__; + background-color: @ini_background_alt; } @@ -99,10 +99,10 @@ margin: 0 0 0 .3em; border-radius: .5em .5em 0 0; font-weight: normal; - background-color: __background_alt__; - color: __text__; - border: 1px solid __border__; - border-bottom-color: __background_alt__; + background-color: @ini_background_alt; + color: @ini_text; + border: 1px solid @ini_border; + border-bottom-color: @ini_background_alt; line-height: 1.4em; position: relative; bottom: -1px; @@ -118,7 +118,7 @@ right: 10px; } #mediamanager__page .namespaces .panelHeader { - border-top: 1px solid __border__; + border-top: 1px solid @ini_border; z-index: 1; } @@ -164,7 +164,7 @@ padding: 0; } #mediamanager__page .panelHeader ul li { - color: __text__; + color: @ini_text; float: left; line-height: 1; padding-left: 3px; @@ -205,7 +205,7 @@ } #mediamanager__page .filelist .panelContent ul li:hover { - background-color: __background_alt__; + background-color: @ini_background_alt; } #mediamanager__page .filelist li dt a { @@ -231,8 +231,8 @@ display: -moz-inline-stack; /* the right margin should visually be 10px, but because of its inline-block nature the whitespace inbetween is about 4px more */ margin: 0 6px 10px 0; - background-color: __background_neu__; - color: __text__; + background-color: @ini_background_neu; + color: @ini_text; padding: 5px; vertical-align: top; text-align: center; @@ -287,13 +287,13 @@ max-height: 50px; margin: 0; margin-bottom: 3px; - background-color: __background__; - color: __text__; + background-color: @ini_background; + color: @ini_text; overflow: hidden; } #mediamanager__page .filelist .rows li:nth-child(2n+1) { - background-color: __background_neu__; + background-color: @ini_background_neu; } #mediamanager__page .filelist .rows li dt { @@ -372,11 +372,11 @@ #mediamanager__page .file dl dt { font-weight: bold; display: block; - background-color: __background_alt__; + background-color: @ini_background_alt; } #mediamanager__page .file dl dd { display: block; - background-color: __background_neu__; + background-color: @ini_background_neu; } @@ -415,7 +415,7 @@ #mediamanager__page #page__revisions ul li div.li div { font-size: 90%; - color: __text_neu__; + color: @ini_text_neu; padding-left: 18px; } @@ -438,7 +438,7 @@ padding: 0; vertical-align: top; text-align: left; - border-color: __background__; + border-color: @ini_background; } [dir=rtl] #mediamanager__diff td, [dir=rtl] #mediamanager__diff th { @@ -447,7 +447,7 @@ #mediamanager__diff th { font-weight: normal; - background-color: __background__; + background-color: @ini_background; line-height: 1.2; } #mediamanager__diff th a { @@ -459,7 +459,7 @@ #mediamanager__diff dl dd strong{ background-color: __highlight__; - color: __text__; + color: @ini_text; font-weight: normal; } diff --git a/lib/tpl/dokuwiki/css/_media_popup.css b/lib/tpl/dokuwiki/css/_media_popup.css index c776e6b8a..1fefd68b6 100644 --- a/lib/tpl/dokuwiki/css/_media_popup.css +++ b/lib/tpl/dokuwiki/css/_media_popup.css @@ -20,13 +20,13 @@ html.popup { overflow: auto; position: absolute; left: 0; - border-right: 1px solid __border__; + border-right: 1px solid @ini_border; } [dir=rtl] #mediamgr__aside { left: auto; right: 0; border-right-width: 0; - border-left: 1px solid __border__; + border-left: 1px solid @ini_border; } #mediamgr__aside .pad { padding: .5em; @@ -52,7 +52,7 @@ html.popup { font-size: 1.5em; margin-bottom: .5em; padding-bottom: .2em; - border-bottom: 1px solid __border__; + border-bottom: 1px solid @ini_border; } /* left side @@ -141,13 +141,13 @@ html.popup { padding: .5em; } #media__content .odd { - background-color: __background_alt__; + background-color: @ini_background_alt; } #media__content .even { } /* highlight newly uploaded or edited file */ #media__content #scroll__here { - border: 1px dashed __border__; + border: 1px dashed @ini_border; } /* link which inserts media file */ @@ -167,7 +167,7 @@ html.popup { /* info how to insert media, if JS disabled */ #media__content div.example { - color: __text_neu__; + color: @ini_text_neu; margin-left: 1em; } diff --git a/lib/tpl/dokuwiki/css/_modal.css b/lib/tpl/dokuwiki/css/_modal.css index a3d3be194..a46dff30e 100644 --- a/lib/tpl/dokuwiki/css/_modal.css +++ b/lib/tpl/dokuwiki/css/_modal.css @@ -18,11 +18,11 @@ } #link__wiz_result { - background-color: __background__; + background-color: @ini_background; width: 293px; height: 193px; overflow: auto; - border: 1px solid __border__; + border: 1px solid @ini_border; margin: 3px auto; text-align: left; line-height: 1; @@ -57,16 +57,16 @@ } #link__wiz_result div.even { - background-color: __background_neu__; + background-color: @ini_background_neu; } #link__wiz_result div.selected { - background-color: __background_alt__; + background-color: @ini_background_alt; } #link__wiz_result span { display: block; - color: __text_neu__; + color: @ini_text_neu; margin-left: 22px; } diff --git a/lib/tpl/dokuwiki/css/_search.css b/lib/tpl/dokuwiki/css/_search.css index 0090308c9..a8972ae72 100644 --- a/lib/tpl/dokuwiki/css/_search.css +++ b/lib/tpl/dokuwiki/css/_search.css @@ -44,14 +44,14 @@ } /* search snippet */ .dokuwiki dl.search_results dd { - color: __text_alt__; + color: @ini_text_alt; background-color: inherit; margin: 0 0 1.2em 0; } /* search hit in normal text */ .dokuwiki .search_hit { - color: __text__; + color: @ini_text; background-color: __highlight__; } /* search hit in search results */ @@ -60,7 +60,7 @@ } /* ellipsis separating snippets */ .dokuwiki .search_results .search_sep { - color: __text__; + color: @ini_text; background-color: inherit; } diff --git a/lib/tpl/dokuwiki/css/_tabs.css b/lib/tpl/dokuwiki/css/_tabs.css index 845ec9a57..860545a27 100644 --- a/lib/tpl/dokuwiki/css/_tabs.css +++ b/lib/tpl/dokuwiki/css/_tabs.css @@ -17,7 +17,7 @@ width: 100%; bottom: 0; left: 0; - border-bottom: 1px solid __border__; + border-bottom: 1px solid @ini_border; z-index: 1; } @@ -39,9 +39,9 @@ display: inline-block; padding: .3em .8em; margin: 0 0 0 .3em; - background-color: __background_neu__; - color: __text__; - border: 1px solid __border__; + background-color: @ini_background_neu; + color: @ini_text; + border: 1px solid @ini_border; border-radius: .5em .5em 0 0; position: relative; z-index: 0; @@ -68,8 +68,8 @@ .dokuwiki ul.tabs li a:active, .dokuwiki ul.tabs li a:focus, .dokuwiki ul.tabs li strong { - background-color: __background_alt__; - color: __text__; + background-color: @ini_background_alt; + color: @ini_text; text-decoration: none; font-weight: normal; } @@ -78,5 +78,5 @@ .dokuwiki .tabs > ul li .active a, .dokuwiki ul.tabs li strong { z-index: 2; - border-bottom-color: __background_alt__; + border-bottom-color: @ini_background_alt; } diff --git a/lib/tpl/dokuwiki/css/_toc.css b/lib/tpl/dokuwiki/css/_toc.css index 1226b5b5b..469e9278c 100644 --- a/lib/tpl/dokuwiki/css/_toc.css +++ b/lib/tpl/dokuwiki/css/_toc.css @@ -11,7 +11,7 @@ float: right; margin: 0 0 1.4em 1.4em; width: 12em; - background-color: __background_alt__; + background-color: @ini_background_alt; color: inherit; } [dir=rtl] #dw__toc { diff --git a/lib/tpl/dokuwiki/css/pagetools.less b/lib/tpl/dokuwiki/css/pagetools.less index 21e5c13ec..2e316122f 100644 --- a/lib/tpl/dokuwiki/css/pagetools.less +++ b/lib/tpl/dokuwiki/css/pagetools.less @@ -101,10 +101,10 @@ #dokuwiki__pagetools:hover ul, #dokuwiki__pagetools ul li a:focus, #dokuwiki__pagetools ul li a:active { - background-color: __background__; - border-color: __border__; + background-color: @ini_background; + border-color: @ini_border; border-radius: 2px; - box-shadow: 2px 2px 2px __text_alt__; + box-shadow: 2px 2px 2px @ini_text_alt; } #dokuwiki__pagetools:hover ul li a, @@ -124,7 +124,7 @@ [dir=rtl] #dokuwiki__pagetools:hover ul, [dir=rtl] #dokuwiki__pagetools ul li a:focus { - box-shadow: -2px 2px 2px __text_alt__; + box-shadow: -2px 2px 2px @ini_text_alt; } [dir=rtl] #dokuwiki__pagetools:hover li a, @@ -158,7 +158,7 @@ text-decoration: none; } #dokuwiki__pagetools ul li a:hover { - background-color: __background_alt__; + background-color: @ini_background_alt; } /*____________ all available icons in sprite ____________*/ diff --git a/lib/tpl/dokuwiki/style.ini b/lib/tpl/dokuwiki/style.ini index 24faffdb3..897b6e6da 100644 --- a/lib/tpl/dokuwiki/style.ini +++ b/lib/tpl/dokuwiki/style.ini @@ -54,32 +54,32 @@ css/print.css = print ;------ guaranteed dokuwiki color placeholders that every plugin can use ; main text and background colors -__text__ = "#333" -__background__ = "#fff" +__text__ = "#333" ; @ini_text +__background__ = "#fff" ; @ini_background ; alternative text and background colors -__text_alt__ = "#999" -__background_alt__ = "#eee" +__text_alt__ = "#999" ; @ini_text_alt +__background_alt__ = "#eee" ; @ini_background_alt ; neutral text and background colors -__text_neu__ = "#666" -__background_neu__ = "#ddd" +__text_neu__ = "#666" ; @ini_text_neu +__background_neu__ = "#ddd" ; @ini_background_neu ; border color -__border__ = "#ccc" +__border__ = "#ccc" ; @ini_border ; highlighted text (e.g. search snippets) -__highlight__ = "#ff9" +__highlight__ = "#ff9" ; @ini_highlight ;-------------------------------------------------------------------------- -__background_site__ = "#fbfaf9" +__background_site__ = "#fbfaf9" ; @ini_background_site ; these are used for links -__link__ = "#2b73b7" -__existing__ = "#080" -__missing__ = "#d30" +__link__ = "#2b73b7" ; @ini_link +__existing__ = "#080" ; @ini_existing +__missing__ = "#d30" ; @ini_missing ; site and sidebar widths -__site_width__ = "75em" -__sidebar_width__ = "16em" +__site_width__ = "75em" ; @ini_site_width +__sidebar_width__ = "16em" ; @ini_sidebar_width ; cut off points for mobile devices -__tablet_width__ = "800px" -__phone_width__ = "480px" +__tablet_width__ = "800px" ; @ini_tablet_width +__phone_width__ = "480px" ; @ini_phone_width -- cgit v1.2.3 From fd975da73e627193ca68a681ea6b2556c8327f63 Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Wed, 31 Jul 2013 11:58:47 +0100 Subject: removed possibility to have rtl.less files in plugins --- lib/exe/css.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/exe/css.php b/lib/exe/css.php index cd531ef35..5c966db82 100644 --- a/lib/exe/css.php +++ b/lib/exe/css.php @@ -365,7 +365,6 @@ function css_pluginstyles($mediatype='screen'){ // please use "[dir=rtl]" in any css file in all, screen or print mode instead if($lang['direction'] == 'rtl'){ $list[DOKU_PLUGIN."$p/rtl.css"] = DOKU_BASE."lib/plugins/$p/"; - $list[DOKU_PLUGIN."$p/rtl.less"] = DOKU_BASE."lib/plugins/$p/"; } } return $list; -- cgit v1.2.3 From 2a7abf2d7fee6a2d6418e5ad4b79e37e6049bd92 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Wed, 31 Jul 2013 18:14:26 +0200 Subject: FS#2751 - self deletion of user account --- inc/actions.php | 28 +++++++++++++----- inc/auth.php | 39 +++++++++++++++++++++++++ inc/confutils.php | 3 ++ inc/html.php | 17 +++++++++++ inc/lang/en/lang.php | 7 +++++ lib/plugins/config/lang/en/lang.php | 1 + lib/plugins/config/settings/config.metadata.php | 2 +- lib/tpl/dokuwiki/css/_forms.css | 5 +++- 8 files changed, 92 insertions(+), 10 deletions(-) diff --git a/inc/actions.php b/inc/actions.php index da3414eb2..bf124c887 100644 --- a/inc/actions.php +++ b/inc/actions.php @@ -92,14 +92,26 @@ function act_dispatch(){ $ACT = 'login'; } - //update user profile - if ($ACT == 'profile') { + // user profile changes + if (in_array($ACT, array('profile','profile_delete'))) { if(!$_SERVER['REMOTE_USER']) { $ACT = 'login'; } else { - if(updateprofile()) { - msg($lang['profchanged'],1); - $ACT = 'show'; + switch ($ACT) { + case 'profile' : + if(updateprofile()) { + msg($lang['profchanged'],1); + $ACT = 'show'; + } + break; + case 'profile_delete' : + if(auth_deleteprofile()){ + msg($lang['profdeleted'],1); + $ACT = 'show'; + } else { + $ACT = 'profile'; + } + break; } } } @@ -247,7 +259,7 @@ function act_validate($act) { //disable all acl related commands if ACL is disabled if(!$conf['useacl'] && in_array($act,array('login','logout','register','admin', 'subscribe','unsubscribe','profile','revert', - 'resendpwd'))){ + 'resendpwd','profile_delete'))){ msg('Command unavailable: '.htmlspecialchars($act),-1); return 'show'; } @@ -258,7 +270,7 @@ function act_validate($act) { if(!in_array($act,array('login','logout','register','save','cancel','edit','draft', 'preview','search','show','check','index','revisions', 'diff','recent','backlink','admin','subscribe','revert', - 'unsubscribe','profile','resendpwd','recover', + 'unsubscribe','profile','profile_delete','resendpwd','recover', 'draftdel','sitemap','media')) && substr($act,0,7) != 'export_' ) { msg('Command unknown: '.htmlspecialchars($act),-1); return 'show'; @@ -287,7 +299,7 @@ function act_permcheck($act){ }else{ $permneed = AUTH_CREATE; } - }elseif(in_array($act,array('login','search','recent','profile','index', 'sitemap'))){ + }elseif(in_array($act,array('login','search','recent','profile','profile_delete','index', 'sitemap'))){ $permneed = AUTH_NONE; }elseif($act == 'revert'){ $permneed = AUTH_ADMIN; diff --git a/inc/auth.php b/inc/auth.php index 537d44c01..75ba9a9ba 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -901,6 +901,45 @@ function updateprofile() { return false; } +function auth_deleteprofile(){ + global $conf; + global $lang; + /* @var auth_basic $auth */ + global $auth; + /* @var Input $INPUT */ + global $INPUT; + + if(!$INPUT->post->bool('delete')) return false; + if(!checkSecurityToken()) return false; + + // action prevented or auth module disallows + if(!actionOK('profile_delete') || !$auth->canDo('delUser')) { + msg($lang['profnodelete'], -1); + return false; + } + + if(!$INPUT->post->bool('confirm_delete')){ + msg($lang['profconfdeletemissing'], -1); + return false; + } + + if($conf['profileconfirm']) { + if(!$auth->checkPass($_SERVER['REMOTE_USER'], $INPUT->post->str('oldpass'))) { + msg($lang['badpassconfirm'], -1); + return false; + } + } + + $deleted[] = $_SERVER['REMOTE_USER']; + if($result = $auth->triggerUserMod('delete', array($deleted))) { + // force and immediate logout including removing the sticky cookie + auth_logoff(); + return true; + } + + return false; +} + /** * Send a new password * diff --git a/inc/confutils.php b/inc/confutils.php index 404cc6050..02be0089c 100644 --- a/inc/confutils.php +++ b/inc/confutils.php @@ -261,6 +261,9 @@ function actionOK($action){ if (is_null($auth) || !$auth->canDo('Profile')) { $disabled[] = 'profile'; } + if (is_null($auth) || !$auth->canDo('delUser')) { + $disabled[] = 'profile_delete'; + } if (is_null($auth)) { $disabled[] = 'login'; } diff --git a/inc/html.php b/inc/html.php index fb39fcb3c..5e3388a52 100644 --- a/inc/html.php +++ b/inc/html.php @@ -1381,6 +1381,23 @@ function html_updateprofile(){ $form->addElement(form_makeButton('reset', '', $lang['btn_reset'])); $form->endFieldset(); html_form('updateprofile', $form); + + if ($auth->canDo('delUser') && actionOK('profile_delete')) { + $form_profiledelete = new Doku_Form(array('id' => 'dw__profiledelete')); + $form_profiledelete->startFieldset($lang['profdeleteuser']); + $form_profiledelete->addHidden('do', 'profile_delete'); + $form_profiledelete->addHidden('delete', '1'); + $form_profiledelete->addElement(form_makeCheckboxField('confirm_delete', '1', $lang['profconfdelete'],'dw__confirmdelete','', array('required' => 'required'))); + if ($conf['profileconfirm']) { + $form_profiledelete->addElement(form_makeTag('br')); + $form_profiledelete->addElement(form_makePasswordField('oldpass', $lang['oldpass'], '', 'block', array('size'=>'50', 'required' => 'required'))); + } + $form_profiledelete->addElement(form_makeButton('submit', '', $lang['btn_deleteuser'])); + $form_profiledelete->endFieldset(); + + html_form('profiledelete', $form_profiledelete); + } + print '
'.NL; } diff --git a/inc/lang/en/lang.php b/inc/lang/en/lang.php index cdad6c9a6..d4acfad6e 100644 --- a/inc/lang/en/lang.php +++ b/inc/lang/en/lang.php @@ -51,6 +51,7 @@ $lang['btn_revert'] = 'Restore'; $lang['btn_register'] = 'Register'; $lang['btn_apply'] = 'Apply'; $lang['btn_media'] = 'Media Manager'; +$lang['btn_deleteuser'] = 'Remove My Account'; $lang['loggedinas'] = 'Logged in as'; $lang['user'] = 'Username'; @@ -63,6 +64,7 @@ $lang['fullname'] = 'Real name'; $lang['email'] = 'E-Mail'; $lang['profile'] = 'User Profile'; $lang['badlogin'] = 'Sorry, username or password was wrong.'; +$lang['badpassconfirm'] = 'Sorry, the password was wrong'; $lang['minoredit'] = 'Minor Changes'; $lang['draftdate'] = 'Draft autosaved on'; // full dformat date will be added $lang['nosecedit'] = 'The page was changed in the meantime, section info was out of date loaded full page instead.'; @@ -81,6 +83,11 @@ $lang['profna'] = 'This wiki does not support profile modificatio $lang['profnochange'] = 'No changes, nothing to do.'; $lang['profnoempty'] = 'An empty name or email address is not allowed.'; $lang['profchanged'] = 'User profile successfully updated.'; +$lang['profnodelete'] = 'This wiki does not support deleting users'; +$lang['profdeleteuser'] = 'Delete Account'; +$lang['profdeleted'] = 'Your user account has been deleted from this wiki'; +$lang['profconfdelete'] = 'I wish to remove my account from this wiki.
This action can not be undone.'; +$lang['profconfdeletemissing'] = 'Confirmation check box not ticked'; $lang['pwdforget'] = 'Forgotten your password? Get a new one'; $lang['resendna'] = 'This wiki does not support password resending.'; diff --git a/lib/plugins/config/lang/en/lang.php b/lib/plugins/config/lang/en/lang.php index 83c843b3a..9558e53dc 100644 --- a/lib/plugins/config/lang/en/lang.php +++ b/lib/plugins/config/lang/en/lang.php @@ -104,6 +104,7 @@ $lang['disableactions'] = 'Disable DokuWiki actions'; $lang['disableactions_check'] = 'Check'; $lang['disableactions_subscription'] = 'Subscribe/Unsubscribe'; $lang['disableactions_wikicode'] = 'View source/Export Raw'; +$lang['disableactions_profile_delete'] = 'Delete Own Account'; $lang['disableactions_other'] = 'Other actions (comma separated)'; $lang['auth_security_timeout'] = 'Authentication Security Timeout (seconds)'; $lang['securecookie'] = 'Should cookies set via HTTPS only be sent via HTTPS by the browser? Disable this option when only the login of your wiki is secured with SSL but browsing the wiki is done unsecured.'; diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php index 22e76a013..ffff15af5 100644 --- a/lib/plugins/config/settings/config.metadata.php +++ b/lib/plugins/config/settings/config.metadata.php @@ -126,7 +126,7 @@ $meta['manager'] = array('string'); $meta['profileconfirm'] = array('onoff'); $meta['rememberme'] = array('onoff'); $meta['disableactions'] = array('disableactions', - '_choices' => array('backlink','index','recent','revisions','search','subscription','register','resendpwd','profile','edit','wikicode','check'), + '_choices' => array('backlink','index','recent','revisions','search','subscription','register','resendpwd','profile','profile_delete','edit','wikicode','check'), '_combine' => array('subscription' => array('subscribe','unsubscribe'), 'wikicode' => array('source','export_raw'))); $meta['auth_security_timeout'] = array('numeric'); $meta['securecookie'] = array('onoff'); diff --git a/lib/tpl/dokuwiki/css/_forms.css b/lib/tpl/dokuwiki/css/_forms.css index 6744750ba..84b7db8e1 100644 --- a/lib/tpl/dokuwiki/css/_forms.css +++ b/lib/tpl/dokuwiki/css/_forms.css @@ -79,7 +79,10 @@ #dw__register fieldset { padding-bottom: 0.7em; } - +#dw__profiledelete { + display: block; + margin-top: 2.8em; +} /** * Styles for the subscription page -- cgit v1.2.3 From 020ea9e10577217f17372cb6510d872f9a5c647c Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Wed, 31 Jul 2013 18:15:57 +0200 Subject: unit tests for self deleting of user accounts --- _test/tests/inc/auth_deleteprofile.test.php | 179 ++++++++++++++++++++++++++++ inc/confutils.php | 2 +- 2 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 _test/tests/inc/auth_deleteprofile.test.php diff --git a/_test/tests/inc/auth_deleteprofile.test.php b/_test/tests/inc/auth_deleteprofile.test.php new file mode 100644 index 000000000..dc38fcd16 --- /dev/null +++ b/_test/tests/inc/auth_deleteprofile.test.php @@ -0,0 +1,179 @@ +cando['delUser'] = $canDeleteUser; + } + + public function checkPass($user, $pass) { + return $pass == 'password'; + } + + public function deleteUsers($users) { + return in_array($_SERVER['REMOTE_USER'], $users); + } + + public function logoff() { + $this->loggedOff = true; + } + +} + +class auth_deleteprofile_test extends DokuWikiTest { + + /* + * Tests: + * + * 1. It works and the user is logged off + * 2. Password matches when config requires it + * 3,4. Auth plugin can prevent & wiki config can prevent + * 5. Any of invalid security token, missing/not set 'delete' flag, missing/unchecked 'confirm_delete' + * + */ + + function test_success() { + + global $ACT, $INPUT, $conf, $auth; + + $ACT = 'profile_delete'; + $conf['profileconfirm'] = false; + $_SERVER['REMOTE_USER'] = 'testuser'; + + $input = array( + 'do' => $ACT, + 'sectok' => getSecurityToken(), + 'delete' => '1', + 'confirm_delete' => '1', + ); + + $_POST = $input; + $_REQUEST = $input; + $INPUT = new Input(); + + $auth = new Mock_Auth_Plugin(); + + $this->assertTrue(auth_deleteprofile()); + $this->assertTrue($auth->loggedOff); + } + + function test_confirmation_required() { + + global $ACT, $INPUT, $conf, $auth; + + $ACT = 'profile_delete'; + $conf['profileconfirm'] = true; + $_SERVER['REMOTE_USER'] = 'testuser'; + + $input = array( + 'do' => $ACT, + 'sectok' => getSecurityToken(), + 'delete' => '1', + 'confirm_delete' => '1', + 'oldpass' => 'wrong', + ); + + $_POST = $input; + $_REQUEST = $input; + $INPUT = new Input(); + + $auth = new Mock_Auth_Plugin(); + + // password check required - it fails, so don't delete profile + $this->assertFalse(auth_deleteprofile()); + + // now it passes, we're good to go + $INPUT->set('oldpass','password'); + $INPUT->post->set('oldpass','password'); + $this->assertTrue(auth_deleteprofile()); + } + + function test_authconfig_prevents() { + + global $ACT, $INPUT, $conf, $auth; + + $ACT = 'profile_delete'; + $conf['profileconfirm'] = false; + $_SERVER['REMOTE_USER'] = 'testuser'; + + $input = array( + 'do' => $ACT, + 'sectok' => getSecurityToken(), + 'delete' => '1', + 'confirm_delete' => '1', + ); + + $_POST = $input; + $_REQUEST = $input; + $INPUT = new Input(); + + $auth = new Mock_Auth_Plugin(false); + $conf['disableactions'] = ''; + $this->assertFalse(auth_deleteprofile()); + } + + function test_wikiconfig_prevents() { + + global $ACT, $INPUT, $conf, $auth; + + $ACT = 'profile_delete'; + $conf['profileconfirm'] = false; + $_SERVER['REMOTE_USER'] = 'testuser'; + + $input = array( + 'do' => $ACT, + 'sectok' => getSecurityToken(), + 'delete' => '1', + 'confirm_delete' => '1', + ); + + $_POST = $input; + $_REQUEST = $input; + $INPUT = new Input(); + + $auth = new Mock_Auth_Plugin(); + $conf['disableactions'] = 'profile_delete'; + + $this->assertFalse(actionOK('profile_delete')); + $this->assertTrue($auth->canDo('delUser')); + + $this->assertFalse(auth_deleteprofile()); + } + + function test_basic_parameters() { + + global $ACT, $INPUT, $conf, $auth; + + $ACT = 'profile_delete'; + $conf['profileconfirm'] = true; + $_SERVER['REMOTE_USER'] = 'testuser'; + + $input = array( + 'do' => $ACT, + 'sectok' => getSecurityToken(), + 'delete' => '1', + 'confirm_delete' => '1', + 'oldpass' => 'password', + ); + + $_POST = $input; + $_REQUEST = $input; + $input_foundation = new Input(); + + $auth = new Mock_Auth_Plugin(); + + $INPUT = clone $input_foundation; + $INPUT->remove('delete'); + $this->assertFalse(auth_deleteprofile()); + + $INPUT = clone $input_foundation; + $INPUT->set('sectok','wrong'); + $this->assertFalse(auth_deleteprofile()); + + $INPUT = clone $input_foundation; + $INPUT->remove('confirm_delete'); + $this->assertFalse(auth_deleteprofile()); + } +} \ No newline at end of file diff --git a/inc/confutils.php b/inc/confutils.php index 02be0089c..0ac003b72 100644 --- a/inc/confutils.php +++ b/inc/confutils.php @@ -241,7 +241,7 @@ function getConfigFiles($type) { */ function actionOK($action){ static $disabled = null; - if(is_null($disabled)){ + if(is_null($disabled) || defined('SIMPLE_TEST')){ global $conf; /** @var auth_basic $auth */ global $auth; -- cgit v1.2.3 From d6d38cc20037bd20fb7183733267d2fbf68b03e4 Mon Sep 17 00:00:00 2001 From: Matthias Schulte Date: Thu, 1 Aug 2013 22:06:14 +0200 Subject: de/de-informal: localization updates (delete user function) --- inc/lang/de-informal/lang.php | 7 +++++++ inc/lang/de/lang.php | 7 +++++++ lib/plugins/config/lang/de-informal/lang.php | 1 + lib/plugins/config/lang/de/lang.php | 1 + 4 files changed, 16 insertions(+) diff --git a/inc/lang/de-informal/lang.php b/inc/lang/de-informal/lang.php index 9a6e6f72c..aaf92ef35 100644 --- a/inc/lang/de-informal/lang.php +++ b/inc/lang/de-informal/lang.php @@ -64,6 +64,7 @@ $lang['btn_revert'] = 'Wiederherstellen'; $lang['btn_register'] = 'Registrieren'; $lang['btn_apply'] = 'Übernehmen'; $lang['btn_media'] = 'Medien-Manager'; +$lang['btn_deleteuser'] = 'Benutzerprofil löschen'; $lang['loggedinas'] = 'Angemeldet als'; $lang['user'] = 'Benutzername'; $lang['pass'] = 'Passwort'; @@ -75,6 +76,7 @@ $lang['fullname'] = 'Voller Name'; $lang['email'] = 'E-Mail'; $lang['profile'] = 'Benutzerprofil'; $lang['badlogin'] = 'Nutzername oder Passwort sind falsch.'; +$lang['badpassconfirm'] = 'Das Passwort war falsch.'; $lang['minoredit'] = 'Kleine Änderung'; $lang['draftdate'] = 'Entwurf gespeichert am'; $lang['nosecedit'] = 'Diese Seite wurde in der Zwischenzeit geändert, da das Sektionsinfo veraltet ist. Die ganze Seite wird stattdessen geladen.'; @@ -91,6 +93,11 @@ $lang['profna'] = 'Änderung des Benutzerprofils in diesem Wiki n $lang['profnochange'] = 'Keine Änderungen, nichts zu tun.'; $lang['profnoempty'] = 'Es muss ein Name oder eine E-Mail Adresse angegeben werden.'; $lang['profchanged'] = 'Benutzerprofil erfolgreich geändert.'; +$lang['profnodelete'] = 'Dieses Wiki unterstützt nicht das Löschen von Benutzern.'; +$lang['profdeleteuser'] = 'Benutzerprofil löschen'; +$lang['profdeleted'] = 'Dein Benutzerprofil wurde im Wiki gelöscht.'; +$lang['profconfdelete'] = 'Ich möchte mein Benutzerprofil löschen.
Diese Aktion ist nicht umkehrbar.'; +$lang['profconfdeletemissing'] = 'Bestätigungs-Checkbox wurde nicht angehakt.'; $lang['pwdforget'] = 'Passwort vergessen? Fordere ein neues an'; $lang['resendna'] = 'Passwörter versenden ist in diesem Wiki nicht möglich.'; $lang['resendpwd'] = 'Neues Passwort setzen für'; diff --git a/inc/lang/de/lang.php b/inc/lang/de/lang.php index af6f32bf4..f7e551c63 100644 --- a/inc/lang/de/lang.php +++ b/inc/lang/de/lang.php @@ -65,6 +65,7 @@ $lang['btn_revert'] = 'Wiederherstellen'; $lang['btn_register'] = 'Registrieren'; $lang['btn_apply'] = 'Übernehmen'; $lang['btn_media'] = 'Medien-Manager'; +$lang['btn_deleteuser'] = 'Benutzerprofil löschen'; $lang['loggedinas'] = 'Angemeldet als'; $lang['user'] = 'Benutzername'; $lang['pass'] = 'Passwort'; @@ -76,6 +77,7 @@ $lang['fullname'] = 'Voller Name'; $lang['email'] = 'E-Mail'; $lang['profile'] = 'Benutzerprofil'; $lang['badlogin'] = 'Nutzername oder Passwort sind falsch.'; +$lang['badpassconfirm'] = 'Das Passwort war falsch.'; $lang['minoredit'] = 'kleine Änderung'; $lang['draftdate'] = 'Entwurf gespeichert am'; $lang['nosecedit'] = 'Diese Seite wurde in der Zwischenzeit geändert, Sektionsinfo ist veraltet, lade stattdessen volle Seite.'; @@ -92,6 +94,11 @@ $lang['profna'] = 'Änderung des Benutzerprofils in diesem Wiki n $lang['profnochange'] = 'Keine Änderungen, nichts zu tun.'; $lang['profnoempty'] = 'Es muss ein Name und eine E-Mail-Adresse angegeben werden.'; $lang['profchanged'] = 'Benutzerprofil erfolgreich geändert.'; +$lang['profnodelete'] = 'Dieses Wiki unterstützt nicht das Löschen von Benutzern.'; +$lang['profdeleteuser'] = 'Benutzerprofil löschen'; +$lang['profdeleted'] = 'Ihr Benutzerprofil wurde im Wiki gelöscht.'; +$lang['profconfdelete'] = 'Ich möchte mein Benutzerprofil löschen.
Diese Aktion ist nicht umkehrbar.'; +$lang['profconfdeletemissing'] = 'Bestätigungs-Checkbox wurde nicht angehakt.'; $lang['pwdforget'] = 'Passwort vergessen? Fordere ein neues an'; $lang['resendna'] = 'Passwörter versenden ist in diesem Wiki nicht möglich.'; $lang['resendpwd'] = 'Neues Passwort setzen für'; diff --git a/lib/plugins/config/lang/de-informal/lang.php b/lib/plugins/config/lang/de-informal/lang.php index 10fa363dc..ce1e6b7b2 100644 --- a/lib/plugins/config/lang/de-informal/lang.php +++ b/lib/plugins/config/lang/de-informal/lang.php @@ -86,6 +86,7 @@ $lang['disableactions'] = 'Deaktiviere DokuWiki\'s Zugriffe'; $lang['disableactions_check'] = 'Check'; $lang['disableactions_subscription'] = 'Bestellen/Abbestellen'; $lang['disableactions_wikicode'] = 'Zeige Quelle/Exportiere Rohdaten'; +$lang['disableactions_profile_delete'] = 'Eigenes Benutzerprofil löschen'; $lang['disableactions_other'] = 'Weitere Aktionen (durch Komma getrennt)'; $lang['auth_security_timeout'] = 'Zeitüberschreitung bei der Authentifizierung (Sekunden)'; $lang['securecookie'] = 'Sollen Cookies, die via HTTPS gesetzt wurden nur per HTTPS versendet werden? Deaktiviere diese Option, wenn nur der Login deines Wikis mit SSL gesichert ist, aber das Betrachten des Wikis ungesichert geschieht.'; diff --git a/lib/plugins/config/lang/de/lang.php b/lib/plugins/config/lang/de/lang.php index dd29f8038..b1acd6afe 100644 --- a/lib/plugins/config/lang/de/lang.php +++ b/lib/plugins/config/lang/de/lang.php @@ -99,6 +99,7 @@ $lang['disableactions'] = 'DokuWiki-Aktionen deaktivieren'; $lang['disableactions_check'] = 'Check'; $lang['disableactions_subscription'] = 'Seiten-Abonnements'; $lang['disableactions_wikicode'] = 'Quelltext betrachten/exportieren'; +$lang['disableactions_profile_delete'] = 'Eigenes Benutzerprofil löschen'; $lang['disableactions_other'] = 'Andere Aktionen (durch Komma getrennt)'; $lang['sneaky_index'] = 'Standardmäßig zeigt DokuWiki alle Namensräume in der Übersicht. Wenn diese Option aktiviert wird, werden alle Namensräume, für die der Benutzer keine Lese-Rechte hat, nicht angezeigt. Dies kann unter Umständen dazu führen, das lesbare Unter-Namensräume nicht angezeigt werden und macht die Übersicht evtl. unbrauchbar in Kombination mit bestimmten ACL Einstellungen.'; $lang['auth_security_timeout'] = 'Authentifikations-Timeout (Sekunden)'; -- cgit v1.2.3 From 4002c084d5e2ffc82739870cb9f107644d9787ff Mon Sep 17 00:00:00 2001 From: Klap-in Date: Thu, 1 Aug 2013 23:05:18 +0200 Subject: Updated tests, removed hash --- _test/tests/inc/common_ml.test.php | 37 ++++++++- .../lib/exe/fetch_statuscodes_external.test.php | 94 ++++++++++------------ 2 files changed, 79 insertions(+), 52 deletions(-) diff --git a/_test/tests/inc/common_ml.test.php b/_test/tests/inc/common_ml.test.php index 6f3b71db4..415c0a88d 100644 --- a/_test/tests/inc/common_ml.test.php +++ b/_test/tests/inc/common_ml.test.php @@ -90,6 +90,25 @@ class common_ml_test extends DokuWikiTest { $this->assertEquals($expect, ml($id, $args)); } + function test_ml_img_external() { + global $conf; + $conf['useslash'] = 0; + $conf['userewrite'] = 0; + + $ids = array( + 'https://example.com/lib/tpl/dokuwiki/images/logo.png', + 'http://example.com/lib/tpl/dokuwiki/images/logo.png', + 'ftp://example.com/lib/tpl/dokuwiki/images/logo.png' + ); + + foreach($ids as $id) { + $tok = media_get_token($id, 0, 0); + + $expect = DOKU_BASE.$this->script.'?tok='.$tok.'&media='.rawurlencode($id); + $this->assertEquals($expect, ml($id)); + } + } + function test_ml_imgresize_array_external() { global $conf; $conf['useslash'] = 0; @@ -107,8 +126,24 @@ class common_ml_test extends DokuWikiTest { $tok = media_get_token($id, $w, 0); $hash = substr(PassHash::hmac('md5', $id, auth_cookiesalt()), 0, 6); - $expect = DOKU_BASE.$this->script.'?hash='.$hash.'&w='.$w.'&tok='.$tok.'&media='.rawurlencode($id); + $expect = DOKU_BASE.$this->script.'?w='.$w.'&tok='.$tok.'&media='.rawurlencode($id); $this->assertEquals($expect, ml($id, $args)); } + + $h = 50; + $args = array('h' => $h); + $tok = media_get_token($id, $h, 0); + + $expect = DOKU_BASE.$this->script.'?h='.$h.'&tok='.$tok.'&media='.rawurlencode($id); + $this->assertEquals($expect, ml($id, $args)); + + $w = 80; + $h = 50; + $args = array('w' => $w, 'h' => $h); + $tok = media_get_token($id, $w, $h); + + $expect = DOKU_BASE.$this->script.'?w='.$w.'&h='.$h.'&tok='.$tok.'&media='.rawurlencode($id); + $this->assertEquals($expect, ml($id, $args)); + } } diff --git a/_test/tests/lib/exe/fetch_statuscodes_external.test.php b/_test/tests/lib/exe/fetch_statuscodes_external.test.php index bd7b2f93b..79a45ec93 100644 --- a/_test/tests/lib/exe/fetch_statuscodes_external.test.php +++ b/_test/tests/lib/exe/fetch_statuscodes_external.test.php @@ -13,7 +13,7 @@ class fetch_statuscodes_external_test extends DokuWikiTest { header('X-Test: check headers working'); $header_check = function_exists('xdebug_get_headers') ? xdebug_get_headers() : headers_list(); - if (empty($header_check)) { + if(empty($header_check)) { $this->markTestSkipped('headers not returned, perhaps your sapi does not return headers, try xdebug'); } else { header_remove('X-Test'); @@ -22,50 +22,53 @@ class fetch_statuscodes_external_test extends DokuWikiTest { parent::setUp(); global $conf; - $conf['fetchsize'] = 500*1024; //500kb + $conf['fetchsize'] = 500 * 1024; //500kb $conf['xsendfile'] = 0; - global $MIME, $EXT, $CACHE, $INPUT; // variables fetch creates in global scope -- should this be in fetch? + global $MIME, $EXT, $CACHE, $INPUT; // variables fetch creates in global scope -- should this be in fetch? } - function getUri($hash=null) { + function getUri() { $w = $this->width ? 'w='.$this->width.'&' : ''; $h = $this->height ? 'h='.$this->height.'&' : ''; - if($hash === null) { - $hash = 'hash='.substr(PassHash::hmac('md5', $this->media, auth_cookiesalt()), 0, 6).'&'; - } - return '/lib/exe/fetch.php?'.$hash.$w.$h.'{%token%}media='.rawurlencode($this->media); + return '/lib/exe/fetch.php?'.$w.$h.'{%token%}media='.rawurlencode($this->media); } - function fetchResponse($token, $hash=null){ + function fetchResponse($token) { $request = new TestRequest(); - return $request->get(array(),str_replace('{%token%}',$token,$this->getUri($hash))); + return $request->get(array(), str_replace('{%token%}', $token, $this->getUri())); } /** - * modified image request with invalid hash - * expect: 412 status code + * modified image request with valid token + * and not-modified image request with valid token + * + * expect: header with mime-type + * expect: content + * expect: no error response */ - function test_invalid_hash() { - $invalid_hash = 'hash='.substr(PassHash::hmac('md5', 'junk', auth_cookiesalt()), 0, 6).'&'; - $token = 'tok='.media_get_token($this->media, $this->width, $this->height).'&'; + function test_valid_token() { + $valid_token_resize = 'tok='.media_get_token($this->media, $this->width, $this->height).'&'; - $this->assertEquals(412,$this->fetchResponse($token, $invalid_hash)->getStatusCode()); + $this->handlevalidresponse($valid_token_resize); + + //original size + $this->width = $this->height = 0; + $valid_token_original = 'tok='.media_get_token($this->media, $this->width, $this->height).'&'; + + $this->handlevalidresponse($valid_token_original); } /** - * modified image request with valid token - * expect: header with mime-type - * expect: content - * expect: no error response + * Performs asserts for valid request + * + * @param $valid_token */ - function test_valid_token(){ - $valid_token = 'tok='.media_get_token($this->media, $this->width, $this->height).'&'; - + private function handlevalidresponse($valid_token){ $response = $this->fetchResponse($valid_token); - $this->assertTrue((bool)$response->getHeader('Content-Type')); - $this->assertTrue((bool)($response->getContent())); + $this->assertTrue((bool) $response->getHeader('Content-Type')); + $this->assertTrue((bool) ($response->getContent())); $status_code = $response->getStatusCode(); $this->assertTrue(is_null($status_code) || (200 == $status_code)); @@ -75,41 +78,30 @@ class fetch_statuscodes_external_test extends DokuWikiTest { * modified image request with invalid token * expect: 412 status code */ - function test_invalid_token(){ - $invalid_token = 'tok='.media_get_token('junk',200,100).'&'; - $this->assertEquals(412,$this->fetchResponse($invalid_token)->getStatusCode()); + function test_invalid_token() { + $invalid_tokens = array( + 'invalid_token_wrongid' => media_get_token('junk', 200, 100), + 'invalid_token_wrongh' => media_get_token($this->media, 200, 10), + 'invalid_token_wrongw' => media_get_token($this->media, 20, 100), + 'invalid_token_wrongwh' => media_get_token($this->media, 20, 10) + ); + foreach($invalid_tokens as $invalid_token) + $this->assertEquals(412, $this->fetchResponse('tok='.$invalid_token.'&')->getStatusCode()); + } /** * modified image request with no token + * and not modified image with no token * expect: 412 status code */ - function test_missing_token(){ - $no_token = ''; - $this->assertEquals(412,$this->fetchResponse($no_token)->getStatusCode()); - } - - /** - * native image request which doesn't require a token - * try: with a token & without a token - * expect: (for both) header with mime-type, content matching source image filesize & no error response - */ - function test_no_token_required(){ - $this->width = $this->height = 0; // no width & height, means image request at native dimensions - $any_token = 'tok='.media_get_token('junk',200,100).'&'; + function test_missing_token() { $no_token = ''; - $file = media_get_from_URL($this->media,'png', -1); - $bytes = filesize($file); - foreach(array($any_token, $no_token) as $token) { - $response = $this->fetchResponse($token); - $this->assertTrue((bool)$response->getHeader('Content-Type')); - $this->assertEquals(strlen($response->getContent()), $bytes); + $this->assertEquals(412, $this->fetchResponse($no_token)->getStatusCode()); - $status_code = $response->getStatusCode(); - $this->assertTrue(is_null($status_code) || (200 == $status_code)); - } + $this->width = $this->height = 0; + $this->assertEquals(412, $this->fetchResponse($no_token)->getStatusCode()); } - } //Setup VIM: ex: et ts=4 : -- cgit v1.2.3 From cc036f74ff14c387f24d72f5a52f2f158208846e Mon Sep 17 00:00:00 2001 From: Klap-in Date: Thu, 1 Aug 2013 23:06:03 +0200 Subject: remove hash for external images, but use token url parameter instead --- inc/common.php | 19 +++++++------------ inc/fetch.functions.php | 8 ++------ inc/media.php | 2 +- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/inc/common.php b/inc/common.php index 1b4d9e8e4..a34cf96c0 100644 --- a/inc/common.php +++ b/inc/common.php @@ -148,7 +148,7 @@ function pageinfo() { $info['id'] = $ID; $info['rev'] = $REV; - if(isset($_SERVER['REMOTE_USER'])) { + if(isset($_SERVER['REMOTE_USER'])) { $sub = new Subscription(); $info['subscribed'] = $sub->user_subscription(); } else { @@ -474,7 +474,7 @@ function ml($id = '', $more = '', $direct = true, $sep = '&', $abs = false) if(is_array($more)) { // add token for resized images - if($more['w'] || $more['h']){ + if($more['w'] || $more['h'] || $isexternalimage){ $more['tok'] = media_get_token($id,$more['w'],$more['h']); } // strip defaults for shorter URLs @@ -485,12 +485,13 @@ function ml($id = '', $more = '', $direct = true, $sep = '&', $abs = false) $more = buildURLparams($more, $sep); } else { $matches = array(); - if (preg_match_all('/\b(w|h)=(\d*)\b/',$more,$matches,PREG_SET_ORDER)){ + if (preg_match_all('/\b(w|h)=(\d*)\b/',$more,$matches,PREG_SET_ORDER) || $isexternalimage){ $resize = array('w'=>0, 'h'=>0); foreach ($matches as $match){ $resize[$match[1]] = $match[2]; } - $more .= $sep.'tok='.media_get_token($id,$resize['w'],$resize['h']); + $more .= $more === '' ? '' : $sep; + $more .= 'tok='.media_get_token($id,$resize['w'],$resize['h']); } $more = str_replace('cache=cache', '', $more); //skip default $more = str_replace(',,', ',', $more); @@ -506,14 +507,8 @@ function ml($id = '', $more = '', $direct = true, $sep = '&', $abs = false) // external URLs are always direct without rewriting if($isexternalimage) { $xlink .= 'lib/exe/fetch.php'; - // add hash: - $xlink .= '?hash='.substr(PassHash::hmac('md5', $id, auth_cookiesalt()), 0, 6); - if($more) { - $xlink .= $sep.$more; - $xlink .= $sep.'media='.rawurlencode($id); - } else { - $xlink .= $sep.'media='.rawurlencode($id); - } + $xlink .= '?'.$more; + $xlink .= $sep.'media='.rawurlencode($id); return $xlink; } diff --git a/inc/fetch.functions.php b/inc/fetch.functions.php index 3c700b35b..207ad9e5f 100644 --- a/inc/fetch.functions.php +++ b/inc/fetch.functions.php @@ -101,8 +101,8 @@ function checkFileStatus(&$media, &$file, $rev = '', $width=0, $height=0) { //media to local file if(media_isexternal($media)) { - //check hash - if(substr(PassHash::hmac('md5', $media, auth_cookiesalt()), 0, 6) !== $INPUT->str('hash')) { + //check token for external image and additional for resized and cached images + if(media_get_token($media, $width, $height) !== $INPUT->str('tok')) { return array(412, 'Precondition Failed'); } //handle external images @@ -111,10 +111,6 @@ function checkFileStatus(&$media, &$file, $rev = '', $width=0, $height=0) { //download failed - redirect to original URL return array(302, $media); } - // check token for resized and cached images - if (($width || $height) && media_get_token($media, $width, $height) !== $INPUT->str('tok')) { - return array(412, 'Precondition Failed'); - } } else { $media = cleanID($media); if(empty($media)) { diff --git a/inc/media.php b/inc/media.php index fbe1363ec..c0e3e9f82 100644 --- a/inc/media.php +++ b/inc/media.php @@ -1900,7 +1900,7 @@ function media_crop_image($file, $ext, $w, $h=0){ */ function media_get_token($id,$w,$h){ // token is only required for modified images - if ($w || $h) { + if ($w || $h || media_isexternal($id)) { $token = $id; if ($w) $token .= '.'.$w; if ($h) $token .= '.'.$h; -- cgit v1.2.3 From e8ec13b9a448dc4c0be4aa459d1586165aed6044 Mon Sep 17 00:00:00 2001 From: Klap-in Date: Fri, 2 Aug 2013 13:38:31 +0200 Subject: localized texts for templates --- inc/template.php | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/inc/template.php b/inc/template.php index bb5f2cd53..33b886927 100644 --- a/inc/template.php +++ b/inc/template.php @@ -1192,6 +1192,39 @@ function tpl_getLang($id) { return $lang[$id]; } +/** + * locale_xhtml($id) + * + * retrieve a language dependent file and pass to xhtml renderer for display + * template equivalent of p_locale_xhtml() + * + * @param string $id id of language dependent wiki page + * @return string parsed contents of the wiki page in xhtml format + */ +function tpl_locale_xhtml($id) { + return p_cached_output(tpl_localFN($id)); +} + +/** + * localFN($id) + * + * prepends appropriate path for a language dependent filename + * template equivalent of localFN() + */ +function tpl_localFN($id) { + $path = tpl_incdir().'lang/'; + global $conf; + $file = DOKU_CONF.'/template_lang/'.$conf['template'].'/'.$conf['lang'].'/'.$id.'.txt'; + if (!@file_exists($file)){ + $file = $path.$conf['lang'].'/'.$id.'.txt'; + if(!@file_exists($file)){ + //fall back to english + $file = $path.'en/'.$id.'.txt'; + } + } + return $file; +} + /** * prints the "main content" in the mediamanger popup * -- cgit v1.2.3 From acd3eb673b5f7c26fc8ec53d0147b30769e2a866 Mon Sep 17 00:00:00 2001 From: Klap-in Date: Fri, 2 Aug 2013 13:41:42 +0200 Subject: Enable LANG.template.