roundcubemail-plugins-kolab/plugins/kolab_notes/notes.js

1493 lines
50 KiB
JavaScript

/**
* Client scripts for the Kolab Notes plugin
*
* @author Thomas Bruederli <bruederli@kolabsys.com>
* @author Aleksander Machniak <machniak@kolabsys.com>
*
* @licstart The following is the entire license notice for the
* JavaScript code in this file.
*
* Copyright (C) 2014-2017, Kolab Systems AG <contact@kolabsys.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @licend The above is the entire license notice
* for the JavaScript code in this file.
*/
function rcube_kolab_notes_ui(settings)
{
/* private vars */
var ui_loading = false;
var saving_lock;
var search_query;
var folder_drop_target;
var notebookslist;
var noteslist;
var notesdata = {};
var taglist;
var search_request;
var search_query;
var render_no_focus;
var me = this;
/* public members */
this.selected_list = null;
this.selected_note = null;
this.notebooks = rcmail.env.kolab_notebooks || {};
this.list_set_sort = list_set_sort;
this.settings = settings;
/**
* initialize the notes UI
*/
function init()
{
// register button commands
rcmail.register_command('createnote', function(){
warn_unsaved_changes(function(){ edit_note(null, 'new'); });
}, false);
rcmail.register_command('list-create', function(){ list_edit_dialog(null); }, true);
rcmail.register_command('list-edit', function(){ list_edit_dialog(me.selected_list); }, false);
rcmail.register_command('list-delete', function(){ list_delete(me.selected_list); }, false);
rcmail.register_command('list-remove', function(){ list_remove(me.selected_list); }, false);
rcmail.register_command('list-sort', list_set_sort, true);
rcmail.register_command('save', save_note, true);
rcmail.register_command('delete', delete_notes, false);
rcmail.register_command('search', quicksearch, true);
rcmail.register_command('reset-search', reset_search, true);
rcmail.register_command('sendnote', send_note, false);
rcmail.register_command('print', print_note, false);
rcmail.register_command('history', show_history_dialog, false);
// register server callbacks
rcmail.addEventListener('plugin.data_ready', data_ready);
rcmail.addEventListener('plugin.render_note', render_note);
rcmail.addEventListener('plugin.update_note', update_note);
rcmail.addEventListener('plugin.update_list', list_update);
rcmail.addEventListener('plugin.destroy_list', list_destroy);
rcmail.addEventListener('plugin.unlock_saving', function() {
if (saving_lock) {
rcmail.set_busy(false, null, saving_lock);
}
if (rcmail.gui_objects.noteseditform) {
rcmail.lock_form(rcmail.gui_objects.noteseditform, false);
}
});
rcmail.addEventListener('plugin.close_history_dialog', close_history_dialog);
rcmail.addEventListener('plugin.note_render_changelog', render_changelog);
rcmail.addEventListener('plugin.note_show_revision', render_revision);
rcmail.addEventListener('plugin.note_show_diff', show_diff);
// initialize folder selectors
if (settings.selected_list && !me.notebooks[settings.selected_list]) {
settings.selected_list = null;
}
for (var id in me.notebooks) {
if (me.notebooks[id].editable && !settings.selected_list) {
settings.selected_list = id;
}
}
var widget_class = window.kolab_folderlist || rcube_treelist_widget;
notebookslist = new widget_class(rcmail.gui_objects.notebooks, {
id_prefix: 'rcmliknb',
save_state: true,
selectable: true,
keyboard: true,
searchbox: '#notebooksearch',
search_action: 'notes/list',
search_sources: [ 'folders', 'users' ],
search_title: rcmail.gettext('listsearchresults','kolab_notes'),
check_droptarget: function(node) {
var list = me.notebooks[node.id];
return !node.virtual && list.editable && node.id != me.selected_list;
}
});
notebookslist.addEventListener('select', function(node) {
var id = node.id;
if (me.notebooks[id] && id != me.selected_list) {
warn_unsaved_changes(function(){
rcmail.enable_command('createnote', has_permission(me.notebooks[id], 'i'));
rcmail.enable_command('list-edit', has_permission(me.notebooks[id], 'a'));
rcmail.enable_command('list-delete', has_permission(me.notebooks[id], 'xa'));
rcmail.enable_command('list-remove', !me.notebooks[id]['default']);
fetch_notes(id); // sets me.selected_list
rcmail.triggerEvent('show-list', {title: me.notebooks[id].listname}); // Elastic
},
function(){
// restore previous selection
notebookslist.select(me.selected_list);
});
}
// unfocus clicked list item
$(notebookslist.get_item(id)).find('a.listname').first().blur();
});
notebookslist.addEventListener('subscribe', function(p) {
var list;
if ((list = me.notebooks[p.id])) {
list.subscribed = p.subscribed || false;
rcmail.http_post('list', { _do:'subscribe', _list:{ id:p.id, permanent:list.subscribed?1:0 } });
}
});
notebookslist.addEventListener('remove', function(p) {
if (me.notebooks[p.id] && !me.notebooks[p.id]['default']) {
list_remove(p.id);
}
});
notebookslist.addEventListener('insert-item', function(p) {
var list = p.data;
if (list && list.id && !list.virtual) {
me.notebooks[list.id] = list;
if (list.subscribed)
rcmail.http_post('list', { _do:'subscribe', _list:{ id:p.id, permanent:1 } });
}
});
notebookslist.addEventListener('click-item', function(p) {
// avoid link execution
return false;
});
notebookslist.addEventListener('search-complete', function(data) {
if (data.length)
rcmail.display_message(rcmail.gettext('nrnotebooksfound','kolab_notes').replace('$nr', data.length), 'voice');
else
rcmail.display_message(rcmail.gettext('nonotebooksfound','kolab_notes'), 'notice');
});
// Make Elastic checkboxes pretty
if (window.UI && UI.pretty_checkbox) {
notebookslist.addEventListener('add-item', function(prop) {
UI.pretty_checkbox($(prop.li).find('input'));
});
}
$(rcmail.gui_objects.notebooks).on('click', 'div.folder > a.listname', function(e) {
var id = String($(this).closest('li').attr('id')).replace(/^rcmliknb/, '');
notebookslist.select(id);
e.preventDefault();
return false;
});
// register dbl-click handler to open list edit dialog
$(rcmail.gui_objects.notebooks).on('dblclick', 'li:not(.virtual) a', function(e) {
var id = String($(this).closest('li').attr('id')).replace(/^rcmliknb/, '');
if (me.notebooks[id] && has_permission(me.notebooks[id], 'a')) {
list_edit_dialog(id);
}
// clear text selection (from dbl-clicking)
var sel = window.getSelection ? window.getSelection() : document.selection;
if (sel && sel.removeAllRanges) {
sel.removeAllRanges();
}
else if (sel && sel.empty) {
sel.empty();
}
e.preventDefault();
return false;
});
// initialize notes list widget
if (rcmail.gui_objects.noteslist) {
rcmail.noteslist = noteslist = new rcube_list_widget(rcmail.gui_objects.noteslist,
{ multiselect:true, draggable:true, keyboard:true });
noteslist.addEventListener('select', function(list) {
render_no_focus = rcube_event._last_keyboard_event && $(list.list).has(rcube_event._last_keyboard_event.target);
var selection_changed = list.selection.length != 1 || !me.selected_note || list.selection[0] != me.selected_note.id;
selection_changed && warn_unsaved_changes(function(){
var note;
if (!list.multi_selecting && noteslist.selection.length == 1 && (note = notesdata[noteslist.selection[0]])) {
edit_note(note.uid, 'edit');
}
else {
reset_view(true);
}
},
function(){
// TODO: previous restore selection
list.select(me.selected_note.id);
});
rcmail.enable_command('delete', me.notebooks[me.selected_list] && has_permission(me.notebooks[me.selected_list], 'td') && list.selection.length > 0);
rcmail.enable_command('sendnote', list.selection.length > 0);
rcmail.enable_command('print', 'history', list.selection.length == 1);
})
.addEventListener('dragstart', function(e) {
folder_drop_target = null;
notebookslist.drag_start();
})
.addEventListener('dragmove', function(e) {
folder_drop_target = notebookslist.intersects(rcube_event.get_mouse_pos(e), true);
})
.addEventListener('dragend', function(e) {
notebookslist.drag_end();
// move dragged notes to this folder
if (folder_drop_target) {
noteslist.draglayer.hide();
// check unsaved changes first
var new_folder_id = folder_drop_target;
warn_unsaved_changes(
// ok
function() {
move_notes(new_folder_id);
reset_view();
noteslist.clear_selection();
},
// nok
undefined,
// beforesave
function(savedata) {
savedata.list = new_folder_id;
// remove from list and thus avoid being moved (again)
var id = me.selected_note.id;
noteslist.remove_row(id);
delete notesdata[id];
}
);
}
folder_drop_target = null;
})
.init().focus();
}
if (settings.sort_col) {
$('#notessortmenu a.by-' + settings.sort_col).addClass('selected');
}
init_editor();
if (settings.selected_list) {
notebookslist.select(settings.selected_list)
}
rcmail.addEventListener('kolab-tags-search', filter_notes)
.addEventListener('kolab-tags-drop-data', function(e) { return notesdata[e.id]; })
.addEventListener('kolab-tags-drop', function(e) {
if ($(e.list).is('#kolabnoteslist')) {
return;
}
var rec = notesdata[e.id];
if (rec && rec.id && e.tag) {
savedata = me.selected_note && rec.uid == me.selected_note.uid ? get_save_data() : $.extend({}, rec);
if (savedata.id) delete savedata.id;
if (savedata.html) delete savedata.html;
if (!savedata.tags)
savedata.tags = [];
savedata.tags.push(e.tag);
rcmail.lock_form(rcmail.gui_objects.noteseditform, true);
saving_lock = rcmail.set_busy(true, 'kolab_notes.savingdata');
rcmail.http_post('action', { _data: savedata, _do: 'edit' }, true);
}
});
rcmail.triggerEvent('kolab-notes-init');
}
this.init = init;
/**
*
*/
function init_dialog()
{
rcmail.register_command('save', save_note, true);
rcmail.addEventListener('plugin.render_note', render_note);
rcmail.addEventListener('plugin.update_note', function(data){
data.id = rcmail.html_identifier_encode(data.uid);
notesdata[data.id] = data;
render_note(data);
});
rcmail.addEventListener('plugin.unlock_saving', function(){
if (saving_lock) {
rcmail.set_busy(false, null, saving_lock);
}
if (rcmail.gui_objects.noteseditform) {
rcmail.lock_form(rcmail.gui_objects.noteseditform, false);
}
if (rcmail.is_framed()) {
parent.$(parent.kolab_note_dialog_element).dialog('destroy');
}
});
var id, callback = function() {
if (settings.selected_uid) {
me.selected_list = settings.selected_list;
edit_note(settings.selected_uid);
}
else {
me.selected_note = $.extend({
list: me.selected_list,
uid: null,
title: rcmail.gettext('newnote','kolab_notes'),
description: '',
tags: [],
created: rcmail.gettext('now', 'kolab_notes'),
changed: rcmail.gettext('now', 'kolab_notes')
}, rcmail.env.kolab_notes_template || {});
render_note(me.selected_note);
}
};
for (id in me.notebooks) {
if (me.notebooks[id].editable) {
me.selected_list = id;
break;
}
}
init_editor(callback);
}
this.init_dialog = init_dialog;
/**
* Initialize TinyMCE editor
*/
function init_editor(callback)
{
if (callback) {
rcmail.addEventListener('editor-load', callback);
}
// initialize HTML editor
var config = $.extend(rcmail.env.editor_config, {disabled_plugins: ['image', 'media']});
rcmail.editor_init(config, 'notecontent');
// register click handler for message links
$(rcmail.gui_objects.notesattachmentslist).on('click', 'li a.messagelink', function() {
rcmail.open_window(this.href);
return false;
});
}
/**
* Quote HTML entities
*/
function Q(str)
{
return String(str).replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
/**
* Check permissions on the given list object
*/
function has_permission(list, perm)
{
// multiple chars means "either of"
if (String(perm).length > 1) {
for (var i=0; i < perm.length; i++) {
if (has_permission(list, perm[i])) {
return true;
}
}
}
if (list.rights && String(list.rights).indexOf(perm) >= 0) {
return true;
}
return (perm == 'i' && list.editable);
}
/**
*
*/
function edit_note(uid, action)
{
if (!uid) {
me.selected_note = null;
if (noteslist)
noteslist.clear_selection();
me.selected_note = {
list: me.selected_list,
uid: null,
title: rcmail.gettext('newnote','kolab_notes'),
description: '',
tags: [],
created: rcmail.gettext('now', 'kolab_notes'),
changed: rcmail.gettext('now', 'kolab_notes')
}
render_note(me.selected_note);
}
else {
ui_loading = rcmail.set_busy(true, 'loading');
rcmail.http_request('get', { _list:me.selected_list, _id:uid }, true);
}
}
/**
*
*/
function list_edit_dialog(id)
{
var list = me.notebooks[id] || { name:'', editable:true, rights: 'riwta' },
title = rcmail.gettext((list.id ? 'editlist' : 'newnotebook'), 'kolab_notes'),
params = {_do: (list.id ? 'form-edit' : 'form-new'), _list: {id: list.id}, _framed: 1},
$dialog = $('<iframe>').attr('src', rcmail.url('list', params)).on('load', function() {
$(this).contents().find('#noteslist-name')
.prop('disabled', !has_permission(list, 'a'))
.val(list.editname || list.name)
.select();
}),
save_func = function() {
var data,
form = $dialog.contents().find('#noteslistpropform'),
name = form.find('#noteslist-name');
// form is not loaded
if (!form || !form.length)
return false;
// do some input validation
if (!name.val() || name.val().length < 2) {
rcmail.alert_dialog(rcmail.gettext('invalidlistproperties', 'kolab_notes'), function() {
name.select();
});
return false;
}
// post data to server
data = form.serializeJSON();
if (list.id)
data.id = list.id;
saving_lock = rcmail.set_busy(true, 'kolab_notes.savingdata');
rcmail.http_post('list', { _do: (list.id ? 'edit' : 'new'), _list: data });
return true;
};
rcmail.simple_dialog($dialog, title, save_func, {
width: 600,
height: 400
});
}
/**
* Callback from server after changing list properties
*/
function list_update(prop)
{
if (prop._reload) {
rcmail.redirect(rcmail.url('', { _list: (prop.newid || prop.id) }));
}
else if (prop.newid && prop.newid != prop.id) {
var book = $.extend({}, me.notebooks[prop.id]);
book.id = prop.newid;
book.name = prop.name;
book.listname = prop.listname;
book.editname = prop.editname || prop.name;
me.notebooks[prop.newid] = book;
delete me.notebooks[prop.id];
// update treelist item
var li = $(notebookslist.get_item(prop.id));
$('.listname', li).html(prop.listname);
notebookslist.update(prop.id, { id:book.id, html:li.html() });
// link all loaded note records to the new list id
if (me.selected_list == prop.id) {
me.selected_list = prop.newid;
for (var k in notesdata) {
if (notesdata[k].list == prop.id) {
notesdata[k].list = book.id;
}
}
notebookslist.select(prop.newid);
}
}
}
/**
*
*/
function list_delete(id)
{
var list = me.notebooks[id];
if (list) {
rcmail.confirm_dialog(rcmail.gettext('kolab_notes.deletenotebookconfirm'), 'delete', function() {
saving_lock = rcmail.set_busy(true, 'kolab_notes.savingdata');
rcmail.http_post('list', { _do: 'delete', _list: { id: list.id } });
});
}
}
/**
*
*/
function list_remove(id)
{
if (me.notebooks[id]) {
list_destroy(me.notebooks[id]);
rcmail.http_post('list', { _do:'subscribe', _list:{ id:id, permanent:0, recursive:1 } });
}
}
/**
* Callback from server on list delete command
*/
function list_destroy(prop)
{
if (!me.notebooks[prop.id]) {
return;
}
notebookslist.remove(prop.id);
delete me.notebooks[prop.id];
if (me.selected_list == prop.id) {
for (id in me.notebooks) {
if (me.notebooks[id]) {
notebookslist.select(id);
break;
}
}
}
}
/**
* Change notes list sort order
*/
function list_set_sort(col)
{
if (settings.sort_col != col) {
settings.sort_col = col;
$('#notessortmenu a').removeClass('selected').filter('.by-' + col).addClass('selected');
rcmail.save_pref({ name: 'kolab_notes_sort_col', value: col });
// re-sort table in DOM
$(noteslist.tbody).children().sortElements(function(la, lb){
var a_id = String(la.id).replace(/^rcmrow/, ''),
b_id = String(lb.id).replace(/^rcmrow/, ''),
a = notesdata[a_id],
b = notesdata[b_id];
if (!a || !b) {
return 0;
}
else if (settings.sort_col == 'title') {
return String(a.title).toLowerCase() > String(b.title).toLowerCase() ? 1 : -1;
}
else {
return b.changed_ - a.changed_;
}
});
}
}
/**
* Execute search
*/
function quicksearch()
{
var q;
if (rcmail.gui_objects.qsearchbox && (q = rcmail.gui_objects.qsearchbox.value)) {
var id = 'search-'+q;
// ignore if query didn't change
if (search_request == id)
return;
warn_unsaved_changes(function(){
search_request = id;
search_query = q;
fetch_notes();
},
function(){
reset_search();
});
}
else { // empty search input equals reset
reset_search();
}
}
/**
* Reset search and get back to normal listing
*/
function reset_search()
{
$(rcmail.gui_objects.qsearchbox).val('');
if (search_request) {
search_request = search_query = null;
fetch_notes();
}
}
/**
*
*/
function fetch_notes(id)
{
if (rcmail.busy)
return;
if (id && id != me.selected_list) {
me.selected_list = id;
}
ui_loading = rcmail.set_busy(true, 'loading');
rcmail.http_request('fetch', { _list:me.selected_list, _q:search_query }, true);
reset_view();
noteslist.clear(true);
notesdata = {};
update_state();
}
/**
* Filter notes by tag
*/
function filter_notes(tags)
{
var id, note, tr, match;
for (id in noteslist.rows) {
tr = noteslist.rows[id].obj;
note = notesdata[id];
match = note.tags && note.tags.length;
for (var i=0; match && note && i < tags.length; i++) {
if ($.inArray(tags[i], note.tags) < 0)
match = false;
}
if (match || !tags.length) {
$(tr).show();
}
else {
$(tr).hide();
}
if (me.selected_note && me.selected_note.uid == note.uid && !match) {
warn_unsaved_changes(function(){
me.selected_note = null;
noteslist.clear_selection();
}, function(){
filter_notes(tags);
});
}
}
}
/**
*
*/
function data_ready(data)
{
data.data.sort(function(a,b){
if (settings.sort_col == 'title') {
return String(a.title).toLowerCase() > String(b.title).toLowerCase() ? 1 : -1;
}
else {
return b.changed_ - a.changed_;
}
});
var i, id, rec;
for (i=0; data.data && i < data.data.length; i++) {
rec = data.data[i];
rec.id = rcmail.html_identifier_encode(rec.uid);
noteslist.insert_row({
id: 'rcmrow' + rec.id,
cols: [
{ className:'title', innerHTML:Q(rec.title) },
{ className:'date', innerHTML:Q(rec.changed || '') }
]
});
notesdata[rec.id] = rec;
}
update_taglist();
rcmail.set_busy(false, 'loading', ui_loading);
rcmail.triggerEvent('listupdate', {list: noteslist, rowcount:noteslist.rowcount});
if (settings.selected_uid) {
noteslist.select(rcmail.html_identifier_encode(settings.selected_uid));
delete settings.selected_uid;
}
else if (me.selected_note && notesdata[me.selected_note.id]) {
noteslist.select(me.selected_note.id);
}
else if (!data.data.length) {
rcmail.display_message(rcmail.gettext('norecordsfound','kolab_notes'), 'notice');
}
}
/**
*
*/
function render_note(data, container, temp, retry)
{
rcmail.set_busy(false, 'loading', ui_loading);
if (!data) {
rcmail.display_message(rcmail.get_label('recordnotfound', 'kolab_notes'), 'error');
return;
}
if (!container) {
container = rcmail.gui_containers['notedetailview'];
}
// for Elastic
rcmail.triggerEvent('show-content', {
mode: data.uid ? 'edit' : 'add',
title: rcmail.gettext(data.uid ? 'editnote' : 'newnote', 'kolab_notes'),
obj: $('#notedetailsbox').parent(),
scrollElement: $('#notedetailsbox')
});
var list = me.notebooks[data.list] || me.notebooks[me.selected_list] || { rights: 'lrs', editable: false };
content = $('#notecontent').val(data.description),
readonly = data.readonly || !(list.editable || !data.uid && has_permission(list,'i')),
attachmentslist = gui_object('notesattachmentslist', container).html(''),
titlecontainer = rcmail.gui_objects.noteviewtitle || container,
is_html = false;
// tag-edit line
var tagline = $('.tagline', titlecontainer);
if (window.kolab_tags_input) {
tagline.parent('.form-group').show();
taglist = kolab_tags_input(tagline, data.tags, readonly);
}
else {
tagline.parent('.form-group').hide();
}
$('.notetitle', titlecontainer).val(data.title).prop('disabled', readonly).show();
$('.dates .notecreated', titlecontainer).text(data.created || '');
$('.dates .notechanged', titlecontainer).text(data.changed || '');
if (data.created || data.changed) {
$('.dates', titlecontainer).show();
}
if (data.links) {
$.each(data.links, function(i, link) {
var li = $('<li>').addClass('link')
.addClass('message eml')
.append($('<a>')
.attr('href', link.mailurl)
.addClass('messagelink')
.text(link.subject || link.uri)
)
.appendTo(attachmentslist);
if (!readonly && !data._from_mail) {
$('<a>').attr({
href: '#delete',
title: rcmail.gettext('removelink', 'kolab_notes'),
label: rcmail.gettext('delete'),
'class': 'delete'
})
.click({ uri:link.uri }, function(e) {
remove_link(this, e.data.uri);
return false;
})
.appendTo(li);
}
});
}
if (!data.list)
data.list = list.id;
data.readonly = readonly;
if (!temp) {
$(rcmail.gui_objects.notebooks).filter('select').val(list.id);
me.selected_note = data;
me.selected_note.id = rcmail.html_identifier_encode(data.uid);
rcmail.enable_command('save', !readonly);
}
var html = data.html || data.description;
// convert plain text to HTML and make URLs clickable
if (html != '' && (!data.html || !html.match(/<(html|body)/))) {
html = text2html(html);
}
if (!readonly) {
gui_object('notesdetailview', container).hide();
gui_object('noteseditform', container).show();
rcmail.editor.set_content(html);
// read possibly re-formatted content back from editor for later comparison
me.selected_note.description = rcmail.editor.get_content().replace(/^\s*(<p><\/p>\n*)?/, '');
is_html = true;
}
else {
gui_object('noteseditform', container).hide();
gui_object('notesdetailview', container).html(html).show();
}
// notify subscribers
rcmail.triggerEvent('kolab_notes_render', { data:data, readonly:readonly, html:is_html });
if (rcmail.is_framed())
parent.rcmail.triggerEvent('kolab_notes_render', { data:data, readonly:readonly, html:is_html });
// Trigger resize (needed for proper editor resizing)
$(window).resize();
// Elastic
$(container).parents('.watermark').addClass('formcontainer');
$('#notedetailsbox').parent().trigger('loaded');
if (!readonly)
$('.notetitle', titlecontainer).focus().select();
}
/**
*
*/
function gui_object(name, container)
{
var elem = rcmail.gui_objects[name], selector = elem;
if (elem && elem.className && container) {
selector = '.' + String(elem.className).split(' ').join('.');
}
else if (elem && elem.id) {
selector = '#' + elem.id;
}
return $(selector, container);
}
/**
* Convert the given plain text to HTML contents to be displayed in editor
*/
function text2html(str)
{
// simple link parser (similar to rcube_string_replacer class in PHP)
var utf_domain = '[^?&@"\'/\\(\\)\\s\\r\\t\\n]+\\.([^\x00-\x2f\x3b-\x40\x5b-\x60\x7b-\x7f]{2,}|xn--[a-z0-9]{2,})',
url1 = '.:;,', url2 = 'a-z0-9%=#@+?&/_~\\[\\]-',
link_pattern = new RegExp('([hf]t+ps?://|www.)('+utf_domain+'(['+url1+']?['+url2+']+)*)?', 'ig'),
link_replace = function(matches, p1, p2) {
var url = (p1 == 'www.' ? 'http://' : '') + p1 + p2;
return '<a href="' + url + '" class="x-templink">' + p1 + p2 + '</a>';
};
return '<pre>' + Q(str).replace(link_pattern, link_replace) + '</pre>';
}
/**
*
*/
function show_history_dialog()
{
var dialog, rec = me.selected_note;
if (!rec || !rec.uid || !window.libkolab_audittrail) {
return false;
}
// render dialog
$dialog = libkolab_audittrail.object_history_dialog({
module: 'kolab_notes',
container: '#notehistory',
title: rcmail.gettext('libkolab.objectchangelog') + ' - ' + rec.title,
// callback function for list actions
listfunc: function(action, rev) {
var rec = $dialog.data('rec');
saving_lock = rcmail.set_busy(true, 'loading', saving_lock);
rcmail.http_post('action', { _do: action, _data: { uid: rec.uid, list:rec.list, rev: rev } }, saving_lock);
},
// callback function for comparing two object revisions
comparefunc: function(rev1, rev2) {
var rec = $dialog.data('rec');
saving_lock = rcmail.set_busy(true, 'loading', saving_lock);
rcmail.http_post('action', { _do: 'diff', _data: { uid: rec.uid, list: rec.list, rev1: rev1, rev2: rev2 } }, saving_lock);
}
});
$dialog.data('rec', rec);
// fetch changelog data
saving_lock = rcmail.set_busy(true, 'loading', saving_lock);
rcmail.http_post('action', { _do: 'changelog', _data: { uid: rec.uid, list: rec.list } }, saving_lock);
}
/**
*
*/
function render_changelog(data)
{
var $dialog = $('#notehistory'),
rec = $dialog.data('rec');
if (data === false || !data.length || !rec) {
// display 'unavailable' message
$('<div class="notfound-message note-dialog-message warning">').text(rcmail.gettext('libkolab.objectchangelognotavailable'))
.insertBefore($dialog.find('.changelog-table').hide());
return;
}
data.module = 'kolab_notes';
libkolab_audittrail.render_changelog(data, rec, me.notebooks[rec.list]);
}
/**
*
*/
function render_revision(data)
{
data.readonly = true;
// clone view and render data into a dialog
var model = rcmail.gui_containers['notedetailview'],
container = model.clone();
container
.removeAttr('id style class role')
.find('.mce-container').remove();
// reset custom styles
container.children('div, form').removeAttr('id style');
// open jquery UI dialog
container.dialog({
modal: false,
resizable: true,
closeOnEscape: true,
title: data.title + ' @ ' + data.rev,
close: function() {
container.dialog('destroy').remove();
},
buttons: [
{
text: rcmail.gettext('close'),
click: function() { container.dialog('close'); },
autofocus: true
}
],
width: model.width(),
height: model.height(),
minWidth: 450,
minHeight: 400
})
.show();
render_note(data, container, true);
}
/**
*
*/
function show_diff(data)
{
var change_old, change_new,
rec = me.selected_note,
$dialog = $('#notediff').clone();
$dialog.find('div.form-section, h2.note-title-new').hide().data('set', false);
// always show title
$('.note-title', $dialog).text(rec.title).removeClass('diff-text-old').show();
// show each property change
$.each(data.changes, function(i, change) {
var prop = change.property, r2, html = false,
row = $('div.note-' + prop, $dialog).first();
// special case: title
if (prop == 'title') {
$('.note-title', $dialog).addClass('diff-text-old').text(change['old'] || '--');
$('.note-title-new', $dialog).text(change['new'] || '--').show();
}
// no display container for this property
if (!row.length) {
return true;
}
if (change.diff_) {
row.children('.diff-text-diff').html(change.diff_);
row.children('.diff-text-old, .diff-text-new').hide();
}
else {
change_old = change.old_ || change['old'] || '--';
change_new = change.new_ || change['new'] || '--';
row.children('.diff-text-old')[html ? 'html' : 'text'](change_old).show();
row.children('.diff-text-new')[html ? 'html' : 'text'](change_new).show();
}
row.show().data('set', true);
});
// open jquery UI dialog
rcmail.simple_dialog($dialog,
rcmail.gettext('libkolab.objectdiff').replace('$rev1', data.rev1).replace('$rev2', data.rev2) + ' - ' + rec.title,
null, {
cancel_label: 'close',
minWidth: 400,
width: 480
}
);
// set dialog size according to content
libkolab_audittrail.dialog_resize($dialog.get(0), $dialog.height(), rcmail.gui_containers.notedetailview.width() - 40);
}
// close the note history dialog
function close_history_dialog()
{
$('#notehistory, #notediff').each(function(i, elem) {
var $dialog = $(elem);
if ($dialog.is(':ui-dialog'))
$dialog.dialog('close');
});
};
/**
*
*/
function remove_link(elem, uri)
{
// remove the link item matching the given uri
me.selected_note.links = $.grep(me.selected_note.links, function(link) { return link.uri != uri; });
me.selected_note._links_removed = true
// remove UI list item
$(elem).hide().closest('li').addClass('deleted');
}
/**
* Open a new window to print the currently selected note
*/
function print_note()
{
var list = me.notebooks[me.selected_list],
uid = me.selected_note ? me.selected_note.uid : 0;
if (list && uid) {
rcmail.open_window(rcmail.url('print', {_uid: uid, _list: list.id}), true, true);
}
}
/**
* Redirect to message compose screen with UIDs of notes to be appended
*/
function send_note()
{
var uids = [];
$.each(noteslist.selection, function() {
if (rec = notesdata[this]) {
uids.push(rec.uid);
// TODO: check if rec.uid == me.selected_note.uid and unsaved changes
}
});
if (uids.length) {
rcmail.goto_url('mail/compose', { _with_notes: uids.join(','), _notes_list: me.selected_list }, true);
}
}
/**
* Display the given counts to each tag
*/
function update_taglist(tags)
{
// compute counts first by iterating over all notes
var counts = {};
$.each(notesdata, function(id, rec) {
for (var t, j=0; rec && rec.tags && j < rec.tags.length; j++) {
t = rec.tags[j];
if (typeof counts[t] == 'undefined')
counts[t] = 0;
counts[t]++;
}
});
rcmail.triggerEvent('kolab-tags-counts', {counter: counts});
if (tags && tags.length) {
rcmail.triggerEvent('kolab-tags-refresh', {tags: tags});
}
}
/**
* Callback from server after saving a note record
*/
function update_note(data)
{
data.id = rcmail.html_identifier_encode(data.uid);
var row, is_new = (notesdata[data.id] == undefined && data.list == me.selected_list);
notesdata[data.id] = data;
if (is_new || me.selected_note && data.id == me.selected_note.id) {
render_note(data);
update_taglist(data.tags || []);
}
else if (data.tags) {
update_taglist(data.tags);
}
// add list item on top
if (is_new) {
noteslist.insert_row({
id: 'rcmrow' + data.id,
cols: [
{ className:'title', innerHTML:Q(data.title) },
{ className:'date', innerHTML:Q(data.changed || '') }
]
}, true);
noteslist.select(data.id);
}
// update list item
else if (row = noteslist.rows[data.id]) {
$('.title', row.obj).text(data.title);
$('.date', row.obj).text(data.changed || '');
// TODO: move to top
}
}
/**
*
*/
function reset_view(list)
{
close_history_dialog();
me.selected_note = null;
$('.notetitle', rcmail.gui_objects.noteviewtitle).val('').hide();
$('.dates', rcmail.gui_objects.noteviewtitle).hide();
$('.tagline', rcmail.gui_objects.noteviewtitle).parent('.form-group').hide();
$(rcmail.gui_objects.noteseditform).hide().parents('.watermark').removeClass('formcontainer');
$(rcmail.gui_objects.notesdetailview).hide();
$(rcmail.gui_objects.notesattachmentslist).html('');
rcmail.enable_command('save', false);
if (!list) {
rcmail.triggerEvent('show-list', {force: true});
}
}
/**
* Collect data from the edit form and submit it to the server
*/
function save_note(beforesave)
{
if (!me.selected_note) {
return false;
}
var savedata = get_save_data();
// run savedata through the given callback function
if (typeof beforesave == 'function') {
beforesave(savedata);
}
// add reference to old list if changed
if (me.selected_note.list && savedata.list != me.selected_note.list) {
savedata._fromlist = me.selected_note.list;
}
// do some input validation
if (savedata.title == '') {
rcmail.alert_dialog(rcmail.gettext('entertitle', 'kolab_notes'), function() {;
$('.notetitle', rcmail.gui_objects.noteviewtitle).focus();
});
return false;
}
if (check_change_state(savedata)) {
rcmail.lock_form(rcmail.gui_objects.noteseditform, true);
saving_lock = rcmail.set_busy(true, 'kolab_notes.savingdata');
rcmail.http_post('action', {_data: savedata, _do: savedata.uid ? 'edit' : 'new'}, true);
}
else {
rcmail.display_message(rcmail.get_label('nochanges', 'kolab_notes'), 'notice');
}
}
/**
* Collect updated note properties from edit form for saving
*/
function get_save_data()
{
var listselect = $('option:selected', rcmail.gui_objects.notebooks),
savedata = {
title: $.trim($('.notetitle', rcmail.gui_objects.noteviewtitle).val()),
description: rcmail.editor.get_content().replace(/^\s*(<p><\/p>\n*)?/, ''),
list: listselect.length ? listselect.val() : me.selected_note.list || me.selected_list,
uid: me.selected_note.uid,
tags: taglist ? kolab_tags_input_value(taglist) : []
};
// copy links
if ($.isArray(me.selected_note.links)) {
savedata.links = me.selected_note.links;
}
return savedata;
}
/**
* Check if the currently edited note record was changed
*/
function check_change_state(data)
{
if (!me.selected_note || me.selected_note.readonly || !has_permission(me.notebooks[me.selected_note.list || me.selected_list], 'i')) {
return false;
}
var savedata = data || get_save_data();
return savedata.title != me.selected_note.title
|| savedata.description != me.selected_note.description
|| savedata.tags.join(',') != (me.selected_note.tags || []).join(',')
|| savedata.list != me.selected_note.list
|| me.selected_note._links_removed;
}
/**
* Check for unsaved changes and warn the user
*/
function warn_unsaved_changes(ok, nok, beforesave)
{
if (typeof ok != 'function')
ok = function(){ };
if (typeof nok != 'function')
nok = function(){ };
if (check_change_state()) {
var dialog, buttons = [];
buttons.push({
text: rcmail.gettext('save'),
'class': 'mainaction save',
click: function() {
save_note(beforesave);
dialog.dialog('close');
rcmail.busy = false; // don't block next action
ok();
}
});
buttons.push({
text: rcmail.gettext('discard', 'kolab_notes'),
'class': 'discard',
click: function() {
dialog.dialog('close');
ok();
}
});
buttons.push({
text: rcmail.gettext('abort', 'kolab_notes'),
'class': 'cancel',
click: function() {
dialog.dialog('close');
nok();
}
});
var options = {
width: 460,
resizable: false,
closeOnEscape: false,
dialogClass: 'warning',
open: function(event, ui) {
$(this).parent().find('.ui-dialog-titlebar-close').hide();
setTimeout(function() {
dialog.parent().find('button:visible').first().focus();
}, 10);
},
close: function(event, ui) {
$(this).dialog('destroy').remove();
}
};
// open jquery UI dialog
dialog = rcmail.show_popup_dialog(
rcmail.gettext('discardunsavedchanges', 'kolab_notes'),
rcmail.gettext('unsavedchanges', 'kolab_notes'),
buttons,
options
);
return false;
}
if (typeof ok == 'function') {
ok();
}
return true;
}
/**
*
*/
function delete_notes()
{
if (!noteslist.selection.length) {
return false;
}
rcmail.confirm_dialog(rcmail.gettext('kolab_notes.deletenotesconfirm'), 'delete', function() {
var i, rec, id, uids = [];
for (i=0; i < noteslist.selection.length; i++) {
id = noteslist.selection[i];
rec = notesdata[id];
if (rec) {
noteslist.remove_row(id);
uids.push(rec.uid);
delete notesdata[id];
}
}
saving_lock = rcmail.set_busy(true, 'kolab_notes.savingdata');
rcmail.http_post('action', { _data: { uid: uids.join(','), list: me.selected_list }, _do: 'delete' }, true);
reset_view();
update_taglist();
noteslist.clear_selection();
});
}
/**
*
*/
function move_notes(list_id)
{
var rec, id, uids = [];
for (var i=0; i < noteslist.selection.length; i++) {
id = noteslist.selection[i];
rec = notesdata[id];
if (rec) {
noteslist.remove_row(id);
uids.push(rec.uid);
delete notesdata[id];
}
}
if (uids.length) {
saving_lock = rcmail.set_busy(true, 'kolab_notes.savingdata');
rcmail.http_post('action', { _data: { uid: uids.join(','), list: me.selected_list, to: list_id }, _do: 'move' }, true);
}
}
/**
* update browser location to remember current view
*/
function update_state()
{
var query = { _list: me.selected_list }
if (settings.selected_uid) {
query._id = settings.selected_uid;
}
if (window.history.replaceState) {
window.history.replaceState({}, document.title, rcmail.url('', query));
}
}
}
// extend jQuery
// from http://james.padolsey.com/javascript/sorting-elements-with-jquery/
jQuery.fn.sortElements = (function(){
var sort = [].sort;
return function(comparator, getSortable) {
getSortable = getSortable || function(){ return this };
var last = null;
return sort.call(this, comparator).each(function(i){
// at this point the array is sorted, so we can just detach each one from wherever it is, and add it after the last
var node = $(getSortable.call(this));
var parent = node.parent();
if (last) last.after(node);
else parent.prepend(node);
last = node;
});
};
})();
// List options menu for Elastic
function kolab_notes_options_menu()
{
var content = $('#options-menu'),
width = content.width() + 25,
dialog = content.clone(true);
// set form values
$('select[name="sort_col"]', dialog).val(kolabnotes.settings.sort_col || '');
$('select[name="sort_ord"]', dialog).val(kolabnotes.settings.sort_order || 'ASC');
// Fix id/for attributes
$('select', dialog).each(function() { this.id = this.id + '-clone'; });
$('label', dialog).each(function() { $(this).attr('for', $(this).attr('for') + '-clone'); });
var save_func = function(e) {
if (rcube_event.is_keyboard(e.originalEvent)) {
$('#listmenulink').focus();
}
var col = $('select[name="sort_col"]', dialog).val(),
ord = $('select[name="sort_ord"]', dialog).val();
kolabnotes.list_set_sort(col, ord);
return true;
};
dialog = rcmail.simple_dialog(dialog, rcmail.gettext('listoptionstitle'), save_func, {
closeOnEscape: true,
open: function(e) {
setTimeout(function() { dialog.find('select').first().focus(); }, 100);
},
minWidth: 400,
width: width
});
};
/* Notes plugin UI initialization */
var kolabnotes;
window.rcmail && rcmail.addEventListener('init', function(evt) {
if (rcmail.task == 'notes' && rcmail.env.action == 'print') {
rcmail.print_dialog();
return;
}
kolabnotes = new rcube_kolab_notes_ui(rcmail.env.kolab_notes_settings);
if (rcmail.env.action == 'dialog-ui')
kolabnotes.init_dialog();
else
kolabnotes.init();
});