Initial commit

This commit is contained in:
Jono Menz 2014-08-13 10:11:18 +09:30
parent a4264b3f98
commit 3f85bd14fb
23 changed files with 643 additions and 3 deletions

View File

@ -1,4 +1,41 @@
silverstripe-betternavigator
============================
![Diagram of module](/images/demo.png?raw=true)
Front-end utility menu for SilverStripe websites featuring administration and development tools
This module is intended to replicate and expand upon the functionality provided by SilverStripe's built-in SilverStripeNavigator class. It provides a handy front-end menu for CMS users which offers these features:
**For Content Authors**
- Indicates to a user that they are logged in
- Indicates whether they are viewing draft or live content
- Quickly edit the page you're viewing
**For Developers**
- When in Dev Mode links are included for accessing most of SilverStripe's [URL Variable Tools](http://doc.silverstripe.org/framework/en/reference/urlvariabletools)
- Developers can access these tools on a live website by nominating themselves as a developer in the site config
##Requirements
SilverStripe 3.1
##Installation
**Composer / Packagist ([best practice](http://doc.silverstripe.org/framework/en/trunk/installation/composer))**
Add "jonom/silverstripe-betternavigator" to your requirements.
**Manually**
Download, place the folder in your project root, rename it to 'betternavigator' (if applicable) and run a dev/build?flush=1.
##How to use
Just place **$BetterNavigator** somewhere in your template(s). If your website uses caching, make sure BetterNavigator's output is excluded.
##Customisation
Scripts and CSS are included via the BetterNavigator.ss template, so you can completely customise the front-end code and included links by copying or creating your own BetterNavigator.ss template.
The BetterNavigator.ss template's scope is set to the page that is being viewed, so any methods available in your page controller will be available in the BetterNavigator.ss template. This should allow you to add custom links by page type if you wish.
##Known issues
- Probably won't work in IE8 or lower.

4
_config.php Normal file
View File

@ -0,0 +1,4 @@
<?php
//Attach BetterNavigator to Controllers
ContentController::add_extension('ContentController','BetterNavigator');

7
_config/config.yml Normal file
View File

@ -0,0 +1,7 @@
---
Name: betternavigator
After: 'framework/*','cms/*'
---
LeftAndMain:
extra_requirements_javascript:
- 'betternavigator/javascript/BN.LeftAndMain.Preview.js'

64
code/BetterNavigator.php Executable file
View File

@ -0,0 +1,64 @@
<?php
class BetterNavigator extends DataExtension {
/**
* Nominate developers who can access developer tools on live site
* Example YAML:
*
* BetterNavigator:
* developers:
* - 'dev@yoursite.com'
* - 'otherdev@yoursite.com'
*
* @config
* @var array
*/
private static $developers;
/**
* Provides a front-end utility menu with administrative functions and developer tools
* Relies on SilverStripeNavigator
*
* @return string
*/
public function BetterNavigator() {
$isDev = Director::isDev();
if($isDev || Permission::check('CMS_ACCESS_CMSMain') || Permission::check('VIEW_DRAFT_CONTENT')) {
if($this->owner && $this->owner->dataRecord) {
//Get SilverStripeNavigator links & stage info (CMS/Stage/Live/Archive)
$nav = array();
$navigator = new SilverStripeNavigator($this->owner->dataRecord);
$items = $navigator->getItems();
foreach($items as $item) {
$nav[$item->getName()] = array(
'Link' => $item->getLink(),
'Active' => $item->isActive()
);
}
//Is the logged in member nominated as a developer?
$member = Member::currentUser();
$devs = Config::inst()->get('BetterNavigator', 'developers');
$isDeveloper = $member && is_array($devs) ? in_array($member->Email, $devs) : false;
//Add other data for template
$nav = array_merge($nav, array(
'Member' => $member,
'Stage' => Versioned::current_stage(),
'LoginLink' => Config::inst()->get('Security', 'login_url'),
'Mode' => Director::get_environment_type(),
'IsDeveloper' => $isDeveloper
));
//Merge with page data, send to template and render
$nav = new ArrayData($nav);
$page = $this->owner->customise($nav);
return $page->renderWith('BetterNavigator');
}
}
return false;
}
}

17
composer.json Normal file
View File

@ -0,0 +1,17 @@
{
"name": "jonom/silverstripe-betternavigator",
"description": "Front-end utility menu for SilverStripe websites featuring administration and development tools",
"type": "silverstripe-module",
"keywords": ["silverstripe", "navigator", "SilverStripeNavigator", "BetterNavigator"],
"license": "BSD-3-Clause",
"authors": [{
"name": "Jonathon Menz",
"homepage": "http://jonathonmenz.com"
}],
"require": {
"silverstripe/framework": "~3.1"
},
"extra": {
"installer-name": "betternavigator"
}
}

210
css/betternavigator.css Normal file
View File

@ -0,0 +1,210 @@
.bn-icon-sprite, .bn-icon-close, .bn-icon-cog, .bn-icon-db, .bn-icon-devmode, .bn-icon-edit, .bn-icon-flush, .bn-icon-info, .bn-icon-tick, .bn-icon-tools, .bn-icon-user, .bn-icon-view {
background-image: url('/betternavigator/images/bn-icon-sff60849a67.png');
background-repeat: no-repeat;
}
.bn-icon-close {
background-position: 0 0;
height: 12px;
width: 12px;
}
.bn-icon-cog {
background-position: 0 -12px;
height: 17px;
width: 17px;
}
.bn-icon-db {
background-position: 0 -29px;
height: 16px;
width: 16px;
}
.bn-icon-devmode {
background-position: 0 -45px;
height: 16px;
width: 16px;
}
.bn-icon-edit {
background-position: 0 -61px;
height: 16px;
width: 16px;
}
.bn-icon-flush {
background-position: 0 -77px;
height: 16px;
width: 16px;
}
.bn-icon-info {
background-position: 0 -93px;
height: 16px;
width: 16px;
}
.bn-icon-tick {
background-position: 0 -109px;
height: 16px;
width: 16px;
}
.bn-icon-tools {
background-position: 0 -125px;
height: 16px;
width: 16px;
}
.bn-icon-user {
background-position: 0 -141px;
height: 16px;
width: 16px;
}
.bn-icon-view {
background-position: 0 -157px;
height: 16px;
width: 16px;
}
span[class^='bn-icon'], span[class*=' bn-icon'] {
display: inline-block;
}
#BetterNavigator {
position: fixed;
top: 0;
right: 0;
z-index: 99999;
background: #cfd8de;
border: 1px solid #ecf0f2;
border-width: 0 0 1px 1px;
box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.5);
font-family: Helvetica, Arial, sans-serif;
font-size: 12px;
text-align: left;
}
#BetterNavigator.collapsed {
right: auto;
left: 100%;
width: auto;
overflow: visible;
}
#BetterNavigator.collapsed #BetterNavigatorStatus {
-moz-transform: rotate(90deg);
-ms-transform: rotate(90deg);
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
-moz-transform-origin: 0 0;
-ms-transform-origin: 0 0;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
white-space: nowrap;
box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5);
border: 1px solid #fff;
border-width: 0 1px 1px 0;
}
#BetterNavigator.collapsed #BetterNavigatorStatus .bn-icon-close {
display: none;
}
#BetterNavigator.collapsed #BetterNavigatorStatus .bn-icon-cog {
display: inline-block;
}
#BetterNavigator.collapsed #BetterNavigatorContent {
display: none;
}
#BetterNavigatorStatus {
color: #fff;
background: #6f6f6f;
text-transform: uppercase;
cursor: pointer;
padding: 10px 15px 8px;
font-weight: bold;
}
#BetterNavigatorStatus.Live {
background: #39b54a;
}
#BetterNavigatorStatus.Live:hover {
background: #36ab46;
}
#BetterNavigatorStatus.Stage {
background: #f26c4f;
}
#BetterNavigatorStatus.Stage:hover {
background: #e5664b;
}
#BetterNavigatorStatus .bn-icon-cog {
margin: -4px 8px -4px -4px;
display: none;
}
#BetterNavigatorStatus .bn-icon-close {
float: right;
margin: 1px 0 0 0;
}
#BetterNavigatorStatus .bn-icon-cog,
#BetterNavigatorStatus .bn-icon-close {
opacity: .7;
}
#BetterNavigatorStatus:hover {
background: dimgray;
}
#BetterNavigatorStatus:hover .bn-icon-cog,
#BetterNavigatorStatus:hover .bn-icon-close {
opacity: 1;
}
#BetterNavigatorContent {
padding: 6px;
color: #71767a;
}
#BetterNavigatorContent .bn-heading {
text-align: center;
text-transform: uppercase;
font-size: 11px;
margin: 8px 0 4px 0;
}
#BetterNavigatorContent span[class^='bn-icon'], #BetterNavigatorContent span[class*=' bn-icon'] {
margin: -2px 5px -3px -2px;
}
#BetterNavigatorContent a,
#BetterNavigatorContent span.bn-disabled {
display: block;
background: #eceff2;
color: #313639;
font-family: Helvetica, Arial, sans-serif;
font-size: 12px;
border-radius: 5px;
border-bottom: 1px solid #a3aaaf;
margin: 0 0 4px 0;
padding: 6px 10px 5px 10px;
line-height: 16px;
font-weight: bold;
}
#BetterNavigatorContent a .light,
#BetterNavigatorContent span.bn-disabled .light {
font-weight: normal;
}
#BetterNavigatorContent a:focus,
#BetterNavigatorContent a:hover,
#BetterNavigatorContent a:active {
background: #fff;
color: #000;
}
#BetterNavigatorContent span.bn-disabled {
background: #afbac0;
color: #51565a;
cursor: default;
}
body > p.message {
text-align: left;
background: #fff;
color: #222;
padding: 10px 20px;
margin: 0;
border-bottom: 1px solid #ccc;
border-left: 5px solid #1d8aff;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
images/bn-icon/close.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1014 B

BIN
images/bn-icon/cog.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
images/bn-icon/db.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
images/bn-icon/devmode.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
images/bn-icon/edit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
images/bn-icon/flush.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
images/bn-icon/info.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
images/bn-icon/tick.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
images/bn-icon/tools.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
images/bn-icon/user.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
images/bn-icon/view.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
images/demo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,17 @@
//Hide the navigator when we're in the CMS
//ToDo - should be easier to use afterIframeAdjustedForPreview() but I couldn't work out how to do this
(function($) {
$('.cms-preview').entwine({
onadd: function() {
var iframe = this.find('iframe');
if (iframe){
iframe.bind('load', function() {
var doc = this.contentDocument;
if(!doc) return;
var navi = doc.getElementById('BetterNavigator');
if(navi) navi.style.display = 'none';
});
}
}
});
}(jQuery));

36
javascript/betternavigator.js Executable file
View File

@ -0,0 +1,36 @@
//For reading cookies
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++) {
var c = ca[i];
while (c.charAt(0)===' ') {
c = c.substring(1);
}
if (c.indexOf(name) !== -1) {
return c.substring(name.length,c.length);
}
}
return "";
}
//Do some stuff when the dom is loaded. (Won't work in IE8 or lower)
document.addEventListener("DOMContentLoaded", function() {
//Dom elements
var BetterNavigator = document.getElementById("BetterNavigator");
var BetterNavigatorStatus = document.getElementById("BetterNavigatorStatus");
//Toggle visibility of menu by clicking status
BetterNavigatorStatus.onclick=function(){
BetterNavigator.className = BetterNavigator.className === 'collapsed' ? 'open' : 'collapsed';
//Set cookie to remember state
document.cookie="BetterNavigator=" + BetterNavigator.className;
};
//Restore menu state
if (getCookie('BetterNavigator') === 'open') {
BetterNavigator.className = 'open';
}
});

167
scss/betternavigator.scss Normal file
View File

@ -0,0 +1,167 @@
@import "compass/css3";
@import "compass/utilities/sprites";
//Icons
$bn-icon-sprite-dimensions: true;
@import "bn-icon/*.png";
@include all-bn-icon-sprites;
span[class^='bn-icon'],span[class*=' bn-icon']{
display: inline-block;
}
//Container
#BetterNavigator {
position: fixed;
top: 0;
right: 0;
z-index: 99999;
background: #cfd8de;
border: 1px solid #ecf0f2;
border-width: 0 0 1px 1px;
box-shadow: 0px 0px 3px rgba(0,0,0,0.5);
font-family: Helvetica, Arial, sans-serif;
font-size: 12px;
text-align: left;
//Toggle states
&.collapsed {
right: auto;
left: 100%;
width: auto;
overflow: visible;
}
&.collapsed #BetterNavigatorStatus {
@include rotate(90deg);
@include transform-origin(0,0);
white-space: nowrap;
box-shadow: 0px 0px 1px rgba(0,0,0,0.5);
border: 1px solid #fff;
border-width: 0 1px 1px 0;
.bn-icon-close {
display: none;
}
.bn-icon-cog {
display: inline-block;
}
}
&.collapsed #BetterNavigatorStatus {
}
&.collapsed #BetterNavigatorContent {
display: none;
}
}
//Status
#BetterNavigatorStatus {
color: #fff;
background: #6f6f6f;
text-transform: uppercase;
cursor: pointer;
padding: 10px 15px 8px;
font-weight: bold;
&.Live {
background: #39b54a;
&:hover {
background: shade(#39b54a, 5);
}
}
&.Stage {
background: #f26c4f;
&:hover {
background: shade(#f26c4f, 5);
}
}
.bn-icon-cog {
margin: -4px 8px -4px -4px;
display: none;
}
.bn-icon-close {
float: right;
margin: 1px 0 0 0;
}
.bn-icon-cog,
.bn-icon-close {
opacity: .7;
}
&:hover {
background: shade(#6f6f6f, 5);
.bn-icon-cog,
.bn-icon-close {
opacity: 1;
}
}
}
//Content
#BetterNavigatorContent {
padding: 6px;
color: #71767a;
.bn-heading {
text-align: center;
text-transform: uppercase;
font-size: 11px;
margin: 8px 0 4px 0;
}
span[class^='bn-icon'],span[class*=' bn-icon']{
margin: -2px 5px -3px -2px;
}
a,
span.bn-disabled {
display: block;
background: #eceff2;
color: #313639;
font-family: Helvetica, Arial, sans-serif;
font-size: 12px;
border-radius: 5px;
border-bottom: 1px solid #a3aaaf;
margin: 0 0 4px 0;
padding: 6px 10px 5px 10px;
line-height: 16px;
font-weight: bold;
.light {
font-weight: normal;
}
}
a:focus,
a:hover,
a:active {
background: #fff;
color: #000;
}
span.bn-disabled {
background: #afbac0;
color: #51565a;
cursor: default;
}
}
//Some hlep for debugging info
body > p.message {
text-align: left;
background: #fff;
color: #222;
padding: 10px 20px;
margin: 0;
border-bottom: 1px solid #ccc;
border-left: 5px solid #1d8aff;
}

View File

@ -0,0 +1,81 @@
<% if $ID > 0 %><%-- Only show on 'real' pages --%>
<% require javascript("betternavigator/javascript/betternavigator.js") %>
<% require css("betternavigator/css/betternavigator.css") %>
<div id="BetterNavigator" class="collapsed">
<div id="BetterNavigatorStatus" class="$Stage">
<span class="bn-icon-cog"></span>
<% if $LiveLink.Active %>Published<% end_if %>
<% if $StageLink.Active %>Draft<% end_if %>
<% if $ArchiveLink.Active %>Archived<% end_if %>
<span class="bn-icon-close"></span>
</div>
<div id="BetterNavigatorContent">
<div class="bn-links">
<% if not $LiveLink.Active %>
<% if $LiveLink.Link %>
<a href="$LiveLink.Link"><span class="bn-icon-view"></span>View Published</a>
<% else %>
<span class="bn-disabled"><span class="bn-icon-view"></span>Not yet published</span>
<% end_if %>
<% end_if %>
<% if not $StageLink.Active %>
<% if $StageLink.Link %>
<a href="$StageLink.Link"><span class="bn-icon-view"></span>View Draft</a>
<% else %>
<span class="bn-disabled"><span class="bn-icon-view"></span>Deleted from draft site</span>
<% end_if %>
<% end_if %>
<a href="$CMSLink.Link" target="_blank"><span class="bn-icon-edit"></span>Edit in CMS</a>
<% if $Member %>
<a href="Security/logout?BackURL=$Link"><span class="bn-icon-user"></span>Log out<% if $Member.FirstName %><span class="light"> ($Member.FirstName)</span><% end_if %></a>
<% else %>
<a href="$LoginLink?BackURL=$Link"><span class="bn-icon-user"></span>Log in</a>
<% end_if %>
</div>
<% if $Mode=='dev' || $IsDeveloper %>
<div class="bn-heading">Developer Tools</div>
<div class="bn-links">
<% if $Mode='dev' %>
<span class="bn-disabled" title="Log out to end Dev Mode"><span class="bn-icon-tick"></span>Dev Mode On</span>
<% else %>
<a href="$Link?isDev=1"><span class="bn-icon-devmode"></span>Dev Mode</a>
<% end_if %>
<a href="$Link?flush=all"><span class="bn-icon-flush"></span>Flush Templates</a>
<a href="/dev/build/?flush=1" target="_blank"><span class="bn-icon-db"></span>Build Database</a>
<a href="/dev/" target="_blank"><span class="bn-icon-tools"></span>Dev Menu</a>
</div>
<div class="bn-heading">Debugging</div>
<div class="bn-links">
<a href="$Link?showtemplate=1"><span class="bn-icon-info"></span>Show Template</a>
<a href="$Link?debug=1&isDev=1"><span class="bn-icon-info"></span>Debug Page</a>
<a href="$Link?debugmethods=1"><span class="bn-icon-info"></span>Debug Methods</a>
<a href="$Link?debug_request=1&isDev=1"><span class="bn-icon-info"></span>Debug Request</a>
<a href="$Link?debugfailover=1&isDev=1"><span class="bn-icon-info"></span>Debug Failover</a>
<a href="$Link?showqueries=1&isDev=1"><span class="bn-icon-info"></span>Show Queries</a>
<a href="$Link?previewwrite=1&isDev=1"><span class="bn-icon-info"></span>Preview write</a>
</div>
<% end_if %>
</div>
</div>
<% end_if %>