Slightly improve the media experience (#452)
* Slightly improve the media experience - Use a grid to display the list of media - Add icons for non-image media preview - Paginate the gallery - Add links to the gallery in the editor and in the profile settings to make it more discoverable when you need it Fixes #432 * Allow video and audio tags in SafeString Otherwise we can't display their preview, nor show them in articles Also show controls by default for these two elements * Show fallback images for audio and unknown files, to make them more visible * Add a new constructor to SafeString when the input is trusted and doesn't need to be escaped. And use it to generate media previews. * Make it possible to insert video/audio in articles
This commit is contained in:
+37
-25
@@ -45,6 +45,17 @@ pub enum MediaCategory {
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl MediaCategory {
|
||||
pub fn to_string(&self) -> &str {
|
||||
match *self {
|
||||
MediaCategory::Image => "image",
|
||||
MediaCategory::Audio => "audio",
|
||||
MediaCategory::Video => "video",
|
||||
MediaCategory::Unknown => "unknown",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Media {
|
||||
insert!(medias, NewMedia);
|
||||
get!(medias);
|
||||
@@ -56,6 +67,23 @@ impl Media {
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
pub fn page_for_user(conn: &Connection, user: &User, (min, max): (i32, i32)) -> Result<Vec<Media>> {
|
||||
medias::table
|
||||
.filter(medias::owner_id.eq(user.id))
|
||||
.offset(min as i64)
|
||||
.limit((max - min) as i64)
|
||||
.load::<Media>(conn)
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
pub fn count_for_user(conn: &Connection, user: &User) -> Result<i64> {
|
||||
medias::table
|
||||
.filter(medias::owner_id.eq(user.id))
|
||||
.count()
|
||||
.get_result(conn)
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
pub fn category(&self) -> MediaCategory {
|
||||
match &*self
|
||||
.file_path
|
||||
@@ -71,41 +99,25 @@ impl Media {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn preview_html(&self, conn: &Connection) -> Result<SafeString> {
|
||||
let url = self.url(conn)?;
|
||||
Ok(match self.category() {
|
||||
MediaCategory::Image => SafeString::new(&format!(
|
||||
r#"<img src="{}" alt="{}" title="{}" class=\"preview\">"#,
|
||||
url, escape(&self.alt_text), escape(&self.alt_text)
|
||||
)),
|
||||
MediaCategory::Audio => SafeString::new(&format!(
|
||||
r#"<audio src="{}" title="{}" class="preview"></audio>"#,
|
||||
url, escape(&self.alt_text)
|
||||
)),
|
||||
MediaCategory::Video => SafeString::new(&format!(
|
||||
r#"<video src="{}" title="{}" class="preview"></video>"#,
|
||||
url, escape(&self.alt_text)
|
||||
)),
|
||||
MediaCategory::Unknown => SafeString::new(""),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn html(&self, conn: &Connection) -> Result<SafeString> {
|
||||
let url = self.url(conn)?;
|
||||
Ok(match self.category() {
|
||||
MediaCategory::Image => SafeString::new(&format!(
|
||||
MediaCategory::Image => SafeString::trusted(&format!(
|
||||
r#"<img src="{}" alt="{}" title="{}">"#,
|
||||
url, escape(&self.alt_text), escape(&self.alt_text)
|
||||
)),
|
||||
MediaCategory::Audio => SafeString::new(&format!(
|
||||
r#"<audio src="{}" title="{}"></audio>"#,
|
||||
MediaCategory::Audio => SafeString::trusted(&format!(
|
||||
r#"<div class="media-preview audio"></div><audio src="{}" title="{}" controls></audio>"#,
|
||||
url, escape(&self.alt_text)
|
||||
)),
|
||||
MediaCategory::Video => SafeString::new(&format!(
|
||||
r#"<video src="{}" title="{}"></video>"#,
|
||||
MediaCategory::Video => SafeString::trusted(&format!(
|
||||
r#"<video src="{}" title="{}" controls></video>"#,
|
||||
url, escape(&self.alt_text)
|
||||
)),
|
||||
MediaCategory::Unknown => SafeString::new(""),
|
||||
MediaCategory::Unknown => SafeString::trusted(&format!(
|
||||
r#"<a href="{}" class="media-preview unknown"></a>"#,
|
||||
url,
|
||||
)),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,20 @@ lazy_static! {
|
||||
static ref CLEAN: Builder<'static> = {
|
||||
let mut b = Builder::new();
|
||||
b.add_generic_attributes(iter::once("id"))
|
||||
.add_tags(iter::once("iframe"))
|
||||
.add_tags(&[ "iframe", "video", "audio" ])
|
||||
.id_prefix(Some("postcontent-"))
|
||||
.url_relative(UrlRelative::Custom(Box::new(url_add_prefix)))
|
||||
.add_tag_attributes(
|
||||
"iframe",
|
||||
["width", "height", "src", "frameborder"].iter().map(|&v| v),
|
||||
[ "width", "height", "src", "frameborder" ].iter().map(|&v| v),
|
||||
)
|
||||
.add_tag_attributes(
|
||||
"video",
|
||||
[ "src", "title", "controls" ].iter(),
|
||||
)
|
||||
.add_tag_attributes(
|
||||
"audio",
|
||||
[ "src", "title", "controls" ].iter(),
|
||||
);
|
||||
b
|
||||
};
|
||||
@@ -53,6 +61,18 @@ impl SafeString {
|
||||
value: CLEAN.clean(&value).to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `SafeString`, but without escaping the given value.
|
||||
///
|
||||
/// Only use when you are sure you can trust the input (when the HTML
|
||||
/// is entirely generated by Plume, not depending on user-inputed data).
|
||||
/// Prefer `SafeString::new` as much as possible.
|
||||
pub fn trusted(value: impl AsRef<str>) -> Self {
|
||||
SafeString {
|
||||
value: value.as_ref().to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(&mut self, value: &str) {
|
||||
self.value = CLEAN.clean(value).to_string();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user