media-tag accessibility and UX improvements

* preview content and prompt users to describe media when uploading
* add 'alt' attributes to rendered media-tag content if it is included in the file's encrypted metadata
* add alt attributes to some related UI elements
pull/1/head
ansuz 3 years ago
parent e074b36761
commit 7231fc6926

@ -273,4 +273,13 @@
}
}
}
#cp-upload-preview-container {
max-width: 100%;
media-tag {
max-width: 100%;
& > * {
max-width: 100%;
}
}
}
}

@ -1658,6 +1658,7 @@ define([
UI.openCustomModal(modal);
};
Messages.toolbar_userMenuAlt = "User menu"; // XXX
UIElements.createUserAdminMenu = function (Common, config) {
var metadataMgr = Common.getMetadataMgr();
@ -1990,8 +1991,11 @@ define([
*/
var $displayName = $userAdmin.find('.'+displayNameCls);
$userAdmin.attr({ // XXX is this on the right element?
alt: Messages.toolbar_userMenuAlt,
});
var $avatar = $userAdmin.find('> button .cp-dropdown-button-title'); // XXX alt="User menu"
var $avatar = $userAdmin.find('> button .cp-dropdown-button-title');
var loadingAvatar;
var to;
var oldUrl = '';

@ -73,7 +73,6 @@ var factory = function () {
* @param {object} cfg Object {Plugins, allowed, download, pdf} containing infos about plugins
* @param {function} cb Callback function: (err, pluginElement) => {}
*/
// XXX add alt attributes if present in metadata
text: function (metadata, url, content, cfg, cb) {
var plainText = document.createElement('div');
plainText.className = "plain-text-reader";
@ -88,6 +87,7 @@ var factory = function () {
image: function (metadata, url, content, cfg, cb) {
var img = document.createElement('img');
img.setAttribute('src', url);
img.setAttribute('alt', metadata.alt || "");
img.blob = content;
cb(void 0, img);
},
@ -95,15 +95,19 @@ var factory = function () {
var video = document.createElement('video');
video.setAttribute('src', url);
video.setAttribute('controls', true);
// https://discuss.codecademy.com/t/can-we-use-an-alt-attribute-with-the-video-tag/300322/4
video.setAttribute('title', metadata.alt || "");
cb(void 0, video);
},
audio: function (metadata, url, content, cfg, cb) {
var audio = document.createElement('audio');
audio.setAttribute('src', url);
audio.setAttribute('controls', true);
audio.setAttribute('alt', metadata.alt || "");
cb(void 0, audio);
},
pdf: function (metadata, url, content, cfg, cb) {
// XXX alt text
var iframe = document.createElement('iframe');
if (cfg.pdf.viewer) { // PDFJS
var viewerUrl = cfg.pdf.viewer + '?file=' + url;
@ -116,6 +120,7 @@ var factory = function () {
download: function (metadata, url, content, cfg, cb) {
var btn = document.createElement('button');
btn.setAttribute('class', 'btn btn-default');
btn.setAttribute('alt', metadata.alt || "");
btn.innerHTML = '<i class="fa fa-save"></i>' + cfg.download.text + '<br>' +
(metadata.name ? '<b>' + fixHTML(metadata.name) + '</b>' : '');
btn.addEventListener('click', function () {
@ -543,7 +548,7 @@ var factory = function () {
// Process
var process = function (mediaObject, decrypted, cfg, cb) {
var metadata = decrypted.metadata;
var metadata = decrypted.metadata || {};
var blob = decrypted.content;
var mediaType = getType(mediaObject, metadata, cfg);
@ -597,6 +602,15 @@ var factory = function () {
});
};
var initHandlers = function () {
return {
'progress': [],
'complete': [],
'metadata': [],
'error': []
};
};
// Initialize a media-tag
var init = function (el, cfg) {
cfg = cfg || {};
@ -614,13 +628,7 @@ var factory = function () {
};
}
var handlers = cfg.handlers || {
'progress': [],
'complete': [],
'metadata': [],
'error': []
};
var handlers = cfg.handlers || initHandlers();
var mediaObject = el._mediaObject = {
handlers: handlers,
tag: el
@ -763,6 +771,24 @@ var factory = function () {
init.fetchDecryptedMetadata = fetchDecryptedMetadata;
init.preview = function (content, metadata, cfg, cb) {
cfg = cfg || {};
addMissingConfig(cfg, config);
var handlers = cfg.handlers || initHandlers();
var el = document.createElement('media-tag');
var mediaObject = el._mediaObject = {
handlers: handlers,
tag: el,
};
process(mediaObject, {
metadata: metadata,
content: content
}, cfg, function (err) {
if (err) { return void cb(err); }
cb(void 0, el);
});
};
return init;
};

@ -11,10 +11,12 @@ define([
'/common/hyperscript.js',
'/customize/messages.js',
'/customize/pages.js',
'/bower_components/nthen/index.js',
'/common/media-tag.js',
'/bower_components/file-saver/FileSaver.min.js',
'/bower_components/tweetnacl/nacl-fast.min.js',
], function ($, ApiConfig, FileCrypto, MakeBackup, Thumb, UI, UIElements, Util, Hash, h, Messages, Pages) {
], function ($, ApiConfig, FileCrypto, MakeBackup, Thumb, UI, UIElements, Util, Hash, h, Messages, Pages, nThen, MT) {
var Nacl = window.nacl;
var module = {};
@ -312,7 +314,11 @@ define([
});
return manualStore;
};
var fileUploadModal = function (defaultFileName, cb) {
Messages.upload_modal_alt = "Alt text"; // XXX
Messages.upload_addOptionalAlt = "Add descriptive text (optional)"; // XXX
var fileUploadModal = function (defaultFileName, cb, preview) {
var parsedName = /^(\.?.+?)(\.[^.]+)?$/.exec(defaultFileName) || [];
var ext = parsedName[2] || "";
@ -321,9 +327,15 @@ define([
// Ask for name, password and owner
var content = h('div', [
h('h4', Messages.upload_modal_title),
(preview? h('div#cp-upload-preview-container', preview): undefined),
UIElements.setHTML(h('label', {for: 'cp-upload-name'}),
Messages._getKey('upload_modal_filename', [ext])),
h('input#cp-upload-name', {type: 'text', placeholder: defaultFileName, value: defaultFileName}),
h('label', {for: 'cp-upload-alt'}, Messages.upload_addOptionalAlt), // XXX alt text for uploads
h('input#cp-upload-alt', {type: 'text', placeholder: Messages.upload_modal_alt}),
h('label', {for: 'cp-upload-password'}, Messages.addOptionalPassword),
UI.passwordInput({id: 'cp-upload-password'}),
h('span', {
@ -335,7 +347,8 @@ define([
manualStore
]);
$(content).find('#cp-upload-owned').on('change', function () {
var $content = $(content);
$content.find('#cp-upload-owned').on('change', function () {
var val = Util.isChecked($(content).find('#cp-upload-owned'));
if (val) {
$(content).find('#cp-upload-store').prop('checked', true).prop('disabled', true);
@ -348,8 +361,9 @@ define([
if (!yes) { return void cb(); }
// Get the values
var newName = $(content).find('#cp-upload-name').val();
var password = $(content).find('#cp-upload-password').val() || undefined;
var newName = $content.find('#cp-upload-name').val();
var password = $content.find('#cp-upload-password').val() || undefined;
var alt = $content.find('#cp-upload-alt').val() || undefined;
var owned = Util.isChecked($(content).find('#cp-upload-owned'));
var forceSave = owned || Util.isChecked($(content).find('#cp-upload-store'));
@ -366,7 +380,8 @@ define([
name: newName,
password: password,
owned: owned,
forceSave: forceSave
forceSave: forceSave,
alt: alt,
});
});
};
@ -437,6 +452,8 @@ define([
}
var thumb;
var preview;
var alt;
var file_arraybuffer;
var name = file.name;
var password;
@ -447,6 +464,7 @@ define([
var metadata = {
name: name,
type: type,
alt: alt,
};
if (thumb) { metadata.thumbnail = thumb; }
queue.push({
@ -486,8 +504,9 @@ define([
password = obj.password;
owned = obj.owned;
forceSave = obj.forceSave;
alt = obj.alt;
finish();
});
}, preview);
}
};
@ -495,11 +514,20 @@ define([
if (e) { console.error(e); }
file_arraybuffer = buffer;
if (!Thumb.isSupportedType(file)) { return getName(); }
nThen(function (w) {
// make a resized thumbnail from the image..
Thumb.fromBlob(file, function (e, thumb64) {
Thumb.fromBlob(file, w(function (e, thumb64) {
if (e) { console.error(e); }
if (!thumb64) { return getName(); }
if (!thumb64) { return; }
thumb = thumb64;
}));
MT.preview(buffer, {
type: file.type,
}, void 0, w(function (err, el) {
if (err) { return void console.error(err); }
preview = el;
}));
}).nThen(function () {
getName();
});
});

@ -341,6 +341,8 @@ define([
});
};
Messages.profile_defaultAlt = "Default profile picture"; // XXX
var displayAvatar = function (val) {
var sframeChan = common.getSframeChannel();
var $span = APP.$avatar;
@ -349,7 +351,7 @@ define([
$('<img>', {
src: '/customize/images/avatar.png',
title: Messages.profile_avatar,
alt: 'Avatar' // XXX translate this "Default profile picture"
alt: Messages.profile_defaultAlt,
}).appendTo($span);
return;
}

Loading…
Cancel
Save