UX: Lightbox support for image uploader. (#7034)
This commit is contained in:
parent
3cb676bf42
commit
58b0e945bd
|
@ -1,9 +1,25 @@
|
|||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import {
|
||||
default as computed,
|
||||
observes
|
||||
} from "ember-addons/ember-computed-decorators";
|
||||
|
||||
import UploadMixin from "discourse/mixins/upload";
|
||||
import lightbox from "discourse/lib/lightbox";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
|
||||
export default Ember.Component.extend(UploadMixin, {
|
||||
classNames: ["image-uploader"],
|
||||
infoHidden: true,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
this._applyLightbox();
|
||||
},
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
$("a.lightbox").magnificPopup("close");
|
||||
},
|
||||
|
||||
@computed("imageUrl")
|
||||
backgroundStyle(imageUrl) {
|
||||
|
@ -20,11 +36,6 @@ export default Ember.Component.extend(UploadMixin, {
|
|||
return imageUrl.split("/").slice(-1)[0];
|
||||
},
|
||||
|
||||
@computed("infoHidden", "imageBaseName")
|
||||
showInfo(infoHidden, imageBaseName) {
|
||||
return !infoHidden && imageBaseName;
|
||||
},
|
||||
|
||||
@computed("backgroundStyle")
|
||||
hasBackgroundStyle(backgroundStyle) {
|
||||
return !Ember.isEmpty(backgroundStyle.string);
|
||||
|
@ -35,16 +46,51 @@ export default Ember.Component.extend(UploadMixin, {
|
|||
},
|
||||
|
||||
uploadDone(upload) {
|
||||
this.setProperties({ imageUrl: upload.url, imageId: upload.id });
|
||||
this.setProperties({
|
||||
imageUrl: upload.url,
|
||||
imageId: upload.id,
|
||||
imageFilesize: upload.human_filesize,
|
||||
imageFilename: upload.original_filename,
|
||||
imageWidth: upload.width,
|
||||
imageHeight: upload.height
|
||||
});
|
||||
|
||||
this._applyLightbox();
|
||||
|
||||
if (this.onUploadDone) {
|
||||
this.onUploadDone(upload);
|
||||
}
|
||||
},
|
||||
|
||||
_openLightbox() {
|
||||
Ember.run.next(() => this.$("a.lightbox").magnificPopup("open"));
|
||||
},
|
||||
|
||||
_applyLightbox() {
|
||||
if (this.get("imageUrl")) Ember.run.next(() => lightbox(this.$()));
|
||||
},
|
||||
|
||||
actions: {
|
||||
toggleInfo() {
|
||||
this.toggleProperty("infoHidden");
|
||||
toggleLightbox() {
|
||||
if (this.get("imageFilename")) {
|
||||
this._openLightbox();
|
||||
} else {
|
||||
ajax(`/uploads/lookup-metadata`, {
|
||||
type: "POST",
|
||||
data: { url: this.get("imageUrl") }
|
||||
})
|
||||
.then(json => {
|
||||
this.setProperties({
|
||||
imageFilename: json.original_filename,
|
||||
imageFilesize: json.human_filesize,
|
||||
imageWidth: json.width,
|
||||
imageHeight: json.height
|
||||
});
|
||||
|
||||
this._openLightbox();
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
}
|
||||
},
|
||||
|
||||
trash() {
|
||||
|
|
|
@ -9,18 +9,28 @@
|
|||
<button {{action "trash"}} class="btn btn-danger pad-left no-text">{{d-icon "far-trash-alt"}}</button>
|
||||
{{/if}}
|
||||
|
||||
{{#if imageBaseName}}
|
||||
{{d-button icon="info-circle" class="btn image-uploader-info-btn no-text"
|
||||
title="upload_selector.filename"
|
||||
action=(action "toggleInfo")}}
|
||||
{{#if imageUrl}}
|
||||
{{d-button icon="discourse-expand"
|
||||
title='expand'
|
||||
class="btn image-uploader-lightbox-btn no-text"
|
||||
action=(action "toggleLightbox")}}
|
||||
{{/if}}
|
||||
|
||||
<span class="btn {{unless uploading 'hidden'}}">{{i18n 'upload_selector.uploading'}} {{uploadProgress}}%</span>
|
||||
</div>
|
||||
|
||||
{{#if showInfo}}
|
||||
<div class="image-uploader-info">
|
||||
<a href={{imageUrl}} target="_blank">{{imageBaseName}}</a>
|
||||
</div>
|
||||
|
||||
{{#if imageUrl}}
|
||||
<a class="lightbox"
|
||||
href={{imageUrl}}
|
||||
title={{imageFilename}}
|
||||
rel="nofollow noopener">
|
||||
|
||||
<div class="meta">
|
||||
<span class="informations">
|
||||
{{imageWidth}}x{{imageHeight}} {{imageFilesize}}
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
|
@ -3,26 +3,6 @@
|
|||
background-size: cover;
|
||||
position: relative;
|
||||
|
||||
.image-uploader-info {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
background: $primary;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
opacity: 0.6;
|
||||
|
||||
a {
|
||||
color: $secondary;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.image-upload-controls {
|
||||
display: flex;
|
||||
|
||||
|
@ -30,7 +10,7 @@
|
|||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.image-uploader-info-btn {
|
||||
.image-uploader-lightbox-btn {
|
||||
background: none;
|
||||
margin-right: 0;
|
||||
margin-left: auto;
|
||||
|
|
|
@ -86,6 +86,19 @@ class UploadsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def metadata
|
||||
params.require(:url)
|
||||
upload = Upload.get_from_url(params[:url])
|
||||
raise Discourse::NotFound unless upload
|
||||
|
||||
render json: {
|
||||
original_filename: upload.original_filename,
|
||||
width: upload.width,
|
||||
height: upload.height,
|
||||
human_filesize: upload.human_filesize
|
||||
}
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def render_404
|
||||
|
|
|
@ -7,6 +7,8 @@ require_dependency "file_store/local_store"
|
|||
require_dependency "base62"
|
||||
|
||||
class Upload < ActiveRecord::Base
|
||||
include ActionView::Helpers::NumberHelper
|
||||
|
||||
SHA1_LENGTH = 40
|
||||
|
||||
belongs_to :user
|
||||
|
@ -208,6 +210,10 @@ class Upload < ActiveRecord::Base
|
|||
upload || Upload.find_by("url LIKE ?", "%#{data[1]}")
|
||||
end
|
||||
|
||||
def human_filesize
|
||||
number_to_human_size(self.filesize)
|
||||
end
|
||||
|
||||
def self.migrate_to_new_scheme(limit = nil)
|
||||
problems = []
|
||||
|
||||
|
|
|
@ -9,5 +9,6 @@ class UploadSerializer < ApplicationSerializer
|
|||
:thumbnail_height,
|
||||
:extension,
|
||||
:short_url,
|
||||
:retain_hours
|
||||
:retain_hours,
|
||||
:human_filesize
|
||||
end
|
||||
|
|
|
@ -206,6 +206,7 @@ en:
|
|||
us_west_2: "US West (Oregon)"
|
||||
|
||||
edit: "edit the title and category of this topic"
|
||||
expand: "Expand"
|
||||
not_implemented: "That feature hasn't been implemented yet, sorry!"
|
||||
no_value: "No"
|
||||
yes_value: "Yes"
|
||||
|
@ -1569,7 +1570,6 @@ en:
|
|||
select_file: "Select File"
|
||||
image_link: "link your image will point to"
|
||||
default_image_alt_text: image
|
||||
filename: "Filename"
|
||||
|
||||
search:
|
||||
sort_by: "Sort by"
|
||||
|
|
|
@ -461,6 +461,7 @@ Discourse::Application.routes.draw do
|
|||
get "stylesheets/:name.css" => "stylesheets#show", constraints: { name: /[-a-z0-9_]+/ }
|
||||
get "theme-javascripts/:digest.js" => "theme_javascripts#show", constraints: { digest: /\h{40}/ }
|
||||
|
||||
post "uploads/lookup-metadata" => "uploads#metadata"
|
||||
post "uploads" => "uploads#create"
|
||||
post "uploads/lookup-urls" => "uploads#lookup_urls"
|
||||
|
||||
|
|
|
@ -6,8 +6,6 @@ require_dependency 'pretty_text'
|
|||
require_dependency 'quote_comparer'
|
||||
|
||||
class CookedPostProcessor
|
||||
include ActionView::Helpers::NumberHelper
|
||||
|
||||
INLINE_ONEBOX_LOADING_CSS_CLASS = "inline-onebox-loading"
|
||||
INLINE_ONEBOX_CSS_CLASS = "inline-onebox"
|
||||
LOADING_SIZE = 10
|
||||
|
@ -422,7 +420,7 @@ class CookedPostProcessor
|
|||
|
||||
filename = get_filename(upload, img["src"])
|
||||
informations = "#{original_width}×#{original_height}"
|
||||
informations << " #{number_to_human_size(upload.filesize)}" if upload
|
||||
informations << " #{upload.human_filesize}" if upload
|
||||
|
||||
a["title"] = CGI.escapeHTML(img["title"] || filename)
|
||||
|
||||
|
|
|
@ -283,4 +283,51 @@ describe UploadsController do
|
|||
expect(result[0]["url"]).to eq(upload.url)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#metadata' do
|
||||
let(:upload) { Fabricate(:upload) }
|
||||
|
||||
describe 'when url is missing' do
|
||||
it 'should return the right response' do
|
||||
post "/uploads/lookup-metadata.json"
|
||||
|
||||
expect(response.status).to eq(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when not signed in' do
|
||||
it 'should return the right response' do
|
||||
post "/uploads/lookup-metadata.json", params: { url: upload.url }
|
||||
|
||||
expect(response.status).to eq(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when signed in' do
|
||||
before do
|
||||
sign_in(Fabricate(:user))
|
||||
end
|
||||
|
||||
describe 'when url is invalid' do
|
||||
it 'should return the right response' do
|
||||
post "/uploads/lookup-metadata.json", params: { url: 'abc' }
|
||||
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
end
|
||||
|
||||
it "should return the right response" do
|
||||
post "/uploads/lookup-metadata.json", params: { url: upload.url }
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(result["original_filename"]).to eq(upload.original_filename)
|
||||
expect(result["width"]).to eq(upload.width)
|
||||
expect(result["height"]).to eq(upload.height)
|
||||
expect(result["human_filesize"]).to eq(upload.human_filesize)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,18 +17,12 @@ componentTest("with image", {
|
|||
"it displays the trash icon"
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
this.$(".image-uploader-info").length,
|
||||
0,
|
||||
"it does not display the image info"
|
||||
);
|
||||
|
||||
await click(".image-uploader-info-btn");
|
||||
await click(".image-uploader-lightbox-btn");
|
||||
|
||||
assert.equal(
|
||||
this.$(".image-uploader-info").length,
|
||||
$(".mfp-container").length,
|
||||
1,
|
||||
"it displays the image info"
|
||||
"it displays the image lightbox"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -50,9 +44,9 @@ componentTest("without image", {
|
|||
);
|
||||
|
||||
assert.equal(
|
||||
this.$(".image-uploader-info-btn").length,
|
||||
this.$(".image-uploader-lightbox-btn").length,
|
||||
0,
|
||||
"it does not display the image info button toggle"
|
||||
"it does not display the button to open image lightbox"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -536,6 +536,15 @@ export default function() {
|
|||
});
|
||||
});
|
||||
|
||||
this.post("/uploads/lookup-metadata", () => {
|
||||
return response(200, {
|
||||
imageFilename: "somefile.png",
|
||||
imageFilesize: "10 KB",
|
||||
imageWidth: "1",
|
||||
imageHeight: "1"
|
||||
});
|
||||
});
|
||||
|
||||
this.get("/inline-onebox", request => {
|
||||
if (
|
||||
request.queryParams.urls.includes(
|
||||
|
|
Loading…
Reference in New Issue