diff --git a/plugins/tasklist/jquery.tagedit.js b/plugins/tasklist/jquery.tagedit.js old mode 100755 new mode 100644 index d70cb327..7d7bf0a3 --- a/plugins/tasklist/jquery.tagedit.js +++ b/plugins/tasklist/jquery.tagedit.js @@ -5,13 +5,14 @@ * Examples and documentation at: tagedit.webwork-albrecht.de * * Copyright (c) 2010 Oliver Albrecht +* Copyright (c) 2012 Thomas BrĂ¼derli * * License: * This work is licensed under a MIT License * http://www.opensource.org/licenses/mit-license.php * * @author Oliver Albrecht Mial: info@webwork-albrecht.de Twitter: @webworka -* @version 1.2.1 (11/2011) +* @version 1.5.1 (10/2013) * Requires: jQuery v1.4+, jQueryUI v1.8+, jQuerry.autoGrowInput * * Example of usage: @@ -52,6 +53,7 @@ options = $.extend(true, { // default options here autocompleteURL: null, + checkToDeleteURL: null, deletedPostfix: '-d', addedPostfix: '-a', additionalListClass: '', @@ -67,14 +69,15 @@ } }, breakKeyCodes: [ 13, 44 ], - checkNewEntriesCaseSensitive: false, + checkNewEntriesCaseSensitive: false, texts: { removeLinkTitle: 'Remove from list.', saveEditLinkTitle: 'Save changes.', deleteLinkTitle: 'Delete this tag from database.', deleteConfirmation: 'Are you sure to delete this entry?', deletedElementTitle: 'This Element will be deleted.', - breakEditLinkTitle: 'Cancel' + breakEditLinkTitle: 'Cancel', + forceDeleteConfirmation: 'There are more records using this tag, are you sure do you want to remove it?' }, tabindex: false }, options || {}); @@ -169,16 +172,16 @@ .each(function() { $(this).autoGrowInput({comfortZone: 15, minWidth: 15, maxWidth: 20000}); - // Event ist triggert in case of choosing an item from the autocomplete, or finish the input + // Event is triggert in case of choosing an item from the autocomplete, or finish the input $(this).bind('transformToTag', function(event, id) { - var oldValue = (typeof id != 'undefined' && id.length > 0); + var oldValue = (typeof id != 'undefined' && (id.length > 0 || id > 0)); var checkAutocomplete = oldValue == true? false : true; // check if the Value ist new var isNewResult = isNew($(this).val(), checkAutocomplete); - if(isNewResult[0] === true || isNewResult[1] != null) { + if(isNewResult[0] === true || (isNewResult[0] === false && typeof isNewResult[1] == 'string')) { - if(oldValue == false && isNewResult[1] != null) { + if(oldValue == false && typeof isNewResult[1] == 'string') { oldValue = true; id = isNewResult[1]; } @@ -199,7 +202,8 @@ // close autocomplete if(options.autocompleteOptions.source) { - $(this).autocomplete( "close" ); + if($(this).is(':ui-autocomplete')) + $(this).autocomplete( "close" ); } }) @@ -288,7 +292,7 @@ } return false; }) - // forward focus event + // forward focus event (on tabbing through the form) .focus(function(e){ $(this).click(); }) } @@ -321,7 +325,7 @@ } textfield.remove(); - $(this).find('a.tagedit-save, a.tagedit-break, a.tagedit-delete, tester').remove(); // Workaround. This normaly has to be done by autogrow Plugin + $(this).find('a.tagedit-save, a.tagedit-break, a.tagedit-delete').remove(); // Workaround. This normaly has to be done by autogrow Plugin $(this).removeClass('tagedit-listelement-edit').unbind('finishEdit'); return false; }); @@ -356,7 +360,16 @@ .click(function() { window.clearTimeout(closeTimer); if(confirm(options.texts.deleteConfirmation)) { - markAsDeleted($(this).parent()); + var canDelete = checkToDelete($(this).parent()); + if (!canDelete && confirm(options.texts.forceDeleteConfirmation)) { + markAsDeleted($(this).parent()); + } + + if(canDelete) { + markAsDeleted($(this).parent()); + } + + $(this).parent().find(':text').trigger('finishEdit', [true]); } else { $(this).parent().find(':text').trigger('finishEdit', [true]); @@ -386,6 +399,42 @@ }); } + /** + * Verifies if the tag select to be deleted is used by other records using an Ajax request. + * + * @param element + * @returns {boolean} + */ + function checkToDelete(element) { + // if no URL is provide will not verify + if(options.checkToDeleteURL === null) { + return false; + } + + var inputName = element.find('input:hidden').attr('name'); + var idPattern = new RegExp('\\d'); + var tagId = inputName.match(idPattern); + var checkResult = false; + + $.ajax({ + async : false, + url : options.checkToDeleteURL, + dataType: 'json', + type : 'POST', + data : { 'tagId' : tagId}, + complete: function (XMLHttpRequest, textStatus) { + + // Expected JSON Object: { "success": Boolean, "allowDelete": Boolean} + var result = $.parseJSON(XMLHttpRequest.responseText); + if(result.success === true){ + checkResult = result.allowDelete; + } + } + }); + + return checkResult; + } + /** * Marks a single Tag as deleted. * @@ -451,12 +500,11 @@ } }); } - + // If there is an entry for that already in the autocomplete, don't use it (Check could be case sensitive or not) for (var i = 0; i < result.length; i++) { - var label = typeof result[i] == 'string' ? result[i] : result[i].label; - if (options.checkNewEntriesCaseSensitive == false) - label = label.toLowerCase(); + var resultValue = result[i].label? result[i].label : result[i]; + var label = options.checkNewEntriesCaseSensitive == true? resultValue : resultValue.toLowerCase(); if (label == compareValue) { isNew = false; autoCompleteId = typeof result[i] == 'string' ? i : result[i].id; @@ -476,60 +524,60 @@ // See related thread: http://stackoverflow.com/questions/931207/is-there-a-jquery-autogrow-plugin-for-text-fields $.fn.autoGrowInput = function(o) { - - o = $.extend({ - maxWidth: 1000, - minWidth: 0, - comfortZone: 70 - }, o); - - this.filter('input:text').each(function(){ - - var minWidth = o.minWidth || $(this).width(), - val = '', - input = $(this), - testSubject = $('').css({ - position: 'absolute', - top: -9999, - left: -9999, - width: 'auto', - fontSize: input.css('fontSize'), - fontFamily: input.css('fontFamily'), - fontWeight: input.css('fontWeight'), - letterSpacing: input.css('letterSpacing'), - whiteSpace: 'nowrap' - }), - check = function() { - - if (val === (val = input.val())) {return;} - - // Enter new content into testSubject - var escaped = val.replace(/&/g, '&').replace(/\s/g,' ').replace(//g, '>'); - testSubject.html(escaped); - - // Calculate new width + whether to change - var testerWidth = testSubject.width(), - newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth, - currentWidth = input.width(), - isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth) - || (newWidth > minWidth && newWidth < o.maxWidth); - - // Animate width - if (isValidWidthChange) { - input.width(newWidth); - } - - }; - - testSubject.insertAfter(input); - - $(this).bind('keyup keydown blur update', check); - - check(); - }); - - return this; + + o = $.extend({ + maxWidth: 1000, + minWidth: 0, + comfortZone: 70 + }, o); + + this.filter('input:text').each(function(){ + + var minWidth = o.minWidth || $(this).width(), + val = '', + input = $(this), + testSubject = $('').css({ + position: 'absolute', + top: -9999, + left: -9999, + width: 'auto', + fontSize: input.css('fontSize'), + fontFamily: input.css('fontFamily'), + fontWeight: input.css('fontWeight'), + letterSpacing: input.css('letterSpacing'), + whiteSpace: 'nowrap' + }), + check = function() { + + if (val === (val = input.val())) {return;} + + // Enter new content into testSubject + var escaped = val.replace(/&/g, '&').replace(/\s/g,' ').replace(//g, '>'); + testSubject.html(escaped); + + // Calculate new width + whether to change + var testerWidth = testSubject.width(), + newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth, + currentWidth = input.width(), + isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth) + || (newWidth > minWidth && newWidth < o.maxWidth); + + // Animate width + if (isValidWidthChange) { + input.width(newWidth); + } + + }; + + testSubject.insertAfter(input); + + $(this).bind('keyup keydown blur update', check); + + check(); + }); + + return this; }; -})(jQuery); +})(jQuery); \ No newline at end of file diff --git a/plugins/tasklist/skins/larry/tagedit.css b/plugins/tasklist/skins/larry/tagedit.css new file mode 100644 index 00000000..0ce32221 --- /dev/null +++ b/plugins/tasklist/skins/larry/tagedit.css @@ -0,0 +1,108 @@ +/** + * Styles of the tagedit inputsforms + */ +.tagedit-list { + width: 100%; + margin: 0; + padding: 4px 4px 0 5px; + overflow: auto; + min-height: 26px; + background: #fff; + border: 1px solid #b2b2b2; + border-radius: 4px; + box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1); + -moz-box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1); + -webkit-box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1); + -o-box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1); +} +.tagedit-list li.tagedit-listelement { + list-style-type: none; + float: left; + margin: 0 4px 4px 0; + padding: 0; +} + +/* New Item input */ +.tagedit-list li.tagedit-listelement-new input { + border: 0; + height: 100%; + padding: 4px 1px; + width: 15px; + background: #fff; + border-radius: 0; + box-shadow: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + -o-box-shadow: none; +} +.tagedit-list li.tagedit-listelement-new input:focus { + box-shadow: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + -o-box-shadow: none; + outline: none; +} +.tagedit-list li.tagedit-listelement-new input.tagedit-input-disabled { + display: none; +} + +/* Item that is put to the List */ +.tagedit span.tag-element, +.tagedit-list li.tagedit-listelement-old { + padding: 3px 0 1px 6px; + background: #ddeef5; + background: -moz-linear-gradient(top, #edf6fa 0%, #d6e9f3 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#edf6fa), color-stop(100%,#d6e9f3)); + background: -o-linear-gradient(top, #edf6fa 0%, #d6e9f3 100%); + background: -ms-linear-gradient(top, #edf6fa 0%, #d6e9f3 100%); + background: linear-gradient(top, #edf6fa 0%, #d6e9f3 100%); + border: 1px solid #c2dae5; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + color: #0d5165; +} + +.tagedit span.tag-element { + margin-right: 0.6em; + padding: 2px 6px; +/* cursor: pointer; */ +} + +.tagedit span.tag-element.inherit { + color: #666; + background: #f2f2f2; + border-color: #ddd; +} + +.tagedit-list li.tagedit-listelement-old a.tagedit-close, +.tagedit-list li.tagedit-listelement-old a.tagedit-break, +.tagedit-list li.tagedit-listelement-old a.tagedit-delete, +.tagedit-list li.tagedit-listelement-old a.tagedit-save { + text-indent: -2000px; + display: inline-block; + position: relative; + top: -1px; + width: 16px; + height: 16px; + margin: 0 2px 0 6px; + background: url('data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAOCAYAAAD0f5bSAAAAgUlEQVQoz2NgQAKzdxwWAOIEIG5AwiC+AAM2AJQIAOL3QPwfCwaJB6BrSMChGB0nwDQYwATP3nn4f+Ge4ygKQXyQOJKYAUjTepjAm09fwBimEUTDxJA0rWdANxWmaMXB0xiGwDADurthGkEAmwbqaCLFeWQFBOlBTlbkkp2MSE2wAA8R50rWvqeRAAAAAElFTkSuQmCC') left 1px no-repeat; + cursor: pointer; +} + +/** Special hacks for IE7 **/ + +html.ie7 .tagedit span.tag-element, +html.ie7 .tagedit-list li.tagedit-listelement-old { + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#edf6fa', endColorstr='#d6e9f3', GradientType=0); +} + +html.ie7 .tagedit-list li.tagedit-listelement span { + position: relative; + top: -3px; +} + +html.ie7 .tagedit-list li.tagedit-listelement-old a.tagedit-close { + left: 5px; +} + diff --git a/plugins/tasklist/skins/larry/tasklist.css b/plugins/tasklist/skins/larry/tasklist.css index e3adcb22..14776e15 100644 --- a/plugins/tasklist/skins/larry/tasklist.css +++ b/plugins/tasklist/skins/larry/tasklist.css @@ -826,99 +826,6 @@ label.block { } -/** - * Styles of the tagedit inputsforms - */ -.tagedit-list { - width: 100%; - margin: 0; - padding: 4px 4px 0 5px; - overflow: auto; - min-height: 26px; - background: #fff; - border: 1px solid #b2b2b2; - border-radius: 4px; - box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1); - -moz-box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1); - -webkit-box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1); - -o-box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1); -} -.tagedit-list li.tagedit-listelement { - list-style-type: none; - float: left; - margin: 0 4px 4px 0; - padding: 0; -} - -/* New Item input */ -.tagedit-list li.tagedit-listelement-new input { - border: 0; - height: 100%; - padding: 4px 1px; - width: 15px; - background: #fff; - border-radius: 0; - box-shadow: none; - -moz-box-shadow: none; - -webkit-box-shadow: none; - -o-box-shadow: none; -} -.tagedit-list li.tagedit-listelement-new input:focus { - box-shadow: none; - -moz-box-shadow: none; - -webkit-box-shadow: none; - -o-box-shadow: none; - outline: none; -} -.tagedit-list li.tagedit-listelement-new input.tagedit-input-disabled { - display: none; -} - -/* Item that is put to the List */ -.form-section span.tag-element, -.tagedit-list li.tagedit-listelement-old { - padding: 3px 0 1px 6px; - background: #ddeef5; - background: -moz-linear-gradient(top, #edf6fa 0%, #d6e9f3 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#edf6fa), color-stop(100%,#d6e9f3)); - background: -o-linear-gradient(top, #edf6fa 0%, #d6e9f3 100%); - background: -ms-linear-gradient(top, #edf6fa 0%, #d6e9f3 100%); - background: linear-gradient(top, #edf6fa 0%, #d6e9f3 100%); - border: 1px solid #c2dae5; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - border-radius: 4px; - color: #0d5165; -} - -.form-section span.tag-element { - margin-right: 0.6em; - padding: 2px 6px; -/* cursor: pointer; */ -} - -.form-section span.tag-element.inherit { - color: #666; - background: #f2f2f2; - border-color: #ddd; -} - -.tagedit-list li.tagedit-listelement-old a.tagedit-close, -.tagedit-list li.tagedit-listelement-old a.tagedit-break, -.tagedit-list li.tagedit-listelement-old a.tagedit-delete, -.tagedit-list li.tagedit-listelement-old a.tagedit-save { - text-indent: -2000px; - display: inline-block; - position: relative; - top: -1px; - width: 16px; - height: 16px; - margin: 0 2px 0 6px; - background: url(sprites.png) -2px -122px no-repeat; - cursor: pointer; -} - - /** Special hacks for IE7 **/ /** They need to be in this file to also affect the task-create dialog embedded in mail view **/ @@ -926,17 +833,3 @@ html.ie7 #taskedit-completeness-slider { display: inline; } -html.ie7 .form-section span.tag-element, -html.ie7 .tagedit-list li.tagedit-listelement-old { - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#edf6fa', endColorstr='#d6e9f3', GradientType=0); -} - -html.ie7 .tagedit-list li.tagedit-listelement span { - position: relative; - top: -3px; -} - -html.ie7 .tagedit-list li.tagedit-listelement-old a.tagedit-close { - left: 5px; -} - diff --git a/plugins/tasklist/tasklist.php b/plugins/tasklist/tasklist.php index 1eaacbd1..ca677447 100644 --- a/plugins/tasklist/tasklist.php +++ b/plugins/tasklist/tasklist.php @@ -777,11 +777,9 @@ class tasklist extends rcube_plugin $this->ui->init_templates(); echo $this->api->output->parse('tasklist.taskedit', false, false); + echo html::tag('link', array('rel' => 'stylesheet', 'type' => 'text/css', 'href' => $this->url($this->local_skin_path() . '/tagedit.css'), 'nl' => true)); echo html::tag('script', array('type' => 'text/javascript'), "rcmail.set_env('tasklists', " . json_encode($this->api->output->env['tasklists']) . ");\n". -// "rcmail.set_env('deleteicon', '" . $this->api->output->env['deleteicon'] . "');\n". -// "rcmail.set_env('cancelicon', '" . $this->api->output->env['cancelicon'] . "');\n". -// "rcmail.set_env('loadingicon', '" . $this->api->output->env['loadingicon'] . "');\n". "rcmail.add_label(" . json_encode($texts) . ");\n" ); exit; diff --git a/plugins/tasklist/tasklist_ui.php b/plugins/tasklist/tasklist_ui.php index 21faba3e..8d3c371d 100644 --- a/plugins/tasklist/tasklist_ui.php +++ b/plugins/tasklist/tasklist_ui.php @@ -81,6 +81,8 @@ class tasklist_ui $this->plugin->include_script('jquery.tagedit.js'); $this->plugin->include_script('tasklist.js'); + + $this->plugin->include_stylesheet($this->plugin->local_skin_path() . '/tagedit.css'); } /**