diff --git a/css/area_main-sidebar-content.less b/css/area_main-sidebar-content.less new file mode 100644 index 0000000..862c0fc --- /dev/null +++ b/css/area_main-sidebar-content.less @@ -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; + } + } + } +} diff --git a/css/area_main-sidebar-nav.less b/css/area_main-sidebar-nav.less new file mode 100755 index 0000000..6565b61 --- /dev/null +++ b/css/area_main-sidebar-nav.less @@ -0,0 +1,152 @@ +/** + * This file provides the design styles the navigational elements in the sidebar + * + * @author Jana Deutschlaender + * @author Andreas Gohr + */ +#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; + } + } + } + } +} diff --git a/css/area_main-sidebar.less b/css/area_main-sidebar.less deleted file mode 100755 index d801f34..0000000 --- a/css/area_main-sidebar.less +++ /dev/null @@ -1,288 +0,0 @@ -/** - * This file provides the design styles for the sidebar (navmain). - * - * @author Jana Deutschlaender - */ - - -#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; - } - } - } - } -} diff --git a/css/area_sidetools.less b/css/area_sidetools.less deleted file mode 100755 index 7d005da..0000000 --- a/css/area_sidetools.less +++ /dev/null @@ -1,342 +0,0 @@ -/** - * This file provides the design styles for the sitetools (nav). - * - * @author Jana Deutschlaender - */ - - -.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; - } - } -} diff --git a/img/account-settings.svg b/img/account-settings.svg new file mode 100644 index 0000000..a7223e9 --- /dev/null +++ b/img/account-settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/apple-safari.svg b/img/apple-safari.svg new file mode 100644 index 0000000..5edc4f4 --- /dev/null +++ b/img/apple-safari.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/sitemap.svg b/img/sitemap.svg new file mode 100644 index 0000000..1afc9f7 --- /dev/null +++ b/img/sitemap.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/js/sidebar-menu.js b/js/sidebar-menu.js deleted file mode 100755 index 471bc47..0000000 --- a/js/sidebar-menu.js +++ /dev/null @@ -1,153 +0,0 @@ -( function( $, spc ) { - - var addToggleLink = function($elem){ - $elem.wrapInner(''); - }, - - 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 ); - diff --git a/js/sidebar.js b/js/sidebar.js new file mode 100644 index 0000000..f31bb75 --- /dev/null +++ b/js/sidebar.js @@ -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('') + .text(text.substr(0, 1).toUpperCase() + text.substr(1, 1).toLowerCase()) + .wrapInner(''); + 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('
') + .attr('role', 'heading') + .attr('aria-level', '2') + .text(text) + .wrapInner('') + .prepend($icon) + ; + + // wrap all following siblings til the next element in a wrapper + const $wrap = jQuery('
') + .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(); +}); + diff --git a/lang/de/lang.php b/lang/de/lang.php index 21178ba..a45586b 100755 --- a/lang/de/lang.php +++ b/lang/de/lang.php @@ -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'; diff --git a/lang/en/lang.php b/lang/en/lang.php index 3ae289b..c4573d8 100755 --- a/lang/en/lang.php +++ b/lang/en/lang.php @@ -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'; diff --git a/main.php b/main.php index 11c2fcf..6d3f3e4 100755 --- a/main.php +++ b/main.php @@ -167,59 +167,14 @@ $classWideContent = ($ACT === "show") ? "": "wide-content "; ?>
- diff --git a/script.js b/script.js index 6ecec7e..2b8a288 100755 --- a/script.js +++ b/script.js @@ -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 */ diff --git a/style.ini b/style.ini index 6785b2e..2e9d166 100755 --- a/style.ini +++ b/style.ini @@ -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 diff --git a/svg.php b/svg.php new file mode 100644 index 0000000..1fab9c2 --- /dev/null +++ b/svg.php @@ -0,0 +1,327 @@ +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 `` 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 ""; + } + + /** + * 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(); + + diff --git a/tpl/main-sidebar-nav.php b/tpl/main-sidebar-nav.php new file mode 100644 index 0000000..dad01bb --- /dev/null +++ b/tpl/main-sidebar-nav.php @@ -0,0 +1,74 @@ + + + + + + + + + + + + diff --git a/tpl/nav-main.php b/tpl/nav-main.php deleted file mode 100755 index 4349a58..0000000 --- a/tpl/nav-main.php +++ /dev/null @@ -1,12 +0,0 @@ -"; - echo "
".tpl_getLang('head_menu_main')."
"; - echo PHP_EOL; - tpl_include_page($conf['sidebar'], 1, 1); - echo PHP_EOL; - echo ""; - - endif ?> diff --git a/tpl/nav-sitetools.php b/tpl/nav-sitetools.php deleted file mode 100755 index cb57c7e..0000000 --- a/tpl/nav-sitetools.php +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/tpl/nav-trace.php b/tpl/nav-trace.php deleted file mode 100755 index 52ade4f..0000000 --- a/tpl/nav-trace.php +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/tpl/nav-usermenu.php b/tpl/nav-usermenu.php deleted file mode 100755 index f6fe3fe..0000000 --- a/tpl/nav-usermenu.php +++ /dev/null @@ -1,23 +0,0 @@ - - - - -