mirror of
https://github.com/wekan/wekan.git
synced 2025-12-16 15:30:13 +01:00
Fix Browser always reload the whole page when I change one of the card color.
Fixed by making label colors and text again editable.
Regression from [Wekan v3.86 2)](b9099a8b7e).
Thanks to javen9881 and xet7 !
Closes #2971
This commit is contained in:
parent
29d62440a5
commit
3546d7aa02
4 changed files with 5 additions and 251 deletions
|
|
@ -33,13 +33,6 @@ BlazeComponent.extendComponent({
|
||||||
cardId,
|
cardId,
|
||||||
});
|
});
|
||||||
resetCommentInput(input);
|
resetCommentInput(input);
|
||||||
// With Richer editor is in use, and comment is submitted,
|
|
||||||
// clear comment form with JQuery. Id #summernote is defined
|
|
||||||
// at client/components/main/editor.jade where it previously was
|
|
||||||
// id=id, now it is id="summernote".
|
|
||||||
if (Meteor.settings.public.RICHER_CARD_COMMENT_EDITOR === 'true') {
|
|
||||||
$('#summernote').summernote('code', '');
|
|
||||||
}
|
|
||||||
Tracker.flush();
|
Tracker.flush();
|
||||||
autosize.update(input);
|
autosize.update(input);
|
||||||
input.trigger('submitted');
|
input.trigger('submitted');
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,8 @@
|
||||||
template(name="editor")
|
template(name="editor")
|
||||||
// With Richer editor is in use, and comment is submitted,
|
|
||||||
// clear comment form with JQuery Comment at
|
|
||||||
// client/components/activities/comments.js . Id #summernote is defined
|
|
||||||
// here at client/components/main/editor.jade where it previously was
|
|
||||||
// id=id, now it is id="summernote".
|
|
||||||
textarea.editor(
|
textarea.editor(
|
||||||
dir="auto"
|
dir="auto"
|
||||||
class="{{class}}"
|
class="{{class}}"
|
||||||
id="summernote"
|
id=id
|
||||||
autofocus=autofocus
|
autofocus=autofocus
|
||||||
placeholder="{{_ 'comment-placeholder'}}")
|
placeholder="{{_ 'comment-placeholder'}}")
|
||||||
+Template.contentBlock
|
+Template.contentBlock
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ Template.editor.onRendered(() => {
|
||||||
autosize($textarea);
|
autosize($textarea);
|
||||||
$textarea.escapeableTextComplete(mentions);
|
$textarea.escapeableTextComplete(mentions);
|
||||||
};
|
};
|
||||||
if (Meteor.settings.public.RICHER_CARD_COMMENT_EDITOR === 'true') {
|
if (Meteor.settings.public.RICHER_CARD_COMMENT_EDITOR !== false) {
|
||||||
const isSmall = Utils.isMiniScreen();
|
const isSmall = Utils.isMiniScreen();
|
||||||
const toolbar = isSmall
|
const toolbar = isSmall
|
||||||
? [
|
? [
|
||||||
|
|
@ -108,37 +108,10 @@ Template.editor.onRendered(() => {
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
// Prevent @member mentions on Add Comment input field
|
|
||||||
// from closing card, part 1.
|
|
||||||
let popupShown = false;
|
|
||||||
inputs.each(function(idx, input) {
|
inputs.each(function(idx, input) {
|
||||||
mSummernotes[idx] = $(input).summernote({
|
mSummernotes[idx] = $(input).summernote({
|
||||||
placeholder,
|
placeholder,
|
||||||
// Prevent @member mentions on Add Comment input field
|
|
||||||
// from closing card, part 2.
|
|
||||||
onKeydown(e) {
|
|
||||||
if (popupShown) {
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onKeyup(e) {
|
|
||||||
if (popupShown) {
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
callbacks: {
|
callbacks: {
|
||||||
// Prevent @member mentions on Add Comment input field
|
|
||||||
// from closing card, part 3.
|
|
||||||
onKeydown(e) {
|
|
||||||
if (popupShown) {
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onKeyup(e) {
|
|
||||||
if (popupShown) {
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onInit(object) {
|
onInit(object) {
|
||||||
const originalInput = this;
|
const originalInput = this;
|
||||||
$(originalInput).on('input', function() {
|
$(originalInput).on('input', function() {
|
||||||
|
|
@ -163,6 +136,7 @@ Template.editor.onRendered(() => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onImageUpload(files) {
|
onImageUpload(files) {
|
||||||
const $summernote = getSummernote(this);
|
const $summernote = getSummernote(this);
|
||||||
if (files && files.length > 0) {
|
if (files && files.length > 0) {
|
||||||
|
|
@ -323,8 +297,7 @@ Blaze.Template.registerHelper(
|
||||||
}
|
}
|
||||||
|
|
||||||
const linkValue = [' ', at, knowedUser.username];
|
const linkValue = [' ', at, knowedUser.username];
|
||||||
//let linkClass = 'atMention js-open-member';
|
let linkClass = 'atMention js-open-member';
|
||||||
let linkClass = 'atMention';
|
|
||||||
if (knowedUser.userId === Meteor.userId()) {
|
if (knowedUser.userId === Meteor.userId()) {
|
||||||
linkClass += ' me';
|
linkClass += ' me';
|
||||||
}
|
}
|
||||||
|
|
@ -367,10 +340,7 @@ Template.viewer.events({
|
||||||
|
|
||||||
const userId = event.currentTarget.dataset.userid;
|
const userId = event.currentTarget.dataset.userid;
|
||||||
if (userId) {
|
if (userId) {
|
||||||
// Prevent @member mentions on Add Comment input field
|
Popup.open('member').call({ userId }, event, templateInstance);
|
||||||
// from closing card, part 4.
|
|
||||||
PopupNoClose.open('member').call({ userId }, event, templateInstance);
|
|
||||||
event.preventDefault();
|
|
||||||
} else {
|
} else {
|
||||||
const href = event.currentTarget.href;
|
const href = event.currentTarget.href;
|
||||||
if (href) {
|
if (href) {
|
||||||
|
|
|
||||||
|
|
@ -206,207 +206,3 @@ escapeActions.forEach(actionName => {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Prevent @member mentions on Add Comment input field
|
|
||||||
// from closing card, part 5.
|
|
||||||
// This duplicate below of above popup function is needed, because at
|
|
||||||
// wekan/components/main/editor.js at bottom is popping up visible
|
|
||||||
// @member mention, and it seems to trigger closing also card popup,
|
|
||||||
// so in below closing popup is disabled.
|
|
||||||
window.PopupNoClose = new (class {
|
|
||||||
constructor() {
|
|
||||||
// The template we use to render popups
|
|
||||||
this.template = Template.popup;
|
|
||||||
|
|
||||||
// We only want to display one popup at a time and we keep the view object
|
|
||||||
// in this `Popup.current` variable. If there is no popup currently opened
|
|
||||||
// the value is `null`.
|
|
||||||
this.current = null;
|
|
||||||
|
|
||||||
// It's possible to open a sub-popup B from a popup A. In that case we keep
|
|
||||||
// the data of popup A so we can return back to it. Every time we open a new
|
|
||||||
// popup the stack grows, every time we go back the stack decrease, and if
|
|
||||||
// we close the popup the stack is reseted to the empty stack [].
|
|
||||||
this._stack = [];
|
|
||||||
|
|
||||||
// We invalidate this internal dependency every time the top of the stack
|
|
||||||
// has changed and we want to re-render a popup with the new top-stack data.
|
|
||||||
this._dep = new Tracker.Dependency();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This function returns a callback that can be used in an event map:
|
|
||||||
/// Template.tplName.events({
|
|
||||||
/// 'click .elementClass': Popup.open("popupName"),
|
|
||||||
/// });
|
|
||||||
/// The popup inherit the data context of its parent.
|
|
||||||
open(name) {
|
|
||||||
const self = this;
|
|
||||||
const popupName = `${name}Popup`;
|
|
||||||
function clickFromPopup(evt) {
|
|
||||||
return $(evt.target).closest('.js-pop-over').length !== 0;
|
|
||||||
}
|
|
||||||
return function(evt) {
|
|
||||||
// If a popup is already opened, clicking again on the opener element
|
|
||||||
// should close it -- and interrupt the current `open` function.
|
|
||||||
/*
|
|
||||||
if (self.isOpen()) {
|
|
||||||
const previousOpenerElement = self._getTopStack().openerElement;
|
|
||||||
if (previousOpenerElement === evt.currentTarget) {
|
|
||||||
self.close();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
$(previousOpenerElement).removeClass('is-active');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// We determine the `openerElement` (the DOM element that is being clicked
|
|
||||||
// and the one we take in reference to position the popup) from the event
|
|
||||||
// if the popup has no parent, or from the parent `openerElement` if it
|
|
||||||
// has one. This allows us to position a sub-popup exactly at the same
|
|
||||||
// position than its parent.
|
|
||||||
let openerElement;
|
|
||||||
if (clickFromPopup(evt)) {
|
|
||||||
openerElement = self._getTopStack().openerElement;
|
|
||||||
} else {
|
|
||||||
self._stack = [];
|
|
||||||
openerElement = evt.currentTarget;
|
|
||||||
}
|
|
||||||
$(openerElement).addClass('is-active');
|
|
||||||
evt.preventDefault();
|
|
||||||
|
|
||||||
// We push our popup data to the stack. The top of the stack is always
|
|
||||||
// used as the data source for our current popup.
|
|
||||||
self._stack.push({
|
|
||||||
popupName,
|
|
||||||
openerElement,
|
|
||||||
hasPopupParent: clickFromPopup(evt),
|
|
||||||
title: self._getTitle(popupName),
|
|
||||||
depth: self._stack.length,
|
|
||||||
offset: self._getOffset(openerElement),
|
|
||||||
dataContext: (this && this.currentData && this.currentData()) || this,
|
|
||||||
});
|
|
||||||
|
|
||||||
// If there are no popup currently opened we use the Blaze API to render
|
|
||||||
// one into the DOM. We use a reactive function as the data parameter that
|
|
||||||
// return the complete along with its top element and depends on our
|
|
||||||
// internal dependency that is being invalidated every time the top
|
|
||||||
// element of the stack has changed and we want to update the popup.
|
|
||||||
//
|
|
||||||
// Otherwise if there is already a popup open we just need to invalidate
|
|
||||||
// our internal dependency, and since we just changed the top element of
|
|
||||||
// our internal stack, the popup will be updated with the new data.
|
|
||||||
if (!self.isOpen()) {
|
|
||||||
self.current = Blaze.renderWithData(
|
|
||||||
self.template,
|
|
||||||
() => {
|
|
||||||
self._dep.depend();
|
|
||||||
return { ...self._getTopStack(), stack: self._stack };
|
|
||||||
},
|
|
||||||
document.body,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
self._dep.changed();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This function returns a callback that can be used in an event map:
|
|
||||||
/// Template.tplName.events({
|
|
||||||
/// 'click .elementClass': Popup.afterConfirm("popupName", function() {
|
|
||||||
/// // What to do after the user has confirmed the action
|
|
||||||
/// }),
|
|
||||||
/// });
|
|
||||||
afterConfirm(name, action) {
|
|
||||||
const self = this;
|
|
||||||
|
|
||||||
return function(evt, tpl) {
|
|
||||||
const context = (this.currentData && this.currentData()) || this;
|
|
||||||
context.__afterConfirmAction = action;
|
|
||||||
self.open(name).call(context, evt, tpl);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The public reactive state of the popup.
|
|
||||||
isOpen() {
|
|
||||||
this._dep.changed();
|
|
||||||
return Boolean(this.current);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// In case the popup was opened from a parent popup we can get back to it
|
|
||||||
/// with this `Popup.back()` function. You can go back several steps at once
|
|
||||||
/// by providing a number to this function, e.g. `Popup.back(2)`. In this case
|
|
||||||
/// intermediate popup won't even be rendered on the DOM. If the number of
|
|
||||||
/// steps back is greater than the popup stack size, the popup will be closed.
|
|
||||||
back(n = 1) {
|
|
||||||
if (this._stack.length > n) {
|
|
||||||
_.times(n, () => this._stack.pop());
|
|
||||||
this._dep.changed();
|
|
||||||
}
|
|
||||||
// else {
|
|
||||||
// this.close();
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Close the current opened popup.
|
|
||||||
/*
|
|
||||||
close() {
|
|
||||||
if (this.isOpen()) {
|
|
||||||
Blaze.remove(this.current);
|
|
||||||
this.current = null;
|
|
||||||
|
|
||||||
const openerElement = this._getTopStack().openerElement;
|
|
||||||
$(openerElement).removeClass('is-active');
|
|
||||||
|
|
||||||
this._stack = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
getOpenerComponent() {
|
|
||||||
const { openerElement } = Template.parentData(4);
|
|
||||||
return BlazeComponent.getComponentForElement(openerElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
// An utility fonction that returns the top element of the internal stack
|
|
||||||
_getTopStack() {
|
|
||||||
return this._stack[this._stack.length - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
// We automatically calculate the popup offset from the reference element
|
|
||||||
// position and dimensions. We also reactively use the window dimensions to
|
|
||||||
// ensure that the popup is always visible on the screen.
|
|
||||||
_getOffset(element) {
|
|
||||||
const $element = $(element);
|
|
||||||
return () => {
|
|
||||||
Utils.windowResizeDep.depend();
|
|
||||||
|
|
||||||
if (Utils.isMiniScreen()) return { left: 0, top: 0 };
|
|
||||||
|
|
||||||
const offset = $element.offset();
|
|
||||||
const popupWidth = 300 + 15;
|
|
||||||
return {
|
|
||||||
left: Math.min(offset.left, $(window).width() - popupWidth),
|
|
||||||
top: offset.top + $element.outerHeight(),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// We get the title from the translation files. Instead of returning the
|
|
||||||
// result, we return a function that compute the result and since `TAPi18n.__`
|
|
||||||
// is a reactive data source, the title will be changed reactively.
|
|
||||||
_getTitle(popupName) {
|
|
||||||
return () => {
|
|
||||||
const translationKey = `${popupName}-title`;
|
|
||||||
|
|
||||||
// XXX There is no public API to check if there is an available
|
|
||||||
// translation for a given key. So we try to translate the key and if the
|
|
||||||
// translation output equals the key input we deduce that no translation
|
|
||||||
// was available and returns `false`. There is a (small) risk a false
|
|
||||||
// positives.
|
|
||||||
const title = TAPi18n.__(translationKey);
|
|
||||||
// when popup showed as full of small screen, we need a default header to clearly see [X] button
|
|
||||||
const defaultTitle = Utils.isMiniScreen() ? '' : false;
|
|
||||||
return title !== translationKey ? title : defaultTitle;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue