1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-02-03 18:38:27 +01:00

Add Videos to Remarkup

Summary: Ref T6916. Added video to remarkup using D7156 as reference.

Test Plan:
  - Viewed video files (MP4, Ogg) in Safari, Chrome, Firefox (some don't work, e.g., OGG in Safari, but nothing we can really do about that).
  - Used `alt`.
  - Used `autoplay`.
  - Used `loop`.
  - Used `media=audio`.
  - Viewed file detail page.

Reviewers: nateguchi2, chad, #blessed_reviewers

Reviewed By: chad, #blessed_reviewers

Subscribers: asherkin, ivo, joshuaspence, Korvin, epriestley

Tags: #remarkup

Maniphest Tasks: T6916

Differential Revision: https://secure.phabricator.com/D11297
This commit is contained in:
epriestley 2016-06-07 10:26:00 -07:00
parent f0eb6f4fe0
commit 411cf13457
7 changed files with 173 additions and 30 deletions

View file

@ -34,9 +34,16 @@ final class PhabricatorFilesConfigOptions
'image/x-icon' => 'image/x-icon',
'image/vnd.microsoft.icon' => 'image/x-icon',
'audio/x-wav' => 'audio/x-wav',
// This is a generic type for both OGG video and OGG audio.
'application/ogg' => 'application/ogg',
'audio/x-wav' => 'audio/x-wav',
'audio/mpeg' => 'audio/mpeg',
'audio/ogg' => 'audio/ogg',
'video/mp4' => 'video/mp4',
'video/ogg' => 'video/ogg',
'video/webm' => 'video/webm',
);
$image_default = array(
@ -49,10 +56,29 @@ final class PhabricatorFilesConfigOptions
'image/vnd.microsoft.icon' => true,
);
// The "application/ogg" type is listed as both an audio and video type,
// because it may contain either type of content.
$audio_default = array(
'audio/x-wav' => true,
'application/ogg' => true,
'audio/mpeg' => true,
'audio/ogg' => true,
// These are video or ambiguous types, but can be forced to render as
// audio with `media=audio`, which seems to work properly in browsers.
// (For example, you can embed a music video as audio if you just want
// to set the mood for your task without distracting viewers.)
'video/mp4' => true,
'video/ogg' => true,
'application/ogg' => true,
);
$video_default = array(
'video/mp4' => true,
'video/ogg' => true,
'video/webm' => true,
'application/ogg' => true,
);
// largely lifted from http://en.wikipedia.org/wiki/Internet_media_type
@ -70,6 +96,7 @@ final class PhabricatorFilesConfigOptions
// movie file icon
'video/mpeg' => 'fa-file-movie-o',
'video/mp4' => 'fa-file-movie-o',
'application/ogg' => 'fa-file-movie-o',
'video/ogg' => 'fa-file-movie-o',
'video/quicktime' => 'fa-file-movie-o',
'video/webm' => 'fa-file-movie-o',
@ -122,8 +149,14 @@ final class PhabricatorFilesConfigOptions
->setSummary(pht('Configure which MIME types are audio.'))
->setDescription(
pht(
'List of MIME types which can be used to render an `%s` tag.',
'List of MIME types which can be rendered with an `%s` tag.',
'<audio />')),
$this->newOption('files.video-mime-types', 'set', $video_default)
->setSummary(pht('Configure which MIME types are video.'))
->setDescription(
pht(
'List of MIME types which can be rendered with a `%s` tag.',
'<video />')),
$this->newOption('files.icon-mime-types', 'wild', $icon_default)
->setLocked(true)
->setSummary(pht('Configure which MIME types map to which icons.'))

View file

@ -230,23 +230,34 @@ final class PhabricatorFileInfoController extends PhabricatorFileController {
$cache_string = pht('Not Applicable');
}
$finfo->addProperty(pht('Viewable Image'), $image_string);
$finfo->addProperty(pht('Cacheable'), $cache_string);
$builtin = $file->getBuiltinName();
if ($builtin === null) {
$builtin_string = pht('No');
} else {
$builtin_string = $builtin;
$types = array();
if ($file->isViewableImage()) {
$types[] = pht('Image');
}
$finfo->addProperty(pht('Builtin'), $builtin_string);
if ($file->isVideo()) {
$types[] = pht('Video');
}
$is_profile = $file->getIsProfileImage()
? pht('Yes')
: pht('No');
if ($file->isAudio()) {
$types[] = pht('Audio');
}
$finfo->addProperty(pht('Profile'), $is_profile);
if ($file->getCanCDN()) {
$types[] = pht('Can CDN');
}
$builtin = $file->getBuiltinName();
if ($builtin !== null) {
$types[] = pht('Builtin ("%s")', $builtin);
}
if ($file->getIsProfileImage()) {
$types[] = pht('Profile');
}
$types = implode(', ', $types);
$finfo->addProperty(pht('Attributes'), $types);
$storage_properties = new PHUIPropertyListView();
$box->addPropertyList($storage_properties, pht('Storage'));
@ -292,6 +303,23 @@ final class PhabricatorFileInfoController extends PhabricatorFileController {
$media = id(new PHUIPropertyListView())
->addImageContent($linked_image);
$box->addPropertyList($media);
} else if ($file->isVideo()) {
$video = phutil_tag(
'video',
array(
'controls' => 'controls',
'class' => 'phui-property-list-video',
),
phutil_tag(
'source',
array(
'src' => $file->getViewURI(),
'type' => $file->getMimeType(),
)));
$media = id(new PHUIPropertyListView())
->addImageContent($video);
$box->addPropertyList($media);
} else if ($file->isAudio()) {
$audio = phutil_tag(

View file

@ -43,12 +43,27 @@ final class PhabricatorEmbedFileRemarkupRule
$is_viewable_image = $object->isViewableImage();
$is_audio = $object->isAudio();
$is_video = $object->isVideo();
$force_link = ($options['layout'] == 'link');
$options['viewable'] = ($is_viewable_image || $is_audio);
// If a file is both audio and video, as with "application/ogg" by default,
// render it as video but allow the user to specify `media=audio` if they
// want to force it to render as audio.
if ($is_audio && $is_video) {
$media = $options['media'];
if ($media == 'audio') {
$is_video = false;
} else {
$is_audio = false;
}
}
$options['viewable'] = ($is_viewable_image || $is_audio || $is_video);
if ($is_viewable_image && !$force_link) {
return $this->renderImageFile($object, $handle, $options);
} else if ($is_video && !$force_link) {
return $this->renderVideoFile($object, $handle, $options);
} else if ($is_audio && !$force_link) {
return $this->renderAudioFile($object, $handle, $options);
} else {
@ -64,6 +79,9 @@ final class PhabricatorEmbedFileRemarkupRule
'width' => null,
'height' => null,
'alt' => null,
'media' => null,
'autoplay' => null,
'loop' => null,
);
if ($option_string) {
@ -201,22 +219,47 @@ final class PhabricatorEmbedFileRemarkupRule
PhabricatorFile $file,
PhabricatorObjectHandle $handle,
array $options) {
return $this->renderMediaFile('audio', $file, $handle, $options);
}
private function renderVideoFile(
PhabricatorFile $file,
PhabricatorObjectHandle $handle,
array $options) {
return $this->renderMediaFile('video', $file, $handle, $options);
}
private function renderMediaFile(
$tag,
PhabricatorFile $file,
PhabricatorObjectHandle $handle,
array $options) {
$is_video = ($tag == 'video');
if (idx($options, 'autoplay')) {
$preload = 'auto';
$autoplay = 'autoplay';
} else {
// If we don't preload video, the user can't see the first frame and
// has no clue what they're looking at, so always preload.
if ($is_video) {
$preload = 'auto';
} else {
$preload = 'none';
}
$autoplay = null;
}
return $this->newTag(
'audio',
$tag,
array(
'controls' => 'controls',
'preload' => $preload,
'autoplay' => $autoplay,
'loop' => idx($options, 'loop') ? 'loop' : null,
'alt' => $options['alt'],
'class' => 'phabricator-media',
),
$this->newTag(
'source',

View file

@ -802,6 +802,16 @@ final class PhabricatorFile extends PhabricatorFileDAO
return idx($mime_map, $mime_type);
}
public function isVideo() {
if (!$this->isViewableInBrowser()) {
return false;
}
$mime_map = PhabricatorEnv::getEnvConfig('files.video-mime-types');
$mime_type = $this->getMimeType();
return idx($mime_map, $mime_type);
}
public function isTransformableImage() {
// NOTE: The way the 'gd' extension works in PHP is that you can install it
// with support for only some file types, so it might be able to handle

View file

@ -410,18 +410,29 @@ You can set file display options like this:
{F123, layout=left, float, size=full, alt="a duckling"}
Valid options are:
Valid options for all files are:
- **layout** left (default), center, right, inline, link (render a link
instead of a thumbnail for images)
- **name** with `layout=link` or for non-images, use this name for the link
text
- **alt** Provide alternate text for assistive technologies.
Image files support these options:
- **float** If layout is set to left or right, the image will be floated so
text wraps around it.
- **size** thumb (default), full
- **name** with `layout=link` or for non-images, use this name for the link
text
- **width** Scale image to a specific width.
- **height** Scale image to a specific height.
- **alt** Provide alternate text for assistive technologies.
Audio and video files support these options:
- **media**: Specify the media type as `audio` or `video`. This allows you
to disambiguate how file format which may contain either audio or video
should be rendered.
- **loop**: Loop this media.
- **autoplay**: Automatically begin playing this media.
== Embedding Countdowns

View file

@ -218,6 +218,17 @@
width: 50%;
}
video.phabricator-media {
background: {$greybackground};
}
.phabricator-remarkup video {
display: block;
margin: 0 auto;
min-width: 240px;
width: 90%;
}
.phabricator-remarkup-mention-exists {
font-weight: bold;
background: #e6f3ff;

View file

@ -160,6 +160,13 @@
min-width: 240px;
}
.phui-property-list-video {
display: block;
margin: 0 auto;
width: 90%;
min-width: 240px;
}
/* When tags appear in property lists, give them a little more vertical
spacing. */
.phui-property-list-view .phui-tag-view {