diff options
author | Bart Visscher <bartv@thisnet.nl> | 2011-09-23 00:22:52 +0400 |
---|---|---|
committer | Bart Visscher <bartv@thisnet.nl> | 2011-09-23 21:40:06 +0400 |
commit | e9950defb240dfe19a22cf1cce34e0fd25e58ee9 (patch) | |
tree | 1df2da6edcc6985700085d82f0e9a54533989b46 | |
parent | 5559a0dedef2ac1f366ca17ddb2286629009ee3c (diff) |
Make event category choice multiselect
-rw-r--r-- | apps/calendar/ajax/editeventform.php | 16 | ||||
-rw-r--r-- | apps/calendar/ajax/neweventform.php | 8 | ||||
-rw-r--r-- | apps/calendar/css/style.css | 2 | ||||
-rw-r--r-- | apps/calendar/index.php | 12 | ||||
-rw-r--r-- | apps/calendar/js/calendar.js | 7 | ||||
-rw-r--r-- | apps/calendar/lib/object.php | 18 | ||||
-rw-r--r-- | apps/calendar/templates/part.eventform.php | 8 | ||||
-rw-r--r-- | core/css/jquery.multiselect.css | 23 | ||||
-rw-r--r-- | core/js/jquery.multiselect.js | 658 | ||||
-rw-r--r-- | lib/base.php | 2 |
10 files changed, 730 insertions, 24 deletions
diff --git a/apps/calendar/ajax/editeventform.php b/apps/calendar/ajax/editeventform.php index 3b8a30f70fc..f310db3e79a 100644 --- a/apps/calendar/ajax/editeventform.php +++ b/apps/calendar/ajax/editeventform.php @@ -20,8 +20,8 @@ if(!OC_USER::isLoggedIn()) { die('<script type="text/javascript">document.location = oc_webroot;</script>'); } -$calendars = OC_Calendar_Calendar::allCalendars(OC_User::getUser()); -$categories = OC_Calendar_Object::getCategoryOptions($l10n); +$calendar_options = OC_Calendar_Calendar::allCalendars(OC_User::getUser()); +$category_options = OC_Calendar_Object::getCategoryOptions($l10n); $repeat_options = OC_Calendar_Object::getRepeatOptions($l10n); $id = $_GET['id']; @@ -55,19 +55,23 @@ switch($dtstart->getDateType()) { $summary = isset($vevent->SUMMARY) ? $vevent->SUMMARY->value : ''; $location = isset($vevent->LOCATION) ? $vevent->LOCATION->value : ''; -$category = isset($vevent->CATEGORIES) ? $vevent->CATEGORIES->value : ''; +$categories = array(); +if (isset($vevent->CATEGORIES)){ + $categories = explode(',', $vevent->CATEGORIES->value); + $categories = array_map('trim', $categories); +} $repeat = isset($vevent->CATEGORY) ? $vevent->CATEGORY->value : ''; $description = isset($vevent->DESCRIPTION) ? $vevent->DESCRIPTION->value : ''; $tmpl = new OC_Template('calendar', 'part.editevent'); $tmpl->assign('id', $id); -$tmpl->assign('calendars', $calendars); -$tmpl->assign('categories', $categories); +$tmpl->assign('calendar_options', $calendar_options); +$tmpl->assign('category_options', $category_options); $tmpl->assign('repeat_options', $repeat_options); $tmpl->assign('title', $summary); $tmpl->assign('location', $location); -$tmpl->assign('category', $category); +$tmpl->assign('categories', $categories); $tmpl->assign('calendar', $data['calendarid']); $tmpl->assign('allday', $allday); $tmpl->assign('startdate', $startdate); diff --git a/apps/calendar/ajax/neweventform.php b/apps/calendar/ajax/neweventform.php index 1d8a61dffd2..132294b496e 100644 --- a/apps/calendar/ajax/neweventform.php +++ b/apps/calendar/ajax/neweventform.php @@ -25,8 +25,8 @@ if(!OC_USER::isLoggedIn()) { die('<script type="text/javascript">document.location = oc_webroot;</script>'); } -$calendars = OC_Calendar_Calendar::allCalendars(OC_User::getUser()); -$categories = OC_Calendar_Object::getCategoryOptions($l10n); +$calendar_options = OC_Calendar_Calendar::allCalendars(OC_User::getUser()); +$category_options = OC_Calendar_Object::getCategoryOptions($l10n); $repeat_options = OC_Calendar_Object::getRepeatOptions($l10n); $startday = substr($_GET['d'], 0, 2); $startmonth = substr($_GET['d'], 2, 2); @@ -56,8 +56,8 @@ if($endtime == 23) { } $tmpl = new OC_Template('calendar', 'part.newevent'); -$tmpl->assign('calendars', $calendars); -$tmpl->assign('categories', $categories); +$tmpl->assign('calendar_options', $calendar_options); +$tmpl->assign('category_options', $category_options); $tmpl->assign('startdate', $startday . '-' . $startmonth . '-' . $startyear); $tmpl->assign('starttime', ($starttime <= 9 ? '0' : '') . $starttime . ':' . $startminutes); $tmpl->assign('enddate', $endday . '-' . $endmonth . '-' . $endyear); diff --git a/apps/calendar/css/style.css b/apps/calendar/css/style.css index 5d08402422a..b1198062763 100644 --- a/apps/calendar/css/style.css +++ b/apps/calendar/css/style.css @@ -68,3 +68,5 @@ color:#333; #fromtime.disabled, #totime.disabled { color:#A9A9A9; } +select#category{width:140px;} +button.category{margin:0 3px;} diff --git a/apps/calendar/index.php b/apps/calendar/index.php index c93ea93bb6c..b4e7d5ff48f 100644 --- a/apps/calendar/index.php +++ b/apps/calendar/index.php @@ -17,7 +17,7 @@ * 59 Temple Place, Suite 330, Boston, * * MA 02111-1307 USA * *************************************************/ -require_once ("../../lib/base.php"); +require_once ('../../lib/base.php'); OC_Util::checkLoggedIn(); // Create default calendar ... $calendars = OC_Calendar_Calendar::allCalendars(OC_User::getUser()); @@ -25,8 +25,10 @@ if( count($calendars) == 0){ OC_Calendar_Calendar::addCalendar(OC_User::getUser(),'default','Default calendar'); $calendars = OC_Calendar_Calendar::allCalendars(OC_User::getUser()); } -OC_UTIL::addScript("calendar", "calendar"); -OC_UTIL::addStyle("calendar", "style"); -OC_APP::setActiveNavigationEntry("calendar_index"); -$output = new OC_TEMPLATE("calendar", "calendar", "user"); +OC_UTIL::addScript('calendar', 'calendar'); +OC_UTIL::addStyle('calendar', 'style'); +OC_UTIL::addScript('', 'jquery.multiselect'); +OC_UTIL::addStyle('', 'jquery.multiselect'); +OC_APP::setActiveNavigationEntry('calendar_index'); +$output = new OC_TEMPLATE('calendar', 'calendar', 'user'); $output -> printPage(); diff --git a/apps/calendar/js/calendar.js b/apps/calendar/js/calendar.js index 5864977eb38..8c1a4afac09 100644 --- a/apps/calendar/js/calendar.js +++ b/apps/calendar/js/calendar.js @@ -288,6 +288,13 @@ Calendar={ $( "#to" ).datepicker({ dateFormat : 'dd-mm-yy' }); + $('#category').multiselect({ + header: false, + noneSelectedText: $('#category').attr('title'), + selectedList: 2, + minWidth:'auto', + classes: 'category', + }); $('#event').dialog({ width : 500, close : function(event, ui) { diff --git a/apps/calendar/lib/object.php b/apps/calendar/lib/object.php index 702033c169c..3bb6543d3fd 100644 --- a/apps/calendar/lib/object.php +++ b/apps/calendar/lib/object.php @@ -301,7 +301,6 @@ class OC_Calendar_Object{ public static function getCategoryOptions($l10n) { return array( - $l10n->t('None'), $l10n->t('Birthday'), $l10n->t('Business'), $l10n->t('Call'), @@ -345,6 +344,11 @@ class OC_Calendar_Object{ $errarr['cal'] = 'true'; $errnum++; } + + if(isset($request['categories']) && !is_array($request['categories'])){ + $errors['categories'] = $l10n->t('Not an array'); + } + $fromday = substr($request['from'], 0, 2); $frommonth = substr($request['from'], 3, 2); $fromyear = substr($request['from'], 6, 4); @@ -434,7 +438,7 @@ class OC_Calendar_Object{ { $title = $request["title"]; $location = $request["location"]; - $cat = $request["category"]; + $categories = $request["categories"]; $allday = isset($request["allday"]); $from = $request["from"]; $fromtime = $request["fromtime"]; @@ -493,15 +497,21 @@ class OC_Calendar_Object{ if($location != ""){ $vevent->LOCATION = $location; + }else{ + unset($vevent->LOCATION); } if($description != ""){ $des = str_replace("\n","\\n", $description); $vevent->DESCRIPTION = $des; + }else{ + unset($vevent->DESCRIPTION); } - if($cat != ""){ - $vevent->CATEGORIES = $cat; + if(!empty($categories)){ + $vevent->CATEGORIES = join(',', $categories); + }else{ + unset($vevent->CATEGORIES); } /*if($repeat == "true"){ diff --git a/apps/calendar/templates/part.eventform.php b/apps/calendar/templates/part.eventform.php index c63d709e26e..5b12407330a 100644 --- a/apps/calendar/templates/part.eventform.php +++ b/apps/calendar/templates/part.eventform.php @@ -16,10 +16,10 @@ <tr> <th width="75px"><?php echo $l->t("Category");?>:</th> <td> - <select style="width:140px;" name="category"> + <select id="category" name="categories[]" multiple="multiple" title="<?php echo $l->t("Select category") ?>"> <?php - foreach($_['categories'] as $category){ - echo '<option value="' . $category . '"' . ($_['category'] == $category ? ' selected="selected"' : '') . '>' . $category . '</option>'; + foreach($_['category_options'] as $category){ + echo '<option value="' . $category . '"' . (in_array($category, $_['categories']) ? ' selected="selected"' : '') . '>' . $category . '</option>'; } ?> </select></td> @@ -27,7 +27,7 @@ <td> <select style="width:140px;" name="calendar"> <?php - foreach($_['calendars'] as $calendar){ + foreach($_['calendar_options'] as $calendar){ echo '<option value="' . $calendar['id'] . '"' . ($_['calendar'] == $calendar['id'] ? ' selected="selected"' : '') . '>' . $calendar['displayname'] . '</option>'; } ?> diff --git a/core/css/jquery.multiselect.css b/core/css/jquery.multiselect.css new file mode 100644 index 00000000000..156799f0869 --- /dev/null +++ b/core/css/jquery.multiselect.css @@ -0,0 +1,23 @@ +.ui-multiselect { padding:2px 0 2px 4px; text-align:left } +.ui-multiselect span.ui-icon { float:right } +.ui-multiselect-single .ui-multiselect-checkboxes input { position:absolute !important; top: auto !important; left:-9999px; } +.ui-multiselect-single .ui-multiselect-checkboxes label { padding:5px !important } + +.ui-multiselect-header { margin-bottom:3px; padding:3px 0 3px 4px } +.ui-multiselect-header ul { font-size:0.9em } +.ui-multiselect-header ul li { float:left; padding:0 10px 0 0 } +.ui-multiselect-header a { text-decoration:none } +.ui-multiselect-header a:hover { text-decoration:underline } +.ui-multiselect-header span.ui-icon { float:left } +.ui-multiselect-header li.ui-multiselect-close { float:right; text-align:right; padding-right:0 } + +.ui-multiselect-menu { display:none; padding:3px; position:absolute; z-index:10000 } +.ui-multiselect-checkboxes { position:relative /* fixes bug in IE6/7 */; overflow-y:scroll } +.ui-multiselect-checkboxes label { cursor:default; display:block; border:1px solid transparent; padding:3px 1px } +.ui-multiselect-checkboxes label input { position:relative; top:1px } +.ui-multiselect-checkboxes li { clear:both; font-size:0.9em; padding-right:3px } +.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label { text-align:center; font-weight:bold; border-bottom:1px solid } +.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label a { display:block; padding:3px; margin:1px 0; text-decoration:none } + +/* remove label borders in IE6 because IE6 does not support transparency */ +* html .ui-multiselect-checkboxes label { border:none } diff --git a/core/js/jquery.multiselect.js b/core/js/jquery.multiselect.js new file mode 100644 index 00000000000..46aab7ebf01 --- /dev/null +++ b/core/js/jquery.multiselect.js @@ -0,0 +1,658 @@ +/* + * jQuery MultiSelect UI Widget 1.11 + * Copyright (c) 2011 Eric Hynds + * + * http://www.erichynds.com/jquery/jquery-ui-multiselect-widget/ + * + * Depends: + * - jQuery 1.4.2+ + * - jQuery UI 1.8 widget factory + * + * Optional: + * - jQuery UI effects + * - jQuery UI position utility + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * +*/ +(function($, undefined){ + +var multiselectID = 0; + +$.widget("ech.multiselect", { + + // default options + options: { + header: true, + height: 175, + minWidth: 225, + classes: '', + checkAllText: 'Check all', + uncheckAllText: 'Uncheck all', + noneSelectedText: 'Select options', + selectedText: '# selected', + selectedList: 0, + show: '', + hide: '', + autoOpen: false, + multiple: true, + position: {} + }, + + _create: function(){ + var el = this.element.hide(), + o = this.options; + + this.speed = $.fx.speeds._default; // default speed for effects + this._isOpen = false; // assume no + + var + button = (this.button = $('<button type="button"><span class="ui-icon ui-icon-triangle-2-n-s"></span></button>')) + .addClass('ui-multiselect ui-widget ui-state-default ui-corner-all') + .addClass( o.classes ) + .attr({ 'title':el.attr('title'), 'aria-haspopup':true, 'tabIndex':el.attr('tabIndex') }) + .insertAfter( el ), + + buttonlabel = (this.buttonlabel = $('<span />')) + .html( o.noneSelectedText ) + .appendTo( button ), + + menu = (this.menu = $('<div />')) + .addClass('ui-multiselect-menu ui-widget ui-widget-content ui-corner-all') + .addClass( o.classes ) + .insertAfter( button ), + + header = (this.header = $('<div />')) + .addClass('ui-widget-header ui-corner-all ui-multiselect-header ui-helper-clearfix') + .appendTo( menu ), + + headerLinkContainer = (this.headerLinkContainer = $('<ul />')) + .addClass('ui-helper-reset') + .html(function(){ + if( o.header === true ){ + return '<li><a class="ui-multiselect-all" href="#"><span class="ui-icon ui-icon-check"></span><span>' + o.checkAllText + '</span></a></li><li><a class="ui-multiselect-none" href="#"><span class="ui-icon ui-icon-closethick"></span><span>' + o.uncheckAllText + '</span></a></li>'; + } else if(typeof o.header === "string"){ + return '<li>' + o.header + '</li>'; + } else { + return ''; + } + }) + .append('<li class="ui-multiselect-close"><a href="#" class="ui-multiselect-close"><span class="ui-icon ui-icon-circle-close"></span></a></li>') + .appendTo( header ), + + checkboxContainer = (this.checkboxContainer = $('<ul />')) + .addClass('ui-multiselect-checkboxes ui-helper-reset') + .appendTo( menu ); + + // perform event bindings + this._bindEvents(); + + // build menu + this.refresh( true ); + + // some addl. logic for single selects + if( !o.multiple ){ + menu.addClass('ui-multiselect-single'); + } + }, + + _init: function(){ + if( this.options.header === false ){ + this.header.hide(); + } + if( !this.options.multiple ){ + this.headerLinkContainer.find('.ui-multiselect-all, .ui-multiselect-none').hide(); + } + if( this.options.autoOpen ){ + this.open(); + } + if( this.element.is(':disabled') ){ + this.disable(); + } + }, + + refresh: function( init ){ + var el = this.element, + o = this.options, + menu = this.menu, + checkboxContainer = this.checkboxContainer, + optgroups = [], + html = [], + id = el.attr('id') || multiselectID++; // unique ID for the label & option tags + + // build items + this.element.find('option').each(function( i ){ + var $this = $(this), + parent = this.parentNode, + title = this.innerHTML, + description = this.title, + value = this.value, + inputID = this.id || 'ui-multiselect-'+id+'-option-'+i, + isDisabled = this.disabled, + isSelected = this.selected, + labelClasses = ['ui-corner-all'], + optLabel; + + // is this an optgroup? + if( parent.tagName.toLowerCase() === 'optgroup' ){ + optLabel = parent.getAttribute('label'); + + // has this optgroup been added already? + if( $.inArray(optLabel, optgroups) === -1 ){ + html.push('<li class="ui-multiselect-optgroup-label"><a href="#">' + optLabel + '</a></li>'); + optgroups.push( optLabel ); + } + } + + if( isDisabled ){ + labelClasses.push('ui-state-disabled'); + } + + // browsers automatically select the first option + // by default with single selects + if( isSelected && !o.multiple ){ + labelClasses.push('ui-state-active'); + } + + html.push('<li class="' + (isDisabled ? 'ui-multiselect-disabled' : '') + '">'); + + // create the label + html.push('<label for="'+inputID+'" title="'+description+'" class="'+labelClasses.join(' ')+ '">'); + html.push('<input id="'+inputID+'" name="multiselect_'+id+'" type="'+(o.multiple ? "checkbox" : "radio")+'" value="'+value+'" title="'+title+'"'); + + // pre-selected? + if( isSelected ){ + html.push(' checked="checked"'); + html.push(' aria-selected="true"'); + } + + // disabled? + if( isDisabled ){ + html.push(' disabled="disabled"'); + html.push(' aria-disabled="true"'); + } + + // add the title and close everything off + html.push(' /><span>' + title + '</span></label></li>'); + }); + + // insert into the DOM + checkboxContainer.html( html.join('') ); + + // cache some moar useful elements + this.labels = menu.find('label'); + + // set widths + this._setButtonWidth(); + this._setMenuWidth(); + + // remember default value + this.button[0].defaultValue = this.update(); + + // broadcast refresh event; useful for widgets + if( !init ){ + this._trigger('refresh'); + } + }, + + // updates the button text. call refresh() to rebuild + update: function(){ + var o = this.options, + $inputs = this.labels.find('input'), + $checked = $inputs.filter(':checked'), + numChecked = $checked.length, + value; + + if( numChecked === 0 ){ + value = o.noneSelectedText; + } else { + if($.isFunction( o.selectedText )){ + value = o.selectedText.call(this, numChecked, $inputs.length, $checked.get()); + } else if( /\d/.test(o.selectedList) && o.selectedList > 0 && numChecked <= o.selectedList){ + value = $checked.map(function(){ return this.title; }).get().join(', '); + } else { + value = o.selectedText.replace('#', numChecked).replace('#', $inputs.length); + } + } + + this.buttonlabel.html( value ); + return value; + }, + + // binds events + _bindEvents: function(){ + var self = this, button = this.button; + + function clickHandler(){ + self[ self._isOpen ? 'close' : 'open' ](); + return false; + } + + // webkit doesn't like it when you click on the span :( + button + .find('span') + .bind('click.multiselect', clickHandler); + + // button events + button.bind({ + click: clickHandler, + keypress: function( e ){ + switch(e.which){ + case 27: // esc + case 38: // up + case 37: // left + self.close(); + break; + case 39: // right + case 40: // down + self.open(); + break; + } + }, + mouseenter: function(){ + if( !button.hasClass('ui-state-disabled') ){ + $(this).addClass('ui-state-hover'); + } + }, + mouseleave: function(){ + $(this).removeClass('ui-state-hover'); + }, + focus: function(){ + if( !button.hasClass('ui-state-disabled') ){ + $(this).addClass('ui-state-focus'); + } + }, + blur: function(){ + $(this).removeClass('ui-state-focus'); + } + }); + + // header links + this.header + .delegate('a', 'click.multiselect', function( e ){ + // close link + if( $(this).hasClass('ui-multiselect-close') ){ + self.close(); + + // check all / uncheck all + } else { + self[ $(this).hasClass('ui-multiselect-all') ? 'checkAll' : 'uncheckAll' ](); + } + + e.preventDefault(); + }); + + // optgroup label toggle support + this.menu + .delegate('li.ui-multiselect-optgroup-label a', 'click.multiselect', function( e ){ + e.preventDefault(); + + var $this = $(this), + $inputs = $this.parent().nextUntil('li.ui-multiselect-optgroup-label').find('input:visible:not(:disabled)'), + nodes = $inputs.get(), + label = $this.parent().text(); + + // trigger event and bail if the return is false + if( self._trigger('beforeoptgrouptoggle', e, { inputs:nodes, label:label }) === false ){ + return; + } + + // toggle inputs + self._toggleChecked( + $inputs.filter(':checked').length !== $inputs.length, + $inputs + ); + + self._trigger('optgrouptoggle', e, { + inputs: nodes, + label: label, + checked: nodes[0].checked + }); + }) + .delegate('label', 'mouseenter.multiselect', function(){ + if( !$(this).hasClass('ui-state-disabled') ){ + self.labels.removeClass('ui-state-hover'); + $(this).addClass('ui-state-hover').find('input').focus(); + } + }) + .delegate('label', 'keydown.multiselect', function( e ){ + e.preventDefault(); + + switch(e.which){ + case 9: // tab + case 27: // esc + self.close(); + break; + case 38: // up + case 40: // down + case 37: // left + case 39: // right + self._traverse(e.which, this); + break; + case 13: // enter + $(this).find('input')[0].click(); + break; + } + }) + .delegate('input[type="checkbox"], input[type="radio"]', 'click.multiselect', function( e ){ + var $this = $(this), + val = this.value, + checked = this.checked, + tags = self.element.find('option'); + + // bail if this input is disabled or the event is cancelled + if( this.disabled || self._trigger('click', e, { value:val, text:this.title, checked:checked }) === false ){ + e.preventDefault(); + return; + } + + // toggle aria state + $this.attr('aria-selected', checked); + + // change state on the original option tags + tags.each(function(){ + if( this.value === val ){ + this.selected = checked; + } else if( !self.options.multiple ){ + this.selected = false; + } + }); + + // some additional single select-specific logic + if( !self.options.multiple ){ + self.labels.removeClass('ui-state-active'); + $this.closest('label').toggleClass('ui-state-active', checked ); + + // close menu + self.close(); + } + + // fire change on the select box + self.element.trigger("change"); + + // setTimeout is to fix multiselect issue #14 and #47. caused by jQuery issue #3827 + // http://bugs.jquery.com/ticket/3827 + setTimeout($.proxy(self.update, self), 10); + }); + + // close each widget when clicking on any other element/anywhere else on the page + $(document).bind('mousedown.multiselect', function( e ){ + if(self._isOpen && !$.contains(self.menu[0], e.target) && !$.contains(self.button[0], e.target) && e.target !== self.button[0]){ + self.close(); + } + }); + + // deal with form resets. the problem here is that buttons aren't + // restored to their defaultValue prop on form reset, and the reset + // handler fires before the form is actually reset. delaying it a bit + // gives the form inputs time to clear. + $(this.element[0].form).bind('reset.multiselect', function(){ + setTimeout(function(){ self.update(); }, 10); + }); + }, + + // set button width + _setButtonWidth: function(){ + var width = this.element.outerWidth(), + o = this.options; + + if( /\d/.test(o.minWidth) && width < o.minWidth){ + width = o.minWidth; + } + + // set widths + this.button.width( width ); + }, + + // set menu width + _setMenuWidth: function(){ + var m = this.menu, + width = this.button.outerWidth()- + parseInt(m.css('padding-left'),10)- + parseInt(m.css('padding-right'),10)- + parseInt(m.css('border-right-width'),10)- + parseInt(m.css('border-left-width'),10); + + m.width( width || this.button.outerWidth() ); + }, + + // move up or down within the menu + _traverse: function( which, start ){ + var $start = $(start), + moveToLast = which === 38 || which === 37, + + // select the first li that isn't an optgroup label / disabled + $next = $start.parent()[moveToLast ? 'prevAll' : 'nextAll']('li:not(.ui-multiselect-disabled, .ui-multiselect-optgroup-label)')[ moveToLast ? 'last' : 'first'](); + + // if at the first/last element + if( !$next.length ){ + var $container = this.menu.find('ul:last'); + + // move to the first/last + this.menu.find('label')[ moveToLast ? 'last' : 'first' ]().trigger('mouseover'); + + // set scroll position + $container.scrollTop( moveToLast ? $container.height() : 0 ); + + } else { + $next.find('label').trigger('mouseover'); + } + }, + + // This is an internal function to toggle the checked property and + // other related attributes of a checkbox. + // + // The context of this function should be a checkbox; do not proxy it. + _toggleCheckbox: function( prop, flag ){ + return function(){ + !this.disabled && (this[ prop ] = flag); + + if( flag ){ + this.setAttribute('aria-selected', true); + } else { + this.removeAttribute('aria-selected'); + } + } + }, + + _toggleChecked: function( flag, group ){ + var $inputs = (group && group.length) ? + group : + this.labels.find('input'), + + self = this; + + // toggle state on inputs + $inputs.each(this._toggleCheckbox('checked', flag)); + + // update button text + this.update(); + + // gather an array of the values that actually changed + var values = $inputs.map(function(){ + return this.value; + }).get(); + + // toggle state on original option tags + this.element + .find('option') + .each(function(){ + if( !this.disabled && $.inArray(this.value, values) > -1 ){ + self._toggleCheckbox('selected', flag).call( this ); + } + }); + + // trigger the change event on the select + if( $inputs.length ) { + this.element.trigger("change"); + } + }, + + _toggleDisabled: function( flag ){ + this.button + .attr({ 'disabled':flag, 'aria-disabled':flag })[ flag ? 'addClass' : 'removeClass' ]('ui-state-disabled'); + + this.menu + .find('input') + .attr({ 'disabled':flag, 'aria-disabled':flag }) + .parent()[ flag ? 'addClass' : 'removeClass' ]('ui-state-disabled'); + + this.element + .attr({ 'disabled':flag, 'aria-disabled':flag }); + }, + + // open the menu + open: function( e ){ + var self = this, + button = this.button, + menu = this.menu, + speed = this.speed, + o = this.options; + + // bail if the multiselectopen event returns false, this widget is disabled, or is already open + if( this._trigger('beforeopen') === false || button.hasClass('ui-state-disabled') || this._isOpen ){ + return; + } + + var $container = menu.find('ul:last'), + effect = o.show, + pos = button.position(); + + // figure out opening effects/speeds + if( $.isArray(o.show) ){ + effect = o.show[0]; + speed = o.show[1] || self.speed; + } + + // set the scroll of the checkbox container + $container.scrollTop(0).height(o.height); + + // position and show menu + if( $.ui.position && !$.isEmptyObject(o.position) ){ + o.position.of = o.position.of || button; + + menu + .show() + .position( o.position ) + .hide() + .show( effect, speed ); + + // if position utility is not available... + } else { + menu.css({ + top: pos.top+button.outerHeight(), + left: pos.left + }).show( effect, speed ); + } + + // select the first option + // triggering both mouseover and mouseover because 1.4.2+ has a bug where triggering mouseover + // will actually trigger mouseenter. the mouseenter trigger is there for when it's eventually fixed + this.labels.eq(0).trigger('mouseover').trigger('mouseenter').find('input').trigger('focus'); + + button.addClass('ui-state-active'); + this._isOpen = true; + this._trigger('open'); + }, + + // close the menu + close: function(){ + if(this._trigger('beforeclose') === false){ + return; + } + + var o = this.options, effect = o.hide, speed = this.speed; + + // figure out opening effects/speeds + if( $.isArray(o.hide) ){ + effect = o.hide[0]; + speed = o.hide[1] || this.speed; + } + + this.menu.hide(effect, speed); + this.button.removeClass('ui-state-active').trigger('blur').trigger('mouseleave'); + this._isOpen = false; + this._trigger('close'); + }, + + enable: function(){ + this._toggleDisabled(false); + }, + + disable: function(){ + this._toggleDisabled(true); + }, + + checkAll: function( e ){ + this._toggleChecked(true); + this._trigger('checkAll'); + }, + + uncheckAll: function(){ + this._toggleChecked(false); + this._trigger('uncheckAll'); + }, + + getChecked: function(){ + return this.menu.find('input').filter(':checked'); + }, + + destroy: function(){ + // remove classes + data + $.Widget.prototype.destroy.call( this ); + + this.button.remove(); + this.menu.remove(); + this.element.show(); + + return this; + }, + + isOpen: function(){ + return this._isOpen; + }, + + widget: function(){ + return this.menu; + }, + + // react to option changes after initialization + _setOption: function( key, value ){ + var menu = this.menu; + + switch(key){ + case 'header': + menu.find('div.ui-multiselect-header')[ value ? 'show' : 'hide' ](); + break; + case 'checkAllText': + menu.find('a.ui-multiselect-all span').eq(-1).text(value); + break; + case 'uncheckAllText': + menu.find('a.ui-multiselect-none span').eq(-1).text(value); + break; + case 'height': + menu.find('ul:last').height( parseInt(value,10) ); + break; + case 'minWidth': + this.options[ key ] = parseInt(value,10); + this._setButtonWidth(); + this._setMenuWidth(); + break; + case 'selectedText': + case 'selectedList': + case 'noneSelectedText': + this.options[key] = value; // these all needs to update immediately for the update() call + this.update(); + break; + case 'classes': + menu.add(this.button).removeClass(this.options.classes).addClass(value); + break; + } + + $.Widget.prototype._setOption.apply( this, arguments ); + } +}); + +})(jQuery); diff --git a/lib/base.php b/lib/base.php index 9542170df54..9b777800764 100644 --- a/lib/base.php +++ b/lib/base.php @@ -115,7 +115,7 @@ class OC{ OC_Util::addScript( "jquery-showpassword" ); OC_Util::addScript( "jquery-tipsy" ); OC_Util::addScript( "js" ); - OC_Util::addScript( "multiselect" ); + //OC_Util::addScript( "multiselect" ); OC_Util::addScript('search','result'); OC_Util::addStyle( "styles" ); OC_Util::addStyle( "multiselect" ); |