diff --git a/plugins/kolab_notes/kolab_notes.php b/plugins/kolab_notes/kolab_notes.php
index b92e71be..87a7a7e5 100644
--- a/plugins/kolab_notes/kolab_notes.php
+++ b/plugins/kolab_notes/kolab_notes.php
@@ -32,6 +32,7 @@ class kolab_notes extends rcube_plugin
private $ui;
private $lists;
private $folders;
+ private $cache = array();
/**
* Required startup method of a Roundcube plugin
@@ -202,7 +203,7 @@ class kolab_notes extends rcube_plugin
}
/**
- *
+ * Handler to retrieve note records for the given list and/or search query
*/
public function notes_fetch()
{
@@ -214,7 +215,7 @@ class kolab_notes extends rcube_plugin
}
/**
- *
+ * Convert the given note records for delivery to the client
*/
protected function notes_data($records, &$tags)
{
@@ -234,7 +235,7 @@ class kolab_notes extends rcube_plugin
}
/**
- *
+ * Read note records for the given list from the storage backend
*/
protected function list_notes($list_id, $search = null)
{
@@ -261,6 +262,9 @@ class kolab_notes extends rcube_plugin
return $results;
}
+ /**
+ * Handler for delivering a full note record to the client
+ */
public function note_record()
{
$data = $this->get_note(array(
@@ -276,6 +280,9 @@ class kolab_notes extends rcube_plugin
$this->rc->output->command('plugin.render_note', $data);
}
+ /**
+ * Get the full note record identified by the given UID + Lolder identifier
+ */
public function get_note($note)
{
if (is_array($note)) {
@@ -286,6 +293,12 @@ class kolab_notes extends rcube_plugin
$uid = $note;
}
+ // deliver from in-memory cache
+ $key = $list_id . ':' . $uid;
+ if ($this->cache[$key]) {
+ return $this->cache[$key];
+ }
+
$this->_read_lists();
if ($list_id) {
if ($folder = $this->folders[$list_id]) {
@@ -306,7 +319,7 @@ class kolab_notes extends rcube_plugin
}
/**
- *
+ * Helper method to encode the given note record for use in the client
*/
private function _client_encode(&$note)
{
@@ -331,6 +344,9 @@ class kolab_notes extends rcube_plugin
return $note;
}
+ /**
+ * Handler for client-initiated actions on a single note record
+ */
public function note_action()
{
$action = rcube_utils::get_input_value('_do', RCUBE_INPUT_POST);
@@ -347,6 +363,17 @@ class kolab_notes extends rcube_plugin
$refresh['tempid'] = $temp_id;
}
break;
+
+ case 'delete':
+ $uids = explode(',', $note['uid']);
+ foreach ($uids as $uid) {
+ $note['uid'] = $uid;
+ if (!($success = $this->delete_note($note))) {
+ $refresh = $this->get_note($note);
+ break;
+ }
+ }
+ break;
}
// show confirmation/error message
@@ -354,7 +381,7 @@ class kolab_notes extends rcube_plugin
$this->rc->output->show_message('successfullysaved', 'confirmation');
}
else {
- $this->rc->output->show_message('kolab_notes.errorsaving', 'error');
+ $this->rc->output->show_message('errorsaving', 'error');
}
// unlock client
@@ -368,10 +395,10 @@ class kolab_notes extends rcube_plugin
/**
* Update an note record with the given data
*
- * @param array Hash array with note properties
+ * @param array Hash array with note properties (id, list)
* @return boolean True on success, False on error
*/
- private function save_note($note)
+ private function save_note(&$note)
{
$this->_read_lists();
@@ -413,12 +440,33 @@ class kolab_notes extends rcube_plugin
else {
$note = $object;
$note['list'] = $list_id;
- // TODO: cache this in memory for later read
+
+ // cache this in memory for later read
+ $key = $list_id . ':' . $note['uid'];
+ $this->cache[$key] = $note;
}
return $saved;
}
+ /**
+ * Remove a single note record from the backend
+ *
+ * @param array Hash array with note properties (id, list)
+ * @param boolean Remove record irreversible (mark as deleted otherwise)
+ * @return boolean True on success, False on error
+ */
+ public function delete_note($note, $force = true)
+ {
+ $this->_read_lists();
+
+ $list_id = $note['list'];
+ if (!$list_id || !($folder = $this->folders[$list_id]))
+ return false;
+
+ return $folder->delete($note['uid'], $force);
+ }
+
/**
* Process the given note data (submitted by the client) before saving it
@@ -431,6 +479,7 @@ class kolab_notes extends rcube_plugin
// clean up HTML content
$object['description'] = $this->_wash_html($note['description']);
+ $is_html = true;
// try to be smart and convert to plain-text if no real formatting is detected
if (preg_match('!
(.*)
!ims', $object['description'], $m)) {
@@ -438,9 +487,16 @@ class kolab_notes extends rcube_plugin
// $converter = new rcube_html2text($m[1], false, true, 0);
// $object['description'] = rtrim($converter->get_text());
$object['description'] = preg_replace('!
!', "\n", $m[1]);
+ $is_html = false;
}
}
+ // Add proper HTML header, otherwise Kontact renders it as plain text
+ if ($is_html) {
+ $object['description'] = ''."\n" .
+ str_replace('', '', $object['description']);
+ }
+
// copy meta data (starting with _) from old object
foreach ((array)$old as $key => $val) {
if (!isset($object[$key]) && $key[0] == '_')
@@ -461,13 +517,13 @@ class kolab_notes extends rcube_plugin
. ''
. '' . $html . '';
- // clean HTML with washhtml by Frederic Motte
+ // clean HTML with washtml by Frederic Motte
$wash_opts = array(
'show_washed' => false,
'allow_remote' => 1,
'charset' => RCUBE_CHARSET,
- 'html_elements' => array('html', 'body', 'link'),
- 'html_attribs' => array('rel', 'type'),
+ 'html_elements' => array('html', 'head', 'meta', 'body', 'link'),
+ 'html_attribs' => array('rel', 'type', 'name', 'http-equiv'),
);
// initialize HTML washer
@@ -476,7 +532,7 @@ class kolab_notes extends rcube_plugin
//$washer->add_callback('form', 'rcmail_washtml_callback');
//$washer->add_callback('style', 'rcmail_washtml_callback');
- // Remove non-UTF8 characters (#1487813)
+ // Remove non-UTF8 characters
$html = rcube_charset::clean($html);
$html = $washer->wash($html);
@@ -486,6 +542,6 @@ class kolab_notes extends rcube_plugin
return $html;
}
-
+
}
diff --git a/plugins/kolab_notes/kolab_notes_ui.php b/plugins/kolab_notes/kolab_notes_ui.php
index 264288d4..f3821400 100644
--- a/plugins/kolab_notes/kolab_notes_ui.php
+++ b/plugins/kolab_notes/kolab_notes_ui.php
@@ -67,7 +67,7 @@ class kolab_notes_ui
$settings['editor'] = array(
'lang' => $lang,
- 'editor_css' => $this->plugin->url() . $this->plugin->local_skin_path() . '/editor.css',
+ 'editor_css' => $this->plugin->url($this->plugin->local_skin_path() . '/editor.css'),
'spellcheck' => intval($this->rc->config->get('enable_spellcheck')),
'spelldict' => intval($this->rc->config->get('spellcheck_dictionary'))
);
diff --git a/plugins/kolab_notes/localization/en_US.inc b/plugins/kolab_notes/localization/en_US.inc
index 131c6c60..4301d1a7 100644
--- a/plugins/kolab_notes/localization/en_US.inc
+++ b/plugins/kolab_notes/localization/en_US.inc
@@ -15,3 +15,4 @@ $labels['changed'] = 'Last Modified';
$labels['savingdata'] = 'Saving data...';
$labels['recordnotfound'] = 'Record not found';
$labels['entertitle'] = 'Please enter a title for this note!';
+$labels['deletenotesconfirm'] = 'Do you really want to delete the selected notes?';
diff --git a/plugins/kolab_notes/notes.js b/plugins/kolab_notes/notes.js
index d2b9319d..ff3aef88 100644
--- a/plugins/kolab_notes/notes.js
+++ b/plugins/kolab_notes/notes.js
@@ -43,11 +43,11 @@ function rcube_kolab_notes_ui(settings)
{
// register button commands
rcmail.register_command('createnote', function(){ edit_note(null, 'new'); }, false);
- rcmail.register_command('list-create', function(){ list_edit_dialog(null); }, true);
+ rcmail.register_command('list-create', function(){ list_edit_dialog(null); }, false);
rcmail.register_command('list-edit', function(){ list_edit_dialog(me.selected_list); }, false);
rcmail.register_command('list-remove', function(){ list_remove(me.selected_list); }, false);
rcmail.register_command('save', save_note, true);
- rcmail.register_command('delete', delete_note, true);
+ rcmail.register_command('delete', delete_note, false);
rcmail.register_command('search', quicksearch, true);
rcmail.register_command('reset-search', reset_search, true);
@@ -87,6 +87,8 @@ function rcube_kolab_notes_ui(settings)
else {
reset_view();
}
+
+ rcmail.enable_command('delete', me.notebooks[me.selected_list] && me.notebooks[me.selected_list].editable && list.selection.length > 0);
})
.init();
}
@@ -293,7 +295,7 @@ function rcube_kolab_notes_ui(settings)
tr = noteslist.rows[id].obj;
note = notesdata[id];
match = note.categories && note.categories.length;
- for (var i=0; match && i < tagsfilter.length; i++) {
+ for (var i=0; match && note && i < tagsfilter.length; i++) {
if ($.inArray(tagsfilter[i], note.categories) < 0)
match = false;
}
@@ -306,7 +308,8 @@ function rcube_kolab_notes_ui(settings)
}
if (me.selected_note && me.selected_note.uid == note.uid && !match) {
- reset_view();
+ noteslist.clear_selection();
+// reset_view();
}
}
}
@@ -389,7 +392,8 @@ function rcube_kolab_notes_ui(settings)
.on('click', function(){ $('.tagline .placeholder').hide(); });
me.selected_note = data;
- rcmail.enable_command('save', 'delete', list.editable && !data.readonly);
+ me.selected_note.id = rcmail.html_identifier_encode(data.uid);
+ rcmail.enable_command('save', list.editable && !data.readonly);
var html, node, editor = tinyMCE.get('notecontent');
if (editor) {
@@ -495,12 +499,25 @@ function rcube_kolab_notes_ui(settings)
function update_note(data)
{
data.id = rcmail.html_identifier_encode(data.uid);
+
+ var row, is_new = notesdata[data.id] == undefined
notesdata[data.id] = data;
render_note(data);
+ // 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
- var row = noteslist.rows[data.id];
- if (row) {
+ else if (row = noteslist.rows[data.id]) {
$('.title', row.obj).html(Q(data.title));
$('.date', row.obj).html(Q(data.changed || ''));
// TODO: move to top
@@ -515,11 +532,10 @@ function rcube_kolab_notes_ui(settings)
function reset_view()
{
me.selected_note = null;
- noteslist.clear_selection();
$('.notetitle', rcmail.gui_objects.noteviewtitle).val('');
$('.tagline, .dates', rcmail.gui_objects.noteviewtitle).hide();
$(rcmail.gui_objects.noteseditform).hide();
- rcmail.enable_command('save', 'delete', false);
+ rcmail.enable_command('save', false);
}
/**
@@ -564,12 +580,29 @@ function rcube_kolab_notes_ui(settings)
function delete_note()
{
- if (!me.selected_note) {
+ if (!noteslist.selection.length) {
return false;
}
- alert(me.selected_note.title)
- reset_view();
+ if (confirm(rcmail.gettext('deletenotesconfirm','kolab_notes'))) {
+ 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];
+ }
+ }
+
+ 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_tagcloud();
+ }
+
}
}
diff --git a/plugins/kolab_notes/skins/larry/notes.css b/plugins/kolab_notes/skins/larry/notes.css
index a3ba1589..747e0d19 100644
--- a/plugins/kolab_notes/skins/larry/notes.css
+++ b/plugins/kolab_notes/skins/larry/notes.css
@@ -10,6 +10,18 @@
* See http://creativecommons.org/licenses/by-sa/3.0/ for details.
*/
+
+#taskbar a.button-notes span.button-inner {
+ background-image: url('sprites.png');
+ background-position: 0 0;
+}
+
+#taskbar a.button-notes:hover span.button-inner,
+#taskbar a.button-notes.button-selected span.button-inner {
+ background-image: url('sprites.png');
+ background-position: 0 -26px;
+}
+
.notesview #sidebar {
position: absolute;
top: 42px;
@@ -28,15 +40,8 @@
}
.notesview #notestoolbar a.button.createnote {
-
-}
-
-.notesview #taskbar a.button-notes span.button-inner {
-
-}
-
-.notesview #taskbar a.button-notes.button-selected span.button-inner {
-
+ background-image: url('sprites.png');
+ background-position: center -54px;
}
.notesview #quicksearchbar {
@@ -146,7 +151,7 @@
}
.notesview #notedetailstitle {
- height: 68px;
+ height: auto;
}
.notesview #notedetailstitle .tagedit-list,
@@ -180,7 +185,8 @@
}
.notesview #notedetailstitle .dates {
- margin-top: 0;
+ margin-top: 4px;
+ margin-bottom: 4px;
}
.notesview #notedetailstitle .tagline {
diff --git a/plugins/kolab_notes/skins/larry/sprites.png b/plugins/kolab_notes/skins/larry/sprites.png
new file mode 100644
index 00000000..cee37c3f
Binary files /dev/null and b/plugins/kolab_notes/skins/larry/sprites.png differ