Linux moodl-moodle-3s8bw1nuh5yqd9-5b875fdd66-8hs4m 4.4.0-186-generic #216-Ubuntu SMP Wed Jul 1 05:34:05 UTC 2020 x86_64
Apache/2.4.41 (Ubuntu)
: 10.39.0.36 | : 10.36.0.0
Cant Read [ /etc/named.conf ]
7.4.3
www-data
www.github.com/MadExploits
Terminal
AUTO ROOT
Adminer
Backdoor Destroyer
Linux Exploit
Lock Shell
Lock File
Create User
CREATE RDP
PHP Mailer
BACKCONNECT
UNLOCK SHELL
HASH IDENTIFIER
CPANEL RESET
CREATE WP USER
README
+ Create Folder
+ Create File
/
var /
moodledata /
filedir /
df /
4a /
[ HOME SHELL ]
Name
Size
Permission
Action
.pkexec
[ DIR ]
drwxr-sr-x
GCONV_PATH=.
[ DIR ]
drwxr-sr-x
.mad-root
0
B
-rw-r--r--
df4ac256a33f48f85c9047863f873e...
46.34
KB
-rw-rw-rw-
pwnkit
10.99
KB
-rwxr-xr-x
Delete
Unzip
Zip
${this.title}
Close
Code Editor : df4ac256a33f48f85c9047863f873e374602e57d
/*global H5P*/ var H5PEditor = H5PEditor || {}; /** * Interactive Video editor widget module * TODO: Rewrite to use H5P.DragQuestion for previewing? * @param {jQuery} $ */ H5PEditor.widgets.dragQuestion = H5PEditor.DragQuestion = (function ($, DragNBar) { /** * Must be changed if the semantics for the elements changes. * @Ď€vate * @type {string} */ var clipboardKey = 'H5PEditor.DragQuestion'; /** * Initialize interactive video editor. * * @param {Object} parent * @param {Object} field * @param {Object} params * @param {function} setValue */ function C(parent, field, params, setValue) { var that = this; this.fakeDropzoneLibrary = 'H5P.DragQuestionDropzone 0.1'; this.parent = parent; // Set params this.params = $.extend({ elements: [], dropZones: [] }, params); setValue(field, this.params); // Get updates for fields H5PEditor.followField(parent, 'settings/background', function (params) { that.setBackground(params); }); H5PEditor.followField(parent, 'settings/size', function (params) { that.setSize(params); }); // Need the override background opacity this.backgroundOpacity = parent.parent.params.backgroundOpacity; this.backgroundOpacity = (this.backgroundOpacity === undefined || this.backgroundOpacity.trim() === '') ? undefined : this.backgroundOpacity; // Update opacity for all dropzones/draggables when global background opacity is changed parent.ready(function () { H5PEditor.findField('../behaviour/backgroundOpacity', parent).$item.find('input').on('change', function () { that.backgroundOpacity = $(this).val().trim(); that.backgroundOpacity = (that.backgroundOpacity === '') ? undefined : that.backgroundOpacity; that.updateAllElementsOpacity(that.elements, that.params.elements, 'element'); }); }); // Get options from semantics, clone since we'll be changing values. this.elementFields = H5P.cloneObject(field.fields[0].field.fields, true); this.dropZoneFields = H5P.cloneObject(field.fields[1].field.fields, true); this.elementLibraryOptions = this.elementFields[0].options; if (typeof this.elementLibraryOptions[0] === 'object') { this.elementLibraryOptions = this.elementLibraryOptions.map(function (option) { return option.name; }); } this.elementDropZoneFieldWeight = 5; this.elementFields[this.elementDropZoneFieldWeight].options = []; this.dropZoneElementFieldWeight = 6; this.elementOptions = []; this.parent = parent; this.field = field; this.passReadies = true; parent.ready(function () { that.passReadies = false; }); H5P.$window.on('resize', function () { if (that.size !== undefined && that.size.width !== undefined) { that.resize(); } }); // Update paste button H5P.externalDispatcher.on('datainclipboard', function (event) { if (!that.libraries) { return; } var canPaste = !event.data.reset; if (canPaste) { // Check if content type is supported here canPaste = that.canPaste(H5P.getClipboard()); } that.dnb.setCanPaste(canPaste); }); } /** * Append field to wrapper. * * @param {jQuery} $wrapper * @returns {undefined} */ C.prototype.appendTo = function ($wrapper) { var that = this; this.$item = $(this.createHtml()).appendTo($wrapper); this.$editor = this.$item.children('.h5peditor-dragquestion'); this.$dnbWrapper = this.$item.children('.h5peditor-dragnbar'); this.$dialog = this.$item.children('.h5peditor-fluid-dialog'); this.$dialogInner = this.$dialog.children('.h5peditor-fd-inner'); this.$errors = this.$item.children('.h5p-errors'); this.$editor.attr('tabindex', -1); // Handle click events for dialog buttons. this.$dialog.find('.h5peditor-done').click(function () { if (that.doneCallback() !== false) { that.hideDialog(); } return false; }).end().find('.h5peditor-remove').click(function () { that.showConfirmationDialog({ headerText: C.t('deleteTaskTitle'), dialogText: C.t('confirmRemoval'), cancelText: C.t('cancel'), confirmText: C.t('confirm'), }, handleFormDialogActions); }); /** * Callback confirm/cancel action * @param {boolean} [confirmFlag] Which button is clicked */ const handleFormDialogActions = function (confirmFlag) { if (!confirmFlag) { return false; } that.removeCallback(); that.hideDialog(); }; }; /** * Check if the clipboard can be pasted into DnD. * * @param {Object} [clipboard] Clipboard data. * @return {boolean} True, if clipboard can be pasted. */ C.prototype.canPaste = function (clipboard) { if (clipboard) { if (clipboard.from === clipboardKey && (!clipboard.generic || this.supported(clipboard.generic.library))) { // Content comes from the same version of DQ // Non generic part = must be content like gotoslide or similar return true; } else if (clipboard.generic && this.supported(clipboard.generic.library)) { // Supported library from another content type return true; } } return false; }; /** * Check if library is supported by Drag Question * * @private * @param {string} lib uber name * @returns {boolean} */ C.prototype.supported = function (lib) { for (var i = 0; i < this.libraries.length; i++) { if (this.libraries[i].restricted !== true && this.libraries[i].uberName === lib) { return true; // Library is supported and allowed } } return false; }; /** * Create HTML for the field. * * @returns {String} */ C.prototype.createHtml = function () { var html = ''; if (this.field.label !== 0) { html += '<span class="h5peditor-label">' + this.field.label + '</span>'; } html += '<div class="h5peditor-dragnbar"></div>' + '<div class="h5peditor-dragquestion">' + C.t('noTaskSize') + '</div>' + '<div class="h5peditor-fluid-dialog">' + ' <div class="h5peditor-fd-inner"></div>' + ' <div class="h5peditor-fd-buttons">' + ' <a href="#" class="h5peditor-fd-button h5peditor-done">' + C.t('done') + '</a>' + ' <a href="#" class="h5peditor-fd-button h5peditor-remove">' + C.t('remove') + '</a>' + ' </div>' + '</div>'; if (this.field.description !== undefined) { html += '<div class="h5peditor-field-description">' + this.field.description + '</div>'; } // removes the description field, so it's not re-rendered on top var field = this.removeAttribute(this.field, 'description'); return H5PEditor.createFieldMarkup(field, html); }; /** * Clones an object, and removes an attribute * * @param {object} obj * @param {string} attributeName * * @return {object} */ C.prototype.removeAttribute = function (obj, attributeName) { var result = H5P.cloneObject(obj); result[attributeName] = undefined; return result; }; /** * Set current background. * * @param {Object} params * @returns {undefined} */ C.prototype.setBackground = function (params) { var path = params === undefined ? '' : params.path; if (path !== '') { // Add correct base path path = 'url("' + H5P.getPath(path, H5PEditor.contentId) + '")'; } this.$editor.css({ backgroundImage: path }); }; /** * Set current dimensions. * * @param {Object} params * @returns {undefined} */ C.prototype.setSize = function (params) { this.size = params; }; /** * Apply new size to task editor once visible. * * @returns {undefined} */ C.prototype.setActive = function () { var that = this; if (this.size === undefined || this.size.width === undefined) { return; } if (this.dnb === undefined) { this.$editor.html('<div class="h5p-throbber">' + H5PEditor.t('core', 'loading') + '</div>') .addClass('h5p-ready'); H5PEditor.LibraryListCache.getLibraries(this.elementLibraryOptions, function (libraries) { that.libraries = libraries; // Add fake library for copy&paste (Dropzones are no libraries) libraries.push({ uberName: that.fakeDropzoneLibrary, name: that.fakeDropzoneLibrary.split(' ')[0], title: that.fakeDropzoneLibrary.split(' ')[0].split('.')[1], majorVersion: that.fakeDropzoneLibrary.split(' ')[1].split('.')[0], minorVersion: that.fakeDropzoneLibrary.split(' ')[1].split('.')[1], restricted: false, runnable: 0 }); // Prevents duplicate loading if (this.dnb === undefined) { that.activateEditor(libraries); } }); } this.resize(); }; /** * Adapt the editor when the window changes size. */ C.prototype.resize = function () { if (!this.$editor.is(':visible')) { return; } if (this.fontSize === undefined) { // Get editor default font size. this.fontSize = parseInt(this.$editor.css('fontSize')); } var maxWidth = this.$item.width(); var editorCss; if (this.size.width < maxWidth) { editorCss = { width: this.size.width, height: this.size.height, fontSize: this.fontSize }; this.$dnbWrapper.css({ width: this.size.width }); } else { editorCss = { width: '100%', height: maxWidth * (this.size.height / this.size.width), fontSize: this.fontSize * (maxWidth / this.size.width) }; this.$dnbWrapper.css({ width: '100%' }); } this.$editor.css(editorCss); if (this.dnb !== undefined) { this.dnb.dnr.setContainerEm(editorCss.fontSize); } this.pToEm = (parseFloat(window.getComputedStyle(this.$editor[0]).width) / this.fontSize) / 100; }; /** * Activate DragNBar and add elements. * * @returns {undefined} */ C.prototype.activateEditor = function (libraries) { var that = this; this.$editor.html('').addClass('h5p-ready'); // Ignore fake libraries const buttonLibraries = libraries.filter(function (library) { return (library.uberName !== that.fakeDropzoneLibrary); }); // Create new bar this.dnb = new DragNBar(this.getButtons(buttonLibraries), this.$editor, this.$item, {libraries: libraries}); that.dnb.dnr.snap = 10; // Add event handling this.dnb.stopMovingCallback = function (x, y) { // Update params when the element is dropped. var id = that.dnb.dnd.$element.data('id'); var params = that.dnb.dnd.$element.hasClass('h5p-dq-dz') ? that.params.dropZones[id] : that.params.elements[id]; params.x = x; params.y = y; }; this.dnb.dnd.releaseCallback = function () { // Edit element when it is dropped. if (that.dnb.newElement) { setTimeout(function () { that.dnb.dnd.$element.dblclick(); that.dnb.blurAll(); }, 1); } }; this.dnb.attach(this.$dnbWrapper); // Set paste button this.dnb.setCanPaste(this.canPaste(H5P.getClipboard())); this.dnb.on('paste', function (event) { var pasted = event.data; var $element; if (!pasted.generic || !that.supported(pasted.generic.library)) { return that.showConfirmationDialog({ headerText: H5PEditor.t('core', 'pasteError'), dialogText: H5PEditor.t('H5P.DragNBar', 'unableToPaste'), cancelText: ' ', confirmText: C.t('ok') }); } if (pasted.from === clipboardKey) { // Pasted content comes from the same version of DQ var isDropZone = pasted.generic.library === that.fakeDropzoneLibrary; that.center(pasted.specific); if (isDropZone) { that.params.dropZones.push(pasted.specific); $element = that.insertDropZone(that.params.dropZones.length - 1); } else { that.params.elements.push(pasted.specific); $element = that.insertElement(that.params.elements.length - 1); } setTimeout(function () { that.dnb.focus($element); }); } else { // Supported library from another content type var id = C.getLibraryID(pasted.generic.library); var elementParams = C.getDefaultElementParams(id); elementParams.type = pasted.generic; elementParams.width = (pasted.width || elementParams.width / that.pToEm) * that.pToEm; elementParams.height = (pasted.height || elementParams.height / that.pToEm) * that.pToEm; that.center(elementParams); that.params.elements.push(elementParams); $element = that.insertElement(that.params.elements.length - 1); setTimeout(function () { that.dnb.focus($element); }); } }); /** * Update params on end of resize * Dimensions contains a data object where each dimensions is optional. */ this.dnb.dnr.on('stoppedResizing', function (dimensions) { var id = that.dnb.$element.data('id'); var params = that.dnb.$element.hasClass('h5p-dq-dz') ? that.params.dropZones[id] : that.params.elements[id]; var containerStyle = window.getComputedStyle(that.$editor[0]); // Set dimensions if they were passed in if (dimensions.data.left !== undefined) { params.x = dimensions.data.left / (parseFloat(containerStyle.width) / 100); } if (dimensions.data.top !== undefined) { params.y = dimensions.data.top / (parseFloat(containerStyle.height) / 100); } if (dimensions.data.width !== undefined) { params.width = dimensions.data.width; } if (dimensions.data.height !== undefined) { params.height = dimensions.data.height; } }); // Add Elements this.elements = []; for (var i = 0; i < this.params.elements.length; i++) { this.insertElement(i); } // Add Drop Zones this.dropZones = []; for (var j = 0; j < this.params.dropZones.length; j++) { this.insertDropZone(j); } this.resize(); }; /** * Help center new elements * @param {object} params */ C.prototype.center = function (params) { var size = window.getComputedStyle(this.dnb.$container[0]); var width = parseFloat(size.width); var height = parseFloat(size.height); var pos = { x: (width - (params.width * this.fontSize)) / 2, y: (height - (params.height * this.fontSize)) / 2 }; this.dnb.avoidOverlapping(pos, { width: params.width * this.fontSize, height: params.height * this.fontSize, }); params.x = pos.x / (width / 100); params.y = pos.y / (height / 100); }; /** * Generate sub forms that's ready to use in the dialog. * * @param {Object} semantics * @param {Object} params * @returns {Object} generatedForm */ C.prototype.generateForm = function (semantics, params) { var $form = $('<div></div>'); H5PEditor.processSemanticsChunk(semantics, params, $form, this); // Remove library selector and copy button and paste button var pos = semantics.map(function (field) { return field.type; }).indexOf('library'); if (pos > -1) { this.children[pos].hide(); } var $lib = $form.children('.library:first'); if ($lib.length !== 0) { $lib.children('label, select, .h5peditor-field-description').hide().end().children('.libwrap').css('margin-top', '0'); } return { $form: $form, children: this.children }; }; /** * Generate a list of buttons for DnB. * * @returns {Array} Buttons */ C.prototype.getButtons = function (libraries) { var that = this; var id = 'dropzone'; var buttons = [{ id: id, title: C.t('insertElement', {':type': C.t(id)}), createElement: function () { that.params.dropZones.push({ x: 0, y: 0, width: 5, height: 2.5, correctElements: [] }); return that.insertDropZone(that.params.dropZones.length - 1); } }]; for (var i = 0; i < libraries.length; i++) { if (libraries[i].restricted !== true) { buttons.push(this.getButton(libraries[i])); } } return buttons; }; /** * Creates a fresh object with default element parameters. * @returns {object} */ C.getDefaultElementParams = function (id) { return { x: 0, y: 0, width: 5, height: id === 'text' ? 1.25 : 5, dropZones: [] }; }; /** * Find generic library identifier without version name. * * @param {string} library * @returns {string} */ C.getLibraryID = function (library) { return library.split(' ')[0].split('.')[1].toLowerCase(); }; /** * Generate a single element button for the DnB. * * @param {String} library Library name + version * @returns {Object} DnB button semantics */ C.prototype.getButton = function (library) { var that = this; var id = C.getLibraryID(library.uberName); return { id: id, title: library.title, createElement: function () { var elementParams = C.getDefaultElementParams(id); elementParams.type = { library: library.uberName, params: {} }; that.params.elements.push(elementParams); return that.insertElement(that.params.elements.length - 1); } }; }; /** * Insert element at given params index. * * @param {int} index * @returns {jQuery} The element's DOM */ C.prototype.insertElement = function (index) { var that = this; var elementParams = this.params.elements[index]; var element = this.generateForm(this.elementFields, elementParams); var library = this.children[0]; // Get image aspect ratio var libraryChange = function () { if (library.children[0].field.type === 'image') { library.children[0].changes.push(function (params) { if (params === undefined) { return; } if (params.width !== undefined && params.height !== undefined) { var editorStyles = window.getComputedStyle(that.$editor[0]); var editorWidth = parseFloat(editorStyles.width); var editorHeight = parseFloat(editorStyles.height); var aspectRatio = params.height / params.width; if (editorHeight / editorWidth > aspectRatio) { elementParams.height = elementParams.width * aspectRatio; } else { elementParams.width = elementParams.height / aspectRatio; } element.$element.css({ width: elementParams.width + 'em', height: elementParams.height + 'em' }); } }); } }; if (library.children === undefined) { library.changes.push(libraryChange); } else { libraryChange(); } element.$element = $('<div class="h5p-dq-element" style="width:' + elementParams.width + 'em;height:' + elementParams.height + 'em;top:' + elementParams.y + '%;left:' + elementParams.x + '%"></div>') .data('id', index) .appendTo(this.$editor) .dblclick(function () { that.editElement(element); }).hover(function () { C.setElementOpacity(element.$element, that.getElementOpacitySetting(elementParams)); }, function () { // Need this timeout for firefox beeing able to get the css hover rule in place setTimeout(function () { C.setElementOpacity(element.$element, that.getElementOpacitySetting(elementParams)); }, 1); }); element.$innerElement = $('<div>', { 'class': 'h5p-dq-element-inner' }).appendTo(element.$element); setTimeout(function () { var type = (elementParams.type ? elementParams.type.library.split(' ')[0] : null); var dnbElement = that.dnb.add(element.$element, DragNBar.clipboardify(clipboardKey, elementParams, 'type'), { cornerLock: (type === 'H5P.Image') }); dnbElement.contextMenu.on('contextMenuEdit', function () { that.editElement(element); that.dnb.blurAll(); }); dnbElement.contextMenu.on('contextMenuRemove', that.elementRemove.bind(that, element)); dnbElement.contextMenu.on('contextMenuBringToFront', that.elementBringToFront.bind(that, element)); dnbElement.contextMenu.on('contextMenuSendToBack', that.elementSendToBack.bind(that, element)); that.dnb.focus(element.$element); }, 0); // Update element that.updateElement(element, index); this.elements[index] = element; return element.$element; }; /** * Removes an element * * @param {object} element */ C.prototype.elementRemove = function (element) { var that = this; /** * Callback confirm/cancel action * @param {boolean} [confirmFlag] Which button is clicked */ const handleTaskDialogActions = function (confirmFlag) { if (!confirmFlag) { return false; } var id = element.$element.data('id'); var value = id.toString(); // Remove element form H5PEditor.removeChildren(element.children); // Remove element element.$element.remove(); that.elements.splice(id, 1); that.params.elements.splice(id, 1); // Remove from options that.elementOptions.splice(id, 1); // Update drop zone params that.params.dropZones.forEach(function (dropZone) { // Update correct elements for drop zone for (let i = 0; i < dropZone.correctElements.length; i++) { if (dropZone.correctElements[i] === value) { dropZone.correctElements.splice(i, 1); i--; } else if (parseInt(dropZone.correctElements[i]) > id) { dropZone.correctElements[i] = '' + (parseInt(dropZone.correctElements[i]) - 1); } } }); that.updateInternalElementIDs(id); that.dnb.blurAll(); }; // confirm remove that.showConfirmationDialog({ headerText: C.t('deleteTaskTitle'), dialogText: C.t('confirmRemoval'), cancelText: C.t('cancel'), confirmText: C.t('confirm'), }, handleTaskDialogActions); }; /** * Brings an element to the front * * @param {object} element */ C.prototype.elementBringToFront = function (element) { var that = this; // Find element ID var id = element.$element.data('id'); var oldId = id.toString(); // Update visuals element.$element.appendTo(that.$editor); // Give new ID that.elements.push(that.elements.splice(id, 1)[0]); that.params.elements.push(that.params.elements.splice(id, 1)[0]); that.elementOptions.push(that.elementOptions.splice(id, 1)[0]); var newId = (that.elements.length - 1).toString(); that.params.dropZones.forEach(function (dropZone) { // Update correct elements for drop zone for (let i = 0; i < dropZone.correctElements.length; i++) { if (dropZone.correctElements[i] === oldId) { dropZone.correctElements[i] = newId; } else if (parseInt(dropZone.correctElements[i]) > id) { dropZone.correctElements[i] = (parseInt(dropZone.correctElements[i]) - 1).toString(); } } }); that.updateInternalElementIDs(id); }; /** * Sends an element to the back * * @param {object} element */ C.prototype.elementSendToBack = function (element) { var that = this; // Find element ID var id = element.$element.data('id'); var oldId = id.toString(); // Update visuals element.$element.prependTo(that.$editor); // Give new ID that.elements.unshift(that.elements.splice(id, 1)[0]); that.params.elements.unshift(that.params.elements.splice(id, 1)[0]); that.elementOptions.unshift(that.elementOptions.splice(id, 1)[0]); var newId = '0'; that.params.dropZones.forEach(function (dropZone) { // Update correct elements for drop zone for (let i = 0; i < dropZone.correctElements.length; i++) { if (dropZone.correctElements[i] === oldId) { dropZone.correctElements[i] = newId; } else if (parseInt(dropZone.correctElements[i]) < id) { dropZone.correctElements[i] = (parseInt(dropZone.correctElements[i]) + 1).toString(); } } }); that.updateInternalElementIDs(0); }; /** * Sync the internal ID of each element. * @param {number} start */ C.prototype.updateInternalElementIDs = function (start) { for (var i = start; i < this.elements.length; i++) { this.elements[i].$element.data('id', i); this.elementOptions[i].value = '' + i; } }; /** * Set callbacks and open dialog with the form for the given element. * * @param {Object} element * @returns {undefined} */ C.prototype.editElement = function (element) { var that = this; var id = element.$element.data('id'); this.doneCallback = function () { // Remove as correct draggable for dropzone if dropzone no longer can be dropped in a dropzone. const elementParams = that.params.elements[id]; // Go through all drop zones for (let dzIndex = 0; dzIndex < that.params.dropZones.length; dzIndex++) { if (elementParams.dropZones.indexOf(dzIndex.toString()) !== -1) { continue; // E can still be dropped in this DZ, skip. } const correctElements = that.params.dropZones[dzIndex].correctElements; const isCorrect = correctElements.indexOf(id.toString()); if (isCorrect !== -1) { // Element can no longer be dropped here so must be removed from correct elements for this DZ correctElements.splice(isCorrect, 1); } } // Validate form var valid = true; for (var i = 0; i < element.children.length; i++) { if (element.children[i].validate() === false) { valid = false; break; } } if (!valid) { return false; } // Must be removed before dnb changes focus! if (H5PEditor.Html) { H5PEditor.Html.removeWysiwyg(); } // Update element that.updateElement(element, id); that.dnb.focus(element.$element); that.dnb.pressed = undefined; }; this.removeCallback = function () { var i, j, ce; // Remove element form H5PEditor.removeChildren(element.children); // Remove element element.$element.remove(); that.elements.splice(id, 1); that.params.elements.splice(id, 1); // Remove from options this.elementOptions.splice(id, 1); // Update drop zone params for (i = 0; i < that.params.dropZones.length; i++) { ce = that.params.dropZones[i].correctElements; for (j = 0; j < ce.length; j++) { if (ce[j] === '' + id) { // Remove from correct answers ce.splice(j, 1); } else if (ce[j] > id) { // Adjust index for others ce[j] = '' + (ce[j] - 1); } } } // Change data index for "all" elements for (i = id; i < that.elements.length; i++) { that.elements[i].$element.data('id', i); that.elementOptions[i].value = '' + i; } }; // Disable background opacity input if overriden globally var disableOpacityField = !!(that.params.elements[id].dropZones.length !== 0 && this.backgroundOpacity); H5PEditor.findField('backgroundOpacity', element).$item.find('input').prop({ disabled: disableOpacityField, title: disableOpacityField ? C.t('backgroundOpacityOverridden') : '' }); element.children[this.elementDropZoneFieldWeight].setActive(); this.showDialog(element.$form); // Blur context menu when showing dialog. setTimeout(function () { that.dnb.blurAll(); }, 10); }; /** * Update the element with new data. * * @param {Object} element * @param {int} id * @returns {undefined} */ C.prototype.updateElement = function (element, id) { var self = this; var params = this.params.elements[id]; var type = (params.type.library.split(' ')[0] === 'H5P.AdvancedText' ? 'text' : 'image'); var hasCk = (element.children[0].children !== undefined && element.children[0].children[0].ckeditor !== undefined); if (type === 'text' && hasCk) { // Create new text instance. Replace asterisk with spans element.instance = H5P.newRunnable({ library: params.type.library, params: { text: params.type.params.text.replace(/\*([^*]+)\*/g, '<span class="h5p-dragquestion-placeholder">$1</span>') } }, H5PEditor.contentId, element.$innerElement); // Remove asterisk from params and input field params.type.params.text = params.type.params.text.replace(/\*([^*]+)\*/g, '$1'); element.children[0].children[0].ckeditor.setData(params.type.params.text); } else { // Create new instance element.instance = H5P.newRunnable(params.type, H5PEditor.contentId, element.$innerElement); } if (type === 'text') { element.$element.addClass('h5p-dq-text'); } // Find label text without html var label = (type === 'text' ? $('<div>' + params.type.params.text + '</div>').text() : params.type.params.alt + ''); // Update correct element options this.elementOptions[id] = { value: '' + id, label: C.t(type) + ': ' + C.getLabel(label) }; // Retain size after toggling class var toggleDraggable = function (addClass, $element) { var toggleClass = addClass !== $element.hasClass('h5p-draggable'); if (!toggleClass) { return; } if (addClass) { $element.addClass('h5p-draggable'); } else { $element.removeClass('h5p-draggable'); } }; if (params.dropZones !== undefined && params.dropZones.length) { toggleDraggable(true, element.$element); } else { toggleDraggable(false, element.$element); if (type === 'text' && hasCk) { // When dialog closes, replace spans with drop zones this.hideDialogCallback = function () { var pWidth = self.$editor.width() / 100; var pHeight = self.$editor.height() / 100; element.$element.find('.h5p-dragquestion-placeholder').each(function () { var $span = $(this); var pos = $span.position(); // Add new drop zone self.params.dropZones.push({ x: params.x + ((pos.left - 3) / pWidth), y: params.y + ((pos.top - 2) / pHeight), width: ($span.width() / self.fontSize) + 0.5, height: ($span.height() / self.fontSize) + 0.3, backgroundOpacity: 0, correctElements: [], label: C.getLabel($span.text()), showLabel: false }); self.insertDropZone(self.params.dropZones.length - 1); // Remove span $span.contents().unwrap(); }); delete self.hideDialogCallback; }; } } C.setElementOpacity(element.$element, this.getElementOpacitySetting(params)); }; /** * Clips text at 32 chars * * @param {String} text * @returns {String} */ C.getLabel = function (text) { return (text.length > 32 ? text.substr(0, 32) + '...' : text); }; /** * Insert the drop zone at the given index. * * @param {int} index * @returns {H5P.jQuery} */ C.prototype.insertDropZone = function (index) { var that = this, dropZoneParams = this.params.dropZones[index], dropZone = this.generateForm(this.dropZoneFields, dropZoneParams); // Fake libraryName for copy&paste dropZoneParams.type = dropZoneParams.type || {library: that.fakeDropzoneLibrary}; dropZone.$dropZone = $('<div class="h5p-dq-dz" style="width:' + dropZoneParams.width + 'em;height:' + dropZoneParams.height + 'em;top:' + dropZoneParams.y + '%;left:' + dropZoneParams.x + '%"></div>') .appendTo(this.$editor) .data('id', index) .dblclick(function () { // Edit that.editDropZone(dropZone); that.dnb.blurAll(); }); // Add label this.updateDropZone(dropZone, index); // Add to dnb after element has been attached setTimeout(function () { var dropzoneDnBElement = that.dnb.add(dropZone.$dropZone, DragNBar.clipboardify(clipboardKey, dropZoneParams, 'type')); // Register listeners for context menu buttons dropzoneDnBElement.contextMenu.on('contextMenuEdit', function () { that.editDropZone(dropZone); that.dnb.blurAll(); }); dropzoneDnBElement.contextMenu.on('contextMenuRemove', function () { that.showConfirmationDialog({ headerText: C.t('deleteTaskTitle'), dialogText: C.t('confirmRemoval'), cancelText: C.t('cancel'), confirmText: C.t('confirm'), }, removeDropzoneDialogActions); }); /** * Callback confirm/cancel action * @param {boolean} [confirmFlag] Which button is clicked */ const removeDropzoneDialogActions = function (confirmFlag) { if (!confirmFlag) { return; } // Remove element form H5PEditor.removeChildren(dropZone.children); var i; var j; var id = dropZone.$dropZone.data('id'); // Remove element dropZone.$dropZone.remove(); that.dropZones.splice(id, 1); that.params.dropZones.splice(id, 1); // Remove from elements that.elementFields[that.elementDropZoneFieldWeight].options.splice(id, 1); // Remove dropZone from element params properly for (i = 0; i < that.params.elements.length; i++) { var dropZones = that.params.elements[i].dropZones; for (j = 0; j < dropZones.length; j++) { if (parseInt(dropZones[j]) === id) { // Remove from element drop zones dropZones.splice(j, 1); if (!dropZones.length) { that.elements[i].$element.removeClass('h5p-draggable'); } } else if (dropZones[j] > id) { // Re index other drop zones dropZones[j] = '' + (dropZones[j] - 1); } } } that.updateInternalDropZoneIDs(id); that.dnb.blurAll(); }; dropzoneDnBElement.contextMenu.on('contextMenuBringToFront', function () { var id = dropZone.$dropZone.data('id'); // Update visuals dropZone.$dropZone.appendTo(that.$editor); // Get new ID that.dropZones.push(that.dropZones.splice(id, 1)[0]); that.params.dropZones.push(that.params.dropZones.splice(id, 1)[0]); var options = that.elementFields[that.elementDropZoneFieldWeight].options; options.push(options.splice(id, 1)[0]); var newID = (that.dropZones.length - 1); // Update dropZone IDs in element params for (var i = 0; i < that.params.elements.length; i++) { var dropZones = that.params.elements[i].dropZones; for (var j = 0; j < dropZones.length; j++) { if (parseInt(dropZones[j]) === id) { // Update ID dropZones[j] = newID; } else if (dropZones[j] > id) { // Re-index other drop zones dropZones[j] = '' + (dropZones[j] - 1); } } } that.updateInternalDropZoneIDs(id); }); dropzoneDnBElement.contextMenu.on('contextMenuSendToBack', function () { var id = dropZone.$dropZone.data('id'); // Update visuals dropZone.$dropZone.prependTo(that.$editor); // Get new ID that.dropZones.unshift(that.dropZones.splice(id, 1)[0]); that.params.dropZones.unshift(that.params.dropZones.splice(id, 1)[0]); var options = that.elementFields[that.elementDropZoneFieldWeight].options; options.unshift(options.splice(id, 1)[0]); var newID = (that.dropZones.length - 1); // Update dropZone IDs in element params for (var i = 0; i < that.params.elements.length; i++) { var dropZones = that.params.elements[i].dropZones; for (var j = 0; j < dropZones.length; j++) { if (parseInt(dropZones[j]) === id) { // Update ID dropZones[j] = newID; } else if (dropZones[j] < id) { // Re-index other drop zones dropZones[j] = '' + (dropZones[j] + 1); } } } that.updateInternalDropZoneIDs(id); }); that.dnb.focus(dropZone.$dropZone); }, 0); this.dropZones[index] = dropZone; return dropZone.$dropZone; }; /** * Sync the internal ID of each drop zone. * @param {number} start */ C.prototype.updateInternalDropZoneIDs = function (start) { for (var i = start; i < this.dropZones.length; i++) { this.dropZones[i].$dropZone.data('id', i); this.elementFields[this.elementDropZoneFieldWeight].options[i].value = i + ''; } }; /** * Set callbacks and open dialog with the form for the given drop zone. * * @param {Object} dropZone * @returns {undefined} */ C.prototype.editDropZone = function (dropZone) { var that = this; var i, j, id = dropZone.$dropZone.data('id'); this.doneCallback = function () { // Validate form var valid = true; for (var i = 0; i < dropZone.children.length; i++) { if (dropZone.children[i].validate() === false) { valid = false; break; } } if (!valid) { return false; } // Must be removed before dnb changes focus! if (H5PEditor.Html) { H5PEditor.Html.removeWysiwyg(); } that.updateDropZone(dropZone, id); that.dnb.focus(dropZone.$dropZone); that.dnb.pressed = undefined; }; this.removeCallback = function () { // Remove element form H5PEditor.removeChildren(dropZone.children); // Remove element dropZone.$dropZone.remove(); that.dropZones.splice(id, 1); that.params.dropZones.splice(id, 1); // Remove from elements this.elementFields[this.elementDropZoneFieldWeight].options.splice(id, 1); // Remove dropZone from element params properly for (i = 0; i < that.params.elements.length; i++) { var dropZones = that.params.elements[i].dropZones; for (j = 0; j < dropZones.length; j++) { if (parseInt(dropZones[j]) === id) { // Remove from element drop zones dropZones.splice(j, 1); if (!dropZones.length) { that.elements[i].$element.removeClass('h5p-draggable'); } } else if (dropZones[j] > id) { // Re index other drop zones dropZones[j] = '' + (dropZones[j] - 1); } } } // Reindex all dropzones for (i = id; i < that.dropZones.length; i++) { that.dropZones[i].$dropZone.data('id', i); this.elementFields[this.elementDropZoneFieldWeight].options[i].value = i + ''; } }; // Add only available options var options = this.dropZoneFields[this.dropZoneElementFieldWeight].options = []; var dropZones; for (i = 0; i < this.elementOptions.length; i++) { dropZones = this.params.elements[i].dropZones; for (j = 0; j < dropZones.length; j++) { if (dropZones[j] === (id + '')) { options.push(this.elementOptions[i]); break; } } } dropZone.children[this.dropZoneElementFieldWeight].setActive(); this.showDialog(dropZone.$form); // Blur context menu when showing dialog setTimeout(function () { that.dnb.blurAll(); }, 10); }; /** * Remove old label and add new. * * @param {Object} dropZone * @param {int} id * @returns {undefined} */ C.prototype.updateDropZone = function (dropZone, id) { var params = this.params.dropZones[id]; // Remove old label and add new. dropZone.$dropZone.children('.h5p-dq-dz-label').remove(); if (params.showLabel === true) { $('<div class="h5p-dq-dz-label">' + params.label + '</div>').appendTo(dropZone.$dropZone); dropZone.$dropZone.addClass('h5p-has-label'); } else { dropZone.$dropZone.removeClass('h5p-has-label'); } // Create/update Tip: dropZone.$dropZone.children('.joubel-tip-container').remove(); if (params.tipsAndFeedback !== undefined && params.tipsAndFeedback.tip !== undefined && params.tipsAndFeedback.tip.trim().length !== 0) { dropZone.$dropZone.append(H5P.JoubelUI.createTip(params.tipsAndFeedback.tip, {showSpeechBubble: false})); } this.elementFields[this.elementDropZoneFieldWeight].options[id] = { value: '' + id, label: params.label }; C.setOpacity(dropZone.$dropZone.add(dropZone.$dropZone.children('.h5p-dq-dz-label')), 'background', params.backgroundOpacity); }; /** * Attach form to dialog and show. * * @param {jQuery} $form * @returns {undefined} */ C.prototype.showDialog = function ($form) { this.dnb.blurAll(); this.$currentForm = $form; $form.appendTo(this.$dialogInner); this.$dialog.show(); this.$editor.add(this.$dnbWrapper).hide(); this.dnb.dnr.toggleModifiers(false); }; /** * Hide dialog and detach form. * * @returns {undefined} */ C.prototype.hideDialog = function () { // Attempt to find and close CKEditor instances before detaching. this.$currentForm.detach(); this.$dialog.hide(); this.$editor.add(this.$dnbWrapper).show(); if (this.hideDialogCallback !== undefined) { this.hideDialogCallback(); } this.dnb.dnr.toggleModifiers(true); }; /** * Update transparency for background. * * @param {jQuery} $element * @param {Number} opacity */ C.setElementOpacity = function ($element, opacity) { C.setOpacity($element, 'background', opacity); C.setOpacity($element, 'boxShadow', opacity); C.setOpacity($element, 'borderColor', opacity); }; /** * Update all elements' opacity * * @param {Array} domElements * @param {Array} elements * @param {String} type */ C.prototype.updateAllElementsOpacity = function (domElements, elements, type) { if (domElements === undefined) { return; } for (var i = 0; i < domElements.length; i++) { C.setElementOpacity(domElements[i]['$'+type], this.getElementOpacitySetting(elements[i])); } }; /** * Get the opacity setting for a given element * * @param {Object} element * @returns {String} opacity */ C.prototype.getElementOpacitySetting = function (element) { if ((element.dropZones !== undefined && element.dropZones.length === 0) || (this.backgroundOpacity === undefined)) { return element.backgroundOpacity; } return this.backgroundOpacity; }; /** * Makes element background, border and shadow transparent. * * @param {jQuery} $element * @param {String} property * @param {Number} opacity */ C.setOpacity = function ($element, property, opacity) { if (property === 'background') { // Set both color and gradient. C.setOpacity($element, 'backgroundColor', opacity); C.setOpacity($element, 'backgroundImage', opacity); return; } opacity = (opacity === undefined ? 1 : opacity / 100); // Private. Get css properties objects. function getProperties(property, value) { switch (property) { case 'borderColor': return { borderTopColor: value, borderRightColor: value, borderBottomColor: value, borderLeftColor: value }; default: var properties = {}; properties[property] = value; return properties; } } // Reset css to be sure we're using CSS and not inline values. var properties = getProperties(property, ''); $element.css(properties); for (var prop in properties) { break; } var style = $element.css(prop); // Assume all props are the same and use the first. style = C.setAlphas(style, 'rgba(', opacity); // Update rgba style = C.setAlphas(style, 'rgb(', opacity); // Convert rgb $element.css(getProperties(property, style)); }; /** * Updates alpha channel for colors in the given style. * * @param {String} style * @param {String} prefix * @param {Number} alpha */ C.setAlphas = function (style, prefix, alpha) { // Style undefined if (!style) { return; } var colorStart = style.indexOf(prefix); while (colorStart !== -1) { var colorEnd = style.indexOf(')', colorStart); var channels = style.substring(colorStart + prefix.length, colorEnd).split(','); // Set alpha channel channels[3] = (channels[3] !== undefined ? parseFloat(channels[3]) * alpha : alpha); style = style.substring(0, colorStart) + 'rgba(' + channels.join(',') + style.substring(colorEnd, style.length); // Look for more colors colorStart = style.indexOf(prefix, colorEnd); } return style; }; /** * Validate the current field. * * @returns {Boolean} */ C.prototype.validate = function () { return true; }; /** * Remove the field from DOM. * * @returns {undefined} */ C.prototype.remove = function () { if (this.dnb !== undefined) { this.dnb.remove(); } this.$item.remove(); }; /** * Collect functions to execute once the tree is complete. * * @param {function} ready * @returns {undefined} */ C.prototype.ready = function (ready) { if (this.passReadies) { this.parent.ready(ready); } else { this.readies.push(ready); } }; /** * Add confirmation dialog to button. * @param {object} dialogOptions Dialog options. * @param {function} handleActions Handle both actions Confirmed and Canceled. */ C.prototype.showConfirmationDialog = function (dialogOptions, handleActions) { const confirmationDialog = new H5P.ConfirmationDialog(dialogOptions) .appendTo(document.body); confirmationDialog.on('confirmed', () => { if (handleActions) { handleActions(true); } }); confirmationDialog.on('canceled', () => { if (handleActions) { handleActions(false); } }); confirmationDialog.show(this.$item.offset().top); }; /** * Translate UI texts for this library. * * @param {String} key * @param {Object} vars * @returns {@exp;H5PEditor@call;t} */ C.t = function (key, vars) { return H5PEditor.t('H5PEditor.DragQuestion', key, vars); }; return C; })(H5P.jQuery, H5P.DragNBar);
Close