Merge branch 'sidebar' into live

* sidebar:
  fix problems with ini handling in svg dispatch
  added profile link to usertools in sidebar
  finally align the menu items correctly
  some more list adjustments for sidebar
  add level1 class to fake inpage lists
  adjusted language
  some style adjustments for the sidebar
  complete refactor of the sidebar behaviour javascript RES-754
  style the fake icon
  use jQuery slector to define the elements
  directly embed SVGs for better styling
  very simple styling of the new sidebar behaviour.
  New sidebar JavaScript logic
  allow style.ini replacements in SVG dispatcher
  SVG Dispatch: allow for referencing material design icons
  add caching and fix <g> wrapping
  fixed content type header
  fixed auth check
  feat: add background-colors to SVG-dispatcher
  first go at a dispatcher to dynamically recolor SVGs
This commit is contained in:
Andreas Gohr 2017-02-21 13:46:23 +01:00
commit 248d08817b
20 changed files with 729 additions and 897 deletions

View file

@ -0,0 +1,19 @@
/**
* This file provides the design styles the non-navigational elements in the sidebar
*/
#dokuwiki__aside {
// do not indent the first level of lists
// and use less indention in deeper levels
ul, ol {
padding-left: 0;
ul, ol {
padding-left: @margin-small;
li {
margin-left: 0;
}
}
}
}

152
css/area_main-sidebar-nav.less Executable file
View file

@ -0,0 +1,152 @@
/**
* This file provides the design styles the navigational elements in the sidebar
*
* @author Jana Deutschlaender <deutschlaender@cosmocode.de>
* @author Andreas Gohr <gohr@cosmocode.de>
*/
#dokuwiki__aside {
@icon-size: @font-size-big;
@menu-margin: @icon-size + @margin-small*2; // FIXME this is still wrong
margin-left: @menu-margin; // moves *all* sidebar content to the right
// the toggle element
h6 {
cursor: pointer;
font-weight: normal;
margin-left: (@menu-margin * -1); // moves the toggles back to the left
color: @color-nav;
border: 1px solid transparent;
border-radius: @fix_border-radius;
transition: @transition color, @transition background-color, @transition border-color;
height: @icon-size + @margin-small;
display: flex;
flex-direction: row;
align-items: center;
span {
display: inline-block;
vertical-align: middle;
}
span.lbl {
flex-grow: 1;
}
span.ico {
width: @menu-margin;
height: @icon-size;
flex-grow: 0;
border-right: 1px solid @color-border;
text-align: center;
margin-right: @margin-small;
color: @color-nav;
// simple fake icon
strong {
display: inline-block;
font-size: @icon-size * 0.5;
width: @icon-size * 0.9;
height: @icon-size * 0.9;
line-height: @icon-size * 0.9;
margin: @icon-size * 0.05;
vertical-align: baseline;
text-align: center;
color: @color-nav;
border: 2px solid @color-nav;
border-top-right-radius: 50%;
border-bottom-left-radius: 50%;
}
// real icon
svg {
width: @icon-size;
height: @icon-size;
path {
fill: @color-nav;
}
}
}
&:hover,
&:focus,
&:active {
background-color: @button_color;
border-color: @button_background;
color: @button_background;
text-decoration: none;
span.ico strong {
color: @button_background;
border-color: @button_background;
}
span.ico svg path {
fill: @button_background;
}
}
}
// the panel (hidden by default)
div.nav-panel {
display: none;
}
}
// FIXME check if the stuff below is still relevant
/* + + + + + + + + + + + + + + + + + + + + + + + + + + */
/* min-width: 1440px */
@media @screen_min-xlg {
#dokuwiki__aside.main-sidebar {
.nav-main {
.li {
font-size: @font-size-default;
padding: .1em 0;
* {
font-size: inherit;
font-weight: inherit;
}
}
> ul > li > .li {
font-size: @font-size-default;
* {
font-size: inherit;
}
}
}
}
}
/* + + + + + + + + + + + + + + + + + + + + + + + + + + */
/* max-width: 1199px */
@media @screen_max-xlg {
#dokuwiki__aside.main-sidebar {
.nav-main {
.li {
font-size: @font-size-default;
padding: .15em 0 .15em .25rem;
* {
font-size: inherit;
font-weight: inherit;
}
}
> ul > li > .li {
font-size: @font-size-default;
> * {
font-size: inherit;
}
}
}
}
}

View file

@ -1,288 +0,0 @@
/**
* This file provides the design styles for the sidebar (navmain).
*
* @author Jana Deutschlaender <deutschlaender@cosmocode.de>
*/
#dokuwiki__aside.main-sidebar {
counter-reset: nav-counter;
/* + + + + + nav main + + + + + */
.nav-main {
> ul {
@icon-size: @margin-default;
margin: 0 0 @margin-default;
padding: 0;
ul {
margin-left: (@icon-size + .5);
}
li {
list-style-type: none;
color: @color-nav;
&:first-of-type {
padding-top: .3em;
}
}
.li {
a {
display: list-item;
list-style-type: square;
color: @color-nav;
font-weight: normal;
padding-top: .1em;
padding-bottom: .1em;
transition: @transition color;
&:hover,
&:focus,
&:active {
color: @button_background;
}
}
}
/* + + + first level + + + */
> li {
counter-increment: nav-counter;
position: relative;
list-style-type: none;
margin: 0;
padding: 0 0 .3em;
&:not(:last-of-type)::after {
content: '';
position: absolute;
left: 0;
bottom: 0;
display: block;
width: 100%;
height: 1px;
background-color: @color-border;
}
> .li {
position: relative;
z-index: 1;
margin-top: -1px;
padding: .5em 0 .5em (@margin-big + 1.1);
&[class="li"] {
border-bottom: solid 1px @color-border;
}
&::before {
.display-flex();
.flex-direction();
.justify-content();
content: counter(nav-counter);
position: absolute;
top: 0;
left: 0;
height: 100%;
width: @margin-big;
overflow: hidden;
color: @color-nav;
text-align: center;
margin-top: auto;
margin-bottom: auto;
}
&::after {
content: '';
position: absolute;
top: 15%;
bottom: 15%;
width: 1px;
left: (@margin-big + .5);
background-color: @color-border;
}
&.opened,
&.closed {
padding: 0;
&::before,
&::after {
display: none;
}
a {
position: relative;
display: block;
border: 1px solid transparent;
border-radius: @fix_border-radius;
margin-bottom: -.3rem;
padding: .7em 0 .7em (@margin-big + 1);
transition: @transition color, @transition background-color, @transition border-color;
&::before {
.display-flex();
.flex-direction();
.justify-content();
content: counter(nav-counter);
position: absolute;
top: 1px;
bottom: 1px;
left: 0;
height: 100%;
width: @margin-big;
overflow: hidden;
color: @color-nav;
text-align: center;
margin-top: auto;
margin-bottom: auto;
transition: @transition color, @transition background-color;
}
&::after {
content: '';
position: absolute;
top: 15%;
bottom: 15%;
width: 1px;
left: @margin-big;
background-color: @color-border;
transition: @transition background-color;
}
&:hover,
&:focus,
&:active {
background-color: @button_color;
border-color: @button_background;
color: @button_background;
text-decoration: none;
&::before {
color: @button_background;
}
&::after {
background-color: @button_background;
}
}
}
}
&.opened {
a {
background-color: @button_background;
color: @button_color;
&::before {
background-color: @color-site-bg;
border-radius: @fix_border-radius 0 0 @fix_border-radius;
}
&::after {
display: none;
}
&:hover,
&:focus,
&:active {
background-color: @button_color;
border-color: @button_background;
color: @button_background;
text-decoration: none;
&::before {
background-color: @button_color;
color: @button_background;
}
&::after {
display: block;
background-color: @button_background;
}
}
}
+ ul {
margin-top: .5em;
margin-bottom: .25em;
}
}
+ ul {
height: auto;
overflow: hidden;
}
&.closed + ul {
height: 0;
li a{
display: none;
}
}
}
}
}
}
}
/* + + + + + + + + + + + + + + + + + + + + + + + + + + */
/* min-width: 1440px */
@media @screen_min-xlg {
#dokuwiki__aside.main-sidebar {
.nav-main {
.li {
font-size: @font-size-default;
padding: .1em 0;
* {
font-size: inherit;
font-weight: inherit;
}
}
> ul > li > .li {
font-size: @font-size-default;
* {
font-size: inherit;
}
}
}
}
}
/* + + + + + + + + + + + + + + + + + + + + + + + + + + */
/* max-width: 1199px */
@media @screen_max-xlg {
#dokuwiki__aside.main-sidebar {
.nav-main {
.li {
font-size: @font-size-default;
padding: .15em 0 .15em .25rem;
* {
font-size: inherit;
font-weight: inherit;
}
}
> ul > li > .li {
font-size: @font-size-default;
> * {
font-size: inherit;
}
}
}
}
}

View file

@ -1,342 +0,0 @@
/**
* This file provides the design styles for the sitetools (nav).
*
* @author Jana Deutschlaender <deutschlaender@cosmocode.de>
*/
.side-tools.main-sidebar {
@icon-size: @margin-default;
counter-increment: bar-counter;
ul,
.trace {
padding-left: (@margin-big + .5);
}
ul {
border-bottom: 1px solid @color-border;
}
li {
list-style-type: none;
a {
display: list-item;
list-style-type: square;
color: @color-nav;
padding-top: .1em;
padding-bottom: .1em;
transition: @transition color;
&:hover,
&:focus,
&:active {
color: @button_background;
}
}
&:first-of-type {
padding-top: .3em;
}
}
> nav {
> ul {
margin: 0;
padding: 0 0 0 (@margin-big + .5);
li {
list-style-type: none;
color: @color-nav;
&:first-of-type {
padding-top: .3em;
}
}
}
}
/* + + + + + headlines for linklists + + + + + */
h6 {
position: relative;
width: auto;
height: auto;
color: @color-nav;
font-weight: normal;
padding: .7em 0 .7em (@margin-big + 1.1);
&[class="sr-only"] {
border-bottom: solid 1px @color-border;
}
* {
color: inherit;
}
/* + + + icon + + + */
&::before {
.display-flex();
.flex-direction();
.justify-content();
content: counter(bar-counter, lower-alpha);
position: absolute;
top: 0;
left: 0;
height: 100%;
width: @margin-big;
overflow: hidden;
text-align: center;
margin-top: auto;
margin-bottom: auto;
}
/* + + + line bottom + + + */
&::after {
content: '';
position: absolute;
top: 15%;
bottom: 15%;
width: 1px;
left: (@margin-big + .6);
background-color: @color-border;
transition: @transition background-color;
}
+ ul,
+ div {
height: auto;
overflow: hidden;
}
/* + + + toggle + + + */
&.opened,
&.closed {
padding: 0;
&::before,
&::after {
display: none;
}
a {
position: relative;
display: block;
border: 1px solid transparent;
border-radius: @fix_border-radius;
padding: .6em 0 .6em (@margin-big + 1);
transition: @transition color, @transition background-color, @transition border-color;
&::before {
.display-flex();
.flex-direction();
.justify-content();
content: counter(bar-counter, lower-alpha);
position: absolute;
top: 1px;
bottom: 1px;
left: 0;
height: 100%;
width: @margin-big;
overflow: hidden;
color: @color-nav;
text-align: center;
margin-top: auto;
margin-bottom: auto;
transition: @transition color;
}
&::after {
content: '';
position: absolute;
top: 15%;
bottom: 15%;
width: 1px;
left: @margin-big;
background-color: @color-border;
transition: @transition background-color;
}
&:hover,
&:focus,
&:active {
background-color: @button_color;
border-color: @button_background;
color: @button_background;
text-decoration: none;
&::before {
color: @button_background;
}
&::after {
background-color: @button_background;
}
}
}
}
&.opened {
a {
background-color: @button_background;
color: @button_color;
&::before {
background-color: @color-site-bg;
border-radius: @fix_border-radius 0 0 @fix_border-radius;
}
&::after {
display: none;
}
&:hover,
&:focus,
&:active {
background-color: @button_color;
border-color: @button_background;
color: @button_background;
text-decoration: none;
&::before {
background-color: @button_color;
color: @button_background;
}
&::after {
display: block;
background-color: @button_background;
}
}
}
+ ul,
+ div {
height: auto;
overflow: hidden;
}
+ ul {
margin-top: .5em;
padding-bottom: .4rem;
}
}
&.closed {
+ ul,
+ div {
height: 0;
a{
display: none;
}
}
}
}
/* + + + + + f.i. trace + + + + + */
p {
max-height: 6rem;
overflow-y: auto;
background-color: @color-content-bg;
border: 1px solid @button_background;
border-radius: @fix_border-radius;
font-size: @font-size-small;
margin-top: .1rem;
padding: .3rem .6em;
* {
font-size: inherit;
}
.bchead {
display: none;
}
.bcsep {
float: left;
clear: both;
display: block;
width: 3%;
vertical-align: top;
color: @color-link;
padding-top: .3em;
}
.breadcrumbs {
border: 0 none;
padding: 0;
margin: 0;
}
bdi {
display: block;
float: left;
width: 94%;
line-height: 125%;
padding: .1rem 0;
margin-left: 2%;
}
a {
cursor: pointer;
}
}
}
/* + + + + + + + + + + + + + + + + + + + + + + + + + + */
/* min-width: 1440px */
@media @screen_min-xlg {
.side-tools.main-sidebar {
h6 {
font-size: @font-size-default;
* {
font-size: inherit;
}
}
li {
font-size: @font-size-small;
padding: .1em 0 .1em .1rem;
> * {
font-size: inherit;
}
}
}
}
/* + + + + + + + + + + + + + + + + + + + + + + + + + + */
/* max-width: 1439px */
@media @screen_max-xlg {
.side-tools.main-sidebar {
h6 {
font-size: @font-size-default;
}
li {
font-size: @font-size-small;
padding: .15em 0 .15em .23rem;
> * {
font-size: inherit;
}
}
p {
font-size: @font-size-small;
}
}
}

1
img/account-settings.svg Normal file
View file

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14M7,22H9V24H7V22M11,22H13V24H11V22M15,22H17V24H15V22Z" /></svg>

After

Width:  |  Height:  |  Size: 472 B

1
img/apple-safari.svg Normal file
View file

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12C4,14.09 4.8,16 6.11,17.41L9.88,9.88L17.41,6.11C16,4.8 14.09,4 12,4M12,20A8,8 0 0,0 20,12C20,9.91 19.2,8 17.89,6.59L14.12,14.12L6.59,17.89C8,19.2 9.91,20 12,20M12,12L11.23,11.23L9.7,14.3L12.77,12.77L12,12M12,17.5H13V19H12V17.5M15.88,15.89L16.59,15.18L17.65,16.24L16.94,16.95L15.88,15.89M17.5,12V11H19V12H17.5M12,6.5H11V5H12V6.5M8.12,8.11L7.41,8.82L6.35,7.76L7.06,7.05L8.12,8.11M6.5,12V13H5V12H6.5Z" /></svg>

After

Width:  |  Height:  |  Size: 787 B

1
img/sitemap.svg Normal file
View file

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M9,2V8H11V11H5C3.89,11 3,11.89 3,13V16H1V22H7V16H5V13H11V16H9V22H15V16H13V13H19V16H17V22H23V16H21V13C21,11.89 20.11,11 19,11H13V8H15V2H9Z" /></svg>

After

Width:  |  Height:  |  Size: 432 B

View file

@ -1,153 +0,0 @@
( function( $, spc ) {
var addToggleLink = function($elem){
$elem.wrapInner('<a href="#toggleMenu" class="toggler"></a>');
},
setContentMinHeight = function(){
var $sidebar = $('.page-wrapper').find('> .tools').find('.col-xs-12');
if($sidebar.length == 1){
var h = $sidebar.height(),
num = parseFloat(h);
if(!isNaN(num)){
$('#dokuwiki__content').css('minHeight',num + 100);
}
}
},
setWideContent = function(){
var $openTogglers = $('.main-sidebar').find('.opened').find('.toggler');
$openTogglers.trigger( "click" );
$('body').addClass('wide-content');
},
setDefaultContent= function(){
$('body').removeClass('wide-content');
},
toggleState = function($toggler){
$toggler.toggleClass('closed');
$toggler.toggleClass('opened');
},
focusFirstSubLink = function($elem, is2nd){
var $foc = (is2nd) ? $elem.find('a')[1] : $elem.find('a')[0];
if($foc){
$foc.focus();
}
return $foc;
},
focusLastSubLink = function($elem){
var $foc = $elem.find('a:last-child'),
height = $elem.find('p').scrollHeight;
if($foc){
$foc.focus();
}
$elem.scrollTop(height);
return $foc;
},
mainMenu = function(){
var $menu = $('.nav-main').find('> ul');
try{
if($menu.length > 0){
var $toggler = $menu.find('> li.level1 > .li'),
$submenu = $menu.find('> li.level1 > ul');
if($toggler.length > 0 && $submenu.length > 0){
$toggler.addClass('closed');
addToggleLink($toggler);
$toggler.each(function( index ) {
$(this).on( "click", function(e) {
e.preventDefault();
var $this = $(this);
toggleState($this);
if($this.hasClass('opened')){
var $foc = focusFirstSubLink($this.closest('li.level1'), true);
}
if($('body').hasClass('wide-content')){
setDefaultContent();
}
});
});
//FIXME: store current nav state with local storage
}
}
}catch(err){
}
},
toggleMainContent = function(){
var $toggler = $('.togglelink.page_main-content').find('a');
$toggler.on("click", function (e) {
e.preventDefault();
var $link = $(this);
if($('body').hasClass('wide-content')){
setDefaultContent();
}else{
setWideContent();
}
});
},
sideMenu = function(){
var $menus = $('.tools').find('.toggle-menu');
try{
$menus.each(function( ) {
var $menu = $(this);
if($menu.length > 0){
var $toggler = $menu.find('h6'),
$submenu = $menu.find('nav > ul, nav > div');
if($toggler.length > 0 && $submenu.length > 0) {
$toggler.addClass('closed');
addToggleLink($toggler);
$toggler.each(function (index) {
$(this).on("click", function (e) {
e.preventDefault();
var $this = $(this);
toggleState($this);
if ($this.hasClass('opened')) {
var $elem = ($submenu.is('div')) ? focusLastSubLink($submenu): focusFirstSubLink($submenu,false);
}
if($('body').hasClass('wide-content')){
setDefaultContent();
}
});
});
//FIXME: store current nav state with local storage
}
}
});
}catch(err){
//console.log('err');
}
};
$(function(){
mainMenu();
sideMenu();
toggleMainContent();
setContentMinHeight();
});
} )( jQuery, spc );

144
js/sidebar.js Normal file
View file

@ -0,0 +1,144 @@
/**
* Sets up the sidebar behaviour
*/
jQuery(function () {
const $nav = jQuery('#dokuwiki__aside');
if (!$nav.length) return;
/**
* closes sidebar
*/
const setWideContent = function () {
$nav.find('div.nav-panel').hide(); // close all panels
jQuery('body').addClass('wide-content');
};
/**
* opens the sidebar
*/
const setDefaultContent = function () {
jQuery('body').removeClass('wide-content');
};
/**
* Accessibility helper, focuses the first link witih the given element
*
* @param {jQuery} $elem
*/
const focusFirstSubLink = function ($elem) {
$elem.find('a').first().focus();
};
/**
* Toggle a navigation panel
*
* @param {jQuery} $toggler The h6 toggler
*/
const toggleNav = function ($toggler) {
const $panel = $toggler.next('div.nav-panel');
const isOpen = $panel.is(':visible');
// open sidebar on interaction
setDefaultContent();
// toggle the panel, focus first link after opening
$panel.dw_toggle(!isOpen, function () {
if (!isOpen) {
focusFirstSubLink($panel);
}
});
};
/**
* Initialize the content navigation
*
* It mangles the sidebar content and handles inline Icon configuration
*/
const initContentNav = function () {
const $main = $nav.find('nav.nav-main');
if (!$main.length) return;
const ELEMENT = 'h1,h2,h3,h4,h5'; // FIXME move to config
const $elements = $main.find(ELEMENT);
$elements.each(function () {
const $me = jQuery(this);
// prepare text and the optional icon
const data = $me.text().split('@', 2);
const text = data[0].trim();
const $icon = jQuery('<span class="ico">')
.text(text.substr(0, 1).toUpperCase() + text.substr(1, 1).toLowerCase())
.wrapInner('<strong>');
if (data[1]) {
const src = data[1].trim();
$icon.load(DOKU_BASE + 'lib/tpl/sprintdoc/svg.php?svg=' + src + '&e=1'); // directly embed
}
// make the new toggler
const $toggler = jQuery('<h6>')
.attr('role', 'heading')
.attr('aria-level', '2')
.text(text)
.wrapInner('<span class="lbl">')
.prepend($icon)
;
// wrap all following siblings til the next element in a wrapper
const $wrap = jQuery('<div>')
.addClass('nav-panel');
const $sibs = $me.nextAll();
for (let i = 0; i < $sibs.length; i++) {
const $sib = jQuery($sibs[i]);
if ($sib.is(ELEMENT)) break;
$sib.detach().appendTo($wrap);
}
$wrap.insertAfter($me);
// replace element with toggler
$me.replaceWith($toggler);
});
};
/**
* Initialize the open/close toggling of menu entries
*/
const initMenuHandling = function () {
$nav.on('click', 'h6', function () {
toggleNav(jQuery(this));
});
};
/**
* Make sure the content area is always as high as the sidebar
*/
const initContentMinHeight = function () {
const $sidebar = jQuery('.page-wrapper').find('> .tools').find('.col-xs-12');
if ($sidebar.length == 1) {
const num = parseFloat($sidebar.height());
if (!isNaN(num)) {
jQuery('#dokuwiki__content').css('minHeight', num + 100);
}
}
};
/**
* Initialize the sidebar handle behaviour
*/
const initSidebarToggling = function () {
const $toggler = jQuery('.togglelink.page_main-content').find('a');
$toggler.click(function (e) {
e.preventDefault();
if (jQuery('body').hasClass('wide-content')) {
setDefaultContent();
} else {
setWideContent();
}
});
};
// main
initContentNav();
initSidebarToggling();
initMenuHandling();
initContentMinHeight();
});

View file

@ -18,7 +18,7 @@ $lang['head_quick_search'] = 'wikiübergreifende Schnellsuche';
$lang['head_menu_main'] = 'Hauptmenü';
$lang['head_menu_status'] = 'Seitenstatus';
$lang['head_breadcrumb'] = 'Standortanzeiger';
$lang['head_menu_trace'] = 'zuletzt angesehen';
$lang['head_menu_trace'] = 'Zuletzt Angesehen';
$lang['head_meta_box'] = 'Metainformationen zur Seite';
$lang['jump_to_quicksearch'] = 'Springe zur Schnellsuche';

View file

@ -18,7 +18,7 @@ $lang['head_quick_search'] = 'quick search';
$lang['head_menu_main'] = 'main menu';
$lang['head_menu_status'] = 'site status';
$lang['head_breadcrumb'] = 'location indicator';
$lang['head_menu_trace'] = 'trace / visited last';
$lang['head_menu_trace'] = 'Last Visited Pages';
$lang['head_meta_box'] = 'meta data for this page';
$lang['jump_to_quicksearch'] = 'Jump to quick search';

View file

@ -167,59 +167,14 @@ $classWideContent = ($ACT === "show") ? "": "wide-content ";
?>
</div><!-- .search -->
<div id="dokuwiki__aside" class="menu main-sidebar">
<div id="dokuwiki__aside">
<?php
/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + */
/* main menu */
/* sidebar */
/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + */
include('tpl/nav-main.php');
include('tpl/main-sidebar-nav.php');
?>
</div><!-- .menu -->
<div class="side-tools main-sidebar toggle-menu">
<?php
/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + */
/* site tools */
/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + */
include('tpl/nav-sitetools.php');
?>
</div><!-- .side-tools -->
<div class="side-tools main-sidebar toggle-menu">
<?php
/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + */
/* user tools */
/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + */
include('tpl/nav-usermenu.php');
?>
</div><!-- .side-tools -->
<div class="side-tools main-sidebar toggle-menu">
<?php
/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + */
/* trace */
/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + */
include('tpl/nav-trace.php');
?>
</div><!-- .side-tools -->
<div class="sidebarfooter main-sidebar">
<?php
/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + */
/* Include Hook: sidebarfooter.html */
/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + */
tpl_includeFile('sidebarfooter.html')
?>
</div><!-- .sidebarheader -->
</div><!-- .aside -->
</div><!-- .col -->
</div><!-- .row -->

View file

@ -3,5 +3,5 @@
/* DOKUWIKI:include js/plugins/do_tasks.js */
/* DOKUWIKI:include js/sidebar-menu.js */
/* DOKUWIKI:include js/meta-box.js */
/* DOKUWIKI:include js/sidebar.js */

View file

@ -71,8 +71,9 @@ css/area_nav-usertools.less = all
css/area_sidebar-search.less = all
css/area_nav-pagetools.less = all
css/area_nav-metabox.less = all
css/area_main-sidebar.less = all
css/area_sidetools.less = all
css/area_main-sidebar-nav.less = all
css/area_main-sidebar-content.less = all
;css/area_sidetools.less = all
css/area_main-content.less = all
css/area_togglelink.less = all

327
svg.php Normal file
View file

@ -0,0 +1,327 @@
<?php
namespace dokuwiki\template\sprintdoc;
if(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__) . '/../../../');
require_once(DOKU_INC . 'inc/init.php');
/**
* Custom XML node that allows prepending
*/
class SvgNode extends \SimpleXMLElement {
/**
* @param string $name Name of the new node
* @param null|string $value
* @return SvgNode
*/
public function prependChild($name, $value = null) {
$dom = dom_import_simplexml($this);
$new = $dom->insertBefore(
$dom->ownerDocument->createElement($name, $value),
$dom->firstChild
);
return simplexml_import_dom($new, get_class($this));
}
/**
* @param \SimpleXMLElement $node the node to be added
* @return \SimpleXMLElement
*/
public function appendNode(\SimpleXMLElement $node) {
$dom = dom_import_simplexml($this);
$domNode = dom_import_simplexml($node);
$newNode = $dom->appendChild($domNode);
return simplexml_import_dom($newNode, get_class($this));
}
/**
* @param \SimpleXMLElement $node the child to remove
* @return \SimpleXMLElement
*/
public function removeChild(\SimpleXMLElement $node) {
$dom = dom_import_simplexml($node);
$dom->parentNode->removeChild($dom);
return $node;
}
/**
* Wraps all elements of $this in a `<g>` tag
*
* @return SvgNode
*/
public function groupChildren() {
$dom = dom_import_simplexml($this);
$g = $dom->ownerDocument->createElement('g');
while($dom->childNodes->length > 0) {
$child = $dom->childNodes->item(0);
$dom->removeChild($child);
$g->appendChild($child);
}
$g = $dom->appendChild($g);
return simplexml_import_dom($g, get_class($this));
}
/**
* Add new style definitions to this element
* @param string $style
*/
public function addStyle($style) {
$defs = $this->defs;
if(!$defs) {
$defs = $this->prependChild('defs');
}
$defs->addChild('style', $style);
}
}
/**
* Manage SVG recoloring
*/
class SVG {
const IMGDIR = __DIR__ . '/img/';
const BACKGROUNDCLASS = 'sprintdoc-background';
const CDNBASE = 'https://cdn.rawgit.com/Templarian/MaterialDesign/master/icons/svg/';
protected $file;
protected $replacements;
/**
* SVG constructor
*/
public function __construct() {
global $INPUT;
$svg = cleanID($INPUT->str('svg'));
if(blank($svg)) $this->abort(404);
// try local file first
$file = self::IMGDIR . $svg;
if(!file_exists($file)) {
// try media file
$file = mediaFN($svg);
if(file_exists($file)) {
// media files are ACL protected
if(auth_quickaclcheck($svg) < AUTH_READ) $this->abort(403);
} else {
// get it from material design icons
$file = getCacheName($svg, '.svg');
io_download(self::CDNBASE . $svg, $file);
}
}
// check if media exists
if(!file_exists($file)) $this->abort(404);
$this->file = $file;
}
/**
* Generate and output
*/
public function out() {
global $conf;
$file = $this->file;
$params = $this->getParameters();
header('Content-Type: image/svg+xml');
$cachekey = md5($file . serialize($params) . $conf['template'] . filemtime(__FILE__));
$cache = new \cache($cachekey, '.svg');
$cache->_event = 'SVG_CACHE';
http_cached($cache->cache, $cache->useCache(array('files' => array($file, __FILE__))));
if($params['e']) {
$content = $this->embedSVG($file);
} else {
$content = $this->generateSVG($file, $params);
}
http_cached_finish($cache->cache, $content);
}
/**
* Generate a new SVG based on the input file and the parameters
*
* @param string $file the SVG file to load
* @param array $params the parameters as returned by getParameters()
* @return string the new XML contents
*/
protected function generateSVG($file, $params) {
/** @var SvgNode $xml */
$xml = simplexml_load_file($file, SvgNode::class);
$xml->addStyle($this->makeStyle($params));
$this->createBackground($xml);
$xml->groupChildren();
return $xml->asXML();
}
/**
* Return the absolute minimum path definition for direct embedding
*
* No styles will be applied. They have to be done in CSS
*
* @param string $file the SVG file to load
* @return string the new XML contents
*/
protected function embedSVG($file) {
/** @var SvgNode $xml */
$xml = simplexml_load_file($file, SvgNode::class);
$def = hsc((string) $xml->path['d']);
$w = hsc($xml['width']);
$h = hsc($xml['height']);
$v = hsc($xml['viewBox']);
return "<svg width=\"$w\" height=\"$h\" viewBox=\"$v\"><path d=\"$def\" /></svg>";
}
/**
* Get the supported parameters from request
*
* @return array
*/
protected function getParameters() {
global $INPUT;
$params = array(
'e' => $INPUT->bool('e', false),
's' => $this->fixColor($INPUT->str('s')),
'f' => $this->fixColor($INPUT->str('f')),
'b' => $this->fixColor($INPUT->str('b')),
'sh' => $this->fixColor($INPUT->str('sh')),
'fh' => $this->fixColor($INPUT->str('fh')),
'bh' => $this->fixColor($INPUT->str('bh')),
);
return $params;
}
/**
* Generate a style setting from the input variables
*
* @param array $params associative array with the given parameters
* @return string
*/
protected function makeStyle($params) {
$element = 'path'; // FIXME configurable?
if(empty($params['b'])) {
$params['b'] = $this->fixColor('00000000');
}
$style = 'g rect.' . self::BACKGROUNDCLASS . '{fill:' . $params['b'] . ';}';
if($params['bh']) {
$style .= 'g:hover rect.' . self::BACKGROUNDCLASS . '{fill:' . $params['bh'] . ';}';
}
if($params['s'] || $params['f']) {
$style .= 'g ' . $element . '{';
if($params['s']) $style .= 'stroke:' . $params['s'] . ';';
if($params['f']) $style .= 'fill:' . $params['f'] . ';';
$style .= '}';
}
if($params['sh'] || $params['fh']) {
$style .= 'g:hover ' . $element . '{';
if($params['sh']) $style .= 'stroke:' . $params['sh'] . ';';
if($params['fh']) $style .= 'fill:' . $params['fh'] . ';';
$style .= '}';
}
return $style;
}
/**
* Takes a hexadecimal color string in the following forms:
*
* RGB
* RRGGBB
* RRGGBBAA
*
* Converts it to rgba() form.
*
* Alternatively takes a replacement name from the current template's style.ini
*
* @param string $color
* @return string
*/
protected function fixColor($color) {
if($color === '') return '';
if(preg_match('/^([0-9a-f])([0-9a-f])([0-9a-f])$/i', $color, $m)) {
$r = hexdec($m[1] . $m[1]);
$g = hexdec($m[2] . $m[2]);
$b = hexdec($m[3] . $m[3]);
$a = hexdec('ff');
} elseif(preg_match('/^([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?$/i', $color, $m)) {
$r = hexdec($m[1]);
$g = hexdec($m[2]);
$b = hexdec($m[3]);
if(isset($m[4])) {
$a = hexdec($m[4]);
} else {
$a = hexdec('ff');
}
} else {
if(is_null($this->replacements)) $this->initReplacements();
if(isset($this->replacements[$color])) {
return $this->replacements[$color];
}
return '';
}
return "rgba($r,$g,$b,$a)";
}
/**
* sets a rectangular background of the size of the svg/this itself
*
* @param SvgNode $g
* @return SvgNode
*/
protected function createBackground(SvgNode $g) {
$rect = $g->prependChild('rect');
$rect->addAttribute('class', self::BACKGROUNDCLASS);
$rect->addAttribute('x', '0');
$rect->addAttribute('y', '0');
$rect->addAttribute('height', '100%');
$rect->addAttribute('width', '100%');
return $rect;
}
/**
* Abort processing with given status code
*
* @param int $status
*/
protected function abort($status) {
http_status($status);
exit;
}
/**
* Initialize the available replacement patterns
*
* Loads the style.ini from the template (and various local locations)
* via a core function only available through some hack.
*/
protected function initReplacements() {
global $conf;
define('SIMPLE_TEST', 1); // hacky shit
include DOKU_INC . 'lib/exe/css.php';
$ini = css_styleini($conf['template']);
$this->replacements = $ini['replacements'];
}
}
// main
$svg = new SVG();
$svg->out();

74
tpl/main-sidebar-nav.php Normal file
View file

@ -0,0 +1,74 @@
<nav class="nav-main">
<?php /* main navigation, loaded from sidebar, fixed up by javascript */
tpl_include_page($conf['sidebar'], 1, 1);
?>
</nav>
<nav class="nav-sitetools">
<h6 role="heading" aria-level="2">
<span class="ico"><?php echo inlineSVG(__DIR__ . '/../img/sitemap.svg') ?></span>
<span class="lbl"><?php echo $lang['site_tools']; ?></span>
</h6>
<div class="nav-panel level1">
<ul>
<?php
tpl_toolsevent(
'sitetools',
array(
'recent' => tpl_action('recent', 1, 'li', 1),
'media' => tpl_action('media', 1, 'li', 1),
'index' => tpl_action('index', 1, 'li', 1),
)
);
?>
</ul>
</div>
</nav>
<nav class="nav-usermenu">
<h6 role="heading" aria-level="2">
<span class="ico"><?php echo inlineSVG(__DIR__ . '/../img/account-settings.svg') ?></span>
<span class="lbl"><?php echo $lang['user_tools']; ?></span>
</h6>
<div class="nav-panel level1">
<ul>
<?php /* dokuwiki user tools */
tpl_toolsevent(
'usertools',
array(
'login' => tpl_action('login', 1, 'li', 1),
'profile' => tpl_action('profile', 1, 'li', 1),
'admin' => tpl_action('admin', 1, 'li', 1),
'register' => tpl_action('register', 1, 'li', 1),
)
);
?>
</ul>
</div>
</nav>
<?php if($conf['breadcrumbs']): ?>
<nav class="nav-trace">
<h6 role="heading" aria-level="2">
<span class="ico"><?php echo inlineSVG(__DIR__ . '/../img/apple-safari.svg') ?></span>
<span class="lbl"><?php echo tpl_getLang('head_menu_trace'); ?></span>
</h6>
<div class="nav-panel level1">
<ul>
<?php /* trace breadcrumbs as list */
// FIXME move to helper class
$crumbs = breadcrumbs();
$crumbs = array_reverse($crumbs, true);
foreach($crumbs as $id => $name) {
echo '<li>';
tpl_link(wl($id), hsc($name), 'title="' . $id . '"');
echo '</li>';
}
?>
</ul>
</div>
</nav>
<?php endif ?>

View file

@ -1,12 +0,0 @@
<?php
if (!defined('DOKU_INC')) die();
if ($showSidebar):
echo "<nav class=\"nav-main\">";
echo "<h6 class=\"sr-only\" role=\"heading\" aria-level=\"2\">".tpl_getLang('head_menu_main')."</h6>";
echo PHP_EOL;
tpl_include_page($conf['sidebar'], 1, 1);
echo PHP_EOL;
echo "</nav>";
endif ?>

View file

@ -1,14 +0,0 @@
<?php
if (!defined('DOKU_INC')) die();
if ($showSidebar): ?>
<nav id="dokuwiki__sitetools" class="nav-sitetools">
<h6 class="sr-only" role="heading" aria-level="2"><?php echo $lang['site_tools']; ?></h6>
<ul><?php tpl_toolsevent('sitetools', array(
'recent' => tpl_action('recent', 1, 'li', 1),
'media' => tpl_action('media', 1, 'li', 1),
'index' => tpl_action('index', 1, 'li', 1),
)); ?></ul>
</nav>
<?php endif ?>

View file

@ -1,11 +0,0 @@
<?php
if (!defined('DOKU_INC')) die();
if ($conf['useacl'] && $showTools): ?>
<nav class="nav-trace <?php echo $navClass?>">
<h6 class="sr-only" role="heading" aria-level="2"><?php echo tpl_getLang('head_menu_trace'); ?></h6>
<div class="trace"><p><?php tpl_breadcrumbs(); ?></p></div>
</nav><!-- #dokuwiki__usertools -->
<?php endif ?>

View file

@ -1,23 +0,0 @@
<?php
if (!defined('DOKU_INC')) die();
if ($conf['useacl'] && $showTools): ?>
<nav class="nav-usermenu <?php echo $navClass?>">
<h6 class="sr-only" role="heading" aria-level="2"><?php echo $lang['user_tools']; ?></h6>
<ul>
<li class="log"><?php tpl_actionlink('login'); ?></li>
<?php if($_SERVER['REMOTE_USER']){
echo '<a class="profile" href="'.wl(tpl_getConf('user_ns').$_SERVER['REMOTE_USER'].':') . '">'.hsc($USERINFO['name']).'</a>';
}?>
<?php /* dokuwiki user tools */
tpl_toolsevent('usertools', array(
'admin' => tpl_action('admin', 1, 'li', 1),
'register' => tpl_action('register', 1, 'li', 1),
)); ?>
</ul>
</nav><!-- #dokuwiki__usertools -->
<?php endif ?>