diff --git a/ghost/admin/assets/img/AddImage.png b/ghost/admin/assets/img/AddImage.png new file mode 100644 index 0000000000..8bcf8b33dc Binary files /dev/null and b/ghost/admin/assets/img/AddImage.png differ diff --git a/ghost/admin/assets/img/returnImage.png b/ghost/admin/assets/img/returnImage.png new file mode 100644 index 0000000000..a59e8198d5 Binary files /dev/null and b/ghost/admin/assets/img/returnImage.png differ diff --git a/ghost/admin/assets/lib/uploader.js b/ghost/admin/assets/lib/uploader.js new file mode 100644 index 0000000000..7ffdd43600 --- /dev/null +++ b/ghost/admin/assets/lib/uploader.js @@ -0,0 +1,177 @@ +/*global jQuery, Ghost, document, Image, window */ +(function ($) { + "use strict"; + + var UploadUi, + $loader = '' + + '
Add image
' + + '' + + '' + + '', + $progress = $('
', { + "class" : "js-upload-progress progress progress-success active", + "style": "opacity:0", + "role": "progressbar", + "aria-valuemin": "0", + "aria-valuemax": "100" + }).append($("
", { + "class": "js-upload-progress-bar bar", + "style": "width:0%" + })); + + UploadUi = function ($dropzone, settings) { + var source, + $link = $('' + + 'add, edit'), + $back = $('' + + 'add, edit'); + + $.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(''); + 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(''); + 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)); \ No newline at end of file diff --git a/ghost/admin/assets/sass/layouts/editor.scss b/ghost/admin/assets/sass/layouts/editor.scss index 6e5732e24c..042f4eb5b8 100644 --- a/ghost/admin/assets/sass/layouts/editor.scss +++ b/ghost/admin/assets/sass/layouts/editor.scss @@ -117,7 +117,7 @@ padding: 5px; &:hover { - @include icon($i-question, '', $brown) + @include icon($i-question, '', $brown); } } @@ -255,7 +255,6 @@ @include breakpoint($netbook) {padding-top: 20px;} @include breakpoint($mobile) {padding: 15px;} } - } // Special case, when scrolling, add shadows to content headers. @@ -331,11 +330,21 @@ text-align: center; } } - + a { + &.image-edit { + width: 16px; + height: 16px; + } + } img { width: 100%; height: auto; } + // prevent uploaded image from being streched in editor + .pre-image-uploader img { + width: auto; + } + } diff --git a/ghost/admin/assets/sass/modules/global.scss b/ghost/admin/assets/sass/modules/global.scss index b196eac15b..02be82aeee 100644 --- a/ghost/admin/assets/sass/modules/global.scss +++ b/ghost/admin/assets/sass/modules/global.scss @@ -1135,6 +1135,16 @@ main { color: $brown; 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 { @include icon($i-camera, 12px); @@ -1146,9 +1156,10 @@ main { right: 0; color: $brown; text-decoration: none; + } - .fileupload { + input { position: absolute; right: 0; margin: 0; @@ -1162,7 +1173,7 @@ main { .progress { position: relative; - top: -39px; + top: -22px; margin: auto; margin-bottom: -12px; display: block; @@ -1186,7 +1197,61 @@ main { 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 diff --git a/ghost/admin/assets/vendor/showdown/extensions/ghostdown.js b/ghost/admin/assets/vendor/showdown/extensions/ghostdown.js index 6d8862b3ed..984c044974 100644 --- a/ghost/admin/assets/vendor/showdown/extensions/ghostdown.js +++ b/ghost/admin/assets/vendor/showdown/extensions/ghostdown.js @@ -9,6 +9,7 @@ return '
' + '' + '
Add image of ' + alt + '
' + + '' + '' + '' + '' + diff --git a/ghost/admin/tpl/settings/general.hbs b/ghost/admin/tpl/settings/general.hbs index 0a89daf1bb..e9166ccf71 100644 --- a/ghost/admin/tpl/settings/general.hbs +++ b/ghost/admin/tpl/settings/general.hbs @@ -15,13 +15,19 @@
- logo +
+ + +

Display a logo on your site in place of blog title

- logo +
+ + +

The icon for your blog, used in your browser tab and elsewhere

diff --git a/ghost/admin/views/editor.js b/ghost/admin/views/editor.js index e951deb907..010fdd7493 100644 --- a/ghost/admin/views/editor.js +++ b/ghost/admin/views/editor.js @@ -303,6 +303,7 @@ var view = this, preview = document.getElementsByClassName('rendered-markdown')[0]; preview.innerHTML = this.converter.makeHtml(this.editor.getValue()); + view.$('.js-drop-zone').upload({editor: true}); Countable.once(preview, function (counter) { view.$('.entry-word-count').text(counter.words + ' words'); view.$('.entry-character-count').text(counter.characters + ' characters'); diff --git a/ghost/admin/views/settings.js b/ghost/admin/views/settings.js index ae6027ed7b..8da3272457 100644 --- a/ghost/admin/views/settings.js +++ b/ghost/admin/views/settings.js @@ -124,7 +124,10 @@ saveSettings: function () { this.model.save({ 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, error: this.saveError @@ -137,6 +140,12 @@ var settings = this.model.toJSON(); this.$('#blog-title').val(settings.title); this.$('#email-address').val(settings.email); + }, + + afterRender: function () { + this.$el.attr('id', this.id); + this.$el.addClass('active'); + this.$('.js-drop-zone').upload(); } });