Implement creation and deletion of notes; create icons for Larry theme
This commit is contained in:
parent
aa4d0e2b94
commit
91e3227e64
6 changed files with 133 additions and 37 deletions
|
@ -32,6 +32,7 @@ class kolab_notes extends rcube_plugin
|
||||||
private $ui;
|
private $ui;
|
||||||
private $lists;
|
private $lists;
|
||||||
private $folders;
|
private $folders;
|
||||||
|
private $cache = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Required startup method of a Roundcube plugin
|
* 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()
|
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)
|
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)
|
protected function list_notes($list_id, $search = null)
|
||||||
{
|
{
|
||||||
|
@ -261,6 +262,9 @@ class kolab_notes extends rcube_plugin
|
||||||
return $results;
|
return $results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for delivering a full note record to the client
|
||||||
|
*/
|
||||||
public function note_record()
|
public function note_record()
|
||||||
{
|
{
|
||||||
$data = $this->get_note(array(
|
$data = $this->get_note(array(
|
||||||
|
@ -276,6 +280,9 @@ class kolab_notes extends rcube_plugin
|
||||||
$this->rc->output->command('plugin.render_note', $data);
|
$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)
|
public function get_note($note)
|
||||||
{
|
{
|
||||||
if (is_array($note)) {
|
if (is_array($note)) {
|
||||||
|
@ -286,6 +293,12 @@ class kolab_notes extends rcube_plugin
|
||||||
$uid = $note;
|
$uid = $note;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deliver from in-memory cache
|
||||||
|
$key = $list_id . ':' . $uid;
|
||||||
|
if ($this->cache[$key]) {
|
||||||
|
return $this->cache[$key];
|
||||||
|
}
|
||||||
|
|
||||||
$this->_read_lists();
|
$this->_read_lists();
|
||||||
if ($list_id) {
|
if ($list_id) {
|
||||||
if ($folder = $this->folders[$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)
|
private function _client_encode(&$note)
|
||||||
{
|
{
|
||||||
|
@ -331,6 +344,9 @@ class kolab_notes extends rcube_plugin
|
||||||
return $note;
|
return $note;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for client-initiated actions on a single note record
|
||||||
|
*/
|
||||||
public function note_action()
|
public function note_action()
|
||||||
{
|
{
|
||||||
$action = rcube_utils::get_input_value('_do', RCUBE_INPUT_POST);
|
$action = rcube_utils::get_input_value('_do', RCUBE_INPUT_POST);
|
||||||
|
@ -347,6 +363,17 @@ class kolab_notes extends rcube_plugin
|
||||||
$refresh['tempid'] = $temp_id;
|
$refresh['tempid'] = $temp_id;
|
||||||
}
|
}
|
||||||
break;
|
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
|
// show confirmation/error message
|
||||||
|
@ -354,7 +381,7 @@ class kolab_notes extends rcube_plugin
|
||||||
$this->rc->output->show_message('successfullysaved', 'confirmation');
|
$this->rc->output->show_message('successfullysaved', 'confirmation');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$this->rc->output->show_message('kolab_notes.errorsaving', 'error');
|
$this->rc->output->show_message('errorsaving', 'error');
|
||||||
}
|
}
|
||||||
|
|
||||||
// unlock client
|
// unlock client
|
||||||
|
@ -368,10 +395,10 @@ class kolab_notes extends rcube_plugin
|
||||||
/**
|
/**
|
||||||
* Update an note record with the given data
|
* 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
|
* @return boolean True on success, False on error
|
||||||
*/
|
*/
|
||||||
private function save_note($note)
|
private function save_note(&$note)
|
||||||
{
|
{
|
||||||
$this->_read_lists();
|
$this->_read_lists();
|
||||||
|
|
||||||
|
@ -413,12 +440,33 @@ class kolab_notes extends rcube_plugin
|
||||||
else {
|
else {
|
||||||
$note = $object;
|
$note = $object;
|
||||||
$note['list'] = $list_id;
|
$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;
|
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
|
* 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
|
// clean up HTML content
|
||||||
$object['description'] = $this->_wash_html($note['description']);
|
$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
|
// try to be smart and convert to plain-text if no real formatting is detected
|
||||||
if (preg_match('!<body><pre>(.*)</pre></body>!ims', $object['description'], $m)) {
|
if (preg_match('!<body><pre>(.*)</pre></body>!ims', $object['description'], $m)) {
|
||||||
|
@ -438,9 +487,16 @@ class kolab_notes extends rcube_plugin
|
||||||
// $converter = new rcube_html2text($m[1], false, true, 0);
|
// $converter = new rcube_html2text($m[1], false, true, 0);
|
||||||
// $object['description'] = rtrim($converter->get_text());
|
// $object['description'] = rtrim($converter->get_text());
|
||||||
$object['description'] = preg_replace('!<br(\s+/)>!', "\n", $m[1]);
|
$object['description'] = preg_replace('!<br(\s+/)>!', "\n", $m[1]);
|
||||||
|
$is_html = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add proper HTML header, otherwise Kontact renders it as plain text
|
||||||
|
if ($is_html) {
|
||||||
|
$object['description'] = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">'."\n" .
|
||||||
|
str_replace('<head>', '<head><meta name="qrichtext" content="1" />', $object['description']);
|
||||||
|
}
|
||||||
|
|
||||||
// copy meta data (starting with _) from old object
|
// copy meta data (starting with _) from old object
|
||||||
foreach ((array)$old as $key => $val) {
|
foreach ((array)$old as $key => $val) {
|
||||||
if (!isset($object[$key]) && $key[0] == '_')
|
if (!isset($object[$key]) && $key[0] == '_')
|
||||||
|
@ -461,13 +517,13 @@ class kolab_notes extends rcube_plugin
|
||||||
. '<meta http-equiv="Content-Type" content="text/html; charset='.RCUBE_CHARSET.'" />'
|
. '<meta http-equiv="Content-Type" content="text/html; charset='.RCUBE_CHARSET.'" />'
|
||||||
. '</head><body>' . $html . '</body></html>';
|
. '</head><body>' . $html . '</body></html>';
|
||||||
|
|
||||||
// clean HTML with washhtml by Frederic Motte
|
// clean HTML with washtml by Frederic Motte
|
||||||
$wash_opts = array(
|
$wash_opts = array(
|
||||||
'show_washed' => false,
|
'show_washed' => false,
|
||||||
'allow_remote' => 1,
|
'allow_remote' => 1,
|
||||||
'charset' => RCUBE_CHARSET,
|
'charset' => RCUBE_CHARSET,
|
||||||
'html_elements' => array('html', 'body', 'link'),
|
'html_elements' => array('html', 'head', 'meta', 'body', 'link'),
|
||||||
'html_attribs' => array('rel', 'type'),
|
'html_attribs' => array('rel', 'type', 'name', 'http-equiv'),
|
||||||
);
|
);
|
||||||
|
|
||||||
// initialize HTML washer
|
// initialize HTML washer
|
||||||
|
@ -476,7 +532,7 @@ class kolab_notes extends rcube_plugin
|
||||||
//$washer->add_callback('form', 'rcmail_washtml_callback');
|
//$washer->add_callback('form', 'rcmail_washtml_callback');
|
||||||
//$washer->add_callback('style', '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 = rcube_charset::clean($html);
|
||||||
|
|
||||||
$html = $washer->wash($html);
|
$html = $washer->wash($html);
|
||||||
|
@ -486,6 +542,6 @@ class kolab_notes extends rcube_plugin
|
||||||
|
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ class kolab_notes_ui
|
||||||
|
|
||||||
$settings['editor'] = array(
|
$settings['editor'] = array(
|
||||||
'lang' => $lang,
|
'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')),
|
'spellcheck' => intval($this->rc->config->get('enable_spellcheck')),
|
||||||
'spelldict' => intval($this->rc->config->get('spellcheck_dictionary'))
|
'spelldict' => intval($this->rc->config->get('spellcheck_dictionary'))
|
||||||
);
|
);
|
||||||
|
|
|
@ -15,3 +15,4 @@ $labels['changed'] = 'Last Modified';
|
||||||
$labels['savingdata'] = 'Saving data...';
|
$labels['savingdata'] = 'Saving data...';
|
||||||
$labels['recordnotfound'] = 'Record not found';
|
$labels['recordnotfound'] = 'Record not found';
|
||||||
$labels['entertitle'] = 'Please enter a title for this note!';
|
$labels['entertitle'] = 'Please enter a title for this note!';
|
||||||
|
$labels['deletenotesconfirm'] = 'Do you really want to delete the selected notes?';
|
||||||
|
|
|
@ -43,11 +43,11 @@ function rcube_kolab_notes_ui(settings)
|
||||||
{
|
{
|
||||||
// register button commands
|
// register button commands
|
||||||
rcmail.register_command('createnote', function(){ edit_note(null, 'new'); }, false);
|
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-edit', function(){ list_edit_dialog(me.selected_list); }, false);
|
||||||
rcmail.register_command('list-remove', function(){ list_remove(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('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('search', quicksearch, true);
|
||||||
rcmail.register_command('reset-search', reset_search, true);
|
rcmail.register_command('reset-search', reset_search, true);
|
||||||
|
|
||||||
|
@ -87,6 +87,8 @@ function rcube_kolab_notes_ui(settings)
|
||||||
else {
|
else {
|
||||||
reset_view();
|
reset_view();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rcmail.enable_command('delete', me.notebooks[me.selected_list] && me.notebooks[me.selected_list].editable && list.selection.length > 0);
|
||||||
})
|
})
|
||||||
.init();
|
.init();
|
||||||
}
|
}
|
||||||
|
@ -293,7 +295,7 @@ function rcube_kolab_notes_ui(settings)
|
||||||
tr = noteslist.rows[id].obj;
|
tr = noteslist.rows[id].obj;
|
||||||
note = notesdata[id];
|
note = notesdata[id];
|
||||||
match = note.categories && note.categories.length;
|
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)
|
if ($.inArray(tagsfilter[i], note.categories) < 0)
|
||||||
match = false;
|
match = false;
|
||||||
}
|
}
|
||||||
|
@ -306,7 +308,8 @@ function rcube_kolab_notes_ui(settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (me.selected_note && me.selected_note.uid == note.uid && !match) {
|
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(); });
|
.on('click', function(){ $('.tagline .placeholder').hide(); });
|
||||||
|
|
||||||
me.selected_note = data;
|
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');
|
var html, node, editor = tinyMCE.get('notecontent');
|
||||||
if (editor) {
|
if (editor) {
|
||||||
|
@ -495,12 +499,25 @@ function rcube_kolab_notes_ui(settings)
|
||||||
function update_note(data)
|
function update_note(data)
|
||||||
{
|
{
|
||||||
data.id = rcmail.html_identifier_encode(data.uid);
|
data.id = rcmail.html_identifier_encode(data.uid);
|
||||||
|
|
||||||
|
var row, is_new = notesdata[data.id] == undefined
|
||||||
notesdata[data.id] = data;
|
notesdata[data.id] = data;
|
||||||
render_note(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
|
// update list item
|
||||||
var row = noteslist.rows[data.id];
|
else if (row = noteslist.rows[data.id]) {
|
||||||
if (row) {
|
|
||||||
$('.title', row.obj).html(Q(data.title));
|
$('.title', row.obj).html(Q(data.title));
|
||||||
$('.date', row.obj).html(Q(data.changed || ''));
|
$('.date', row.obj).html(Q(data.changed || ''));
|
||||||
// TODO: move to top
|
// TODO: move to top
|
||||||
|
@ -515,11 +532,10 @@ function rcube_kolab_notes_ui(settings)
|
||||||
function reset_view()
|
function reset_view()
|
||||||
{
|
{
|
||||||
me.selected_note = null;
|
me.selected_note = null;
|
||||||
noteslist.clear_selection();
|
|
||||||
$('.notetitle', rcmail.gui_objects.noteviewtitle).val('');
|
$('.notetitle', rcmail.gui_objects.noteviewtitle).val('');
|
||||||
$('.tagline, .dates', rcmail.gui_objects.noteviewtitle).hide();
|
$('.tagline, .dates', rcmail.gui_objects.noteviewtitle).hide();
|
||||||
$(rcmail.gui_objects.noteseditform).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()
|
function delete_note()
|
||||||
{
|
{
|
||||||
if (!me.selected_note) {
|
if (!noteslist.selection.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
alert(me.selected_note.title)
|
if (confirm(rcmail.gettext('deletenotesconfirm','kolab_notes'))) {
|
||||||
reset_view();
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,18 @@
|
||||||
* See http://creativecommons.org/licenses/by-sa/3.0/ for details.
|
* 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 {
|
.notesview #sidebar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 42px;
|
top: 42px;
|
||||||
|
@ -28,15 +40,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.notesview #notestoolbar a.button.createnote {
|
.notesview #notestoolbar a.button.createnote {
|
||||||
|
background-image: url('sprites.png');
|
||||||
}
|
background-position: center -54px;
|
||||||
|
|
||||||
.notesview #taskbar a.button-notes span.button-inner {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.notesview #taskbar a.button-notes.button-selected span.button-inner {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.notesview #quicksearchbar {
|
.notesview #quicksearchbar {
|
||||||
|
@ -146,7 +151,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.notesview #notedetailstitle {
|
.notesview #notedetailstitle {
|
||||||
height: 68px;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notesview #notedetailstitle .tagedit-list,
|
.notesview #notedetailstitle .tagedit-list,
|
||||||
|
@ -180,7 +185,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.notesview #notedetailstitle .dates {
|
.notesview #notedetailstitle .dates {
|
||||||
margin-top: 0;
|
margin-top: 4px;
|
||||||
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notesview #notedetailstitle .tagline {
|
.notesview #notedetailstitle .tagline {
|
||||||
|
|
BIN
plugins/kolab_notes/skins/larry/sprites.png
Normal file
BIN
plugins/kolab_notes/skins/larry/sprites.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2 KiB |
Loading…
Add table
Reference in a new issue