Use tinyMCE editor for notes contents; implement data saving and tags listing/filtering
This commit is contained in:
parent
27a669a195
commit
aa4d0e2b94
5 changed files with 455 additions and 27 deletions
|
@ -210,7 +210,7 @@ class kolab_notes extends rcube_plugin
|
||||||
$list = rcube_utils::get_input_value('_list', RCUBE_INPUT_GPC);
|
$list = rcube_utils::get_input_value('_list', RCUBE_INPUT_GPC);
|
||||||
|
|
||||||
$data = $this->notes_data($this->list_notes($list, $search), $tags);
|
$data = $this->notes_data($this->list_notes($list, $search), $tags);
|
||||||
$this->rc->output->command('plugin.data_ready', array('list' => $list, 'search' => $search, 'data' => $data, 'tags' => array_values(array_unique($tags))));
|
$this->rc->output->command('plugin.data_ready', array('list' => $list, 'search' => $search, 'data' => $data, 'tags' => array_values($tags)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -221,10 +221,10 @@ class kolab_notes extends rcube_plugin
|
||||||
$tags = array();
|
$tags = array();
|
||||||
|
|
||||||
foreach ($records as $i => $rec) {
|
foreach ($records as $i => $rec) {
|
||||||
$this->_client_encode($records[$i]);
|
|
||||||
unset($records[$i]['description']);
|
unset($records[$i]['description']);
|
||||||
|
$this->_client_encode($records[$i]);
|
||||||
|
|
||||||
foreach ((array)$reg['categories'] as $tag) {
|
foreach ((array)$rec['categories'] as $tag) {
|
||||||
$tags[] = $tag;
|
$tags[] = $tag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -311,7 +311,7 @@ class kolab_notes extends rcube_plugin
|
||||||
private function _client_encode(&$note)
|
private function _client_encode(&$note)
|
||||||
{
|
{
|
||||||
foreach ($note as $key => $prop) {
|
foreach ($note as $key => $prop) {
|
||||||
if ($key[0] == '_') {
|
if ($key[0] == '_' || $key == 'x-custom') {
|
||||||
unset($note[$key]);
|
unset($note[$key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -323,6 +323,11 @@ class kolab_notes extends rcube_plugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clean HTML contents
|
||||||
|
if (!empty($note['description']) && preg_match('/<(html|body|div|p|span)(\s+[a-z]|>)/', $note['description'])) {
|
||||||
|
$note['html'] = $this->_wash_html($note['description']);
|
||||||
|
}
|
||||||
|
|
||||||
return $note;
|
return $note;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,12 +336,16 @@ class kolab_notes extends rcube_plugin
|
||||||
$action = rcube_utils::get_input_value('_do', RCUBE_INPUT_POST);
|
$action = rcube_utils::get_input_value('_do', RCUBE_INPUT_POST);
|
||||||
$note = rcube_utils::get_input_value('_data', RCUBE_INPUT_POST, true);
|
$note = rcube_utils::get_input_value('_data', RCUBE_INPUT_POST, true);
|
||||||
|
|
||||||
$success =false;
|
$success = false;
|
||||||
switch ($action) {
|
switch ($action) {
|
||||||
case 'save':
|
case 'new':
|
||||||
console($action, $note);
|
$temp_id = $rec['tempid'];
|
||||||
sleep(3);
|
|
||||||
$success = true;
|
case 'edit':
|
||||||
|
if ($success = $this->save_note($note)) {
|
||||||
|
$refresh = $this->get_note($note);
|
||||||
|
$refresh['tempid'] = $temp_id;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,8 +359,133 @@ class kolab_notes extends rcube_plugin
|
||||||
|
|
||||||
// unlock client
|
// unlock client
|
||||||
$this->rc->output->command('plugin.unlock_saving');
|
$this->rc->output->command('plugin.unlock_saving');
|
||||||
// $this->rc->output->command('plugin.update_note', $note);
|
|
||||||
|
if ($refresh) {
|
||||||
|
$this->rc->output->command('plugin.update_note', $this->_client_encode($refresh));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an note record with the given data
|
||||||
|
*
|
||||||
|
* @param array Hash array with note properties
|
||||||
|
* @return boolean True on success, False on error
|
||||||
|
*/
|
||||||
|
private function save_note($note)
|
||||||
|
{
|
||||||
|
$this->_read_lists();
|
||||||
|
|
||||||
|
$list_id = $note['list'];
|
||||||
|
if (!$list_id || !($folder = $this->folders[$list_id]))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// moved from another folder
|
||||||
|
if ($note['_fromlist'] && ($fromfolder = $this->folders[$note['_fromlist']])) {
|
||||||
|
if (!$fromfolder->move($note['id'], $folder->name))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
unset($note['_fromlist']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// load previous version of this record to merge
|
||||||
|
if ($note['uid']) {
|
||||||
|
$old = $folder->get_object($note['uid']);
|
||||||
|
if (!$old || PEAR::isError($old))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// merge existing properties if the update isn't complete
|
||||||
|
if (!isset($note['title']) || !isset($note['description']))
|
||||||
|
$note += $old;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate new note object from input
|
||||||
|
$object = $this->_write_preprocess($note, $old);
|
||||||
|
$saved = $folder->save($object, 'note', $note['uid']);
|
||||||
|
|
||||||
|
if (!$saved) {
|
||||||
|
raise_error(array(
|
||||||
|
'code' => 600, 'type' => 'php',
|
||||||
|
'file' => __FILE__, 'line' => __LINE__,
|
||||||
|
'message' => "Error saving note object to Kolab server"),
|
||||||
|
true, false);
|
||||||
|
$saved = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$note = $object;
|
||||||
|
$note['list'] = $list_id;
|
||||||
|
// TODO: cache this in memory for later read
|
||||||
|
}
|
||||||
|
|
||||||
|
return $saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the given note data (submitted by the client) before saving it
|
||||||
|
*/
|
||||||
|
private function _write_preprocess($note, $old = array())
|
||||||
|
{
|
||||||
|
$object = $note;
|
||||||
|
|
||||||
|
// TODO: handle attachments
|
||||||
|
|
||||||
|
// clean up HTML content
|
||||||
|
$object['description'] = $this->_wash_html($note['description']);
|
||||||
|
|
||||||
|
// 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('!<(a|b|i|strong|em|p|span|div|pre|li)(\s+[a-z]|>)!im', $m[1])) {
|
||||||
|
// $converter = new rcube_html2text($m[1], false, true, 0);
|
||||||
|
// $object['description'] = rtrim($converter->get_text());
|
||||||
|
$object['description'] = preg_replace('!<br(\s+/)>!', "\n", $m[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy meta data (starting with _) from old object
|
||||||
|
foreach ((array)$old as $key => $val) {
|
||||||
|
if (!isset($object[$key]) && $key[0] == '_')
|
||||||
|
$object[$key] = $val;
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($object['list'], $object['tempid'], $object['created'], $object['changed'], $object['created_'], $object['changed_']);
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanity checks/cleanups HTML content
|
||||||
|
*/
|
||||||
|
private function _wash_html($html)
|
||||||
|
{
|
||||||
|
// Add header with charset spec., washtml cannot work without that
|
||||||
|
$html = '<html><head>'
|
||||||
|
. '<meta http-equiv="Content-Type" content="text/html; charset='.RCUBE_CHARSET.'" />'
|
||||||
|
. '</head><body>' . $html . '</body></html>';
|
||||||
|
|
||||||
|
// clean HTML with washhtml 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'),
|
||||||
|
);
|
||||||
|
|
||||||
|
// initialize HTML washer
|
||||||
|
$washer = new rcube_washtml($wash_opts);
|
||||||
|
|
||||||
|
//$washer->add_callback('form', 'rcmail_washtml_callback');
|
||||||
|
//$washer->add_callback('style', 'rcmail_washtml_callback');
|
||||||
|
|
||||||
|
// Remove non-UTF8 characters (#1487813)
|
||||||
|
$html = rcube_charset::clean($html);
|
||||||
|
|
||||||
|
$html = $washer->wash($html);
|
||||||
|
|
||||||
|
// remove unwanted comments (produced by washtml)
|
||||||
|
$html = preg_replace('/<!--[^>]+-->/', '', $html);
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,22 @@ class kolab_notes_ui
|
||||||
|
|
||||||
// TODO: load config options and user prefs relevant for the UI
|
// TODO: load config options and user prefs relevant for the UI
|
||||||
$settings = array();
|
$settings = array();
|
||||||
|
|
||||||
|
// TinyMCE uses two-letter lang codes, with exception of Chinese
|
||||||
|
$lang = strtolower($_SESSION['language']);
|
||||||
|
$lang = strpos($lang, 'zh_') === 0 ? str_replace('_', '-', $lang) : substr($lang, 0, 2);
|
||||||
|
|
||||||
|
if (!file_exists(INSTALL_PATH . 'program/js/tiny_mce/langs/'.$lang.'.js')) {
|
||||||
|
$lang = 'en';
|
||||||
|
}
|
||||||
|
|
||||||
|
$settings['editor'] = array(
|
||||||
|
'lang' => $lang,
|
||||||
|
'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'))
|
||||||
|
);
|
||||||
|
|
||||||
$this->rc->output->set_env('kolab_notes_settings', $settings);
|
$this->rc->output->set_env('kolab_notes_settings', $settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +127,9 @@ class kolab_notes_ui
|
||||||
public function editform($attrib)
|
public function editform($attrib)
|
||||||
{
|
{
|
||||||
$attrib += array('action' => '#', 'id' => 'rcmkolabnoteseditform');
|
$attrib += array('action' => '#', 'id' => 'rcmkolabnoteseditform');
|
||||||
|
|
||||||
$this->rc->output->add_gui_object('noteseditform', $attrib['id']);
|
$this->rc->output->add_gui_object('noteseditform', $attrib['id']);
|
||||||
|
$this->rc->output->include_script('tiny_mce/tiny_mce.js');
|
||||||
|
|
||||||
$textarea = new html_textarea(array('name' => 'content', 'id' => 'notecontent', 'cols' => 60, 'rows' => 20, 'tabindex' => 3));
|
$textarea = new html_textarea(array('name' => 'content', 'id' => 'notecontent', 'cols' => 60, 'rows' => 20, 'tabindex' => 3));
|
||||||
return html::tag('form', $attrib, $textarea->show(), array_merge(html::$common_attrib, array('action')));
|
return html::tag('form', $attrib, $textarea->show(), array_merge(html::$common_attrib, array('action')));
|
||||||
|
|
|
@ -27,6 +27,7 @@ function rcube_kolab_notes_ui(settings)
|
||||||
var search_query;
|
var search_query;
|
||||||
var noteslist;
|
var noteslist;
|
||||||
var notesdata = {};
|
var notesdata = {};
|
||||||
|
var tagsfilter = [];
|
||||||
var tags = [];
|
var tags = [];
|
||||||
var me = this;
|
var me = this;
|
||||||
|
|
||||||
|
@ -46,12 +47,14 @@ function rcube_kolab_notes_ui(settings)
|
||||||
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('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);
|
||||||
|
|
||||||
// register server callbacks
|
// register server callbacks
|
||||||
rcmail.addEventListener('plugin.data_ready', data_ready);
|
rcmail.addEventListener('plugin.data_ready', data_ready);
|
||||||
rcmail.addEventListener('plugin.render_note', render_note);
|
rcmail.addEventListener('plugin.render_note', render_note);
|
||||||
|
rcmail.addEventListener('plugin.update_note', update_note);
|
||||||
rcmail.addEventListener('plugin.unlock_saving', function(){
|
rcmail.addEventListener('plugin.unlock_saving', function(){
|
||||||
if (saving_lock) {
|
if (saving_lock) {
|
||||||
rcmail.set_busy(false, null, saving_lock);
|
rcmail.set_busy(false, null, saving_lock);
|
||||||
|
@ -78,6 +81,7 @@ function rcube_kolab_notes_ui(settings)
|
||||||
noteslist.addEventListener('select', function(list) {
|
noteslist.addEventListener('select', function(list) {
|
||||||
var note;
|
var note;
|
||||||
if (list.selection.length == 1 && (note = notesdata[list.selection[0]])) {
|
if (list.selection.length == 1 && (note = notesdata[list.selection[0]])) {
|
||||||
|
// TODO: check for unsaved changes and warn
|
||||||
edit_note(note.uid, 'edit');
|
edit_note(note.uid, 'edit');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -87,6 +91,90 @@ function rcube_kolab_notes_ui(settings)
|
||||||
.init();
|
.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// click-handler on tags list
|
||||||
|
$(rcmail.gui_objects.notestagslist).on('click', function(e){
|
||||||
|
var item = e.target.nodeName == 'LI' ? $(e.target) : $(e.target).closest('li'),
|
||||||
|
tag = item.data('value');
|
||||||
|
|
||||||
|
if (!tag)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// reset selection on regular clicks
|
||||||
|
var index = $.inArray(tag, tagsfilter);
|
||||||
|
var shift = e.shiftKey || e.ctrlKey || e.metaKey;
|
||||||
|
|
||||||
|
if (!shift) {
|
||||||
|
if (tagsfilter.length > 1)
|
||||||
|
index = -1;
|
||||||
|
|
||||||
|
$('li', this).removeClass('selected');
|
||||||
|
tagsfilter = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// add tag to filter
|
||||||
|
if (index < 0) {
|
||||||
|
item.addClass('selected');
|
||||||
|
tagsfilter.push(tag);
|
||||||
|
}
|
||||||
|
else if (shift) {
|
||||||
|
item.removeClass('selected');
|
||||||
|
var a = tagsfilter.slice(0,index);
|
||||||
|
tagsfilter = a.concat(tagsfilter.slice(index+1));
|
||||||
|
}
|
||||||
|
|
||||||
|
filter_notes();
|
||||||
|
|
||||||
|
// clear text selection in IE after shift+click
|
||||||
|
if (shift && document.selection)
|
||||||
|
document.selection.empty();
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
.mousedown(function(e){
|
||||||
|
// disable content selection with the mouse
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// initialize tinyMCE editor
|
||||||
|
var editor_conf = {
|
||||||
|
mode: 'textareas',
|
||||||
|
elements: 'notecontent',
|
||||||
|
apply_source_formatting: true,
|
||||||
|
theme: 'advanced',
|
||||||
|
language: settings.editor.lang,
|
||||||
|
content_css: settings.editor.editor_css,
|
||||||
|
theme_advanced_toolbar_location: 'top',
|
||||||
|
theme_advanced_toolbar_align: 'left',
|
||||||
|
theme_advanced_buttons3: '',
|
||||||
|
theme_advanced_statusbar_location: 'none',
|
||||||
|
// extended_valid_elements: 'font[face|size|color|style],span[id|class|align|style]',
|
||||||
|
relative_urls: false,
|
||||||
|
remove_script_host: false,
|
||||||
|
gecko_spellcheck: true,
|
||||||
|
convert_urls: false,
|
||||||
|
paste_data_images: true,
|
||||||
|
plugins: 'paste,tabfocus,searchreplace,table,inlinepopups',
|
||||||
|
theme_advanced_buttons1: 'bold,italic,underline,|,justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,outdent,indent,blockquote,|,forecolor,backcolor,fontselect,fontsizeselect',
|
||||||
|
theme_advanced_buttons2: 'link,unlink,table,charmap,|,search,code,|,undo,redo',
|
||||||
|
setup: function(ed) {
|
||||||
|
// make links open on shift-click
|
||||||
|
ed.onClick.add(function(ed, e) {
|
||||||
|
var link = $(e.target).closest('a');
|
||||||
|
if (link.length && e.shiftKey) {
|
||||||
|
window.open(link.get(0).href, '_blank');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// support external configuration settings e.g. from skin
|
||||||
|
if (window.rcmail_editor_settings)
|
||||||
|
$.extend(editor_conf, window.rcmail_editor_settings);
|
||||||
|
|
||||||
|
tinyMCE.init(editor_conf);
|
||||||
|
|
||||||
if (me.selected_list) {
|
if (me.selected_list) {
|
||||||
rcmail.enable_command('createnote', true);
|
rcmail.enable_command('createnote', true);
|
||||||
$('#rcmliknb'+me.selected_list).click();
|
$('#rcmliknb'+me.selected_list).click();
|
||||||
|
@ -194,6 +282,33 @@ function rcube_kolab_notes_ui(settings)
|
||||||
reset_view();
|
reset_view();
|
||||||
noteslist.clear();
|
noteslist.clear();
|
||||||
notesdata = {};
|
notesdata = {};
|
||||||
|
tagsfilter = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function filter_notes()
|
||||||
|
{
|
||||||
|
// tagsfilter
|
||||||
|
var note, tr, match;
|
||||||
|
for (var id in noteslist.rows) {
|
||||||
|
tr = noteslist.rows[id].obj;
|
||||||
|
note = notesdata[id];
|
||||||
|
match = note.categories && note.categories.length;
|
||||||
|
for (var i=0; match && i < tagsfilter.length; i++) {
|
||||||
|
if ($.inArray(tagsfilter[i], note.categories) < 0)
|
||||||
|
match = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match || !tagsfilter.length) {
|
||||||
|
$(tr).show();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$(tr).hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (me.selected_note && me.selected_note.uid == note.uid && !match) {
|
||||||
|
reset_view();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -220,7 +335,7 @@ function rcube_kolab_notes_ui(settings)
|
||||||
notesdata[rec.id] = rec;
|
notesdata[rec.id] = rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
tags = data.tags || [];
|
render_tagslist(data.tags || [], true)
|
||||||
rcmail.set_busy(false, 'loading', ui_loading);
|
rcmail.set_busy(false, 'loading', ui_loading);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,13 +351,14 @@ function rcube_kolab_notes_ui(settings)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var list = me.notebooks[data.list] || me.notebooks[me.selected_list]
|
var list = me.notebooks[data.list] || me.notebooks[me.selected_list];
|
||||||
var title = $('.notetitle', rcmail.gui_objects.noteviewtitle).val(data.title);
|
content = $('#notecontent').val(data.description);
|
||||||
var content = $('#notecontent').val(data.description);
|
$('.notetitle', rcmail.gui_objects.noteviewtitle).val(data.title);
|
||||||
$('.dates .notecreated', rcmail.gui_objects.noteviewtitle).html(Q(data.created || ''));
|
$('.dates .notecreated', rcmail.gui_objects.noteviewtitle).html(Q(data.created || ''));
|
||||||
$('.dates .notechanged', rcmail.gui_objects.noteviewtitle).html(Q(data.changed || ''));
|
$('.dates .notechanged', rcmail.gui_objects.noteviewtitle).html(Q(data.changed || ''));
|
||||||
if (data.created || data.changed)
|
if (data.created || data.changed) {
|
||||||
$('.dates', rcmail.gui_objects.noteviewtitle).show();
|
$('.dates', rcmail.gui_objects.noteviewtitle).show();
|
||||||
|
}
|
||||||
|
|
||||||
$(rcmail.gui_objects.noteseditform).show();
|
$(rcmail.gui_objects.noteseditform).show();
|
||||||
|
|
||||||
|
@ -265,7 +381,7 @@ function rcube_kolab_notes_ui(settings)
|
||||||
animSpeed: 100,
|
animSpeed: 100,
|
||||||
allowEdit: false,
|
allowEdit: false,
|
||||||
checkNewEntriesCaseSensitive: false,
|
checkNewEntriesCaseSensitive: false,
|
||||||
autocompleteOptions: { source: tags, minLength: 0 },
|
autocompleteOptions: { source: tags, minLength: 0, noCheck: true },
|
||||||
texts: { removeLinkTitle: rcmail.gettext('removetag', 'kolab_notes') }
|
texts: { removeLinkTitle: rcmail.gettext('removetag', 'kolab_notes') }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -273,8 +389,124 @@ 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', list.editable && !data.readonly);
|
rcmail.enable_command('save', 'delete', list.editable && !data.readonly);
|
||||||
content.select();
|
|
||||||
|
var html, node, editor = tinyMCE.get('notecontent');
|
||||||
|
if (editor) {
|
||||||
|
html = data.html || data.description;
|
||||||
|
if (!html.match(/<(html|body|p|div|span)/))
|
||||||
|
html = '<pre>' + Q(html) + '</pre>';
|
||||||
|
|
||||||
|
editor.setContent(html);
|
||||||
|
node = editor.getContentAreaContainer().childNodes[0];
|
||||||
|
if (node) node.tabIndex = content.get(0).tabIndex;
|
||||||
|
editor.getBody().focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger resize (needed for proper editor resizing)
|
||||||
|
$(window).resize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function render_tagslist(newtags, replace)
|
||||||
|
{
|
||||||
|
if (replace) {
|
||||||
|
tags = newtags;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var append = [];
|
||||||
|
for (var i=0; i < newtags.length; i++) {
|
||||||
|
if ($.inArray(newtags[i], tags) < 0)
|
||||||
|
append.push(newtags[i]);
|
||||||
|
}
|
||||||
|
if (!append.length) {
|
||||||
|
update_tagcloud();
|
||||||
|
return; // nothing to be added
|
||||||
|
}
|
||||||
|
tags = tags.concat(append);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort tags first
|
||||||
|
tags.sort(function(a,b){
|
||||||
|
return a.toLowerCase() > b.toLowerCase() ? 1 : -1;
|
||||||
|
})
|
||||||
|
|
||||||
|
var widget = $(rcmail.gui_objects.notestagslist).html('');
|
||||||
|
|
||||||
|
// append tags to tag cloud
|
||||||
|
$.each(tags, function(i, tag){
|
||||||
|
li = $('<li>').attr('rel', tag).data('value', tag)
|
||||||
|
.html(Q(tag) + '<span class="count"></span>')
|
||||||
|
.appendTo(widget)
|
||||||
|
/*
|
||||||
|
.draggable({
|
||||||
|
addClasses: false,
|
||||||
|
revert: 'invalid',
|
||||||
|
revertDuration: 300,
|
||||||
|
helper: tag_draggable_helper,
|
||||||
|
start: tag_draggable_start,
|
||||||
|
appendTo: 'body',
|
||||||
|
cursor: 'pointer'
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
});
|
||||||
|
|
||||||
|
update_tagcloud();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the given counts to each tag and set those inactive which don't
|
||||||
|
* have any matching records in the current view.
|
||||||
|
*/
|
||||||
|
function update_tagcloud(counts)
|
||||||
|
{
|
||||||
|
// compute counts first by iterating over all visible task items
|
||||||
|
if (typeof counts == 'undefined') {
|
||||||
|
counts = {};
|
||||||
|
$.each(notesdata, function(id, rec){
|
||||||
|
for (var t, j=0; rec && rec.categories && j < rec.categories.length; j++) {
|
||||||
|
t = rec.categories[j];
|
||||||
|
if (typeof counts[t] == 'undefined')
|
||||||
|
counts[t] = 0;
|
||||||
|
counts[t]++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(rcmail.gui_objects.notestagslist).children('li').each(function(i,li){
|
||||||
|
var elem = $(li), tag = elem.attr('rel'),
|
||||||
|
count = counts[tag] || 0;
|
||||||
|
|
||||||
|
elem.children('.count').html(count+'');
|
||||||
|
if (count == 0) elem.addClass('inactive');
|
||||||
|
else elem.removeClass('inactive');
|
||||||
|
|
||||||
|
if (tagsfilter && tagsfilter.length && $.inArray(tag, tagsfilter)) {
|
||||||
|
elem.addClass('selected');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback from server after saving a note record
|
||||||
|
*/
|
||||||
|
function update_note(data)
|
||||||
|
{
|
||||||
|
data.id = rcmail.html_identifier_encode(data.uid);
|
||||||
|
notesdata[data.id] = data;
|
||||||
|
render_note(data);
|
||||||
|
|
||||||
|
// update list item
|
||||||
|
var row = noteslist.rows[data.id];
|
||||||
|
if (row) {
|
||||||
|
$('.title', row.obj).html(Q(data.title));
|
||||||
|
$('.date', row.obj).html(Q(data.changed || ''));
|
||||||
|
// TODO: move to top
|
||||||
|
}
|
||||||
|
|
||||||
|
render_tagslist(data.categories || []);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -283,10 +515,11 @@ 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', false);
|
rcmail.enable_command('save', 'delete', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -298,9 +531,10 @@ function rcube_kolab_notes_ui(settings)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var editor = tinyMCE.get('notecontent');
|
||||||
var savedata = {
|
var savedata = {
|
||||||
title: trim($('.notetitle', rcmail.gui_objects.noteviewtitle).val()),
|
title: trim($('.notetitle', rcmail.gui_objects.noteviewtitle).val()),
|
||||||
description: $('#notecontent').val(),
|
description: editor ? editor.getContent({ format:'html' }) : $('#notecontent').val(),
|
||||||
list: me.selected_note.list || me.selected_list,
|
list: me.selected_note.list || me.selected_list,
|
||||||
uid: me.selected_note.uid,
|
uid: me.selected_note.uid,
|
||||||
categories: []
|
categories: []
|
||||||
|
@ -325,8 +559,19 @@ function rcube_kolab_notes_ui(settings)
|
||||||
|
|
||||||
rcmail.lock_form(rcmail.gui_objects.noteseditform, true);
|
rcmail.lock_form(rcmail.gui_objects.noteseditform, true);
|
||||||
saving_lock = rcmail.set_busy(true, 'kolab_notes.savingdata');
|
saving_lock = rcmail.set_busy(true, 'kolab_notes.savingdata');
|
||||||
rcmail.http_post('action', { _data: savedata, _do:'save' }, true);
|
rcmail.http_post('action', { _data: savedata, _do: savedata.uid?'edit':'new' }, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function delete_note()
|
||||||
|
{
|
||||||
|
if (!me.selected_note) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
alert(me.selected_note.title)
|
||||||
|
reset_view();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -104,18 +104,24 @@
|
||||||
background: #f9f9f9;
|
background: #f9f9f9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notesview #notecontent {
|
.notesview #noteform {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 82px;
|
top: 82px;
|
||||||
left: 0;
|
left: 0;
|
||||||
bottom: 41px;
|
bottom: 41px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notesview #notecontent {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
padding: 8px 0 8px 8px;
|
padding: 8px 0 8px 8px;
|
||||||
resize: none;
|
resize: none;
|
||||||
font-family: monospace;
|
font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
|
||||||
font-size: 9pt;
|
font-size: 12px;
|
||||||
outline: none;
|
outline: none;
|
||||||
-webkit-box-sizing: border-box;
|
-webkit-box-sizing: border-box;
|
||||||
-moz-box-sizing: border-box;
|
-moz-box-sizing: border-box;
|
||||||
|
@ -135,6 +141,10 @@
|
||||||
box-shadow: inset 0 0 3px 2px rgba(71,135,177, 0.9);
|
box-shadow: inset 0 0 3px 2px rgba(71,135,177, 0.9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.notesview .defaultSkin table.mceLayout {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.notesview #notedetailstitle {
|
.notesview #notedetailstitle {
|
||||||
height: 68px;
|
height: 68px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
<div id="tagsbox" class="uibox listbox">
|
<div id="tagsbox" class="uibox listbox">
|
||||||
<h2 class="boxtitle"><roundcube:label name="kolab_notes.tags" id="taglist" /></h2>
|
<h2 class="boxtitle"><roundcube:label name="kolab_notes.tags" id="taglist" /></h2>
|
||||||
<div class="scroller">
|
<div class="scroller">
|
||||||
<roundcube:object name="plugin.tagslist" id="tagslist" />
|
<roundcube:object name="plugin.tagslist" id="tagslist" class="tagcloud" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -84,11 +84,32 @@ $(document).ready(function(e){
|
||||||
UI.init();
|
UI.init();
|
||||||
|
|
||||||
new rcube_splitter({ id:'notesviewsplitter', p1:'#sidebar', p2:'#mainview-right',
|
new rcube_splitter({ id:'notesviewsplitter', p1:'#sidebar', p2:'#mainview-right',
|
||||||
orientation:'v', relative:true, start:240, min:180, size:16, offset:2 }).init();
|
orientation:'v', relative:true, start:240, min:180, size:16, offset:2, render:layout_view }).init();
|
||||||
new rcube_splitter({ id:'noteslistsplitter2', p1:'#noteslistbox', p2:'#notedetailsbox',
|
new rcube_splitter({ id:'noteslistsplitter2', p1:'#noteslistbox', p2:'#notedetailsbox',
|
||||||
orientation:'v', relative:true, start:242, min:180, size:16, offset:2 }).init();
|
orientation:'v', relative:true, start:242, min:180, size:16, offset:2, render:layout_view }).init();
|
||||||
new rcube_splitter({ id:'notesviewsplitterv', p1:'#tagsbox', p2:'#notebooksbox',
|
new rcube_splitter({ id:'notesviewsplitterv', p1:'#tagsbox', p2:'#notebooksbox',
|
||||||
orientation:'h', relative:true, start:242, min:120, size:16, offset:6 }).init();
|
orientation:'h', relative:true, start:242, min:120, size:16, offset:6 }).init();
|
||||||
|
|
||||||
|
function layout_view()
|
||||||
|
{
|
||||||
|
var form = $('#noteform'),
|
||||||
|
content = $('#notecontent'),
|
||||||
|
header = $('#notedetailstitle'),
|
||||||
|
w, h;
|
||||||
|
|
||||||
|
form.css('top', header.outerHeight()+'px');
|
||||||
|
|
||||||
|
w = form.outerWidth();
|
||||||
|
h = form.outerHeight();
|
||||||
|
content.width(w).height(h);
|
||||||
|
|
||||||
|
$('#notecontent_tbl').width(w+'px').height('').css('margin-top', '-1px');
|
||||||
|
$('#notecontent_ifr').width(w+'px').height((h-54)+'px');
|
||||||
|
}
|
||||||
|
|
||||||
|
$(window).resize(function(e){
|
||||||
|
layout_view();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Add table
Reference in a new issue