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
69
ghost/admin/admin-ui-temp.js
Normal 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);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}());
|
289
ghost/admin/assets/fonts/icons.dev.svg
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
ghost/admin/assets/fonts/icons.eot
Normal file
289
ghost/admin/assets/fonts/icons.svg
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
ghost/admin/assets/fonts/icons.ttf
Normal file
BIN
ghost/admin/assets/fonts/icons.woff
Normal file
BIN
ghost/admin/assets/img/dash/CampaignMonitor@2x.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
ghost/admin/assets/img/dash/Facebook@2x.png
Normal file
After Width: | Height: | Size: 122 KiB |
BIN
ghost/admin/assets/img/dash/Facebook_Images@2x.png
Normal file
After Width: | Height: | Size: 89 KiB |
BIN
ghost/admin/assets/img/dash/GooglePlus@2x.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
ghost/admin/assets/img/dash/Image@2x.png
Normal file
After Width: | Height: | Size: 1.7 MiB |
BIN
ghost/admin/assets/img/dash/PostsStats@2x.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
ghost/admin/assets/img/dash/Stats@2x.png
Normal file
After Width: | Height: | Size: 98 KiB |
BIN
ghost/admin/assets/img/dash/Time@2x.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
ghost/admin/assets/img/dash/Twitter@2x.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
ghost/admin/assets/img/ghost-icon.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
ghost/admin/assets/img/loadingcat.gif
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
ghost/admin/assets/img/logo.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
ghost/admin/assets/img/postimg.jpg
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
ghost/admin/assets/img/test-icon.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
ghost/admin/assets/img/user.jpg
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
ghost/admin/assets/img/users.png
Normal file
After Width: | Height: | Size: 54 KiB |
1
ghost/admin/assets/sass/ie.scss
Normal file
@ -0,0 +1 @@
|
||||
/* IE specific override styles. */
|
1061
ghost/admin/assets/sass/layouts/dashboard.scss
Normal file
521
ghost/admin/assets/sass/layouts/editor.scss
Normal 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;
|
||||
}
|
159
ghost/admin/assets/sass/layouts/login.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
248
ghost/admin/assets/sass/layouts/manage.scss
Normal 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
|
345
ghost/admin/assets/sass/layouts/settings.scss
Normal 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
|
29
ghost/admin/assets/sass/modules/animations.scss
Normal 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; }
|
||||
}
|
546
ghost/admin/assets/sass/modules/breakpoint.scss
Normal 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;
|
||||
}
|
419
ghost/admin/assets/sass/modules/forms.scss
Normal 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;
|
||||
}
|
||||
|
1174
ghost/admin/assets/sass/modules/global.scss
Normal file
214
ghost/admin/assets/sass/modules/icons.scss
Normal 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;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
181
ghost/admin/assets/sass/modules/mixins.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
396
ghost/admin/assets/sass/modules/normalize.scss
vendored
Normal 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;
|
||||
}
|
678
ghost/admin/assets/sass/modules/typeplate.scss
Normal 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>″″</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.
|
||||
*
|
||||
*/
|
50
ghost/admin/assets/sass/screen.scss
Normal 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. */
|
1571
ghost/admin/assets/vendor/backbone/backbone.js
vendored
Normal file
39
ghost/admin/assets/vendor/chart.min.js
vendored
Normal 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={}};
|
246
ghost/admin/assets/vendor/codemirror/codemirror.css
vendored
Normal 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;
|
||||
}
|
||||
}
|
5585
ghost/admin/assets/vendor/codemirror/codemirror.js
vendored
Normal file
344
ghost/admin/assets/vendor/codemirror/mode/markdown/index.html
vendored
Normal 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
|
||||
================
|
||||
|
||||
<ul id="ProjectSubmenu">
|
||||
<li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
|
||||
<li><a class="selected" title="Markdown Basics">Basics</a></li>
|
||||
<li><a href="/projects/markdown/syntax" title="Markdown Syntax Documentation">Syntax</a></li>
|
||||
<li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
|
||||
<li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
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 `<h1>` and `<h2>` 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 '`>`' 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
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
||||
|
||||
|
||||
Output:
|
||||
|
||||
<h1>A First Level Header</h1>
|
||||
|
||||
<h2>A Second Level Header</h2>
|
||||
|
||||
<p>Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.</p>
|
||||
|
||||
<p>The quick brown fox jumped over the lazy
|
||||
dog's back.</p>
|
||||
|
||||
<h3>Header 3</h3>
|
||||
|
||||
<blockquote>
|
||||
<p>This is a blockquote.</p>
|
||||
|
||||
<p>This is the second paragraph in the blockquote.</p>
|
||||
|
||||
<h2>This is an H2 in a blockquote</h2>
|
||||
</blockquote>
|
||||
|
||||
|
||||
|
||||
### 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:
|
||||
|
||||
<p>Some of these words <em>are emphasized</em>.
|
||||
Some of these words <em>are emphasized also</em>.</p>
|
||||
|
||||
<p>Use two asterisks for <strong>strong emphasis</strong>.
|
||||
Or, if you prefer, <strong>use two underscores instead</strong>.</p>
|
||||
|
||||
|
||||
|
||||
## 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:
|
||||
|
||||
<ul>
|
||||
<li>Candy.</li>
|
||||
<li>Gum.</li>
|
||||
<li>Booze.</li>
|
||||
</ul>
|
||||
|
||||
Ordered (numbered) lists use regular numbers, followed by periods, as
|
||||
list markers:
|
||||
|
||||
1. Red
|
||||
2. Green
|
||||
3. Blue
|
||||
|
||||
Output:
|
||||
|
||||
<ol>
|
||||
<li>Red</li>
|
||||
<li>Green</li>
|
||||
<li>Blue</li>
|
||||
</ol>
|
||||
|
||||
If you put blank lines between items, you'll get `<p>` 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:
|
||||
|
||||
<ul>
|
||||
<li><p>A list item.</p>
|
||||
<p>With multiple paragraphs.</p></li>
|
||||
<li><p>Another item in the list.</p></li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
### 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:
|
||||
|
||||
<p>This is an <a href="http://example.com/">
|
||||
example link</a>.</p>
|
||||
|
||||
Optionally, you may include a title attribute in the parentheses:
|
||||
|
||||
This is an [example link](http://example.com/ "With a Title").
|
||||
|
||||
Output:
|
||||
|
||||
<p>This is an <a href="http://example.com/" title="With a Title">
|
||||
example link</a>.</p>
|
||||
|
||||
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:
|
||||
|
||||
<p>I get 10 times more traffic from <a href="http://google.com/"
|
||||
title="Google">Google</a> than from <a href="http://search.yahoo.com/"
|
||||
title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/"
|
||||
title="MSN Search">MSN</a>.</p>
|
||||
|
||||
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:
|
||||
|
||||
<p>I start my morning with a cup of coffee and
|
||||
<a href="http://www.nytimes.com/">The New York Times</a>.</p>
|
||||
|
||||
|
||||
### 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:
|
||||
|
||||
<img src="/path/to/img.jpg" alt="alt text" title="Title" />
|
||||
|
||||
|
||||
|
||||
### Code ###
|
||||
|
||||
In a regular paragraph, you can create code span by wrapping text in
|
||||
backtick quotes. Any ampersands (`&`) and angle brackets (`<` or
|
||||
`>`) 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 `<blink>` tags.
|
||||
|
||||
I wish SmartyPants used named entities like `&mdash;`
|
||||
instead of decimal-encoded entites like `&#8212;`.
|
||||
|
||||
Output:
|
||||
|
||||
<p>I strongly recommend against using any
|
||||
<code>&lt;blink&gt;</code> tags.</p>
|
||||
|
||||
<p>I wish SmartyPants used named entities like
|
||||
<code>&amp;mdash;</code> instead of decimal-encoded
|
||||
entites like <code>&amp;#8212;</code>.</p>
|
||||
|
||||
|
||||
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, `&`, `<`,
|
||||
and `>` 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:
|
||||
|
||||
<blockquote>
|
||||
<p>For example.</p>
|
||||
</blockquote>
|
||||
|
||||
Output:
|
||||
|
||||
<p>If you want your page to validate under XHTML 1.0 Strict,
|
||||
you've got to put paragraph tags in your blockquotes:</p>
|
||||
|
||||
<pre><code>&lt;blockquote&gt;
|
||||
&lt;p&gt;For example.&lt;/p&gt;
|
||||
&lt;/blockquote&gt;
|
||||
</code></pre>
|
||||
</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>
|
526
ghost/admin/assets/vendor/codemirror/mode/markdown/markdown.js
vendored
Normal 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");
|
636
ghost/admin/assets/vendor/codemirror/mode/markdown/test.js
vendored
Normal 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, it’ll 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
@ -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))
|
362
ghost/admin/assets/vendor/handlebars/handlebars-runtime.js
vendored
Normal 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 = {
|
||||
"&": "&",
|
||||
"<": "<",
|
||||
">": ">",
|
||||
'"': """,
|
||||
"'": "'",
|
||||
"`": "`"
|
||||
};
|
||||
|
||||
var badChars = /[&<>"'`]/g;
|
||||
var possible = /[&<>"'`]/;
|
||||
|
||||
var escapeChar = function(chr) {
|
||||
return escape[chr] || "&";
|
||||
};
|
||||
|
||||
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);
|
||||
;
|
11
ghost/admin/assets/vendor/icheck/jquery.icheck.min.js
vendored
Normal 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");
|
6
ghost/admin/assets/vendor/jquery/jquery-ui-1.10.3.custom.min.js
vendored
Normal file
6
ghost/admin/assets/vendor/jquery/jquery.min.js
vendored
Normal file
6
ghost/admin/assets/vendor/moment.js
vendored
Normal file
14
ghost/admin/assets/vendor/packery.pkgd.min.js
vendored
Normal file
223
ghost/admin/assets/vendor/shortcuts.js
vendored
Normal 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;
|
||||
}
|
||||
}
|
29
ghost/admin/assets/vendor/showdown/extensions/ghostdown.js
vendored
Normal 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;
|
||||
}());
|
62
ghost/admin/assets/vendor/showdown/showdown.js
vendored
Normal file
1227
ghost/admin/assets/vendor/underscore.js
vendored
Normal file
16
ghost/admin/helpers/index.js
Normal 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
@ -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;
|
||||
|
||||
}());
|
51
ghost/admin/markdown-actions.js
Normal 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()
|
||||
}
|
||||
};
|
||||
|
||||
}());
|
49
ghost/admin/models/post.js
Normal 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;
|
||||
}
|
||||
});
|
||||
|
||||
}());
|
16
ghost/admin/models/settings.js
Normal 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'
|
||||
}
|
||||
});
|
||||
|
||||
}());
|
43
ghost/admin/models/widget.js
Normal 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
@ -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
@ -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
@ -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));
|
||||
});
|
||||
|
||||
}());
|
13
ghost/admin/tpl/list-item.hbs
Normal 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>
|
19
ghost/admin/tpl/preview.hbs
Normal 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>
|
44
ghost/admin/tpl/widget.hbs
Normal 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}}
|
1
ghost/admin/tpl/widgets/custom/instagram.hbs
Normal file
@ -0,0 +1 @@
|
||||
<img class="photo" src="{{content.data.image}}" />
|
5
ghost/admin/tpl/widgets/custom/lastfm.hbs
Normal 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>
|
15
ghost/admin/tpl/widgets/custom/popular-posts.hbs
Normal 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>
|
2
ghost/admin/tpl/widgets/custom/post-ideas.hbs
Normal 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>
|
8
ghost/admin/tpl/widgets/custom/time.hbs
Normal 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>
|
18
ghost/admin/tpl/widgets/custom/tweets.hbs
Normal 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>
|
9
ghost/admin/tpl/widgets/custom/upcoming-posts.hbs
Normal 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>
|
0
ghost/admin/tpl/widgets/default/blank.hbs
Normal file
4
ghost/admin/tpl/widgets/default/number.hbs
Normal 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
@ -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
@ -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;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}());
|
172
ghost/admin/views/dashboard.js
Normal 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;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}());
|
25
ghost/admin/views/debug.js
Normal 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
@ -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();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}());
|
152
ghost/admin/views/settings.js
Normal 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: {
|
||||
}
|
||||
});
|
||||
|
||||
}());
|