diff --git a/customize.dist/src/less2/include/modals-ui-elements.less b/customize.dist/src/less2/include/modals-ui-elements.less
index 7ec19a699..94ec06cc0 100644
--- a/customize.dist/src/less2/include/modals-ui-elements.less
+++ b/customize.dist/src/less2/include/modals-ui-elements.less
@@ -273,4 +273,19 @@
}
}
}
+ #cp-upload-preview-container {
+ max-width: 100%;
+ max-height: 300px;
+ overflow: auto;
+ media-tag {
+ max-width: 100%;
+ iframe {
+ // pdfs don't take the full width unless we tell them to
+ width: 100%;
+ }
+ & > * {
+ max-width: 100%;
+ }
+ }
+ }
}
diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js
index 5bc8bf4f6..f77a9d422 100644
--- a/www/common/common-ui-elements.js
+++ b/www/common/common-ui-elements.js
@@ -1658,6 +1658,7 @@ define([
UI.openCustomModal(modal);
};
+ Messages.toolbar_userMenuAlt = "User menu"; // XXX
UIElements.createUserAdminMenu = function (Common, config) {
var metadataMgr = Common.getMetadataMgr();
@@ -1990,6 +1991,9 @@ 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');
var loadingAvatar;
diff --git a/www/common/media-tag.js b/www/common/media-tag.js
index d1a5ebcda..e8b35a47e 100644
--- a/www/common/media-tag.js
+++ b/www/common/media-tag.js
@@ -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 = '' + cfg.download.text + '
' +
(metadata.name ? '' + fixHTML(metadata.name) + '' : '');
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;
};
diff --git a/www/common/sframe-common-file.js b/www/common/sframe-common-file.js
index 1286da14d..a56313444 100644
--- a/www/common/sframe-common-file.js
+++ b/www/common/sframe-common-file.js
@@ -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(); }
- // make a resized thumbnail from the image..
- Thumb.fromBlob(file, function (e, thumb64) {
- if (e) { console.error(e); }
- if (!thumb64) { return getName(); }
- thumb = thumb64;
+ nThen(function (w) {
+ // make a resized thumbnail from the image..
+ Thumb.fromBlob(file, w(function (e, thumb64) {
+ if (e) { console.error(e); }
+ 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();
});
});
diff --git a/www/profile/inner.js b/www/profile/inner.js
index c63b72e99..284b19114 100644
--- a/www/profile/inner.js
+++ b/www/profile/inner.js
@@ -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([
$('', {
src: '/customize/images/avatar.png',
title: Messages.profile_avatar,
- alt: 'Avatar' // XXX translate this "Default profile picture"
+ alt: Messages.profile_defaultAlt,
}).appendTo($span);
return;
}