mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-24 19:33:02 +03:00
Added image upload reusable plugin
issue #40 and issue #280 - Adds uploader jquery plugin - includes settings for enabling/disabling upload progress bar - adds routing for image uploads - adds directories by year and month based on upload date - Implements plugin on settings - general pane - Implements plugin on editor - adjusted general tab to save uploaded image src TODO: - Add error handling - Storing information on editor - Add events
This commit is contained in:
parent
b9dfcc485c
commit
558c9d6caa
BIN
core/client/assets/img/AddImage.png
Normal file
BIN
core/client/assets/img/AddImage.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 367 B |
BIN
core/client/assets/img/returnImage.png
Normal file
BIN
core/client/assets/img/returnImage.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
177
core/client/assets/lib/uploader.js
Normal file
177
core/client/assets/lib/uploader.js
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
/*global jQuery, Ghost, document, Image, window */
|
||||||
|
(function ($) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var UploadUi,
|
||||||
|
$loader = '<span class="media"><span class="hidden">Image Upload</span></span>' +
|
||||||
|
'<div class="description">Add image</div>' +
|
||||||
|
'<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>',
|
||||||
|
$progress = $('<div />', {
|
||||||
|
"class" : "js-upload-progress progress progress-success active",
|
||||||
|
"style": "opacity:0",
|
||||||
|
"role": "progressbar",
|
||||||
|
"aria-valuemin": "0",
|
||||||
|
"aria-valuemax": "100"
|
||||||
|
}).append($("<div />", {
|
||||||
|
"class": "js-upload-progress-bar bar",
|
||||||
|
"style": "width:0%"
|
||||||
|
}));
|
||||||
|
|
||||||
|
UploadUi = function ($dropzone, settings) {
|
||||||
|
var source,
|
||||||
|
$link = $('<a class="js-edit-image image-edit" href="#" >' +
|
||||||
|
'<img src="/public/assets/img/addImage.png" width="16" height="16" alt="add, edit"></a>'),
|
||||||
|
$back = $('<a class="js-return-image image-edit" href="#" >' +
|
||||||
|
'<img src="/public/assets/img/returnImage.png" width="16" height="16" alt="add, edit"></a>');
|
||||||
|
|
||||||
|
$.extend(this, {
|
||||||
|
bindFileUpload: function () {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
$dropzone.find('.js-fileupload').fileupload().fileupload("option", {
|
||||||
|
url: '/ghost/upload',
|
||||||
|
add: function (e, data) {
|
||||||
|
$dropzone.find('a.js-return-image').remove();
|
||||||
|
$dropzone.find('span.media, div.description, a.image-url, a.image-webcam')
|
||||||
|
.animate({opacity: 0}, 250, function () {
|
||||||
|
if (settings.progressbar) {
|
||||||
|
$dropzone.find('span.media').after($progress);
|
||||||
|
$progress.animate({opacity: 100}, 250);
|
||||||
|
}
|
||||||
|
data.submit();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
dropZone: $dropzone,
|
||||||
|
progressall: function (e, data) {
|
||||||
|
var progress = parseInt(data.loaded / data.total * 100, 10);
|
||||||
|
if (!settings.editor) {$progress.find('div.js-progress').css({"position": "absolute", "top": "40px"}); }
|
||||||
|
if (settings.progressbar) {
|
||||||
|
$progress.find('.js-upload-progress-bar').css('width', progress + '%');
|
||||||
|
if (data.loaded / data.total === 1) {
|
||||||
|
$progress.animate({opacity: 0}, 250, function () {
|
||||||
|
$dropzone.find('span.media').after('<img class="fileupload-loading" src="/public/img/loadingcat.gif" />');
|
||||||
|
if (!settings.editor) {$progress.find('.fileupload-loading').css({"top": "56px"}); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
done: function (e, data) {
|
||||||
|
function showImage(width, height) {
|
||||||
|
$dropzone.find('img.js-upload-target').attr({"width": width, "height": height}).css({"display": "block"});
|
||||||
|
$dropzone.find('.fileupload-loading').removeClass('fileupload-loading');
|
||||||
|
$dropzone.css({"height": "auto"});
|
||||||
|
if (!$dropzone.find('a.js-edit-image')[0]) {
|
||||||
|
$link.css({"opacity": 100});
|
||||||
|
$dropzone.find('.js-upload-target').after($link);
|
||||||
|
}
|
||||||
|
$dropzone.delay(250).animate({opacity: 100}, 1000, function () {
|
||||||
|
self.init();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function animateDropzone($img) {
|
||||||
|
$dropzone.animate({opacity: 0}, 250, function () {
|
||||||
|
$dropzone.removeClass('image-uploader').addClass('pre-image-uploader');
|
||||||
|
$dropzone.css({minHeight: 0});
|
||||||
|
self.removeExtras();
|
||||||
|
$dropzone.animate({height: $img.height()}, 250, function () {
|
||||||
|
showImage($img.width(), $img.height());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function preloadImage() {
|
||||||
|
var $img = $dropzone.find('img.js-upload-target')
|
||||||
|
.attr({'src': '', "width": 'auto', "height": 'auto'});
|
||||||
|
$img.one('load', function () { animateDropzone($img); })
|
||||||
|
.attr('src', data.result);
|
||||||
|
}
|
||||||
|
preloadImage();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
removeExtras: function () {
|
||||||
|
$dropzone.find('div.description, span.media, div.js-upload-progress, a.image-url, a.image-webcam')
|
||||||
|
.remove();
|
||||||
|
},
|
||||||
|
|
||||||
|
initWithDropzone: function () {
|
||||||
|
var self = this;
|
||||||
|
//This is the start point if no image exists
|
||||||
|
$dropzone.find('img.js-upload-target').css({"display": "none"});
|
||||||
|
$dropzone.removeClass('pre-image-uploader').addClass('image-uploader');
|
||||||
|
if (!$dropzone.find('span.media')[0]) {
|
||||||
|
$dropzone.append($loader);
|
||||||
|
}
|
||||||
|
if ($dropzone.find('a.js-edit-image')[0]) {
|
||||||
|
$dropzone.find('a.js-edit-image').remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
$back.on('click', function () {
|
||||||
|
$dropzone.find('a.js-return-image').remove();
|
||||||
|
$dropzone.find('img.js-upload-target').attr({"src": source}).css({"display": "block"});
|
||||||
|
self.removeExtras();
|
||||||
|
$dropzone.removeClass('image-uploader').addClass('pre-image-uploader');
|
||||||
|
self.init();
|
||||||
|
});
|
||||||
|
this.bindFileUpload();
|
||||||
|
},
|
||||||
|
|
||||||
|
initWithImage: function () {
|
||||||
|
var self = this;
|
||||||
|
// This is the start point if an image already exists
|
||||||
|
source = $dropzone.find('img.js-upload-target').attr('src');
|
||||||
|
$dropzone.removeClass('image-uploader').addClass('pre-image-uploader');
|
||||||
|
|
||||||
|
if (!$dropzone.find('a.js-edit-image')[0]) {
|
||||||
|
$link.css({"opacity": 100});
|
||||||
|
$dropzone.find('.js-upload-target').after($link);
|
||||||
|
}
|
||||||
|
|
||||||
|
$link.on('click', function () {
|
||||||
|
$dropzone.find('a.js-edit-image').remove();
|
||||||
|
$dropzone.find('img.js-upload-target').attr({"src": ""}).css({"display": "none"});
|
||||||
|
$back.css({"cursor": "pointer", "z-index": 9999, "opacity": 100});
|
||||||
|
$dropzone.find('.js-upload-target').after($back);
|
||||||
|
self.init();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
init: function () {
|
||||||
|
var img;
|
||||||
|
// First check if field image is defined by checking for js-upload-target class
|
||||||
|
if ($dropzone.find('img.js-upload-target')[0]) {
|
||||||
|
if ($dropzone.find('img.js-upload-target').attr('src') === '') {
|
||||||
|
this.initWithDropzone();
|
||||||
|
} else {
|
||||||
|
this.initWithImage();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This ensures there is an image we can hook into to display uploaded image
|
||||||
|
$dropzone.prepend('<img class="js-upload-target" style="display: none" src="" />');
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
$.fn.upload = function (options) {
|
||||||
|
var settings = $.extend({
|
||||||
|
progressbar: true,
|
||||||
|
editor: false
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
return this.each(function () {
|
||||||
|
var $dropzone = $(this),
|
||||||
|
ui;
|
||||||
|
|
||||||
|
ui = new UploadUi($dropzone, settings);
|
||||||
|
ui.init();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}(jQuery));
|
@ -117,7 +117,7 @@
|
|||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
@include icon($i-question, '', $brown)
|
@include icon($i-question, '', $brown);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,7 +255,6 @@
|
|||||||
@include breakpoint($netbook) {padding-top: 20px;}
|
@include breakpoint($netbook) {padding-top: 20px;}
|
||||||
@include breakpoint($mobile) {padding: 15px;}
|
@include breakpoint($mobile) {padding: 15px;}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case, when scrolling, add shadows to content headers.
|
// Special case, when scrolling, add shadows to content headers.
|
||||||
@ -331,11 +330,21 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
a {
|
||||||
|
&.image-edit {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
img {
|
img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
// prevent uploaded image from being streched in editor
|
||||||
|
.pre-image-uploader img {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1135,6 +1135,16 @@ main {
|
|||||||
color: $brown;
|
color: $brown;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
.image-edit {
|
||||||
|
line-height: 12px;
|
||||||
|
padding: 10px;
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
opacity: 0;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
.image-webcam {
|
.image-webcam {
|
||||||
@include icon($i-camera, 12px);
|
@include icon($i-camera, 12px);
|
||||||
@ -1146,9 +1156,10 @@ main {
|
|||||||
right: 0;
|
right: 0;
|
||||||
color: $brown;
|
color: $brown;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.fileupload {
|
input {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@ -1162,7 +1173,7 @@ main {
|
|||||||
|
|
||||||
.progress {
|
.progress {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: -39px;
|
top: -22px;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
margin-bottom: -12px;
|
margin-bottom: -12px;
|
||||||
display: block;
|
display: block;
|
||||||
@ -1186,7 +1197,61 @@ main {
|
|||||||
background: $blue;
|
background: $blue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.pre-image-uploader {
|
||||||
|
@include box-sizing(border-box);
|
||||||
|
@include baseline;
|
||||||
|
position: relative;
|
||||||
|
overflow:hidden;
|
||||||
|
height: auto;
|
||||||
|
color: $brown;
|
||||||
|
|
||||||
|
input {
|
||||||
|
position: absolute;
|
||||||
|
left: 9999px;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.image-edit {
|
||||||
|
|
||||||
|
line-height: 12px;
|
||||||
|
padding: 10px;
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
opacity: 0;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//.progress {
|
||||||
|
// position: relative;
|
||||||
|
// top: -39px;
|
||||||
|
// margin: auto;
|
||||||
|
// margin-bottom: -12px;
|
||||||
|
// display: block;
|
||||||
|
// overflow: hidden;
|
||||||
|
// @include linear-gradient(to bottom, #f5f5f5, #f9f9f9);
|
||||||
|
// border-radius: 12px;
|
||||||
|
// box-shadow: (rgba(0,0,0,0.1) 0 1px 2px inset);
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//.fileupload-loading {
|
||||||
|
// display: block;
|
||||||
|
// top: 50%;
|
||||||
|
// width: 35px;
|
||||||
|
// height: 28px;
|
||||||
|
// margin: -28px auto 0;
|
||||||
|
// background-size: contain;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//.bar {
|
||||||
|
// height: 12px;
|
||||||
|
// background: $blue;
|
||||||
|
//}
|
||||||
|
|
||||||
/* ==========================================================================
|
/* ==========================================================================
|
||||||
Misc
|
Misc
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
return '<section class="js-drop-zone image-uploader">' +
|
return '<section class="js-drop-zone image-uploader">' +
|
||||||
'<span class="media"><span class="hidden">Image Upload</span></span>' +
|
'<span class="media"><span class="hidden">Image Upload</span></span>' +
|
||||||
'<div class="description">Add image of <strong>' + alt + '</strong></div>' +
|
'<div class="description">Add image of <strong>' + alt + '</strong></div>' +
|
||||||
|
'<img class="js-upload-target" style="display: none" alt="alt" src="" />' +
|
||||||
'<input data-url="upload" class="js-fileupload fileupload" type="file" name="uploadimage">' +
|
'<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-url" title="Add image from URL"><span class="hidden">URL</span></a>' +
|
||||||
'<a class="image-webcam" title="Add image from webcam">' +
|
'<a class="image-webcam" title="Add image from webcam">' +
|
||||||
|
@ -15,13 +15,19 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label><strong>Blog Logo</strong></label>
|
<label><strong>Blog Logo</strong></label>
|
||||||
<img src="/public/img/logo.png" alt="logo" height="38" width="381"/>
|
<section class="js-drop-zone">
|
||||||
|
<img id="logo" class="js-upload-target" src="{{logo}}"{{#unless logo}} style="display: none"{{/unless}} alt="logo"/>
|
||||||
|
<input data-url="upload" class="js-fileupload" type="file" name="uploadimage">
|
||||||
|
</section>
|
||||||
<p>Display a logo on your site in place of blog title</p>
|
<p>Display a logo on your site in place of blog title</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label><strong>Blog Icon</strong></label>
|
<label><strong>Blog Icon</strong></label>
|
||||||
<img src="/public/img/test-icon.png" alt="logo" height="38" width="38"/>
|
<section class="js-drop-zone">
|
||||||
|
<img id="icon" class="js-upload-target" src="{{icon}}"{{#unless icon}} style="display: none"{{/unless}} style="display: none" alt="icon"/>
|
||||||
|
<input data-url="upload" class="js-fileupload" type="file" name="uploadimage">
|
||||||
|
</section>
|
||||||
<p>The icon for your blog, used in your browser tab and elsewhere</p>
|
<p>The icon for your blog, used in your browser tab and elsewhere</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -321,6 +321,7 @@
|
|||||||
var view = this,
|
var view = this,
|
||||||
preview = document.getElementsByClassName('rendered-markdown')[0];
|
preview = document.getElementsByClassName('rendered-markdown')[0];
|
||||||
preview.innerHTML = this.converter.makeHtml(this.editor.getValue());
|
preview.innerHTML = this.converter.makeHtml(this.editor.getValue());
|
||||||
|
view.$('.js-drop-zone').upload({editor: true});
|
||||||
Countable.once(preview, function (counter) {
|
Countable.once(preview, function (counter) {
|
||||||
view.$('.entry-word-count').text(counter.words + ' words');
|
view.$('.entry-word-count').text(counter.words + ' words');
|
||||||
view.$('.entry-character-count').text(counter.characters + ' characters');
|
view.$('.entry-character-count').text(counter.characters + ' characters');
|
||||||
|
@ -128,7 +128,10 @@
|
|||||||
saveSettings: function () {
|
saveSettings: function () {
|
||||||
this.model.save({
|
this.model.save({
|
||||||
title: this.$('#blog-title').val(),
|
title: this.$('#blog-title').val(),
|
||||||
email: this.$('#email-address').val()
|
email: this.$('#email-address').val(),
|
||||||
|
logo: this.$('#logo').attr("src"),
|
||||||
|
icon: this.$('#icon').attr("src")
|
||||||
|
|
||||||
}, {
|
}, {
|
||||||
success: this.saveSuccess,
|
success: this.saveSuccess,
|
||||||
error: this.saveError
|
error: this.saveError
|
||||||
@ -141,6 +144,12 @@
|
|||||||
var settings = this.model.toJSON();
|
var settings = this.model.toJSON();
|
||||||
this.$('#blog-title').val(settings.title);
|
this.$('#blog-title').val(settings.title);
|
||||||
this.$('#email-address').val(settings.email);
|
this.$('#email-address').val(settings.email);
|
||||||
|
},
|
||||||
|
|
||||||
|
afterRender: function () {
|
||||||
|
this.$el.attr('id', this.id);
|
||||||
|
this.$el.addClass('active');
|
||||||
|
this.$('.js-drop-zone').upload();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2,11 +2,12 @@ var Ghost = require('../../ghost'),
|
|||||||
dataExport = require('../data/export'),
|
dataExport = require('../data/export'),
|
||||||
dataImport = require('../data/import'),
|
dataImport = require('../data/import'),
|
||||||
_ = require('underscore'),
|
_ = require('underscore'),
|
||||||
fs = require('fs'),
|
fs = require('fs-extra'),
|
||||||
path = require('path'),
|
path = require('path'),
|
||||||
when = require('when'),
|
when = require('when'),
|
||||||
nodefn = require('when/node/function'),
|
nodefn = require('when/node/function'),
|
||||||
api = require('../api'),
|
api = require('../api'),
|
||||||
|
moment = require('moment'),
|
||||||
|
|
||||||
ghost = new Ghost(),
|
ghost = new Ghost(),
|
||||||
dataProvider = ghost.dataProvider,
|
dataProvider = ghost.dataProvider,
|
||||||
@ -54,6 +55,40 @@ function setSelected(list, name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
adminControllers = {
|
adminControllers = {
|
||||||
|
'uploader': function (req, res) {
|
||||||
|
var currentDate = moment(),
|
||||||
|
month = currentDate.format("MMM"),
|
||||||
|
year = currentDate.format("YYYY"),
|
||||||
|
tmp_path = req.files.uploadimage.path,
|
||||||
|
dir = path.join('content/images', year, month),
|
||||||
|
target_path = path.join(dir, req.files.uploadimage.name),
|
||||||
|
ext = path.extname(req.files.uploadimage.name),
|
||||||
|
src = path.join('/', target_path);
|
||||||
|
|
||||||
|
|
||||||
|
function renameFile() {
|
||||||
|
// adds directories recursively
|
||||||
|
fs.mkdirs(dir, function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
} else {
|
||||||
|
fs.copy(tmp_path, target_path, function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
} else {
|
||||||
|
res.send(src);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ext === ".jpg" || ext === ".png" || ext === ".gif") {
|
||||||
|
renameFile();
|
||||||
|
} else {
|
||||||
|
res.send("Invalid filetype");
|
||||||
|
}
|
||||||
|
},
|
||||||
'login': function (req, res) {
|
'login': function (req, res) {
|
||||||
res.render('login', {
|
res.render('login', {
|
||||||
bodyClass: 'ghost-login',
|
bodyClass: 'ghost-login',
|
||||||
|
@ -39,12 +39,18 @@
|
|||||||
|
|
||||||
<script src="/shared/vendor/jquery/jquery.js"></script>
|
<script src="/shared/vendor/jquery/jquery.js"></script>
|
||||||
<script src="/shared/vendor/jquery/jquery-ui-1.10.3.custom.min.js"></script>
|
<script src="/shared/vendor/jquery/jquery-ui-1.10.3.custom.min.js"></script>
|
||||||
|
<script src="/public/lib/jquery-utils.js"></script>
|
||||||
<script src="/shared/vendor/underscore.js"></script>
|
<script src="/shared/vendor/underscore.js"></script>
|
||||||
<script src="/shared/vendor/backbone/backbone.js"></script>
|
<script src="/shared/vendor/backbone/backbone.js"></script>
|
||||||
<script src="/shared/vendor/handlebars/handlebars-runtime.js"></script>
|
<script src="/shared/vendor/handlebars/handlebars-runtime.js"></script>
|
||||||
<script src="/shared/vendor/moment.js"></script>
|
<script src="/shared/vendor/moment.js"></script>
|
||||||
|
|
||||||
<script src="/public/vendor/icheck/jquery.icheck.min.js"></script>
|
<script src="/public/vendor/icheck/jquery.icheck.min.js"></script>
|
||||||
|
|
||||||
|
<script src="/shared/vendor/jquery/jquery.ui.widget.js"></script>
|
||||||
|
<script src="/shared/vendor/jquery/jquery.iframe-transport.js"></script>
|
||||||
|
<script src="/shared/vendor/jquery/jquery.fileupload.js"></script>
|
||||||
|
|
||||||
<script src="/public/vendor/codemirror/codemirror.js"></script>
|
<script src="/public/vendor/codemirror/codemirror.js"></script>
|
||||||
<script src="/public/vendor/codemirror/mode/markdown/markdown.js"></script>
|
<script src="/public/vendor/codemirror/mode/markdown/markdown.js"></script>
|
||||||
<script src="/public/vendor/showdown/showdown.js"></script>
|
<script src="/public/vendor/showdown/showdown.js"></script>
|
||||||
@ -54,8 +60,10 @@
|
|||||||
<script src="/public/vendor/to-title-case.js"></script>
|
<script src="/public/vendor/to-title-case.js"></script>
|
||||||
<script src="/public/vendor/packery.pkgd.min.js"></script>
|
<script src="/public/vendor/packery.pkgd.min.js"></script>
|
||||||
|
|
||||||
<script src="/public/lib/jquery-utils.js"></script>
|
|
||||||
<script src="/public/init.js"></script>
|
<script src="/public/init.js"></script>
|
||||||
|
|
||||||
|
<script src="/public/assets/lib/uploader.js"></script>
|
||||||
|
|
||||||
<script src="/public/tpl/hbs-tpl.js"></script>
|
<script src="/public/tpl/hbs-tpl.js"></script>
|
||||||
<script src="/public/toggle.js"></script>
|
<script src="/public/toggle.js"></script>
|
||||||
<script src="/public/markdown-actions.js"></script>
|
<script src="/public/markdown-actions.js"></script>
|
||||||
|
1301
core/shared/vendor/jquery/jquery.fileupload.js
vendored
Normal file
1301
core/shared/vendor/jquery/jquery.fileupload.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
185
core/shared/vendor/jquery/jquery.iframe-transport.js
vendored
Normal file
185
core/shared/vendor/jquery/jquery.iframe-transport.js
vendored
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
/*
|
||||||
|
* jQuery Iframe Transport Plugin 1.6.1
|
||||||
|
* https://github.com/blueimp/jQuery-File-Upload
|
||||||
|
*
|
||||||
|
* Copyright 2011, Sebastian Tschan
|
||||||
|
* https://blueimp.net
|
||||||
|
*
|
||||||
|
* Licensed under the MIT license:
|
||||||
|
* http://www.opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*jslint unparam: true, nomen: true */
|
||||||
|
/*global define, window, document */
|
||||||
|
|
||||||
|
(function (factory) {
|
||||||
|
'use strict';
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// Register as an anonymous AMD module:
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else {
|
||||||
|
// Browser globals:
|
||||||
|
factory(window.jQuery);
|
||||||
|
}
|
||||||
|
}(function ($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// Helper variable to create unique names for the transport iframes:
|
||||||
|
var counter = 0;
|
||||||
|
|
||||||
|
// The iframe transport accepts three additional options:
|
||||||
|
// options.fileInput: a jQuery collection of file input fields
|
||||||
|
// options.paramName: the parameter name for the file form data,
|
||||||
|
// overrides the name property of the file input field(s),
|
||||||
|
// can be a string or an array of strings.
|
||||||
|
// options.formData: an array of objects with name and value properties,
|
||||||
|
// equivalent to the return data of .serializeArray(), e.g.:
|
||||||
|
// [{name: 'a', value: 1}, {name: 'b', value: 2}]
|
||||||
|
$.ajaxTransport('iframe', function (options) {
|
||||||
|
if (options.async) {
|
||||||
|
var form,
|
||||||
|
iframe,
|
||||||
|
addParamChar;
|
||||||
|
return {
|
||||||
|
send: function (_, completeCallback) {
|
||||||
|
form = $('<form style="display:none;"></form>');
|
||||||
|
form.attr('accept-charset', options.formAcceptCharset);
|
||||||
|
addParamChar = /\?/.test(options.url) ? '&' : '?';
|
||||||
|
// XDomainRequest only supports GET and POST:
|
||||||
|
if (options.type === 'DELETE') {
|
||||||
|
options.url = options.url + addParamChar + '_method=DELETE';
|
||||||
|
options.type = 'POST';
|
||||||
|
} else if (options.type === 'PUT') {
|
||||||
|
options.url = options.url + addParamChar + '_method=PUT';
|
||||||
|
options.type = 'POST';
|
||||||
|
} else if (options.type === 'PATCH') {
|
||||||
|
options.url = options.url + addParamChar + '_method=PATCH';
|
||||||
|
options.type = 'POST';
|
||||||
|
}
|
||||||
|
// javascript:false as initial iframe src
|
||||||
|
// prevents warning popups on HTTPS in IE6.
|
||||||
|
// IE versions below IE8 cannot set the name property of
|
||||||
|
// elements that have already been added to the DOM,
|
||||||
|
// so we set the name along with the iframe HTML markup:
|
||||||
|
iframe = $(
|
||||||
|
'<iframe src="javascript:false;" name="iframe-transport-' +
|
||||||
|
(counter += 1) + '"></iframe>'
|
||||||
|
).bind('load', function () {
|
||||||
|
var fileInputClones,
|
||||||
|
paramNames = $.isArray(options.paramName) ?
|
||||||
|
options.paramName : [options.paramName];
|
||||||
|
iframe
|
||||||
|
.unbind('load')
|
||||||
|
.bind('load', function () {
|
||||||
|
var response;
|
||||||
|
// Wrap in a try/catch block to catch exceptions thrown
|
||||||
|
// when trying to access cross-domain iframe contents:
|
||||||
|
try {
|
||||||
|
response = iframe.contents();
|
||||||
|
// Google Chrome and Firefox do not throw an
|
||||||
|
// exception when calling iframe.contents() on
|
||||||
|
// cross-domain requests, so we unify the response:
|
||||||
|
if (!response.length || !response[0].firstChild) {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
response = undefined;
|
||||||
|
}
|
||||||
|
// The complete callback returns the
|
||||||
|
// iframe content document as response object:
|
||||||
|
completeCallback(
|
||||||
|
200,
|
||||||
|
'success',
|
||||||
|
{'iframe': response}
|
||||||
|
);
|
||||||
|
// Fix for IE endless progress bar activity bug
|
||||||
|
// (happens on form submits to iframe targets):
|
||||||
|
$('<iframe src="javascript:false;"></iframe>')
|
||||||
|
.appendTo(form);
|
||||||
|
form.remove();
|
||||||
|
});
|
||||||
|
form
|
||||||
|
.prop('target', iframe.prop('name'))
|
||||||
|
.prop('action', options.url)
|
||||||
|
.prop('method', options.type);
|
||||||
|
if (options.formData) {
|
||||||
|
$.each(options.formData, function (index, field) {
|
||||||
|
$('<input type="hidden"/>')
|
||||||
|
.prop('name', field.name)
|
||||||
|
.val(field.value)
|
||||||
|
.appendTo(form);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (options.fileInput && options.fileInput.length &&
|
||||||
|
options.type === 'POST') {
|
||||||
|
fileInputClones = options.fileInput.clone();
|
||||||
|
// Insert a clone for each file input field:
|
||||||
|
options.fileInput.after(function (index) {
|
||||||
|
return fileInputClones[index];
|
||||||
|
});
|
||||||
|
if (options.paramName) {
|
||||||
|
options.fileInput.each(function (index) {
|
||||||
|
$(this).prop(
|
||||||
|
'name',
|
||||||
|
paramNames[index] || options.paramName
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Appending the file input fields to the hidden form
|
||||||
|
// removes them from their original location:
|
||||||
|
form
|
||||||
|
.append(options.fileInput)
|
||||||
|
.prop('enctype', 'multipart/form-data')
|
||||||
|
// enctype must be set as encoding for IE:
|
||||||
|
.prop('encoding', 'multipart/form-data');
|
||||||
|
}
|
||||||
|
form.submit();
|
||||||
|
// Insert the file input fields at their original location
|
||||||
|
// by replacing the clones with the originals:
|
||||||
|
if (fileInputClones && fileInputClones.length) {
|
||||||
|
options.fileInput.each(function (index, input) {
|
||||||
|
var clone = $(fileInputClones[index]);
|
||||||
|
$(input).prop('name', clone.prop('name'));
|
||||||
|
clone.replaceWith(input);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
form.append(iframe).appendTo(document.body);
|
||||||
|
},
|
||||||
|
abort: function () {
|
||||||
|
if (iframe) {
|
||||||
|
// javascript:false as iframe src aborts the request
|
||||||
|
// and prevents warning popups on HTTPS in IE6.
|
||||||
|
// concat is used to avoid the "Script URL" JSLint error:
|
||||||
|
iframe
|
||||||
|
.unbind('load')
|
||||||
|
.prop('src', 'javascript'.concat(':false;'));
|
||||||
|
}
|
||||||
|
if (form) {
|
||||||
|
form.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// The iframe transport returns the iframe content document as response.
|
||||||
|
// The following adds converters from iframe to text, json, html, and script:
|
||||||
|
$.ajaxSetup({
|
||||||
|
converters: {
|
||||||
|
'iframe text': function (iframe) {
|
||||||
|
return iframe && $(iframe[0].body).text();
|
||||||
|
},
|
||||||
|
'iframe json': function (iframe) {
|
||||||
|
return iframe && $.parseJSON($(iframe[0].body).text());
|
||||||
|
},
|
||||||
|
'iframe html': function (iframe) {
|
||||||
|
return iframe && $(iframe[0].body).html();
|
||||||
|
},
|
||||||
|
'iframe script': function (iframe) {
|
||||||
|
return iframe && $.globalEval($(iframe[0].body).text());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}));
|
530
core/shared/vendor/jquery/jquery.ui.widget.js
vendored
Normal file
530
core/shared/vendor/jquery/jquery.ui.widget.js
vendored
Normal file
@ -0,0 +1,530 @@
|
|||||||
|
/*
|
||||||
|
* jQuery UI Widget 1.10.1+amd
|
||||||
|
* https://github.com/blueimp/jQuery-File-Upload
|
||||||
|
*
|
||||||
|
* Copyright 2013 jQuery Foundation and other contributors
|
||||||
|
* Released under the MIT license.
|
||||||
|
* http://jquery.org/license
|
||||||
|
*
|
||||||
|
* http://api.jqueryui.com/jQuery.widget/
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function (factory) {
|
||||||
|
if (typeof define === "function" && define.amd) {
|
||||||
|
// Register as an anonymous AMD module:
|
||||||
|
define(["jquery"], factory);
|
||||||
|
} else {
|
||||||
|
// Browser globals:
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
}(function( $, undefined ) {
|
||||||
|
|
||||||
|
var uuid = 0,
|
||||||
|
slice = Array.prototype.slice,
|
||||||
|
_cleanData = $.cleanData;
|
||||||
|
$.cleanData = function( elems ) {
|
||||||
|
for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
|
||||||
|
try {
|
||||||
|
$( elem ).triggerHandler( "remove" );
|
||||||
|
// http://bugs.jquery.com/ticket/8235
|
||||||
|
} catch( e ) {}
|
||||||
|
}
|
||||||
|
_cleanData( elems );
|
||||||
|
};
|
||||||
|
|
||||||
|
$.widget = function( name, base, prototype ) {
|
||||||
|
var fullName, existingConstructor, constructor, basePrototype,
|
||||||
|
// proxiedPrototype allows the provided prototype to remain unmodified
|
||||||
|
// so that it can be used as a mixin for multiple widgets (#8876)
|
||||||
|
proxiedPrototype = {},
|
||||||
|
namespace = name.split( "." )[ 0 ];
|
||||||
|
|
||||||
|
name = name.split( "." )[ 1 ];
|
||||||
|
fullName = namespace + "-" + name;
|
||||||
|
|
||||||
|
if ( !prototype ) {
|
||||||
|
prototype = base;
|
||||||
|
base = $.Widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create selector for plugin
|
||||||
|
$.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
|
||||||
|
return !!$.data( elem, fullName );
|
||||||
|
};
|
||||||
|
|
||||||
|
$[ namespace ] = $[ namespace ] || {};
|
||||||
|
existingConstructor = $[ namespace ][ name ];
|
||||||
|
constructor = $[ namespace ][ name ] = function( options, element ) {
|
||||||
|
// allow instantiation without "new" keyword
|
||||||
|
if ( !this._createWidget ) {
|
||||||
|
return new constructor( options, element );
|
||||||
|
}
|
||||||
|
|
||||||
|
// allow instantiation without initializing for simple inheritance
|
||||||
|
// must use "new" keyword (the code above always passes args)
|
||||||
|
if ( arguments.length ) {
|
||||||
|
this._createWidget( options, element );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// extend with the existing constructor to carry over any static properties
|
||||||
|
$.extend( constructor, existingConstructor, {
|
||||||
|
version: prototype.version,
|
||||||
|
// copy the object used to create the prototype in case we need to
|
||||||
|
// redefine the widget later
|
||||||
|
_proto: $.extend( {}, prototype ),
|
||||||
|
// track widgets that inherit from this widget in case this widget is
|
||||||
|
// redefined after a widget inherits from it
|
||||||
|
_childConstructors: []
|
||||||
|
});
|
||||||
|
|
||||||
|
basePrototype = new base();
|
||||||
|
// we need to make the options hash a property directly on the new instance
|
||||||
|
// otherwise we'll modify the options hash on the prototype that we're
|
||||||
|
// inheriting from
|
||||||
|
basePrototype.options = $.widget.extend( {}, basePrototype.options );
|
||||||
|
$.each( prototype, function( prop, value ) {
|
||||||
|
if ( !$.isFunction( value ) ) {
|
||||||
|
proxiedPrototype[ prop ] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
proxiedPrototype[ prop ] = (function() {
|
||||||
|
var _super = function() {
|
||||||
|
return base.prototype[ prop ].apply( this, arguments );
|
||||||
|
},
|
||||||
|
_superApply = function( args ) {
|
||||||
|
return base.prototype[ prop ].apply( this, args );
|
||||||
|
};
|
||||||
|
return function() {
|
||||||
|
var __super = this._super,
|
||||||
|
__superApply = this._superApply,
|
||||||
|
returnValue;
|
||||||
|
|
||||||
|
this._super = _super;
|
||||||
|
this._superApply = _superApply;
|
||||||
|
|
||||||
|
returnValue = value.apply( this, arguments );
|
||||||
|
|
||||||
|
this._super = __super;
|
||||||
|
this._superApply = __superApply;
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
});
|
||||||
|
constructor.prototype = $.widget.extend( basePrototype, {
|
||||||
|
// TODO: remove support for widgetEventPrefix
|
||||||
|
// always use the name + a colon as the prefix, e.g., draggable:start
|
||||||
|
// don't prefix for widgets that aren't DOM-based
|
||||||
|
widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name
|
||||||
|
}, proxiedPrototype, {
|
||||||
|
constructor: constructor,
|
||||||
|
namespace: namespace,
|
||||||
|
widgetName: name,
|
||||||
|
widgetFullName: fullName
|
||||||
|
});
|
||||||
|
|
||||||
|
// If this widget is being redefined then we need to find all widgets that
|
||||||
|
// are inheriting from it and redefine all of them so that they inherit from
|
||||||
|
// the new version of this widget. We're essentially trying to replace one
|
||||||
|
// level in the prototype chain.
|
||||||
|
if ( existingConstructor ) {
|
||||||
|
$.each( existingConstructor._childConstructors, function( i, child ) {
|
||||||
|
var childPrototype = child.prototype;
|
||||||
|
|
||||||
|
// redefine the child widget using the same prototype that was
|
||||||
|
// originally used, but inherit from the new version of the base
|
||||||
|
$.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
|
||||||
|
});
|
||||||
|
// remove the list of existing child constructors from the old constructor
|
||||||
|
// so the old child constructors can be garbage collected
|
||||||
|
delete existingConstructor._childConstructors;
|
||||||
|
} else {
|
||||||
|
base._childConstructors.push( constructor );
|
||||||
|
}
|
||||||
|
|
||||||
|
$.widget.bridge( name, constructor );
|
||||||
|
};
|
||||||
|
|
||||||
|
$.widget.extend = function( target ) {
|
||||||
|
var input = slice.call( arguments, 1 ),
|
||||||
|
inputIndex = 0,
|
||||||
|
inputLength = input.length,
|
||||||
|
key,
|
||||||
|
value;
|
||||||
|
for ( ; inputIndex < inputLength; inputIndex++ ) {
|
||||||
|
for ( key in input[ inputIndex ] ) {
|
||||||
|
value = input[ inputIndex ][ key ];
|
||||||
|
if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
|
||||||
|
// Clone objects
|
||||||
|
if ( $.isPlainObject( value ) ) {
|
||||||
|
target[ key ] = $.isPlainObject( target[ key ] ) ?
|
||||||
|
$.widget.extend( {}, target[ key ], value ) :
|
||||||
|
// Don't extend strings, arrays, etc. with objects
|
||||||
|
$.widget.extend( {}, value );
|
||||||
|
// Copy everything else by reference
|
||||||
|
} else {
|
||||||
|
target[ key ] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
};
|
||||||
|
|
||||||
|
$.widget.bridge = function( name, object ) {
|
||||||
|
var fullName = object.prototype.widgetFullName || name;
|
||||||
|
$.fn[ name ] = function( options ) {
|
||||||
|
var isMethodCall = typeof options === "string",
|
||||||
|
args = slice.call( arguments, 1 ),
|
||||||
|
returnValue = this;
|
||||||
|
|
||||||
|
// allow multiple hashes to be passed on init
|
||||||
|
options = !isMethodCall && args.length ?
|
||||||
|
$.widget.extend.apply( null, [ options ].concat(args) ) :
|
||||||
|
options;
|
||||||
|
|
||||||
|
if ( isMethodCall ) {
|
||||||
|
this.each(function() {
|
||||||
|
var methodValue,
|
||||||
|
instance = $.data( this, fullName );
|
||||||
|
if ( !instance ) {
|
||||||
|
return $.error( "cannot call methods on " + name + " prior to initialization; " +
|
||||||
|
"attempted to call method '" + options + "'" );
|
||||||
|
}
|
||||||
|
if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
|
||||||
|
return $.error( "no such method '" + options + "' for " + name + " widget instance" );
|
||||||
|
}
|
||||||
|
methodValue = instance[ options ].apply( instance, args );
|
||||||
|
if ( methodValue !== instance && methodValue !== undefined ) {
|
||||||
|
returnValue = methodValue && methodValue.jquery ?
|
||||||
|
returnValue.pushStack( methodValue.get() ) :
|
||||||
|
methodValue;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.each(function() {
|
||||||
|
var instance = $.data( this, fullName );
|
||||||
|
if ( instance ) {
|
||||||
|
instance.option( options || {} )._init();
|
||||||
|
} else {
|
||||||
|
$.data( this, fullName, new object( options, this ) );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
$.Widget = function( /* options, element */ ) {};
|
||||||
|
$.Widget._childConstructors = [];
|
||||||
|
|
||||||
|
$.Widget.prototype = {
|
||||||
|
widgetName: "widget",
|
||||||
|
widgetEventPrefix: "",
|
||||||
|
defaultElement: "<div>",
|
||||||
|
options: {
|
||||||
|
disabled: false,
|
||||||
|
|
||||||
|
// callbacks
|
||||||
|
create: null
|
||||||
|
},
|
||||||
|
_createWidget: function( options, element ) {
|
||||||
|
element = $( element || this.defaultElement || this )[ 0 ];
|
||||||
|
this.element = $( element );
|
||||||
|
this.uuid = uuid++;
|
||||||
|
this.eventNamespace = "." + this.widgetName + this.uuid;
|
||||||
|
this.options = $.widget.extend( {},
|
||||||
|
this.options,
|
||||||
|
this._getCreateOptions(),
|
||||||
|
options );
|
||||||
|
|
||||||
|
this.bindings = $();
|
||||||
|
this.hoverable = $();
|
||||||
|
this.focusable = $();
|
||||||
|
|
||||||
|
if ( element !== this ) {
|
||||||
|
$.data( element, this.widgetFullName, this );
|
||||||
|
this._on( true, this.element, {
|
||||||
|
remove: function( event ) {
|
||||||
|
if ( event.target === element ) {
|
||||||
|
this.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.document = $( element.style ?
|
||||||
|
// element within the document
|
||||||
|
element.ownerDocument :
|
||||||
|
// element is window or document
|
||||||
|
element.document || element );
|
||||||
|
this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
|
||||||
|
}
|
||||||
|
|
||||||
|
this._create();
|
||||||
|
this._trigger( "create", null, this._getCreateEventData() );
|
||||||
|
this._init();
|
||||||
|
},
|
||||||
|
_getCreateOptions: $.noop,
|
||||||
|
_getCreateEventData: $.noop,
|
||||||
|
_create: $.noop,
|
||||||
|
_init: $.noop,
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this._destroy();
|
||||||
|
// we can probably remove the unbind calls in 2.0
|
||||||
|
// all event bindings should go through this._on()
|
||||||
|
this.element
|
||||||
|
.unbind( this.eventNamespace )
|
||||||
|
// 1.9 BC for #7810
|
||||||
|
// TODO remove dual storage
|
||||||
|
.removeData( this.widgetName )
|
||||||
|
.removeData( this.widgetFullName )
|
||||||
|
// support: jquery <1.6.3
|
||||||
|
// http://bugs.jquery.com/ticket/9413
|
||||||
|
.removeData( $.camelCase( this.widgetFullName ) );
|
||||||
|
this.widget()
|
||||||
|
.unbind( this.eventNamespace )
|
||||||
|
.removeAttr( "aria-disabled" )
|
||||||
|
.removeClass(
|
||||||
|
this.widgetFullName + "-disabled " +
|
||||||
|
"ui-state-disabled" );
|
||||||
|
|
||||||
|
// clean up events and states
|
||||||
|
this.bindings.unbind( this.eventNamespace );
|
||||||
|
this.hoverable.removeClass( "ui-state-hover" );
|
||||||
|
this.focusable.removeClass( "ui-state-focus" );
|
||||||
|
},
|
||||||
|
_destroy: $.noop,
|
||||||
|
|
||||||
|
widget: function() {
|
||||||
|
return this.element;
|
||||||
|
},
|
||||||
|
|
||||||
|
option: function( key, value ) {
|
||||||
|
var options = key,
|
||||||
|
parts,
|
||||||
|
curOption,
|
||||||
|
i;
|
||||||
|
|
||||||
|
if ( arguments.length === 0 ) {
|
||||||
|
// don't return a reference to the internal hash
|
||||||
|
return $.widget.extend( {}, this.options );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( typeof key === "string" ) {
|
||||||
|
// handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
|
||||||
|
options = {};
|
||||||
|
parts = key.split( "." );
|
||||||
|
key = parts.shift();
|
||||||
|
if ( parts.length ) {
|
||||||
|
curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
|
||||||
|
for ( i = 0; i < parts.length - 1; i++ ) {
|
||||||
|
curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
|
||||||
|
curOption = curOption[ parts[ i ] ];
|
||||||
|
}
|
||||||
|
key = parts.pop();
|
||||||
|
if ( value === undefined ) {
|
||||||
|
return curOption[ key ] === undefined ? null : curOption[ key ];
|
||||||
|
}
|
||||||
|
curOption[ key ] = value;
|
||||||
|
} else {
|
||||||
|
if ( value === undefined ) {
|
||||||
|
return this.options[ key ] === undefined ? null : this.options[ key ];
|
||||||
|
}
|
||||||
|
options[ key ] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._setOptions( options );
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
_setOptions: function( options ) {
|
||||||
|
var key;
|
||||||
|
|
||||||
|
for ( key in options ) {
|
||||||
|
this._setOption( key, options[ key ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
_setOption: function( key, value ) {
|
||||||
|
this.options[ key ] = value;
|
||||||
|
|
||||||
|
if ( key === "disabled" ) {
|
||||||
|
this.widget()
|
||||||
|
.toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
|
||||||
|
.attr( "aria-disabled", value );
|
||||||
|
this.hoverable.removeClass( "ui-state-hover" );
|
||||||
|
this.focusable.removeClass( "ui-state-focus" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
enable: function() {
|
||||||
|
return this._setOption( "disabled", false );
|
||||||
|
},
|
||||||
|
disable: function() {
|
||||||
|
return this._setOption( "disabled", true );
|
||||||
|
},
|
||||||
|
|
||||||
|
_on: function( suppressDisabledCheck, element, handlers ) {
|
||||||
|
var delegateElement,
|
||||||
|
instance = this;
|
||||||
|
|
||||||
|
// no suppressDisabledCheck flag, shuffle arguments
|
||||||
|
if ( typeof suppressDisabledCheck !== "boolean" ) {
|
||||||
|
handlers = element;
|
||||||
|
element = suppressDisabledCheck;
|
||||||
|
suppressDisabledCheck = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no element argument, shuffle and use this.element
|
||||||
|
if ( !handlers ) {
|
||||||
|
handlers = element;
|
||||||
|
element = this.element;
|
||||||
|
delegateElement = this.widget();
|
||||||
|
} else {
|
||||||
|
// accept selectors, DOM elements
|
||||||
|
element = delegateElement = $( element );
|
||||||
|
this.bindings = this.bindings.add( element );
|
||||||
|
}
|
||||||
|
|
||||||
|
$.each( handlers, function( event, handler ) {
|
||||||
|
function handlerProxy() {
|
||||||
|
// allow widgets to customize the disabled handling
|
||||||
|
// - disabled as an array instead of boolean
|
||||||
|
// - disabled class as method for disabling individual parts
|
||||||
|
if ( !suppressDisabledCheck &&
|
||||||
|
( instance.options.disabled === true ||
|
||||||
|
$( this ).hasClass( "ui-state-disabled" ) ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return ( typeof handler === "string" ? instance[ handler ] : handler )
|
||||||
|
.apply( instance, arguments );
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy the guid so direct unbinding works
|
||||||
|
if ( typeof handler !== "string" ) {
|
||||||
|
handlerProxy.guid = handler.guid =
|
||||||
|
handler.guid || handlerProxy.guid || $.guid++;
|
||||||
|
}
|
||||||
|
|
||||||
|
var match = event.match( /^(\w+)\s*(.*)$/ ),
|
||||||
|
eventName = match[1] + instance.eventNamespace,
|
||||||
|
selector = match[2];
|
||||||
|
if ( selector ) {
|
||||||
|
delegateElement.delegate( selector, eventName, handlerProxy );
|
||||||
|
} else {
|
||||||
|
element.bind( eventName, handlerProxy );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_off: function( element, eventName ) {
|
||||||
|
eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
|
||||||
|
element.unbind( eventName ).undelegate( eventName );
|
||||||
|
},
|
||||||
|
|
||||||
|
_delay: function( handler, delay ) {
|
||||||
|
function handlerProxy() {
|
||||||
|
return ( typeof handler === "string" ? instance[ handler ] : handler )
|
||||||
|
.apply( instance, arguments );
|
||||||
|
}
|
||||||
|
var instance = this;
|
||||||
|
return setTimeout( handlerProxy, delay || 0 );
|
||||||
|
},
|
||||||
|
|
||||||
|
_hoverable: function( element ) {
|
||||||
|
this.hoverable = this.hoverable.add( element );
|
||||||
|
this._on( element, {
|
||||||
|
mouseenter: function( event ) {
|
||||||
|
$( event.currentTarget ).addClass( "ui-state-hover" );
|
||||||
|
},
|
||||||
|
mouseleave: function( event ) {
|
||||||
|
$( event.currentTarget ).removeClass( "ui-state-hover" );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_focusable: function( element ) {
|
||||||
|
this.focusable = this.focusable.add( element );
|
||||||
|
this._on( element, {
|
||||||
|
focusin: function( event ) {
|
||||||
|
$( event.currentTarget ).addClass( "ui-state-focus" );
|
||||||
|
},
|
||||||
|
focusout: function( event ) {
|
||||||
|
$( event.currentTarget ).removeClass( "ui-state-focus" );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_trigger: function( type, event, data ) {
|
||||||
|
var prop, orig,
|
||||||
|
callback = this.options[ type ];
|
||||||
|
|
||||||
|
data = data || {};
|
||||||
|
event = $.Event( event );
|
||||||
|
event.type = ( type === this.widgetEventPrefix ?
|
||||||
|
type :
|
||||||
|
this.widgetEventPrefix + type ).toLowerCase();
|
||||||
|
// the original event may come from any element
|
||||||
|
// so we need to reset the target on the new event
|
||||||
|
event.target = this.element[ 0 ];
|
||||||
|
|
||||||
|
// copy original event properties over to the new event
|
||||||
|
orig = event.originalEvent;
|
||||||
|
if ( orig ) {
|
||||||
|
for ( prop in orig ) {
|
||||||
|
if ( !( prop in event ) ) {
|
||||||
|
event[ prop ] = orig[ prop ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.element.trigger( event, data );
|
||||||
|
return !( $.isFunction( callback ) &&
|
||||||
|
callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
|
||||||
|
event.isDefaultPrevented() );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
|
||||||
|
$.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
|
||||||
|
if ( typeof options === "string" ) {
|
||||||
|
options = { effect: options };
|
||||||
|
}
|
||||||
|
var hasOptions,
|
||||||
|
effectName = !options ?
|
||||||
|
method :
|
||||||
|
options === true || typeof options === "number" ?
|
||||||
|
defaultEffect :
|
||||||
|
options.effect || defaultEffect;
|
||||||
|
options = options || {};
|
||||||
|
if ( typeof options === "number" ) {
|
||||||
|
options = { duration: options };
|
||||||
|
}
|
||||||
|
hasOptions = !$.isEmptyObject( options );
|
||||||
|
options.complete = callback;
|
||||||
|
if ( options.delay ) {
|
||||||
|
element.delay( options.delay );
|
||||||
|
}
|
||||||
|
if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
|
||||||
|
element[ method ]( options );
|
||||||
|
} else if ( effectName !== method && element[ effectName ] ) {
|
||||||
|
element[ effectName ]( options.duration, options.easing, callback );
|
||||||
|
} else {
|
||||||
|
element.queue(function( next ) {
|
||||||
|
$( this )[ method ]();
|
||||||
|
if ( callback ) {
|
||||||
|
callback.call( element[ 0 ] );
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
}));
|
2
index.js
2
index.js
@ -126,6 +126,7 @@ ghost.app().configure(function () {
|
|||||||
ghost.app().use(express.favicon(__dirname + '/content/images/favicon.ico'));
|
ghost.app().use(express.favicon(__dirname + '/content/images/favicon.ico'));
|
||||||
ghost.app().use(I18n.load(ghost));
|
ghost.app().use(I18n.load(ghost));
|
||||||
ghost.app().use(express.bodyParser({}));
|
ghost.app().use(express.bodyParser({}));
|
||||||
|
ghost.app().use(express.bodyParser({uploadDir: __dirname + '/content/images'}));
|
||||||
ghost.app().use(express.cookieParser('try-ghost'));
|
ghost.app().use(express.cookieParser('try-ghost'));
|
||||||
ghost.app().use(express.cookieSession({ cookie: { maxAge: 60000000 }}));
|
ghost.app().use(express.cookieSession({ cookie: { maxAge: 60000000 }}));
|
||||||
ghost.app().use(ghost.initTheme(ghost.app()));
|
ghost.app().use(ghost.initTheme(ghost.app()));
|
||||||
@ -195,6 +196,7 @@ when.all([ghost.init(), filters.loadCoreFilters(ghost), helpers.loadCoreHelpers(
|
|||||||
ghost.app().del('/api/v0.1/notifications/:id', authAPI, disableCachedResult, api.requestHandler(api.notifications.destroy));
|
ghost.app().del('/api/v0.1/notifications/:id', authAPI, disableCachedResult, api.requestHandler(api.notifications.destroy));
|
||||||
ghost.app().post('/api/v0.1/notifications/', authAPI, disableCachedResult, api.requestHandler(api.notifications.add));
|
ghost.app().post('/api/v0.1/notifications/', authAPI, disableCachedResult, api.requestHandler(api.notifications.add));
|
||||||
|
|
||||||
|
ghost.app().post('/ghost/upload', admin.uploader);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frontend routes..
|
* Frontend routes..
|
||||||
|
@ -25,7 +25,8 @@
|
|||||||
"bcrypt-nodejs": "0.0.3",
|
"bcrypt-nodejs": "0.0.3",
|
||||||
"node-uuid": "1.4.0",
|
"node-uuid": "1.4.0",
|
||||||
"colors": "0.6.1",
|
"colors": "0.6.1",
|
||||||
"semver": "2.1.0"
|
"semver": "2.1.0",
|
||||||
|
"fs-extra": "0.6.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"grunt": "~0.4.1",
|
"grunt": "~0.4.1",
|
||||||
|
Loading…
Reference in New Issue
Block a user