App restructure - closes #245

- This is a first pass at getting a more logical structure. The focus is on moving from admin/frontend to client/server.
- The location of the databases is highly important, this isn't expected to change again
In the future
- client/assets should probably become public/
- more stuff should be shared (helpers etc)
- cleanup some confusion around tpl and views
This commit is contained in:
Hannah Wolfe 2013-07-11 20:02:18 +01:00
commit 624680bb93
82 changed files with 19837 additions and 0 deletions

View File

@ -0,0 +1,69 @@
// # Temporary Admin UI
/*global window, document, $ */
(function () {
"use strict";
// UTILS
/**
* Allows to check contents of each element exactly
* @param obj
* @param index
* @param meta
* @param stack
* @returns {boolean}
*/
$.expr[":"].containsExact = function (obj, index, meta, stack) {
return (obj.textContent || obj.innerText || $(obj).text() || "") === meta[3];
};
// Called on Window resize
$(window).resize(function () {
var loginContainer = $(".js-login-container"),
marginTop = Math.floor((loginContainer.parent().height() - loginContainer.height()) / 2) - 15;
loginContainer.css('margin-top', marginTop).delay(250).fadeIn(750);
});
// Allow notifications to be dismissed
$(document).on('click', '.js-notification .close', function () {
$(this).parent().fadeOut(200, function () { $(this).remove(); });
});
$(document).ready(function () {
// ## Set interactions for all menus
// This finds all visible '.overlay' elements and hides them upon clicking away from the element itself.
$("body").on('click', function (event) {
var $target = $(event.target);
if (!$target.parents().is(".overlay:visible") && !$target.is(".overlay:visible")) {
$("body").find(".overlay:visible").fadeOut();
}
});
// LOGIN SCREEN
$(window).resize();
// EDITOR / NOTIFICATIONS
$('.entry-content header, .entry-preview header').on('click', function () {
$('.entry-content, .entry-preview').removeClass('active');
$(this).closest('section').addClass('active');
});
$('.entry-title .icon-fullscreen').on('click', function (e) {
e.preventDefault();
$('body').toggleClass('fullscreen');
});
$('.options.up').on('click', function (e) {
e.stopPropagation();
$(this).next("ul").fadeToggle(200);
});
});
}());

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

@ -0,0 +1 @@
/* IE specific override styles. */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,521 @@
/*
* These styles control elements specific to the post editor screen
* used for publishing content with Ghost.
*
* Table of Contents:
*
* Editor / Preview
* Post Preview Content
* Full Screen Mode
* Publish Bar
*/
/* =============================================================================
Editor / Preview
============================================================================= */
.editor {
// The main post title
.entry-title {
@extend %box;
height: 35px;
padding: 10px 15px;
margin-bottom: 15px;
position:relative;
@include breakpoint($mobile) {
box-shadow: none;
}
input {
border: 0;
margin: 0;
padding:0;
font-size: 2em;
font-weight: 300;
width: 100%;
&:focus {
outline: 0;
}
}
}
// The two content panel wrappers, positioned left/right
.entry-markdown { left:0; border-right:$lightbrown 2px solid; }
.entry-preview { right:0; border-left:$lightbrown 2px solid; }
// The visual styles for both panels
.entry-markdown, .entry-preview {
@include box-sizing(border-box);
width: 50%;
padding: 15px;
position: absolute;
bottom:40px; // height of the publish bar
top:69px; // height of the post title + margin
background: #fff;
box-shadow: $shadow;
@include breakpoint($mobile) {
box-shadow: none;
}
// Convert all content areas to small boxes
@include breakpoint($netbook) {
top:109px;
left:0;
right:0;
width:100%;
border:none;
z-index:100;
min-height:380px;
.markdown, .entry-preview-content {
height:50px;
overflow: hidden;
}
}
.floatingheader {
// Turn headers into tabs which act as links
// both headers set to grey/inactive colour
@include breakpoint($netbook) {
cursor:pointer;
width:50%;
border-right:$lightbrown 2px solid;
color:#fff;
font-weight: normal;
background:$brown;
position:absolute;
top:-40px;
left:0;
box-shadow: rgba(0,0,0,0.1) 0 -2px 3px inset;
a {
color:#fff;
}
}
a {
color: $brown;
}
.markdown-help {
@include icon($i-question, '', lighten($brown, 15%));
float:right;
&:hover {
@include icon($i-question, '', $brown)
}
}
.entry-word-count {
float:right;
}
}
// Give the tab with the .active class the highest z-index
&.active {
z-index: 200;
}
// Restore the normal height of the .active tab (inactive tab stays small, hidden behind)
&.active .markdown,
&.active .entry-preview-content {
height:auto;
overflow: auto;
}
// Restore the white bg of the currently .active tab, remove hand cursor from currently active tab
&.active header {
@include breakpoint($netbook) {
cursor:auto;
color: $brown;
background:#fff;
box-shadow: none;
a {
color: $brown;
}
}
}
// Hide markdown icon + wordcount when we hit mobile
@include breakpoint($mobile) {
.markdown-help,
.entry-word-count {
display: none;
}
}
}
.entry-markdown-content {
textarea {
border: 0;
width: 100%;
height: 100%;
max-width: 100%;
margin: 0;
padding: 0;
position:absolute;
top: 0;
right:0;
bottom:0;
left:0;
&:focus {
outline: 0;
}
}
.CodeMirror {
height: auto;
position:absolute;
top:0;
left:0;
right:0;
bottom:0;
font-family: $font-family-mono;
font-size:1.1em;
line-height:1.2em;
color: lighten($darkgrey, 30%);
.CodeMirror-focused,
.CodeMirror-selected {
color: $darkgrey;
background: lighten($blue, 20%);
text-shadow: none;
}
::selection {
color: $darkgrey;
background: lighten($blue, 20%);
text-shadow: none;
}
}
.CodeMirror-lines {
padding: 65px 0 40px 0; /* Vertical padding around content */
@include breakpoint($netbook) {padding-top: 25px;}
@include breakpoint($mobile) {padding: 15px 0;}
}
.CodeMirror pre {
padding: 0 40px; /* Horizontal padding of content */
@include breakpoint($mobile) {padding: 0 15px;}
}
.cm-header {
color:#000;
font-size: 1.4em;
line-height: 1.4em;
}
.cm-string,
.cm-link,
.cm-comment,
.cm-quote {color:#000;}
}
.entry-preview {
// Align the tab of entry-preview on the right
.floatingheader {
@include breakpoint($netbook) {
right:0;
left:auto;
border-right:none;
border-left:$lightbrown 2px solid;
}
}
.entry-preview-content {
position:absolute;
top:0;
right:0;
bottom:0;
left:0;
padding: 60px 40px 40px 40px;
overflow: auto;
// Tweak padding for smaller screens
@include breakpoint($netbook) {padding-top: 20px;}
@include breakpoint($mobile) {padding: 15px;}
}
}
// Special case, when scrolling, add shadows to content headers.
.scrolling {
.floatingheader {
@include breakpoint($netbook) {
box-shadow: none;
}
&::before,
&::after {
@include breakpoint($netbook) {display:none;}
}
}
.CodeMirror-scroll,
.entry-preview-content {
@include breakpoint($netbook) {
box-shadow: 0 5px 5px rgba(0,0,0,0.05) inset;
}
}
}
}//.editor
/* =============================================================================
Post Preview Content
============================================================================= */
// The styles for the actual content inside the preview
// TODO: These should just be defaults, overridden by editor.hbs in theme dir
.entry-preview-content,
.content-preview-content {
font-size:1.15em;
line-height: 1.5em;
a {
color: $blue;
text-decoration: underline;
}
p {
text-indent: 0;
margin: 1.2em 0 1.6em;
&:first-child {
margin-top:0;
}
}
h1 {
font-size: 3em;
}
h2 {
font-size: 2.2em;
}
h3 {
font-size: 1.8em;
}
.btn {
text-decoration: none;
color: $grey;
}
.img-placeholder {
border: 5px dashed $grey;
height: 100px;
position: relative;
span {
display: block;
height: 30px;
position: absolute;
margin-top: -15px;
top: 50%;
width: 100%;
text-align: center;
}
}
img {
width: 100%;
height: auto;
}
}
/* =============================================================================
Full Screen Mode
============================================================================= */
body.zen {
background: lighten($lightbrown, 3%);
#usermenu {display:none;}
#global-header, #publish-bar {
opacity: 0;
height:0;
overflow: hidden;
@include transition(all 0.5s ease-out);
}
main {top: 15px;@include transition(all 0.5s ease-out);}
.entry-markdown, .entry-preview {bottom:0;@include transition(all 0.5s ease-out);}
}
/* =============================================================================
Publish Bar
============================================================================= */
#publish-bar {
@include box-sizing(border-box);
height:40px;
padding: 0;
color: $midgrey;
background: darken($darkgrey, 4%);
position: fixed;
bottom: 0;
left:0;
right:0;
z-index:900;
box-shadow: 0 -2px 8px rgba(0,0,0,0.2);
@include breakpoint($netbook) {font-weight:normal;}
button {
min-height: 30px;
height: 30px;
line-height: 12px;
padding: 0 10px;
margin-top: 5px;
border-top:rgba(255,255,255,0.4) 1px solid;
}
.button-link { border-top: none; }
.options {
width:30px;
min-height: 30px;
height: 30px;
margin-top:5px;
box-shadow: rgba(255,255,255,0.4) 0 1px 0 inset;
&.up:hover {
@include icon($i-chevron-down) {
margin-top:-5px;
@include transform(rotate(540deg));
@include transition(transform 0.6s ease);
};
}
}
.splitbutton-save{
.button-save{
@include transition(width 0.25s ease);
}
.editor-options{
@extend %menu;
@extend %menu-right;
bottom: 140%;
right: -3%;
a{
font-size: 14px;
}
}
}
}
#entry-categories {
position: absolute;
top:0;
left:0;
right: 165px;
bottom:0;
text-transform: none;
padding: 10px 0 0 0;
}
.category-label {
display: block;
float:left;
@include icon($i-tag);
padding:1px 8px 0 8px;
@include transition;
&:hover {
cursor:pointer;
color: $lightgrey;
}
}
.category-input {
display: inline-block;
color: $lightgrey;
font-weight: 300;
background: transparent;
border: none;
&:focus {outline:none;}
}
.category {
@include icon-after($i-x, 8px, $darkgrey) {
margin-left:4px;
vertical-align:5%;
text-shadow: rgba(255,255,255,0.15) 0 1px 0;
@include transition;
}
display: block;
float: left;
margin-right: 5px;
padding: 0 5px;
color: $lightgrey;
background: lighten($grey, 15%);
border-radius: $rounded;
box-shadow:
rgba(255,255,255,0.2) 0 1px 0 inset,
#000 0 1px 3px;
&:hover {
cursor: pointer;
@include icon-after($i-x, 8px, $lightgrey) {text-shadow: none;}
}
}
.suggestions {
@extend %menu;
bottom: 100%;
li.selected{
background: $blue;
box-shadow:
rgba(255,255,255,0.2) 0 1px 0 inset,
rgba(0,0,0,0.5) 0 1px 5px;
}
mark{
background: none;
color: white;
font-weight: bold;
}
}
#entry-settings {
@include icon($i-settings, 1.1em){vertical-align:0;};
@include box-sizing(border-box);
display:inline-block;
padding: 0 10px;
line-height: 1.8em;
color: $midgrey;
@include transition;
&:hover {
color: $lightgrey;
}
}
#entry-settings-menu {
position: absolute;
bottom:50px;
right:-5px;
}
#entry-actions {
margin-right:6px;
position: relative;
}
#entry-actions-menu {
position: absolute;
bottom:50px;
right:-5px;
}

View File

@ -0,0 +1,159 @@
/*
* These styles control elements specific to the Ghost admin login screen.
*
* Table of Contents:
*
*
*/
/* =============================================================================
Login
============================================================================= */
.ghost-login {
color: $midgrey;
background: $darkgrey;
@include breakpoint($mobile) {
background: $darkgrey;
}
main {
top: 15px;
@include breakpoint($mobile) { top: 0; }
}
}//.ghost-login
.login-box {
max-width: 530px;
margin: 0 auto;
padding: 0;
display: none;
@include breakpoint(630px) {
max-width: 264px;
text-align: center;
}
}
#login {
@include box-sizing(border-box);
max-width: 530px;
color: lighten($midgrey, 15%);
@include breakpoint(630px) {
max-width: 264px;
}
div { // Yes. Really.
position:relative;
margin:0 0 5px 0;
background: lighten($darkgrey, 10%);
float: left;
@include breakpoint(630px) { margin-bottom: 1em; }
}
input {
display:inline-block;
clear:both;
margin:0;
padding: 8px 0 8px 8px;
width: 188px;
position: relative;
border: none;
color: #fff;
font-size: 1.1em;
font-weight: 200;
background: transparent;
box-shadow: none;
@include transition(background ease 0.25s);
@include breakpoint(630px) {
width:236px;
@include transition(none);
}
&:focus {
background: lighten($darkgrey, 15%);
}
}
.email-wrap {
position:relative;
@include icon($i-mail, 12px) {
position:absolute;
bottom:11px;
left:8px;
z-index:100;
}
margin-right: 3px;
border-radius: 2px 0 0 2px;
@include breakpoint(630px) {
margin-right:0;
border-radius: 2px;
}
.email {
padding-left: 28px;
border-radius: 2px 0 0 2px;
}
}
.password-wrap {
position:relative;
@include icon($i-lock, 10px) {
position:absolute;
bottom:12px;
left:11px;
z-index:100;
}
border-radius: 0 2px 2px 0;
@include breakpoint(630px) {
border-radius: 2px;
}
.password {
padding-left: 28px;
border-radius: 0 2px 2px 0;
}
}
button {
width: 85px;
height: 36px;
margin:0 0 0 10px;
padding: 0.5em 1.37em;
min-height: 30px;
min-width: 80px;
box-shadow: rgba(255,255,255,0.15) 0 1px 0 inset;
@include breakpoint(630px) {
margin:0;
width: 100%;
margin-bottom: 1em;
}
}
.meta {
clear:both;
color: $midgrey;
}
a {
color: darken($midgrey, 10%);
font-size: 0.9em;
&:hover {
color: lighten($midgrey, 5%);
text-decoration: none;
}
}
}

View File

@ -0,0 +1,248 @@
/*
* These styles control elements specific to the mage posts screen
* used for previewing and reading existing content in Ghost.
*
* Table of Contents:
*
* Manage
* Preview
*
*/
/* =============================================================================
Manage
============================================================================= */
.manage {
.content-list {
@include box-sizing(border-box);
width: 35%;
padding: 15px;
position: absolute;
bottom:0;
top:0;
left:0;
border-right:$lightbrown 2px solid;
background: #fff;
box-shadow: $shadow;
@include breakpoint(900px) {
width:300px;
}
@include breakpoint($tablet) {
width:auto;
right:0;
z-index: 500;
border:none;
}
.content-filter {
position:relative;
z-index: 300;
> a {
padding: 5px;
margin-left:-5px;
}
.menu-drop {
display: block;
}
}
.button-add {
@include icon($i-add);
position:absolute;
top:10px;
right:15px;
z-index: 700;
color: #fff;
padding-left:5px;
}
.content-list-content {
position:absolute;
top:0;
right:0;
bottom:0;
left:0;
overflow: auto;
padding-top: 40px;
}
.entry-title {
font-size: 1.4em;
line-height:1.1em;
margin-bottom:0.5em;
font-weight: normal;
}
.views {
@include icon($i-stats, 10px, $brown);
float:right;
text-align: right;
margin-left:15px;
@include breakpoint($tablet) {
float:none;
}
}
.featured .date {
@include icon($i-featured, 11px) {
margin-right:12px;
vertical-align: 0;
};
}
ol {
list-style: none;
padding:0;
margin:0;
border-top: $lightbrown 1px solid;
li {
margin:0;
padding: 0;
border-bottom: $lightbrown 1px solid;
position:relative;
a {
display:block;
padding:20px 15px;
color: $brown;
@include breakpoint($mobile) { padding:15px; }
@include breakpoint($tablet) { padding-right: 40px; }
@include icon-after($i-chevron) {
position:absolute;
top:50%;
margin-top:-6px;
right:15px;
}
@include breakpoint($biggerthan-tablet) { &::after {display: none} }
&:hover { text-decoration: none; }
}
}//li
li.active {
@include breakpoint($biggerthan-tablet) {
// only apply active styles on larger devices
border-bottom: lighten($midgrey, 40%) 1px solid;
background: lighten($midgrey, 45%);
box-shadow:
lighten($midgrey, 40%) 0 -1px 0, // top border
rgba(0,0,0,0.06) 7px 0 0 inset, // big left border
lighten($midgrey, 40%) 1px 0 0 inset; // small left border
a:hover {
box-shadow: rgba(0,0,0,0.1) 7px 0 0 inset;
@include transition(all 0.4s ease);
}
.entry-title { font-weight: bold; }
.entry-meta { color: $darkgrey; }
.views {
@include icon($i-stats, 10px, $darkgrey);
color: $darkgrey;
font-weight: normal;
}
}
}//li.active
}
}//.content-list
/* =============================================================================
Preview
============================================================================= */
.content-preview {
@include box-sizing(border-box);
width: 65%;
padding: 15px;
position: absolute;
bottom:0;
top:0;
right:0;
border-left:$lightbrown 2px solid;
background: #fff;
box-shadow: $shadow;
@include breakpoint(900px) {
width: auto;
left: 300px;
}
.unfeatured {
@include icon($i-unfeatured, 14px);
vertical-align: -6%;
margin: 0 7px 0 -5px;
padding: 5px;
}
.featured {
@include icon($i-featured, 14px);
vertical-align: -6%;
margin: 0 7px 0 -5px;
padding: 5px;
}
.normal {
text-transform: none;
margin:0 3px;
}
.content-preview-content {
position: absolute;
top:0;
right:0;
bottom:0;
left:0;
overflow: auto;
padding: 80px 40px;
.wrapper {
max-width: 700px;
margin:0 auto;
}
}
.post-controls {
float:right;
position: relative;
ul {
position: absolute;
top:15px;
right:-15px;
}
}
.post-edit {
@include icon($i-edit, 14px);
margin-right:7px;
padding: 5px;
}
.post-settings {
@include icon($i-settings, 14px);
padding: 5px;
margin-right: -5px;
}
img {
width:100%;
height:auto;
}
}//.preview-post
}//.manage

View File

@ -0,0 +1,345 @@
/*
* These styles control elements specific to the settings screen
* used for configuring your Ghost install.
*
* Table of Contents:
*
* Settings
*
*/
/* =============================================================================
Settings
============================================================================= */
.settings {
// The main white bg for the page
.wrapper {
background: #fff;
box-shadow: $shadow;
position:absolute;
top:0;
bottom:0;
left:0;
right:0;
margin:0;
padding:0;
}
.title {
text-transform: uppercase;
font-weight: normal;
font-size: 1.6em;
line-height: 0.8em;
margin:0 0 18px 0;
padding:0;
border: none;
}
/* =============================================================================
Sidebar
============================================================================= */
//The whole left column sidebar, duh.
.settings-sidebar {
width:20%;
position:absolute;
top:0;
left:0;
bottom:0;
z-index: 700;
box-shadow: $lightbrown 1px 0 0;
@include breakpoint($tablet) {
width:100%;
box-shadow: none;
}
> header {
height: 17px;
padding: 30px 15px 30px 40px;
margin-bottom: 0;
border-bottom: none;
box-shadow: #edece4 0 -1px 0 inset;
@include breakpoint($netbook) {
padding-left: 15px;
};
}
}//.settings-sidebar
//Main settings-menu styles, apply to every item
.settings-menu {
position:absolute;
top: 77px; //30px + 17px title + 30px
left:0;
bottom:0;
right:-1px;
overflow: auto;
@include breakpoint($tablet) { right:0; };
ul {
border-top:none;
@include breakpoint($tablet) { border-bottom: #edece4 1px solid; }
}
li {
margin-right:1px;
border-top: #fff 1px solid;
@include breakpoint($tablet) {
margin-right:0;
border-top: #edece4 1px solid;
}
a {
padding:15px 15px 15px 40px;
border-bottom:none;
@include breakpoint($netbook) { padding-left: 15px; }
@include breakpoint($tablet) {
@include icon-after($i-chevron) {float:right;margin-top:5px;};
}
}
&:first-child { border-top: none; }
&:first-child.active { border-top:none; }
&.active {
@include breakpoint($biggerthan-tablet) {
// only apply active styles on larger devices
margin-right:0;
position:relative;
z-index: 300;
border-top: #edece4 1px solid;
box-shadow:
#fff 1px 0 0,
#edece4 0 1px 0;
@include transition;
a {
color: $darkgrey;
font-weight: bold;
background: #fff;
}
}
}//.active
}//li
// Give all icons some space
li a:before {
margin-right: 20px;
@include breakpoint($netbook) {
margin-right: 15px;
}
}
// Add the icons for specific menu items
.general a { @include icon($i-settings) }
.publishing a { @include icon($i-content) }
.services a { @include icon($i-services) }
.users a { @include icon($i-users) }
.appearance a { @include icon($i-appearance) }
.plugins a { @include icon($i-plugins) }
}//.settings-menu
/* =============================================================================
Content
============================================================================= */
// The main content panel on the right
.settings-content {
padding:0;
position:absolute;
top:0;
right:0;
left:20%;
bottom:0;
@include breakpoint($tablet) { display: none; }
display: none;
&.active {display:block;}
> header {
height: 17px;
padding: 30px 220px 29px 40px;
border-bottom:$lightbrown 1px solid;
margin-bottom:40px;
text-transform: none;
font-weight: normal;
line-height: inherit;
color: inherit;
@include breakpoint($netbook) { padding-left:15px; }
@include breakpoint($letterbox) {
height: auto;
padding: 5px;
position: absolute;
top:0;
right:0;
border:none;
.title { display:none; }
}
}//header
.page-actions {
position:absolute;
top:20px;
right:40px;
z-index: 700;
font-size: 1em;
@include breakpoint($netbook) { right:15px; }
.button-add {
position:relative;
padding-left:50px;
@include icon($i-add, 1.4em, rgba(255,255,255,0.6)) {
position: absolute;
top:0;
padding:9px 8px 0 0;
left:9px;
bottom:0;
width: 20px;
border-right: darken($green, 8%) 1px solid;
};
}
}
.content {
position: absolute;
top:77px; //30px + 17px title + 30px
right:0;
left:0;
bottom:0;
padding:40px;
overflow:auto;
@include breakpoint($netbook) { padding-left:15px; }
@include breakpoint($letterbox) { top: 0; }
}
.user-group-header {
margin-bottom: 0px;
padding-bottom: 20px;
border: 0 none;
border-bottom: 1px solid darken($lightbrown, 10%);
h3 {
display: inline-block;
margin: 0;
color: $midbrown;
font-weight: normal;
font-size: 1.1em;
line-height: 1em;
}
}
.user-search {
display: inline-block;
float: right;
label { margin: 0}
&:hover .user-search-input, .user-search-input:focus {
width: 260px;
padding: 0 10px;
}
.user-search-input {
@include box-sizing(border-box);
width: 0px;
padding: 0;
border: none;
border-bottom: lighten($lightbrown, 2%) 1px solid;
@include transition(width 0.2s ease-in-out);
box-shadow: none;
}
.search-icon {
@include icon($i-search, 1em, $midbrown);
}
}
.users {
padding: 0px;
margin-top: 0px;
list-style: none;
}
.user {
@include box-sizing(border-box);
display: block;
width: 100%;
padding: 20px;
border: 0 none;
border-top: 1px solid $lightgrey;
&:first-child {
border: none;
}
.user-image {
display: inline-block;
width: 40px;
height: 40px;
margin-right: 17px;
vertical-align: middle;
background-color: $lightbrown;
border-radius: 20px;
&.invite {
@include box-sizing(border-box);
padding-top: 8px;
text-align: center;
@include icon($i-mail, 1em, $brown);
}
img {
width: 40px;
height: 40px;
border-radius: 20px;
}
}
.user-meta {
display: inline-block;
vertical-align: middle;
.user-name {
margin: 0;
margin-top: 0.4em;
font-weight: 400;
font-size: 1.2em;
line-height: 1em;
}
.user-last-seen {
line-height: 1em;
}
}
}
.user-role {
padding: 2px 8px;
float: right;
font-size: 0.8em;
color: #fff;
text-transform: uppercase;
&.admin {
background-color: #DE523A;
}
&.editor {
background-color: #4A8CBD;
}
}
}//.settings-content
}//.settings

View File

@ -0,0 +1,29 @@
/*
* Specific styles for re-usable animations in Ghost admin.
*
* Table of Contents:
*
*
*/
/* =============================================================================
General
============================================================================= */
@-webkit-keyframes off-canvas {
0% { left:0; }
100% { left:300px; }
}
@-moz-keyframes off-canvas {
0% { opacity: 0; }
100% { opacity: 1; }
}
@-o-keyframes off-canvas {
0% { opacity: 0; }
100% { opacity: 1; }
}
@keyframes off-canvas {
0% { opacity: 0; }
100% { opacity: 1; }
}

View File

@ -0,0 +1,546 @@
/*
* Breakpoint Sass 1.3.0
* Last updated: 2012-08-28
* Copyright: Mason Wendell 2012 - MIT Licensed
* Source: https://github.com/canarymason/breakpoint
*/
//////////////////////////////
// Default Variables
//////////////////////////////
$breakpoint-default-feature: 'min-width' !default;
$breakpoint-default-media: 'all' !default;
$breakpoint-force-media-all: false !default;
$breakpoint-default-pair: 'width' !default;
$breakpoint-to-ems: false !default;
$breakpoint-prefixes: 'webkit' 'moz' !default;
$breakpoint-prefixed-queries: 'device-pixel-ratio' 'min-device-pixel-ratio' 'max-device-pixel-ratio' !default;
$breakpoint-no-queries: false !default;
$breakpoint-no-query-wrappers: false !default;
$breakpoint-base-font-size: false;
//////////////////////////////
// Converts the input value to Base EMs
//////////////////////////////
@function breakpoint-to-base-em($value, $base-font-size: false) {
$value-unit: unit($value);
// Will convert relative EMs into root EMs.
@if $base-font-size and type-of($base-font-size) == 'number' and $value-unit == 'em' {
$base-unit: unit($base-font-size);
@if $base-unit == 'px' or $base-unit == '%' or $base-unit == 'em' or $base-unit == 'pt' {
@return base-conversion($value) / base-conversion($base-font-size) * 1em;
}
@else {
@warn '#{$base-font-size} is not set in valid units for font size!';
@return false;
}
}
@else {
@return base-conversion($value);
}
}
@function base-conversion($value) {
$unit: unit($value);
@if $unit == 'px' {
@return $value / 16px * 1em;
}
@else if $unit == '%' {
@return $value / 100% * 1em;
}
@else if $unit == 'em' {
@return $value;
}
@else if $unit == 'pt' {
@return $value / 12pt * 1em;
}
@else {
@return $value;
// @warn 'Everything is terrible! What have you done?!';
}
}
//////////////////////////////
// Returns whether the feature can have a min/max pair
//////////////////////////////
@function breakpoint-min-max($feature) {
@if $feature == 'color' or $feature == 'color-index' or $feature == 'aspect-ratio' or $feature == 'device-height' or $feature == 'device-width' or $feature == 'height' or $feature == 'monochrome' or $feature == 'resolution' or $feature == 'width' or $feature == 'device-pixel-ratio' {
@return true;
}
@else {
@return false;
}
}
//////////////////////////////
// Returns whether the feature can have a string value
//////////////////////////////
@function breakpoint-string-value($feature) {
@if $feature == 'orientation' or $feature == 'scan' or $feature == 'color' or $feature == 'resolution' or $feature == 'min-resolution' or $feature == 'max-resolution' {
@return true;
}
@else {
@return false;
}
}
//////////////////////////////
// Experimental Media Queries
//////////////////////////////
@function breakpoint-experimental($property, $prefix) {
@if $property == 'min-device-pixel-ratio' {
@if $prefix == 'webkit' {
@return '-#{$prefix}-#{$property}';
}
@else if $prefix == 'moz' {
@return 'min--#{$prefix}-device-pixel-ratio';
}
@else {
@warn '#{$property} is not fully supported in -#{prefix}';
@return 'ERROR';
}
}
@else if $property == 'max-device-pixel-ratio' {
@if $prefix == 'webkit' {
@return '-#{$prefix}-#{$property}';
}
@else if $prefix == 'moz' {
@return 'max--#{$prefix}-device-pixel-ratio';
}
@else {
@warn '#{$property} is not fully supported in -#{prefix}';
@return 'ERROR';
}
}
@else {
@return '-#{$prefix}-#{$property}';
}
}
//////////////////////////////
// Private Breakpoint Variables
//////////////////////////////
$TXkgdmFyaWFibGUhIEdvIGF3YXkh: () !default;
//////////////////////////////
// Breakpoint Get Context
// $feature: Input feature to get it's current MQ context. Returns false if no context
//////////////////////////////
@function breakpoint-get-context($feature) {
@each $context in $TXkgdmFyaWFibGUhIEdvIGF3YXkh {
@if $feature == nth($context, 1) {
@return nth($context, 2);
}
}
@return false;
}
//////////////////////////////
// Private function to set context
//////////////////////////////
@function U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh($feature, $value) {
@if $value == 'monochrome' {
$feature: 'monochrome';
}
$append: $feature;
$append: join($append, $value, space);
$TXkgdmFyaWFibGUhIEdvIGF3YXkh: append($TXkgdmFyaWFibGUhIEdvIGF3YXkh, $append, comma);
@return true;
}
//////////////////////////////
// Private function to reset context
//////////////////////////////
@mixin TXkgcmVzZXQhIEdvIGF3YXkh {
$TXkgdmFyaWFibGUhIEdvIGF3YXkh: ();
}
//////////////////////////////
// Breakpoint Mixin
//////////////////////////////
@mixin breakpoint($breakpoint, $media: $breakpoint-default-media, $no-query: false, $base-font-size: $breakpoint-base-font-size) {
// Query and Media String Defaults
$query: false !default;
$query-holder: false !default;
$media-string: false !default;
$do-prefix: false !default;
$webkit: false !default;
$webkit-first: true !default;
$moz: false !default;
$moz-first: true !default;
$o: false !default;
$o-first: true !default;
$ms: false !default;
$ms-first: true !default;
// Holder for Count
$first: true !default;
// Reset Context
@include TXkgcmVzZXQhIEdvIGF3YXkh;
// Set Media Context
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh('media', $media);
// Initialize Query String
@if $media != 'all' or $breakpoint-force-media-all {
$media-string: "#{$media} ";
}
@else {
$media-string: "";
}
// If we have a single query, let's just work with that.
@if is_breakpoint_list($breakpoint) == false {
@each $prefix-query in $breakpoint-prefixed-queries {
@if $do-prefix == false {
$do-prefix: featureExists($prefix-query, $breakpoint);
}
}
@if $do-prefix {
@each $prfx in $breakpoint-prefixes {
@if $prfx == 'webkit' {
$webkit: breakpoint-switch($breakpoint, $media-string, true, $prfx, $base-font-size: $base-font-size);
}
@if $prfx == 'moz' {
$moz: breakpoint-switch($breakpoint, $media-string, true, $prfx, $base-font-size: $base-font-size);
}
@if $prfx == 'o' {
$o: breakpoint-switch($breakpoint, $media-string, true, $prfx, $base-font-size: $base-font-size);
}
@if $prfx == 'ms' {
$ms: breakpoint-switch($breakpoint, $media-string, true, $prfx, $base-font-size: $base-font-size);
}
}
}
@else {
$query: breakpoint-switch($breakpoint, $media-string, true, $base-font-size: $base-font-size);
}
}
@else {
// See if Prefix Query exists
@each $prefix-query in $breakpoint-prefixed-queries {
@if $do-prefix == false {
$do-prefix: featureExists($prefix-query, $breakpoint);
}
}
@if $do-prefix {
@each $prfx in $breakpoint-prefixes {
@each $bkpt in $breakpoint {
@if $prfx == 'webkit' {
@if $webkit-first {
$webkit: breakpoint-switch($bkpt, $media-string, true, $prfx, $base-font-size: $base-font-size);
$webkit-first: false;
}
@else {
$webkit: join($webkit, breakpoint-switch($bkpt, $media-string, $prefix: $prfx, $base-font-size: $base-font-size));
}
}
@if $prfx == 'moz' {
@if $moz-first {
$moz: breakpoint-switch($bkpt, $media-string, true, $prfx, $base-font-size: $base-font-size);
$moz-first: false;
}
@else {
$moz: join($moz, breakpoint-switch($bkpt, $media-string, $prefix: $prfx, $base-font-size: $base-font-size));
}
}
@if $prfx == 'o' {
@if $o-first {
$o: breakpoint-switch($bkpt, $media-string, true, $prfx, $base-font-size: $base-font-size);
$o-first: false;
}
@else {
$o: join($o, breakpoint-switch($bkpt, $media-string, $prefix: $prfx, $base-font-size: $base-font-size));
}
}
@if $prfx == 'ms' {
@if $ms-first {
$ms: breakpoint-switch($bkpt, $media-string, true, $prfx, $base-font-size: $base-font-size);
$ms-first: false;
}
@else {
$ms: join($ms, breakpoint-switch($bkpt, $media-string, $prefix: $prfx, $base-font-size: $base-font-size));
}
}
}
}
}
@else {
@each $bkpt in $breakpoint {
@if $first == true {
$query: breakpoint-switch($bkpt, $media-string, true, $base-font-size: $base-font-size);
$first: false;
}
@else {
$query: join($query, breakpoint-switch($bkpt, $media-string, $base-font-size: $base-font-size));
}
}
}
}
@if $breakpoint-no-queries {
@if $no-query {
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh('no queries', true);
@if $breakpoint-no-query-wrappers and type-of($no-query) == string {
#{$no-query} & {
@content;
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh('no query wrapper', $no-query);
}
}
@else {
@content;
}
}
}
@else {
@if $breakpoint-no-query-wrappers and type-of($no-query) == string {
#{$no-query} & {
@content;
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh('no query wrapper', $no-query);
}
}
@if $query {
@media #{$query} {
@content;
}
}
@else {
$pf-queries: $webkit, $moz, $o, $ms;
$pf-query: ();
@each $pfq in $pf-queries {
@if $pfq {
$pf-query: append($pf-query, $pfq, comma);
}
}
@media #{$pf-query} {
@content;
}
}
}
@include TXkgcmVzZXQhIEdvIGF3YXkh;
}
@function breakpoint-switch($breakpoint, $media-string, $first: false, $prefix: false, $base-font-size: $breakpoint-base-font-size) {
// Feature/Value/Length/Query Placehoders:
$feature: false !default;
$min-feature: "min-#{$breakpoint-default-pair}" !default;
$max-feature: "max-#{$breakpoint-default-pair}" !default;
$value: false !default;
$min-value: false !default;
$max-value: false !default;
$length: false !default;
$query: false !default;
$length: length($breakpoint);
// Check to see if there is only one item.
@if $length == 1 {
$value: $breakpoint;
@if type-of($breakpoint) == 'number' {
$feature: $breakpoint-default-feature;
}
// If EM Breakpoints are active, do it!
@if $breakpoint-to-ems and type-of($value) == 'number' {
$value: breakpoint-to-base-em($value, $base-font-size);
}
// Build the Query
$query: breakpoint-generate($media-string, $feature, $value, $first);
// Set Context
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh($feature, $value);
}
@else if $length == 2 {
// If both are numbers, we've got a double!
@if type-of(nth($breakpoint, 1)) == 'number' and type-of(nth($breakpoint, 2)) == 'number' {
// See which is larger.
@if nth($breakpoint, 1) > nth($breakpoint, 2) {
$min-value: nth($breakpoint, 2);
$max-value: nth($breakpoint, 1);
}
@else {
$min-value: nth($breakpoint, 1);
$max-value: nth($breakpoint, 2);
}
// If EM Breakpoints are active, do it!
@if $breakpoint-to-ems and type-of($min-value) == 'number' {
$min-value: breakpoint-to-base-em($min-value, $base-font-size);
}
@if $breakpoint-to-ems and type-of($max-value) == 'number' {
$max-value: breakpoint-to-base-em($max-value, $base-font-size);
}
// Min/Max for given
$query: breakpoint-generate($media-string, $min-feature, $min-value, $first);
$query: join($query, breakpoint-generate($media-string, $max-feature, $max-value));
// Set Context
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh($min-feature, $min-value);
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh($max-feature, $max-value);
}
@else if type-of(nth($breakpoint, 1)) == 'string' and type-of(nth($breakpoint, 2)) == 'string' {
@if breakpoint-string-value(nth($breakpoint, 1)) == true {
$feature: nth($breakpoint, 1);
$value: nth($breakpoint, 2);
}
@else {
$feature: nth($breakpoint, 2);
$value: nth($breakpoint, 1);
}
// If EM Breakpoints are active, do it!
@if $breakpoint-to-ems and type-of($value) == 'number' {
$value: breakpoint-to-base-em($value, $base-font-size);
}
// Build the Query
$query: breakpoint-generate($media-string, $feature, $value, $first);
// Set Context
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh($feature, $value);
}
@else {
// Because we can have either the first or second option be the feature, we switch on it.
@if type-of(nth($breakpoint, 1)) == string {
$feature: nth($breakpoint, 1);
$value: nth($breakpoint, 2);
}
@else if type-of(nth($breakpoint, 2)) == string {
$feature: nth($breakpoint, 2);
$value: nth($breakpoint, 1);
}
@if $feature == 'device-pixel-ratio' or $feature == 'min-device-pixel-ratio' or $feature == 'max-device-pixel-ratio' {
$feature: breakpoint-experimental($feature, $prefix);
//$value: 96 * $value * 1dpi;
// @if $feature == 'device-pixel-ratio' {
// $feature: 'resolution';
// }
// @else if $feature == 'min-device-pixel-ratio' {
// $feature: 'min-resolution';
// }
// @else if $feature == 'max-device-pixel-ratio' {
// $feature: 'max-resolution';
// }
}
// If EM Breakpoints are active, do it!
@if $breakpoint-to-ems and type-of($value) == 'number' {
$value: breakpoint-to-base-em($value, $base-font-size);
}
// Build the Query
$query: breakpoint-generate($media-string, $feature, $value, $first);
// Set Context
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh($feature, $value);
}
}
@else if $length == 3 {
@if type-of(nth($breakpoint, 1)) == 'string' {
$feature: nth($breakpoint, 1);
// See which is larger.
@if nth($breakpoint, 2) > nth($breakpoint, 3) {
$min-value: nth($breakpoint, 3);
$max-value: nth($breakpoint, 2);
}
@else {
$min-value: nth($breakpoint, 2);
$max-value: nth($breakpoint, 3);
}
}
@else {
$feature: nth($breakpoint, 3);
// See which is larger.
@if nth($breakpoint, 1) > nth($breakpoint, 2) {
$min-value: nth($breakpoint, 2);
$max-value: nth($breakpoint, 1);
}
@else {
$min-value: nth($breakpoint, 1);
$max-value: nth($breakpoint, 2);
}
}
// If EM Breakpoints are active, do it!
@if $breakpoint-to-ems and type-of($min-value) == 'number' {
$min-value: breakpoint-to-base-em($min-value, $base-font-size);
}
@if $breakpoint-to-ems and type-of($max-value) == 'number' {
$max-value: breakpoint-to-base-em($max-value, $base-font-size);
}
@if breakpoint-min-max($feature) == true {
@if $feature == 'device-pixel-ratio' {
$min-feature: breakpoint-experimental('min-#{$feature}', $prefix);
$max-feature: breakpoint-experimental('max-#{$feature}', $prefix);
}
@else {
$min-feature: 'min-#{$feature}';
$max-feature: 'max-#{$feature}';
}
// Min/Max for given
$query: breakpoint-generate($media-string, $min-feature, $min-value, $first);
$query: join($query, breakpoint-generate($media-string, $max-feature, $max-value));
// Set Context
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh($min-feature, $min-value);
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh($max-feature, $max-value);
}
@else {
@warn '#{$feature} cannot have a min/max value!';
}
}
@return $query;
}
@function breakpoint-generate($media, $feature, $value, $first: false) {
// Media Query string to be returned
$new-string: "";
// If it's the first item, it gets special treatment
@if $first == true {
// And Statement
$and: 'and ';
// If $media is blank (i.e. all), remove and statement
@if $media == '' {
$and: '';
}
@if $feature != false {
$new-string: #{$media}unquote("#{$and}(#{$feature}: #{$value})");
}
@else {
$new-string: #{$media}unquote("#{$and}(#{$value})");
}
}
@else {
@if $feature != false {
$new-string: unquote("and (#{$feature}: #{$value})");
}
@else {
$new-string: unquote("and (#{$value})");
}
}
@return $new-string;
}

View File

@ -0,0 +1,419 @@
/*
* These are the global generic form styles used throughout the Ghost admin,
* but mainly in the settings pages. Don't fuck with them.
*
* Table of Contents:
*
* General
* Buttons
* Split Buttons
* iCheck jQuery Plugin Styles
*
*/
/* =============================================================================
General
============================================================================= */
form {
fieldset {
border: none;
margin:0 0 3em 0;
padding:0;
}
legend {
display: block;
width: 100%;
margin: 2em 0;
border-bottom:$lightbrown 1px solid;
font-size: 1.2em;
line-height: 2.0em;
color: $brown;
}
label {
display:block;
margin:1.5em 0;
padding-left:140px;
position:relative;
b {
display:inline-block;
position: absolute;
top:0.5em;
left:0;
width:120px;
font-weight:normal;
color:$darkgrey;
text-align: right;
}
}
p {
color: darken($brown, 5%);
font-size: 1em;
margin:0;
}
input, textarea, select {
width: 260px;
padding: 5px 7px;
margin: 0;
outline: 0;
font-size: 1.1em;
line-height: 1.4em;
background: #fff;
border: darken($lightbrown, 5%) 1px solid;
border-radius: $rounded;
@include transition(all 0.15s ease-in-out);
}
textarea {
width:100%;
max-width:340px;
min-width:250px;
height:auto;
min-height: 80px;
}
input, select, textarea {
margin-bottom:5px;
}
input[type="text"]:focus,
input[type="email"]:focus,
input[type="search"]:focus,
input[type="tel"]:focus,
input[type="url"]:focus,
input[type="password"]:focus,
input[type="number"]:focus,
input[type="date"]:focus,
input[type="month"]:focus,
input[type="week"]:focus,
input[type="time"]:focus,
input[type="datetime"]:focus,
input[type="datetime-local"]:focus,
textarea:focus {
border:$grey 1px solid;
background:#fff;
outline:none;
outline-width:0;
}
select {
width:270px;
height:30px;
line-height:30px;
}
.radio input[type="radio"],
.checkbox input[type="checkbox"] {
float: left;
width:auto;
margin-right:6px;
margin-top:4px;
font-size:1em;
}
.radio, .checkbox {
width:auto;
margin: 5px 0;
font-weight: normal;
padding:0.55em 0;
cursor: pointer;
}
}//form
/* =============================================================================
Buttons
============================================================================= */
/*
* Buttons are used for primary calls to action on a page.
*
* Usage:
* <button type="button" class="button">Default</button>
*/
// This base style is used on all buttons
%button {
@include box-sizing(border-box);
min-height: 35px;
width:auto;
display: inline-block;
padding: 0.9em 1.37em;
cursor: pointer;
text-decoration: none;
color: #fff;
font-size: 11px; // Hack because Firefox sucks ass.
line-height: 13px; // Hack because Firefox sucks ass.
font-weight: 300;
text-align: center;
letter-spacing: 1px;
text-transform: uppercase;
text-shadow: none;
border-radius: 0.2em;
border: rgba(0,0,0,0.05) 0.1em solid;
@include transition(background 0.3s ease, border-color 0.3s ease);
&:hover {
border-color: transparent;
background: #f8f8f8;
text-decoration: none;
}
}
// This is the default button style
.button,
button,
input[type="button"] {
@extend %button;
color:#777;
font-weight: normal;
background: #eee;
box-shadow: none;
&:hover {
border-color: rgba(0,0,0,0.1);
}
}
// Button for save/next/continue/confirm actions
.button-save,
button[type="submit"],
input[type="submit"] {
@extend %button;
background: $blue;
box-shadow: none;
&:hover {background: darken($blue, 10%);}
}
// Button for actions which add stuff
.button-add {
@extend %button;
background: $green;
&:hover {background: darken($green, 8%);}
}
// Button for deleting/removing stuff
.button-delete,
button[type="reset"],
input[type="reset"] {
@extend %button;
background: $red;
box-shadow: none;
&:hover {background: darken($red, 10%);}
}
// Alternative button with more visual attention, but no extra semantic meaning
.button-alt {
@extend %button;
background: lighten($darkgrey, 10%);
&:hover {background: $darkgrey;}
}
// This applies normal link styles to de-emphasise a button
.button-link {
@extend %button;
color: $blue;
background: transparent;
border: none;
&:hover {
background: transparent;
text-decoration: underline;
}
}
/* =============================================================================
Split Buttons
============================================================================= */
/*
* The splitbutton adds addition values to a button, via a dropdown (or drop-up).
*
* Usage:
* <section class="splitbutton">
* <button type="button" class="button">Split Up</button>
* <a class="options" href="#"><span class="hidden">Options</span></a>
* </section>
*/
// These are the base styles applied to all splitbuttons
%splitbutton {
display: inline-block;
position: relative;
font-size: 0; // hack to stop space after button
white-space: nowrap;
button {
font-size: 11px; // hack to restore font size
@include border-right-radius(0);
}
// This is the additional dropdown arrow, to the right of the button.
.options {
display: inline-block;
position:relative;
width: 35px;
height: 35px;
margin-left: -1px;
vertical-align: top;
text-align: center;
color: #fff;
background: #e5e5e5;
border-radius: 0 2px 2px 0;
box-shadow:
rgba(0,0,0,0.02) 0 1px 0 inset,
rgba(0,0,0,0.02) -1px 0 0 inset,
rgba(0,0,0,0.02) 0 -1px 0 inset;
@include icon($i-chevron-down, 9px) {
position: absolute;
top: 50%;
right: 50%;
margin-top: -3px;
margin-right: -5px;
@include transition(transform 0.3s ease, margin-top 0.3s ease);
};
// Spin the arrow on hover
&:hover {
box-shadow: none;
background: #f8f8f8;
@include icon($i-chevron-down) {
@include transform(rotate(360deg));
};
}
// If it has a class of "up" spin it an extra 180degress to point up
&.up:hover {
@include icon($i-chevron-down) {
margin-top:-4px;
@include transform(rotate(540deg));
@include transition(transform 0.6s ease);
};
}
}
}
// The default splitbutton
.splitbutton {
@extend %splitbutton;
.options {
color:#777;
&:hover {
box-shadow:
rgba(0,0,0,0.07) 0 1px 0 inset,
rgba(0,0,0,0.07) -1px 0 0 inset,
rgba(0,0,0,0.07) 0 -1px 0 inset;
}
}
}
// For save/next/continue/confirm actions
.splitbutton-save {
@extend %splitbutton;
.options {
background: darken($blue, 5%);
&:hover {background: darken($blue, 10%);}
}
}
// For actions which add something
.splitbutton-add {
@extend %splitbutton;
.options {
background: darken($green, 6%);
&:hover {background: darken($green, 8%);}
}
}
// For actions which delete something
.splitbutton-delete {
@extend %splitbutton;
.options {
background: darken($red, 6%);
&:hover {background: darken($red, 10%);}
}
}
// Alternative style with more visual attention, but no extra semantic meaning
.splitbutton-alt {
@extend %splitbutton;
.options {
background: lighten($darkgrey, 4%);
&:hover {background: $darkgrey;}
}
}
/* =============================================================================
iCheck jQuery Plugin Styles
============================================================================= */
.icheckbox_ghost,
.iradio_ghost {
@include box-sizing(border-box);
display: block;
width: 16px;
height: 16px;
float: left;
margin: 2px 0 0 0;
padding: 0;
margin-right: 6px;
background: none;
border: none;
box-shadow: none;
border-radius: 2px;
@include transition(
border ease 0.25s,
background ease 0.2s
);
}
.icheckbox_ghost {
border: 1px solid darken($lightbrown, 5%);
}
.icheckbox_ghost.hover {
border: $brown 1px solid;
}
.icheckbox_ghost.checked {
background: $blue;
border: $blue 1px solid;
padding:0;
@include icon($i-check, 12px, #fff) {
position: relative;
top: -4px;
left: -1px
}
}
.icheckbox_ghost.disabled {
border: 1px solid $lightbrown;
}
.icheckbox_ghost.checked.disabled {
background: $lightbrown;
}
.iradio_ghost {
border-radius: 11px;
border: 1px solid darken($lightbrown, 5%);
}
.iradio_ghost.hover {
border: $blue 2px solid;
}
.iradio_ghost.checked {
background: $blue;
border: none;
@include icon($i-check, 1em, #fff);
}
.iradio_ghost.disabled {
border: 1px solid $lightbrown;
cursor: default;
}
.iradio_ghost.checked.disabled {
background: $lightbrown;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,214 @@
/*
* The icons used in Ghost are the Pictos set by Drew Wilson - http://pictos.css
* They are embedded via a custom icon font built with http://icomoon.io
*
* Table of Contents:
*
* Font Face
* Icon Element
* Icon Variables / Short Names
* Usage
*/
/* =============================================================================
The Font Face
============================================================================= */
/* Generated by icomoon.co */
@font-face {
font-family: 'Icons';
src:url('../fonts/icons.eot');
src:url('../fonts/icons.eot?#iefix') format('embedded-opentype'),
url('../fonts/icons.woff') format('woff'),
url('../fonts/icons.ttf') format('truetype'),
url('../fonts/icons.svg#icons') format('svg');
font-weight: normal;
font-style: normal;
}
/* =============================================================================
The Icon Element
============================================================================= */
/*
* Epic dynamic icon element by Eric Eggert, this thing is so fucking cool it's
* actually unreal. http://cl.ly/O40t
*/
%icon:before,
%icon:after {
font-family: "Icons";
font-weight: normal;
font-style: normal;
vertical-align: -7%;
text-transform:none;
speak: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
}
@mixin icon($char, $size: '', $color: '') {
@extend %icon;
&:before {
content: '#{$char}';
@if $size != '' {
font-size: $size;
}
@if $color != '' {
color: $color;
}
@content;
}
&:hover {
text-decoration:none;
}
}
/*
* Special use case for when we want to add an icon after an element rather
* than before it. For things like dropdowns.
*/
@mixin icon-after($char, $size: '', $color: '') {
@extend %icon;
&:after {
content: '#{$char}';
@if $size != '' {
font-size: $size;
}
@if $color != '' {
color: $color;
}
@content;
}
&:hover {
text-decoration:none;
}
}
/* =============================================================================
Icon Variables / Short Names
============================================================================= */
/*
* For accessibility, icon characters in the icon font are stored in Unicode's
* Private Use Area characters. This means that screen readers won't attempt to
* read them out loud. For code maintainability, we then store these Unicode
* references inside Sass variables.
*/
// Placeholder
$i: \e018;
// Icons
$i-ghost: \e000;
$i-chevron-down: \e001;
$i-users: \e002;
$i-tag: \e003;
$i-tablet: \e004;
$i-menu: \e005;
$i-settings: \e006;
$i-search: \e007;
$i-search-left: \e008;
$i-rss: \e009;
$i-preview: \e00a;
$i-plugins: \e00b;
$i-pin: \e00c;
$i-pc: \e00d;
$i-pacman: \e00e;
$i-edit: \e00f;
$i-mobile: \e010;
$i-image: \e011;
$i-mail: \e012;
$i-list: \e013;
$i-info: \e014;
$i-home: \e015;
$i-grid: \e016;
$i-fullscreen: \e017;
$i-question: \e018;
$i-external: \e019;
$i-error: \e01a;
$i-comments: \e01b;
$i-close: \e01c;
$i-chevron: \e01d;
$i-calendar: \e01e;
$i-archive: \e01f;
$i-services: \e020;
$i-appearance: \e021;
$i-video: \e022;
$i-remove: \e023;
$i-reply: \e024;
$i-stats: \e025;
$i-featured: \e026;
$i-unfeatured: \e027;
$i-clock: \e028;
$i-settings2: \e029;
$i-camera: \e02a;
$i-power: \e02b;
$i-lock: \e02c;
$i-content: \e02d;
$i-user: \e02e;
$i-support: \e02f;
$i-success: \e030;
$i-notification: \e031;
$i-add: \e032;
$i-check: \e033;
$i-x: \e034;
$i-link: \e035;
$i-camera: \e036;
$i-repost: \e037;
$i-weather-rain: \e038;
$i-weather-sun: \e039;
$i-weather-partial: \e03a;
$i-weather-snow: \e03b;
$i-weather-cloudy: \e03c;
/* =============================================================================
Usage
=============================================================================
To create a button with a label that is prefixed with a camera icon, we might
write our Sass something like this:
#button {
display: block;
width: 200px;
height: 40px;
@include icon($i-camera, 16px, #fff) {vertical-align:-10%;};
}
Thi would then output full CSS something like this:
#button {
display: block;
width: 200px;
height: 40px;
}
#button:before {
content: "\e02a";
size: 16px;
color: #fff;
font-family: "Icons";
font-weight: normal;
font-style: normal;
vertical-align: -10%;
text-transform:none;
speak: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
}
*/

View File

@ -0,0 +1,181 @@
/*
* These are Sass variables used to make our CSS more dynamic by re-using
* common property values throughout our styles. Don't overdo it.
*
* Table of Contents:
*
* Compass Shit
* Compass Plugins
* Colors
* Gradients
* Typography
* Global Styles
*
*/
/* =============================================================================
Bourbon Imports
============================================================================= */
// Bourbon - http://bourbon.io/
@import "bourbon/_bourbon";
$rounded: 2px;
$shadow: rgba(0,0,0,0.05) 0 1px 5px;
$default-transition-duration: 0.3s;
/* =============================================================================
Plugins
============================================================================= */
// Breakpoint - http://breakpoint-sass.com/
@import "breakpoint";
$breakpoint-default-feature: max-width;
// Max widths
$netbook: 1000px;
$tablet: 800px;
$mobile: 400px;
// Min widths
$biggerthan-widescreen: min-width 1500px, min-width 1500px;
$biggerthan-netbook: min-width 1000px, min-width 1000px;
$biggerthan-tablet: min-width 800px, min-width 800px;
$biggerthan-mobile: min-width 400px, min-width 400px;
// Heights
$letterbox: max-height 600px, max-height 600px;
// Pixel Densities
$retina: 2 device-pixel-ratio;
/* =============================================================================
Colors
============================================================================= */
$darkgrey: #242628;
$grey: #35393b;
$midgrey: #7d878a;
$lightgrey: #e2edf2;
$brown: #aaa9a2;
$midbrown: #c0bfb6;
$lightbrown: #edece4;
$blue: #5BA4E5;
$red: #e25440;
$orange: #F2A925;
$green: #9FBB58;
/* =============================================================================
Gradients
============================================================================= */
/*
* Auto Gradients
*
* If the gradient mixin is called with 1 value: gradient(#444) - then a second
* color which is 10% lighter than the entered value will be auto-generated. If
* the gradient mixin is called with 2 values: gradient(#444,#666) - then those
* two values will be used instead, as normal.
*/
@mixin gradient($color1: #aaa, $color2: none) {
@if $color2 == 'none' {
background-color: lighten($color1, 10%);
background-image: -webkit-linear-gradient(bottom, $color1, lighten($color1, 10%));
background-image: -moz-linear-gradient(bottom, $color1, lighten($color1, 10%));
background-image: -ms-linear-gradient(bottom, $color1, lighten($color1, 10%));
background-image: linear-gradient(bottom, $color1, lighten($color1, 10%));
} @else {
background-color: $color2;
background-image: -webkit-linear-gradient(bottom, $color1, $color2);
background-image: -moz-linear-gradient(bottom, $color1, $color2);
background-image: -ms-linear-gradient(bottom, $color1, $color2);
background-image: linear-gradient(to top, $color1, $color2);
}
}
// The same as the above, but with the colours reversed.
@mixin inversegradient($color1: #aaa, $color2: none) {
@if $color2 == 'none' {
background-color: $color1;
background-image: -webkit-linear-gradient(bottom, lighten($color1, 10%), $color1);
background-image: -moz-linear-gradient(bottom, lighten($color1, 10%), $color1);
background-image: -ms-linear-gradient(bottom, lighten($color1, 10%), $color1);
background-image: linear-gradient(bottom, lighten($color1, 10%), $color1);
} @else {
background-color: $color1;
background-image: -webkit-linear-gradient(bottom, $color2, $color1);
background-image: -moz-linear-gradient(bottom, $color2, $color1);
background-image: -ms-linear-gradient(bottom, $color2, $color1);
background-image: linear-gradient(to top, $color2, $color1);
}
}
/* =============================================================================
Typography
============================================================================= */
@mixin baseline {
margin: 1.6em 0;
}
//Does this really need to be a mixin?
@mixin hidden {
text-indent: -9999px;
visibility: hidden;
display: none;
}
/* =============================================================================
Global Elements
============================================================================= */
%box, .box {
padding: 15px;
margin-bottom: 15px;
background: #fff;
position: relative;
box-shadow: $shadow;
header {
height:14px;
border-bottom: 1px solid $lightbrown;
padding-bottom: 15px;
margin-bottom: 15px;
text-transform: uppercase;
font-size:0.85em;
color: $brown;
}
footer {
height:14px;
border-top: 1px solid $lightbrown;
padding-top: 10px;
margin-top:15px;
text-transform: uppercase;
font-size:0.85em;
color: $brown;
}
header a,
footer a {
color:$brown;
&:hover {
color:$darkgrey;
text-decoration: none;
}
}
}

View File

@ -0,0 +1,396 @@
/*! normalize.css v2.1.0 | MIT License | git.io/normalize */
/* ==========================================================================
HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined in IE 8/9.
*/
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section,
summary {
display: block;
}
/**
* Correct `inline-block` display not defined in IE 8/9.
*/
audio,
canvas,
video {
display: inline-block;
}
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Address styling not present in IE 8/9.
*/
[hidden] {
display: none;
}
/* ==========================================================================
Base
========================================================================== */
/**
* 1. Set default font family to sans-serif.
* 2. Prevent iOS text size adjust after orientation change, without disabling
* user zoom.
*/
html {
font-family: sans-serif; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
-ms-text-size-adjust: 100%; /* 2 */
}
/**
* Remove default margin.
*/
body {
margin: 0;
}
/* ==========================================================================
Links
========================================================================== */
/**
* Address `outline` inconsistency between Chrome and other browsers.
*/
a:focus {
outline: thin dotted;
}
/**
* Improve readability when focused and also mouse hovered in all browsers.
*/
a:active,
a:hover {
outline: 0;
}
/* ==========================================================================
Typography
========================================================================== */
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari 5, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/**
* Address styling not present in IE 8/9, Safari 5, and Chrome.
*/
abbr[title] {
border-bottom: 1px dotted;
}
/**
* Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
*/
b,
strong {
font-weight: bold;
}
/**
* Address styling not present in Safari 5 and Chrome.
*/
dfn {
font-style: italic;
}
/**
* Address differences between Firefox and other browsers.
*/
hr {
-moz-box-sizing: content-box;
box-sizing: content-box;
height: 0;
}
/**
* Address styling not present in IE 8/9.
*/
mark {
background: #ff0;
color: #000;
}
/**
* Correct font family set oddly in Safari 5 and Chrome.
*/
code,
kbd,
pre,
samp {
font-family: monospace, serif;
font-size: 1em;
}
/**
* Improve readability of pre-formatted text in all browsers.
*/
pre {
white-space: pre-wrap;
}
/**
* Set consistent quote types.
*/
q {
quotes: "\201C" "\201D" "\2018" "\2019";
}
/**
* Address inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
/* ==========================================================================
Embedded content
========================================================================== */
/**
* Remove border when inside `a` element in IE 8/9.
*/
img {
border: 0;
}
/**
* Correct overflow displayed oddly in IE 9.
*/
svg:not(:root) {
overflow: hidden;
}
/* ==========================================================================
Figures
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari 5.
*/
figure {
margin: 0;
}
/* ==========================================================================
Forms
========================================================================== */
/**
* Define consistent border, margin, and padding.
*/
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
/**
* 1. Correct `color` not being inherited in IE 8/9.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
border: 0; /* 1 */
padding: 0; /* 2 */
}
/**
* 1. Correct font family not being inherited in all browsers.
* 2. Correct font size not being inherited in all browsers.
* 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
*/
button,
input,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 2 */
margin: 0; /* 3 */
}
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
button,
input {
line-height: normal;
}
/**
* Address inconsistent `text-transform` inheritance for `button` and `select`.
* All other form control elements do not inherit `text-transform` values.
* Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+.
* Correct `select` style inheritance in Firefox 4+ and Opera.
*/
button,
select {
text-transform: none;
}
/**
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Correct inability to style clickable `input` types in iOS.
* 3. Improve usability and consistency of cursor style between image-type
* `input` and others.
*/
button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button; /* 2 */
cursor: pointer; /* 3 */
}
/**
* Re-set default cursor for disabled elements.
*/
button[disabled],
html input[disabled] {
cursor: default;
}
/**
* 1. Address box sizing set to `content-box` in IE 8/9.
* 2. Remove excess padding in IE 8/9.
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
* (include `-moz` to future-proof).
*/
input[type="search"] {
-webkit-appearance: textfield; /* 1 */
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box; /* 2 */
box-sizing: content-box;
}
/**
* Remove inner padding and search cancel button in Safari 5 and Chrome
* on OS X.
*/
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/**
* 1. Remove default vertical scrollbar in IE 8/9.
* 2. Improve readability and alignment in all browsers.
*/
textarea {
overflow: auto; /* 1 */
vertical-align: top; /* 2 */
}
/* ==========================================================================
Tables
========================================================================== */
/**
* Remove most spacing between table cells.
*/
table {
border-collapse: collapse;
border-spacing: 0;
}

View File

@ -0,0 +1,678 @@
/*!
+---------------------------------------------------------------------+
| _ _ _ |
| | |_ _ _ _ __ ___ _ __ | | __ _ | |_ ___ |
| | __|| | | || '_ \ / _ \| '_ \ | | / _` || __|/ _ \ |
| | |_ | |_| || |_) || __/| |_) || || (_| || |_| __/ |
| \__| \__, || .__/ \___|| .__/ |_| \__,_| \__|\___| |
| |___/ |_| |_| |
| |
| |
| URL: http://typeplate.com |
| VERSION: 1.0.0 |
| Github: https://github.com/typePlate/typeplate.github.com |
| AUTHORS: Zachary Kain (@zakkain) & Dennis Gaebel (@gryghostvisuals) |
| LICENSE: Creative Commmons |
| http://creativecommons.org/licenses/by/3.0 |
| |
+---------------------------------------------------------------------+
*/
// ==========================================================================
//
// $V a r i a b l e s
//
// ==========================================================================
// $B a s e T y p e
// --------------------------------------------------------------------------
$weight: normal;
$line-height: 1.65;
$font-size: 81.2; // percentage value (16 * 112.5% = 18px)
$font-base: 16 * ($font-size/100); // converts our percentage to a pixel value
$measure: $font-base * $line-height;
$font-family: 'Open Sans', sans-serif;
$font-family-serif: serif;
$font-family-mono: Inconsolata, monospace;
$font-properties: $weight, $line-height, $font-size, $font-family;
//the serif boolean var can be redeclared from another stylesheet. However
//the var must be placed after your @import "typeplate.scss";
$sans-serif-boolean: true !default;
// $C o l o r
// --------------------------------------------------------------------------
$body-copy-color: #444;
$heading-color: #222;
// $A M P E R S A N D @font-face
// --------------------------------------------------------------------------
$amp-fontface-name: Ampersand;
$amp-fontface-source: local('Georgia'), local('Garamond'), local('Palatino'), local('Book Antiqua');
$amp-fontface-fallback: local('Georgia');
// $A M P E R S A N D e l e m e n t
// --------------------------------------------------------------------------
// Allows for our ampersand element to have differing
// font-family from the ampersand unicode font-family.
$amp-font-family: Verdana, sans-serif;
// $T y p e S c a l e
// --------------------------------------------------------------------------
$tera: 117; // 117 = 18 × 6.5
$giga: 90; // 90 = 18 × 5
$mega: 72; // 72 = 18 × 4
$alpha: 60; // 60 = 18 × 3.3333
$beta: 48; // 48 = 18 × 2.6667
$gamma: 36; // 36 = 18 × 2
$delta: 24; // 24 = 18 × 1.3333
$epsilon: 21; // 21 = 18 × 1.1667
$zeta: 18; // 18 = 18 × 1
// $T y p e S c a l e U n i t
// --------------------------------------------------------------------------
$type-scale-unit-value: rem;
// $T e x t I n d e n t a t i o n
// --------------------------------------------------------------------------
$indent-val: 1.5em;
// $S t a t s T a b
// --------------------------------------------------------------------------
$stats-font-size: 1.5rem;
$stats-list-margin: 0 0.625rem 0 0;
$stats-list-padding: 0 0.625rem 0 0;
$stats-item-font-size: 0.875rem;
$stats-item-margin: 0.125rem 0 0 0;
$stats-border-style: 0.125rem solid #ccc;
// ==========================================================================
//
// $F o n t f a c e s
//
// ==========================================================================
// $U N I C O D E - R A N G E A m p e r s a n d
// --------------------------------------------------------------------------
@font-face {
font-family: '#{$amp-fontface-name}';
src: $amp-fontface-source;
unicode-range: U+0026;
}
// Ampersand fallback font for unicode range
@font-face {
font-family: '#{$amp-fontface-name}';
src: $amp-fontface-fallback;
unicode-range: U+270C;
}
// ==========================================================================
//
// $F u n c t i o n s
//
// ==========================================================================
// $C o n t e x t C a l c u l a t o r
// --------------------------------------------------------------------------
@function ems($target, $context) {
@return ($target/$context)#{em};
}
// $M o d u l a r S c a l e
// --------------------------------------------------------------------------
// http://thesassway.com/projects/modular-scale
@function modular-scale($scale, $base, $value) {
// divide a given font-size by base font-size & return a relative em value
@return ($scale/$base)#{$value};
}
@function measure-margin($scale, $measure, $value) {
// divide 1 unit of measure by given font-size & return a relative em value
@return ($measure/$scale)#{$value};
}
// ==========================================================================
//
// $M i x i n s
//
// ==========================================================================
// $M o d u l a r S c a l e
// --------------------------------------------------------------------------
// $Typographic scale
@mixin modular-scale($scale, $base, $value, $measure:"") {
font-size: $scale#{px};
font-size: modular-scale($scale, $base, $value);
@if $measure != "" {
margin-bottom: measure-margin($scale, $measure, $value);
}
}
// $B o d y C o p y
// --------------------------------------------------------------------------
@mixin base-type($weight, $line-height, $font-size, $font-family...) {
@if $sans-serif-boolean {
font: $weight #{$font-size}%/#{$line-height} $font-family;
}@else {
font: $weight #{$font-size}%/#{$line-height} $font-family-serif;
}
}
// $H y p h e n
// --------------------------------------------------------------------------
//http://trentwalton.com/2011/09/07/css-hyphenation
@mixin css-hyphens($val) {
// Accepted values: [ none | manual | auto ]
-webkit-hyphens: $val; // Safari 5.1 thru 6, iOS 4.2 thru 6
-moz-hyphens: $val; // Firefox 16 thru 20
-ms-hyphens: $val; // IE10
hyphens: $val; // W3C standard
};
// $S m a l l c a p s
// --------------------------------------------------------------------------
// http://blog.hypsometry.com/articles/true-small-capitals-with-font-face
// ISSUE#1 : https://github.com/zakkain/web-thang/issues/1
@mixin smallcaps($color, $font-weight) {
// depends on the font family.
// some font-families don't support small caps
// or don't provide them with their web font.
font-variant: small-caps;
font-weight: $font-weight;
text-transform: lowercase;
color: $color;
}
// $F o n t - S i z e - A d j u s t
// --------------------------------------------------------------------------
// correct x-height for fallback fonts: requires secret formula
// yet to be discovered. This is still wacky for support. Use
// wisely grasshopper.
@mixin font-size-adjust($adjust-value) {
// firefox 17+ only (as of Feb. 2013)
font-size-adjust: $adjust-value;
}
// $A m p e r s a n d
// --------------------------------------------------------------------------
@mixin ampersand($amp-font-family...) {
font-family: $amp-font-family;
}
%ampersand-placeholder {
@include ampersand($amp-fontface-name, $amp-font-family);
}
// Call your ampersand on any element you wish from another stylesheet
// using this Sass extend we've provided...
// @extend %ampersand-placeholder;
// $W o r d W r a p
// --------------------------------------------------------------------------
// Silent Sass Classes - A.K.A Placeholders
//
// normal: Indicates that lines may only break at normal word break points.
// break-word : Indicates that normally unbreakable words may be broken at
// arbitrary points if there are no otherwise acceptable break points in the line.
%breakword {
word-wrap: breakword;
}
%normal-wrap {
word-wrap: normal;
}
%inherit-wrap {
word-wrap: auto;
}
// $D r o p c a p s
// --------------------------------------------------------------------------
/**
* Dropcap Sass @include
* Use the following Sass @include with any selector you feel necessary.
*
@include dropcap($float: left, $font-size: 4em, $font-family: inherit, $text-indent: 0, $margin: inherit, $padding: inherit, $color: inherit, $lineHeight: 1, $bg: transparent);
*
* Extend this object into your custom stylesheet.
*
*/
// Include your '@include dropcap()' mixin and pass the following
// arguments below. Feel free to pass in arguments we've provided.
// At this time you cannot pass in font-family arguments but you're gonna
// change that anyway so why not just make that separately in your declaration.
@mixin dropcap($float: left, $font-size: 4em, $font-family: inherit, $text-indent: 0, $margin: inherit, $padding: inherit, $color: inherit, $lineHeight: 1, $bg: transparent) {
&:first-letter {
float: $float;
margin: $margin;
padding: $padding;
font-size: $font-size;
font-family: $font-family;
line-height: $lineHeight;
text-indent: $text-indent;
background: $bg;
color: $color;
}
}
// $D e f i n i t i o n L i s t
// --------------------------------------------------------------------------
// lining
// http://lea.verou.me/2012/02/flexible-multiline-definition-lists-with-2-lines-of-css
//
// dictionary-style
// http://lea.verou.me/2012/02/flexible-multiline-definition-lists-with-2-lines-of-css
@mixin definition-list-style($style) {
// lining style
@if $style == lining {
dt,
dd {
display: inline;
margin: 0;
}
dt,
dd {
& + dt {
&:before {
content: "\A";
white-space: pre;
}
}
}
dd {
& + dd {
&:before {
content: ", ";
}
}
&:before {
content: ": ";
margin-left: -0.2rem; //removes extra space between the dt and the colon
}
}
}
// dictionary-style
@if $style == dictionary-style {
dt {
display: inline;
counter-reset: definitions;
& + dt {
&:before {
content: ", ";
margin-left: -0.2rem; // removes extra space between the dt and the comma
}
}
}
dd {
display: block;
counter-increment: definitions;
&:before {
content: counter(definitions, decimal) ". ";
}
}
}
}
// ==========================================================================
//
// $T y p e l a t e S t y l i n g
//
// ==========================================================================
// $G l o b a l s
// --------------------------------------------------------------------------
html {
@include base-type($font-properties...);
}
body {
// Ala Trent Walton
@include css-hyphens(auto);
// normal: Indicates that lines may only break at normal word break points.
// break-word : Indicates that normally unbreakable words may be broken at ...
// arbitrary points if there are no otherwise acceptable break points in the line.
@extend %breakword;
color: $body-copy-color;
}
// $H e a d i n g s
// --------------------------------------------------------------------------
// styles for all headings, in the style of @csswizardry
%hN {
// voodoo to enable ligatures and kerning
text-rendering: optimizeLegibility;
// this fixes huge spaces when a heading wraps onto two lines
line-height: 1;
margin-top: 0;
}
// make a multi-dimensional array, where:
// the first value is the name of the class
// and the second value is the variable for the size
$sizes: tera $tera, giga $giga, mega $mega, alpha $alpha, beta $beta, gamma $gamma, delta $delta, epsilon $epsilon, zeta $zeta;
// for each size in the scale, create a class
@each $size in $sizes {
.#{nth($size, 1)} {
@include modular-scale(nth($size, 2), $font-base, '#{$type-scale-unit-value}', $measure);
}
}
// associate h1-h6 tags with their appropriate greek heading
h1 { @extend .alpha; @extend %hN; }
h2 { @extend .beta; @extend %hN; }
h3 { @extend .gamma; @extend %hN; }
h4 { @extend .delta; @extend %hN; }
h5 { @extend .epsilon; @extend %hN; }
h6 { @extend .zeta; @extend %hN; }
// $ P a r a g r a p h s
// --------------------------------------------------------------------------
p {
& + p {
//siblings indentation
text-indent: $indent-val;
}
}
// $C o d e b l o c k s
// --------------------------------------------------------------------------
@mixin white-space($wrap-space) {
@if $wrap-space == 'pre-wrap' {
white-space: #{-moz-}$wrap-space; // Firefox 1.0-2.0
white-space: $wrap-space; // current browsers
} @else {
white-space: $wrap-space;
}
}
pre code {
@extend %normal-wrap;
@include white-space(pre-wrap);
}
pre {
@include white-space(pre);
}
code {
@include white-space(pre);
font-family: monospace;
}
// $ S m a l l c a p s
// --------------------------------------------------------------------------
/**
* Abbreviations Markup
*
<abbr title="hyper text markup language">HMTL</abbr>
*
* Extend this object into your markup.
*
*/
abbr {
@include smallcaps(gray, 600);
&:hover {
cursor: help;
}
}
// $ H e a d i n g s C o l o r
// --------------------------------------------------------------------------
h1,
h2,
h3,
h4,
h5,
h6 {
color: $heading-color;
}
// $ D e f i n i t i o n L i s t s
// --------------------------------------------------------------------------
/**
* Lining Definition Style Markup
*
<dl class="lining">
<dt><b></b></dt>
<dd></dd>
</dl>
*
* Extend this object into your markup.
*
*/
.lining {
@include definition-list-style(lining);
}
/**
* Dictionary Definition Style Markup
*
<dl class="dictionary-style">
<dt><b></b></dt>
<dd></dd>
</dl>
*
* Extend this object into your markup.
*
*/
.dictionary-style {
@include definition-list-style(dictionary-style);
}
// $S t a t s T a b
// --------------------------------------------------------------------------
/**
* Stats Tab Markup
*
<ul class="stats-tabs">
<li><a href="#">[value]<b>[name]</b></a></li>
</ul>
*
* Extend this object into your markup.
*
*/
.stats-tabs {
padding: 0;
li {
display: inline-block;
margin: $stats-list-margin;
padding: $stats-list-padding;
border-right: $stats-border-style;
&:last-child {
margin: 0;
padding: 0;
border: none;
}
a {
display: inline-block;
font-size: $stats-font-size;
font-weight: bold;
b {
display: block;
margin: $stats-item-margin;
font-size: $stats-item-font-size;
font-weight: normal;
}
}
}
}
// $Blockquote Cites
// --------------------------------------------------------------------------
/**
* Blockquote Markup
*
<blockquote cite="">
<p>&Prime;&Prime;</p>
<cite>
<small><a href=""></a></small>
</cite>
</blockquote>
*
* Extend this object into your markup.
*
*/
@mixin cite-style($display:block, $text-align:right, $font-size: .875em) {
display: $display;
font-size: $font-size;
text-align: $text-align;
}
%cite {
@include cite-style;
}
// $Pull Quotes
// --------------------------------------------------------------------------
// http://24ways.org/2005/swooshy-curly-quotes-without-images
//
// http://todomvc.com - Thanks sindresorhus!
// https://github.com/typeplate/typeplate.github.com/issues/49
/**
* Pull Quotes Markup
*
<aside class="pull-quote">
<blockquote>
<p></p>
</blockquote>
</aside>
*
* Extend this object into your custom stylesheet.
*
*/
@mixin pull-quotes($font-size, $opacity) {
position: relative;
padding: ems($font-size, $font-size);
&:before,
&:after {
height: ems($font-size, $font-size);
opacity: $opacity;
position: absolute;
font-size: $font-size;
}
&:before {
content: '';
top: 0em;
left: 0em;
}
&:after {
content: '';
bottom: 0em;
right: 0em;
}
}
.pull-quote {
@include pull-quotes(4em, .15);
}
// $Figures
// --------------------------------------------------------------------------
/**
* Figures Markup
*
<figure>
<figcaption>
<strong>Fig. 4.2 | </strong>Type Anatomy, an excerpt from Mark Boulton's book<cite title="http://designingfortheweb.co.uk/book/part3/part3_chapter11.php">"Designing for the Web"</cite>
</figcaption>
</figure>
*
* Extend this object into your markup.
*
*/
// $Footnotes
// --------------------------------------------------------------------------
/**
* Footnote Markup : Replace 'X' with your unique number for each footnote
*
<article>
<p><sup><a href="#fn-itemX" id="fn-returnX"></a></sup></p>
<footer>
<ol class="foot-notes">
<li id="fn-itemX"><a href="#fn-returnX"></a></li>
</ol>
</footer>
</article>
*
* Extend this object into your markup.
*
*/

View File

@ -0,0 +1,50 @@
/*
* Welcome to Ghost - all styles for the Ghost platform are located within
* this set of Sass files. Use this file like a table of contents.
*/
/* ==========================================================================
Modules - These styles are re-used in many areas, and are grouped by type.
========================================================================== */
@import "modules/mixins";
/* Sass variables like colours, font sizes, basic styles. */
@import "modules/normalize";
/* Browser cross compatibility normalisation*/
@import "modules/typeplate";
/* All the styles controlling the typographic styles. */
@import "modules/icons";
/* All the styles controlling icons. */
@import "modules/animations";
/* Keyframe animations. */
@import "modules/global";
/* Global elements for the UI, like the header and footer. */
@import "modules/forms";
/* All the styles controlling forms and form fields. */
/* ==========================================================================
Layouts - Styles for specific admin screen layouts, grouped by screen.
========================================================================== */
@import "layouts/dashboard";
/* The default admin page, the dashboard. */
@import "layouts/manage";
/* The manage posts screen. */
@import "layouts/editor";
/* The write/edit post screen. */
@import "layouts/settings";
/* The settings screen. */
@import "layouts/login";
/* The settings screen. */

File diff suppressed because it is too large Load Diff

39
ghost/admin/assets/vendor/chart.min.js vendored Normal file
View File

@ -0,0 +1,39 @@
var Chart=function(s){function v(a,c,b){a=A((a-c.graphMin)/(c.steps*c.stepValue),1,0);return b*c.steps*a}function x(a,c,b,e){function h(){g+=f;var k=a.animation?A(d(g),null,0):1;e.clearRect(0,0,q,u);a.scaleOverlay?(b(k),c()):(c(),b(k));if(1>=g)D(h);else if("function"==typeof a.onAnimationComplete)a.onAnimationComplete()}var f=a.animation?1/A(a.animationSteps,Number.MAX_VALUE,1):1,d=B[a.animationEasing],g=a.animation?0:1;"function"!==typeof c&&(c=function(){});D(h)}function C(a,c,b,e,h,f){var d;a=
Math.floor(Math.log(e-h)/Math.LN10);h=Math.floor(h/(1*Math.pow(10,a)))*Math.pow(10,a);e=Math.ceil(e/(1*Math.pow(10,a)))*Math.pow(10,a)-h;a=Math.pow(10,a);for(d=Math.round(e/a);d<b||d>c;)a=d<b?a/2:2*a,d=Math.round(e/a);c=[];z(f,c,d,h,a);return{steps:d,stepValue:a,graphMin:h,labels:c}}function z(a,c,b,e,h){if(a)for(var f=1;f<b+1;f++)c.push(E(a,{value:(e+h*f).toFixed(0!=h%1?h.toString().split(".")[1].length:0)}))}function A(a,c,b){return!isNaN(parseFloat(c))&&isFinite(c)&&a>c?c:!isNaN(parseFloat(b))&&
isFinite(b)&&a<b?b:a}function y(a,c){var b={},e;for(e in a)b[e]=a[e];for(e in c)b[e]=c[e];return b}function E(a,c){var b=!/\W/.test(a)?F[a]=F[a]||E(document.getElementById(a).innerHTML):new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g," ").split("<%").join("\t").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split("\t").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');");return c?
b(c):b}var r=this,B={linear:function(a){return a},easeInQuad:function(a){return a*a},easeOutQuad:function(a){return-1*a*(a-2)},easeInOutQuad:function(a){return 1>(a/=0.5)?0.5*a*a:-0.5*(--a*(a-2)-1)},easeInCubic:function(a){return a*a*a},easeOutCubic:function(a){return 1*((a=a/1-1)*a*a+1)},easeInOutCubic:function(a){return 1>(a/=0.5)?0.5*a*a*a:0.5*((a-=2)*a*a+2)},easeInQuart:function(a){return a*a*a*a},easeOutQuart:function(a){return-1*((a=a/1-1)*a*a*a-1)},easeInOutQuart:function(a){return 1>(a/=0.5)?
0.5*a*a*a*a:-0.5*((a-=2)*a*a*a-2)},easeInQuint:function(a){return 1*(a/=1)*a*a*a*a},easeOutQuint:function(a){return 1*((a=a/1-1)*a*a*a*a+1)},easeInOutQuint:function(a){return 1>(a/=0.5)?0.5*a*a*a*a*a:0.5*((a-=2)*a*a*a*a+2)},easeInSine:function(a){return-1*Math.cos(a/1*(Math.PI/2))+1},easeOutSine:function(a){return 1*Math.sin(a/1*(Math.PI/2))},easeInOutSine:function(a){return-0.5*(Math.cos(Math.PI*a/1)-1)},easeInExpo:function(a){return 0==a?1:1*Math.pow(2,10*(a/1-1))},easeOutExpo:function(a){return 1==
a?1:1*(-Math.pow(2,-10*a/1)+1)},easeInOutExpo:function(a){return 0==a?0:1==a?1:1>(a/=0.5)?0.5*Math.pow(2,10*(a-1)):0.5*(-Math.pow(2,-10*--a)+2)},easeInCirc:function(a){return 1<=a?a:-1*(Math.sqrt(1-(a/=1)*a)-1)},easeOutCirc:function(a){return 1*Math.sqrt(1-(a=a/1-1)*a)},easeInOutCirc:function(a){return 1>(a/=0.5)?-0.5*(Math.sqrt(1-a*a)-1):0.5*(Math.sqrt(1-(a-=2)*a)+1)},easeInElastic:function(a){var c=1.70158,b=0,e=1;if(0==a)return 0;if(1==(a/=1))return 1;b||(b=0.3);e<Math.abs(1)?(e=1,c=b/4):c=b/(2*
Math.PI)*Math.asin(1/e);return-(e*Math.pow(2,10*(a-=1))*Math.sin((1*a-c)*2*Math.PI/b))},easeOutElastic:function(a){var c=1.70158,b=0,e=1;if(0==a)return 0;if(1==(a/=1))return 1;b||(b=0.3);e<Math.abs(1)?(e=1,c=b/4):c=b/(2*Math.PI)*Math.asin(1/e);return e*Math.pow(2,-10*a)*Math.sin((1*a-c)*2*Math.PI/b)+1},easeInOutElastic:function(a){var c=1.70158,b=0,e=1;if(0==a)return 0;if(2==(a/=0.5))return 1;b||(b=1*0.3*1.5);e<Math.abs(1)?(e=1,c=b/4):c=b/(2*Math.PI)*Math.asin(1/e);return 1>a?-0.5*e*Math.pow(2,10*
(a-=1))*Math.sin((1*a-c)*2*Math.PI/b):0.5*e*Math.pow(2,-10*(a-=1))*Math.sin((1*a-c)*2*Math.PI/b)+1},easeInBack:function(a){return 1*(a/=1)*a*(2.70158*a-1.70158)},easeOutBack:function(a){return 1*((a=a/1-1)*a*(2.70158*a+1.70158)+1)},easeInOutBack:function(a){var c=1.70158;return 1>(a/=0.5)?0.5*a*a*(((c*=1.525)+1)*a-c):0.5*((a-=2)*a*(((c*=1.525)+1)*a+c)+2)},easeInBounce:function(a){return 1-B.easeOutBounce(1-a)},easeOutBounce:function(a){return(a/=1)<1/2.75?1*7.5625*a*a:a<2/2.75?1*(7.5625*(a-=1.5/2.75)*
a+0.75):a<2.5/2.75?1*(7.5625*(a-=2.25/2.75)*a+0.9375):1*(7.5625*(a-=2.625/2.75)*a+0.984375)},easeInOutBounce:function(a){return 0.5>a?0.5*B.easeInBounce(2*a):0.5*B.easeOutBounce(2*a-1)+0.5}},q=s.canvas.width,u=s.canvas.height;window.devicePixelRatio&&(s.canvas.style.width=q+"px",s.canvas.style.height=u+"px",s.canvas.height=u*window.devicePixelRatio,s.canvas.width=q*window.devicePixelRatio,s.scale(window.devicePixelRatio,window.devicePixelRatio));this.PolarArea=function(a,c){r.PolarArea.defaults={scaleOverlay:!0,
scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleShowLine:!0,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animation:!0,animationSteps:100,animationEasing:"easeOutBounce",
animateRotate:!0,animateScale:!1,onAnimationComplete:null};var b=c?y(r.PolarArea.defaults,c):r.PolarArea.defaults;return new G(a,b,s)};this.Radar=function(a,c){r.Radar.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleShowLine:!0,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!1,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",
scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,angleShowLineOut:!0,angleLineColor:"rgba(0,0,0,.1)",angleLineWidth:1,pointLabelFontFamily:"'Arial'",pointLabelFontStyle:"normal",pointLabelFontSize:12,pointLabelFontColor:"#666",pointDot:!0,pointDotRadius:3,pointDotStrokeWidth:1,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?y(r.Radar.defaults,c):r.Radar.defaults;return new H(a,b,s)};this.Pie=function(a,
c){r.Pie.defaults={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animation:!0,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,onAnimationComplete:null};var b=c?y(r.Pie.defaults,c):r.Pie.defaults;return new I(a,b,s)};this.Doughnut=function(a,c){r.Doughnut.defaults={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,percentageInnerCutout:50,animation:!0,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,
onAnimationComplete:null};var b=c?y(r.Doughnut.defaults,c):r.Doughnut.defaults;return new J(a,b,s)};this.Line=function(a,c){r.Line.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,bezierCurve:!0,
pointDot:!0,pointDotRadius:4,pointDotStrokeWidth:2,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?y(r.Line.defaults,c):r.Line.defaults;return new K(a,b,s)};this.Bar=function(a,c){r.Bar.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",
scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,barShowStroke:!0,barStrokeWidth:2,barValueSpacing:5,barDatasetSpacing:1,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?y(r.Bar.defaults,c):r.Bar.defaults;return new L(a,b,s)};var G=function(a,c,b){var e,h,f,d,g,k,j,l,m;g=Math.min.apply(Math,[q,u])/2;g-=Math.max.apply(Math,[0.5*c.scaleFontSize,0.5*c.scaleLineWidth]);
d=2*c.scaleFontSize;c.scaleShowLabelBackdrop&&(d+=2*c.scaleBackdropPaddingY,g-=1.5*c.scaleBackdropPaddingY);l=g;d=d?d:5;e=Number.MIN_VALUE;h=Number.MAX_VALUE;for(f=0;f<a.length;f++)a[f].value>e&&(e=a[f].value),a[f].value<h&&(h=a[f].value);f=Math.floor(l/(0.66*d));d=Math.floor(0.5*(l/d));m=c.scaleShowLabels?c.scaleLabel:null;c.scaleOverride?(j={steps:c.scaleSteps,stepValue:c.scaleStepWidth,graphMin:c.scaleStartValue,labels:[]},z(m,j.labels,j.steps,c.scaleStartValue,c.scaleStepWidth)):j=C(l,f,d,e,h,
m);k=g/j.steps;x(c,function(){for(var a=0;a<j.steps;a++)if(c.scaleShowLine&&(b.beginPath(),b.arc(q/2,u/2,k*(a+1),0,2*Math.PI,!0),b.strokeStyle=c.scaleLineColor,b.lineWidth=c.scaleLineWidth,b.stroke()),c.scaleShowLabels){b.textAlign="center";b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;var e=j.labels[a];if(c.scaleShowLabelBackdrop){var d=b.measureText(e).width;b.fillStyle=c.scaleBackdropColor;b.beginPath();b.rect(Math.round(q/2-d/2-c.scaleBackdropPaddingX),Math.round(u/2-k*(a+
1)-0.5*c.scaleFontSize-c.scaleBackdropPaddingY),Math.round(d+2*c.scaleBackdropPaddingX),Math.round(c.scaleFontSize+2*c.scaleBackdropPaddingY));b.fill()}b.textBaseline="middle";b.fillStyle=c.scaleFontColor;b.fillText(e,q/2,u/2-k*(a+1))}},function(e){var d=-Math.PI/2,g=2*Math.PI/a.length,f=1,h=1;c.animation&&(c.animateScale&&(f=e),c.animateRotate&&(h=e));for(e=0;e<a.length;e++)b.beginPath(),b.arc(q/2,u/2,f*v(a[e].value,j,k),d,d+h*g,!1),b.lineTo(q/2,u/2),b.closePath(),b.fillStyle=a[e].color,b.fill(),
c.segmentShowStroke&&(b.strokeStyle=c.segmentStrokeColor,b.lineWidth=c.segmentStrokeWidth,b.stroke()),d+=h*g},b)},H=function(a,c,b){var e,h,f,d,g,k,j,l,m;a.labels||(a.labels=[]);g=Math.min.apply(Math,[q,u])/2;d=2*c.scaleFontSize;for(e=l=0;e<a.labels.length;e++)b.font=c.pointLabelFontStyle+" "+c.pointLabelFontSize+"px "+c.pointLabelFontFamily,h=b.measureText(a.labels[e]).width,h>l&&(l=h);g-=Math.max.apply(Math,[l,1.5*(c.pointLabelFontSize/2)]);g-=c.pointLabelFontSize;l=g=A(g,null,0);d=d?d:5;e=Number.MIN_VALUE;
h=Number.MAX_VALUE;for(f=0;f<a.datasets.length;f++)for(m=0;m<a.datasets[f].data.length;m++)a.datasets[f].data[m]>e&&(e=a.datasets[f].data[m]),a.datasets[f].data[m]<h&&(h=a.datasets[f].data[m]);f=Math.floor(l/(0.66*d));d=Math.floor(0.5*(l/d));m=c.scaleShowLabels?c.scaleLabel:null;c.scaleOverride?(j={steps:c.scaleSteps,stepValue:c.scaleStepWidth,graphMin:c.scaleStartValue,labels:[]},z(m,j.labels,j.steps,c.scaleStartValue,c.scaleStepWidth)):j=C(l,f,d,e,h,m);k=g/j.steps;x(c,function(){var e=2*Math.PI/
a.datasets[0].data.length;b.save();b.translate(q/2,u/2);if(c.angleShowLineOut){b.strokeStyle=c.angleLineColor;b.lineWidth=c.angleLineWidth;for(var d=0;d<a.datasets[0].data.length;d++)b.rotate(e),b.beginPath(),b.moveTo(0,0),b.lineTo(0,-g),b.stroke()}for(d=0;d<j.steps;d++){b.beginPath();if(c.scaleShowLine){b.strokeStyle=c.scaleLineColor;b.lineWidth=c.scaleLineWidth;b.moveTo(0,-k*(d+1));for(var f=0;f<a.datasets[0].data.length;f++)b.rotate(e),b.lineTo(0,-k*(d+1));b.closePath();b.stroke()}c.scaleShowLabels&&
(b.textAlign="center",b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily,b.textBaseline="middle",c.scaleShowLabelBackdrop&&(f=b.measureText(j.labels[d]).width,b.fillStyle=c.scaleBackdropColor,b.beginPath(),b.rect(Math.round(-f/2-c.scaleBackdropPaddingX),Math.round(-k*(d+1)-0.5*c.scaleFontSize-c.scaleBackdropPaddingY),Math.round(f+2*c.scaleBackdropPaddingX),Math.round(c.scaleFontSize+2*c.scaleBackdropPaddingY)),b.fill()),b.fillStyle=c.scaleFontColor,b.fillText(j.labels[d],0,-k*(d+
1)))}for(d=0;d<a.labels.length;d++){b.font=c.pointLabelFontStyle+" "+c.pointLabelFontSize+"px "+c.pointLabelFontFamily;b.fillStyle=c.pointLabelFontColor;var f=Math.sin(e*d)*(g+c.pointLabelFontSize),h=Math.cos(e*d)*(g+c.pointLabelFontSize);b.textAlign=e*d==Math.PI||0==e*d?"center":e*d>Math.PI?"right":"left";b.textBaseline="middle";b.fillText(a.labels[d],f,-h)}b.restore()},function(d){var e=2*Math.PI/a.datasets[0].data.length;b.save();b.translate(q/2,u/2);for(var g=0;g<a.datasets.length;g++){b.beginPath();
b.moveTo(0,d*-1*v(a.datasets[g].data[0],j,k));for(var f=1;f<a.datasets[g].data.length;f++)b.rotate(e),b.lineTo(0,d*-1*v(a.datasets[g].data[f],j,k));b.closePath();b.fillStyle=a.datasets[g].fillColor;b.strokeStyle=a.datasets[g].strokeColor;b.lineWidth=c.datasetStrokeWidth;b.fill();b.stroke();if(c.pointDot){b.fillStyle=a.datasets[g].pointColor;b.strokeStyle=a.datasets[g].pointStrokeColor;b.lineWidth=c.pointDotStrokeWidth;for(f=0;f<a.datasets[g].data.length;f++)b.rotate(e),b.beginPath(),b.arc(0,d*-1*
v(a.datasets[g].data[f],j,k),c.pointDotRadius,2*Math.PI,!1),b.fill(),b.stroke()}b.rotate(e)}b.restore()},b)},I=function(a,c,b){for(var e=0,h=Math.min.apply(Math,[u/2,q/2])-5,f=0;f<a.length;f++)e+=a[f].value;x(c,null,function(d){var g=-Math.PI/2,f=1,j=1;c.animation&&(c.animateScale&&(f=d),c.animateRotate&&(j=d));for(d=0;d<a.length;d++){var l=j*a[d].value/e*2*Math.PI;b.beginPath();b.arc(q/2,u/2,f*h,g,g+l);b.lineTo(q/2,u/2);b.closePath();b.fillStyle=a[d].color;b.fill();c.segmentShowStroke&&(b.lineWidth=
c.segmentStrokeWidth,b.strokeStyle=c.segmentStrokeColor,b.stroke());g+=l}},b)},J=function(a,c,b){for(var e=0,h=Math.min.apply(Math,[u/2,q/2])-5,f=h*(c.percentageInnerCutout/100),d=0;d<a.length;d++)e+=a[d].value;x(c,null,function(d){var k=-Math.PI/2,j=1,l=1;c.animation&&(c.animateScale&&(j=d),c.animateRotate&&(l=d));for(d=0;d<a.length;d++){var m=l*a[d].value/e*2*Math.PI;b.beginPath();b.arc(q/2,u/2,j*h,k,k+m,!1);b.arc(q/2,u/2,j*f,k+m,k,!0);b.closePath();b.fillStyle=a[d].color;b.fill();c.segmentShowStroke&&
(b.lineWidth=c.segmentStrokeWidth,b.strokeStyle=c.segmentStrokeColor,b.stroke());k+=m}},b)},K=function(a,c,b){var e,h,f,d,g,k,j,l,m,t,r,n,p,s=0;g=u;b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;t=1;for(d=0;d<a.labels.length;d++)e=b.measureText(a.labels[d]).width,t=e>t?e:t;q/a.labels.length<t?(s=45,q/a.labels.length<Math.cos(s)*t?(s=90,g-=t):g-=Math.sin(s)*t):g-=c.scaleFontSize;d=c.scaleFontSize;g=g-5-d;e=Number.MIN_VALUE;h=Number.MAX_VALUE;for(f=0;f<a.datasets.length;f++)for(l=
0;l<a.datasets[f].data.length;l++)a.datasets[f].data[l]>e&&(e=a.datasets[f].data[l]),a.datasets[f].data[l]<h&&(h=a.datasets[f].data[l]);f=Math.floor(g/(0.66*d));d=Math.floor(0.5*(g/d));l=c.scaleShowLabels?c.scaleLabel:"";c.scaleOverride?(j={steps:c.scaleSteps,stepValue:c.scaleStepWidth,graphMin:c.scaleStartValue,labels:[]},z(l,j.labels,j.steps,c.scaleStartValue,c.scaleStepWidth)):j=C(g,f,d,e,h,l);k=Math.floor(g/j.steps);d=1;if(c.scaleShowLabels){b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;
for(e=0;e<j.labels.length;e++)h=b.measureText(j.labels[e]).width,d=h>d?h:d;d+=10}r=q-d-t;m=Math.floor(r/(a.labels.length-1));n=q-t/2-r;p=g+c.scaleFontSize/2;x(c,function(){b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(q-t/2+5,p);b.lineTo(q-t/2-r-5,p);b.stroke();0<s?(b.save(),b.textAlign="right"):b.textAlign="center";b.fillStyle=c.scaleFontColor;for(var d=0;d<a.labels.length;d++)b.save(),0<s?(b.translate(n+d*m,p+c.scaleFontSize),b.rotate(-(s*(Math.PI/180))),b.fillText(a.labels[d],
0,0),b.restore()):b.fillText(a.labels[d],n+d*m,p+c.scaleFontSize+3),b.beginPath(),b.moveTo(n+d*m,p+3),c.scaleShowGridLines&&0<d?(b.lineWidth=c.scaleGridLineWidth,b.strokeStyle=c.scaleGridLineColor,b.lineTo(n+d*m,5)):b.lineTo(n+d*m,p+3),b.stroke();b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(n,p+5);b.lineTo(n,5);b.stroke();b.textAlign="right";b.textBaseline="middle";for(d=0;d<j.steps;d++)b.beginPath(),b.moveTo(n-3,p-(d+1)*k),c.scaleShowGridLines?(b.lineWidth=c.scaleGridLineWidth,
b.strokeStyle=c.scaleGridLineColor,b.lineTo(n+r+5,p-(d+1)*k)):b.lineTo(n-0.5,p-(d+1)*k),b.stroke(),c.scaleShowLabels&&b.fillText(j.labels[d],n-8,p-(d+1)*k)},function(d){function e(b,c){return p-d*v(a.datasets[b].data[c],j,k)}for(var f=0;f<a.datasets.length;f++){b.strokeStyle=a.datasets[f].strokeColor;b.lineWidth=c.datasetStrokeWidth;b.beginPath();b.moveTo(n,p-d*v(a.datasets[f].data[0],j,k));for(var g=1;g<a.datasets[f].data.length;g++)c.bezierCurve?b.bezierCurveTo(n+m*(g-0.5),e(f,g-1),n+m*(g-0.5),
e(f,g),n+m*g,e(f,g)):b.lineTo(n+m*g,e(f,g));b.stroke();c.datasetFill?(b.lineTo(n+m*(a.datasets[f].data.length-1),p),b.lineTo(n,p),b.closePath(),b.fillStyle=a.datasets[f].fillColor,b.fill()):b.closePath();if(c.pointDot){b.fillStyle=a.datasets[f].pointColor;b.strokeStyle=a.datasets[f].pointStrokeColor;b.lineWidth=c.pointDotStrokeWidth;for(g=0;g<a.datasets[f].data.length;g++)b.beginPath(),b.arc(n+m*g,p-d*v(a.datasets[f].data[g],j,k),c.pointDotRadius,0,2*Math.PI,!0),b.fill(),b.stroke()}}},b)},L=function(a,
c,b){var e,h,f,d,g,k,j,l,m,t,r,n,p,s,w=0;g=u;b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;t=1;for(d=0;d<a.labels.length;d++)e=b.measureText(a.labels[d]).width,t=e>t?e:t;q/a.labels.length<t?(w=45,q/a.labels.length<Math.cos(w)*t?(w=90,g-=t):g-=Math.sin(w)*t):g-=c.scaleFontSize;d=c.scaleFontSize;g=g-5-d;e=Number.MIN_VALUE;h=Number.MAX_VALUE;for(f=0;f<a.datasets.length;f++)for(l=0;l<a.datasets[f].data.length;l++)a.datasets[f].data[l]>e&&(e=a.datasets[f].data[l]),a.datasets[f].data[l]<
h&&(h=a.datasets[f].data[l]);f=Math.floor(g/(0.66*d));d=Math.floor(0.5*(g/d));l=c.scaleShowLabels?c.scaleLabel:"";c.scaleOverride?(j={steps:c.scaleSteps,stepValue:c.scaleStepWidth,graphMin:c.scaleStartValue,labels:[]},z(l,j.labels,j.steps,c.scaleStartValue,c.scaleStepWidth)):j=C(g,f,d,e,h,l);k=Math.floor(g/j.steps);d=1;if(c.scaleShowLabels){b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;for(e=0;e<j.labels.length;e++)h=b.measureText(j.labels[e]).width,d=h>d?h:d;d+=10}r=q-d-t;m=
Math.floor(r/a.labels.length);s=(m-2*c.scaleGridLineWidth-2*c.barValueSpacing-(c.barDatasetSpacing*a.datasets.length-1)-(c.barStrokeWidth/2*a.datasets.length-1))/a.datasets.length;n=q-t/2-r;p=g+c.scaleFontSize/2;x(c,function(){b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(q-t/2+5,p);b.lineTo(q-t/2-r-5,p);b.stroke();0<w?(b.save(),b.textAlign="right"):b.textAlign="center";b.fillStyle=c.scaleFontColor;for(var d=0;d<a.labels.length;d++)b.save(),0<w?(b.translate(n+
d*m,p+c.scaleFontSize),b.rotate(-(w*(Math.PI/180))),b.fillText(a.labels[d],0,0),b.restore()):b.fillText(a.labels[d],n+d*m+m/2,p+c.scaleFontSize+3),b.beginPath(),b.moveTo(n+(d+1)*m,p+3),b.lineWidth=c.scaleGridLineWidth,b.strokeStyle=c.scaleGridLineColor,b.lineTo(n+(d+1)*m,5),b.stroke();b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(n,p+5);b.lineTo(n,5);b.stroke();b.textAlign="right";b.textBaseline="middle";for(d=0;d<j.steps;d++)b.beginPath(),b.moveTo(n-3,p-(d+1)*
k),c.scaleShowGridLines?(b.lineWidth=c.scaleGridLineWidth,b.strokeStyle=c.scaleGridLineColor,b.lineTo(n+r+5,p-(d+1)*k)):b.lineTo(n-0.5,p-(d+1)*k),b.stroke(),c.scaleShowLabels&&b.fillText(j.labels[d],n-8,p-(d+1)*k)},function(d){b.lineWidth=c.barStrokeWidth;for(var e=0;e<a.datasets.length;e++){b.fillStyle=a.datasets[e].fillColor;b.strokeStyle=a.datasets[e].strokeColor;for(var f=0;f<a.datasets[e].data.length;f++){var g=n+c.barValueSpacing+m*f+s*e+c.barDatasetSpacing*e+c.barStrokeWidth*e;b.beginPath();
b.moveTo(g,p);b.lineTo(g,p-d*v(a.datasets[e].data[f],j,k)+c.barStrokeWidth/2);b.lineTo(g+s,p-d*v(a.datasets[e].data[f],j,k)+c.barStrokeWidth/2);b.lineTo(g+s,p);c.barShowStroke&&b.stroke();b.closePath();b.fill()}}},b)},D=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){window.setTimeout(a,1E3/60)},F={}};

View File

@ -0,0 +1,246 @@
/* BASICS */
.CodeMirror {
/* Set height, width, borders, and global font properties here */
font-family: monospace;
height: 300px;
}
.CodeMirror-scroll {
/* Set scrolling behaviour here */
overflow: auto;
}
/* PADDING */
.CodeMirror-lines {
padding: 4px 0; /* Vertical padding around content */
}
.CodeMirror pre {
padding: 0 4px; /* Horizontal padding of content */
}
.CodeMirror-scrollbar-filler {
background-color: white; /* The little square between H and V scrollbars */
}
/* GUTTER */
.CodeMirror-gutters {
border-right: 1px solid #ddd;
background-color: #f7f7f7;
}
.CodeMirror-linenumbers {}
.CodeMirror-linenumber {
padding: 0 3px 0 5px;
min-width: 20px;
text-align: right;
color: #999;
}
/* CURSOR */
.CodeMirror div.CodeMirror-cursor {
border-left: 1px solid black;
z-index: 3;
}
/* Shown when moving in bi-directional text */
.CodeMirror div.CodeMirror-secondarycursor {
border-left: 1px solid silver;
}
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
width: auto;
border: 0;
background: #7e7;
z-index: 1;
}
/* Can style cursor different in overwrite (non-insert) mode */
.CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {}
.cm-tab { display: inline-block; }
/* DEFAULT THEME */
.cm-s-default .cm-keyword {color: #708;}
.cm-s-default .cm-atom {color: #219;}
.cm-s-default .cm-number {color: #164;}
.cm-s-default .cm-def {color: #00f;}
.cm-s-default .cm-variable {color: black;}
.cm-s-default .cm-variable-2 {color: #05a;}
.cm-s-default .cm-variable-3 {color: #085;}
.cm-s-default .cm-property {color: black;}
.cm-s-default .cm-operator {color: black;}
.cm-s-default .cm-comment {color: #a50;}
.cm-s-default .cm-string {color: #a11;}
.cm-s-default .cm-string-2 {color: #f50;}
.cm-s-default .cm-meta {color: #555;}
.cm-s-default .cm-error {color: #f00;}
.cm-s-default .cm-qualifier {color: #555;}
.cm-s-default .cm-builtin {color: #30a;}
.cm-s-default .cm-bracket {color: #997;}
.cm-s-default .cm-tag {color: #170;}
.cm-s-default .cm-attribute {color: #00c;}
.cm-s-default .cm-header {color: blue;}
.cm-s-default .cm-quote {color: #090;}
.cm-s-default .cm-hr {color: #999;}
.cm-s-default .cm-link {color: #00c;}
.cm-negative {color: #d44;}
.cm-positive {color: #292;}
.cm-header, .cm-strong {font-weight: bold;}
.cm-em {font-style: italic;}
.cm-link {text-decoration: underline;}
.cm-invalidchar {color: #f00;}
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
/* STOP */
/* The rest of this file contains styles related to the mechanics of
the editor. You probably shouldn't touch them. */
.CodeMirror {
line-height: 1;
position: relative;
overflow: hidden;
background: white;
color: black;
}
.CodeMirror-scroll {
/* 30px is the magic margin used to hide the element's real scrollbars */
/* See overflow: hidden in .CodeMirror */
margin-bottom: -30px; margin-right: -30px;
padding-bottom: 30px; padding-right: 30px;
height: 100%;
outline: none; /* Prevent dragging from highlighting the element */
position: relative;
}
.CodeMirror-sizer {
position: relative;
}
/* The fake, visible scrollbars. Used to force redraw during scrolling
before actuall scrolling happens, thus preventing shaking and
flickering artifacts. */
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler {
position: absolute;
z-index: 6;
display: none;
}
.CodeMirror-vscrollbar {
right: 0; top: 0;
overflow-x: hidden;
overflow-y: scroll;
}
.CodeMirror-hscrollbar {
bottom: 0; left: 0;
overflow-y: hidden;
overflow-x: scroll;
}
.CodeMirror-scrollbar-filler {
right: 0; bottom: 0;
z-index: 6;
}
.CodeMirror-gutters {
position: absolute; left: 0; top: 0;
height: 100%;
padding-bottom: 30px;
z-index: 3;
}
.CodeMirror-gutter {
height: 100%;
padding-bottom: 30px;
margin-bottom: -32px;
display: inline-block;
/* Hack to make IE7 behave */
*zoom:1;
*display:inline;
}
.CodeMirror-gutter-elt {
position: absolute;
cursor: default;
z-index: 4;
}
.CodeMirror-lines {
cursor: text;
}
.CodeMirror pre {
/* Reset some styles that the rest of the page might have set */
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
border-width: 0;
background: transparent;
font-family: inherit;
font-size: inherit;
margin: 0;
white-space: pre;
word-wrap: normal;
line-height: inherit;
color: inherit;
z-index: 2;
position: relative;
overflow: visible;
}
.CodeMirror-wrap pre {
word-wrap: break-word;
white-space: pre-wrap;
word-break: normal;
}
.CodeMirror-linebackground {
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
z-index: 0;
}
.CodeMirror-linewidget {
position: relative;
z-index: 2;
overflow: auto;
}
.CodeMirror-widget {
display: inline-block;
}
.CodeMirror-wrap .CodeMirror-scroll {
overflow-x: hidden;
}
.CodeMirror-measure {
position: absolute;
width: 100%; height: 0px;
overflow: hidden;
visibility: hidden;
}
.CodeMirror-measure pre { position: static; }
.CodeMirror div.CodeMirror-cursor {
position: absolute;
visibility: hidden;
border-right: none;
width: 0;
}
.CodeMirror-focused div.CodeMirror-cursor {
visibility: visible;
}
.CodeMirror-selected { background: #d9d9d9; }
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
.cm-searching {
background: #ffa;
background: rgba(255, 255, 0, .4);
}
/* IE7 hack to prevent it from returning funny offsetTops on the spans */
.CodeMirror span { *vertical-align: text-bottom; }
@media print {
/* Hide the cursor when printing */
.CodeMirror div.CodeMirror-cursor {
visibility: hidden;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,344 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>CodeMirror: Markdown mode</title>
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="../../addon/edit/continuelist.js"></script>
<script src="../xml/xml.js"></script>
<script src="markdown.js"></script>
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<link rel="stylesheet" href="../../doc/docs.css">
</head>
<body>
<h1>CodeMirror: Markdown mode</h1>
<!-- source: http://daringfireball.net/projects/markdown/basics.text -->
<form><textarea id="code" name="code">
Markdown: Basics
================
&lt;ul id="ProjectSubmenu"&gt;
&lt;li&gt;&lt;a href="/projects/markdown/" title="Markdown Project Page"&gt;Main&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="selected" title="Markdown Basics"&gt;Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/projects/markdown/syntax" title="Markdown Syntax Documentation"&gt;Syntax&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/projects/markdown/license" title="Pricing and License Information"&gt;License&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/projects/markdown/dingus" title="Online Markdown Web Form"&gt;Dingus&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
Getting the Gist of Markdown's Formatting Syntax
------------------------------------------------
This page offers a brief overview of what it's like to use Markdown.
The [syntax page] [s] provides complete, detailed documentation for
every feature, but Markdown should be very easy to pick up simply by
looking at a few examples of it in action. The examples on this page
are written in a before/after style, showing example syntax and the
HTML output produced by Markdown.
It's also helpful to simply try Markdown out; the [Dingus] [d] is a
web application that allows you type your own Markdown-formatted text
and translate it to XHTML.
**Note:** This document is itself written using Markdown; you
can [see the source for it by adding '.text' to the URL] [src].
[s]: /projects/markdown/syntax "Markdown Syntax"
[d]: /projects/markdown/dingus "Markdown Dingus"
[src]: /projects/markdown/basics.text
## Paragraphs, Headers, Blockquotes ##
A paragraph is simply one or more consecutive lines of text, separated
by one or more blank lines. (A blank line is any line that looks like
a blank line -- a line containing nothing but spaces or tabs is
considered blank.) Normal paragraphs should not be indented with
spaces or tabs.
Markdown offers two styles of headers: *Setext* and *atx*.
Setext-style headers for `&lt;h1&gt;` and `&lt;h2&gt;` are created by
"underlining" with equal signs (`=`) and hyphens (`-`), respectively.
To create an atx-style header, you put 1-6 hash marks (`#`) at the
beginning of the line -- the number of hashes equals the resulting
HTML header level.
Blockquotes are indicated using email-style '`&gt;`' angle brackets.
Markdown:
A First Level Header
====================
A Second Level Header
---------------------
Now is the time for all good men to come to
the aid of their country. This is just a
regular paragraph.
The quick brown fox jumped over the lazy
dog's back.
### Header 3
&gt; This is a blockquote.
&gt;
&gt; This is the second paragraph in the blockquote.
&gt;
&gt; ## This is an H2 in a blockquote
Output:
&lt;h1&gt;A First Level Header&lt;/h1&gt;
&lt;h2&gt;A Second Level Header&lt;/h2&gt;
&lt;p&gt;Now is the time for all good men to come to
the aid of their country. This is just a
regular paragraph.&lt;/p&gt;
&lt;p&gt;The quick brown fox jumped over the lazy
dog's back.&lt;/p&gt;
&lt;h3&gt;Header 3&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a blockquote.&lt;/p&gt;
&lt;p&gt;This is the second paragraph in the blockquote.&lt;/p&gt;
&lt;h2&gt;This is an H2 in a blockquote&lt;/h2&gt;
&lt;/blockquote&gt;
### Phrase Emphasis ###
Markdown uses asterisks and underscores to indicate spans of emphasis.
Markdown:
Some of these words *are emphasized*.
Some of these words _are emphasized also_.
Use two asterisks for **strong emphasis**.
Or, if you prefer, __use two underscores instead__.
Output:
&lt;p&gt;Some of these words &lt;em&gt;are emphasized&lt;/em&gt;.
Some of these words &lt;em&gt;are emphasized also&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Use two asterisks for &lt;strong&gt;strong emphasis&lt;/strong&gt;.
Or, if you prefer, &lt;strong&gt;use two underscores instead&lt;/strong&gt;.&lt;/p&gt;
## Lists ##
Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`,
`+`, and `-`) as list markers. These three markers are
interchangable; this:
* Candy.
* Gum.
* Booze.
this:
+ Candy.
+ Gum.
+ Booze.
and this:
- Candy.
- Gum.
- Booze.
all produce the same output:
&lt;ul&gt;
&lt;li&gt;Candy.&lt;/li&gt;
&lt;li&gt;Gum.&lt;/li&gt;
&lt;li&gt;Booze.&lt;/li&gt;
&lt;/ul&gt;
Ordered (numbered) lists use regular numbers, followed by periods, as
list markers:
1. Red
2. Green
3. Blue
Output:
&lt;ol&gt;
&lt;li&gt;Red&lt;/li&gt;
&lt;li&gt;Green&lt;/li&gt;
&lt;li&gt;Blue&lt;/li&gt;
&lt;/ol&gt;
If you put blank lines between items, you'll get `&lt;p&gt;` tags for the
list item text. You can create multi-paragraph list items by indenting
the paragraphs by 4 spaces or 1 tab:
* A list item.
With multiple paragraphs.
* Another item in the list.
Output:
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A list item.&lt;/p&gt;
&lt;p&gt;With multiple paragraphs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Another item in the list.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
### Links ###
Markdown supports two styles for creating links: *inline* and
*reference*. With both styles, you use square brackets to delimit the
text you want to turn into a link.
Inline-style links use parentheses immediately after the link text.
For example:
This is an [example link](http://example.com/).
Output:
&lt;p&gt;This is an &lt;a href="http://example.com/"&gt;
example link&lt;/a&gt;.&lt;/p&gt;
Optionally, you may include a title attribute in the parentheses:
This is an [example link](http://example.com/ "With a Title").
Output:
&lt;p&gt;This is an &lt;a href="http://example.com/" title="With a Title"&gt;
example link&lt;/a&gt;.&lt;/p&gt;
Reference-style links allow you to refer to your links by names, which
you define elsewhere in your document:
I get 10 times more traffic from [Google][1] than from
[Yahoo][2] or [MSN][3].
[1]: http://google.com/ "Google"
[2]: http://search.yahoo.com/ "Yahoo Search"
[3]: http://search.msn.com/ "MSN Search"
Output:
&lt;p&gt;I get 10 times more traffic from &lt;a href="http://google.com/"
title="Google"&gt;Google&lt;/a&gt; than from &lt;a href="http://search.yahoo.com/"
title="Yahoo Search"&gt;Yahoo&lt;/a&gt; or &lt;a href="http://search.msn.com/"
title="MSN Search"&gt;MSN&lt;/a&gt;.&lt;/p&gt;
The title attribute is optional. Link names may contain letters,
numbers and spaces, but are *not* case sensitive:
I start my morning with a cup of coffee and
[The New York Times][NY Times].
[ny times]: http://www.nytimes.com/
Output:
&lt;p&gt;I start my morning with a cup of coffee and
&lt;a href="http://www.nytimes.com/"&gt;The New York Times&lt;/a&gt;.&lt;/p&gt;
### Images ###
Image syntax is very much like link syntax.
Inline (titles are optional):
![alt text](/path/to/img.jpg "Title")
Reference-style:
![alt text][id]
[id]: /path/to/img.jpg "Title"
Both of the above examples produce the same output:
&lt;img src="/path/to/img.jpg" alt="alt text" title="Title" /&gt;
### Code ###
In a regular paragraph, you can create code span by wrapping text in
backtick quotes. Any ampersands (`&amp;`) and angle brackets (`&lt;` or
`&gt;`) will automatically be translated into HTML entities. This makes
it easy to use Markdown to write about HTML example code:
I strongly recommend against using any `&lt;blink&gt;` tags.
I wish SmartyPants used named entities like `&amp;mdash;`
instead of decimal-encoded entites like `&amp;#8212;`.
Output:
&lt;p&gt;I strongly recommend against using any
&lt;code&gt;&amp;lt;blink&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;
&lt;p&gt;I wish SmartyPants used named entities like
&lt;code&gt;&amp;amp;mdash;&lt;/code&gt; instead of decimal-encoded
entites like &lt;code&gt;&amp;amp;#8212;&lt;/code&gt;.&lt;/p&gt;
To specify an entire block of pre-formatted code, indent every line of
the block by 4 spaces or 1 tab. Just like with code spans, `&amp;`, `&lt;`,
and `&gt;` characters will be escaped automatically.
Markdown:
If you want your page to validate under XHTML 1.0 Strict,
you've got to put paragraph tags in your blockquotes:
&lt;blockquote&gt;
&lt;p&gt;For example.&lt;/p&gt;
&lt;/blockquote&gt;
Output:
&lt;p&gt;If you want your page to validate under XHTML 1.0 Strict,
you've got to put paragraph tags in your blockquotes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;blockquote&amp;gt;
&amp;lt;p&amp;gt;For example.&amp;lt;/p&amp;gt;
&amp;lt;/blockquote&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: 'markdown',
lineNumbers: true,
theme: "default",
extraKeys: {"Enter": "newlineAndIndentContinueMarkdownList"}
});
</script>
<p>Optionally depends on the XML mode for properly highlighted inline XML blocks.</p>
<p><strong>MIME types defined:</strong> <code>text/x-markdown</code>.</p>
<p><strong>Parsing/Highlighting Tests:</strong> <a href="../../test/index.html#markdown_*">normal</a>, <a href="../../test/index.html#verbose,markdown_*">verbose</a>.</p>
</body>
</html>

View File

@ -0,0 +1,526 @@
CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
var htmlFound = CodeMirror.mimeModes.hasOwnProperty("text/html");
var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? "text/html" : "text/plain");
var aliases = {
html: "htmlmixed",
js: "javascript",
json: "application/json",
c: "text/x-csrc",
"c++": "text/x-c++src",
java: "text/x-java",
csharp: "text/x-csharp",
"c#": "text/x-csharp",
scala: "text/x-scala"
};
var getMode = (function () {
var i, modes = {}, mimes = {}, mime;
var list = [];
for (var m in CodeMirror.modes)
if (CodeMirror.modes.propertyIsEnumerable(m)) list.push(m);
for (i = 0; i < list.length; i++) {
modes[list[i]] = list[i];
}
var mimesList = [];
for (var m in CodeMirror.mimeModes)
if (CodeMirror.mimeModes.propertyIsEnumerable(m))
mimesList.push({mime: m, mode: CodeMirror.mimeModes[m]});
for (i = 0; i < mimesList.length; i++) {
mime = mimesList[i].mime;
mimes[mime] = mimesList[i].mime;
}
for (var a in aliases) {
if (aliases[a] in modes || aliases[a] in mimes)
modes[a] = aliases[a];
}
return function (lang) {
return modes[lang] ? CodeMirror.getMode(cmCfg, modes[lang]) : null;
};
}());
// Should underscores in words open/close em/strong?
if (modeCfg.underscoresBreakWords === undefined)
modeCfg.underscoresBreakWords = true;
// Turn on fenced code blocks? ("```" to start/end)
if (modeCfg.fencedCodeBlocks === undefined) modeCfg.fencedCodeBlocks = false;
// Turn on task lists? ("- [ ] " and "- [x] ")
if (modeCfg.taskLists === undefined) modeCfg.taskLists = false;
var codeDepth = 0;
var header = 'header'
, code = 'comment'
, quote1 = 'atom'
, quote2 = 'number'
, list1 = 'variable-2'
, list2 = 'variable-3'
, list3 = 'keyword'
, hr = 'hr'
, image = 'tag'
, linkinline = 'link'
, linkemail = 'link'
, linktext = 'link'
, linkhref = 'string'
, em = 'em'
, strong = 'strong';
var hrRE = /^([*\-=_])(?:\s*\1){2,}\s*$/
, ulRE = /^[*\-+]\s+/
, olRE = /^[0-9]+\.\s+/
, taskListRE = /^\[(x| )\](?=\s)/ // Must follow ulRE or olRE
, headerRE = /^(?:\={1,}|-{1,})$/
, textRE = /^[^!\[\]*_\\<>` "'(]+/;
function switchInline(stream, state, f) {
state.f = state.inline = f;
return f(stream, state);
}
function switchBlock(stream, state, f) {
state.f = state.block = f;
return f(stream, state);
}
// Blocks
function blankLine(state) {
// Reset linkTitle state
state.linkTitle = false;
// Reset EM state
state.em = false;
// Reset STRONG state
state.strong = false;
// Reset state.quote
state.quote = 0;
if (!htmlFound && state.f == htmlBlock) {
state.f = inlineNormal;
state.block = blockNormal;
}
// Mark this line as blank
state.thisLineHasContent = false;
return null;
}
function blockNormal(stream, state) {
var prevLineIsList = (state.list !== false);
if (state.list !== false && state.indentationDiff >= 0) { // Continued list
if (state.indentationDiff < 4) { // Only adjust indentation if *not* a code block
state.indentation -= state.indentationDiff;
}
state.list = null;
} else if (state.list !== false && state.indentation > 0) {
state.list = null;
state.listDepth = Math.floor(state.indentation / 4);
} else if (state.list !== false) { // No longer a list
state.list = false;
state.listDepth = 0;
}
if (state.indentationDiff >= 4) {
state.indentation -= 4;
stream.skipToEnd();
return code;
} else if (stream.eatSpace()) {
return null;
} else if (stream.peek() === '#' || (state.prevLineHasContent && stream.match(headerRE)) ) {
state.header = true;
} else if (stream.eat('>')) {
state.indentation++;
state.quote = 1;
stream.eatSpace();
while (stream.eat('>')) {
stream.eatSpace();
state.quote++;
}
} else if (stream.peek() === '[') {
return switchInline(stream, state, footnoteLink);
} else if (stream.match(hrRE, true)) {
return hr;
} else if ((!state.prevLineHasContent || prevLineIsList) && (stream.match(ulRE, true) || stream.match(olRE, true))) {
state.indentation += 4;
state.list = true;
state.listDepth++;
if (modeCfg.taskLists && stream.match(taskListRE, false)) {
state.taskList = true;
}
} else if (modeCfg.fencedCodeBlocks && stream.match(/^```([\w+#]*)/, true)) {
// try switching mode
state.localMode = getMode(RegExp.$1);
if (state.localMode) state.localState = state.localMode.startState();
switchBlock(stream, state, local);
return code;
}
return switchInline(stream, state, state.inline);
}
function htmlBlock(stream, state) {
var style = htmlMode.token(stream, state.htmlState);
if (htmlFound && style === 'tag' && state.htmlState.type !== 'openTag' && !state.htmlState.context) {
state.f = inlineNormal;
state.block = blockNormal;
}
if (state.md_inside && stream.current().indexOf(">")!=-1) {
state.f = inlineNormal;
state.block = blockNormal;
state.htmlState.context = undefined;
}
return style;
}
function local(stream, state) {
if (stream.sol() && stream.match(/^```/, true)) {
state.localMode = state.localState = null;
state.f = inlineNormal;
state.block = blockNormal;
return code;
} else if (state.localMode) {
return state.localMode.token(stream, state.localState);
} else {
stream.skipToEnd();
return code;
}
}
// Inline
function getType(state) {
var styles = [];
if (state.taskOpen) { return "meta"; }
if (state.taskClosed) { return "property"; }
if (state.strong) { styles.push(strong); }
if (state.em) { styles.push(em); }
if (state.linkText) { styles.push(linktext); }
if (state.code) { styles.push(code); }
if (state.header) { styles.push(header); }
if (state.quote) { styles.push(state.quote % 2 ? quote1 : quote2); }
if (state.list !== false) {
var listMod = (state.listDepth - 1) % 3;
if (!listMod) {
styles.push(list1);
} else if (listMod === 1) {
styles.push(list2);
} else {
styles.push(list3);
}
}
return styles.length ? styles.join(' ') : null;
}
function handleText(stream, state) {
if (stream.match(textRE, true)) {
return getType(state);
}
return undefined;
}
function inlineNormal(stream, state) {
var style = state.text(stream, state);
if (typeof style !== 'undefined')
return style;
if (state.list) { // List marker (*, +, -, 1., etc)
state.list = null;
return getType(state);
}
if (state.taskList) {
var taskOpen = stream.match(taskListRE, true)[1] !== "x";
if (taskOpen) state.taskOpen = true;
else state.taskClosed = true;
state.taskList = false;
return getType(state);
}
state.taskOpen = false;
state.taskClosed = false;
var ch = stream.next();
if (ch === '\\') {
stream.next();
return getType(state);
}
// Matches link titles present on next line
if (state.linkTitle) {
state.linkTitle = false;
var matchCh = ch;
if (ch === '(') {
matchCh = ')';
}
matchCh = (matchCh+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
var regex = '^\\s*(?:[^' + matchCh + '\\\\]+|\\\\\\\\|\\\\.)' + matchCh;
if (stream.match(new RegExp(regex), true)) {
return linkhref;
}
}
// If this block is changed, it may need to be updated in GFM mode
if (ch === '`') {
var t = getType(state);
var before = stream.pos;
stream.eatWhile('`');
var difference = 1 + stream.pos - before;
if (!state.code) {
codeDepth = difference;
state.code = true;
return getType(state);
} else {
if (difference === codeDepth) { // Must be exact
state.code = false;
return t;
}
return getType(state);
}
} else if (state.code) {
return getType(state);
}
if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) {
stream.match(/\[[^\]]*\]/);
state.inline = state.f = linkHref;
return image;
}
if (ch === '[' && stream.match(/.*\](\(| ?\[)/, false)) {
state.linkText = true;
return getType(state);
}
if (ch === ']' && state.linkText) {
var type = getType(state);
state.linkText = false;
state.inline = state.f = linkHref;
return type;
}
if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, true)) {
return switchInline(stream, state, inlineElement(linkinline, '>'));
}
if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, true)) {
return switchInline(stream, state, inlineElement(linkemail, '>'));
}
if (ch === '<' && stream.match(/^\w/, false)) {
if (stream.string.indexOf(">")!=-1) {
var atts = stream.string.substring(1,stream.string.indexOf(">"));
if (/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(atts)) {
state.md_inside = true;
}
}
stream.backUp(1);
return switchBlock(stream, state, htmlBlock);
}
if (ch === '<' && stream.match(/^\/\w*?>/)) {
state.md_inside = false;
return "tag";
}
var ignoreUnderscore = false;
if (!modeCfg.underscoresBreakWords) {
if (ch === '_' && stream.peek() !== '_' && stream.match(/(\w)/, false)) {
var prevPos = stream.pos - 2;
if (prevPos >= 0) {
var prevCh = stream.string.charAt(prevPos);
if (prevCh !== '_' && prevCh.match(/(\w)/, false)) {
ignoreUnderscore = true;
}
}
}
}
var t = getType(state);
if (ch === '*' || (ch === '_' && !ignoreUnderscore)) {
if (state.strong === ch && stream.eat(ch)) { // Remove STRONG
state.strong = false;
return t;
} else if (!state.strong && stream.eat(ch)) { // Add STRONG
state.strong = ch;
return getType(state);
} else if (state.em === ch) { // Remove EM
state.em = false;
return t;
} else if (!state.em) { // Add EM
state.em = ch;
return getType(state);
}
} else if (ch === ' ') {
if (stream.eat('*') || stream.eat('_')) { // Probably surrounded by spaces
if (stream.peek() === ' ') { // Surrounded by spaces, ignore
return getType(state);
} else { // Not surrounded by spaces, back up pointer
stream.backUp(1);
}
}
}
return getType(state);
}
function linkHref(stream, state) {
// Check if space, and return NULL if so (to avoid marking the space)
if(stream.eatSpace()){
return null;
}
var ch = stream.next();
if (ch === '(' || ch === '[') {
return switchInline(stream, state, inlineElement(linkhref, ch === '(' ? ')' : ']'));
}
return 'error';
}
function footnoteLink(stream, state) {
if (stream.match(/^[^\]]*\]:/, true)) {
state.f = footnoteUrl;
return linktext;
}
return switchInline(stream, state, inlineNormal);
}
function footnoteUrl(stream, state) {
// Check if space, and return NULL if so (to avoid marking the space)
if(stream.eatSpace()){
return null;
}
// Match URL
stream.match(/^[^\s]+/, true);
// Check for link title
if (stream.peek() === undefined) { // End of line, set flag to check next line
state.linkTitle = true;
} else { // More content on line, check if link title
stream.match(/^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/, true);
}
state.f = state.inline = inlineNormal;
return linkhref;
}
var savedInlineRE = [];
function inlineRE(endChar) {
if (!savedInlineRE[endChar]) {
// Escape endChar for RegExp (taken from http://stackoverflow.com/a/494122/526741)
endChar = (endChar+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
// Match any non-endChar, escaped character, as well as the closing
// endChar.
savedInlineRE[endChar] = new RegExp('^(?:[^\\\\]|\\\\.)*?(' + endChar + ')');
}
return savedInlineRE[endChar];
}
function inlineElement(type, endChar, next) {
next = next || inlineNormal;
return function(stream, state) {
stream.match(inlineRE(endChar));
state.inline = state.f = next;
return type;
};
}
return {
startState: function() {
return {
f: blockNormal,
prevLineHasContent: false,
thisLineHasContent: false,
block: blockNormal,
htmlState: CodeMirror.startState(htmlMode),
indentation: 0,
inline: inlineNormal,
text: handleText,
linkText: false,
linkTitle: false,
em: false,
strong: false,
header: false,
taskList: false,
list: false,
listDepth: 0,
quote: 0
};
},
copyState: function(s) {
return {
f: s.f,
prevLineHasContent: s.prevLineHasContent,
thisLineHasContent: s.thisLineHasContent,
block: s.block,
htmlState: CodeMirror.copyState(htmlMode, s.htmlState),
indentation: s.indentation,
localMode: s.localMode,
localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null,
inline: s.inline,
text: s.text,
linkTitle: s.linkTitle,
em: s.em,
strong: s.strong,
header: s.header,
taskList: s.taskList,
list: s.list,
listDepth: s.listDepth,
quote: s.quote,
md_inside: s.md_inside
};
},
token: function(stream, state) {
if (stream.sol()) {
if (stream.match(/^\s*$/, true)) {
state.prevLineHasContent = false;
return blankLine(state);
} else {
state.prevLineHasContent = state.thisLineHasContent;
state.thisLineHasContent = true;
}
// Reset state.header
state.header = false;
// Reset state.taskList
state.taskList = false;
// Reset state.code
state.code = false;
state.f = state.block;
var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length;
var difference = Math.floor((indentation - state.indentation) / 4) * 4;
if (difference > 4) difference = 4;
var adjustedIndentation = state.indentation + difference;
state.indentationDiff = adjustedIndentation - state.indentation;
state.indentation = adjustedIndentation;
if (indentation > 0) return null;
}
return state.f(stream, state);
},
blankLine: blankLine,
getType: getType
};
}, "xml");
CodeMirror.defineMIME("text/x-markdown", "markdown");

View File

@ -0,0 +1,636 @@
(function() {
var mode = CodeMirror.getMode({tabSize: 4}, "markdown");
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
MT("plainText",
"foo");
// Code blocks using 4 spaces (regardless of CodeMirror.tabSize value)
MT("codeBlocksUsing4Spaces",
" [comment foo]");
// Code blocks using 4 spaces with internal indentation
MT("codeBlocksUsing4SpacesIndentation",
" [comment bar]",
" [comment hello]",
" [comment world]",
" [comment foo]",
"bar");
// Code blocks using 4 spaces with internal indentation
MT("codeBlocksUsing4SpacesIndentation",
" foo",
" [comment bar]",
" [comment hello]",
" [comment world]");
// Code blocks using 1 tab (regardless of CodeMirror.indentWithTabs value)
MT("codeBlocksUsing1Tab",
"\t[comment foo]");
// Inline code using backticks
MT("inlineCodeUsingBackticks",
"foo [comment `bar`]");
// Block code using single backtick (shouldn't work)
MT("blockCodeSingleBacktick",
"[comment `]",
"foo",
"[comment `]");
// Unclosed backticks
// Instead of simply marking as CODE, it would be nice to have an
// incomplete flag for CODE, that is styled slightly different.
MT("unclosedBackticks",
"foo [comment `bar]");
// Per documentation: "To include a literal backtick character within a
// code span, you can use multiple backticks as the opening and closing
// delimiters"
MT("doubleBackticks",
"[comment ``foo ` bar``]");
// Tests based on Dingus
// http://daringfireball.net/projects/markdown/dingus
//
// Multiple backticks within an inline code block
MT("consecutiveBackticks",
"[comment `foo```bar`]");
// Multiple backticks within an inline code block with a second code block
MT("consecutiveBackticks",
"[comment `foo```bar`] hello [comment `world`]");
// Unclosed with several different groups of backticks
MT("unclosedBackticks",
"[comment ``foo ``` bar` hello]");
// Closed with several different groups of backticks
MT("closedBackticks",
"[comment ``foo ``` bar` hello``] world");
// atx headers
// http://daringfireball.net/projects/markdown/syntax#header
MT("atxH1",
"[header # foo]");
MT("atxH2",
"[header ## foo]");
MT("atxH3",
"[header ### foo]");
MT("atxH4",
"[header #### foo]");
MT("atxH5",
"[header ##### foo]");
MT("atxH6",
"[header ###### foo]");
// H6 - 7x '#' should still be H6, per Dingus
// http://daringfireball.net/projects/markdown/dingus
MT("atxH6NotH7",
"[header ####### foo]");
// Setext headers - H1, H2
// Per documentation, "Any number of underlining =s or -s will work."
// http://daringfireball.net/projects/markdown/syntax#header
// Ideally, the text would be marked as `header` as well, but this is
// not really feasible at the moment. So, instead, we're testing against
// what works today, to avoid any regressions.
//
// Check if single underlining = works
MT("setextH1",
"foo",
"[header =]");
// Check if 3+ ='s work
MT("setextH1",
"foo",
"[header ===]");
// Check if single underlining - works
MT("setextH2",
"foo",
"[header -]");
// Check if 3+ -'s work
MT("setextH2",
"foo",
"[header ---]");
// Single-line blockquote with trailing space
MT("blockquoteSpace",
"[atom > foo]");
// Single-line blockquote
MT("blockquoteNoSpace",
"[atom >foo]");
// No blank line before blockquote
MT("blockquoteNoBlankLine",
"foo",
"[atom > bar]");
// Nested blockquote
MT("blockquoteSpace",
"[atom > foo]",
"[number > > foo]",
"[atom > > > foo]");
// Single-line blockquote followed by normal paragraph
MT("blockquoteThenParagraph",
"[atom >foo]",
"",
"bar");
// Multi-line blockquote (lazy mode)
MT("multiBlockquoteLazy",
"[atom >foo]",
"[atom bar]");
// Multi-line blockquote followed by normal paragraph (lazy mode)
MT("multiBlockquoteLazyThenParagraph",
"[atom >foo]",
"[atom bar]",
"",
"hello");
// Multi-line blockquote (non-lazy mode)
MT("multiBlockquote",
"[atom >foo]",
"[atom >bar]");
// Multi-line blockquote followed by normal paragraph (non-lazy mode)
MT("multiBlockquoteThenParagraph",
"[atom >foo]",
"[atom >bar]",
"",
"hello");
// Check list types
MT("listAsterisk",
"foo",
"bar",
"",
"[variable-2 * foo]",
"[variable-2 * bar]");
MT("listPlus",
"foo",
"bar",
"",
"[variable-2 + foo]",
"[variable-2 + bar]");
MT("listDash",
"foo",
"bar",
"",
"[variable-2 - foo]",
"[variable-2 - bar]");
MT("listNumber",
"foo",
"bar",
"",
"[variable-2 1. foo]",
"[variable-2 2. bar]");
// Lists require a preceding blank line (per Dingus)
MT("listBogus",
"foo",
"1. bar",
"2. hello");
// Formatting in lists (*)
MT("listAsteriskFormatting",
"[variable-2 * ][variable-2&em *foo*][variable-2 bar]",
"[variable-2 * ][variable-2&strong **foo**][variable-2 bar]",
"[variable-2 * ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
"[variable-2 * ][variable-2&comment `foo`][variable-2 bar]");
// Formatting in lists (+)
MT("listPlusFormatting",
"[variable-2 + ][variable-2&em *foo*][variable-2 bar]",
"[variable-2 + ][variable-2&strong **foo**][variable-2 bar]",
"[variable-2 + ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
"[variable-2 + ][variable-2&comment `foo`][variable-2 bar]");
// Formatting in lists (-)
MT("listDashFormatting",
"[variable-2 - ][variable-2&em *foo*][variable-2 bar]",
"[variable-2 - ][variable-2&strong **foo**][variable-2 bar]",
"[variable-2 - ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
"[variable-2 - ][variable-2&comment `foo`][variable-2 bar]");
// Formatting in lists (1.)
MT("listNumberFormatting",
"[variable-2 1. ][variable-2&em *foo*][variable-2 bar]",
"[variable-2 2. ][variable-2&strong **foo**][variable-2 bar]",
"[variable-2 3. ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
"[variable-2 4. ][variable-2&comment `foo`][variable-2 bar]");
// Paragraph lists
MT("listParagraph",
"[variable-2 * foo]",
"",
"[variable-2 * bar]");
// Multi-paragraph lists
//
// 4 spaces
MT("listMultiParagraph",
"[variable-2 * foo]",
"",
"[variable-2 * bar]",
"",
" [variable-2 hello]");
// 4 spaces, extra blank lines (should still be list, per Dingus)
MT("listMultiParagraphExtra",
"[variable-2 * foo]",
"",
"[variable-2 * bar]",
"",
"",
" [variable-2 hello]");
// 4 spaces, plus 1 space (should still be list, per Dingus)
MT("listMultiParagraphExtraSpace",
"[variable-2 * foo]",
"",
"[variable-2 * bar]",
"",
" [variable-2 hello]",
"",
" [variable-2 world]");
// 1 tab
MT("listTab",
"[variable-2 * foo]",
"",
"[variable-2 * bar]",
"",
"\t[variable-2 hello]");
// No indent
MT("listNoIndent",
"[variable-2 * foo]",
"",
"[variable-2 * bar]",
"",
"hello");
// Blockquote
MT("blockquote",
"[variable-2 * foo]",
"",
"[variable-2 * bar]",
"",
" [variable-2&atom > hello]");
// Code block
MT("blockquoteCode",
"[variable-2 * foo]",
"",
"[variable-2 * bar]",
"",
" [comment > hello]",
"",
" [variable-2 world]");
// Code block followed by text
MT("blockquoteCodeText",
"[variable-2 * foo]",
"",
" [variable-2 bar]",
"",
" [comment hello]",
"",
" [variable-2 world]");
// Nested list
MT("listAsteriskNested",
"[variable-2 * foo]",
"",
" [variable-3 * bar]");
MT("listPlusNested",
"[variable-2 + foo]",
"",
" [variable-3 + bar]");
MT("listDashNested",
"[variable-2 - foo]",
"",
" [variable-3 - bar]");
MT("listNumberNested",
"[variable-2 1. foo]",
"",
" [variable-3 2. bar]");
MT("listMixed",
"[variable-2 * foo]",
"",
" [variable-3 + bar]",
"",
" [keyword - hello]",
"",
" [variable-2 1. world]");
MT("listBlockquote",
"[variable-2 * foo]",
"",
" [variable-3 + bar]",
"",
" [atom&variable-3 > hello]");
MT("listCode",
"[variable-2 * foo]",
"",
" [variable-3 + bar]",
"",
" [comment hello]");
// Code with internal indentation
MT("listCodeIndentation",
"[variable-2 * foo]",
"",
" [comment bar]",
" [comment hello]",
" [comment world]",
" [comment foo]",
" [variable-2 bar]");
// List nesting edge cases
MT("listNested",
"[variable-2 * foo]",
"",
" [variable-3 * bar]",
"",
" [variable-2 hello]"
);
MT("listNested",
"[variable-2 * foo]",
"",
" [variable-3 * bar]",
"",
" [variable-3 * foo]"
);
// Code followed by text
MT("listCodeText",
"[variable-2 * foo]",
"",
" [comment bar]",
"",
"hello");
// Following tests directly from official Markdown documentation
// http://daringfireball.net/projects/markdown/syntax#hr
MT("hrSpace",
"[hr * * *]");
MT("hr",
"[hr ***]");
MT("hrLong",
"[hr *****]");
MT("hrSpaceDash",
"[hr - - -]");
MT("hrDashLong",
"[hr ---------------------------------------]");
// Inline link with title
MT("linkTitle",
"[link [[foo]]][string (http://example.com/ \"bar\")] hello");
// Inline link without title
MT("linkNoTitle",
"[link [[foo]]][string (http://example.com/)] bar");
// Inline link with image
MT("linkImage",
"[link [[][tag ![[foo]]][string (http://example.com/)][link ]]][string (http://example.com/)] bar");
// Inline link with Em
MT("linkEm",
"[link [[][link&em *foo*][link ]]][string (http://example.com/)] bar");
// Inline link with Strong
MT("linkStrong",
"[link [[][link&strong **foo**][link ]]][string (http://example.com/)] bar");
// Inline link with EmStrong
MT("linkEmStrong",
"[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string (http://example.com/)] bar");
// Image with title
MT("imageTitle",
"[tag ![[foo]]][string (http://example.com/ \"bar\")] hello");
// Image without title
MT("imageNoTitle",
"[tag ![[foo]]][string (http://example.com/)] bar");
// Image with asterisks
MT("imageAsterisks",
"[tag ![[*foo*]]][string (http://example.com/)] bar");
// Not a link. Should be normal text due to square brackets being used
// regularly in text, especially in quoted material, and no space is allowed
// between square brackets and parentheses (per Dingus).
MT("notALink",
"[[foo]] (bar)");
// Reference-style links
MT("linkReference",
"[link [[foo]]][string [[bar]]] hello");
// Reference-style links with Em
MT("linkReferenceEm",
"[link [[][link&em *foo*][link ]]][string [[bar]]] hello");
// Reference-style links with Strong
MT("linkReferenceStrong",
"[link [[][link&strong **foo**][link ]]][string [[bar]]] hello");
// Reference-style links with EmStrong
MT("linkReferenceEmStrong",
"[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string [[bar]]] hello");
// Reference-style links with optional space separator (per docuentation)
// "You can optionally use a space to separate the sets of brackets"
MT("linkReferenceSpace",
"[link [[foo]]] [string [[bar]]] hello");
// Should only allow a single space ("...use *a* space...")
MT("linkReferenceDoubleSpace",
"[[foo]] [[bar]] hello");
// Reference-style links with implicit link name
MT("linkImplicit",
"[link [[foo]]][string [[]]] hello");
// @todo It would be nice if, at some point, the document was actually
// checked to see if the referenced link exists
// Link label, for reference-style links (taken from documentation)
MT("labelNoTitle",
"[link [[foo]]:] [string http://example.com/]");
MT("labelIndented",
" [link [[foo]]:] [string http://example.com/]");
MT("labelSpaceTitle",
"[link [[foo bar]]:] [string http://example.com/ \"hello\"]");
MT("labelDoubleTitle",
"[link [[foo bar]]:] [string http://example.com/ \"hello\"] \"world\"");
MT("labelTitleDoubleQuotes",
"[link [[foo]]:] [string http://example.com/ \"bar\"]");
MT("labelTitleSingleQuotes",
"[link [[foo]]:] [string http://example.com/ 'bar']");
MT("labelTitleParenthese",
"[link [[foo]]:] [string http://example.com/ (bar)]");
MT("labelTitleInvalid",
"[link [[foo]]:] [string http://example.com/] bar");
MT("labelLinkAngleBrackets",
"[link [[foo]]:] [string <http://example.com/> \"bar\"]");
MT("labelTitleNextDoubleQuotes",
"[link [[foo]]:] [string http://example.com/]",
"[string \"bar\"] hello");
MT("labelTitleNextSingleQuotes",
"[link [[foo]]:] [string http://example.com/]",
"[string 'bar'] hello");
MT("labelTitleNextParenthese",
"[link [[foo]]:] [string http://example.com/]",
"[string (bar)] hello");
MT("labelTitleNextMixed",
"[link [[foo]]:] [string http://example.com/]",
"(bar\" hello");
MT("linkWeb",
"[link <http://example.com/>] foo");
MT("linkEmail",
"[link <user@example.com>] foo");
MT("emAsterisk",
"[em *foo*] bar");
MT("emUnderscore",
"[em _foo_] bar");
MT("emInWordAsterisk",
"foo[em *bar*]hello");
MT("emInWordUnderscore",
"foo[em _bar_]hello");
// Per documentation: "...surround an * or _ with spaces, itll be
// treated as a literal asterisk or underscore."
MT("emEscapedBySpaceIn",
"foo [em _bar _ hello_] world");
MT("emEscapedBySpaceOut",
"foo _ bar[em _hello_]world");
// Unclosed emphasis characters
// Instead of simply marking as EM / STRONG, it would be nice to have an
// incomplete flag for EM and STRONG, that is styled slightly different.
MT("emIncompleteAsterisk",
"foo [em *bar]");
MT("emIncompleteUnderscore",
"foo [em _bar]");
MT("strongAsterisk",
"[strong **foo**] bar");
MT("strongUnderscore",
"[strong __foo__] bar");
MT("emStrongAsterisk",
"[em *foo][em&strong **bar*][strong hello**] world");
MT("emStrongUnderscore",
"[em _foo][em&strong __bar_][strong hello__] world");
// "...same character must be used to open and close an emphasis span.""
MT("emStrongMixed",
"[em _foo][em&strong **bar*hello__ world]");
MT("emStrongMixed",
"[em *foo][em&strong __bar_hello** world]");
// These characters should be escaped:
// \ backslash
// ` backtick
// * asterisk
// _ underscore
// {} curly braces
// [] square brackets
// () parentheses
// # hash mark
// + plus sign
// - minus sign (hyphen)
// . dot
// ! exclamation mark
MT("escapeBacktick",
"foo \\`bar\\`");
MT("doubleEscapeBacktick",
"foo \\\\[comment `bar\\\\`]");
MT("escapeAsterisk",
"foo \\*bar\\*");
MT("doubleEscapeAsterisk",
"foo \\\\[em *bar\\\\*]");
MT("escapeUnderscore",
"foo \\_bar\\_");
MT("doubleEscapeUnderscore",
"foo \\\\[em _bar\\\\_]");
MT("escapeHash",
"\\# foo");
MT("doubleEscapeHash",
"\\\\# foo");
// Tests to make sure GFM-specific things aren't getting through
MT("taskList",
"[variable-2 * [ ]] bar]");
MT("fencedCodeBlocks",
"[comment ```]",
"foo",
"[comment ```]");
})();

377
ghost/admin/assets/vendor/countable.js vendored Normal file
View File

@ -0,0 +1,377 @@
/**
* Countable is a script to allow for live paragraph-, word- and character-
* counting on an HTML element.
*
* @author Sacha Schmid (<https://github.com/RadLikeWhoa>)
* @version 2.0.0
* @license MIT
* @see <http://radlikewhoa.github.io/Countable/>
*/
/**
* Note: For the purpose of this internal documentation, arguments of the type
* {Nodes} are to be interpreted as either {NodeList} or {Element}.
*/
;(function (global) {
'use strict'
/**
* @private
*
* `_liveElements` holds all elements that have the live-counting
* functionality bound to them.
*
* `_event` holds the event to handle the live counting, based on the
* browser's capabilities.
*/
var _liveElements = [],
_event = 'oninput' in document ? 'input' : 'keyup'
/**
* `String.trim()` polyfill for non-supporting browsers. This is the
* recommended polyfill on MDN.
*
* @see <http://goo.gl/uYveB>
* @see <http://goo.gl/xjIxJ>
*
* @return {String} The original string with leading and trailing whitespace
* removed.
*/
if (!String.prototype.trim) {
String.prototype.trim = function () {
return this.replace(/^\s+|\s+$/g, '')
}
}
/**
* `ucs2decode` function from the punycode.js library.
*
* Creates an array containing the decimal code points of each Unicode
* character in the string. While JavaScript uses UCS-2 internally, this
* function will convert a pair of surrogate halves (each of which UCS-2
* exposes as separate characters) into a single code point, matching
* UTF-16.
*
* @see <http://goo.gl/8M09r>
* @see <http://goo.gl/u4UUC>
*
* @param {String} string The Unicode input string (UCS-2).
*
* @return {Array} The new array of code points.
*/
function _decode (string) {
var output = [],
counter = 0,
length = string.length,
value, extra
while (counter < length) {
value = string.charCodeAt(counter++)
if ((value & 0xF800) == 0xD800 && counter < length) {
// High surrogate, and there is a next character.
extra = string.charCodeAt(counter++)
if ((extra & 0xFC00) == 0xDC00) {
// Low surrogate.
output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000)
} else {
output.push(value, extra)
}
} else {
output.push(value)
}
}
return output
}
/**
* `_validateArguments` validates the arguments given to each function call.
* Errors are logged to the console as warnings, but Countable fails silently.
*
* @private
*
* @param {Nodes} elements The (collection of) element(s) to
* validate.
*
* @param {Function} callback The callback function to validate.
*
* @return {Boolean} Returns whether all arguments are vaild.
*/
function _validateArguments (elements, callback) {
var elementsValid = elements && ((Object.prototype.toString.call(elements) === '[object NodeList]' && elements.length) || (elements.nodeType === 1)),
callbackValid = callback && typeof callback === 'function'
if ('console' in window && 'warn' in console) {
if (!elementsValid) console.warn('Countable: No valid elements were found')
if (!callbackValid) console.warn('Countable: "' + callback + '" is not a valid callback function')
}
return elementsValid && callbackValid
}
/**
* `_extendDefaults` is a function to extend a set of default options with the
* ones given in the function call. Available options are described below.
*
* {Boolean} hardReturns Use two returns to seperate a paragraph instead of
* one.
* {Boolean} stripTags Strip HTML tags before counting the values.
*
* @private
*
* @param {Object} options Countable allows the options described above.
* They can be used in a function call to override
* the default behaviour.
*
* @return {Object} The new options object.
*/
function _extendDefaults (options) {
var defaults = { hardReturns: false, stripTags: false }
for (var prop in options) {
if (defaults.hasOwnProperty(prop)) defaults[prop] = options[prop]
}
return defaults
}
/**
* `_count` trims an element's value, optionally strips HTML tags and counts
* paragraphs, words, characters and characters plus spaces.
*
* @private
*
* @param {Element} element The element whose value is to be counted.
*
* @param {Object} options The options to use for the counting.
*
* @return {Object} The object containing the number of paragraphs,
* words, characters and characters plus spaces.
*/
function _count (element, options) {
var original = 'value' in element ? element.value : element.innerText || element.textContent,
temp, trimmed
/**
* The initial implementation to allow for HTML tags stripping was created
* @craniumslows while the current one was created by @Rob--W.
*
* @see <http://goo.gl/Exmlr>
* @see <http://goo.gl/gFQQh>
*/
if (options.stripTags) original = original.replace(/<\/?[a-z][^>]*>/gi, '')
trimmed = original.trim()
/**
* Most of the performance improvements are based on the works of @epmatsw.
*
* @see <http://goo.gl/SWOLB>
*/
return {
paragraphs: trimmed ? (trimmed.match(options.hardReturns ? /\n{2,}/g : /\n+/g) || []).length + 1 : 0,
words: trimmed ? (trimmed.replace(/['";:,.?¿\-!¡]+/g, '').match(/\S+/g) || []).length : 0,
characters: trimmed ? _decode(trimmed.replace(/\s/g, '')).length : 0,
all: _decode(original.replace(/[\n\r]/g, '')).length
}
}
/**
* `_loop` is a helper function to iterate over a collection, e.g. a NodeList
* or an Array. The callback receives the current element as the single
* parameter.
*
* @private
*
* @param {Array} which The collection to iterate over.
*
* @param {Function} callback The callback function to call on each
* iteration.
*/
function _loop (which, callback) {
var len = which.length
if (typeof len !== 'undefined') {
while (len--) {
callback(which[len])
}
} else {
callback(which)
}
}
/**
* This is the main object that will later be exposed to other scripts. It
* holds all the public methods that can be used to enable the Countable
* functionality.
*/
var Countable = {
/**
* The `live` method binds the counting handler to all given elements. The
* event is either `oninput` or `onkeydown`, based on the capabilities of
* the browser.
*
* @param {Nodes} elements All elements that should receive the
* Countable functionality.
*
* @param {Function} callback The callback to fire whenever the
* element's value changes. The callback is
* called with the relevant element bound to
* `this` and the counted values as the
* single parameter.
*
* @param {Object} [options] An object to modify Countable's
* behaviour. Refer to `_extendDefaults` for
* a list of available options.
*
* @return {Object} Returns the Countable object to allow for chaining.
*/
live: function (elements, callback, options) {
var ops = _extendDefaults(options),
bind = function (element) {
var handler = function () {
callback.call(element, _count(element, ops))
}
_liveElements.push({ element: element, handler: handler })
handler()
if (element.addEventListener) {
element.addEventListener(_event, handler, false)
} else if (element.attachEvent) {
element.attachEvent('on' + _event, handler)
}
}
if (!_validateArguments(elements, callback)) return
if (elements.length) {
_loop(elements, bind)
} else {
bind(elements)
}
return this
},
/**
* The `die` method removes the Countable functionality from all given
* elements.
*
* @param {Nodes} elements All elements whose Countable functionality
* should be unbound.
*
* @return {Object} Returns the Countable object to allow for chaining.
*/
die: function (elements) {
if (!_validateArguments(elements, function () {})) return
_loop(elements, function (element) {
var liveElement
_loop(_liveElements, function (live) {
if (live.element === element) liveElement = live
})
if (!liveElement) return
if (element.removeEventListener) {
element.removeEventListener(_event, liveElement.handler, false)
} else if (element.detachEvent) {
element.detachEvent('on' + _event, liveElement.handler)
}
_liveElements.splice(_liveElements.indexOf(liveElement), 1)
})
return this
},
/**
* The `once` method works mostly like the `live` method, but no events are
* bound, the functionality is only executed once.
*
* @param {Nodes} elements All elements that should receive the
* Countable functionality.
*
* @param {Function} callback The callback to fire whenever the
* element's value changes. The callback is
* called with the relevant element bound to
* `this` and the counted values as the
* single parameter.
*
* @param {Object} [options] An object to modify Countable's
* behaviour. Refer to `_extendDefaults`
* for a list of available options.
*
* @return {Object} Returns the Countable object to allow for chaining.
*/
once: function (elements, callback, options) {
if (!_validateArguments(elements, callback)) return
_loop(elements, function (element) {
callback.call(element, _count(element, _extendDefaults(options)))
})
return this
},
/**
* The `enabled` method checks if the live-counting functionality is bound
* to an element.
*
* @param {Element} element A single Element.
*
* @return {Boolean} A boolean value representing whether Countable
* functionality is bound to the given element.
*/
enabled: function (element) {
var isEnabled = false
if (element && element.nodeType === 1) {
_loop(_liveElements, function (live) {
if (live.element === element) isEnabled = true
})
}
return isEnabled
}
}
/**
* Expose Countable depending on the module system used across the
* application. (Node / CommonJS, AMD, global)
*/
if (typeof exports === 'object') {
module.exports = Countable
} else if (typeof define === 'function' && define.amd) {
define(function () { return Countable })
} else {
global.Countable = Countable
}
}(this))

View File

@ -0,0 +1,362 @@
/*
Copyright (C) 2011 by Yehuda Katz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// lib/handlebars/browser-prefix.js
var Handlebars = {};
(function(Handlebars, undefined) {
;
// lib/handlebars/base.js
Handlebars.VERSION = "1.0.0";
Handlebars.COMPILER_REVISION = 4;
Handlebars.REVISION_CHANGES = {
1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
2: '== 1.0.0-rc.3',
3: '== 1.0.0-rc.4',
4: '>= 1.0.0'
};
Handlebars.helpers = {};
Handlebars.partials = {};
var toString = Object.prototype.toString,
functionType = '[object Function]',
objectType = '[object Object]';
Handlebars.registerHelper = function(name, fn, inverse) {
if (toString.call(name) === objectType) {
if (inverse || fn) { throw new Handlebars.Exception('Arg not supported with multiple helpers'); }
Handlebars.Utils.extend(this.helpers, name);
} else {
if (inverse) { fn.not = inverse; }
this.helpers[name] = fn;
}
};
Handlebars.registerPartial = function(name, str) {
if (toString.call(name) === objectType) {
Handlebars.Utils.extend(this.partials, name);
} else {
this.partials[name] = str;
}
};
Handlebars.registerHelper('helperMissing', function(arg) {
if(arguments.length === 2) {
return undefined;
} else {
throw new Error("Missing helper: '" + arg + "'");
}
});
Handlebars.registerHelper('blockHelperMissing', function(context, options) {
var inverse = options.inverse || function() {}, fn = options.fn;
var type = toString.call(context);
if(type === functionType) { context = context.call(this); }
if(context === true) {
return fn(this);
} else if(context === false || context == null) {
return inverse(this);
} else if(type === "[object Array]") {
if(context.length > 0) {
return Handlebars.helpers.each(context, options);
} else {
return inverse(this);
}
} else {
return fn(context);
}
});
Handlebars.K = function() {};
Handlebars.createFrame = Object.create || function(object) {
Handlebars.K.prototype = object;
var obj = new Handlebars.K();
Handlebars.K.prototype = null;
return obj;
};
Handlebars.logger = {
DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3,
methodMap: {0: 'debug', 1: 'info', 2: 'warn', 3: 'error'},
// can be overridden in the host environment
log: function(level, obj) {
if (Handlebars.logger.level <= level) {
var method = Handlebars.logger.methodMap[level];
if (typeof console !== 'undefined' && console[method]) {
console[method].call(console, obj);
}
}
}
};
Handlebars.log = function(level, obj) { Handlebars.logger.log(level, obj); };
Handlebars.registerHelper('each', function(context, options) {
var fn = options.fn, inverse = options.inverse;
var i = 0, ret = "", data;
var type = toString.call(context);
if(type === functionType) { context = context.call(this); }
if (options.data) {
data = Handlebars.createFrame(options.data);
}
if(context && typeof context === 'object') {
if(context instanceof Array){
for(var j = context.length; i<j; i++) {
if (data) { data.index = i; }
ret = ret + fn(context[i], { data: data });
}
} else {
for(var key in context) {
if(context.hasOwnProperty(key)) {
if(data) { data.key = key; }
ret = ret + fn(context[key], {data: data});
i++;
}
}
}
}
if(i === 0){
ret = inverse(this);
}
return ret;
});
Handlebars.registerHelper('if', function(conditional, options) {
var type = toString.call(conditional);
if(type === functionType) { conditional = conditional.call(this); }
if(!conditional || Handlebars.Utils.isEmpty(conditional)) {
return options.inverse(this);
} else {
return options.fn(this);
}
});
Handlebars.registerHelper('unless', function(conditional, options) {
return Handlebars.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn});
});
Handlebars.registerHelper('with', function(context, options) {
var type = toString.call(context);
if(type === functionType) { context = context.call(this); }
if (!Handlebars.Utils.isEmpty(context)) return options.fn(context);
});
Handlebars.registerHelper('log', function(context, options) {
var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;
Handlebars.log(level, context);
});
;
// lib/handlebars/utils.js
var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
Handlebars.Exception = function(message) {
var tmp = Error.prototype.constructor.apply(this, arguments);
// Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
for (var idx = 0; idx < errorProps.length; idx++) {
this[errorProps[idx]] = tmp[errorProps[idx]];
}
};
Handlebars.Exception.prototype = new Error();
// Build out our basic SafeString type
Handlebars.SafeString = function(string) {
this.string = string;
};
Handlebars.SafeString.prototype.toString = function() {
return this.string.toString();
};
var escape = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
'"': "&quot;",
"'": "&#x27;",
"`": "&#x60;"
};
var badChars = /[&<>"'`]/g;
var possible = /[&<>"'`]/;
var escapeChar = function(chr) {
return escape[chr] || "&amp;";
};
Handlebars.Utils = {
extend: function(obj, value) {
for(var key in value) {
if(value.hasOwnProperty(key)) {
obj[key] = value[key];
}
}
},
escapeExpression: function(string) {
// don't escape SafeStrings, since they're already safe
if (string instanceof Handlebars.SafeString) {
return string.toString();
} else if (string == null || string === false) {
return "";
}
// Force a string conversion as this will be done by the append regardless and
// the regex test will do this transparently behind the scenes, causing issues if
// an object's to string has escaped characters in it.
string = string.toString();
if(!possible.test(string)) { return string; }
return string.replace(badChars, escapeChar);
},
isEmpty: function(value) {
if (!value && value !== 0) {
return true;
} else if(toString.call(value) === "[object Array]" && value.length === 0) {
return true;
} else {
return false;
}
}
};
;
// lib/handlebars/runtime.js
Handlebars.VM = {
template: function(templateSpec) {
// Just add water
var container = {
escapeExpression: Handlebars.Utils.escapeExpression,
invokePartial: Handlebars.VM.invokePartial,
programs: [],
program: function(i, fn, data) {
var programWrapper = this.programs[i];
if(data) {
programWrapper = Handlebars.VM.program(i, fn, data);
} else if (!programWrapper) {
programWrapper = this.programs[i] = Handlebars.VM.program(i, fn);
}
return programWrapper;
},
merge: function(param, common) {
var ret = param || common;
if (param && common) {
ret = {};
Handlebars.Utils.extend(ret, common);
Handlebars.Utils.extend(ret, param);
}
return ret;
},
programWithDepth: Handlebars.VM.programWithDepth,
noop: Handlebars.VM.noop,
compilerInfo: null
};
return function(context, options) {
options = options || {};
var result = templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data);
var compilerInfo = container.compilerInfo || [],
compilerRevision = compilerInfo[0] || 1,
currentRevision = Handlebars.COMPILER_REVISION;
if (compilerRevision !== currentRevision) {
if (compilerRevision < currentRevision) {
var runtimeVersions = Handlebars.REVISION_CHANGES[currentRevision],
compilerVersions = Handlebars.REVISION_CHANGES[compilerRevision];
throw "Template was precompiled with an older version of Handlebars than the current runtime. "+
"Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+").";
} else {
// Use the embedded version info since the runtime doesn't know about this revision yet
throw "Template was precompiled with a newer version of Handlebars than the current runtime. "+
"Please update your runtime to a newer version ("+compilerInfo[1]+").";
}
}
return result;
};
},
programWithDepth: function(i, fn, data /*, $depth */) {
var args = Array.prototype.slice.call(arguments, 3);
var program = function(context, options) {
options = options || {};
return fn.apply(this, [context, options.data || data].concat(args));
};
program.program = i;
program.depth = args.length;
return program;
},
program: function(i, fn, data) {
var program = function(context, options) {
options = options || {};
return fn(context, options.data || data);
};
program.program = i;
program.depth = 0;
return program;
},
noop: function() { return ""; },
invokePartial: function(partial, name, context, helpers, partials, data) {
var options = { helpers: helpers, partials: partials, data: data };
if(partial === undefined) {
throw new Handlebars.Exception("The partial " + name + " could not be found");
} else if(partial instanceof Function) {
return partial(context, options);
} else if (!Handlebars.compile) {
throw new Handlebars.Exception("The partial " + name + " could not be compiled when running in runtime-only mode");
} else {
partials[name] = Handlebars.compile(partial, {data: data !== undefined});
return partials[name](context, options);
}
}
};
Handlebars.template = Handlebars.VM.template;
;
// lib/handlebars/browser-suffix.js
})(Handlebars);
;

View File

@ -0,0 +1,11 @@
/*!
* iCheck v0.8.5 jQuery plugin, http://git.io/uhUPMA
*/
(function(f,m,z,u,k,r,l,n,D,t,v,s){function A(a,c,j){var d=a[0],b=/ble/.test(j)?r:k;active="update"==j?{checked:d[k],disabled:d[r]}:d[b];if(/^ch|di/.test(j)&&!active)w(a,b);else if(/^un|en/.test(j)&&active)x(a,b);else if("update"==j)for(var b in active)active[b]?w(a,b,!0):x(a,b,!0);else if(!c||"toggle"==j)c||a.trigger("ifClicked"),active?d[l]!==u&&x(a,b):w(a,b)}function w(a,c,j){var d=a[0],b=a.parent(),E=c==r?"enabled":"un"+k,n=e(a,E+g(d[l])),h=e(a,c+g(d[l]));if(!0!==d[c]&&!j&&(d[c]=!0,a.trigger("ifChanged").trigger("if"+
g(c)),c==k&&d[l]==u&&d.name)){j=a.closest("form");var p='input[name="'+d.name+'"]',p=j.length?j.find(p):f(p);p.each(function(){this!==d&&f(this).data(m)&&x(f(this),c)})}d[r]&&e(a,s,!0)&&b.find("."+m+"-helper").css(s,"default");b[t](h||e(a,c));b[v](n||e(a,E)||"")}function x(a,c,j){var d=a[0],b=a.parent(),f=c==r?"enabled":"un"+k,n=e(a,f+g(d[l])),h=e(a,c+g(d[l]));!1!==d[c]&&!j&&(d[c]=!1,a.trigger("ifChanged").trigger("if"+g(f)));!d[r]&&e(a,s,!0)&&b.find("."+m+"-helper").css(s,"pointer");b[v](h||e(a,
c)||"");b[t](n||e(a,f))}function F(a,c){a.data(m)&&(a.parent().html(a.attr("style",a.data(m).s||"").trigger(c||"")),a.off(".i").unwrap(),f('label[for="'+a[0].id+'"]').add(a.closest("label")).off(".i"))}function e(a,c,f){if(a.data(m))return a.data(m).o[c+(f?"":"Class")]}function g(a){return a.charAt(0).toUpperCase()+a.slice(1)}f.fn[m]=function(a,c){var j=navigator.userAgent,d=/ipad|iphone|ipod/i.test(j),b=":"+z+", :"+u,e=f(),g=function(a){a.each(function(){var a=f(this);e=a.is(b)?e.add(a):e.add(a.find(b))})};
if(/^(check|uncheck|toggle|disable|enable|update|destroy)$/.test(a))return g(this),e.each(function(){var d=f(this);"destroy"==a?F(d,"ifDestroyed"):A(d,!0,a);f.isFunction(c)&&c()});if("object"==typeof a||!a){var h=f.extend({checkedClass:k,disabledClass:r,labelHover:!0},a),p=h.handle,s=h.hoverClass||"hover",I=h.focusClass||"focus",G=h.activeClass||"active",H=!!h.labelHover,C=h.labelHoverClass||"hover",y=(""+h.increaseArea).replace("%","")|0;if(p==z||p==u)b=":"+p;-50>y&&(y=-50);g(this);return e.each(function(){var a=
f(this);F(a);var c=this,b=c.id,e=-y+"%",g=100+2*y+"%",g={position:"absolute",top:e,left:e,display:"block",width:g,height:g,margin:0,padding:0,background:"#fff",border:0,opacity:0},e=d||/android|blackberry|windows phone|opera mini/i.test(j)?{position:"absolute",visibility:"hidden"}:y?g:{position:"absolute",opacity:0},p=c[l]==z?h.checkboxClass||"i"+z:h.radioClass||"i"+u,B=f('label[for="'+b+'"]').add(a.closest("label")),q=a.wrap('<div class="'+p+'"/>').trigger("ifCreated").parent().append(h.insert),
g=f('<ins class="'+m+'-helper"/>').css(g).appendTo(q);a.data(m,{o:h,s:a.attr("style")}).css(e);h.inheritClass&&q[t](c.className);h.inheritID&&b&&q.attr("id",m+"-"+b);"static"==q.css("position")&&q.css("position","relative");A(a,!0,"update");if(B.length)B.on(n+".i mouseenter.i mouseleave.i "+D,function(b){var e=b[l],g=f(this);if(!c[r])if(e==n?A(a,!1,!0):H&&(/ve|nd/.test(e)?(q[v](s),g[v](C)):(q[t](s),g[t](C))),d)b.stopPropagation();else return!1});a.on(n+".i focus.i blur.i keyup.i keydown.i keypress.i",
function(b){var d=b[l];b=b.keyCode;if(d==n)return!1;if("keydown"==d&&32==b)return c[l]==u&&c[k]||(c[k]?x(a,k):w(a,k)),!1;if("keyup"==d&&c[l]==u)!c[k]&&w(a,k);else if(/us|ur/.test(d))q["blur"==d?v:t](I)});g.on(n+" mousedown mouseup mouseover mouseout "+D,function(b){var e=b[l],f=/wn|up/.test(e)?G:s;if(!c[r]){if(e==n)A(a,!1,!0);else{if(/wn|er|in/.test(e))q[t](f);else q[v](f+" "+G);if(B.length&&H&&f==s)B[/ut|nd/.test(e)?v:t](C)}if(d)b.stopPropagation();else return!1}})})}return this}})(jQuery,"iCheck",
"checkbox","radio","checked","disabled","type","click","touchbegin.i touchend.i","addClass","removeClass","cursor");

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

6
ghost/admin/assets/vendor/moment.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

223
ghost/admin/assets/vendor/shortcuts.js vendored Normal file
View File

@ -0,0 +1,223 @@
/**
* http://www.openjs.com/scripts/events/keyboard_shortcuts/
* Version : 2.01.B
* By Binny V A
* License : BSD
*/
shortcut = {
'all_shortcuts':{},//All the shortcuts are stored in this array
'add': function(shortcut_combination,callback,opt) {
//Provide a set of default options
var default_options = {
'type':'keydown',
'propagate':false,
'disable_in_input':false,
'target':document,
'keycode':false
}
if(!opt) opt = default_options;
else {
for(var dfo in default_options) {
if(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];
}
}
var ele = opt.target;
if(typeof opt.target == 'string') ele = document.getElementById(opt.target);
var ths = this;
shortcut_combination = shortcut_combination.toLowerCase();
//The function to be called at keypress
var func = function(e) {
e = e || window.event;
if(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields
var element;
if(e.target) element=e.target;
else if(e.srcElement) element=e.srcElement;
if(element.nodeType==3) element=element.parentNode;
if(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;
}
//Find Which key is pressed
if (e.keyCode) code = e.keyCode;
else if (e.which) code = e.which;
var character = String.fromCharCode(code).toLowerCase();
if(code == 188) character=","; //If the user presses , when the type is onkeydown
if(code == 190) character="."; //If the user presses , when the type is onkeydown
var keys = shortcut_combination.split("+");
//Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
var kp = 0;
//Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
var shift_nums = {
"`":"~",
"1":"!",
"2":"@",
"3":"#",
"4":"$",
"5":"%",
"6":"^",
"7":"&",
"8":"*",
"9":"(",
"0":")",
"-":"_",
"=":"+",
";":":",
"'":"\"",
",":"<",
".":">",
"/":"?",
"\\":"|"
}
//Special Keys - and their codes
var special_keys = {
'esc':27,
'escape':27,
'tab':9,
'space':32,
'return':13,
'enter':13,
'backspace':8,
'scrolllock':145,
'scroll_lock':145,
'scroll':145,
'capslock':20,
'caps_lock':20,
'caps':20,
'numlock':144,
'num_lock':144,
'num':144,
'pause':19,
'break':19,
'insert':45,
'home':36,
'delete':46,
'end':35,
'pageup':33,
'page_up':33,
'pu':33,
'pagedown':34,
'page_down':34,
'pd':34,
'left':37,
'up':38,
'right':39,
'down':40,
'f1':112,
'f2':113,
'f3':114,
'f4':115,
'f5':116,
'f6':117,
'f7':118,
'f8':119,
'f9':120,
'f10':121,
'f11':122,
'f12':123
}
var modifiers = {
shift: { wanted:false, pressed:false},
ctrl : { wanted:false, pressed:false},
alt : { wanted:false, pressed:false},
meta : { wanted:false, pressed:false} //Meta is Mac specific
};
if(e.ctrlKey) modifiers.ctrl.pressed = true;
if(e.shiftKey) modifiers.shift.pressed = true;
if(e.altKey) modifiers.alt.pressed = true;
if(e.metaKey) modifiers.meta.pressed = true;
for(var i=0; k=keys[i],i<keys.length; i++) {
//Modifiers
if(k == 'ctrl' || k == 'control') {
kp++;
modifiers.ctrl.wanted = true;
} else if(k == 'shift') {
kp++;
modifiers.shift.wanted = true;
} else if(k == 'alt') {
kp++;
modifiers.alt.wanted = true;
} else if(k == 'meta') {
kp++;
modifiers.meta.wanted = true;
} else if(k.length > 1) { //If it is a special key
if(special_keys[k] == code) kp++;
} else if(opt['keycode']) {
if(opt['keycode'] == code) kp++;
} else { //The special keys did not match
if(character == k) kp++;
else {
if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase
character = shift_nums[character];
if(character == k) kp++;
}
}
}
}
if(kp == keys.length &&
modifiers.ctrl.pressed == modifiers.ctrl.wanted &&
modifiers.shift.pressed == modifiers.shift.wanted &&
modifiers.alt.pressed == modifiers.alt.wanted &&
modifiers.meta.pressed == modifiers.meta.wanted) {
callback(e);
if(!opt['propagate']) { //Stop the event
//e.cancelBubble is supported by IE - this will kill the bubbling process.
e.cancelBubble = true;
e.returnValue = false;
//e.stopPropagation works in Firefox.
if (e.stopPropagation) {
e.stopPropagation();
e.preventDefault();
}
return false;
}
}
}
this.all_shortcuts[shortcut_combination] = {
'callback':func,
'target':ele,
'event': opt['type']
};
//Attach the function with the event
if(ele.addEventListener) ele.addEventListener(opt['type'], func, false);
else if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);
else ele['on'+opt['type']] = func;
},
//Remove the shortcut - just specify the shortcut and I will remove the binding
'remove':function(shortcut_combination) {
shortcut_combination = shortcut_combination.toLowerCase();
var binding = this.all_shortcuts[shortcut_combination];
delete(this.all_shortcuts[shortcut_combination])
if(!binding) return;
var type = binding['event'];
var ele = binding['target'];
var callback = binding['callback'];
if(ele.detachEvent) ele.detachEvent('on'+type, callback);
else if(ele.removeEventListener) ele.removeEventListener(type, callback, false);
else ele['on'+type] = false;
}
}

View File

@ -0,0 +1,29 @@
(function () {
var ghostdown = function (converter) {
return [
// [image] syntax
{
type: 'lang',
filter: function (source) {
return source.replace(/\n?!image\[([\d\w\s]*)\]/gi, function (match, alt, a) {
return '<section class="js-drop-zone image-uploader">' +
'<span class="media"><span class="hidden">Image Upload</span></span>' +
'<div class="description">Add image of <strong>' + alt + '</strong></div>' +
'<input data-url="upload" class="js-fileupload fileupload" type="file" name="uploadimage">' +
'<a class="image-url" title="Add image from URL"><span class="hidden">URL</span></a>' +
'<a class="image-webcam" title="Add image from webcam">' +
'<span class="hidden">Webcam</span></a>' +
'</section>';
});
}
}
];
};
// Client-side export
if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) {
window.Showdown.extensions.ghostdown = ghostdown;
}
// Server-side export
if (typeof module !== 'undefined') module.exports = ghostdown;
}());

File diff suppressed because one or more lines are too long

1227
ghost/admin/assets/vendor/underscore.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
/*globals Handlebars, moment
*/
(function () {
"use strict";
Handlebars.registerHelper('dateFormat', function (context, block) {
var f = block.hash.format || "MMM Do, YYYY",
timeago = block.hash.timeago,
date;
if (timeago) {
date = moment(context).fromNow();
} else {
date = moment(context).format(f);
}
return date;
});
}());

34
ghost/admin/init.js Normal file
View File

@ -0,0 +1,34 @@
/*globals window, $, _, Backbone */
(function () {
"use strict";
var Ghost = {
Layout : {},
Views : {},
Collections : {},
Models : {},
settings: {
apiRoot: '/api/v0.1'
},
// This is a helper object to denote legacy things in the
// middle of being transitioned.
temporary: {},
currentView: null,
router: null
};
Ghost.init = function () {
Ghost.router = new Ghost.Router();
Backbone.history.start({
pushState: true,
hashChange: false,
root: '/ghost'
});
};
window.Ghost = Ghost;
}());

View File

@ -0,0 +1,51 @@
// # Surrounds given text with Markdown syntax
/*global $, CodeMirror */
(function () {
"use strict";
var Markdown = {
init : function (options, elem) {
var self = this;
self.elem = elem;
self.style = (typeof options === 'string') ? options : options.style;
self.options = $.extend({}, CodeMirror.prototype.addMarkdown.options, options);
self.replace();
},
replace: function () {
var text = this.elem.getSelection(), md;
if (this.options.syntax[this.style]) {
md = this.options.syntax[this.style].replace('$1', text);
this.elem.replaceSelection(md);
}
}
};
CodeMirror.prototype.addMarkdown = function (options) {
var markdown = Object.create(Markdown);
markdown.init(options, this);
};
CodeMirror.prototype.addMarkdown.options = {
style: null,
syntax: {
bold: "**$1**",
italic: "_$1_",
strike: "~~$1~~",
code: "`$1`",
h1: "\n# $1\n",
h2: "\n## $1\n",
h3: "\n### $1\n",
h4: "\n#### $1\n",
h5: "\n##### $1\n",
h6: "\n###### $1\n",
link: "[$1](http://)",
image: "!image[$1](http://)",
blockquote: "> $1",
currentDate: new Date().toLocaleString()
}
};
}());

View File

@ -0,0 +1,49 @@
/*global window, document, Ghost, $, _, Backbone */
(function () {
"use strict";
Ghost.Models.Post = Backbone.Model.extend({
defaults: {
status: 'draft'
},
blacklist: ['published', 'draft'],
parse: function (resp) {
if (resp.status) {
resp.published = !!(resp.status === "published");
resp.draft = !!(resp.status === "draft");
}
if (resp.tags) {
// TODO: parse tags into it's own collection on the model (this.tags)
return resp;
}
return resp;
},
validate: function (attrs) {
if (_.isEmpty(attrs.title)) {
return 'You must specify a title for the post.';
}
}
});
Ghost.Collections.Posts = Backbone.Collection.extend({
url: Ghost.settings.apiRoot + '/posts',
model: Ghost.Models.Post,
parse: function (resp) {
if (_.isArray(resp.posts)) {
this.limit = resp.limit;
this.currentPage = resp.page;
this.totalPages = resp.pages;
this.totalPosts = resp.total;
this.nextPage = resp.next;
this.prevPage = resp.prev;
return resp.posts;
}
return resp;
}
});
}());

View File

@ -0,0 +1,16 @@
/*global window, document, Ghost, $, _, Backbone */
(function () {
"use strict";
// Set the url manually and id to '0' to force PUT requests
Ghost.Models.Settings = Backbone.Model.extend({
url: '/api/v0.1/settings/',
id: "0",
defaults: {
title: 'My Blog',
description: '',
email: 'admin@tryghost.org'
}
});
}());

View File

@ -0,0 +1,43 @@
/*global window, document, Ghost, $, _, Backbone */
(function () {
"use strict";
Ghost.Models.Widget = Backbone.Model.extend({
defaults: {
title: "",
name: "",
author: "",
applicationID: "",
size: "",
content: {
template: '',
data: {
number: {
count: 0,
sub: {
value: 0,
dir: "", // "up" or "down"
item: "",
period: ""
}
}
}
},
settings: {
settingsPane: false,
enabled: false,
options: [{
title: "ERROR",
value: "Widget options not set"
}]
}
}
});
Ghost.Collections.Widgets = Backbone.Collection.extend({
// url: Ghost.settings.apiRoot + '/widgets', // What will this be?
model: Ghost.Models.Widget
});
}());

459
ghost/admin/router.js Normal file
View File

@ -0,0 +1,459 @@
/*global window, document, Ghost, Backbone, $, _ */
(function () {
"use strict";
Ghost.Router = Backbone.Router.extend({
routes: {
'' : 'dashboard',
'content/' : 'blog',
'settings/' : 'settings',
'settings(/:pane)' : 'settings',
'editor/' : 'editor',
'editor(/:id)' : 'editor',
'debug/' : 'debug'
},
blog: function () {
var posts = new Ghost.Collections.Posts();
posts.fetch({ data: { status: 'all', orderBy: ['updated_at', 'DESC'] } }).then(function () {
Ghost.currentView = new Ghost.Views.Blog({ el: '#main', collection: posts });
});
},
settings: function (pane) {
var settings = new Ghost.Models.Settings();
settings.fetch().then(function () {
Ghost.currentView = new Ghost.Views.Settings({ el: '#main', model: settings, pane: pane });
});
},
editor: function (id) {
var post = new Ghost.Models.Post();
post.urlRoot = Ghost.settings.apiRoot + '/posts';
if (id) {
post.id = id;
post.fetch().then(function () {
Ghost.currentView = new Ghost.Views.Editor({ el: '#main', model: post });
});
} else {
Ghost.currentView = new Ghost.Views.Editor({ el: '#main', model: post });
}
},
debug: function () {
Ghost.currentView = new Ghost.Views.Debug({ el: "#main" });
},
dashboard: function () {
var widgets = new Ghost.Collections.Widgets();
widgets.add({
title: "LINZ, AUSTRIA",
name: "time",
author: "Matthew Harrison-Jones",
applicationID: "com.ghost.time",
content: {
template: 'custom/time',
data: {
day: "Today",
weather: "12",
time: "12:42PM",
date: "Monday / March 5 / 2013"
}
},
settings: {
settingsPane: true,
options: [{
title: "Timezone",
value: "GMT"
}]
}
});
widgets.add({
title: "Ghost",
name: "image",
author: "Matthew Harrison-Jones",
applicationID: "com.ghost.image",
size: "2x1",
content: {
template: 'default/blank'
},
settings: {
settingsPane: true
}
});
widgets.add({
title: "Upcoming Posts",
name: "posts",
author: "Matthew Harrison-Jones",
applicationID: "com.ghost.posts",
content: {
template: 'custom/upcoming-posts',
data: {
ready: 9,
pending: 4,
draft: 1
}
},
settings: {
settingsPane: true
}
});
widgets.add({
title: "Unique Visitors (7 days)",
name: "stats",
author: "Matthew Harrison-Jones",
applicationID: "com.ghost.stats",
size: "2x2",
content: {
template: 'default/number',
data: {
number: {
count: "293,051",
sub: {
value: "+14%",
dir: "up",
item: "",
period: "in the last 7 days"
}
}
}
},
settings: {
settingsPane: true
}
});
widgets.add({
title: "Facebook Likes",
name: "facebook",
author: "Matthew Harrison-Jones",
applicationID: "com.ghost.facebook",
content: {
template: 'default/number',
data: {
number: {
count: "12,329",
sub: {
value: "-3",
dir: "down",
item: "likes",
period: "today"
}
}
}
},
settings: {
settingsPane: true
}
});
widgets.add({
title: "Google Plus",
name: "gplus",
author: "Matthew Harrison-Jones",
applicationID: "com.ghost.gplus",
content: {
template: 'default/number',
data: {
number: {
count: "4,103",
sub: {
item: "have you in circles"
}
}
}
},
settings: {
settingsPane: true
}
});
widgets.add({
title: "Twitter",
name: "twitter",
author: "Matthew Harrison-Jones",
applicationID: "com.ghost.twitter",
content: {
template: 'default/blank'
},
settings: {
settingsPane: true,
enabled: true,
options: [
{
title: "Account",
value: "@JohnONolan"
},
{
title: "Display",
value: "Last Tweets"
},
{
title: "Quantity",
value: 6
}
]
}
});
widgets.add({
title: "Campaign Monitor",
name: "campaignmonitor",
author: "Matthew Harrison-Jones",
applicationID: "com.ghost.campaignmonitor",
content: {
template: 'default/number',
data: {
number: {
count: "5,693",
sub: {
value: "+63",
dir: "up",
item: "subscribers",
period: "this week"
}
}
}
},
settings: {
settingsPane: true
}
});
widgets.add({
title: "Most Popular Posts",
name: "popular",
author: "Matthew Harrison-Jones",
applicationID: "com.ghost.popular",
size: "1x2",
content: {
template: 'custom/popular-posts',
data: {
posts: [
{
title: "The Night of The Headless Horseman Part II",
time: "Yesterday",
count: "3,128"
},
{
title: "Latin Script & Why it's Particularly Boring to Read",
time: "Wednesday",
count: "1,345"
},
{
title: "59 Signs Your Cat and/or Dog Might be Planning To Kill You",
time: "Tuesday",
count: "824"
},
{
title: "A Love Letter to Emma Stone",
time: "Today",
count: "293"
},
{
title: "Lorem Ipsum Dolor Sit Amet & Other Funny Moments",
time: "Yesterday",
count: "124"
},
{
title: "Matt Does Git",
time: "Thursday",
count: "100"
}
]
}
}
});
widgets.add({
title: "Posts This Week (Out Of 20)",
name: "postsWeek",
author: "Matthew Harrison-Jones",
applicationID: "com.ghost.postsWeek",
content: {
template: 'default/blank'
}
});
widgets.add({
title: "Your RSS News Feed",
name: "rss",
author: "Matthew Harrison-Jones",
applicationID: "com.ghost.rss",
size: "2x2",
content: {
template: 'default/blank'
},
settings: {
settingsPane: true
}
});
widgets.add({
title: "Instagram",
name: "instagram",
author: "Matthew Harrison-Jones",
applicationID: "com.ghost.instagram",
content: {
template: 'custom/instagram',
data: {
image: "http://f.cl.ly/items/303f3y1n3I2L1F10343E/instagram.jpg"
}
},
settings: {
settingsPane: true,
options: [{
title: "Account",
value: "@JohnONolan"
}]
}
});
widgets.add({
title: "Klout",
name: "klout",
author: "Matthew Harrison-Jones",
applicationID: "com.ghost.klout",
content: {
template: 'default/number',
data: {
number: {
count: "64.23",
sub: {
value: "-0.42",
dir: "down",
item: "",
period: "in the last 30 days"
}
}
}
},
settings: {
settingsPane: true
}
});
widgets.add({
title: "Bounce Rate",
name: "bounce",
author: "Matthew Harrison-Jones",
applicationID: "com.ghost.bounce",
content: {
template: 'default/number',
data: {
number: {
count: "40.21%",
sub: {
value: "-2.53%",
dir: "up",
item: "",
period: "in the last month"
}
}
}
},
settings: {
settingsPane: true
}
});
widgets.add({
title: "Average Time On Site",
name: "avgTime",
author: "Matthew Harrison-Jones",
applicationID: "com.ghost.avgTime",
content: {
template: 'default/number',
data: {
number: {
count: "2m 16s",
sub: {
value: "+31.4%",
dir: "up",
item: "",
period: "in the last month"
}
}
}
},
settings: {
settingsPane: true
}
});
widgets.add({
title: "Last.fm",
name: "lastfm",
author: "Matthew Harrison-Jones",
applicationID: "com.ghost.lastfm",
content: {
template: 'custom/lastfm',
data: {
cover: "http://f.cl.ly/items/0p0r3T3v3M0R0H1k1p0S/imagine_dragons.png",
artist: "Imagine Dragons",
title: "On Top of The World"
}
},
settings: {
settingsPane: true
}
});
widgets.add({
title: "Post Ideas",
name: "ideas",
author: "Matthew Harrison-Jones",
applicationID: "com.ghost.ideas",
size: "2x1",
content: {
template: 'custom/post-ideas'
},
settings: {
settingsPane: true
}
});
widgets.add({
title: "Twitter",
name: "tweets",
author: "Matthew Harrison-Jones",
applicationID: "com.ghost.tweets",
content: {
template: 'custom/tweets',
data: {
avatar: "http://f.cl.ly/items/1A1S0D3T3p1g1B2Z3J0u/ghost_twitter.jpeg",
name: "Ghost",
handle: "@TryGhost",
tweet: "If you're exploring the <a href='#'>@twitterapi</a>, be sure and bring the new field guide along. <a href='#'>dev.twitter.com/blog/...</a>",
time: "3 May 12"
}
},
settings: {
settingsPane: true
}
});
widgets.add({
title: "Backups",
name: "backups",
author: "Matthew Harrison-Jones",
applicationID: "com.ghost.backups",
content: {
template: 'default/blank'
},
settings: {
settingsPane: true
}
});
//widgets.fetch().then(function () {
Ghost.currentView = new Ghost.Views.Dashboard({ el: '#main', collection: widgets });
//});
}
});
}());

188
ghost/admin/tagui.js Normal file
View File

@ -0,0 +1,188 @@
// ## Tag Selector UI
/*global window, document, $ */
(function () {
"use strict";
var suggestions,
categoryOffset,
existingTags = [], // This will be replaced by an API return.
keys = {
UP: 38,
DOWN: 40,
ESC: 27,
ENTER: 13,
COMMA: 188,
BACKSPACE: 8
};
function findTerms(searchTerm, array) {
searchTerm = searchTerm.toUpperCase();
return $.map(array, function (item) {
var match = item.toUpperCase().indexOf(searchTerm) !== -1;
return match ? item : null;
});
}
function showSuggestions($target, searchTerm) {
suggestions.show();
var results = findTerms(searchTerm, existingTags),
pos = $target.position(),
styles = {
left: pos.left
},
maxSuggestions = 5, // Limit the suggestions number
results_length = results.length,
i,
suggest;
suggestions.css(styles);
suggestions.html("");
if (results_length < maxSuggestions) {
maxSuggestions = results_length;
}
for (i = 0; i < maxSuggestions; i += 1) {
suggestions.append("<li><a href='#'>" + results[i] + "</a></li>");
}
suggest = $('ul.suggestions li a:contains("' + searchTerm + '")');
suggest.each(function () {
var src_str = $(this).html(),
term = searchTerm,
pattern;
term = term.replace(/(\s+)/, "(<[^>]+>)*$1(<[^>]+>)*");
pattern = new RegExp("(" + term + ")", "i");
src_str = src_str.replace(pattern, "<mark>$1</mark>");
/*jslint regexp: true */ // - would like to remove this
src_str = src_str.replace(/(<mark>[^<>]*)((<[^>]+>)+)([^<>]*<\/mark>)/, "$1</mark>$2<mark>$4");
$(this).html(src_str);
});
}
function handleTagKeyup(e) {
var $target = $(e.currentTarget),
searchTerm = $.trim($target.val()).toLowerCase(),
category,
populator;
if (e.keyCode === keys.UP) {
e.preventDefault();
if (suggestions.is(":visible")) {
if (suggestions.children(".selected").length === 0) {
suggestions.find("li:last-child").addClass('selected');
} else {
suggestions.children(".selected").removeClass('selected').prev().addClass('selected');
}
}
} else if (e.keyCode === keys.DOWN) {
e.preventDefault();
if (suggestions.is(":visible")) {
if (suggestions.children(".selected").length === 0) {
suggestions.find("li:first-child").addClass('selected');
} else {
suggestions.children(".selected").removeClass('selected').next().addClass('selected');
}
}
} else if (e.keyCode === keys.ESC) {
suggestions.hide();
} else if ((e.keyCode === keys.ENTER || e.keyCode === keys.COMMA) && searchTerm) {
// Submit tag using enter or comma key
e.preventDefault();
if (suggestions.is(":visible") && suggestions.children(".selected").length !== 0) {
if ($('.category:containsExact("' + suggestions.children(".selected").text() + '")').length === 0) {
category = $('<span class="category">' + suggestions.children(".selected").text() + '</span>');
if ($target.data('populate')) {
populator = $($target.data('populate'));
populator.append(category);
}
}
suggestions.hide();
} else {
if (e.keyCode === keys.COMMA) {
searchTerm = searchTerm.replace(",", "");
} // Remove comma from string if comma is uses to submit.
if ($('.category:containsExact("' + searchTerm + '")').length === 0) {
category = $('<span class="category">' + searchTerm + '</span>');
if ($target.data('populate')) {
populator = $($target.data('populate'));
populator.append(category);
}
}
}
$target.val('').focus();
searchTerm = ""; // Used to reset search term
suggestions.hide();
}
if (e.keyCode === keys.UP || e.keyCode === keys.DOWN) {
return false;
}
if (searchTerm) {
showSuggestions($target, searchTerm);
} else {
suggestions.hide();
}
}
function handleTagKeyDown(e) {
var $target = $(e.currentTarget),
populator,
lastBlock;
// Delete character tiggers on Keydown, so needed to check on that event rather than Keyup.
if (e.keyCode === keys.BACKSPACE && !$target.val()) {
populator = $($target.data('populate'));
lastBlock = populator.find('.category').last();
lastBlock.remove();
}
}
function handleSuggestionClick(e) {
var $target = $(e.currentTarget),
category = $('<span class="category">' + $(e.currentTarget).text() + '</span>'),
populator;
if ($target.parent().data('populate')) {
populator = $($target.parent().data('populate'));
populator.append(category);
suggestions.hide();
$('[data-input-behaviour="tag"]').val('').focus();
}
}
function handleCategoryClick(e) {
$(e.currentTarget).remove();
}
function handleClickOff(e) {
if (window.matchMedia('max-width: 650px')) {
e.preventDefault();
$('body').toggleClass('off-canvas');
}
}
$(document).ready(function () {
suggestions = $("ul.suggestions").hide(); // Initnialise suggestions overlay
if ($('.category-input').length) {
categoryOffset = $('.category-input').offset().left;
$('.category-blocks').css({'left': categoryOffset + 'px'});
}
$('[data-input-behaviour="tag"]')
.on('keyup', handleTagKeyup)
.on('keydown', handleTagKeyDown);
$('ul.suggestions').on('click', "li", handleSuggestionClick);
$('.categories').on('click', ".category", handleCategoryClick);
$('[data-off-canvas]').on('click', handleClickOff);
});
}());

39
ghost/admin/toggle.js Normal file
View File

@ -0,0 +1,39 @@
// # Toggle Support
/*global document, $, Ghost */
(function () {
"use strict";
Ghost.temporary.initToggles = function ($el) {
$el.find('[data-toggle]').each(function () {
var toggle = $(this).data('toggle');
$(this).parent().children(toggle).hide();
});
$el.find('[data-toggle]').on('click', function (e) {
e.preventDefault();
e.stopPropagation();
$(this).toggleClass('active');
var toggle = $(this).data('toggle');
$(this).parent().children(toggle).fadeToggle(200).toggleClass('open');
});
};
$(document).ready(function () {
// ## Toggle Up In Your Grill
// Allows for toggling via data-attributes.
// ### Usage
// <nav>
// <a href="#" data-toggle=".toggle-me">Toggle</a>
// <ul class="toggle-me">
// <li>Toggled yo</li>
// </ul>
// </nav>
Ghost.temporary.initToggles($(document));
});
}());

View File

@ -0,0 +1,13 @@
<a class="permalink{{#if featured}} featured{{/if}}" href="#">
<h3 class="entry-title">{{title}}</h3>
<section class="entry-meta">
<time datetime="2013-01-04" class="date">
{{#if published}}
Published {{dateFormat published_at timeago="True"}}
{{else}}
<span class="status-draft">Draft</span>
{{/if}}
</time>
{{!<span class="views">1,934</span>}}
</section>
</a>

View File

@ -0,0 +1,19 @@
<header class="floatingheader">
<a class="{{#if featured}}featured{{else}}unfeatured{{/if}}" href="#">
<span class="hidden">Star</span>
</a>
{{! TODO: JavaScript toggle featured/unfeatured}}
<span class="status">{{#if published}}Published{{else}}Written{{/if}}</span>
<span class="normal">by</span>
<span class="author">Joe Bloggs</span>
<section class="post-controls">
<a class="post-edit" href="#"><span class="hidden">Edit Post</span></a>
<a class="post-settings" href="#" data-toggle=".menu-drop-right"><span class="hidden">Post Settings</span></a>
<ul class="menu-drop-right overlay">
<li><a href="#" class="delete">Delete</a></li>
</ul>
</section>
</header>
<section class="content-preview-content">
<div class="wrapper">{{{content}}}</div>
</section>

View File

@ -0,0 +1,44 @@
{{#if settings.enabled}}
<header class="widget-header">
<span class="widget-title">{{Title}} Settings</span>
<div class="widget-settings-toggle close js-view-widget"></div>
</header>
<section class="widget-content">
{{#each settings.options}}
<label>
<span class="title">{{this.title}}</span> <input type="text" value="{{this.value}}"/>
</label>
{{/each}}
</section>
<footer class="widget-footer">
<div class="widget-size-options">
<div class="size-options-container js-widget-resizer" data-size="1x1">
<span class="mini-widget size-1x1 active"></span>
<span class="mini-widget size-1x1"></span>
<span class="mini-widget size-1x1"></span>
<span class="mini-widget size-1x1"></span>
</div>
<div class="size-options-container js-widget-resizer" data-size="2x1">
<span class="mini-widget size-2x1 active"></span>
<span class="mini-widget size-1x1"></span>
<span class="mini-widget size-1x1"></span>
</div>
<div class="size-options-container js-widget-resizer" data-size="1x2">
<span class="mini-widget size-1x2 active"></span>
<span class="mini-widget size-1x1"></span>
<span class="mini-widget size-1x1"></span>
</div>
<div class="size-options-container js-widget-resizer" data-size="2x2">
<span class="mini-widget size-2x2 active"></span>
</div>
</div>
<div class="widget-settings-toggle done js-submit-changes"></div>
</footer>
{{else}}
<section class="widget-content">
</section>
<footer class="widget-footer">
<span class="widget-title">{{title}}</span>
{{#if settings.settingsPane}}<div class="widget-settings-toggle js-view-settings"></div>{{/if}}
</footer>
{{/if}}

View File

@ -0,0 +1 @@
<img class="photo" src="{{content.data.image}}" />

View File

@ -0,0 +1,5 @@
<img class="cover" src="{{content.data.cover}}" />
<section class="banner">
<span class="song-artist">{{content.data.artist}}</span>
<span class="song-title">{{oontent.data.title}}</span>
</section>

View File

@ -0,0 +1,15 @@
<ul class="nav clearfix">
<li class="tab active"><a href="#">This Week</a></li>
<li class="tab"><a href="#">Month</a></li>
<li class="tab"><a href="#">Year</a></li>
<li class="tab"><a href="#">Ever</a></li>
</ul>
<ul class="post-list nav">
{{#each content.data.posts}}
<li class="post-item">
<h1 class="post-title">{{this.title}}</h1>
<span class="post-date"> {{this.time}}</span>
<span class="post-count"> {{this.count}}</span>
</li>
{{/each}}
</ul>

View File

@ -0,0 +1,2 @@
<input type="text" class="idea-title" placeholder="Enter the title of your post idea...." />
<textarea class="idea-content" placeholder="This is a brief synopsis of the idea here with your key points. Paste in any relevant links to your reference material. Markdown is fully supported. Hit enter when your done."></textarea>

View File

@ -0,0 +1,8 @@
<header class="summary clearfix">
<span class="day">{{content.data.day}}</span>
<span class="weather">{{content.data.weather}}°</span>
</header>
<time>
<span class="clock">{{content.data.time}}</span>
<span class="date">{{content.data.date}}</span>
</time>

View File

@ -0,0 +1,18 @@
<header>
<div class="twitter-display-image">
<img src="{{content.data.avatar}}" />
</div>
<span class="twitter-name">{{content.data.name}}</span>
<span class="twitter-handle">{{contnet.data.handle}}</span>
</header>
<article class="latest-tweet">
{{{content.data.tweet}}}
</article>
<footer>
<time class="tweet-time">{{content.data.time}}</time>
<div class="twitter-functions">
<a href="#"><i class="reply"></i></a>
<a href="#"><i class="retweet"></i></a>
<a href="#"><i class="favourite"></i></a>
</div>
</footer>

View File

@ -0,0 +1,9 @@
<div class="chart">
<canvas id="poststats" width="250" height="250"></canvas>
<div class="sheen"></div>
<ul class="data">
<li><span class="ready">{{content.data.ready}}</span> Ready</li>
<li><span class="pending">{{content.data.pending}}</span> Pending</li>
<li><span class="draft">{{content.data.draft}}</span> Draft</li>
</ul>
</div>

View File

@ -0,0 +1,4 @@
<div class="info">
<span class="count">{{content.data.number.count}}</span>
<span class="sub"><mark class="{{content.data.number.sub.dir}}">{{content.data.number.sub.value}}</mark> {{content.data.number.sub.item}} {{content.data.number.sub.period}}</span>
</div>

75
ghost/admin/views/base.js Normal file
View File

@ -0,0 +1,75 @@
/*global window, document, Ghost, $, _, Backbone, JST */
(function () {
"use strict";
Ghost.View = Backbone.View.extend({
// Adds a subview to the current view, which will
// ensure its removal when this view is removed,
// or when view.removeSubviews is called
addSubview: function (view) {
if (!(view instanceof Backbone.View)) {
throw new Error("Subview must be a Backbone.View");
}
this.subviews = this.subviews || [];
this.subviews.push(view);
return view;
},
// Removes any subviews associated with this view
// by `addSubview`, which will in-turn remove any
// children of those views, and so on.
removeSubviews: function () {
var i, l, children = this.subviews;
if (!children) {
return this;
}
for (i = 0, l = children.length; i < l; i += 1) {
children[i].remove();
}
this.subviews = [];
return this;
},
// Extends the view's remove, by calling `removeSubviews`
// if any subviews exist.
remove: function () {
if (this.subviews) {
this.removeSubviews();
}
return Backbone.View.prototype.remove.apply(this, arguments);
}
});
Ghost.TemplateView = Ghost.View.extend({
templateName: "widget",
template: function (data) {
return JST[this.templateName](data);
},
templateData: function () {
if (this.model) {
return this.model.toJSON();
}
if (this.collection) {
return this.collection.toJSON();
}
return {};
},
render: function () {
this.$el.html(this.template(this.templateData()));
if (_.isFunction(this.afterRender)) {
this.afterRender();
}
return this;
}
});
}());

184
ghost/admin/views/blog.js Normal file
View File

@ -0,0 +1,184 @@
/*global window, document, Ghost, $, _, Backbone, JST */
(function () {
"use strict";
var ContentList,
ContentItem,
PreviewContainer,
// Add shadow during scrolling
scrollShadow = function (target, e) {
if ($(e.currentTarget).scrollTop() > 10) {
$(target).addClass('scrolling');
} else {
$(target).removeClass('scrolling');
}
};
// Base view
// ----------
Ghost.Views.Blog = Ghost.View.extend({
initialize: function (options) {
this.addSubview(new PreviewContainer({ el: '.js-content-preview', collection: this.collection })).render();
this.addSubview(new ContentList({ el: '.js-content-list', collection: this.collection })).render();
}
});
// Content list (sidebar)
// -----------------------
ContentList = Ghost.View.extend({
events: {
'click .content-list-content' : 'scrollHandler'
},
initialize: function (options) {
this.$('.content-list-content').on('scroll', _.bind(scrollShadow, null, '.content-list'));
this.listenTo(this.collection, 'remove', this.showNext);
},
showNext: function () {
var id = this.collection.at(0).id;
if (id) {
Backbone.trigger('blog:activeItem', id);
}
},
render: function () {
this.collection.each(function (model) {
this.$('ol').append(this.addSubview(new ContentItem({model: model})).render().el);
}, this);
this.showNext();
}
});
// Content Item
// -----------------------
ContentItem = Ghost.View.extend({
tagName: 'li',
events: {
'click a': 'setActiveItem'
},
active: false,
initialize: function () {
this.listenTo(Backbone, 'blog:activeItem', this.checkActive);
this.listenTo(this.model, 'destroy', this.removeItem);
},
removeItem: function () {
var view = this;
$.when(this.$el.slideUp()).then(function () {
view.remove();
});
},
// If the current item isn't active, we trigger the event to
// notify a change in which item we're viewing.
setActiveItem: function (e) {
e.preventDefault();
if (this.active !== true) {
Backbone.trigger('blog:activeItem', this.model.id);
this.render();
}
},
// Checks whether this item is active and doesn't match the current id.
checkActive: function (id) {
if (this.model.id !== id) {
if (this.active) {
this.active = false;
this.$el.removeClass('active');
this.render();
}
} else {
this.active = true;
this.$el.addClass('active');
}
},
showPreview: function (e) {
var item = $(e.currentTarget);
this.$('.content-list-content li').removeClass('active');
item.addClass('active');
Backbone.trigger('blog:activeItem', item.data('id'));
},
templateName: "list-item",
template: function (data) {
return JST[this.templateName](data);
},
render: function () {
this.$el.html(this.template(_.extend({active: this.active}, this.model.toJSON())));
return this;
}
});
// Content preview
// ----------------
PreviewContainer = Ghost.View.extend({
activeId: null,
events: {
'click .post-controls .delete' : 'deletePost',
'click .post-controls .post-edit' : 'editPost'
},
initialize: function (options) {
this.listenTo(Backbone, 'blog:activeItem', this.setActivePreview);
this.$('.content-preview-content').on('scroll', _.bind(scrollShadow, null, '.content-preview'));
},
setActivePreview: function (id) {
if (this.activeId !== id) {
this.activeId = id;
this.render();
}
},
deletePost: function (e) {
e.preventDefault();
if (window.confirm('Are you sure you want to delete this post?')) {
this.model.destroy({
wait: true
});
}
},
editPost: function (e) {
e.preventDefault();
// for now this will disable "open in new tab", but when we have a Router implemented
// it can go back to being a normal link to '#/ghost/editor/X'
window.location = '/ghost/editor/' + this.model.get('id');
},
templateName: "preview",
template: function (data) {
return JST[this.templateName](data);
},
render: function () {
if (this.activeId) {
this.model = this.collection.get(this.activeId);
this.$el.html(this.template(this.model.toJSON()));
}
this.$('.wrapper').on('click', 'a', function (e) {
$(e.currentTarget).attr('target', '_blank');
});
Ghost.temporary.initToggles(this.$el);
return this;
}
});
}());

View File

@ -0,0 +1,172 @@
/*global window, document, Ghost, $, _, Backbone, JST */
(function () {
"use strict";
var Widgets,
Widget,
WidgetContent,
$widgetContainer,
$itemElems,
widgetPositions;
widgetPositions = {
mobile: {},
tablet: {},
netbook: {},
desktop: {}
};
// Base view
// ----------
Ghost.Views.Dashboard = Ghost.View.extend({
initialize: function (options) {
this.addSubview(new Widgets({ el: '.js-widget-container', collection: this.collection })).render();
}
});
// Widgets
// ----------
Widgets = Ghost.View.extend({
initialize: function () {
$widgetContainer = this.$el;
},
packeryInit: function () {
var self = this;
$widgetContainer.packery({
itemSelector: '.js-widget',
gutter: 10,
columnWidth: 340,
rowHeight: 300
});
$itemElems = $($widgetContainer.packery('getItemElements'));
// make item elements draggable
$itemElems.draggable();
// bind Draggable events to Packery
$widgetContainer.packery('bindUIDraggableEvents', $itemElems);
$widgetContainer.packery('on', 'dragItemPositioned', function () {
var viewportSize = $(window).width();
if (viewportSize <= 400) { // Mobile
widgetPositions.mobile = self.getWidgetOrder($itemElems);
} else if (viewportSize > 400 && viewportSize <= 800) { // Tablet
widgetPositions.tablet = self.getWidgetOrder($itemElems);
} else if (viewportSize > 800 && viewportSize <= 1000) { // Netbook
widgetPositions.netbook = self.getWidgetOrder($itemElems);
} else if (viewportSize > 1000) {
widgetPositions.desktop = self.getWidgetOrder($itemElems);
}
localStorage.setItem('widgetPositions', JSON.stringify(widgetPositions));
// Retrieve the object from storage with `JSON.parse(localStorage.getItem('widgetPositions'));`
});
},
getWidgetOrder: function (itemElems) {
// items are in order within the layout
var order = {};
_.each(itemElems, function (widget, index) {
order[widget.getAttribute("data-widget-id")] = index;
});
return order;
},
render: function () {
this.collection.each(function (model) {
this.$el.append(this.addSubview(new Widget({model: model})).render().el);
}, this);
this.packeryInit();
}
});
// Widget
// ----------
Widget = Ghost.View.extend({
tagName: 'article',
attributes: function () {
var size = (this.model.get('size')) ? " widget-" + this.model.get('size') : "",
settings = (this.model.attributes.settings.enabled) ? " widget-settings" : "";
return {
'class': 'widget-' + this.model.get('name') + size + settings + ' js-widget',
'data-widget-id': this.model.get('applicationID')
};
},
events: {
'click .js-widget-resizer': 'resizeWidget',
'click .js-view-settings': 'showSettings',
'click .js-view-widget': 'showWidget'
},
resizeWidget: function (e) {
e.preventDefault();
var data = $(e.currentTarget).data('size');
this.$el.removeClass("widget-1x2 widget-2x1 widget-2x2");
if (data !== "1x1") {
this.$el.addClass('widget-' + data);
$widgetContainer.packery('fit', this.el);
} else {
$widgetContainer.packery();
}
$(e.currentTarget).siblings('.active').removeClass('active');
$(e.currentTarget).addClass('active');
},
showSettings: function (e) {
e.preventDefault();
this.model.attributes.settings.enabled = true;
this.$el.addClass("widget-settings");
this.render();
},
showWidget: function (e) {
e.preventDefault();
this.model.attributes.settings.enabled = false;
this.$el.removeClass("widget-settings");
this.render();
},
templateName: "widget",
template: function (data) {
return JST[this.templateName](data);
},
render: function () {
this.$el.html(this.template(this.model.toJSON()));
if (!this.model.attributes.settings.enabled) {
this.$(".widget-content").html(this.addSubview(new WidgetContent({model: this.model})).render().el);
} else {
var size = !this.model.get('size') ? "1x1" : this.model.get('size');
this.$el.find("[data-size='" + size + "']").addClass('active');
}
return this;
}
});
// Widget Content
// ----------
WidgetContent = Ghost.View.extend({
template: function (data) {
return JST['widgets/' + this.model.attributes.content.template](data);
},
render: function () {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
}());

View File

@ -0,0 +1,25 @@
/*global window, document, Ghost, $, _, Backbone, JST */
(function () {
"use strict";
Ghost.Views.Debug = Ghost.View.extend({
events: {
"click .settings-menu a": "handleMenuClick"
},
handleMenuClick: function (ev) {
ev.preventDefault();
var $target = $(ev.currentTarget);
// Hide the current content
this.$(".settings-content").hide();
// Show the clicked content
this.$("#debug-" + $target.attr("class")).show();
return false;
}
});
}());

257
ghost/admin/views/editor.js Normal file
View File

@ -0,0 +1,257 @@
// # Article Editor
/*global window, document, $, _, Backbone, Ghost, Showdown, CodeMirror, shortcut, Countable */
(function () {
"use strict";
var PublishBar,
TagWidget,
ActionsWidget,
MarkdownShortcuts = [
{'key': 'Ctrl+B', 'style': 'bold'},
{'key': 'Meta+B', 'style': 'bold'},
{'key': 'Ctrl+I', 'style': 'italic'},
{'key': 'Meta+I', 'style': 'italic'},
{'key': 'Ctrl+Alt+U', 'style': 'strike'},
{'key': 'Ctrl+Shift+K', 'style': 'code'},
{'key': 'Ctrl+Alt+1', 'style': 'h1'},
{'key': 'Ctrl+Alt+2', 'style': 'h2'},
{'key': 'Ctrl+Alt+3', 'style': 'h3'},
{'key': 'Ctrl+Alt+4', 'style': 'h4'},
{'key': 'Ctrl+Alt+5', 'style': 'h5'},
{'key': 'Ctrl+Alt+6', 'style': 'h6'},
{'key': 'Ctrl+Shift+L', 'style': 'link'},
{'key': 'Ctrl+Shift+I', 'style': 'image'},
{'key': 'Ctrl+Q', 'style': 'blockquote'},
{'key': 'Ctrl+Shift+1', 'style': 'currentdate'}
];
// The publish bar associated with a post, which has the TagWidget and
// Save button and options and such.
// ----------------------------------------
PublishBar = Ghost.View.extend({
initialize: function () {
this.addSubview(new TagWidget({el: this.$('#entry-categories'), model: this.model})).render();
this.addSubview(new ActionsWidget({el: this.$('#entry-actions'), model: this.model})).render();
}
});
// The Tag UI area associated with a post
// ----------------------------------------
TagWidget = Ghost.View.extend({
});
// The Publish, Queue, Publish Now buttons
// ----------------------------------------
ActionsWidget = Ghost.View.extend({
events: {
'click [data-set-status]': 'handleStatus',
'click .js-post-button': 'updatePost'
},
statusMap: {
'draft' : 'Save Draft',
'published': 'Update Post',
'scheduled' : 'Save Schedued Post'
},
initialize: function () {
var self = this;
// Toggle publish
shortcut.add("Ctrl+Alt+P", function () {
self.toggleStatus();
});
shortcut.add("Ctrl+S", function () {
self.updatePost();
});
shortcut.add("Meta+S", function () {
self.updatePost();
});
this.listenTo(this.model, 'change:status', this.render);
this.model.on('change:id', function (m) {
Backbone.history.navigate('/editor/' + m.id);
});
},
toggleStatus: function () {
var keys = Object.keys(this.statusMap),
model = this.model,
currentIndex = keys.indexOf(model.get('status')),
newIndex;
if (keys[currentIndex + 1] === 'scheduled') { // TODO: Remove once scheduled posts work
newIndex = currentIndex + 2 > keys.length - 1 ? 0 : currentIndex + 1;
} else {
newIndex = currentIndex + 1 > keys.length - 1 ? 0 : currentIndex + 1;
}
this.savePost({
status: keys[newIndex]
}).then(function () {
window.alert('Your post: ' + model.get('title') + ' has been ' + keys[newIndex]);
});
},
handleStatus: function (e) {
e.preventDefault();
var status = $(e.currentTarget).attr('data-set-status'),
model = this.model;
if (status === 'publish-on') {
return window.alert('Scheduled publishing not supported yet.');
}
if (status === 'queue') {
return window.alert('Scheduled publishing not supported yet.');
}
this.savePost({
status: status
}).then(function () {
window.alert('Your post: ' + model.get('title') + ' has been ' + status);
});
},
updatePost: function (e) {
if (e) {
e.preventDefault();
}
var model = this.model;
this.savePost().then(function () {
window.alert('Your post was saved as ' + model.get('status'));
}, function () {
window.alert(model.validationError);
});
},
savePost: function (data) {
// TODO: The content_raw getter here isn't great, shouldn't rely on currentView.
_.each(this.model.blacklist, function (item) {
this.model.unset(item);
}, this);
var saved = this.model.save(_.extend({
title: $('#entry-title').val(),
content_raw: Ghost.currentView.editor.getValue()
}, data));
// TODO: Take this out if #2489 gets merged in Backbone. Or patch Backbone
// ourselves for more consistent promises.
if (saved) {
return saved;
}
return $.Deferred().reject();
},
render: function () {
this.$('.js-post-button').text(this.statusMap[this.model.get('status')]);
}
});
// The entire /editor page's route (TODO: move all views to client side templates)
// ----------------------------------------
Ghost.Views.Editor = Ghost.View.extend({
initialize: function () {
// Add the container view for the Publish Bar
this.addSubview(new PublishBar({el: "#publish-bar", model: this.model})).render();
this.$('#entry-markdown').html(this.model.get('content_raw'));
this.initMarkdown();
this.renderPreview();
// TODO: Debounce
this.$('.CodeMirror-scroll').on('scroll', this.syncScroll);
// Shadow on Markdown if scrolled
this.$('.CodeMirror-scroll').on('scroll', function (e) {
if ($('.CodeMirror-scroll').scrollTop() > 10) {
$('.entry-markdown').addClass('scrolling');
} else {
$('.entry-markdown').removeClass('scrolling');
}
});
// Shadow on Preview if scrolled
this.$('.entry-preview-content').on('scroll', function (e) {
if ($('.entry-preview-content').scrollTop() > 10) {
$('.entry-preview').addClass('scrolling');
} else {
$('.entry-preview').removeClass('scrolling');
}
});
// Zen writing mode shortcut
shortcut.add("Alt+Shift+Z", function () {
$('body').toggleClass('zen');
});
$('.entry-markdown header, .entry-preview header').click(function (e) {
$('.entry-markdown, .entry-preview').removeClass('active');
$(e.target).closest('section').addClass('active');
});
},
syncScroll: function (e) {
var $codeViewport = $(e.target),
$previewViewport = $('.entry-preview-content'),
$codeContent = $('.CodeMirror-sizer'),
$previewContent = $('.rendered-markdown'),
// calc position
codeHeight = $codeContent.height() - $codeViewport.height(),
previewHeight = $previewContent.height() - $previewViewport.height(),
ratio = previewHeight / codeHeight,
previewPostition = $codeViewport.scrollTop() * ratio;
// apply new scroll
$previewViewport.scrollTop(previewPostition);
},
// This updates the editor preview panel.
// Currently gets called on every key press.
// Also trigger word count update
renderPreview: function () {
var view = this,
preview = document.getElementsByClassName('rendered-markdown')[0];
preview.innerHTML = this.converter.makeHtml(this.editor.getValue());
Countable.once(preview, function (counter) {
view.$('.entry-word-count').text(counter.words + ' words');
view.$('.entry-character-count').text(counter.characters + ' characters');
view.$('.entry-paragraph-count').text(counter.paragraphs + ' paragraphs');
});
},
// Markdown converter & markdown shortcut initialization.
initMarkdown: function () {
this.converter = new Showdown.converter({extensions: ['ghostdown']});
this.editor = CodeMirror.fromTextArea(document.getElementById('entry-markdown'), {
mode: 'markdown',
tabMode: 'indent',
tabindex: "2",
lineWrapping: true
});
var view = this;
_.each(MarkdownShortcuts, function (combo) {
shortcut.add(combo.key, function () {
return view.editor.addMarkdown({style: combo.style});
});
});
this.editor.on('change', function () {
view.renderPreview();
});
}
});
}());

View File

@ -0,0 +1,152 @@
/*global window, document, Ghost, $, _, Backbone */
(function () {
"use strict";
var Settings = {};
// Base view
// ----------
Ghost.Views.Settings = Ghost.View.extend({
initialize: function (options) {
this.addSubview(new Settings.Sidebar({
el: '.settings-sidebar',
pane: options.pane,
model: this.model
}));
this.$('input').iCheck({
checkboxClass: 'icheckbox_ghost'
});
}
});
// Sidebar (tabs)
// ---------------
Settings.Sidebar = Ghost.View.extend({
initialize: function (options) {
this.menu = this.$('.settings-menu');
this.showContent(options.pane || 'general');
},
events: {
'click .settings-menu li' : 'switchPane'
},
switchPane: function (e) {
e.preventDefault();
var item = $(e.currentTarget),
id = item.find('a').attr('href').substring(1);
this.showContent(id);
},
showContent: function (id) {
Backbone.history.navigate('/settings/' + id);
if (this.pane && '#' + id === this.pane.el) {
return;
}
_.result(this.pane, 'destroy');
this.setActive(id);
this.pane = new Settings[id]({ model: this.model });
this.pane.render();
},
setActive: function (id) {
this.menu.find('li').removeClass('active');
this.menu.find('a[href=#' + id + ']').parent().addClass('active');
}
});
// Content panes
// --------------
Settings.Pane = Ghost.View.extend({
destroy: function () {
this.$el.removeClass('active');
this.undelegateEvents();
},
render: function () {
this.$el.addClass('active');
}
});
// TODO: render templates on the client
// TODO: use some kind of data-binding for forms
// ### General settings
Settings.general = Settings.Pane.extend({
el: '#general',
events: {
'click .button-save': 'saveSettings'
},
saveSettings: function () {
this.model.save({
title: this.$('#blog-title').val(),
email: this.$('#email-address').val()
}, {
success: function () {
window.alert('Saved');
}
});
},
render: function () {
var settings = this.model.toJSON();
this.$('#blog-title').val(settings.title);
this.$('#email-address').val(settings.email);
Settings.Pane.prototype.render.call(this);
}
});
// ### Content settings
Settings.content = Settings.Pane.extend({
el: '#content',
events: {
'click .button-save': 'saveSettings'
},
saveSettings: function () {
this.model.save({
description: this.$('#blog-description').val()
}, {
success: function () {
window.alert('Saved');
}
});
},
render: function () {
var settings = this.model.toJSON();
this.$('#blog-description').val(settings.description);
Settings.Pane.prototype.render.call(this);
}
});
// ### User settings
Settings.users = Settings.Pane.extend({
el: '#users',
events: {
}
});
// ### Appearance settings
Settings.appearance = Settings.Pane.extend({
el: '#appearance',
events: {
}
});
// ### Services settings
Settings.services = Settings.Pane.extend({
el: '#services',
events: {
}
});
// ### Plugins settings
Settings.plugins = Settings.Pane.extend({
el: '#plugins',
events: {
}
});
}());