This commit is contained in:
Markos Gogoulos
2026-03-13 09:51:43 +02:00
parent 0c8a464845
commit e1e04ea93a
11 changed files with 398 additions and 233 deletions

View File

@@ -88,3 +88,27 @@ Configure default display options for auto-converted URLs:
### For Students (Display) ### For Students (Display)
When content is viewed, the Filter will ensure the video is loaded securely via LTI 1.3, authenticating the user with MediaCMS automatically. When content is viewed, the Filter will ensure the video is loaded securely via LTI 1.3, authenticating the user with MediaCMS automatically.
## Build instructions / Developing with the plugin
two types of changes: php (no build), js (build with npx grunt amd)
needs moodle/
npx version, dependencies etc
1. make changes here in lms-plugins/mediacms-moodle
2. copy to moodle
3. run `npx grunt amd` in moodle to build the JS files
4. from moodle copy back
sudo cp -r ~/mediacms/lms-plugins/mediacms-moodle/tiny/mediacms/ -r ~/mediacms/moodle/public/lib/editor/tiny/plugins/
5. cd ~/mediacms/moodle/public/lib/editor/tiny/plugins/mediacms/
npx grunt amd
6.
cp files back...
sudo cp -r /home/user/mediacms/moodle/public/lib/editor/tiny/plugins/mediacms /home/user/mediacms/lms-plugins/mediacms-moodle/tiny/
php admin/cli/purge_caches.php after

View File

@@ -31,6 +31,7 @@ global $DB, $PAGE, $OUTPUT, $SITE, $USER, $SESSION;
require_login(); require_login();
$courseid = required_param('courseid', PARAM_INT); $courseid = required_param('courseid', PARAM_INT);
$action = optional_param('action', '', PARAM_TEXT);
$ltitoolid = get_config('filter_mediacms', 'ltitoolid'); $ltitoolid = get_config('filter_mediacms', 'ltitoolid');
if (empty($ltitoolid)) { if (empty($ltitoolid)) {
@@ -68,7 +69,11 @@ $PAGE->set_title('MediaCMS Select Media');
$typeconfig = lti_get_type_type_config($type->id); $typeconfig = lti_get_type_type_config($type->id);
// Store redirect_path in session — lti_auth.php picks it up after the OIDC roundtrip. // Store redirect_path in session — lti_auth.php picks it up after the OIDC roundtrip.
$SESSION->mediacms_launch_customparams = 'redirect_path=/lti/select-media/?mode=lms_embed_mode'; if ($action === 'upload') {
$SESSION->mediacms_launch_customparams = 'redirect_path=/upload';
} else {
$SESSION->mediacms_launch_customparams = 'redirect_path=/lti/select-media/?mode=lms_embed_mode';
}
$content = lti_initiate_login($course->id, 0, null, $typeconfig, null, 'MediaCMS Select Media'); $content = lti_initiate_login($course->id, 0, null, $typeconfig, null, 'MediaCMS Select Media');

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +1,3 @@
define("tiny_mediacms/selectors",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;return _exports.default={IMAGE:{actions:{submit:".tiny_imagecms_urlentrysubmit",imageBrowser:".openimagecmsbrowser",addUrl:".tiny_imagecms_addurl",deleteImage:".tiny_imagecms_deleteicon"},elements:{form:"form.tiny_imagecms_form",alignSettings:".tiny_imagecms_button",alt:".tiny_imagecms_altentry",altWarning:".tiny_imagecms_altwarning",height:".tiny_imagecms_heightentry",width:".tiny_imagecms_widthentry",url:".tiny_imagecms_urlentry",urlWarning:".tiny_imagecms_urlwarning",size:".tiny_imagecms_size",presentation:".tiny_imagecms_presentation",constrain:".tiny_imagecms_constrain",customStyle:".tiny_imagecms_customstyle",preview:".tiny_imagecms_preview",previewBox:".tiny_imagecms_preview_box",loaderIcon:".tiny_imagecms_loader",loaderIconContainer:".tiny_imagecms_loader_container",insertImage:".tiny_imagecms_insert_image",modalFooter:".modal-footer",dropzoneContainer:".tiny_imagecms_dropzone_container",fileInput:"#tiny_imagecms_fileinput",fileNameLabel:".tiny_imagecms_filename",sizeOriginal:".tiny_imagecms_sizeoriginal",sizeCustom:".tiny_imagecms_sizecustom",properties:".tiny_imagecms_properties"},styles:{responsive:"img-fluid"}},EMBED:{actions:{submit:".tiny_mediacms_submit",mediaBrowser:".openmediacmsbrowser"},elements:{form:"form.tiny_mediacms_form",source:".tiny_mediacms_source",track:".tiny_mediacms_track",mediaSource:".tiny_mediacms_media_source",linkSource:".tiny_mediacms_link_source",linkSize:".tiny_mediacms_link_size",posterSource:".tiny_mediacms_poster_source",posterSize:".tiny_mediacms_poster_size",displayOptions:".tiny_mediacms_display_options",name:".tiny_mediacms_name_entry",title:".tiny_mediacms_title_entry",url:".tiny_mediacms_url_entry",width:".tiny_mediacms_width_entry",height:".tiny_mediacms_height_entry",trackSource:".tiny_mediacms_track_source",trackKind:".tiny_mediacms_track_kind_entry",trackLabel:".tiny_mediacms_track_label_entry",trackLang:".tiny_mediacms_track_lang_entry",trackDefault:".tiny_mediacms_track_default",mediaControl:".tiny_mediacms_controls",mediaAutoplay:".tiny_mediacms_autoplay",mediaMute:".tiny_mediacms_mute",mediaLoop:".tiny_mediacms_loop",advancedSettings:".tiny_mediacms_advancedsettings",linkTab:'li[data-medium-type="link"]',videoTab:'li[data-medium-type="video"]',audioTab:'li[data-medium-type="audio"]',linkPane:'.tab-pane[data-medium-type="link"]',videoPane:'.tab-pane[data-medium-type="video"]',audioPane:'.tab-pane[data-medium-type="audio"]',trackSubtitlesTab:'li[data-track-kind="subtitles"]',trackCaptionsTab:'li[data-track-kind="captions"]',trackDescriptionsTab:'li[data-track-kind="descriptions"]',trackChaptersTab:'li[data-track-kind="chapters"]',trackMetadataTab:'li[data-track-kind="metadata"]',trackSubtitlesPane:'.tab-pane[data-track-kind="subtitles"]',trackCaptionsPane:'.tab-pane[data-track-kind="captions"]',trackDescriptionsPane:'.tab-pane[data-track-kind="descriptions"]',trackChaptersPane:'.tab-pane[data-track-kind="chapters"]',trackMetadataPane:'.tab-pane[data-track-kind="metadata"]'},mediaTypes:{link:"LINK",video:"VIDEO",audio:"AUDIO"},trackKinds:{subtitles:"SUBTITLES",captions:"CAPTIONS",descriptions:"DESCRIPTIONS",chapters:"CHAPTERS",metadata:"METADATA"}},IFRAME:{actions:{remove:'[data-action="remove"]'},elements:{form:"form.tiny_iframecms_form",url:".tiny_iframecms_url",urlWarning:".tiny_iframecms_url_warning",showTitle:".tiny_iframecms_showtitle",linkTitle:".tiny_iframecms_linktitle",showRelated:".tiny_iframecms_showrelated",showUserAvatar:".tiny_iframecms_showuseravatar",textLinkOnly:".tiny_iframecms_textlinkonly",startAt:".tiny_iframecms_startat",startAtEnabled:".tiny_iframecms_startat_enabled",aspectRatio:".tiny_iframecms_aspectratio",width:".tiny_iframecms_width",height:".tiny_iframecms_height",preview:".tiny_iframecms_preview",previewContainer:".tiny_iframecms_preview_container",tabs:".tiny_iframecms_tabs",tabUrlBtn:".tiny_iframecms_tab_url_btn",tabIframeLibraryBtn:".tiny_iframecms_tab_iframe_library_btn",paneUrl:".tiny_iframecms_pane_url",paneIframeLibrary:".tiny_iframecms_pane_iframe_library",iframeLibraryContainer:".tiny_iframecms_iframe_library_container",iframeLibraryPlaceholder:".tiny_iframecms_iframe_library_placeholder",iframeLibraryLoading:".tiny_iframecms_iframe_library_loading",iframeLibraryFrame:".tiny_iframecms_iframe_library_frame"},aspectRatios:{"16:9":{width:560,height:315},"4:3":{width:560,height:420},"1:1":{width:400,height:400},custom:null}}},_exports.default})); define("tiny_mediacms/selectors",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;return _exports.default={IMAGE:{actions:{submit:".tiny_imagecms_urlentrysubmit",imageBrowser:".openimagecmsbrowser",addUrl:".tiny_imagecms_addurl",deleteImage:".tiny_imagecms_deleteicon"},elements:{form:"form.tiny_imagecms_form",alignSettings:".tiny_imagecms_button",alt:".tiny_imagecms_altentry",altWarning:".tiny_imagecms_altwarning",height:".tiny_imagecms_heightentry",width:".tiny_imagecms_widthentry",url:".tiny_imagecms_urlentry",urlWarning:".tiny_imagecms_urlwarning",size:".tiny_imagecms_size",presentation:".tiny_imagecms_presentation",constrain:".tiny_imagecms_constrain",customStyle:".tiny_imagecms_customstyle",preview:".tiny_imagecms_preview",previewBox:".tiny_imagecms_preview_box",loaderIcon:".tiny_imagecms_loader",loaderIconContainer:".tiny_imagecms_loader_container",insertImage:".tiny_imagecms_insert_image",modalFooter:".modal-footer",dropzoneContainer:".tiny_imagecms_dropzone_container",fileInput:"#tiny_imagecms_fileinput",fileNameLabel:".tiny_imagecms_filename",sizeOriginal:".tiny_imagecms_sizeoriginal",sizeCustom:".tiny_imagecms_sizecustom",properties:".tiny_imagecms_properties"},styles:{responsive:"img-fluid"}},EMBED:{actions:{submit:".tiny_mediacms_submit",mediaBrowser:".openmediacmsbrowser"},elements:{form:"form.tiny_mediacms_form",source:".tiny_mediacms_source",track:".tiny_mediacms_track",mediaSource:".tiny_mediacms_media_source",linkSource:".tiny_mediacms_link_source",linkSize:".tiny_mediacms_link_size",posterSource:".tiny_mediacms_poster_source",posterSize:".tiny_mediacms_poster_size",displayOptions:".tiny_mediacms_display_options",name:".tiny_mediacms_name_entry",title:".tiny_mediacms_title_entry",url:".tiny_mediacms_url_entry",width:".tiny_mediacms_width_entry",height:".tiny_mediacms_height_entry",trackSource:".tiny_mediacms_track_source",trackKind:".tiny_mediacms_track_kind_entry",trackLabel:".tiny_mediacms_track_label_entry",trackLang:".tiny_mediacms_track_lang_entry",trackDefault:".tiny_mediacms_track_default",mediaControl:".tiny_mediacms_controls",mediaAutoplay:".tiny_mediacms_autoplay",mediaMute:".tiny_mediacms_mute",mediaLoop:".tiny_mediacms_loop",advancedSettings:".tiny_mediacms_advancedsettings",linkTab:'li[data-medium-type="link"]',videoTab:'li[data-medium-type="video"]',audioTab:'li[data-medium-type="audio"]',linkPane:'.tab-pane[data-medium-type="link"]',videoPane:'.tab-pane[data-medium-type="video"]',audioPane:'.tab-pane[data-medium-type="audio"]',trackSubtitlesTab:'li[data-track-kind="subtitles"]',trackCaptionsTab:'li[data-track-kind="captions"]',trackDescriptionsTab:'li[data-track-kind="descriptions"]',trackChaptersTab:'li[data-track-kind="chapters"]',trackMetadataTab:'li[data-track-kind="metadata"]',trackSubtitlesPane:'.tab-pane[data-track-kind="subtitles"]',trackCaptionsPane:'.tab-pane[data-track-kind="captions"]',trackDescriptionsPane:'.tab-pane[data-track-kind="descriptions"]',trackChaptersPane:'.tab-pane[data-track-kind="chapters"]',trackMetadataPane:'.tab-pane[data-track-kind="metadata"]'},mediaTypes:{link:"LINK",video:"VIDEO",audio:"AUDIO"},trackKinds:{subtitles:"SUBTITLES",captions:"CAPTIONS",descriptions:"DESCRIPTIONS",chapters:"CHAPTERS",metadata:"METADATA"}},IFRAME:{actions:{remove:'[data-action="remove"]'},elements:{form:"form.tiny_iframecms_form",url:".tiny_iframecms_url",urlWarning:".tiny_iframecms_url_warning",showTitle:".tiny_iframecms_showtitle",linkTitle:".tiny_iframecms_linktitle",showRelated:".tiny_iframecms_showrelated",showUserAvatar:".tiny_iframecms_showuseravatar",textLinkOnly:".tiny_iframecms_textlinkonly",startAt:".tiny_iframecms_startat",startAtEnabled:".tiny_iframecms_startat_enabled",aspectRatio:".tiny_iframecms_aspectratio",width:".tiny_iframecms_width",height:".tiny_iframecms_height",preview:".tiny_iframecms_preview",previewContainer:".tiny_iframecms_preview_container",tabs:".tiny_iframecms_tabs",tabUrlBtn:".tiny_iframecms_tab_url_btn",tabIframeLibraryBtn:".tiny_iframecms_tab_iframe_library_btn",tabUploadMediaBtn:".tiny_iframecms_upload_media_btn",paneUrl:".tiny_iframecms_pane_url",paneIframeLibrary:".tiny_iframecms_pane_iframe_library",iframeLibraryContainer:".tiny_iframecms_iframe_library_container",iframeLibraryPlaceholder:".tiny_iframecms_iframe_library_placeholder",iframeLibraryLoading:".tiny_iframecms_iframe_library_loading",iframeLibraryFrame:".tiny_iframecms_iframe_library_frame"},aspectRatios:{"16:9":{width:560,height:315},"4:3":{width:560,height:420},"1:1":{width:400,height:400},custom:null}}},_exports.default}));
//# sourceMappingURL=selectors.min.js.map //# sourceMappingURL=selectors.min.js.map

File diff suppressed because one or more lines are too long

View File

@@ -936,6 +936,87 @@ export default class IframeEmbed {
}); });
} }
// Upload media button handler
const uploadMediaBtn = form.querySelector(
Selectors.IFRAME.elements.tabUploadMediaBtn,
);
if (uploadMediaBtn) {
uploadMediaBtn.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
// Ensure we are on the iframe library tab
this.switchToIframeLibraryTab(root);
// Get the upload URL, preferring LTI launch if available
let uploadUrl = '';
const ltiConfig = getLti(this.editor);
if (ltiConfig && ltiConfig.contentItemUrl) {
try {
const urlObj = new URL(ltiConfig.contentItemUrl);
urlObj.searchParams.set('action', 'upload');
uploadUrl = urlObj.toString();
} catch (err) {
// Ignore errors silently for Moodle coding style
}
}
if (!uploadUrl) {
// Get the MediaCMS base URL from plugin data configuration
let baseUrl = '';
try {
const editorData = getData(this.editor);
if (editorData && editorData.mediacmsBaseUrl) {
baseUrl = editorData.mediacmsBaseUrl;
}
} catch (err) {
// Ignore errors silently for Moodle coding style
}
// Fallback to iframeLibraryUrl if not set
if (!baseUrl) {
try {
const urlObj = new URL(this.iframeLibraryUrl);
baseUrl = `${urlObj.protocol}//${urlObj.host}`;
} catch (err) {
// Ignore errors silently for Moodle coding style
}
}
// Ensure no trailing slash before appending /upload
baseUrl = baseUrl.replace(/\/$/, '');
uploadUrl = baseUrl ? `${baseUrl}/upload` : '';
}
if (uploadUrl) {
const pane = form.querySelector(Selectors.IFRAME.elements.paneIframeLibrary);
if (pane) {
const iframeEl = pane.querySelector(Selectors.IFRAME.elements.iframeLibraryFrame);
const placeholderEl = pane.querySelector(Selectors.IFRAME.elements.iframeLibraryPlaceholder);
const loadingEl = pane.querySelector(Selectors.IFRAME.elements.iframeLibraryLoading);
if (placeholderEl) {
placeholderEl.classList.add('d-none');
}
if (loadingEl) {
loadingEl.classList.remove('d-none');
}
if (iframeEl) {
iframeEl.classList.add('d-none');
const loadHandler = () => {
this.handleIframeLibraryLoad(root);
iframeEl.removeEventListener('load', loadHandler);
};
iframeEl.addEventListener('load', loadHandler);
iframeEl.src = uploadUrl;
}
}
}
});
}
// Iframe library event listeners // Iframe library event listeners
this.registerIframeLibraryEventListeners(root); this.registerIframeLibraryEventListeners(root);

View File

@@ -143,6 +143,7 @@ export default {
tabs: '.tiny_iframecms_tabs', tabs: '.tiny_iframecms_tabs',
tabUrlBtn: '.tiny_iframecms_tab_url_btn', tabUrlBtn: '.tiny_iframecms_tab_url_btn',
tabIframeLibraryBtn: '.tiny_iframecms_tab_iframe_library_btn', tabIframeLibraryBtn: '.tiny_iframecms_tab_iframe_library_btn',
tabUploadMediaBtn: '.tiny_iframecms_upload_media_btn',
paneUrl: '.tiny_iframecms_pane_url', paneUrl: '.tiny_iframecms_pane_url',
paneIframeLibrary: '.tiny_iframecms_pane_iframe_library', paneIframeLibrary: '.tiny_iframecms_pane_iframe_library',
// Iframe library elements // Iframe library elements

View File

@@ -149,9 +149,9 @@ $string['librarysortnewest'] = 'Newest first';
$string['librarysortoldest'] = 'Oldest first'; $string['librarysortoldest'] = 'Oldest first';
$string['librarysorttitle'] = 'Title A-Z'; $string['librarysorttitle'] = 'Title A-Z';
$string['librarysortviews'] = 'Most views'; $string['librarysortviews'] = 'Most views';
$string['libraryloading'] = 'Loading videos...'; $string['libraryloading'] = 'Loading...';
$string['libraryempty'] = 'No videos found'; $string['libraryempty'] = 'Not found';
$string['libraryerror'] = 'Failed to load videos'; $string['libraryerror'] = 'Failed to load';
$string['libraryretry'] = 'Retry'; $string['libraryretry'] = 'Retry';
$string['libraryprev'] = 'Previous'; $string['libraryprev'] = 'Previous';
$string['librarynext'] = 'Next'; $string['librarynext'] = 'Next';

View File

@@ -47,6 +47,12 @@
{{#str}} tabembedurl, tiny_mediacms {{/str}} {{#str}} tabembedurl, tiny_mediacms {{/str}}
</button> </button>
</li> </li>
<!-- Upload media button -->
<li class="nav-item ms-auto ml-auto" role="presentation">
<button class="btn btn-outline-secondary btn-sm mt-1 me-2 mr-2 tiny_iframecms_upload_media_btn" type="button" title="Upload media">
<svg xmlns="http://www.w3.org/2000/svg" height="18px" viewBox="0 -960 960 960" width="18px" fill="currentColor" style="vertical-align: text-bottom; margin-right: 4px;"><path d="M440-440H280v-80h160v-160h80v160h160v80H520v160h-80v-160ZM160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h480q33 0 56.5 23.5T720-720v180l160-160v440L720-420v180q0 33-23.5 56.5T640-160H160Zm0-80h480v-480H160v480Zm0 0v-480 480Z"/></svg>Upload media
</button>
</li>
</ul> </ul>
<!-- Tab Content --> <!-- Tab Content -->

View File

@@ -1,225 +1,273 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load i18n %} {% load i18n %}
{% load static %}
{% load static %} {% load custom_filters %}
{% block headtitle %}Add new media - {{PORTAL_NAME}}{% endblock headtitle %} {% block headtitle %}Add new media - {{PORTAL_NAME}}{% endblock headtitle %}
{% load custom_filters %}
{% block externallinks %}
{% block externallinks %} {% if LOAD_FROM_CDN %}
{% if LOAD_FROM_CDN %} <link href="https://cdnjs.cloudflare.com/ajax/libs/file-uploader/5.13.0/fine-uploader.min.js" rel="preload" as="script">
<link href="https://cdnjs.cloudflare.com/ajax/libs/file-uploader/5.13.0/fine-uploader.min.js" rel="preload" as="script"> <script src="https://cdnjs.cloudflare.com/ajax/libs/file-uploader/5.13.0/fine-uploader.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/file-uploader/5.13.0/fine-uploader.min.js"></script> {% else %}
{% else %} <link href="{% static "lib/file-uploader/5.13.0/fine-uploader.min.js" %}" rel="preload" as="script">
<link href="{% static "lib/file-uploader/5.13.0/fine-uploader.min.js" %}" rel="preload" as="script"> <script src="{% static "lib/file-uploader/5.13.0/fine-uploader.min.js" %}"></script>
<script src="{% static "lib/file-uploader/5.13.0/fine-uploader.min.js" %}"></script> {% endif %}
{% endif %} {% endblock externallinks %}
{% endblock externallinks %}
{% block topimports %}
{% block topimports %} <link href="{% static "css/add-media.css" %}" rel="preload" as="style">
<link href="{% static "css/add-media.css" %}" rel="preload" as="style"> <link href="{% static "css/add-media.css" %}" rel="stylesheet">
<link href="{% static "css/add-media.css" %}" rel="stylesheet"> <style>
{%endblock topimports %} /* LMS Embed Mode specific styling */
.is-lms-embed .media-uploader-wrap {
{% block innercontent %} padding: 10px 15px;
{% get_current_language as LANGUAGE_CODE %} }
.is-lms-embed .media-uploader-top-wrap {
{% if request.user.is_authenticated %} margin-bottom: 10px;
padding: 0;
{% if can_add %} }
.is-lms-embed .media-uploader-top-left-wrap h1 {
<div class="media-uploader-wrap"> font-size: 1.2rem;
<div class="media-uploader-top-wrap"> margin: 0;
<div class="media-uploader-top-left-wrap"> padding: 0;
<h1>{{ "Upload media" | custom_translate:LANGUAGE_CODE}}</h1> }
</div> .is-lms-embed .media-uploader-bottom-wrap {
<div class="media-uploader-top-right-wrap"> </div> margin-top: 10px;
</div> }
<script type="text/template" id="qq-template"> .is-lms-embed .media-drag-drop-inner {
<div class="media-uploader-bottom-wrap qq-uploader-selector"> padding: 20px 10px;
<div class="media-uploader-bottom-left-wrap"> min-height: 140px;
<div class="media-drag-drop-wrap"> border-width: 2px;
<div class="media-drag-drop-inner" qq-drop-area-text="Drop files here"> }
<div class="media-drag-drop-content"> .is-lms-embed .media-drag-drop-content-inner span {
<div class="media-drag-drop-content-inner"> font-size: 13px;
<span><i class="material-icons">cloud_upload</i></span> margin-bottom: 6px;
<span>{{ "Drag and drop files" | custom_translate:LANGUAGE_CODE}}</span> line-height: 1.2;
<span>{{ "or" | custom_translate:LANGUAGE_CODE}}</span> }
<span class="browse-files-btn-wrap"> .is-lms-embed .media-drag-drop-content-inner i.material-icons {
<span class="qq-upload-button-selector">{{ "Browse your files" | custom_translate:LANGUAGE_CODE}}</span> font-size: 32px;
</span> margin-bottom: 4px;
}
<div class="qq-upload-drop-area-selector media-dropzone" qq-hide-dropzone> .is-lms-embed .qq-upload-button-selector {
<span class="qq-upload-drop-area-text-selector"></span> padding: 6px 16px;
</div> font-size: 13px;
margin-top: 5px;
</div> }
</div> .is-lms-embed .media-upload-items-list {
margin-top: 10px;
</div> }
</div> </style>
</div> {% endblock topimports %}
<div class="media-uploader-bottom-right-wrap">
<ul class="media-upload-items-list qq-upload-list-selector"> {% block innercontent %}
<li> {% get_current_language as LANGUAGE_CODE %}
<div class="media-upload-item-main">
<div class="media-upload-item-thumb"> {% if request.user.is_authenticated %}
<img class="qq-thumbnail-selector" qq-max-size="120" qq-server-scale alt="" />
<span class="media-upload-item-spinner qq-upload-spinner-selector"><i class="material-icons">autorenew</i></span> {% if can_add %}
<button type="button" class="qq-upload-retry-selector retry-media-upload-item" aria-label="Retry"><i class="material-icons">refresh</i> Retry</button>
</div> <div class="media-uploader-wrap" id="media-uploader-wrap">
<div class="media-upload-item-details"> <div class="media-uploader-top-wrap">
<div class="media-upload-item-name"> <div class="media-uploader-top-left-wrap">
<span class="media-upload-item-filename qq-upload-file-selector"></span> <h1>{{ "Upload media" | custom_translate:LANGUAGE_CODE}}</h1>
<input class="media-upload-item-filename-input qq-edit-filename-selector" tab-index="0" type="text" /> </div>
</div> <div class="media-uploader-top-right-wrap"> </div>
<div class="media-upload-item-details-bottom"> </div>
<div class="media-upload-item-progress-bar-container qq-progress-bar-container-selector">
<div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="media-upload-item-progress-bar qq-progress-bar-selector"></div> <script type="text/template" id="qq-template">
</div> <div class="media-uploader-bottom-wrap qq-uploader-selector">
<span class="media-upload-item-upload-size qq-upload-size-selector"></span> <div class="media-uploader-bottom-left-wrap">
<span role="status" class="media-upload-item-status-text qq-upload-status-text-selector"></span> <div class="media-drag-drop-wrap">
</div> <div class="media-drag-drop-inner" qq-drop-area-text="Drop files here">
<div class="media-upload-item-top-actions"> <div class="media-drag-drop-content">
<span class="filename-edit qq-edit-filename-icon-selector" aria-label="Edit filename">Edit filename <i class="material-icons">create</i></span> <div class="media-drag-drop-content-inner">
<button type="button" class="delete-media-upload-item qq-upload-delete-selector" aria-label="Delete">Delete <i class="material-icons">delete</i></button> <span><i class="material-icons">cloud_upload</i></span>
<button type="button" class="cancel-media-upload-item qq-upload-cancel-selector" aria-label="Cancel">Cancel <i class="material-icons">cancel</i></button> <span>{{ "Drag and drop files" | custom_translate:LANGUAGE_CODE}}</span>
<a href="#" class="view-uploaded-media-link qq-hide">{{ "View media" | custom_translate:LANGUAGE_CODE}}<i class="material-icons">open_in_new</i></a> <span>{{ "or" | custom_translate:LANGUAGE_CODE}}</span>
</div> <span class="browse-files-btn-wrap">
<div class="media-upload-item-bottom-actions"> <span class="qq-upload-button-selector">{{ "Browse your files" | custom_translate:LANGUAGE_CODE}}</span>
<button type="button" class="continue-media-upload-item qq-upload-continue-selector" aria-label="Continue"><i class="material-icons">play_circle_outline</i> Continue</button> </span>
<button type="button" class="pause-media-upload-item qq-upload-pause-selector" aria-label="Pause"><i class="material-icons">pause_circle_outline</i> Pause</button>
</div> <div class="qq-upload-drop-area-selector media-dropzone" qq-hide-dropzone>
</div> <span class="qq-upload-drop-area-text-selector"></span>
</div> </div>
</li> </div>
</ul> </div>
<dialog class="qq-alert-dialog-selector"> </div>
<div class="qq-dialog-message-selector"></div> </div>
<div class="qq-dialog-buttons"> </div>
<button type="button" class="qq-cancel-button-selector">CLOSE</button> <div class="media-uploader-bottom-right-wrap">
</div> <ul class="media-upload-items-list qq-upload-list-selector">
</dialog> <li>
<dialog class="qq-confirm-dialog-selector"> <div class="media-upload-item-main">
<div class="qq-dialog-message-selector"></div> <div class="media-upload-item-thumb">
<div class="qq-dialog-buttons"> <img class="qq-thumbnail-selector" qq-max-size="120" qq-server-scale alt="" />
<button type="button" class="qq-cancel-button-selector">NO</button> <span class="media-upload-item-spinner qq-upload-spinner-selector"><i class="material-icons">autorenew</i></span>
<button type="button" class="qq-ok-button-selector">YES</button> <button type="button" class="qq-upload-retry-selector retry-media-upload-item" aria-label="Retry"><i class="material-icons">refresh</i> Retry</button>
</div> </div>
</dialog> <div class="media-upload-item-details">
<dialog class="qq-prompt-dialog-selector"> <div class="media-upload-item-name">
<div class="qq-dialog-message-selector"></div> <span class="media-upload-item-filename qq-upload-file-selector"></span>
<input type="text"> <input class="media-upload-item-filename-input qq-edit-filename-selector" tab-index="0" type="text" />
<div class="qq-dialog-buttons"> </div>
<button type="button" class="qq-cancel-button-selector">CANCEL</button> <div class="media-upload-item-details-bottom">
<button type="button" class="qq-ok-button-selector">OK</button> <div class="media-upload-item-progress-bar-container qq-progress-bar-container-selector">
</div> <div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="media-upload-item-progress-bar qq-progress-bar-selector"></div>
</dialog> </div>
</div> <span class="media-upload-item-upload-size qq-upload-size-selector"></span>
</div> <span role="status" class="media-upload-item-status-text qq-upload-status-text-selector"></span>
</script> </div>
<div class="media-uploader"></div> <div class="media-upload-item-top-actions">
</div> <span class="filename-edit qq-edit-filename-icon-selector" aria-label="Edit filename">Edit filename <i class="material-icons">create</i></span>
<button type="button" class="delete-media-upload-item qq-upload-delete-selector" aria-label="Delete">Delete <i class="material-icons">delete</i></button>
{% else %} <button type="button" class="cancel-media-upload-item qq-upload-cancel-selector" aria-label="Cancel">Cancel <i class="material-icons">cancel</i></button>
<a href="#" class="view-uploaded-media-link qq-hide">{{ "View media" | custom_translate:LANGUAGE_CODE}}<i class="material-icons">open_in_new</i></a>
{{can_upload_exp}} </div>
<div class="media-upload-item-bottom-actions">
<br> <button type="button" class="continue-media-upload-item qq-upload-continue-selector" aria-label="Continue"><i class="material-icons">play_circle_outline</i> Continue</button>
<button type="button" class="pause-media-upload-item qq-upload-pause-selector" aria-label="Pause"><i class="material-icons">pause_circle_outline</i> Pause</button>
<a href='/contact'>Contact</a> portal owners for more information. </div>
</div>
{% endif %} </div>
</li>
{% else %} </ul>
<dialog class="qq-alert-dialog-selector">
{% endif %} <div class="qq-dialog-message-selector"></div>
{% endblock innercontent %} <div class="qq-dialog-buttons">
<button type="button" class="qq-cancel-button-selector">CLOSE</button>
{% block bottomimports %} </div>
<script src="{% static "js/add-media.js" %}?v={{ VERSION }}"></script> </dialog>
<script> <dialog class="qq-confirm-dialog-selector">
document.addEventListener("DOMContentLoaded", function(event) { <div class="qq-dialog-message-selector"></div>
function getCSRFToken() { <div class="qq-dialog-buttons">
var i, cookies, cookie, cookieVal = null; <button type="button" class="qq-cancel-button-selector">NO</button>
if ( document.cookie && '' !== document.cookie ) { <button type="button" class="qq-ok-button-selector">YES</button>
cookies = document.cookie.split(';'); </div>
i = 0; </dialog>
while( i < cookies.length ){ <dialog class="qq-prompt-dialog-selector">
cookie = cookies[i].trim(); <div class="qq-dialog-message-selector"></div>
if ( 'csrftoken=' === cookie.substring(0, 10) ) { <input type="text">
cookieVal = decodeURIComponent( cookie.substring(10) ); <div class="qq-dialog-buttons">
break; <button type="button" class="qq-cancel-button-selector">CANCEL</button>
} <button type="button" class="qq-ok-button-selector">OK</button>
i += 1; </div>
} </dialog>
} </div>
return cookieVal; </div>
} </script>
<div class="media-uploader"></div>
var default_concurrent_chunked_uploader = new qq.FineUploader({ </div>
debug: true,
element: document.querySelector('.media-uploader'), {% else %}
request: {
endpoint: '{% url 'uploader:upload' %}', {{can_upload_exp}}
params: {},
customHeaders: { <br>
'X-CSRFToken': getCSRFToken('csrftoken'),
}, <a href='/contact'>Contact</a> portal owners for more information.
},
retry: { {% endif %}
enableAuto: true,
maxAutoAttempts: 2, {% endif %}
}, {% endblock innercontent %}
validation: {
itemLimit: {{UPLOAD_MAX_FILES_NUMBER}}, {% block bottomimports %}
sizeLimit: {{UPLOAD_MAX_SIZE}}, <script src="{% static "js/add-media.js" %}?v={{ VERSION }}"></script>
}, <script>
chunking: { document.addEventListener("DOMContentLoaded", function(event) {
enabled: true,
concurrent: { if (sessionStorage.getItem('lms_embed_mode') === 'true') {
enabled: true, var wrap = document.getElementById('media-uploader-wrap');
}, if (wrap) {
success: { wrap.classList.add('is-lms-embed');
endpoint: '{% url 'uploader:upload' %}?done', }
}, }
},
callbacks: { function getCSRFToken() {
onError: function(id, name, errorReason, xhrOrXdr) { var i, cookies, cookie, cookieVal = null;
console.warn(qq.format("Error on file number {} - {}. Reason: {}", id, name, errorReason)); if ( document.cookie && '' !== document.cookie ) {
}, cookies = document.cookie.split(';');
onComplete: function( id, name, response, request ) { i = 0;
while( i < cookies.length ){
if( response.success ){ cookie = cookies[i].trim();
if ( 'csrftoken=' === cookie.substring(0, 10) ) {
if( response.media_url ) { cookieVal = decodeURIComponent( cookie.substring(10) );
if( 1 === this._currentItemLimit ) { break;
setTimeout(function(){ window.location.href = response.media_url; }, 500); }
return; i += 1;
} }
} }
return cookieVal;
var listEl = document.querySelector( '.qq-file-id-' + id ); }
var viewFileEl = listEl.querySelector( '.view-uploaded-media-link' );
var default_concurrent_chunked_uploader = new qq.FineUploader({
if( listEl ){ debug: true,
var fileUrl = response.media_url; element: document.querySelector('.media-uploader'),
listEl.style.cursor = 'pointer'; request: {
listEl.addEventListener( 'click', function(ev){ endpoint: '{% url 'uploader:upload' %}',
ev.preventDefault(); params: {},
ev.stopPropagation(); customHeaders: {
window.location.href = fileUrl; 'X-CSRFToken': getCSRFToken('csrftoken'),
}); },
} },
retry: {
if( viewFileEl ){ enableAuto: true,
viewFileEl.setAttribute( 'href', response.media_url ); maxAutoAttempts: 2,
viewFileEl.setAttribute( 'class', 'view-uploaded-media-link' ); },
} validation: {
} itemLimit: sessionStorage.getItem('lms_embed_mode') === 'true' ? 1 : {{UPLOAD_MAX_FILES_NUMBER}},
}, sizeLimit: {{UPLOAD_MAX_SIZE}},
}, },
}); chunking: {
}); enabled: true,
</script> concurrent: {
{% endblock bottomimports %} enabled: true,
},
success: {
endpoint: '{% url 'uploader:upload' %}?done',
},
},
callbacks: {
onError: function(id, name, errorReason, xhrOrXdr) {
console.warn(qq.format("Error on file number {} - {}. Reason: {}", id, name, errorReason));
},
onComplete: function( id, name, response, request ) {
if ( response.success ) {
if ( response.media_url ) {
if ( 1 === this._currentItemLimit ) {
if (sessionStorage.getItem('lms_embed_mode') === 'true') {
window.location.href = '{% url "get_user" username=request.user.username %}?mode=lms_embed_mode';
return;
}
setTimeout(function(){ window.location.href = response.media_url; }, 500);
return;
}
}
var listEl = document.querySelector( '.qq-file-id-' + id );
var viewFileEl = listEl.querySelector( '.view-uploaded-media-link' );
if ( listEl ) {
var fileUrl = response.media_url;
listEl.style.cursor = 'pointer';
listEl.addEventListener( 'click', function(ev) {
ev.preventDefault();
ev.stopPropagation();
window.location.href = fileUrl;
});
}
if ( viewFileEl ) {
viewFileEl.setAttribute( 'href', response.media_url );
viewFileEl.setAttribute( 'class', 'view-uploaded-media-link' );
}
}
},
},
});
});
</script>
{% endblock bottomimports %}