iso-profiles-settings/tromjaro/gnome/live-overlay/etc/skel/.local/share/gnome-shell/extensions/todo.txt@bart.libert.gmail.com/todoMenuItem.js
2019-07-09 04:57:09 +03:00

521 lines
19 KiB
JavaScript

const Clutter = imports.gi.Clutter;
const Ellipsize = imports.gi.Pango.EllipsizeMode;
const Gdk = imports.gi.Gdk;
const Lang = imports.lang;
const Params = imports.misc.params;
const PopupMenu = imports.ui.popupMenu;
const St = imports.gi.St;
const GrabHelper = imports.ui.grabHelper;
const Extension = imports.misc.extensionUtils.getCurrentExtension();
const Shared = Extension.imports.sharedConstants;
const UrlHighlighter = Extension.imports.urlHighlighter;
const Utils = Extension.imports.utils;
const Third = Extension.imports.third_party;
const JsTodo = Third.jsTodoTxt.jsTodoTxt;
const Gettext = imports.gettext;
const _ = Gettext.domain('todotxt').gettext;
var TodoMenuItem = new Lang.Class({
Name: 'TodoMenuItem',
Extends: PopupMenu.PopupBaseMenuItem,
labelExpanded: false,
ellipsizeMode: Shared.TASK_ELLIPSIZE_MIDDLE,
maxWidth: undefined,
buttons: [],
labels: [],
settings: null,
task: null,
_RGBAColorToHex: function(rgbaColor) {
return (0 + (Math.round(rgbaColor * 255)).toString(16)).slice(-2);
},
_RGBAStringtoHexString: function(rgbaColorSting) {
let rgbaColor = new Gdk.RGBA();
rgbaColor.parse(rgbaColorSting);
return '#' + this._RGBAColorToHex(rgbaColor.red) + '' +
this._RGBAColorToHex(rgbaColor.green) + '' +
this._RGBAColorToHex(rgbaColor.blue);
},
expandLabel: function() {
if (!this.labelExpanded) {
let singleLineWidth = this.label.clutter_text.get_preferred_width(-1)[1];
let singleLineHeight = this.label.clutter_text.get_preferred_height(-1)[1];
let numberOfLinesNeeded = Math.round((singleLineWidth / this.maxWidth) + 1);
this.label.clutter_text.set_ellipsize(Ellipsize.NONE);
this.label.clutter_text.set_line_wrap(true);
this.label.clutter_text.set_line_wrap_mode(imports.gi.Pango.WrapMode.WORD_CHAR);
this.label.set_height(numberOfLinesNeeded * singleLineHeight);
this.labelExpanded = true;
for (let i = 0, len = this.buttons.length; i < len; i++) {
this.buttons[i].set_style('margin-bottom: ' + (numberOfLinesNeeded - 1) * singleLineHeight +
'px;');
}
}
},
_convertEllipsizeMode: function(configEllipsizeMode) {
if (this.ellipsizeMode == Shared.TASK_ELLIPSIZE_START) {
return Ellipsize.START;
}
if (this.ellipsizeMode == Shared.TASK_ELLIPSIZE_MIDDLE) {
return Ellipsize.MIDDLE;
}
return Ellipsize.END;
},
contractLabel: function() {
if (this.labelExpanded) {
this.label.clutter_text.set_ellipsize(this._convertEllipsizeMode(this.ellipsizeMode));
this.label.clutter_text.set_line_wrap(false);
this.label.clutter_text.set_line_wrap_mode(imports.gi.Pango.WrapMode.WORD_CHAR);
this.label.set_height(-1);
this.labelExpanded = false;
for (let i = 0, len = this.buttons.length; i < len; i++) {
this.buttons[i].set_style('margin-bottom: 0px;');
}
}
},
_truncate: function(expansionMode) {
this.label.clutter_text.set_ellipsize(this._convertEllipsizeMode(this.ellipsizeMode));
this.label.set_reactive(true);
if (expansionMode == Shared.TASK_EXPAND_SCROLL || expansionMode == Shared.TASK_EXPAND_BOTH) {
this.label.connect('scroll-event', Lang.bind(this, function(o, e) {
if (e.get_scroll_direction() == Clutter.ScrollDirection.UP) {
this.contractLabel();
return;
}
if (e.get_scroll_direction() == Clutter.ScrollDirection.DOWN) {
this.expandLabel();
return;
}
}));
}
this.label.set_style('max-width: ' + this.maxWidth + 'px');
},
_addLabel: function(labelSource) {
let label = new St.Label({
text: '',
x_align: St.Align.END
});
if (this.task[labelSource] !== null) {
label.set_text(this.task[labelSource].join());
this.addActor(label);
this.labels.push(label);
}
},
_addProjectsLabel: function() {
if (this.settings.get('show-projects-label')) {
this._addLabel('projects');
}
},
_addContextsLabel: function() {
if (this.settings.get('show-contexts-label')) {
this._addLabel('contexts');
}
},
_createTextLabel: function() {
let markupFunction = function(url, color) {
return '<span foreground="' + color + '"><u>' + url + '</u></span>';
};
let urlColor = this.settings.get('url-color');
if (urlColor == Shared.URL_COLOR_TASK) {
markupFunction = function(url, color) {
return '<u>' + url + '</u>';
};
}
if (urlColor == Shared.URL_COLOR_CUSTOM) {
let hexColor = this._RGBAStringtoHexString(this.settings.get('custom-url-color'));
markupFunction = function(url, color) {
return '<span foreground="' + hexColor + '"><u>' + url + '</u></span>';
};
}
this.highlighter = new UrlHighlighter.TaskURLHighlighter(this.task.text, false, true,
markupFunction);
this.label = this.highlighter.actor;
this.label.x_expand = true;
},
_addButtons: function() {
let expansionMode = this.settings.get('long-tasks-expansion-mode');
if (expansionMode == Shared.TASK_EXPAND_BUTTON || expansionMode == Shared.TASK_EXPAND_BOTH) {
this._addExpandButton();
}
if (this.settings.get('show-done-or-archive-button')) {
if (!this.task.complete) {
this._addDoneButton();
} else {
this._addArchiveButton();
}
}
if (this.settings.get('show-delete-button')) {
this._addDeleteButton();
}
if (this.settings.get('show-edit-button')) {
this._addEditButton();
}
if (this.settings.get('show-priority-buttons')) {
this._addPriorityButtons();
}
},
_addEditButton: function() {
let editButton = this._createButton('input-keyboard-symbolic',
_('Edit %(task)'.replace('%(task)', this.task.text)));
editButton.connect('clicked', Lang.bind(this, function() {
this.enterEditMode();
}));
this.addActor(editButton);
},
_addPriorityButton: function(up) {
let prioButton = this._createButton('go-' + ((up === true) ? 'up' : 'down') + '-symbolic', (up ===
true) ?
_('Increase %(task) priority'.replace('%(task)', this.task.text)) :
_('Decrease %(task) priority'.replace('%(task)', this.task.text)));
let _up = up;
prioButton.connect('clicked', Lang.bind(this, function() {
this.taskActions.priorityAction(this.task, _up);
}));
this.addActor(prioButton);
},
_addPriorityButtons: function() {
this._addPriorityButton(true);
this._addPriorityButton(false);
},
_addArchiveButton: function() {
let archiveButton = this._createButton('document-save-symbolic',
_('Archive %(task)'.replace('%(task)', this.task.text)));
archiveButton.connect('clicked', Lang.bind(this, function() {
this.taskActions.archiveAction(this.task);
}));
this.actor.add_style_class_name('doneTaskItem');
this.addActor(archiveButton);
},
_addDeleteButton: function() {
let deleteButton = this._createButton('edit-delete-symbolic',
_('Delete %(task)'.replace('%(task)', this.task.text)));
deleteButton.connect('clicked', Lang.bind(this, function() {
this.enterDeleteMode();
}));
this.addActor(deleteButton);
},
_addExpandButton: function() {
let iconNames = [
'view-more-symbolic',
'content-loading-symbolic',
'zoom-in-symbolic',
'zoom-original-symbolic',
'view-more',
'content-loading',
'zoom-in',
'zoom-original'
];
let expandButton = this._createButton(Utils.getFirstExistingIcon(iconNames),
_('Expand %(task)'.replace('%(task)', this.task.text)));
expandButton.connect('clicked', Lang.bind(this, function() {
if (this.labelExpanded) {
this.contractLabel();
} else {
this.expandLabel();
}
}));
this.addActor(expandButton);
},
_addDoneButton: function() {
let doneButton = this._createButton('object-select-symbolic',
_('Mark %(task) as done'.replace('%(task)', this.task.text)));
doneButton.connect('clicked', Lang.bind(this, function() {
this.taskActions.doneAction(this.task);
}));
this.addActor(doneButton);
},
_createButton: function(icon, accessible_name, dont_store) {
let button = new St.Button({
child: new St.Icon({
icon_name: icon,
y_expand: false
}),
y_align: St.Align.START,
reactive: true,
can_focus: true,
track_hover: true,
style_class: 'todo-txt-task-button',
y_expand: false,
y_fill: false
});
dont_store = dont_store || false;
if (Utils.isValid(accessible_name)) {
button.set_accessible_name(accessible_name);
}
if (!dont_store) {
this.buttons.push(button);
}
return button;
},
_applyPriorityStyling: function() {
if (!this.settings.get('style-priorities')) {
return;
}
let markup = this.settings.get('priorities-markup')[this.task.priority];
if (!Utils.isValid(markup)) {
return;
}
let style = '';
if (markup.changeColor === true) {
style = style + 'color:' + markup.color.to_string() + ';';
}
if (markup.bold === true) {
style = style + 'font-weight: bold;';
}
if (markup.italic === true) {
style = style + 'font-style: italic;';
}
this.actor.set_style(style);
},
_setClickAction: function() {
this.connect('activate', Lang.bind(this, function() {
switch (this.settings.get('click-action')) {
case Shared.CLICK_ACTION_EDIT:
this.enterEditMode();
break;
case Shared.CLICK_ACTION_DONE:
this.taskActions.doneAction(this.task);
break;
default:
break;
}
}));
},
_init: function(task, settings, actions, params) {
this.parent(params);
this.buttons = [];
this.labels = [];
this.taskActions = Params.parse(actions, {
'doneAction': null,
'archiveAction': null,
'deleteAction': null,
'editAction': null,
'priorityAction': null
});
this.task = task;
this.ellipsizeMode = settings.get('long-tasks-ellipsize-mode');
this.maxWidth = settings.get('long-tasks-max-width');
this.settings = settings;
if (!('addActor' in TodoMenuItem.prototype)) {
TodoMenuItem.prototype.addActor = function(element) {
this.actor.add(element);
};
}
this._createTextLabel();
this.addActor(this.label);
this._addProjectsLabel();
this._addContextsLabel();
this._addButtons();
this._setClickAction();
this._applyPriorityStyling();
if (settings.get('truncate-long-tasks')) {
this._truncate(settings.get('long-tasks-expansion-mode'));
}
this.label.add_style_class_name('todo-txt-task-label');
this.grabHelper = new GrabHelper.GrabHelper(this);
this.grabHelper.addActor(this);
},
setActive: function(active) {
let activeChanged = active != this.active;
if (activeChanged) {
this.active = active;
if (active) {
this.actor.add_style_class_name('selected');
} else {
this.actor.remove_style_class_name('selected');
// Remove the CSS active state if the user press the button and
// while holding moves to another menu item, so we don't paint all items.
// The correct behaviour would be to set the new item with the CSS
// active state as well, but button-press-event is not trigered,
// so we should track it in our own, which would involve some work
// in the container
this.actor.remove_style_pseudo_class('active');
}
this.emit('active-changed', active);
}
},
removeButtonsAndLabels: function() {
for (let i = 0, len = this.labels.length; i < len; i++) {
this.actor.remove_child(this.labels[i]);
}
for (let i = 0, len = this.buttons.length; i < len; i++) {
this.actor.remove_child(this.buttons[i]);
}
},
restoreButtonsAndLabels: function() {
for (let i = 0, len = this.labels.length; i < len; i++) {
this.actor.insert_child_at_index(this.labels[i], i + 2);
}
for (let i = 0, len = this.buttons.length; i < len; i++) {
this.actor.insert_child_at_index(this.buttons[i], i + 2 + this.labels.length);
}
},
exitEditMode: function() {
this.highlighter.actor.set_text(this.task.text);
this.label = this.highlighter.actor;
this.actor.remove_child(this.editTask);
this.actor.insert_child_at_index(this.label, 1);
this.restoreButtonsAndLabels();
this.setSensitive(true);
this.editTask = null;
},
enterEditMode: function() {
let oldTask = this.task;
this.removeButtonsAndLabels();
this.actor.remove_child(this.label);
this.setSensitive(false);
this.editTask = new St.Entry({
name: 'editTask',
text: this.task.toString(),
track_hover: true,
can_focus: true,
x_expand: true
});
this.editTask.set_primary_icon(new St.Icon({
icon_name: 'document-save-symbolic',
icon_size: 14
}));
this.editTask.set_secondary_icon(new St.Icon({
icon_name: 'edit-delete-symbolic',
icon_size: 14
}));
this.editTask.connect('primary-icon-clicked', Lang.bind(this, function() {
this.taskActions.editAction(oldTask, new JsTodo.TodoTxtItem(this.editTask.get_text()));
this.exitEditMode();
}));
this.editTask.connect('secondary-icon-clicked', Lang.bind(this, function() {
this.exitEditMode();
}));
this.editTask.clutter_text.connect('key-press-event', Lang.bind(this, function(actor, event) {
let symbol = event.get_key_symbol();
let modifiers = event.get_state();
if (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_KP_Enter || symbol ==
Clutter.KEY_ISO_Enter) {
this.taskActions.editAction(oldTask, new JsTodo.TodoTxtItem(this.editTask.get_text()));
return Clutter.EVENT_STOP;
}
let isCtrlModifier = (modifiers & Clutter.ModifierType.CONTROL_MASK) !== 0;
if (isCtrlModifier && (symbol == Clutter.KEY_c)) {
this.exitEditMode();
return Clutter.EVENT_STOP;
}
return Clutter.EVENT_PROPAGATE;
}));
this.actor.insert_child_at_index(this.editTask, 1);
this.editTask.clutter_text.grab_key_focus();
// this.grabHelper.grab({ actor: this.editTask, focus: this.editTask, onUngrab: Lang.bind(this, this.exitEditMode) });
},
_createYesButton: function() {
let iconNames = [
'emblem-ok-symbolic',
'stock_yes-symbolic',
'gtk-yes-symbolic',
'dialog-yes-symbolic',
'gtk-ok-symbolic',
'stock_yes',
'gtk-yes',
'dialog-yes',
'gtk-ok'
];
return this._createButton(Utils.getFirstExistingIcon(iconNames),
_('Delete %(task)'.replace('%(task)', this.task.text)), true);
},
_createNoButton: function() {
let iconNames = [
'cancel-symbolic',
'gtk-cancel-symbolic',
'button_cancel-symbolic',
'gtk-no-symbolic',
'dialog-no-symbolic',
'edit-undo-symbolic',
'edit-clear-symbolic',
'cancel',
'gtk-cancel',
'button_cancel',
'gtk-no',
'dialog-no',
'edit-undo',
'edit-clear'
];
return this._createButton(Utils.getFirstExistingIcon(iconNames),
_('Undo delete %(task)'.replace('%(task)', this.task.text)), true);
},
enterDeleteMode: function() {
if (this.settings.get('confirm-delete')) {
this.removeButtonsAndLabels();
this.actor.remove_child(this.label);
this.setSensitive(false);
this.deleteLabel = new St.Label({
text: _('Are you sure?'),
x_expand: true
});
let confirmStyle = 'color: #F00; font-weight: bold; font-style: italic';
this.deleteLabel.set_style(confirmStyle);
this.yesButton = this._createYesButton();
this.noButton = this._createNoButton();
this.yesButton.set_style(confirmStyle);
this.noButton.set_style(confirmStyle);
this.yesButton.connect('clicked', Lang.bind(this, function() {
this.taskActions.deleteAction(this.task);
return;
}));
this.noButton.connect('clicked', Lang.bind(this, function() {
this.actor.remove_child(this.yesButton);
this.actor.remove_child(this.noButton);
this.actor.remove_child(this.deleteLabel);
this.actor.insert_child_at_index(this.label, 1);
this.restoreButtonsAndLabels();
this.setSensitive(true);
return;
}));
this.addActor(this.deleteLabel);
this.addActor(this.yesButton);
this.addActor(this.noButton);
return;
}
this.taskActions.deleteAction(this.task);
}
});
/* vi: set expandtab tabstop=4 shiftwidth=4: */