From d2f731551e89cdf6a2b3d19fd77a3dee85879008 Mon Sep 17 00:00:00 2001 From: Nils Hoffmann Date: Wed, 4 Sep 2024 12:22:00 +0200 Subject: [PATCH] suggested changes to build process and examples #1681 --- .../libs/bootstrap/bootstrap-tagsinput.min.js | 4 +- .../libs/bootstrap/bootstrap-wysiwyg.min.js | 2 +- OpenRobertaWeb/gulpfile.js | 112 ++++++++++++++---- OpenRobertaWeb/package-lock.json | 20 +++- OpenRobertaWeb/package.json | 4 +- 5 files changed, 111 insertions(+), 31 deletions(-) diff --git a/OpenRobertaServer/staticResources/libs/bootstrap/bootstrap-tagsinput.min.js b/OpenRobertaServer/staticResources/libs/bootstrap/bootstrap-tagsinput.min.js index 057ee9f427..cc0d74eba6 100644 --- a/OpenRobertaServer/staticResources/libs/bootstrap/bootstrap-tagsinput.min.js +++ b/OpenRobertaServer/staticResources/libs/bootstrap/bootstrap-tagsinput.min.js @@ -1,7 +1,7 @@ /* - * bootstrap-tagsinput v0.8.0 + * bootstrap-tagsinput v0.7.1 by Tim Schlechter * */ -!function(a){"use strict";function b(b,c){this.isInit=!0,this.itemsArray=[],this.$element=a(b),this.$element.hide(),this.isSelect="SELECT"===b.tagName,this.multiple=this.isSelect&&b.hasAttribute("multiple"),this.objectItems=c&&c.itemValue,this.placeholderText=b.hasAttribute("placeholder")?this.$element.attr("placeholder"):"",this.inputSize=Math.max(1,this.placeholderText.length),this.$container=a('
'),this.$input=a('').appendTo(this.$container),this.$element.before(this.$container),this.build(c),this.isInit=!1}function c(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(a){return a[c]}}}function d(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(){return c}}}function e(a){return a?i.text(a).html():""}function f(a){var b=0;if(document.selection){a.focus();var c=document.selection.createRange();c.moveStart("character",-a.value.length),b=c.text.length}else(a.selectionStart||"0"==a.selectionStart)&&(b=a.selectionStart);return b}function g(b,c){var d=!1;return a.each(c,function(a,c){if("number"==typeof c&&b.which===c)return d=!0,!1;if(b.which===c.which){var e=!c.hasOwnProperty("altKey")||b.altKey===c.altKey,f=!c.hasOwnProperty("shiftKey")||b.shiftKey===c.shiftKey,g=!c.hasOwnProperty("ctrlKey")||b.ctrlKey===c.ctrlKey;if(e&&f&&g)return d=!0,!1}}),d}var h={tagClass:function(a){return"label label-info"},focusClass:"focus",itemValue:function(a){return a?a.toString():a},itemText:function(a){return this.itemValue(a)},itemTitle:function(a){return null},freeInput:!0,addOnBlur:!0,maxTags:void 0,maxChars:void 0,confirmKeys:[13,44],delimiter:",",delimiterRegex:null,cancelConfirmKeysOnEmpty:!1,onTagExists:function(a,b){b.hide().fadeIn()},trimValue:!1,allowDuplicates:!1,triggerChange:!0};b.prototype={constructor:b,add:function(b,c,d){var f=this;if(!(f.options.maxTags&&f.itemsArray.length>=f.options.maxTags)&&(b===!1||b)){if("string"==typeof b&&f.options.trimValue&&(b=a.trim(b)),"object"==typeof b&&!f.objectItems)throw"Can't add objects when itemValue option is not set";if(!b.toString().match(/^\s*$/)){if(f.isSelect&&!f.multiple&&f.itemsArray.length>0&&f.remove(f.itemsArray[0]),"string"==typeof b&&"INPUT"===this.$element[0].tagName){var g=f.options.delimiterRegex?f.options.delimiterRegex:f.options.delimiter,h=b.split(g);if(h.length>1){for(var i=0;if.options.maxInputLength)){var o=a.Event("beforeItemAdd",{item:b,cancel:!1,options:d});if(f.$element.trigger(o),!o.cancel){f.itemsArray.push(b);var p=a(''+e(k)+'');p.data("item",b),f.findInputWrapper().before(p),p.after(" ");var q=a('option[value="'+encodeURIComponent(j)+'"]',f.$element).length||a('option[value="'+e(j)+'"]',f.$element).length;if(f.isSelect&&!q){var r=a("");r.data("item",b),r.attr("value",j),f.$element.append(r)}c||f.pushVal(f.options.triggerChange),f.options.maxTags!==f.itemsArray.length&&f.items().toString().length!==f.options.maxInputLength||f.$container.addClass("bootstrap-tagsinput-max"),a(".typeahead, .twitter-typeahead",f.$container).length&&f.$input.typeahead("val",""),this.isInit?f.$element.trigger(a.Event("itemAddedOnInit",{item:b,options:d})):f.$element.trigger(a.Event("itemAdded",{item:b,options:d}))}}}else if(f.options.onTagExists){var s=a(".tag",f.$container).filter(function(){return a(this).data("item")===n});f.options.onTagExists(b,s)}}}},remove:function(b,c,d){var e=this;if(e.objectItems&&(b="object"==typeof b?a.grep(e.itemsArray,function(a){return e.options.itemValue(a)==e.options.itemValue(b)}):a.grep(e.itemsArray,function(a){return e.options.itemValue(a)==b}),b=b[b.length-1]),b){var f=a.Event("beforeItemRemove",{item:b,cancel:!1,options:d});if(e.$element.trigger(f),f.cancel)return;a(".tag",e.$container).filter(function(){return a(this).data("item")===b}).remove(),a("option",e.$element).filter(function(){return a(this).data("item")===b}).remove(),a.inArray(b,e.itemsArray)!==-1&&e.itemsArray.splice(a.inArray(b,e.itemsArray),1)}c||e.pushVal(e.options.triggerChange),e.options.maxTags>e.itemsArray.length&&e.$container.removeClass("bootstrap-tagsinput-max"),e.$element.trigger(a.Event("itemRemoved",{item:b,options:d}))},removeAll:function(){var b=this;for(a(".tag",b.$container).remove(),a("option",b.$element).remove();b.itemsArray.length>0;)b.itemsArray.pop();b.pushVal(b.options.triggerChange)},refresh:function(){var b=this;a(".tag",b.$container).each(function(){var c=a(this),d=c.data("item"),f=b.options.itemValue(d),g=b.options.itemText(d),h=b.options.tagClass(d);if(c.attr("class",null),c.addClass("tag "+e(h)),c.contents().filter(function(){return 3==this.nodeType})[0].nodeValue=e(g),b.isSelect){var i=a("option",b.$element).filter(function(){return a(this).data("item")===d});i.attr("value",f)}})},items:function(){return this.itemsArray},pushVal:function(){var b=this,c=a.map(b.items(),function(a){return b.options.itemValue(a).toString()});b.$element.val(c,!0),b.options.triggerChange&&b.$element.trigger("change")},build:function(b){var e=this;if(e.options=a.extend({},h,b),e.objectItems&&(e.options.freeInput=!1),c(e.options,"itemValue"),c(e.options,"itemText"),d(e.options,"tagClass"),e.options.typeahead){var i=e.options.typeahead||{};d(i,"source"),e.$input.typeahead(a.extend({},i,{source:function(b,c){function d(a){for(var b=[],d=0;d$1")}}))}if(e.options.typeaheadjs){var j=e.options.typeaheadjs;a.isArray(j)||(j=[null,j]);var k=j[1].valueKey,l=k?function(a){return a[k]}:function(a){return a};a.fn.typeahead.apply(e.$input,j).on("typeahead:selected",a.proxy(function(a,b){e.add(l(b)),e.$input.typeahead("val","")},e))}e.$container.on("click",a.proxy(function(a){e.$element.attr("disabled")||e.$input.removeAttr("disabled"),e.$input.focus()},e)),e.options.addOnBlur&&e.options.freeInput&&e.$input.on("focusout",a.proxy(function(b){0===a(".typeahead, .twitter-typeahead",e.$container).length&&(e.add(e.$input.val()),e.$input.val(""))},e)),e.$container.on({focusin:function(){e.$container.addClass(e.options.focusClass)},focusout:function(){e.$container.removeClass(e.options.focusClass)}}),e.$container.on("keydown","input",a.proxy(function(b){var c=a(b.target),d=e.findInputWrapper();if(e.$element.attr("disabled"))return void e.$input.attr("disabled","disabled");switch(b.which){case 8:if(0===f(c[0])){var g=d.prev();g.length&&e.remove(g.data("item"))}break;case 46:if(0===f(c[0])){var h=d.next();h.length&&e.remove(h.data("item"))}break;case 37:var i=d.prev();0===c.val().length&&i[0]&&(i.before(d),c.focus());break;case 39:var j=d.next();0===c.val().length&&j[0]&&(j.after(d),c.focus())}var k=c.val().length;Math.ceil(k/5);c.attr("size",Math.max(this.inputSize,c.val().length))},e)),e.$container.on("keypress","input",a.proxy(function(b){var c=a(b.target);if(e.$element.attr("disabled"))return void e.$input.attr("disabled","disabled");var d=c.val(),f=e.options.maxChars&&d.length>=e.options.maxChars;e.options.freeInput&&(g(b,e.options.confirmKeys)||f)&&(0!==d.length&&(e.add(f?d.substr(0,e.options.maxChars):d),c.val("")),e.options.cancelConfirmKeysOnEmpty===!1&&b.preventDefault());var h=c.val().length;Math.ceil(h/5);c.attr("size",Math.max(this.inputSize,c.val().length))},e)),e.$container.on("click","[data-role=remove]",a.proxy(function(b){e.$element.attr("disabled")||e.remove(a(b.target).closest(".tag").data("item"))},e)),e.options.itemValue===h.itemValue&&("INPUT"===e.$element[0].tagName?e.add(e.$element.val()):a("option",e.$element).each(function(){e.add(a(this).attr("value"),!0)}))},destroy:function(){var a=this;a.$container.off("keypress","input"),a.$container.off("click","[role=remove]"),a.$container.remove(),a.$element.removeData("tagsinput"),a.$element.show()},focus:function(){this.$input.focus()},input:function(){return this.$input},findInputWrapper:function(){for(var b=this.$input[0],c=this.$container[0];b&&b.parentNode!==c;)b=b.parentNode;return a(b)}},a.fn.tagsinput=function(c,d,e){var f=[];return this.each(function(){var g=a(this).data("tagsinput");if(g)if(c||d){if(void 0!==g[c]){if(3===g[c].length&&void 0!==e)var h=g[c](d,null,e);else var h=g[c](d);void 0!==h&&f.push(h)}}else f.push(g);else g=new b(this,c),a(this).data("tagsinput",g),f.push(g),"SELECT"===this.tagName&&a("option",a(this)).attr("selected","selected"),a(this).val(a(this).val())}),"string"==typeof c?f.length>1?f:f[0]:f},a.fn.tagsinput.Constructor=b;var i=a("
");a(function(){a("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput()})}(window.jQuery); +!function(a){"use strict";function b(b,c){this.isInit=!0,this.itemsArray=[],this.$element=a(b),this.$element.hide(),this.isSelect="SELECT"===b.tagName,this.multiple=this.isSelect&&b.hasAttribute("multiple"),this.objectItems=c&&c.itemValue,this.placeholderText=b.hasAttribute("placeholder")?this.$element.attr("placeholder"):"",this.inputSize=Math.max(1,this.placeholderText.length),this.$container=a('
'),this.$input=a('').appendTo(this.$container),this.$element.before(this.$container),this.build(c),this.isInit=!1}function c(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(a){return a[c]}}}function d(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(){return c}}}function e(a){return a?i.text(a).html():""}function f(a){var b=0;if(document.selection){a.focus();var c=document.selection.createRange();c.moveStart("character",-a.value.length),b=c.text.length}else(a.selectionStart||"0"==a.selectionStart)&&(b=a.selectionStart);return b}function g(b,c){var d=!1;return a.each(c,function(a,c){if("number"==typeof c&&b.which===c)return d=!0,!1;if(b.which===c.which){var e=!c.hasOwnProperty("altKey")||b.altKey===c.altKey,f=!c.hasOwnProperty("shiftKey")||b.shiftKey===c.shiftKey,g=!c.hasOwnProperty("ctrlKey")||b.ctrlKey===c.ctrlKey;if(e&&f&&g)return d=!0,!1}}),d}var h={tagClass:function(a){return"label label-info"},itemValue:function(a){return a?a.toString():a},itemText:function(a){return this.itemValue(a)},itemTitle:function(a){return null},freeInput:!0,addOnBlur:!0,maxTags:void 0,maxChars:void 0,confirmKeys:[13,44],delimiter:",",delimiterRegex:null,cancelConfirmKeysOnEmpty:!1,onTagExists:function(a,b){b.hide().fadeIn()},trimValue:!1,allowDuplicates:!1};b.prototype={constructor:b,add:function(b,c,d){var f=this;if(!(f.options.maxTags&&f.itemsArray.length>=f.options.maxTags)&&(b===!1||b)){if("string"==typeof b&&f.options.trimValue&&(b=a.trim(b)),"object"==typeof b&&!f.objectItems)throw"Can't add objects when itemValue option is not set";if(!b.toString().match(/^\s*$/)){if(f.isSelect&&!f.multiple&&f.itemsArray.length>0&&f.remove(f.itemsArray[0]),"string"==typeof b&&"INPUT"===this.$element[0].tagName){var g=f.options.delimiterRegex?f.options.delimiterRegex:f.options.delimiter,h=b.split(g);if(h.length>1){for(var i=0;if.options.maxInputLength)){var o=a.Event("beforeItemAdd",{item:b,cancel:!1,options:d});if(f.$element.trigger(o),!o.cancel){f.itemsArray.push(b);var p=a(''+e(k)+'');p.data("item",b),f.findInputWrapper().before(p),p.after(" ");var q=a('option[value="'+encodeURIComponent(j)+'"]',f.$element).length||a('option[value="'+e(j)+'"]',f.$element).length;if(f.isSelect&&!q){var r=a("");r.data("item",b),r.attr("value",j),f.$element.append(r)}c||f.pushVal(),(f.options.maxTags===f.itemsArray.length||f.items().toString().length===f.options.maxInputLength)&&f.$container.addClass("bootstrap-tagsinput-max"),a(".typeahead, .twitter-typeahead",f.$container).length&&f.$input.typeahead("val",""),this.isInit?f.$element.trigger(a.Event("itemAddedOnInit",{item:b,options:d})):f.$element.trigger(a.Event("itemAdded",{item:b,options:d}))}}}else if(f.options.onTagExists){var s=a(".tag",f.$container).filter(function(){return a(this).data("item")===n});f.options.onTagExists(b,s)}}}},remove:function(b,c,d){var e=this;if(e.objectItems&&(b="object"==typeof b?a.grep(e.itemsArray,function(a){return e.options.itemValue(a)==e.options.itemValue(b)}):a.grep(e.itemsArray,function(a){return e.options.itemValue(a)==b}),b=b[b.length-1]),b){var f=a.Event("beforeItemRemove",{item:b,cancel:!1,options:d});if(e.$element.trigger(f),f.cancel)return;a(".tag",e.$container).filter(function(){return a(this).data("item")===b}).remove(),a("option",e.$element).filter(function(){return a(this).data("item")===b}).remove(),-1!==a.inArray(b,e.itemsArray)&&e.itemsArray.splice(a.inArray(b,e.itemsArray),1)}c||e.pushVal(),e.options.maxTags>e.itemsArray.length&&e.$container.removeClass("bootstrap-tagsinput-max"),e.$element.trigger(a.Event("itemRemoved",{item:b,options:d}))},removeAll:function(){var b=this;for(a(".tag",b.$container).remove(),a("option",b.$element).remove();b.itemsArray.length>0;)b.itemsArray.pop();b.pushVal()},refresh:function(){var b=this;a(".tag",b.$container).each(function(){var c=a(this),d=c.data("item"),f=b.options.itemValue(d),g=b.options.itemText(d),h=b.options.tagClass(d);if(c.attr("class",null),c.addClass("tag "+e(h)),c.contents().filter(function(){return 3==this.nodeType})[0].nodeValue=e(g),b.isSelect){var i=a("option",b.$element).filter(function(){return a(this).data("item")===d});i.attr("value",f)}})},items:function(){return this.itemsArray},pushVal:function(){var b=this,c=a.map(b.items(),function(a){return b.options.itemValue(a).toString()});b.$element.val(c,!0).trigger("change")},build:function(b){var e=this;if(e.options=a.extend({},h,b),e.objectItems&&(e.options.freeInput=!1),c(e.options,"itemValue"),c(e.options,"itemText"),d(e.options,"tagClass"),e.options.typeahead){var i=e.options.typeahead||{};d(i,"source"),e.$input.typeahead(a.extend({},i,{source:function(b,c){function d(a){for(var b=[],d=0;d$1")}}))}if(e.options.typeaheadjs){var j=null,k={},l=e.options.typeaheadjs;a.isArray(l)?(j=l[0],k=l[1]):k=l,e.$input.typeahead(j,k).on("typeahead:selected",a.proxy(function(a,b){k.valueKey?e.add(b[k.valueKey]):e.add(b),e.$input.typeahead("val","")},e))}e.$container.on("click",a.proxy(function(a){e.$element.attr("disabled")||e.$input.removeAttr("disabled"),e.$input.focus()},e)),e.options.addOnBlur&&e.options.freeInput&&e.$input.on("focusout",a.proxy(function(b){0===a(".typeahead, .twitter-typeahead",e.$container).length&&(e.add(e.$input.val()),e.$input.val(""))},e)),e.$container.on("keydown","input",a.proxy(function(b){var c=a(b.target),d=e.findInputWrapper();if(e.$element.attr("disabled"))return void e.$input.attr("disabled","disabled");switch(b.which){case 8:if(0===f(c[0])){var g=d.prev();g.length&&e.remove(g.data("item"))}break;case 46:if(0===f(c[0])){var h=d.next();h.length&&e.remove(h.data("item"))}break;case 37:var i=d.prev();0===c.val().length&&i[0]&&(i.before(d),c.focus());break;case 39:var j=d.next();0===c.val().length&&j[0]&&(j.after(d),c.focus())}var k=c.val().length;Math.ceil(k/5);c.attr("size",Math.max(this.inputSize,c.val().length))},e)),e.$container.on("keypress","input",a.proxy(function(b){var c=a(b.target);if(e.$element.attr("disabled"))return void e.$input.attr("disabled","disabled");var d=c.val(),f=e.options.maxChars&&d.length>=e.options.maxChars;e.options.freeInput&&(g(b,e.options.confirmKeys)||f)&&(0!==d.length&&(e.add(f?d.substr(0,e.options.maxChars):d),c.val("")),e.options.cancelConfirmKeysOnEmpty===!1&&b.preventDefault());var h=c.val().length;Math.ceil(h/5);c.attr("size",Math.max(this.inputSize,c.val().length))},e)),e.$container.on("click","[data-role=remove]",a.proxy(function(b){e.$element.attr("disabled")||e.remove(a(b.target).closest(".tag").data("item"))},e)),e.options.itemValue===h.itemValue&&("INPUT"===e.$element[0].tagName?e.add(e.$element.val()):a("option",e.$element).each(function(){e.add(a(this).attr("value"),!0)}))},destroy:function(){var a=this;a.$container.off("keypress","input"),a.$container.off("click","[role=remove]"),a.$container.remove(),a.$element.removeData("tagsinput"),a.$element.show()},focus:function(){this.$input.focus()},input:function(){return this.$input},findInputWrapper:function(){for(var b=this.$input[0],c=this.$container[0];b&&b.parentNode!==c;)b=b.parentNode;return a(b)}},a.fn.tagsinput=function(c,d,e){var f=[];return this.each(function(){var g=a(this).data("tagsinput");if(g)if(c||d){if(void 0!==g[c]){if(3===g[c].length&&void 0!==e)var h=g[c](d,null,e);else var h=g[c](d);void 0!==h&&f.push(h)}}else f.push(g);else g=new b(this,c),a(this).data("tagsinput",g),f.push(g),"SELECT"===this.tagName&&a("option",a(this)).attr("selected","selected"),a(this).val(a(this).val())}),"string"==typeof c?f.length>1?f:f[0]:f},a.fn.tagsinput.Constructor=b;var i=a("
");a(function(){a("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput()})}(window.jQuery); //# sourceMappingURL=bootstrap-tagsinput.min.js.map \ No newline at end of file diff --git a/OpenRobertaServer/staticResources/libs/bootstrap/bootstrap-wysiwyg.min.js b/OpenRobertaServer/staticResources/libs/bootstrap/bootstrap-wysiwyg.min.js index e06fc8c3bd..6211a3e5a8 100644 --- a/OpenRobertaServer/staticResources/libs/bootstrap/bootstrap-wysiwyg.min.js +++ b/OpenRobertaServer/staticResources/libs/bootstrap/bootstrap-wysiwyg.min.js @@ -7,4 +7,4 @@ * About = A tiny Bootstrap and jQuery based WYSIWYG rich text editor based on the browser function execCommand. */ -!function(a,b){"use strict";function c(c,d){this.selectedRange=null,this.editor=b(c);var e=b(c),f={hotKeys:{"Ctrl+b meta+b":"bold","Ctrl+i meta+i":"italic","Ctrl+u meta+u":"underline","Ctrl+z":"undo","Ctrl+y meta+y meta+shift+z":"redo","Ctrl+l meta+l":"justifyleft","Ctrl+r meta+r":"justifyright","Ctrl+e meta+e":"justifycenter","Ctrl+j meta+j":"justifyfull","Shift+tab":"outdent",tab:"indent"},toolbarSelector:"[data-role=editor-toolbar]",commandRole:"edit",activeToolbarClass:"btn-info",selectionMarker:"edit-focus-marker",selectionColor:"darkgrey",dragAndDropImages:!0,keypressTimeout:200,fileUploadError:function(a,b){console.log("File upload error",a,b)}},g=b.extend(!0,{},f,d),h="a[data-"+g.commandRole+"],button[data-"+g.commandRole+"],input[type=button][data-"+g.commandRole+"]";this.bindHotkeys(e,g,h),g.dragAndDropImages&&this.initFileDrops(e,g,h),this.bindToolbar(e,b(g.toolbarSelector),g,h),e.attr("contenteditable",!0).on("mouseup keyup mouseout",function(){this.saveSelection(),this.updateToolbar(e,h,g)}.bind(this));var i=this;b(a).bind("touchend",function(a){var b=e.is(a.target)||e.has(a.target).length>0,c=i.getCurrentRange();c&&c.startContainer===c.endContainer&&c.startOffset===c.endOffset&&!b||(i.saveSelection(),i.updateToolbar(e,h,g))})}function d(b){if(a.getSelection&&document.createRange){var c=a.getSelection(),d=document.createRange();d.selectNodeContents(b),c.removeAllRanges(),c.addRange(d)}else if(document.selection&&document.body.createTextRange){var e=document.body.createTextRange();e.moveToElementText(b),e.select()}}c.prototype.readFileIntoDataUrl=function(a){var c=b.Deferred(),d=new FileReader;return d.onload=function(a){c.resolve(a.target.result)},d.onerror=c.reject,d.onprogress=c.notify,d.readAsDataURL(a),c.promise()},c.prototype.cleanHtml=function(a){var c=this;if(!0===b(c).data("wysiwyg-html-mode")&&(b(c).html(b(c).text()),b(c).attr("contenteditable",!0),b(c).data("wysiwyg-html-mode",!1)),!0===a&&b(c).parent().is("form")){var d=b(c).html;if(b(d).has("img").length){var e=b("img",b(d)),f=[],g=b(c).parent();b.each(e,function(a,c){b(c).attr("src").match(/^data:image\/.*$/)&&(f.push(e[a]),b(g).prepend(""),b(c).attr("src","postedimage/"+a))})}}var h=b(c).html();return h&&h.replace(/(
|\s|

<\/div>| )*$/,"")},c.prototype.updateToolbar=function(a,c,d){d.activeToolbarClass&&b(d.toolbarSelector).find(c).each(function(){var a=b(this),c=a.data(d.commandRole).split(" "),e=c[0];c.length>1&&document.queryCommandEnabled(e)&&document.queryCommandValue(e)===c[1]?a.addClass(d.activeToolbarClass):1===c.length&&document.queryCommandEnabled(e)&&document.queryCommandState(e)?a.addClass(d.activeToolbarClass):a.removeClass(d.activeToolbarClass)})},c.prototype.execCommand=function(a,b,c,d,e){var f=a.split(" "),g=f.shift(),h=f.join(" ")+(b||""),i=a.split("-");1===i.length?document.execCommand(g,!1,h):"format"===i[0]&&2===i.length&&document.execCommand("formatBlock",!1,i[1]),c.trigger("change"),this.updateToolbar(c,e,d)},c.prototype.bindHotkeys=function(a,c,d){var e=this;b.each(c.hotKeys,function(f,g){g&&b(a).keydown(f,function(f){a.attr("contenteditable")&&b(a).is(":visible")&&(f.preventDefault(),f.stopPropagation(),e.execCommand(g,null,a,c,d))}).keyup(f,function(c){a.attr("contenteditable")&&b(a).is(":visible")&&(c.preventDefault(),c.stopPropagation())})}),a.keyup(function(){a.trigger("change")})},c.prototype.getCurrentRange=function(){var b,c;return a.getSelection?(b=a.getSelection(),b.getRangeAt&&b.rangeCount&&(c=b.getRangeAt(0))):document.selection&&(c=document.selection.createRange()),c},c.prototype.saveSelection=function(){this.selectedRange=this.getCurrentRange()},c.prototype.restoreSelection=function(){var b;if(a.getSelection||document.createRange){if(b=a.getSelection(),this.selectedRange){try{b.removeAllRanges()}catch(c){document.body.createTextRange().select(),document.selection.empty()}b.addRange(this.selectedRange)}}else document.selection&&this.selectedRange&&this.selectedRange.select()},c.prototype.toggleHtmlEdit=function(a){if(!0!==a.data("wysiwyg-html-mode")){var c=a.html(),d=b("
");b(d).append(document.createTextNode(c)),b(d).attr("contenteditable",!0),b(a).html(" "),b(a).append(b(d)),b(a).attr("contenteditable",!1),b(a).data("wysiwyg-html-mode",!0),b(d).focus()}else b(a).html(b(a).text()),b(a).attr("contenteditable",!0),b(a).data("wysiwyg-html-mode",!1),b(a).focus()},c.prototype.insertFiles=function(a,c,d,e){var f=this;d.focus(),b.each(a,function(a,g){/^image\//.test(g.type)?b.when(f.readFileIntoDataUrl(g)).done(function(a){f.execCommand("insertimage",a,d,c,e),d.trigger("image-inserted")}).fail(function(a){c.fileUploadError("file-reader",a)}):c.fileUploadError("unsupported-file-type",g.type)})},c.prototype.markSelection=function(a,b){this.restoreSelection(),document.queryCommandSupported("hiliteColor")&&document.execCommand("hiliteColor",!1,a||"transparent"),this.saveSelection()},c.prototype.bindToolbar=function(c,e,f,g){var h=this;e.find(g).click(function(){h.restoreSelection(),c.focus(),"html"===c.data(f.commandRole)?h.toggleHtmlEdit(c):h.execCommand(b(this).data(f.commandRole),null,c,f,g),h.saveSelection()}),e.find("[data-toggle=dropdown]").on("click",function(){h.markSelection(f.selectionColor,f)}),e.on("hide.bs.dropdown",function(){h.markSelection(!1,f)}),e.find("input[type=text][data-"+f.commandRole+"]").on("webkitspeechchange change",function(){var e=this.value;this.value="",h.restoreSelection(),""===a.getSelection().toString().trim()&&e&&(h.editor.append(""+e+""),d(b("span:last",h.editor)[0])),e&&(c.focus(),h.execCommand(b(this).data(f.commandRole),e,c,f,g)),h.saveSelection()}).on("blur",function(){b(this);h.markSelection(!1,f)}),e.find("input[type=file][data-"+f.commandRole+"]").change(function(){h.restoreSelection(),"file"===this.type&&this.files&&this.files.length>0&&h.insertFiles(this.files,f,c,g),h.saveSelection(),this.value=""})},c.prototype.initFileDrops=function(a,b,c){var d=this;a.on("dragenter dragover",!1).on("drop",function(e){var f=e.originalEvent.dataTransfer;e.stopPropagation(),e.preventDefault(),f&&f.files&&f.files.length>0&&d.insertFiles(f.files,b,a,c)})},b.fn.wysiwyg=function(a){new c(this,a)}}(window,window.jQuery);
\ No newline at end of file
+!function(a,b){"use strict";function c(c,d){this.selectedRange=null,this.editor=b(c);var e=b(c),f={hotKeys:{"Ctrl+b meta+b":"bold","Ctrl+i meta+i":"italic","Ctrl+u meta+u":"underline","Ctrl+z":"undo","Ctrl+y meta+y meta+shift+z":"redo","Ctrl+l meta+l":"justifyleft","Ctrl+r meta+r":"justifyright","Ctrl+e meta+e":"justifycenter","Ctrl+j meta+j":"justifyfull","Shift+tab":"outdent",tab:"indent"},toolbarSelector:"[data-role=editor-toolbar]",commandRole:"edit",activeToolbarClass:"btn-info",selectionMarker:"edit-focus-marker",selectionColor:"darkgrey",dragAndDropImages:!0,keypressTimeout:200,fileUploadError:function(a,b){console.log("File upload error",a,b)}},g=b.extend(!0,{},f,d),h="a[data-"+g.commandRole+"],button[data-"+g.commandRole+"],input[type=button][data-"+g.commandRole+"]";this.bindHotkeys(e,g,h),g.dragAndDropImages&&this.initFileDrops(e,g,h),this.bindToolbar(e,b(g.toolbarSelector),g,h),e.attr("contenteditable",!0).on("mouseup keyup mouseout",function(){this.saveSelection(),this.updateToolbar(e,h,g)}.bind(this)),b(a).bind("touchend",function(a){var b=e.is(a.target)||e.has(a.target).length>0,c=this.getCurrentRange(),d=c&&c.startContainer===c.endContainer&&c.startOffset===c.endOffset;(!d||b)&&(this.saveSelection(),this.updateToolbar(e,h,g))})}c.prototype.readFileIntoDataUrl=function(a){var c=b.Deferred(),d=new FileReader;return d.onload=function(a){c.resolve(a.target.result)},d.onerror=c.reject,d.onprogress=c.notify,d.readAsDataURL(a),c.promise()},c.prototype.cleanHtml=function(a){var c=this;if(b(c).data("wysiwyg-html-mode")===!0&&(b(c).html(b(c).text()),b(c).attr("contenteditable",!0),b(c).data("wysiwyg-html-mode",!1)),a===!0&&b(c).parent().is("form")){var d=b(c).html;if(b(d).has("img").length){var e=b("img",b(d)),f=[],g=b(c).parent();b.each(e,function(a,c){b(c).attr("src").match(/^data:image\/.*$/)&&(f.push(e[a]),b(g).prepend(""),b(c).attr("src","postedimage/"+a))})}}var h=b(c).html();return h&&h.replace(/(
|\s|

<\/div>| )*$/,"")},c.prototype.updateToolbar=function(a,c,d){d.activeToolbarClass&&b(d.toolbarSelector).find(c).each(function(){var a=b(this),c=a.data(d.commandRole).split(" "),e=c[0];c.length>1&&document.queryCommandEnabled(e)&&document.queryCommandValue(e)===c[1]?a.addClass(d.activeToolbarClass):1===c.length&&document.queryCommandEnabled(e)&&document.queryCommandState(e)?a.addClass(d.activeToolbarClass):a.removeClass(d.activeToolbarClass)})},c.prototype.execCommand=function(a,b,c,d,e){var f=a.split(" "),g=f.shift(),h=f.join(" ")+(b||""),i=a.split("-");1===i.length?document.execCommand(g,!1,h):"format"===i[0]&&2===i.length&&document.execCommand("formatBlock",!1,i[1]),c.trigger("change"),this.updateToolbar(c,e,d)},c.prototype.bindHotkeys=function(a,c,d){var e=this;b.each(c.hotKeys,function(f,g){b(a).keydown(f,function(f){a.attr("contenteditable")&&b(a).is(":visible")&&(f.preventDefault(),f.stopPropagation(),e.execCommand(g,null,a,c,d))}).keyup(f,function(c){a.attr("contenteditable")&&b(a).is(":visible")&&(c.preventDefault(),c.stopPropagation())})}),a.keyup(function(){a.trigger("change")})},c.prototype.getCurrentRange=function(){var b,c;return a.getSelection?(b=a.getSelection(),b.getRangeAt&&b.rangeCount&&(c=b.getRangeAt(0))):document.selection&&(c=document.selection.createRange()),c},c.prototype.saveSelection=function(){this.selectedRange=this.getCurrentRange()},c.prototype.restoreSelection=function(){var b;if(a.getSelection||document.createRange){if(b=a.getSelection(),this.selectedRange){try{b.removeAllRanges()}catch(c){document.body.createTextRange().select(),document.selection.empty()}b.addRange(this.selectedRange)}}else document.selection&&this.selectedRange&&this.selectedRange.select()},c.prototype.toggleHtmlEdit=function(a){if(a.data("wysiwyg-html-mode")!==!0){var c=a.html(),d=b("
");b(d).append(document.createTextNode(c)),b(d).attr("contenteditable",!0),b(a).html(" "),b(a).append(b(d)),b(a).attr("contenteditable",!1),b(a).data("wysiwyg-html-mode",!0),b(d).focus()}else b(a).html(b(a).text()),b(a).attr("contenteditable",!0),b(a).data("wysiwyg-html-mode",!1),b(a).focus()},c.prototype.insertFiles=function(a,c,d,e){var f=this;d.focus(),b.each(a,function(a,g){/^image\//.test(g.type)?b.when(f.readFileIntoDataUrl(g)).done(function(a){f.execCommand("insertimage",a,d,c,e),d.trigger("image-inserted")}).fail(function(a){c.fileUploadError("file-reader",a)}):c.fileUploadError("unsupported-file-type",g.type)})},c.prototype.markSelection=function(a,b,c){this.restoreSelection(),document.queryCommandSupported("hiliteColor")&&document.execCommand("hiliteColor",!1,b||"transparent"),this.saveSelection(),a.data(c.selectionMarker,b)},c.prototype.bindToolbar=function(a,c,d,e){var f=this;c.find(e).click(function(){f.restoreSelection(),a.focus(),"html"===a.data(d.commandRole)?f.toggleHtmlEdit(a):f.execCommand(b(this).data(d.commandRole),null,a,d,e),f.saveSelection()}),c.find("[data-toggle=dropdown]").click(this.restoreSelection()),c.find("input[type=text][data-"+d.commandRole+"]").on("webkitspeechchange change",function(){var c=this.value;this.value="",f.restoreSelection(),c&&(a.focus(),f.execCommand(b(this).data(d.commandRole),c,a,d,e)),f.saveSelection()}).on("focus",function(){var a=b(this);a.data(d.selectionMarker)||(f.markSelection(a,d.selectionColor,d),a.focus())}).on("blur",function(){var a=b(this);a.data(d.selectionMarker)&&f.markSelection(a,!1,d)}),c.find("input[type=file][data-"+d.commandRole+"]").change(function(){f.restoreSelection(),"file"===this.type&&this.files&&this.files.length>0&&f.insertFiles(this.files,d,a,e),f.saveSelection(),this.value=""})},c.prototype.initFileDrops=function(a,b,c){var d=this;a.on("dragenter dragover",!1).on("drop",function(e){var f=e.originalEvent.dataTransfer;e.stopPropagation(),e.preventDefault(),f&&f.files&&f.files.length>0&&d.insertFiles(f.files,b,a,c)})},b.fn.wysiwyg=function(a){new c(this,a)}}(window,window.jQuery);
\ No newline at end of file
diff --git a/OpenRobertaWeb/gulpfile.js b/OpenRobertaWeb/gulpfile.js
index 5afcb4fa66..55aafb0914 100644
--- a/OpenRobertaWeb/gulpfile.js
+++ b/OpenRobertaWeb/gulpfile.js
@@ -19,17 +19,81 @@ const files = {
     jsPath: 'src/**/*',
     nodePaths: [
         {
-            //folder name in libs
             moduleName: 'ace',
-            //base path for the node module
-            base: '../OpenRobertaWeb/node_modules/ace-builds/src-min-noconflict',
-            //defines files to be copied over
-            src: [
-                //you may add '/**/*.js' instead of a {folder: '', file['']} structure or similar paths with wildcard
+            bases: [
                 {
-                    //the base folder is just an empty string, files may also be described as *.js if all files of a given folder should be copied
-                    folder: '',
-                    files: ['ace.js', 'ext-language_tools.js', 'mode-c_cpp.js', 'mode-java.js', 'mode-python.js', 'mode-json.js'],
+                    base: '../OpenRobertaWeb/node_modules/ace-builds/src-min-noconflict',
+                    //defines files to be copied over
+                    src: [
+                        //you may add '/**/*.js' instead of a {folder: '', file['']} structure or similar paths with wildcard
+                        {
+                            //the base folder is just an empty string, files may also be described as *.js if all files of a given folder should be copied
+                            folderSrc: '',
+                            folderDest: '',
+                            files: ['ace.js', 'ext-language_tools.js', 'mode-c_cpp.js', 'mode-java.js', 'mode-python.js', 'mode-json.js'],
+                        },
+                    ],
+                },
+            ],
+        },
+        {
+            moduleName: 'bootstrap',
+            bases: [
+                {
+                    base: '../OpenRobertaWeb/node_modules/bootstrap',
+                    src: [
+                        {
+                            folderSrc: 'dist/js',
+                            folderDest: '',
+                            files: ['bootstrap.bundle.min.js'],
+                        },
+                    ],
+                },
+                {
+                    base: '../OpenRobertaWeb/node_modules/bootstrap-tagsinput',
+                    src: [
+                        {
+                            folderSrc: 'dist',
+                            folderDest: '',
+                            files: ['bootstrap-tagsinput.min.js'],
+                        },
+                    ],
+                },
+                {
+                    base: '../OpenRobertaWeb/node_modules/bootstrap-wysiwyg/',
+                    src: [
+                        {
+                            folderSrc: 'js',
+                            folderDest: '',
+                            files: ['bootstrap-wysiwyg.min.js'],
+                        },
+                    ],
+                },
+                {
+                    //TODO boostrap-tables
+                    base: '',
+                    src: [
+                        {
+                            folderSrc: '',
+                            folderDest: 'boostrap-table-1.22.1-dist',
+                            files: ['bootstrap-table.min.js', 'bootstrap-table-local.min.js'],
+                        },
+                    ],
+                },
+            ],
+        },
+        {
+            moduleName: 'dapjs',
+            bases: [
+                {
+                    base: '../OpenRobertaWeb/node_modules/dapjs',
+                    src: [
+                        {
+                            folderSrc: 'dist',
+                            folderDest: '',
+                            files: ['dap.umd.js'],
+                        },
+                    ],
                 },
             ],
         },
@@ -68,21 +132,23 @@ function jsTask() {
 
 function nodeTask() {
     const streams = files.nodePaths.map(function (module) {
-        return module.src.map(function (source) {
-            if (typeof source === 'string') {
-                return src(module.base + source, { sourcemaps: true }) // set source and turn on sourcemaps
-                    .pipe(dest('../OpenRobertaServer/staticResources/libs/' + module.moduleName, { sourcemaps: '.' }));
-            } else if (source.folder !== undefined && source.files !== undefined) {
-                return source.files.map(function (file) {
-                    return src(module.base + '/' + source.folder + '/' + file).pipe(
-                        dest('../OpenRobertaServer/staticResources/libs/' + module.moduleName + '/' + source.folder, { sourcemaps: '.' })
+        return module.bases.map(function (base) {
+            return base.src.map(function (source) {
+                if (typeof source === 'string') {
+                    return src(base.base + source, { sourcemaps: true }) // set source and turn on sourcemaps
+                        .pipe(dest('../OpenRobertaServer/staticResources/libs/' + module.moduleName, { sourcemaps: '.' }));
+                } else if (source.folderSrc !== undefined && source.folderDest !== undefined && source.files !== undefined) {
+                    return source.files.map(function (file) {
+                        return src(base.base + '/' + source.folderSrc + '/' + file).pipe(
+                            dest('../OpenRobertaServer/staticResources/libs/' + module.moduleName + '/' + source.folderDest, { sourcemaps: '.' })
+                        );
+                    });
+                } else {
+                    throw Error(
+                        'make sure to define folder and files for each source or add a plain string as path, for copying from base folder leave this as an empty String'
                     );
-                });
-            } else {
-                throw Error(
-                    'make sure to define folder and files for each source or add a plain string as path, for copying from base folder leave this as an empty String'
-                );
-            }
+                }
+            });
         });
     });
     return merge(...streams);
diff --git a/OpenRobertaWeb/package-lock.json b/OpenRobertaWeb/package-lock.json
index 1a6db27ebe..d8c9152c98 100644
--- a/OpenRobertaWeb/package-lock.json
+++ b/OpenRobertaWeb/package-lock.json
@@ -12,7 +12,9 @@
         "@types/ace": "^0.0.52",
         "ace-builds": "^1.35.2",
         "bootstrap": "^5.3.2",
-        "bootstrap-table": "^1.22.1",
+        "bootstrap-table": "^1.22.2",
+        "bootstrap-tagsinput": "^0.7.1",
+        "bootstrap-wysiwyg": "^2.0.1",
         "d3": "^3.5.16",
         "dapjs": "^2.3.0",
         "gulp": "^5.0.0",
@@ -699,13 +701,23 @@
       }
     },
     "node_modules/bootstrap-table": {
-      "version": "1.22.1",
-      "resolved": "https://registry.npmjs.org/bootstrap-table/-/bootstrap-table-1.22.1.tgz",
-      "integrity": "sha512-Nw8p+BmaiMDSfoer/p49YeI3vJQAWhudxhyKMuqnJBb3NRvCRewMk7JDgiN9SQO3YeSejOirKtcdWpM0dtddWg==",
+      "version": "1.23.2",
+      "resolved": "https://registry.npmjs.org/bootstrap-table/-/bootstrap-table-1.23.2.tgz",
+      "integrity": "sha512-1IFiWFZzbKlleXgYEHdwHkX6rxlQMEx2N1tA8rJK/j08pI+NjIGnxFeXUL26yQLQ0U135eis/BX3OV1+anY25g==",
       "peerDependencies": {
         "jquery": "3"
       }
     },
+    "node_modules/bootstrap-tagsinput": {
+      "version": "0.7.1",
+      "resolved": "https://registry.npmjs.org/bootstrap-tagsinput/-/bootstrap-tagsinput-0.7.1.tgz",
+      "integrity": "sha512-xSks67GWgXLnmO5gqp788vhh7WoXd9mHj5uKE5zg8rvw3sNYYSCjrSlrPRlPdpYKwmuxeuf2jsNjBSWEucyB1w=="
+    },
+    "node_modules/bootstrap-wysiwyg": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/bootstrap-wysiwyg/-/bootstrap-wysiwyg-2.0.1.tgz",
+      "integrity": "sha512-lZsz2sU0NoOJmUaVg86ZJHmNXSfAb13EThfzMhY1K/nUAXPHcBPAxvG3sIfaonKkchEDDAI1jAWxQUsmvsOR4A=="
+    },
     "node_modules/brace-expansion": {
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
diff --git a/OpenRobertaWeb/package.json b/OpenRobertaWeb/package.json
index bd2e52c234..cdf801ad11 100644
--- a/OpenRobertaWeb/package.json
+++ b/OpenRobertaWeb/package.json
@@ -18,7 +18,9 @@
     "@types/ace": "^0.0.52",
     "ace-builds": "^1.35.2",
     "bootstrap": "^5.3.2",
-    "bootstrap-table": "^1.22.1",
+    "bootstrap-table": "^1.22.2",
+    "bootstrap-tagsinput": "^0.7.1",
+    "bootstrap-wysiwyg": "^2.0.1",
     "d3": "^3.5.16",
     "dapjs": "^2.3.0",
     "gulp": "^5.0.0",