Initial commit: Angular frontend and Expressjs backend
This commit is contained in:
2
worklenz-frontend/src/res/js/jquery-3.6.1.min.js
vendored
Normal file
2
worklenz-frontend/src/res/js/jquery-3.6.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
812
worklenz-frontend/src/res/js/jquery.mentiony.js
Normal file
812
worklenz-frontend/src/res/js/jquery.mentiony.js
Normal file
@@ -0,0 +1,812 @@
|
||||
/*
|
||||
* Contentediable Mentiony jQuery plugin
|
||||
* Version 0.1.0
|
||||
* Written by: Luat Nguyen(luatnd) on 2016/05/27
|
||||
*
|
||||
* Transform textarea or input into contentediable with mention feature.
|
||||
*
|
||||
* License: MIT License - http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
var tmpEle = null;
|
||||
|
||||
(function ($) {
|
||||
var KEY = {
|
||||
AT: 64,
|
||||
BACKSPACE: 8,
|
||||
DELETE: 46,
|
||||
TAB: 9,
|
||||
ESC: 27,
|
||||
RETURN: 13,
|
||||
LEFT: 37,
|
||||
UP: 38,
|
||||
RIGHT: 39,
|
||||
DOWN: 40,
|
||||
SPACE: 32,
|
||||
HOME: 36,
|
||||
END: 35,
|
||||
COMMA: 188,
|
||||
NUMPAD_ADD: 107,
|
||||
NUMPAD_DECIMAL: 110,
|
||||
NUMPAD_DIVIDE: 111,
|
||||
NUMPAD_ENTER: 108,
|
||||
NUMPAD_MULTIPLY: 106,
|
||||
NUMPAD_SUBTRACT: 109,
|
||||
PAGE_DOWN: 34,
|
||||
PAGE_UP: 33,
|
||||
PERIOD: 190,
|
||||
};
|
||||
|
||||
jQuery.fn.mentiony = function (method, options) {
|
||||
var defaults = {
|
||||
debug: 0, // Set 1 to see console log message of this plugin
|
||||
|
||||
/**
|
||||
* True [default] will make mention area size equal to initial size of textarea. NOTE: Textarea must visible on document ready if this value is true.
|
||||
* False will not specify the CSS width attribute to every mention area.
|
||||
*/
|
||||
applyInitialSize: true,
|
||||
|
||||
globalTimeout: null, // Don't overwrite this config
|
||||
timeOut: 400, // Do mention only when user input idle time > this value
|
||||
triggerChar: '@', // @keyword-to-mention
|
||||
|
||||
/**
|
||||
* Function for mention data processing
|
||||
* @param mode
|
||||
* @param keyword
|
||||
* @param onDataRequestCompleteCallback
|
||||
*/
|
||||
onDataRequest: function (mode, keyword, onDataRequestCompleteCallback) {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Addition keyboard event handle for old and new input
|
||||
* Why we need this:
|
||||
* • Because some original js was binded to textarea, we need to bind it to contenteditable too.
|
||||
* • Useful when you wanna passing some event trigger of old element to new editable content
|
||||
* • Old input element already be trigger some event, then you need to pass some needed event to new editable element
|
||||
* @param event
|
||||
* @param oldInputEle
|
||||
* @param newEditableEle
|
||||
*/
|
||||
onKeyPress: function (event, oldInputEle, newEditableEle) {
|
||||
oldInputEle.trigger(event);
|
||||
},
|
||||
onKeyUp: function (event, oldInputEle, newEditableEle) {
|
||||
oldInputEle.trigger(event);
|
||||
},
|
||||
onBlur: function (event, oldInputEle, newEditableEle) {
|
||||
oldInputEle.trigger(event);
|
||||
},
|
||||
onPaste: function (event, oldInputEle, newEditableEle) {
|
||||
oldInputEle.trigger(event);
|
||||
},
|
||||
onInput: function (oldInputEle, newEditableEle) {
|
||||
|
||||
},
|
||||
|
||||
// adjust popover relative position with its parent.
|
||||
popoverOffset: {
|
||||
x: -30,
|
||||
y: 0
|
||||
},
|
||||
|
||||
templates: {
|
||||
container: '<div id="mentiony-container-[ID]" class="mentiony-container"></div>',
|
||||
content: '<div id="mentiony-content-[ID]" class="mentiony-content" contenteditable="true"></div>',
|
||||
popover: '<div id="mentiony-popover-[ID]" class="mentiony-popover"></div>',
|
||||
list: '<ul id="mentiony-popover-[ID]" class="mentiony-list"></ul>',
|
||||
listItem: '<li class="mentiony-item" data-item-id="">' +
|
||||
'<div class="row">' +
|
||||
'<div class="col-xs-3 col-sm-3 col-md-3 col-lg-3">' +
|
||||
'<img src="https://avatars2.githubusercontent.com/u/1859127?v=3&s=140">' +
|
||||
'</div>' +
|
||||
'<div class="pl0 col-xs-9 col-sm-9 col-md-9 col-lg-9">' +
|
||||
'<p class="title">Company name</p>' +
|
||||
'<p class="help-block">Addition information</p>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</li>',
|
||||
normalText: '<span class="normal-text"> </span>',
|
||||
highlight: '<span class="highlight"></span>',
|
||||
highlightContent: '<a href="[HREF]" data-item-id="[ITEM_ID]" class="mentiony-link">[TEXT]</a>',
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof method === 'object' || !method) {
|
||||
options = method;
|
||||
}
|
||||
|
||||
var settings = $.extend({}, defaults, options);
|
||||
|
||||
return this.each(function () {
|
||||
var instance = $.data(this, 'mentiony') || $.data(this, 'mentiony', new MentionsInput(settings));
|
||||
|
||||
if (typeof instance[method] === 'function') {
|
||||
return instance[method].apply(this, Array.prototype.slice.call(outerArguments, 1));
|
||||
} else if (typeof method === 'object' || !method) {
|
||||
return instance.init.call(this, this);
|
||||
} else {
|
||||
$.error('Method ' + method + ' does not exist');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var MentionsInput = function (settings) {
|
||||
var elmInputBoxContainer, elmInputBoxContent, elmInputBox,
|
||||
elmInputBoxInitialWidth, elmInputBoxInitialHeight,
|
||||
editableContentLineHeightPx,
|
||||
popoverEle, list, elmInputBoxId,
|
||||
elmInputBoxContentAbsPosition = {top: 0, left: 0},
|
||||
dropDownShowing = false,
|
||||
events = {
|
||||
keyDown: false,
|
||||
keyPress: false,
|
||||
input: false,
|
||||
keyup: false,
|
||||
},
|
||||
currentMention = {
|
||||
keyword: '',
|
||||
jqueryDomNode: null, // represent jQuery dom data
|
||||
mentionItemDataSet: [], // list item json data was store here
|
||||
lastActiveNode: 0,
|
||||
charAtFound: false, // tracking @ char appear or not
|
||||
}
|
||||
;
|
||||
var needMention = false; // Mention state
|
||||
var inputId = Math.random().toString(36).substr(2, 6); // generate 6 character rand string
|
||||
|
||||
var onDataRequestCompleteCallback = function (responseData) {
|
||||
populateDropdown(currentMention.keyword, responseData);
|
||||
};
|
||||
|
||||
function initTextArea(ele) {
|
||||
elmInputBox = $(ele);
|
||||
|
||||
if (elmInputBox.attr('data-mentions-input') == 'true') {
|
||||
return;
|
||||
} else {
|
||||
elmInputBox.attr('data-mentions-input', 'true');
|
||||
|
||||
if (elmInputBox.attr('id').length == 0) {
|
||||
elmInputBoxId = 'mentiony-input-' + inputId;
|
||||
elmInputBox.attr('id', elmInputBoxId);
|
||||
} else {
|
||||
elmInputBoxId = elmInputBox.attr('id');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Initial UI information
|
||||
elmInputBoxInitialWidth = elmInputBox.prop('scrollWidth');
|
||||
elmInputBoxInitialHeight = elmInputBox.prop('scrollHeight');
|
||||
|
||||
// Container
|
||||
elmInputBoxContainer = $(settings.templates.container.replace('[ID]', inputId));
|
||||
elmInputBoxContent = $(settings.templates.content.replace('[ID]', inputId));
|
||||
|
||||
// Make UI and hide the textarea
|
||||
var placeholderText = elmInputBox.attr('placeholder');
|
||||
if (typeof placeholderText === 'undefined') {
|
||||
placeholderText = elmInputBox.text();
|
||||
}
|
||||
elmInputBoxContent.attr('data-placeholder', placeholderText);
|
||||
|
||||
elmInputBoxContainer.append(elmInputBox.clone().addClass('mention-input-hidden'));
|
||||
elmInputBoxContainer.append(elmInputBoxContent);
|
||||
elmInputBox.replaceWith(elmInputBoxContainer);
|
||||
|
||||
popoverEle = $(settings.templates.popover.replace('[ID]', inputId));
|
||||
list = $(settings.templates.list.replace('[ID]', inputId));
|
||||
elmInputBoxContainer.append(popoverEle);
|
||||
popoverEle.append(list);
|
||||
|
||||
// Reset the input
|
||||
elmInputBox = $('#' + elmInputBoxId);
|
||||
|
||||
// Update initial UI
|
||||
var containerPadding = parseInt(elmInputBoxContainer.css('padding'));
|
||||
|
||||
if (settings.applyInitialSize) {
|
||||
elmInputBoxContainer.addClass('initial-size');
|
||||
elmInputBoxContainer.css({width: (elmInputBoxInitialWidth) + 'px'});
|
||||
elmInputBoxContent.width((elmInputBoxInitialWidth - 2 * containerPadding) + 'px');
|
||||
} else {
|
||||
elmInputBoxContainer.addClass('auto-size');
|
||||
}
|
||||
|
||||
elmInputBoxContent.css({minHeight: elmInputBoxInitialHeight + 'px'});
|
||||
|
||||
elmInputBoxContentAbsPosition = elmInputBoxContent.offset();
|
||||
editableContentLineHeightPx = parseInt($(elmInputBoxContent.css('line-height')).selector);
|
||||
|
||||
// This event occured from top to down.
|
||||
// When press a key: onInputBoxKeyDown --> onInputBoxKeyPress --> onInputBoxInput --> onInputBoxKeyUp
|
||||
elmInputBoxContent.bind('keydown', onInputBoxKeyDown);
|
||||
elmInputBoxContent.bind('keypress', onInputBoxKeyPress);
|
||||
elmInputBoxContent.bind('input', onInputBoxInput);
|
||||
elmInputBoxContent.bind('keyup', onInputBoxKeyUp);
|
||||
elmInputBoxContent.bind('click', onInputBoxClick);
|
||||
elmInputBoxContent.bind('blur', onInputBoxBlur);
|
||||
elmInputBoxContent.bind('paste', onInputBoxPaste);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put all special key handle here
|
||||
* @param e
|
||||
*/
|
||||
function onInputBoxKeyDown(e) {
|
||||
// log('onInputBoxKeyDown');
|
||||
|
||||
// reset events tracking
|
||||
events = {
|
||||
keyDown: true,
|
||||
keyPress: false,
|
||||
input: false,
|
||||
keyup: false,
|
||||
};
|
||||
|
||||
|
||||
if (dropDownShowing) {
|
||||
return handleUserChooseOption(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Character was entered was handled here
|
||||
* This event occur when a printable was pressed. Or combined multi key was handle here, up/down can not read combined key
|
||||
* NOTE: Delete key is not be triggered here
|
||||
* @param e
|
||||
*/
|
||||
function onInputBoxKeyPress(e) {
|
||||
// log('onInputBoxKeyPress');
|
||||
events.keyPress = true;
|
||||
|
||||
if (!needMention) {
|
||||
// Try to check if need mention
|
||||
needMention = (e.keyCode === KEY.AT || e.which === KEY.AT);
|
||||
// log(needMention, 'needMention', 'info');
|
||||
}
|
||||
|
||||
// force focus on element so it triggers on IE
|
||||
content.click();
|
||||
|
||||
settings.onKeyPress.call(this, e, elmInputBox, elmInputBoxContent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* When input value was change, with any key effect the input value
|
||||
* Delete was trigger here
|
||||
*/
|
||||
function onInputBoxInput(e) {
|
||||
// log('onInputBoxInput');
|
||||
events.input = true;
|
||||
|
||||
// convert android character to codes so it could be matched
|
||||
var converted = e.originalEvent.data.charCodeAt(0);
|
||||
|
||||
// trigger mentiony on mobile devices
|
||||
if (!needMention) {
|
||||
needMention = ((e.keyCode === KEY.AT || e.which === KEY.AT) || (converted === KEY.AT));
|
||||
}
|
||||
|
||||
// force focus on element so it triggers on IE
|
||||
content.click();
|
||||
|
||||
settings.onInput.call(this, elmInputBox, elmInputBoxContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put all special key handle here
|
||||
* @param e
|
||||
*/
|
||||
function onInputBoxKeyUp(e) {
|
||||
// log('onInputBoxKeyUp');
|
||||
events.keyup = true;
|
||||
// log(events, 'events');
|
||||
|
||||
if (events.input) {
|
||||
updateDataInputData(e);
|
||||
}
|
||||
|
||||
if (needMention) {
|
||||
// Update mention keyword only inputing(not enter), left, right
|
||||
if ((e.keyCode !== KEY.RETURN || e.which === KEY.RETURN) && (events.input || (e.keyCode === KEY.LEFT || e.which === KEY.LEFT) || (e.keyCode === KEY.RIGHT || e.which === KEY.RIGHT))) {
|
||||
updateMentionKeyword(e);
|
||||
doSearchAndShow();
|
||||
}
|
||||
}
|
||||
|
||||
settings.onKeyUp.call(this, e, elmInputBox, elmInputBoxContent);
|
||||
}
|
||||
|
||||
function onInputBoxClick(e) {
|
||||
// log('onInputBoxClick');
|
||||
|
||||
if (needMention) {
|
||||
updateMentionKeyword(e);
|
||||
doSearchAndShow();
|
||||
}
|
||||
}
|
||||
|
||||
function onInputBoxBlur(e) {
|
||||
// log('onInputBoxBlur');
|
||||
|
||||
settings.onBlur.call(this, e, elmInputBox, elmInputBoxContent);
|
||||
}
|
||||
|
||||
function onInputBoxPaste(e) {
|
||||
// log('onInputBoxPaste');
|
||||
|
||||
settings.onPaste.call(this, e, elmInputBox, elmInputBoxContent);
|
||||
}
|
||||
|
||||
function onListItemClick(e) {
|
||||
//$(this) is the clicked listItem
|
||||
setSelectedMention($(this));
|
||||
choseMentionOptions(true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save content to original textarea element, using for form submit to server-side
|
||||
* @param e
|
||||
*/
|
||||
function updateDataInputData(e) {
|
||||
var elmInputBoxText = elmInputBoxContent.html();
|
||||
elmInputBox.val(convertSpace(elmInputBoxText));
|
||||
log(elmInputBox.val(), 'elmInputBoxText : ');
|
||||
tmpEle = elmInputBox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim space and from string
|
||||
* @param text
|
||||
* @returns {*|void|string|XML}
|
||||
*/
|
||||
function trimSpace(text) {
|
||||
return text.replace(/^( | |\s)+|( | |\s)+$/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to space
|
||||
* @param text
|
||||
* @returns {*|void|string|XML}
|
||||
*/
|
||||
function convertSpace(text) {
|
||||
return text.replace(/( )+/g, ' ');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle User search action with timeout, and show mention if needed
|
||||
*/
|
||||
function doSearchAndShow() {
|
||||
|
||||
if (settings.timeOut > 0) {
|
||||
if (settings.globalTimeout !== null) {
|
||||
clearTimeout(settings.globalTimeout);
|
||||
}
|
||||
settings.globalTimeout = setTimeout(function () {
|
||||
settings.globalTimeout = null;
|
||||
|
||||
settings.onDataRequest.call(this, 'search', currentMention.keyword, onDataRequestCompleteCallback);
|
||||
|
||||
}, settings.timeOut);
|
||||
|
||||
} else {
|
||||
settings.onDataRequest.call(this, 'search', currentMention.keyword, onDataRequestCompleteCallback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and handle dropdown popover content show/hide
|
||||
* @param keyword
|
||||
* @param responseData
|
||||
*/
|
||||
function populateDropdown(keyword, responseData) {
|
||||
list.empty();
|
||||
currentMention.jqueryDomNode = null;
|
||||
currentMention.mentionItemDataSet = responseData;
|
||||
|
||||
if (responseData.length) {
|
||||
if (currentMention.charAtFound === true) {
|
||||
showDropDown();
|
||||
}
|
||||
|
||||
responseData.forEach(function (item, index) {
|
||||
var listItem = $(settings.templates.listItem);
|
||||
listItem.attr('data-item-id', item.id);
|
||||
listItem.find('img:first').attr('src', item.avatar);
|
||||
listItem.find('p.title:first').html(item.name);
|
||||
listItem.find('p.help-block:first').html(item.info);
|
||||
listItem.bind('click', onListItemClick);
|
||||
list.append(listItem);
|
||||
});
|
||||
|
||||
} else {
|
||||
hideDropDown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show popover box contain result item
|
||||
*/
|
||||
function showDropDown() {
|
||||
var curAbsPos = getSelectionCoords();
|
||||
dropDownShowing = true;
|
||||
popoverEle.css({
|
||||
display: 'block',
|
||||
top: curAbsPos.y - (elmInputBoxContentAbsPosition.top - $(document).scrollTop()) + (editableContentLineHeightPx + 10),
|
||||
left: curAbsPos.x - elmInputBoxContentAbsPosition.left
|
||||
});
|
||||
}
|
||||
|
||||
function hideDropDown() {
|
||||
dropDownShowing = false;
|
||||
popoverEle.css({display: 'none'});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle the event when user choosing / chose.
|
||||
* @param e
|
||||
* @returns {boolean} Continue to run the rest of code or not. If choosing metion or choosed mention, will stop doing anything else.
|
||||
*/
|
||||
function handleUserChooseOption(e) {
|
||||
if (!dropDownShowing) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((e.keyCode === KEY.UP || e.which === KEY.UP) || (e.keyCode === KEY.DOWN || e.which === KEY.DOWN)) {
|
||||
choosingMentionOptions(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to exit mention state: Stop mention if @, Home, Enter, Tabs
|
||||
if (((e.keyCode === KEY.HOME || e.which === KEY.HOME))
|
||||
|| ((e.keyCode === KEY.RETURN || e.which === KEY.RETURN))
|
||||
|| ((e.keyCode === KEY.TAB || e.which === KEY.TAB))
|
||||
) {
|
||||
choseMentionOptions();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update mention keyword on: Input / LEFT-RIGHT
|
||||
*/
|
||||
function updateMentionKeyword(e) {
|
||||
if (document.selection) {
|
||||
// var node = document.selection.createRange().parentElement(); // IE
|
||||
var node = document.selection.createRange(); // IE
|
||||
// TODO: Test on IE
|
||||
} else {
|
||||
// var node = window.getSelection().anchorNode.parentNode; // everyone else
|
||||
var node = window.getSelection().anchorNode; // everyone else
|
||||
}
|
||||
|
||||
var textNodeData = node.data;
|
||||
if (typeof textNodeData === 'undefined') {
|
||||
textNodeData = '';
|
||||
}
|
||||
var cursorPosition = getSelectionEndPositionInCurrentLine(); // passing the js DOM ele
|
||||
|
||||
// Save current position for mouse click handling, because when you use mouse, no selection was found.
|
||||
currentMention.lastActiveNode = node;
|
||||
|
||||
// reset and set new mention keyword
|
||||
currentMention.keyword = '';
|
||||
|
||||
var i = cursorPosition - 1; // NOTE: cursorPosition is Non-zero base
|
||||
var next = true;
|
||||
while (next) {
|
||||
var charAt = textNodeData.charAt(i);
|
||||
if (charAt === '' || charAt === settings.triggerChar) {
|
||||
next = false;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
|
||||
currentMention.keyword = textNodeData.substring(i + 1, cursorPosition);
|
||||
if (currentMention.keyword.indexOf(settings.triggerChar) === -1) {
|
||||
currentMention.keyword = '';
|
||||
currentMention.charAtFound = false;
|
||||
|
||||
// NOTE: Still need mention but turn off dropdown now
|
||||
hideDropDown();
|
||||
} else {
|
||||
currentMention.keyword = currentMention.keyword.substring(1, cursorPosition);
|
||||
currentMention.charAtFound = true;
|
||||
}
|
||||
|
||||
log(currentMention.keyword, 'currentMention.keyword');
|
||||
}
|
||||
|
||||
function getMentionKeyword() {
|
||||
return currentMention.keyword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update UI, show the selected item
|
||||
* @param item Jquery object represent the list-item
|
||||
*/
|
||||
function setSelectedMention(item) {
|
||||
currentMention.jqueryDomNode = item;
|
||||
updateSelectedMentionUI(item);
|
||||
|
||||
log(item, 'setSelectedMention item: ');
|
||||
}
|
||||
|
||||
function updateSelectedMentionUI(selectedMentionItem) {
|
||||
$.each(list.children(), function (i, listItem) {
|
||||
$(listItem).removeClass('active');
|
||||
});
|
||||
selectedMentionItem.addClass('active');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle when user use keyboard to choose mention
|
||||
* @param e
|
||||
*/
|
||||
function choosingMentionOptions(e) {
|
||||
log('choosingMentionOptions');
|
||||
|
||||
// Get Selected mention Item
|
||||
if (currentMention.jqueryDomNode === null) {
|
||||
setSelectedMention(list.children().first());
|
||||
}
|
||||
|
||||
var item = [];
|
||||
|
||||
if (e.keyCode === KEY.DOWN || e.which === KEY.DOWN) {
|
||||
item = currentMention.jqueryDomNode.next();
|
||||
} else if (e.keyCode === KEY.UP || e.which === KEY.UP) {
|
||||
item = currentMention.jqueryDomNode.prev();
|
||||
}
|
||||
|
||||
if (item.length === 0) {
|
||||
item = currentMention.jqueryDomNode;
|
||||
}
|
||||
|
||||
setSelectedMention(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle UI and data when user chose an mention option.
|
||||
*/
|
||||
function choseMentionOptions(chooseByMouse) {
|
||||
if (chooseByMouse === 'undefined') {
|
||||
chooseByMouse = false;
|
||||
}
|
||||
log('choosedMentionOptions by ' + (chooseByMouse ? 'Mouse' : 'Keyboard'));
|
||||
|
||||
var currentMentionItemData = {};
|
||||
|
||||
var selectedId = currentMention.jqueryDomNode.attr('data-item-id');
|
||||
for (var i = 0, len = currentMention.mentionItemDataSet.length; i < len; i++) {
|
||||
if (selectedId == currentMention.mentionItemDataSet[i].id) {
|
||||
currentMentionItemData = currentMention.mentionItemDataSet[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var highlightNode = $(settings.templates.highlight);
|
||||
var highlightContentNode = $(settings.templates.highlightContent
|
||||
.replace('[HREF]', currentMentionItemData.href)
|
||||
.replace('[TEXT]', currentMentionItemData.name)
|
||||
.replace('[ITEM_ID]', currentMentionItemData.id)
|
||||
);
|
||||
highlightNode.append(highlightContentNode);
|
||||
replaceTextInRange('@' + currentMention.keyword, highlightNode.prop('outerHTML'), chooseByMouse);
|
||||
|
||||
|
||||
// Finish mention
|
||||
log('Finish mention', '', 'warn');
|
||||
|
||||
needMention = false; // Reset mention state
|
||||
currentMention.keyword = ''; // reset current Data if start with @
|
||||
|
||||
hideDropDown();
|
||||
updateDataInputData();
|
||||
}
|
||||
|
||||
function log(msg, prefix, level) {
|
||||
if (typeof level === 'undefined') {
|
||||
level = 'log';
|
||||
}
|
||||
if (settings.debug === 1) {
|
||||
eval("console." + level + "(inputId, prefix ? prefix + ':' : '', msg);");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Intend to replace current @key-word with mention structured HTML
|
||||
* NOTE: depend on jQuery
|
||||
* @param fromString
|
||||
* @param toTextHtml
|
||||
* @param choosedByMouse
|
||||
*/
|
||||
function replaceTextInRange(fromString, toTextHtml, choosedByMouse) {
|
||||
var positionInfo = {
|
||||
startBefore: 0,
|
||||
startAfter: 0,
|
||||
stopBefore: 0,
|
||||
stopAfter: 0,
|
||||
};
|
||||
|
||||
var sel = window.getSelection();
|
||||
var range;
|
||||
|
||||
|
||||
// Move caret to current caret in case of contentediable is not active --> no caret
|
||||
|
||||
if (choosedByMouse !== 'undefined' && choosedByMouse === true) {
|
||||
var lastActiveNode = currentMention.lastActiveNode;
|
||||
try {
|
||||
var offset = lastActiveNode.data.length;
|
||||
} catch (e) {
|
||||
log(e, 'lastActiveNode Error:');
|
||||
var offset = 0;
|
||||
}
|
||||
|
||||
range = document.createRange();
|
||||
range.setStart(lastActiveNode, offset);
|
||||
range.collapse(true);
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
|
||||
// TODO: Bug: Choose mention by mouse: @123456: IF user put caret between 2 & 3 THEN the highlight will replace only 3456
|
||||
}
|
||||
|
||||
var isIE = false;
|
||||
|
||||
var stopPos = sel.focusOffset;
|
||||
var startPos = stopPos - fromString.length;
|
||||
|
||||
if (window.getSelection) {
|
||||
isIE = false;
|
||||
sel = window.getSelection();
|
||||
if (sel.rangeCount > 0) {
|
||||
range = sel.getRangeAt(0).cloneRange();
|
||||
range.collapse(true);
|
||||
}
|
||||
} else if ((sel = document.selection) && sel.type != "Control") {
|
||||
range = sel.createRange();
|
||||
isIE = true;
|
||||
}
|
||||
|
||||
if (startPos !== stopPos) {
|
||||
// replace / Remove content
|
||||
range.setStart(sel.anchorNode, startPos);
|
||||
range.setEnd(sel.anchorNode, stopPos);
|
||||
range.deleteContents();
|
||||
}
|
||||
|
||||
// insert
|
||||
var node = document.createElement('span');
|
||||
node.setAttribute('class', 'mention-area');
|
||||
node.innerHTML = toTextHtml;
|
||||
range.insertNode(node);
|
||||
range.setEnd(sel.focusNode, range.endContainer.length);
|
||||
|
||||
positionInfo.startBefore = startPos;
|
||||
positionInfo.stopBefore = stopPos;
|
||||
positionInfo.startAfter = startPos;
|
||||
positionInfo.stopAfter = startPos + node.innerText.length;
|
||||
|
||||
|
||||
// move cursor to end of keyword after replace
|
||||
var stop = false;
|
||||
node = $(sel.anchorNode);
|
||||
while (!stop) {
|
||||
if (node.next().text().length === 0) {
|
||||
stop = true;
|
||||
} else {
|
||||
node = node.next();
|
||||
}
|
||||
}
|
||||
|
||||
// insert <newElem> after list
|
||||
var newElem = $(settings.templates.normalText).insertAfter(node);
|
||||
|
||||
// move caret to after <newElem>
|
||||
range = document.createRange();
|
||||
range.setStartAfter(newElem.get(0));
|
||||
range.setEndAfter(newElem.get(0));
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
|
||||
return positionInfo;
|
||||
}
|
||||
|
||||
|
||||
// Public methods
|
||||
return {
|
||||
init: function (domTarget) {
|
||||
initTextArea(domTarget);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get current caret / selection absolute position (relative to viewport , not to parent)
|
||||
* Thank to Tim Down: http://stackoverflow.com/questions/6846230/coordinates-of-selected-text-in-browser-page
|
||||
* NOTE: This is relative to viewport, not its parent
|
||||
* @param win
|
||||
* @returns {{x: number, y: number}}
|
||||
*/
|
||||
function getSelectionCoords(win) {
|
||||
win = win || window;
|
||||
var doc = win.document;
|
||||
var sel = doc.selection, range, rects, rect;
|
||||
var x = 0, y = 0;
|
||||
if (sel) {
|
||||
if (sel.type != "Control") {
|
||||
range = sel.createRange();
|
||||
range.collapse(true);
|
||||
x = range.boundingLeft;
|
||||
y = range.boundingTop;
|
||||
}
|
||||
} else if (win.getSelection) {
|
||||
sel = win.getSelection();
|
||||
if (sel.rangeCount) {
|
||||
range = sel.getRangeAt(0).cloneRange();
|
||||
|
||||
if (range.getClientRects) {
|
||||
range.collapse(true);
|
||||
rects = range.getClientRects();
|
||||
if (rects.length > 0) {
|
||||
rect = rects[0];
|
||||
}
|
||||
x = rect.left;
|
||||
y = rect.top;
|
||||
}
|
||||
// Fall back to inserting a temporary element
|
||||
if (x == 0 && y == 0) {
|
||||
var span = doc.createElement("span");
|
||||
if (span.getClientRects) {
|
||||
// Ensure span has dimensions and position by
|
||||
// adding a zero-width space character
|
||||
span.appendChild(doc.createTextNode("\u200b"));
|
||||
range.insertNode(span);
|
||||
rect = span.getClientRects()[0];
|
||||
x = rect.left;
|
||||
y = rect.top;
|
||||
var spanParent = span.parentNode;
|
||||
spanParent.removeChild(span);
|
||||
|
||||
// Glue any broken text nodes back together
|
||||
spanParent.normalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {x: x, y: y};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current caret position in current line (not the current contenteditable)
|
||||
* @returns {number}
|
||||
*/
|
||||
function getSelectionEndPositionInCurrentLine() {
|
||||
var selectionEndPos = 0;
|
||||
if (window.getSelection) {
|
||||
var sel = window.getSelection();
|
||||
selectionEndPos = sel.focusOffset;
|
||||
}
|
||||
|
||||
return selectionEndPos;
|
||||
}
|
||||
|
||||
// TODO: Add setting option: showMentionedItem :Filter mentioned item, we should not show a item if it already mentioned
|
||||
// TODO: Elastic search in case of local data (in case of ajax --> depend on server-side)
|
||||
// TODO: Use higlight
|
||||
// TODO: Dropdown: scroll to see more item WHEN user press DOWN and reach the end of list.
|
||||
// TODO: Change to A cross-browser JavaScript range and selection library.: https://github.com/timdown/rangy
|
||||
|
||||
}(jQuery));
|
||||
306
worklenz-frontend/src/res/js/smooth-scroll.js
Normal file
306
worklenz-frontend/src/res/js/smooth-scroll.js
Normal file
@@ -0,0 +1,306 @@
|
||||
// SmoothScroll v0.9.9
|
||||
// Licensed under the terms of the MIT license.
|
||||
|
||||
// People involved
|
||||
// - Balazs Galambosi: maintainer (CHANGELOG.txt)
|
||||
// - Patrick Brunner (patrickb1991@gmail.com)
|
||||
// - Michael Herf: ssc_pulse Algorithm
|
||||
|
||||
function ssc_init() {
|
||||
if (!document.body) return;
|
||||
var e = document.body;
|
||||
var t = document.documentElement;
|
||||
var n = window.innerHeight;
|
||||
var r = e.scrollHeight;
|
||||
ssc_root = document.compatMode.indexOf("CSS") >= 0 ? t : e;
|
||||
ssc_activeElement = e;
|
||||
ssc_initdone = true;
|
||||
if (top != self) {
|
||||
ssc_frame = true
|
||||
} else if (r > n && (e.offsetHeight <= n || t.offsetHeight <= n)) {
|
||||
ssc_root.style.height = "auto";
|
||||
if (ssc_root.offsetHeight <= n) {
|
||||
var i = document.createElement("div");
|
||||
i.style.clear = "both";
|
||||
e.appendChild(i)
|
||||
}
|
||||
}
|
||||
if (!ssc_fixedback) {
|
||||
e.style.backgroundAttachment = "scroll";
|
||||
t.style.backgroundAttachment = "scroll"
|
||||
}
|
||||
if (ssc_keyboardsupport) {
|
||||
ssc_addEvent("keydown", ssc_keydown)
|
||||
}
|
||||
}
|
||||
|
||||
function ssc_scrollArray(e, t, n, r) {
|
||||
r || (r = 1e3);
|
||||
ssc_directionCheck(t, n);
|
||||
ssc_que.push({
|
||||
x: t,
|
||||
y: n,
|
||||
lastX: t < 0 ? .99 : -.99,
|
||||
lastY: n < 0 ? .99 : -.99,
|
||||
start: +(new Date)
|
||||
});
|
||||
if (ssc_pending) {
|
||||
return
|
||||
}
|
||||
var i = function () {
|
||||
var s = +(new Date);
|
||||
var o = 0;
|
||||
var u = 0;
|
||||
for (var a = 0; a < ssc_que.length; a++) {
|
||||
var f = ssc_que[a];
|
||||
var l = s - f.start;
|
||||
var c = l >= ssc_animtime;
|
||||
var h = c ? 1 : l / ssc_animtime;
|
||||
if (ssc_pulseAlgorithm) {
|
||||
h = ssc_pulse(h)
|
||||
}
|
||||
var p = f.x * h - f.lastX >> 0;
|
||||
var d = f.y * h - f.lastY >> 0;
|
||||
o += p;
|
||||
u += d;
|
||||
f.lastX += p;
|
||||
f.lastY += d;
|
||||
if (c) {
|
||||
ssc_que.splice(a, 1);
|
||||
a--
|
||||
}
|
||||
}
|
||||
if (t) {
|
||||
var v = e.scrollLeft;
|
||||
e.scrollLeft += o;
|
||||
if (o && e.scrollLeft === v) {
|
||||
t = 0
|
||||
}
|
||||
}
|
||||
if (n) {
|
||||
var m = e.scrollTop;
|
||||
e.scrollTop += u;
|
||||
if (u && e.scrollTop === m) {
|
||||
n = 0
|
||||
}
|
||||
}
|
||||
if (!t && !n) {
|
||||
ssc_que = []
|
||||
}
|
||||
if (ssc_que.length) {
|
||||
setTimeout(i, r / ssc_framerate + 1)
|
||||
} else {
|
||||
ssc_pending = false
|
||||
}
|
||||
};
|
||||
setTimeout(i, 0);
|
||||
ssc_pending = true
|
||||
}
|
||||
|
||||
function ssc_wheel(e) {
|
||||
if (!ssc_initdone) {
|
||||
ssc_init()
|
||||
}
|
||||
var t = e.target;
|
||||
var n = ssc_overflowingAncestor(t);
|
||||
if (!n || e.defaultPrevented || ssc_isNodeName(ssc_activeElement, "embed") || ssc_isNodeName(t, "embed") && /\.pdf/i.test(t.src)) {
|
||||
return true
|
||||
}
|
||||
var r = e.wheelDeltaX || 0;
|
||||
var i = e.wheelDeltaY || 0;
|
||||
if (!r && !i) {
|
||||
i = e.wheelDelta || 0
|
||||
}
|
||||
if (Math.abs(r) > 1.2) {
|
||||
r *= ssc_stepsize / 120
|
||||
}
|
||||
if (Math.abs(i) > 1.2) {
|
||||
i *= ssc_stepsize / 120
|
||||
}
|
||||
ssc_scrollArray(n, -r, -i);
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
function ssc_keydown(e) {
|
||||
var t = e.target;
|
||||
var n = e.ctrlKey || e.altKey || e.metaKey;
|
||||
if (/input|textarea|embed/i.test(t.nodeName) || t.isContentEditable || e.defaultPrevented || n) {
|
||||
return true
|
||||
}
|
||||
if (ssc_isNodeName(t, "button") && e.keyCode === ssc_key.spacebar) {
|
||||
return true
|
||||
}
|
||||
var r, i = 0,
|
||||
s = 0;
|
||||
var o = ssc_overflowingAncestor(ssc_activeElement);
|
||||
if (o) {
|
||||
var u = o.clientHeight;
|
||||
}
|
||||
if (o == document.body) {
|
||||
u = window.innerHeight
|
||||
}
|
||||
switch (e.keyCode) {
|
||||
case ssc_key.up:
|
||||
s = -ssc_arrowscroll;
|
||||
break;
|
||||
case ssc_key.down:
|
||||
s = ssc_arrowscroll;
|
||||
break;
|
||||
case ssc_key.spacebar:
|
||||
r = e.shiftKey ? 1 : -1;
|
||||
s = -r * u * .9;
|
||||
break;
|
||||
case ssc_key.pageup:
|
||||
s = -u * .9;
|
||||
break;
|
||||
case ssc_key.pagedown:
|
||||
s = u * .9;
|
||||
break;
|
||||
case ssc_key.home:
|
||||
s = -o.scrollTop;
|
||||
break;
|
||||
case ssc_key.end:
|
||||
var a = o.scrollHeight - o.scrollTop - u;
|
||||
s = a > 0 ? a + 10 : 0;
|
||||
break;
|
||||
case ssc_key.left:
|
||||
i = -ssc_arrowscroll;
|
||||
break;
|
||||
case ssc_key.right:
|
||||
i = ssc_arrowscroll;
|
||||
break;
|
||||
default:
|
||||
return true
|
||||
}
|
||||
ssc_scrollArray(o, i, s);
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
function ssc_mousedown(e) {
|
||||
ssc_activeElement = e.target
|
||||
}
|
||||
|
||||
function ssc_setCache(e, t) {
|
||||
for (var n = e.length; n--;) ssc_cache[ssc_uniqueID(e[n])] = t;
|
||||
return t
|
||||
}
|
||||
|
||||
function ssc_overflowingAncestor(e) {
|
||||
var t = [];
|
||||
var n = ssc_root.scrollHeight;
|
||||
do {
|
||||
var r = ssc_cache[ssc_uniqueID(e)];
|
||||
if (r) {
|
||||
return ssc_setCache(t, r)
|
||||
}
|
||||
t.push(e);
|
||||
if (n === e.scrollHeight) {
|
||||
if (!ssc_frame || ssc_root.clientHeight + 10 < n) {
|
||||
return ssc_setCache(t, document.body)
|
||||
}
|
||||
} else if (e.clientHeight + 10 < e.scrollHeight) {
|
||||
overflow = getComputedStyle(e, "").getPropertyValue("overflow");
|
||||
if (overflow === "scroll" || overflow === "auto") {
|
||||
return ssc_setCache(t, e)
|
||||
}
|
||||
}
|
||||
} while (e = e.parentNode)
|
||||
}
|
||||
|
||||
function ssc_addEvent(e, t, n) {
|
||||
window.addEventListener(e, t, n || false)
|
||||
}
|
||||
|
||||
function ssc_removeEvent(e, t, n) {
|
||||
window.removeEventListener(e, t, n || false)
|
||||
}
|
||||
|
||||
function ssc_isNodeName(e, t) {
|
||||
return e.nodeName.toLowerCase() === t.toLowerCase()
|
||||
}
|
||||
|
||||
function ssc_directionCheck(e, t) {
|
||||
e = e > 0 ? 1 : -1;
|
||||
t = t > 0 ? 1 : -1;
|
||||
if (ssc_direction.x !== e || ssc_direction.y !== t) {
|
||||
ssc_direction.x = e;
|
||||
ssc_direction.y = t;
|
||||
ssc_que = []
|
||||
}
|
||||
}
|
||||
|
||||
function ssc_pulse_(e) {
|
||||
var t, n, r;
|
||||
e = e * ssc_pulseScale;
|
||||
if (e < 1) {
|
||||
t = e - (1 - Math.exp(-e))
|
||||
} else {
|
||||
n = Math.exp(-1);
|
||||
e -= 1;
|
||||
r = 1 - Math.exp(-e);
|
||||
t = n + r * (1 - n)
|
||||
}
|
||||
return t * ssc_pulseNormalize
|
||||
}
|
||||
|
||||
function ssc_pulse(e) {
|
||||
if (e >= 1) return 1;
|
||||
if (e <= 0) return 0;
|
||||
if (ssc_pulseNormalize == 1) {
|
||||
ssc_pulseNormalize /= ssc_pulse_(1)
|
||||
}
|
||||
return ssc_pulse_(e)
|
||||
}
|
||||
|
||||
var ssc_framerate = 150;
|
||||
var ssc_animtime = 500;
|
||||
var ssc_stepsize = 150;
|
||||
var ssc_pulseAlgorithm = true;
|
||||
var ssc_pulseScale = 6;
|
||||
var ssc_pulseNormalize = 1;
|
||||
var ssc_keyboardsupport = true;
|
||||
var ssc_arrowscroll = 50;
|
||||
var ssc_frame = false;
|
||||
var ssc_direction = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
|
||||
var ssc_initdone = false;
|
||||
var ssc_fixedback = true;
|
||||
var ssc_root = document.documentElement;
|
||||
var ssc_activeElement;
|
||||
var ssc_key = {
|
||||
left: 37,
|
||||
up: 38,
|
||||
right: 39,
|
||||
down: 40,
|
||||
spacebar: 32,
|
||||
pageup: 33,
|
||||
pagedown: 34,
|
||||
end: 35,
|
||||
home: 36
|
||||
};
|
||||
|
||||
var ssc_que = [];
|
||||
var ssc_pending = false;
|
||||
var ssc_cache = {};
|
||||
|
||||
setInterval(function () {
|
||||
ssc_cache = {}
|
||||
}, 10 * 1e3);
|
||||
|
||||
var ssc_uniqueID = function () {
|
||||
var e = 0;
|
||||
return function (t) {
|
||||
return t.ssc_uniqueID || (t.ssc_uniqueID = e++)
|
||||
}
|
||||
}();
|
||||
|
||||
var ischrome = /chrome/.test(navigator.userAgent.toLowerCase());
|
||||
|
||||
if (ischrome) {
|
||||
ssc_addEvent("mousedown", ssc_mousedown);
|
||||
ssc_addEvent("mousewheel", ssc_wheel);
|
||||
ssc_addEvent("load", ssc_init)
|
||||
}
|
||||
41
worklenz-frontend/src/res/scss/antd-variables.scss
Normal file
41
worklenz-frontend/src/res/scss/antd-variables.scss
Normal file
@@ -0,0 +1,41 @@
|
||||
:root {
|
||||
--ant-primary-color: #1890ff;
|
||||
--ant-primary-color-hover: #40a9ff;
|
||||
--ant-primary-color-active: #096dd9;
|
||||
--ant-primary-color-outline: rgba(24, 144, 255, .2);
|
||||
--ant-primary-1: #e6f7ff;
|
||||
--ant-primary-2: #bae7ff;
|
||||
--ant-primary-3: #91d5ff;
|
||||
--ant-primary-4: #69c0ff;
|
||||
--ant-primary-5: #40a9ff;
|
||||
--ant-primary-6: #1890ff;
|
||||
--ant-primary-7: #096dd9;
|
||||
--ant-primary-color-deprecated-l-35: #cbe6ff;
|
||||
--ant-primary-color-deprecated-l-20: #7ec1ff;
|
||||
--ant-primary-color-deprecated-t-20: #46a6ff;
|
||||
--ant-primary-color-deprecated-t-50: #8cc8ff;
|
||||
--ant-primary-color-deprecated-f-12: rgba(24, 144, 255, .12);
|
||||
--ant-primary-color-active-deprecated-f-30: rgba(230, 247, 255, .3);
|
||||
--ant-primary-color-active-deprecated-d-02: #dcf4ff;
|
||||
--ant-success-color: #52c41a;
|
||||
--ant-success-color-hover: #73d13d;
|
||||
--ant-success-color-active: #389e0d;
|
||||
--ant-success-color-outline: rgba(82, 196, 26, .2);
|
||||
--ant-success-color-deprecated-bg: #f6ffed;
|
||||
--ant-success-color-deprecated-border: #b7eb8f;
|
||||
--ant-error-color: #ff4d4f;
|
||||
--ant-error-color-hover: #ff7875;
|
||||
--ant-error-color-active: #d9363e;
|
||||
--ant-error-color-outline: rgba(255, 77, 79, .2);
|
||||
--ant-error-color-deprecated-bg: #fff2f0;
|
||||
--ant-error-color-deprecated-border: #ffccc7;
|
||||
--ant-warning-color: #faad14;
|
||||
--ant-warning-color-hover: #ffc53d;
|
||||
--ant-warning-color-active: #d48806;
|
||||
--ant-warning-color-outline: rgba(250, 173, 20, .2);
|
||||
--ant-warning-color-deprecated-bg: #fffbe6;
|
||||
--ant-warning-color-deprecated-border: #ffe58f;
|
||||
--ant-info-color: #1890ff;
|
||||
--ant-info-color-deprecated-bg: #e6f7ff;
|
||||
--ant-info-color-deprecated-border: #91d5ff
|
||||
}
|
||||
22275
worklenz-frontend/src/res/scss/antd.scss
Normal file
22275
worklenz-frontend/src/res/scss/antd.scss
Normal file
File diff suppressed because it is too large
Load Diff
407
worklenz-frontend/src/res/scss/gantt.scss
Normal file
407
worklenz-frontend/src/res/scss/gantt.scss
Normal file
@@ -0,0 +1,407 @@
|
||||
$red: #ff6252;
|
||||
$column_count: var(--column_count);
|
||||
$column_width: var(--column_width);
|
||||
|
||||
:root {
|
||||
--column_count: 20;
|
||||
--column_width: 70px;
|
||||
}
|
||||
|
||||
|
||||
.header {
|
||||
color: #202125;
|
||||
margin-bottom: 40px;
|
||||
|
||||
h2 {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
p {
|
||||
font-weight: 300;
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
max-width: 100vw;
|
||||
min-width: 700px;
|
||||
margin: 0 auto;
|
||||
padding: 0px;
|
||||
gap: 10px;
|
||||
overflow: auto;
|
||||
max-height: 80vh;
|
||||
}
|
||||
|
||||
.gantt {
|
||||
display: grid;
|
||||
border: 0;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&__row {
|
||||
display: grid;
|
||||
grid-template-columns: 200px 1fr;
|
||||
background-color: #fff;
|
||||
|
||||
&--empty {
|
||||
background-color: #fafafa !important;
|
||||
z-index: 1;
|
||||
|
||||
.gantt__row-first {
|
||||
border-width: 1px 1px 0 0;
|
||||
border-left: 1px solid #f0f0f0;
|
||||
}
|
||||
}
|
||||
|
||||
&--lines {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: transparent;
|
||||
grid-template-columns: 200px repeat($column_count, $column_width);
|
||||
|
||||
span {
|
||||
display: block;
|
||||
border-right: 1px solid #f0f0f0;
|
||||
|
||||
&.weekend {
|
||||
background: linear-gradient(-45deg, rgb(230, 230, 230) 12.5%, transparent 12.5%, transparent 50%, rgb(230, 230, 230) 50%, rgb(230, 230, 230) 62.5%, transparent 62.5%, transparent) 0% 0% / 5px 5px;
|
||||
z-index: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:after {
|
||||
grid-row: 1;
|
||||
grid-column: 0;
|
||||
background-color: #1688b345;
|
||||
z-index: 2;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&--months {
|
||||
color: #000;
|
||||
background-color: #fafafa !important;
|
||||
grid-template-columns: 200px repeat($column_count, $column_width);
|
||||
|
||||
.gantt__row-first {
|
||||
border-top: 0 !important;
|
||||
background-color: #fafafa !important;
|
||||
}
|
||||
|
||||
span {
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
align-self: center;
|
||||
font-weight: bold;
|
||||
padding: 20px 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-first {
|
||||
background-color: #fff;
|
||||
border: none;
|
||||
padding: 15px 10px;
|
||||
font-size: 13px;
|
||||
// font-weight: bold;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&-first-user {
|
||||
border-width: 1px 1px 0px 0px;
|
||||
}
|
||||
|
||||
&-bars {
|
||||
list-style: none;
|
||||
display: grid;
|
||||
padding: 0px 0px;
|
||||
margin: 0px 0px 7px 0px;
|
||||
grid-template-columns: repeat($column_count, $column_width);
|
||||
grid-gap: 0px 0;
|
||||
align-items: center;
|
||||
|
||||
li {
|
||||
font-weight: 500;
|
||||
text-align: left;
|
||||
font-size: 13px;
|
||||
min-height: 15px;
|
||||
background-color: #55de84;
|
||||
padding: 0px 0px;
|
||||
margin: 7px 1px 0px 1px;
|
||||
color: #fff;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
line-height: 21px;
|
||||
|
||||
.ant-btn {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
padding: 0px 15px;
|
||||
color: white;
|
||||
border: none;
|
||||
font-weight: 400;
|
||||
|
||||
:hover {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
&.stripes {
|
||||
background-image: repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255, 255, 255, .1) 5px, rgba(255, 255, 255, .1) 12px);
|
||||
}
|
||||
|
||||
&:before,
|
||||
&:after {
|
||||
content: "";
|
||||
height: 100%;
|
||||
top: 0;
|
||||
z-index: 4;
|
||||
position: absolute;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
&:before {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&:after {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-month-range {
|
||||
list-style: none;
|
||||
display: grid;
|
||||
padding: 12px 0px;
|
||||
margin: 0;
|
||||
grid-template-columns: repeat($column_count, $column_width);
|
||||
grid-gap: 8px 0;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
align-items: center;
|
||||
|
||||
li {
|
||||
font-weight: 500;
|
||||
text-align: left;
|
||||
font-size: 14px;
|
||||
min-height: 15px;
|
||||
background-color: #55de84;
|
||||
padding: 0px 0px;
|
||||
margin: 0px 1px;
|
||||
color: #fff;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
animation: 0.5s ease-out 0s 1 scale-up-hor-left;
|
||||
|
||||
.ant-btn {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
padding: 0px 8px;
|
||||
color: white;
|
||||
border: none;
|
||||
font-weight: 400;
|
||||
|
||||
:hover {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
&:before,
|
||||
&:after {
|
||||
content: "";
|
||||
height: 100%;
|
||||
top: 0;
|
||||
z-index: 4;
|
||||
position: absolute;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
&:before {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&:after {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.project-header {
|
||||
background-color: #f0f2f5 !important;
|
||||
font-size: 14px;
|
||||
border-right: 1px solid #f0f0f0;
|
||||
border-top: 1px solid #bdbdbd;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.col {
|
||||
padding: 16px 0;
|
||||
text-align: center;
|
||||
border-radius: 0;
|
||||
min-height: 30px;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
background: rgba(0, 160, 233, 0.7);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.col.right {
|
||||
background: #00a0e9;
|
||||
}
|
||||
|
||||
.sticky-left {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.grid-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.grid-header.sticky-left {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.grid-column {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.gantt__row {
|
||||
a {
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.gantt__row--months span {
|
||||
font-weight: 500;
|
||||
padding: 12px 10px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.gantt-user {
|
||||
border-right: 1px solid #f0f0f0;
|
||||
border-left: 1px solid #f0f0f0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.dotted-border {
|
||||
border-bottom: 1px dashed #707070;
|
||||
|
||||
:last-of-type {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.p-default {
|
||||
padding: 24px !important;
|
||||
}
|
||||
|
||||
.border-l-b {
|
||||
border-left: 1px solid #f0f0f0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
border-right: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.project-name {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #292929;
|
||||
}
|
||||
|
||||
.project-name:hover {
|
||||
color: #40a9ff;
|
||||
}
|
||||
|
||||
.ant-popover-inner-content {
|
||||
padding: 12px 24px;
|
||||
}
|
||||
|
||||
/** ---------- animations ---------- */
|
||||
@-webkit-keyframes scale-up-hor-left {
|
||||
0% {
|
||||
-webkit-transform: scaleX(0.4);
|
||||
transform: scaleX(0.4);
|
||||
-webkit-transform-origin: 0% 0%;
|
||||
transform-origin: 0% 0%;
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: scaleX(1);
|
||||
transform: scaleX(1);
|
||||
-webkit-transform-origin: 0% 0%;
|
||||
transform-origin: 0% 0%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes scale-up-hor-left {
|
||||
0% {
|
||||
-webkit-transform: scaleX(0.4);
|
||||
transform: scaleX(0.4);
|
||||
-webkit-transform-origin: 0% 0%;
|
||||
transform-origin: 0% 0%;
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: scaleX(1);
|
||||
transform: scaleX(1);
|
||||
-webkit-transform-origin: 0% 0%;
|
||||
transform-origin: 0% 0%;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes slideDown {
|
||||
from {
|
||||
-webkit-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
-webkit-transform: translateY(0);
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
-webkit-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
-webkit-transform: translateY(0);
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.weekend {
|
||||
background: linear-gradient(-45deg, rgb(230, 230, 230) 12.5%, transparent 12.5%, transparent 50%, rgb(230, 230, 230) 50%, rgb(230, 230, 230) 62.5%, transparent 62.5%, transparent) 0% 0% / 5px 5px;
|
||||
}
|
||||
|
||||
.sunday {
|
||||
border-right: solid 1px silver !important;
|
||||
}
|
||||
|
||||
.member {
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.header-bg {
|
||||
background-color: #fafafa !important;
|
||||
}
|
||||
|
||||
.month {
|
||||
font-weight: 500;
|
||||
}
|
||||
Reference in New Issue
Block a user