mirror of https://github.com/snachodog/mybuddy.git
Update static files so tests run
This commit is contained in:
parent
8a37b44839
commit
bd78149db3
|
@ -10586,6 +10586,10 @@ h3 {
|
||||||
font-size: 1.65em;
|
font-size: 1.65em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
color: #343a40;
|
||||||
|
}
|
||||||
|
|
||||||
#view-core\:child .child-photo {
|
#view-core\:child .child-photo {
|
||||||
max-width: 150px;
|
max-width: 150px;
|
||||||
}
|
}
|
Binary file not shown.
Binary file not shown.
|
@ -13248,46 +13248,46 @@ function transpose(out, a) {
|
||||||
};
|
};
|
||||||
},{}],64:[function(_dereq_,module,exports){
|
},{}],64:[function(_dereq_,module,exports){
|
||||||
(function (global){(function (){
|
(function (global){(function (){
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
var isBrowser = _dereq_('is-browser')
|
var isBrowser = _dereq_('is-browser')
|
||||||
var hasHover
|
var hasHover
|
||||||
|
|
||||||
if (typeof global.matchMedia === 'function') {
|
if (typeof global.matchMedia === 'function') {
|
||||||
hasHover = !global.matchMedia('(hover: none)').matches
|
hasHover = !global.matchMedia('(hover: none)').matches
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
hasHover = isBrowser
|
hasHover = isBrowser
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = hasHover
|
module.exports = hasHover
|
||||||
|
|
||||||
}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||||||
},{"is-browser":68}],65:[function(_dereq_,module,exports){
|
},{"is-browser":68}],65:[function(_dereq_,module,exports){
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
var isBrowser = _dereq_('is-browser')
|
var isBrowser = _dereq_('is-browser')
|
||||||
|
|
||||||
function detect() {
|
function detect() {
|
||||||
var supported = false
|
var supported = false
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var opts = Object.defineProperty({}, 'passive', {
|
var opts = Object.defineProperty({}, 'passive', {
|
||||||
get: function() {
|
get: function() {
|
||||||
supported = true
|
supported = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
window.addEventListener('test', null, opts)
|
window.addEventListener('test', null, opts)
|
||||||
window.removeEventListener('test', null, opts)
|
window.removeEventListener('test', null, opts)
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
supported = false
|
supported = false
|
||||||
}
|
}
|
||||||
|
|
||||||
return supported
|
return supported
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = isBrowser && detect()
|
module.exports = isBrowser && detect()
|
||||||
|
|
||||||
},{"is-browser":68}],66:[function(_dereq_,module,exports){
|
},{"is-browser":68}],66:[function(_dereq_,module,exports){
|
||||||
exports.read = function (buffer, offset, isLE, mLen, nBytes) {
|
exports.read = function (buffer, offset, isLE, mLen, nBytes) {
|
||||||
|
@ -13407,78 +13407,78 @@ if (typeof Object.create === 'function') {
|
||||||
},{}],68:[function(_dereq_,module,exports){
|
},{}],68:[function(_dereq_,module,exports){
|
||||||
module.exports = true;
|
module.exports = true;
|
||||||
},{}],69:[function(_dereq_,module,exports){
|
},{}],69:[function(_dereq_,module,exports){
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
module.exports = isMobile
|
module.exports = isMobile
|
||||||
module.exports.isMobile = isMobile
|
module.exports.isMobile = isMobile
|
||||||
module.exports.default = isMobile
|
module.exports.default = isMobile
|
||||||
|
|
||||||
var mobileRE = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series[46]0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i
|
var mobileRE = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series[46]0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i
|
||||||
|
|
||||||
var tabletRE = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series[46]0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino|android|ipad|playbook|silk/i
|
var tabletRE = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series[46]0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino|android|ipad|playbook|silk/i
|
||||||
|
|
||||||
function isMobile (opts) {
|
function isMobile (opts) {
|
||||||
if (!opts) opts = {}
|
if (!opts) opts = {}
|
||||||
var ua = opts.ua
|
var ua = opts.ua
|
||||||
if (!ua && typeof navigator !== 'undefined') ua = navigator.userAgent
|
if (!ua && typeof navigator !== 'undefined') ua = navigator.userAgent
|
||||||
if (ua && ua.headers && typeof ua.headers['user-agent'] === 'string') {
|
if (ua && ua.headers && typeof ua.headers['user-agent'] === 'string') {
|
||||||
ua = ua.headers['user-agent']
|
ua = ua.headers['user-agent']
|
||||||
}
|
}
|
||||||
if (typeof ua !== 'string') return false
|
if (typeof ua !== 'string') return false
|
||||||
|
|
||||||
var result = opts.tablet ? tabletRE.test(ua) : mobileRE.test(ua)
|
var result = opts.tablet ? tabletRE.test(ua) : mobileRE.test(ua)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!result &&
|
!result &&
|
||||||
opts.tablet &&
|
opts.tablet &&
|
||||||
opts.featureDetect &&
|
opts.featureDetect &&
|
||||||
navigator &&
|
navigator &&
|
||||||
navigator.maxTouchPoints > 1 &&
|
navigator.maxTouchPoints > 1 &&
|
||||||
ua.indexOf('Macintosh') !== -1 &&
|
ua.indexOf('Macintosh') !== -1 &&
|
||||||
ua.indexOf('Safari') !== -1
|
ua.indexOf('Safari') !== -1
|
||||||
) {
|
) {
|
||||||
result = true
|
result = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
},{}],70:[function(_dereq_,module,exports){
|
},{}],70:[function(_dereq_,module,exports){
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this string all whitespace?
|
* Is this string all whitespace?
|
||||||
* This solution kind of makes my brain hurt, but it's significantly faster
|
* This solution kind of makes my brain hurt, but it's significantly faster
|
||||||
* than !str.trim() or any other solution I could find.
|
* than !str.trim() or any other solution I could find.
|
||||||
*
|
*
|
||||||
* whitespace codes from: http://en.wikipedia.org/wiki/Whitespace_character
|
* whitespace codes from: http://en.wikipedia.org/wiki/Whitespace_character
|
||||||
* and verified with:
|
* and verified with:
|
||||||
*
|
*
|
||||||
* for(var i = 0; i < 65536; i++) {
|
* for(var i = 0; i < 65536; i++) {
|
||||||
* var s = String.fromCharCode(i);
|
* var s = String.fromCharCode(i);
|
||||||
* if(+s===0 && !s.trim()) console.log(i, s);
|
* if(+s===0 && !s.trim()) console.log(i, s);
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* which counts a couple of these as *not* whitespace, but finds nothing else
|
* which counts a couple of these as *not* whitespace, but finds nothing else
|
||||||
* that *is* whitespace. Note that charCodeAt stops at 16 bits, but it appears
|
* that *is* whitespace. Note that charCodeAt stops at 16 bits, but it appears
|
||||||
* that there are no whitespace characters above this, and code points above
|
* that there are no whitespace characters above this, and code points above
|
||||||
* this do not map onto white space characters.
|
* this do not map onto white space characters.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = function(str){
|
module.exports = function(str){
|
||||||
var l = str.length,
|
var l = str.length,
|
||||||
a;
|
a;
|
||||||
for(var i = 0; i < l; i++) {
|
for(var i = 0; i < l; i++) {
|
||||||
a = str.charCodeAt(i);
|
a = str.charCodeAt(i);
|
||||||
if((a < 9 || a > 13) && (a !== 32) && (a !== 133) && (a !== 160) &&
|
if((a < 9 || a > 13) && (a !== 32) && (a !== 133) && (a !== 160) &&
|
||||||
(a !== 5760) && (a !== 6158) && (a < 8192 || a > 8205) &&
|
(a !== 5760) && (a !== 6158) && (a < 8192 || a > 8205) &&
|
||||||
(a !== 8232) && (a !== 8233) && (a !== 8239) && (a !== 8287) &&
|
(a !== 8232) && (a !== 8233) && (a !== 8239) && (a !== 8287) &&
|
||||||
(a !== 8288) && (a !== 12288) && (a !== 65279)) {
|
(a !== 8288) && (a !== 12288) && (a !== 65279)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
},{}],71:[function(_dereq_,module,exports){
|
},{}],71:[function(_dereq_,module,exports){
|
||||||
var rootPosition = { left: 0, top: 0 }
|
var rootPosition = { left: 0, top: 0 }
|
||||||
|
|
|
@ -0,0 +1,337 @@
|
||||||
|
(function() {
|
||||||
|
/**
|
||||||
|
* Parse a string as hexadecimal number
|
||||||
|
*/
|
||||||
|
function hexParse(x) {
|
||||||
|
return parseInt(x, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to compute a high-contrast color from a background color.
|
||||||
|
*
|
||||||
|
* (This probably should be researched better because this was
|
||||||
|
* hand-crafted ad-hoc.)
|
||||||
|
*/
|
||||||
|
function computeComplementaryColor(colorStr) {
|
||||||
|
let avgColor = 0.0;
|
||||||
|
avgColor += hexParse(colorStr.substring(1, 3)) * -0.5;
|
||||||
|
avgColor += hexParse(colorStr.substring(3, 5)) * 1.5;
|
||||||
|
avgColor += hexParse(colorStr.substring(5, 7)) * 1.0;
|
||||||
|
|
||||||
|
if (avgColor > 200) {
|
||||||
|
return "#101010";
|
||||||
|
} else {
|
||||||
|
return "#E0E0E0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CSRF token should always be present because it is auto-included with
|
||||||
|
// every tag-editor widget
|
||||||
|
const CSRF_TOKEN = document.querySelector('input[name="csrfmiddlewaretoken"]').value;
|
||||||
|
|
||||||
|
function doReq(method, uri, data, success, fail) {
|
||||||
|
// TODO: prefer jQuery based requests for now
|
||||||
|
|
||||||
|
const req = new XMLHttpRequest();
|
||||||
|
req.addEventListener('load', () => {
|
||||||
|
if ((req.status >= 200) && (req.status < 300)) {
|
||||||
|
success(req.responseText, req);
|
||||||
|
} else {
|
||||||
|
fail(req.responseText, req);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for (const name of ["error", "timeout", "abort"]) {
|
||||||
|
req.addEventListener(name, () => {
|
||||||
|
fail(req.responseText, req);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
req.timeout = 20000;
|
||||||
|
|
||||||
|
req.open(method, uri);
|
||||||
|
req.setRequestHeader("Content-Type", "application/json");
|
||||||
|
req.setRequestHeader("Accept", "application/json");
|
||||||
|
req.setRequestHeader("X-CSRFTOKEN", CSRF_TOKEN);
|
||||||
|
req.send(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class allowing generic operations on the tag lists, like:
|
||||||
|
*
|
||||||
|
* - Adding tags to a tag list
|
||||||
|
* - Updating or creating new tags with a set name and color
|
||||||
|
* - Controlling the error modal
|
||||||
|
*/
|
||||||
|
class TaggingBase {
|
||||||
|
constructor(widget) {
|
||||||
|
this.prototype = widget.querySelector('.prototype-tag');
|
||||||
|
this.listeners = [];
|
||||||
|
|
||||||
|
this.modalElement = widget.querySelector('.tag-editor-error-modal');
|
||||||
|
this.modalBodyNode = this.modalElement.querySelector('.modal-body');
|
||||||
|
|
||||||
|
// Clean whitespace text nodes between spans
|
||||||
|
for (const n of this.modalBodyNode.childNodes) {
|
||||||
|
if (n.nodeType === Node.TEXT_NODE) {
|
||||||
|
this.modalBodyNode.removeChild(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showModal(msg) {
|
||||||
|
const selectedMessage = this.modalBodyNode.querySelector(`span[data-message='${msg}']`);
|
||||||
|
if (!selectedMessage) {
|
||||||
|
selectedMessage = this.modalBodyNode.childNodes[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const n of this.modalBodyNode.childNodes) {
|
||||||
|
n.classList.add('d-none');
|
||||||
|
}
|
||||||
|
selectedMessage.classList.remove('d-none');
|
||||||
|
|
||||||
|
jQuery(this.modalElement).modal('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
addTagListUpdatedListener(c) {
|
||||||
|
this.listeners.push(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
callTagListUpdatedListeners() {
|
||||||
|
for (const l of this.listeners) {
|
||||||
|
l();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTag(tag, name, color, actionSymbol) {
|
||||||
|
const actionTextNode = tag.querySelector('.add-remove-icon').childNodes[0];
|
||||||
|
|
||||||
|
name = name || tag.getAttribute("data-value");
|
||||||
|
color = color || tag.getAttribute("data-color");
|
||||||
|
actionSymbol = actionSymbol || actionTextNode.textContent;
|
||||||
|
|
||||||
|
tag.childNodes[0].textContent = name;
|
||||||
|
tag.setAttribute("data-value", name);
|
||||||
|
tag.setAttribute("data-color", color);
|
||||||
|
|
||||||
|
const textColor = computeComplementaryColor(color);
|
||||||
|
tag.setAttribute('style', `background-color: ${color}; color: ${textColor};`);
|
||||||
|
actionTextNode.textContent = actionSymbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
createNewTag(name, color, actionSymbol) {
|
||||||
|
const tag = this.prototype.cloneNode(true);
|
||||||
|
tag.classList.remove("prototype-tag");
|
||||||
|
tag.classList.add("tag");
|
||||||
|
this.updateTag(tag, name, color, actionSymbol);
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
insertTag(list, tag) {
|
||||||
|
list.appendChild(tag);
|
||||||
|
this.callTagListUpdatedListeners();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for the edit field allowing to dynamically create new tags.
|
||||||
|
*
|
||||||
|
* Handles user inputs for the editor. Calls the 'onInsertNewTag' callback
|
||||||
|
* when the craetion of a new tag has been requested. All backend handling
|
||||||
|
* like guareteening that the requested tag exists is handled by this class,
|
||||||
|
* the only task left is to add the new tag to the tags-list when
|
||||||
|
* 'onInsertNewTag' is called.
|
||||||
|
*/
|
||||||
|
class AddNewTagControl {
|
||||||
|
/**
|
||||||
|
* @param widget
|
||||||
|
* The root DOM element of the widget
|
||||||
|
* @param taggingBase
|
||||||
|
* Reference to a common TaggingBase class to be used by this widget
|
||||||
|
* @param onInsertNewTag
|
||||||
|
* Callback that is called when a new tag should be added to the
|
||||||
|
* tags widget.
|
||||||
|
*/
|
||||||
|
constructor(widget, taggingBase, onInsertNewTag) {
|
||||||
|
this.widget = widget;
|
||||||
|
this.taggingBase = taggingBase;
|
||||||
|
|
||||||
|
this.apiTagsUrl = widget.getAttribute('data-tags-url');
|
||||||
|
this.createTagInputs = widget.querySelector('.create-tag-inputs');
|
||||||
|
this.addTagInput = this.createTagInputs.querySelector('input[type="text"]');
|
||||||
|
this.addTagButton = this.createTagInputs.querySelector('.btn-add-new-tag');
|
||||||
|
|
||||||
|
this.addTagInput.value = "";
|
||||||
|
|
||||||
|
this.onInsertNewTag = onInsertNewTag;
|
||||||
|
|
||||||
|
this.addTagButton.addEventListener('click', () => this.onCreateTagClicked());
|
||||||
|
this.addTagInput.addEventListener('keydown', (e) => {
|
||||||
|
const key = e.key.toLowerCase();
|
||||||
|
if (key === "enter") {
|
||||||
|
e.preventDefault();
|
||||||
|
this.onCreateTagClicked();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback called when the the "Add" button of the add-tag input is
|
||||||
|
* clicked or enter is pressed in the editor.
|
||||||
|
*/
|
||||||
|
onCreateTagClicked() {
|
||||||
|
// TODO: Make promise based
|
||||||
|
|
||||||
|
const tagName = this.addTagInput.value.trim();
|
||||||
|
const uriTagName = encodeURIComponent(tagName);
|
||||||
|
|
||||||
|
const fail = (msg) => {
|
||||||
|
this.addTagInput.select();
|
||||||
|
this.taggingBase.showModal(msg || "generic");
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!tagName) {
|
||||||
|
fail('invalid-tag-name');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const addTag = (name, color) => {
|
||||||
|
const tag = this.taggingBase.createNewTag(name, color, "-");
|
||||||
|
this.addTagInput.value = "";
|
||||||
|
this.onInsertNewTag(tag);
|
||||||
|
};
|
||||||
|
|
||||||
|
const data = JSON.stringify({
|
||||||
|
'name': this.addTagInput.value
|
||||||
|
});
|
||||||
|
|
||||||
|
doReq("GET", `${this.apiTagsUrl}?name=${uriTagName}`, null,
|
||||||
|
(text) => {
|
||||||
|
const json = JSON.parse(text);
|
||||||
|
if (json.count) {
|
||||||
|
const tagJson = json.results[0];
|
||||||
|
addTag(tagJson.name, tagJson.color);
|
||||||
|
} else {
|
||||||
|
doReq("POST", this.apiTagsUrl, data,
|
||||||
|
(text) => {
|
||||||
|
const tagJson = JSON.parse(text);
|
||||||
|
addTag(tagJson.name, tagJson.color);
|
||||||
|
}, () => fail("tag-creation-failed")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, () => fail("tag-checking-failed")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JavaScript implementation for the tags editor.
|
||||||
|
*
|
||||||
|
* This class uses TaggingBase and AddNewTagControl to provide the custom
|
||||||
|
* tag editor controls. This mainly consists of updating the hidden
|
||||||
|
* input values with the current list of tags and adding/removing
|
||||||
|
* tags from the current-tags- or recently-used-lists.
|
||||||
|
*/
|
||||||
|
class TagsEditor {
|
||||||
|
/**
|
||||||
|
* @param tagEditorRoot
|
||||||
|
* The root DOM element of the widget.
|
||||||
|
*/
|
||||||
|
constructor(tagEditorRoot) {
|
||||||
|
this.widget = tagEditorRoot;
|
||||||
|
this.taggingBase = new TaggingBase(this.widget);
|
||||||
|
this.addTagControl = new AddNewTagControl(
|
||||||
|
this.widget, this.taggingBase, (t) => this.insertNewTag(t)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.currentTags = this.widget.querySelector('.current_tags');
|
||||||
|
this.newTags = this.widget.querySelector('.new-tags');
|
||||||
|
this.inputElement = this.widget.querySelector('input[type="hidden"]');
|
||||||
|
|
||||||
|
for (const tag of this.newTags.querySelectorAll(".tag")) {
|
||||||
|
this.configureAddTag(tag);
|
||||||
|
}
|
||||||
|
for (const tag of this.currentTags.querySelectorAll(".tag")) {
|
||||||
|
this.configureRemoveTag(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateInputList();
|
||||||
|
this.taggingBase.addTagListUpdatedListener(
|
||||||
|
() => this.updateInputList()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a new tag into the "current tag" list.
|
||||||
|
*
|
||||||
|
* Makes sure that no duplicates are present in the widget before adding
|
||||||
|
* the new tag. If a duplicate is found, the old tag is removed before
|
||||||
|
* the new one is added.
|
||||||
|
*/
|
||||||
|
insertNewTag(tag) {
|
||||||
|
const name = tag.getAttribute("data-value");
|
||||||
|
|
||||||
|
const oldTag = this.widget.querySelector(`span[data-value="${name}"]`);
|
||||||
|
if (oldTag) {
|
||||||
|
oldTag.parentNode.removeChild(oldTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.taggingBase.insertTag(this.currentTags, tag);
|
||||||
|
this.configureRemoveTag(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registeres a click-callback for a given node.
|
||||||
|
*
|
||||||
|
* The callback chain-calls another callback "onClicked" after
|
||||||
|
* moving the clicked tag from the old tag-list to a new tag list.
|
||||||
|
*/
|
||||||
|
registerNewCallback(tag, newParent, onClicked) {
|
||||||
|
function callback(event) {
|
||||||
|
tag.parentNode.removeChild(tag);
|
||||||
|
this.taggingBase.insertTag(newParent, tag);
|
||||||
|
|
||||||
|
tag.removeEventListener('click', callback);
|
||||||
|
onClicked(tag);
|
||||||
|
}
|
||||||
|
tag.addEventListener('click', callback.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the value of the hidden input element.
|
||||||
|
*
|
||||||
|
* Sets the value from the list of tags added to the currentTags
|
||||||
|
* DOM element.
|
||||||
|
*/
|
||||||
|
updateInputList() {
|
||||||
|
const names = [];
|
||||||
|
for (const tag of this.currentTags.querySelectorAll(".tag")) {
|
||||||
|
const name = tag.getAttribute("data-value");
|
||||||
|
names.push(`"${name}"`);
|
||||||
|
}
|
||||||
|
this.inputElement.value = names.join(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure a tag-DOM element as a "add tag" button.
|
||||||
|
*/
|
||||||
|
configureAddTag(tag) {
|
||||||
|
this.taggingBase.updateTag(tag, null, null, "+");
|
||||||
|
this.registerNewCallback(tag, this.currentTags, () => this.configureRemoveTag(tag));
|
||||||
|
this.updateInputList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure a tag-DOM element as a "remove tag" button.
|
||||||
|
*/
|
||||||
|
configureRemoveTag(tag) {
|
||||||
|
this.taggingBase.updateTag(tag, null, null, "-");
|
||||||
|
this.registerNewCallback(tag, this.newTags, () => this.configureAddTag(tag));
|
||||||
|
this.updateInputList();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('load', () => {
|
||||||
|
for (const el of document.querySelectorAll('.babybuddy-tags-editor')) {
|
||||||
|
new TagsEditor(el);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
Binary file not shown.
Binary file not shown.
|
@ -26822,35 +26822,35 @@ return Popper;
|
||||||
return moment;
|
return moment;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
/*@preserve
|
/*@preserve
|
||||||
* Tempus Dominus Bootstrap4 v5.1.2 (https://tempusdominus.github.io/bootstrap-4/)
|
* Tempus Dominus Bootstrap4 v5.1.2 (https://tempusdominus.github.io/bootstrap-4/)
|
||||||
* Copyright 2016-2018 Jonathan Peterson
|
* Copyright 2016-2018 Jonathan Peterson
|
||||||
* Licensed under MIT (https://github.com/tempusdominus/bootstrap-3/blob/master/LICENSE)
|
* Licensed under MIT (https://github.com/tempusdominus/bootstrap-3/blob/master/LICENSE)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (typeof jQuery === 'undefined') {
|
if (typeof jQuery === 'undefined') {
|
||||||
throw new Error('Tempus Dominus Bootstrap4\'s requires jQuery. jQuery must be included before Tempus Dominus Bootstrap4\'s JavaScript.');
|
throw new Error('Tempus Dominus Bootstrap4\'s requires jQuery. jQuery must be included before Tempus Dominus Bootstrap4\'s JavaScript.');
|
||||||
}
|
}
|
||||||
|
|
||||||
+function ($) {
|
+function ($) {
|
||||||
var version = $.fn.jquery.split(' ')[0].split('.');
|
var version = $.fn.jquery.split(' ')[0].split('.');
|
||||||
if ((version[0] < 2 && version[1] < 9) || (version[0] === 1 && version[1] === 9 && version[2] < 1) || (version[0] >= 4)) {
|
if ((version[0] < 2 && version[1] < 9) || (version[0] === 1 && version[1] === 9 && version[2] < 1) || (version[0] >= 4)) {
|
||||||
throw new Error('Tempus Dominus Bootstrap4\'s requires at least jQuery v3.0.0 but less than v4.0.0');
|
throw new Error('Tempus Dominus Bootstrap4\'s requires at least jQuery v3.0.0 but less than v4.0.0');
|
||||||
}
|
}
|
||||||
}(jQuery);
|
}(jQuery);
|
||||||
|
|
||||||
|
|
||||||
if (typeof moment === 'undefined') {
|
if (typeof moment === 'undefined') {
|
||||||
throw new Error('Tempus Dominus Bootstrap4\'s requires moment.js. Moment.js must be included before Tempus Dominus Bootstrap4\'s JavaScript.');
|
throw new Error('Tempus Dominus Bootstrap4\'s requires moment.js. Moment.js must be included before Tempus Dominus Bootstrap4\'s JavaScript.');
|
||||||
}
|
}
|
||||||
|
|
||||||
var version = moment.version.split('.')
|
var version = moment.version.split('.')
|
||||||
if ((version[0] <= 2 && version[1] < 17) || (version[0] >= 3)) {
|
if ((version[0] <= 2 && version[1] < 17) || (version[0] >= 3)) {
|
||||||
throw new Error('Tempus Dominus Bootstrap4\'s requires at least moment.js v2.17.0 but less than v3.0.0');
|
throw new Error('Tempus Dominus Bootstrap4\'s requires at least moment.js v2.17.0 but less than v3.0.0');
|
||||||
}
|
}
|
||||||
|
|
||||||
+function () {
|
+function () {
|
||||||
|
|
||||||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
|
||||||
|
|
||||||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||||
|
@ -27179,8 +27179,8 @@ var DateTimePicker = function ($, moment) {
|
||||||
this._int();
|
this._int();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -28330,8 +28330,8 @@ var DateTimePicker = function ($, moment) {
|
||||||
return NAME;
|
return NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
}, {
|
}, {
|
||||||
|
@ -28340,8 +28340,8 @@ var DateTimePicker = function ($, moment) {
|
||||||
return DATA_KEY;
|
return DATA_KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
}, {
|
}, {
|
||||||
|
@ -28350,8 +28350,8 @@ var DateTimePicker = function ($, moment) {
|
||||||
return EVENT_KEY;
|
return EVENT_KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
}, {
|
}, {
|
||||||
|
@ -29537,10 +29537,10 @@ var TempusDominusBootstrap4 = function ($) {
|
||||||
return TempusDominusBootstrap4;
|
return TempusDominusBootstrap4;
|
||||||
}(DateTimePicker);
|
}(DateTimePicker);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
* jQuery
|
* jQuery
|
||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -29598,6 +29598,6 @@ var TempusDominusBootstrap4 = function ($) {
|
||||||
};
|
};
|
||||||
|
|
||||||
return TempusDominusBootstrap4;
|
return TempusDominusBootstrap4;
|
||||||
}(jQuery);
|
}(jQuery);
|
||||||
|
|
||||||
}();
|
}();
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue