提交 8dcd03f2 编写于 作者: J Jacob Schatz

initial new menu

上级 d33cc4e5
......@@ -16,12 +16,12 @@
else
$(this).html totalIssues - 1
$("body").on "click", ".issues-other-filters .dropdown-menu a", ->
$('.issues-list').block(
message: null,
overlayCSS:
backgroundColor: '#DDD'
opacity: .4
)
# $('.issues-list').block(
# message: null,
# overlayCSS:
# backgroundColor: '#DDD'
# opacity: .4
# )
reload: ->
Issues.initSelects()
......
//= require sifter.js
/**
* multiawesome.js (v0.12.1)
* Copyright (c) 2015 Jacob Schatz & contributors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy of the License at:
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
* ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*
* @author Jacob Schatz <jschatz@gitlab.com>
*/
/*jshint curly:false */
/*jshint browser:true */
(function ( $ ) {
$.fn.multiawesome = function( settings ) {
settings = settings || {};
var MultiAwesome = {
searchTemplate: '<li><div class="input-with-icon"><i class="fa fa-search"></i><input type="text" id="multiawesome-search-input" /></div></li>',
itemContainerTemplate: '<li class="dropdown-multi-menu-selections"><ul></ul></li>',
itemTemplate: '<li><a href="#" class="item" tabIndex="-1"><input type="checkbox" name="{{name}}" value="{{data}}"/>{{label}}</a></li>',
seperatorTemplate: '<li role="separator" class="divider"></li>',
titleTemplate: '<li class=dropdown-multi-menu-title><div class=dropdown-multi-menu-title-area><h3>{{title}}</h3></div></li>',
categoryContainerTemplate: '<li class=dropdown-multi-menu-category><ul></ul></li>',
categoryItemTemplate: '<li><a href="#" class="category" tabIndex="-1"><input type="checkbox" value="{{category}}"/>{{category}}</a></li>',
tipTemplate: '<li class=dropdown-multi-menu-tip><div class=dropdown-multi-menu-tip-area><p>{{tip}}</p></div></li>',
minSearchLength: 2,
};
return this.each(function() {
var self = this,
categories = [],
$self = $(self),
$form = $(self).closest('form'),
$itemContainer,
$itemContainerUL,
itemTemplate,
itemContainerTemplate,
categoriesSet = false,
selectedItems = [],
selectedCategories = [],
$searchInput,
multiple = typeof $self.attr('data-multiple') !== 'undefined',
currentData = settings.data || $self.data('data'),
inputName = $(self).data('name'),
sifter,
dataObject = {
label: 'label',
data: 'data',
category: 'category'
};
if( self.tagName !== 'UL') {
return;
}
var prepareDropdown = function() {
var placeholder = $self.data('placeholder');
if( typeof settings.searchTemplate !== 'undefined' ) {
MultiAwesome.searchTemplate = settings.searchTemplate;
}
$self.prepend(MultiAwesome.searchTemplate);
if( placeholder ) {
$('#multiawesome-search-input').prop( 'placeholder', placeholder );
}
};
var attachBtnListeners = function() {
$( 'ul.dropdown-multi-menu' ).on( 'click', 'li.dropdown-multi-menu-category a' , dropdownCategoryLinkClicked );
$( 'ul.dropdown-multi-menu' ).on( 'click', 'li.dropdown-multi-menu-selections a', dropdownSelectionLinkClicked );
$searchInput = $('#multiawesome-search-input');
$searchInput.on( 'keydown keyup update', inputSearched );
};
var parseSearchResults = function(results) {
var finalData = [];
results.forEach( function( result ) {
finalData.push(currentData[result.id]);
});
renderData( finalData );
};
var inputSearched = function() {
var minSearchLength = settings.minSearchLength || MultiAwesome.minSearchLength;
//remove current hidden inputs
$('input[type="hidden"][name="' + inputName + '"]').remove();
if( $searchInput.val().length > minSearchLength ) {
var results = sifter.search($searchInput.val(), {
fields: [dataObject.label],
sort: [{field: dataObject.label, direction: 'asc'}]
});
parseSearchResults(results.items);
} else {
renderData( currentData );
}
};
var configureData = function() {
if ( typeof settings.itemLabelTitle !== 'undefined' ) {
dataObject.label = settings.itemLabelTitle;
}
if ( typeof settings.itemDataTitle !== 'undefined' ) {
dataObject.data = settings.itemDataTitle;
}
if ( typeof settings.itemCategoryTitle !== 'undefined' ) {
dataObject.category = settings.itemCategoryTitle;
}
};
var addCategories = function() {
var $categoryContainer;
var $categoryContainerUL;
if( categories.length ) {
if( typeof settings.categoryContainerTemplate !== 'undefined' ) {
$categoryContainer = $(settings.categoryContainerTemplate);
} else {
$categoryContainer = $(MultiAwesome.categoryContainerTemplate);
}
$categoryContainerUL = $categoryContainer.find('ul');
$self.prepend(MultiAwesome.seperatorTemplate);
categories.forEach(function( category ) {
$categoryContainerUL.prepend( MultiAwesome.categoryItemTemplate
.replace( /{{category}}/g, category ) );
});
$self.prepend($categoryContainer);
}
};
var addTitle = function() {
var titleTemplate;
var titleData = $self.data('title') || settings.title;
if( typeof titleData !== 'undefined') {
if(typeof settings.titleTemplate !== 'undefined') {
titleTemplate = settings.titleTemplate;
} else {
titleTemplate = MultiAwesome.titleTemplate;
}
$self.prepend(MultiAwesome.seperatorTemplate);
$self.prepend(titleTemplate
.replace(/{{title}}/g, titleData)
);
}
};
var addData = function(callback) {
function parseDataWhenReady() {
itemTemplate = MultiAwesome.itemTemplate;
itemContainerTemplate = MultiAwesome.itemContainerTemplate;
if( typeof settings.itemTemplate !== 'undefined' ) {
itemTemplate = settings.itemTemplate;
}
if( typeof settings.itemContainerTemplate !== 'undefined' ) {
itemContainerTemplate = settings.itemContainerTemplate;
}
$itemContainer = $(itemContainerTemplate);
$itemContainerUL = $itemContainer.find('ul');
sifter = new Sifter(currentData);
renderData( currentData,callback );
}
configureData();
if ( typeof currentData !== 'undefined' ) {
if ( typeof currentData === 'string') {
$.getJSON(currentData, function(data) {
currentData = data;
parseDataWhenReady();
});
} else if ( typeof currentData === 'object' ) {
parseDataWhenReady();
}
}
};
var renderData = function( data, callback ) {
selectedItems = [];
$itemContainerUL.empty();
var emptyObj = {};
var skipMatch = false;
if( !data.length ) {
emptyObj[dataObject.label] = 'No matches found';
emptyObj[dataObject.data] = '';
emptyObj[dataObject.category] = '';
data.push(emptyObj);
skipMatch = true;
}
data.forEach( function( item ) {
if( !categoriesSet && !skipMatch ) {
var addCategory = item[dataObject.category];
if( item.hasOwnProperty( dataObject.category ) && categories.indexOf( addCategory ) === -1 ) {
categories.push( addCategory );
}
} else {
// only do this if the categories are already set... they won't search categories on the first time.
if( selectedCategories.length &&
selectedCategories.indexOf(item[dataObject.category]) === -1 &&
!skipMatch) {
return;
}
}
$itemContainerUL.append(
itemTemplate
.replace(/{{data}}/g,item[dataObject.data])
.replace(/{{label}}/g,item[dataObject.label])
.replace(/{{name}}/g, '_' + inputName)
);
});
if( !categoriesSet ) {
$self.append($itemContainer);
}
if( categories.length ){
categoriesSet = true;
}
if( callback ) {
callback();
}
};
var addToForm = function( val ) {
$form.prepend('<input type="hidden" name="' + inputName + '" value="' + val + '" />');
};
var removeFromForm = function( val ) {
$form
.find('input[name="' + inputName + '"][value="' + val + '"]')
.remove();
};
/* * * * * * * * * * * * * * * */
/* listeners
/* * * * * * * * * * * * * * * */
var dropdownInputClicked = function( e ) {
return false;
};
var dropdownCategoryLinkClicked = function ( e ) {
var $target = $( e.currentTarget ),
$inp = $target.find( 'input' ),
val = $inp.val(),
i = selectedCategories.indexOf( val );
if ( i > -1 ) {
var spliced = selectedCategories.splice( i, 1 );
$target.removeClass('selected');
setTimeout( function() {
$inp.prop( 'checked', false );
}, 0);
} else {
selectedCategories.push( val );
$target.addClass('selected');
setTimeout( function() {
$inp.prop( 'checked', true );
}, 0);
}
inputSearched();
$( e.target ).blur();
return false;
};
var dropdownSelectionLinkClicked = function ( e ) {
var $target = $( e.currentTarget ),
$inp = $target.find( 'input' ),
val = $inp.val(),
i = selectedItems.indexOf( val );
if ( i > -1 ) {
var spliced = selectedItems.splice( i, 1 );
if( multiple ) {
removeFromForm( spliced );
} else {
$form
.find('input[name="' + inputName + '"]')
.remove();
}
$target.removeClass('selected');
setTimeout( function() {
$inp.prop( 'checked', false );
}, 0);
} else {
if( !multiple ) {
selectedItems = [];
$form
.find('input[name="' + inputName + '"]')
.remove();
$form
.find('input[name="_' + inputName + '"]')
.parent()
.removeClass('selected');
}
selectedItems.push( val );
addToForm( val );
$target.addClass('selected');
setTimeout( function() {
$inp.prop( 'checked', true );
}, 0);
}
$( e.target ).blur();
return false;
};
var addTip = function() {
var tipTemplate;
var tipData = $self.data('tip') || settings.tip;
if( typeof tipData !== 'undefined') {
if(typeof settings.tipTemplate !== 'undefined') {
tipTemplate = settings.tipTemplate;
} else {
tipTemplate = MultiAwesome.tipTemplate;
}
$self.append(MultiAwesome.seperatorTemplate);
$self.append(tipTemplate
.replace(/{{tip}}/g, tipData)
);
}
};
/* * * * * * * * * * * * * * * */
/* setup
/* * * * * * * * * * * * * * * */
var setup = function() {
addData(function(){
addCategories();
prepareDropdown();
addTitle();
attachBtnListeners();
addTip();
});
};
setup();
});
};
})( jQuery );
\ No newline at end of file
//= require sifter
/**
* multiawesome.js (v0.12.1)
* Copyright (c) 2015 Jacob Schatz & contributors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy of the License at:
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
* ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*
* @author Jacob Schatz <jschatz@gitlab.com>
*/
/*jshint curly:false */
/*jshint browser:true */
(function ( $ ) {
'use strict';
$.fn.multiawesome = function( settings ) {
settings = settings || {};
var MultiAwesome = {
searchTemplate: '<li><div class="input-with-icon"><i class="fa fa-search"></i><input type="text" id="multiawesome-search-input" /></div></li>',
itemContainerTemplate: '<li class="dropdown-multi-menu-selections"><ul></ul></li>',
itemTemplate: '<li><a href="#" class="item" tabIndex="-1"><input type="checkbox" name="{{name}}" value="{{data}}"/>{{label}}</a></li>',
seperatorTemplate: '<li role="separator" class="divider"></li>',
titleTemplate: '<li class=dropdown-multi-menu-title><div class=dropdown-multi-menu-title-area><h3>{{title}}</h3></div></li>',
categoryContainerTemplate: '<li class=dropdown-multi-menu-category><ul></ul></li>',
categoryItemTemplate: '<li><a href="#" class="category" tabIndex="-1"><input type="checkbox" value="{{category}}"/>{{category}}</a></li>',
tipTemplate: '<li class=dropdown-multi-menu-tip><div class=dropdown-multi-menu-tip-area><p>{{tip}}</p></div></li>',
minSearchLength: 2
};
return this.each(function() {
var self = this,
categories = [],
$self = $(self),
$form = $(self).closest('form'),
$itemContainer,
$itemContainerUL,
itemTemplate,
itemContainerTemplate,
categoriesSet = false,
selectedItems = [],
selectedCategories = [],
$searchInput,
onChange = settings.onChange || function(){},
multiple = typeof $self.attr('data-multiple') !== 'undefined',
currentData = settings.data || $self.data('data'),
inputName = $(self).data('name'),
sifter,
alwaysData = settings.always || [],
dataObject = {
label: 'label',
data: 'data',
category: 'category'
};
if( self.tagName !== 'UL') {
return;
}
var prepareDropdown = function() {
var placeholder = $self.data('placeholder');
if( typeof settings.searchTemplate !== 'undefined' ) {
MultiAwesome.searchTemplate = settings.searchTemplate;
}
$self.prepend(MultiAwesome.searchTemplate);
if( placeholder ) {
$('#multiawesome-search-input').prop( 'placeholder', placeholder );
}
};
var attachBtnListeners = function() {
$( 'ul.dropdown-multi-menu' ).on( 'click', 'li.dropdown-multi-menu-category a' , dropdownCategoryLinkClicked );
$( 'ul.dropdown-multi-menu' ).on( 'click', 'li.dropdown-multi-menu-selections a', dropdownSelectionLinkClicked );
$searchInput = $('#multiawesome-search-input');
$searchInput.on( 'keydown keyup update', inputSearched );
};
var parseSearchResults = function(results) {
var finalData = [];
results.forEach( function( result ) {
finalData.push(currentData[result.id]);
});
renderData( finalData );
};
var inputSearched = function() {
var minSearchLength = settings.minSearchLength || MultiAwesome.minSearchLength;
//remove current hidden inputs
$('input[type="hidden"][name="' + inputName + '"]').remove();
if( $searchInput.val().length > minSearchLength ) {
var results = sifter.search($searchInput.val(), {
fields: [dataObject.label],
sort: [{field: dataObject.label, direction: 'asc'}]
});
parseSearchResults(results.items);
} else {
renderData( currentData );
}
};
var configureData = function() {
if ( typeof settings.itemLabelTitle !== 'undefined' ) {
dataObject.label = settings.itemLabelTitle;
}
if ( typeof settings.itemDataTitle !== 'undefined' ) {
dataObject.data = settings.itemDataTitle;
}
if ( typeof settings.itemCategoryTitle !== 'undefined' ) {
dataObject.category = settings.itemCategoryTitle;
}
};
var addCategories = function() {
var $categoryContainer;
var $categoryContainerUL;
if( categories.length ) {
if( typeof settings.categoryContainerTemplate !== 'undefined' ) {
$categoryContainer = $(settings.categoryContainerTemplate);
} else {
$categoryContainer = $(MultiAwesome.categoryContainerTemplate);
}
$categoryContainerUL = $categoryContainer.find('ul');
$self.prepend(MultiAwesome.seperatorTemplate);
categories.forEach(function( category ) {
$categoryContainerUL.prepend( MultiAwesome.categoryItemTemplate
.replace( /\{\{category\}\}/g, category ) );
});
$self.prepend($categoryContainer);
}
};
var addTitle = function() {
var titleTemplate;
var titleData = $self.data('title') || settings.title;
if( typeof titleData !== 'undefined') {
if(typeof settings.titleTemplate !== 'undefined') {
titleTemplate = settings.titleTemplate;
} else {
titleTemplate = MultiAwesome.titleTemplate;
}
$self.prepend(MultiAwesome.seperatorTemplate);
$self.prepend(titleTemplate
.replace(/\{\{title\}\}/g, titleData)
);
}
};
var addData = function(callback) {
function parseDataWhenReady() {
itemTemplate = MultiAwesome.itemTemplate;
itemContainerTemplate = MultiAwesome.itemContainerTemplate;
if( typeof settings.itemTemplate !== 'undefined' ) {
itemTemplate = settings.itemTemplate;
}
if( typeof settings.itemContainerTemplate !== 'undefined' ) {
itemContainerTemplate = settings.itemContainerTemplate;
}
$itemContainer = $(itemContainerTemplate);
$itemContainerUL = $itemContainer.find('ul');
sifter = new Sifter(currentData);
renderData( currentData,callback );
}
configureData();
if ( typeof currentData !== 'undefined' ) {
if ( typeof currentData === 'string') {
$.getJSON(currentData, function(data) {
currentData = data;
parseDataWhenReady();
});
} else if ( typeof currentData === 'object' ) {
parseDataWhenReady();
}
}
};
var renderData = function( data, callback ) {
selectedItems = [];
$itemContainerUL.empty();
var emptyObj = {};
var skipMatch = false;
if( !data.length ) {
emptyObj[dataObject.label] = 'No matches found';
emptyObj[dataObject.data] = '';
emptyObj[dataObject.category] = '';
data.push(emptyObj);
skipMatch = true;
}
data = data.concat(alwaysData);
data.forEach( function( item ) {
if( !categoriesSet && !skipMatch ) {
var addCategory = item[dataObject.category];
if( item.hasOwnProperty( dataObject.category ) && categories.indexOf( addCategory ) === -1 ) {
categories.push( addCategory );
}
} else {
// only do this if the categories are already set... they won't search categories on the first time.
if( selectedCategories.length &&
selectedCategories.indexOf(item[dataObject.category]) === -1 &&
!skipMatch) {
return;
}
}
$itemContainerUL.append(
itemTemplate
.replace(/\{\{data\}\}/g,item[dataObject.data])
.replace(/\{\{label\}\}/g,item[dataObject.label])
.replace(/\{\{name\}\}/g, '_' + inputName)
);
});
if( !categoriesSet ) {
$self.append($itemContainer);
}
if( categories.length ){
categoriesSet = true;
}
if( callback ) {
callback();
}
};
var addToForm = function( val ) {
$form.prepend('<input type="hidden" name="' + inputName + '" value="' + val + '" />');
};
var removeFromForm = function( val ) {
$form
.find('input[name="' + inputName + '"][value="' + val + '"]')
.remove();
};
/* * * * * * * * * * * * * * * */
/* listeners
/* * * * * * * * * * * * * * * */
var dropdownInputClicked = function( e ) {
return false;
};
var dropdownCategoryLinkClicked = function ( e ) {
var $target = $( e.currentTarget ),
$inp = $target.find( 'input' ),
val = $inp.val(),
i = selectedCategories.indexOf( val );
e.preventDefault();
if ( i > -1 ) {
var spliced = selectedCategories.splice( i, 1 );
$target.removeClass('selected');
setTimeout( function() {
$inp.prop( 'checked', false );
}, 0);
} else {
selectedCategories.push( val );
$target.addClass('selected');
setTimeout( function() {
$inp.prop( 'checked', true );
}, 0);
}
inputSearched();
$( e.target ).blur();
return false;
};
var findItemWithData = function(searchData, id) {
var item = {};
for (var i = searchData.length - 1; i >= 0; i--) {
item = searchData[i];
if( item.hasOwnProperty(dataObject.data) && item[dataObject.data] == id ) {
return item;
}
};
return undefined;
};
var dropdownSelectionLinkClicked = function ( e ) {
var $target = $( e.currentTarget ),
$inp = $target.find( 'input' ),
findItemInData,
val = $inp.val(),
i = selectedItems.indexOf( val );
e.preventDefault();
if ( i > -1 ) {
var spliced = selectedItems.splice( i, 1 );
if( multiple ) {
removeFromForm( spliced );
} else {
$form
.find('input[name="' + inputName + '"]')
.remove();
}
$target.removeClass('selected');
setTimeout( function() {
$inp.prop( 'checked', false );
}, 0);
} else {
if( !multiple ) {
selectedItems = [];
$form
.find('input[name="' + inputName + '"]')
.remove();
$form
.find('input[name="_' + inputName + '"]')
.parent()
.removeClass('selected');
}
findItemInData = findItemWithData(currentData, val);
if( typeof findItemInData === 'undefined' ) {
findItemInData = findItemWithData(alwaysData, val)
}
onChange(findItemInData);
selectedItems.push( val );
addToForm( val );
$target.addClass('selected');
setTimeout( function() {
$inp.prop( 'checked', true );
}, 0);
}
if( multiple ) {
// close the dropdown if single selection
$( e.target ).blur();
return false;
} else {
var button = $self.prevAll('.dropdown-toggle');
$self.prevAll('.dropdown-toggle')
.contents()
.each(
function(){
if ( this.nodeType === 3 && this.nodeValue.trim() ) {
this.textContent = $target.text();
}
});
}
};
var addTip = function() {
var tipTemplate;
var tipData = $self.data('tip') || settings.tip;
if( typeof tipData !== 'undefined') {
if(typeof settings.tipTemplate !== 'undefined') {
tipTemplate = settings.tipTemplate;
} else {
tipTemplate = MultiAwesome.tipTemplate;
}
$self.append(MultiAwesome.seperatorTemplate);
$self.append(tipTemplate
.replace(/\{\{tip\}\}/g, tipData)
);
}
};
/* * * * * * * * * * * * * * * */
/* setup
/* * * * * * * * * * * * * * * */
var setup = function() {
addData(function(){
addCategories();
prepareDropdown();
addTitle();
attachBtnListeners();
addTip();
});
};
setup();
});
};
})( jQuery );
\ No newline at end of file
......@@ -49,3 +49,8 @@
* Styles for JS behaviors.
*/
@import "behaviors.scss";
/*
* Styles for multiawesome
*/
@import "multiawesome";
\ No newline at end of file
.open>.dropdown-multi-menu {
max-width: 320px;
border-radius: 0px;
}
.dropdown-multi-menu input[type='text'] {
margin: 0 5px;
width: 309px;
height: 35px;
padding-left: 6px;
}
.dropdown-multi-menu input[type='checkbox'] {
margin: 0 5px;
display: none;
}
.dropdown-multi-menu>li>a {
padding-left: 0;
}
.dropdown-multi-menu .dropdown-multi-menu-title-area h3 {
font-size: 15px;
text-align: center;
margin-top: 5px;
}
.dropdown-multi-menu .dropdown-multi-menu-title-area h3::after {
content: "";
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACGUlEQVQ4jZ2VMXbiMBCGf83KKcxzntOmI1VMEyj2BLpD9gRbwQVygeUCpMsdcgKfQaYJqeIu1RYGC/stNjNbJOaBY8hu/lrz69PoH0mJCBaLhVEArqMoxhf0vFgYARBFUawWT08my7KxiMD3/fhmOLz/H7PE2ruyLL8rpRCG4b0WEQjzeVXXxq3X59ba8zAMZ/1+Pz9l9PLyEiyXy0lRFGZb18bTOhYR6GgwiOdJcu3Wa9R1bZxz5r1mespwuVxOnHO/mBla69jv9R6jwSAmALgZDu9934+JCMyMoiiMtfYuTdOgbZSmaWCtvSuKwjAziOigVbpZGIbhDACKojCnSLMsOyTz/bipPTB879nUWgvnnNkjxdnZ2TMAbDab6zbZaDQ62FCjpS5SIgIAMDOOkTVSItLZ9CRJxnmez5gZzRqlFIgIQRBMhkfiRZ1uADzPeyUiiMiOTERARPA87/VY3VHDr+pDDxtVVXXJzLtjAm9HZmZUVXV5rO5DD9M0DbIsmzSXQkQ4dSntifpA2JWzdmxO5XRnuE92KmddOd0n3Rl+NgGNPpsoAoB5koy7yLpenH6/n49Go2l79udJMgaAbz9ub02+Wv2s69poreNer/cQhuHs4uJi0zbbV1mWcxHJt9sttnVtmPmPc+63VkpBEa205z36vh8fm4C2rq6ucgDTxFqUZbkiolwplavmCwDenvB/MWtr/wv5CwCanfXE6iK0AAAAAElFTkSuQmCC');
background-repeat: no-repeat;
background-size: 11px;
width: 12px;
height: 12px;
display: inline-block;
position: absolute;
right: 13px;
top: 13px;
cursor: pointer;
}
.dropdown-multi-menu .dropdown-multi-menu-selections {
max-height: 150px;
overflow-y: scroll;
margin-top: 15px;
}
.dropdown-multi-menu .dropdown-multi-menu-category ul{
padding-left: 15px;
list-style: none;
max-height: 65px;
overflow-y: scroll;
}
.dropdown-multi-menu .dropdown-multi-menu-selections ul{
padding-left: 15px;
list-style: none;
}
.dropdown-multi-menu .dropdown-multi-menu-selections li{
margin-bottom: 10px;
}
.dropdown-multi-menu .dropdown-multi-menu-selections ul a, .dropdown-multi-menu .dropdown-multi-menu-category ul a{
text-decoration: none;
color: #333;
display: inline-block;
width: 285px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
height: 30px;
padding-left: 30px;
}
.dropdown-multi-menu .dropdown-multi-menu-selections ul a.selected, .dropdown-multi-menu .dropdown-multi-menu-category ul a.selected {
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAYCAMAAADat72NAAABtlBMVEX////b29vc29vc3NzZ2dna2dnb2trY19fZ2NjV1dXW1tbT09PU09PV1NTR0dHS0dHS0tLPz8/Qz8/Q0NDNzc3Ozc3Ly8vMy8vMzMzJycnKycnKysrIyMjJyMjKyMjFxcXGxcXGxsbHxcXHxsbEw8PExMTFxMTBwcHBwsLCwcG/v7+9vb2+vr6/vr67u7u8vLy5ubm6ubm7ubm3t7e4t7e4uLi1tbW3tra0s7OysbGysrKzsbGvr6+wr6+urq6vrq6sq6utrKypqamrqqqsqqqop6epp6eqqKimpaWnpaWnpqako6OkpKSlo6OioaGjoqKkoqKgn5+goKChn5+hoKCenp6fnp6cm5ucnJydm5udnJyenJx+fX1/fHx/fX2Afn6Af3+Bf3+BgICCgICCgYGDgYGDgoKEgoKFgoKFg4OGhISGhYWHhYWIh4eJh4eJiIiJiYmKiIiLiYmLioqMioqMi4uNi4uNjIyOjIyPjY2Qjo6Qj4+SkJCSkZGTkZGTkpKUk5OVk5OVlJSWlZWXlZWYlpaYl5eYmJiZmJiZmZmamJibmZmbmpqcm5uenp6fn5+op6erqqouFWZ5AAAAXHRSTlMADw8PFhYWHR0kJCwsLDMzMzo6OkJCSUlJUFBQV1dXX19fX19mZmZtbW11fHx8g4OKioqSkpKZmaCoqKivr7a2vb3FxcXMzMzT09Pb29vi4uLp6enp8PD4+Pj4+E8lS9YAAAEjSURBVCjPY2DACYRtrDhwywralTZL45RldymLb5LEJctkWBOXHiSAS9q8OSOzxRiXrGJPWmqdNTcOWY3ggtQyN15cXvIpTCnxVcIhK+pYnZwZLYdDls22Nj2rywiHLKNeW2p8oxaMK6vGgiKt05edVGXPDOWJB7S6KyPJSgVnxZRb8sC4Co2JJV4icFkJl6KYXB8hOJ8/KiW5wl8TyuN0KonP81BEMs24Iye10A8S+Kwm1bGZESoobtHszkwtDtUGMS0aUjM7TdG8YhRZmJIdLc/IpNqWktpoxonuVeWw3OTC3gkT+/NTK525MINCN6QsNSuvND+93FUGW1CJeZekJiSn5wSKYw9KNc/q9IS8cH1cCYDPoT63XR13ypQwczbAEAQAnkJCZAp/V+QAAAAASUVORK5CYII=');
background-repeat: no-repeat;
background-size: 16px;
background-position: 2px 4px;
}
.dropdown-multi-menu .dropdown-multi-menu-tip-area {
margin: 10px;
text-align: left;
max-height: 40px;
overflow-y: scroll;
}
.dropdown-multi-menu .dropdown-multi-menu-tip-area p {
margin-bottom: 0;
}
.dropdown-multi-menu .input-with-icon {
position: relative;
margin: 10px 0;
}
.dropdown-multi-menu .input-with-icon i {
position: absolute;
right: 0;
padding: 10px 12px;
color: #817F7F;
pointer-events: none;
}
......@@ -42,6 +42,11 @@
class: 'select2 trigger-submit', include_blank: true,
data: {placeholder: 'Milestone'})
.filter-item.inline.people-filter.btn-group
%button.btn.btn-default.dropdown-toggle{ "data-toggle" => 'dropdown' }
People
%span.caret
%ul.dropdown-menu.dropdown-multi-menu
.filter-item.inline.labels-filter
= select_tag('label_name', projects_labels_options,
class: 'select2 trigger-submit', include_blank: true,
......@@ -70,3 +75,11 @@
event.preventDefault();
Turbolinks.visit(this.action + '&' + $(this).serialize());
});
$('ul.dropdown-multi-menu').multiawesome({
data: [{label:'milestone',data:1},{label:'no milestone',data:1}],
title: "Milestones",
onChange: function(item) {
console.log("changed",item)
}
});
此差异已折叠。
/**
* sifter.js
* Copyright (c) 2013 Brian Reavis & contributors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy of the License at:
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
* ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*
* @author Brian Reavis <brian@thirdroute.com>
*/
(function(root, factory) {
if (typeof define === 'function' && define.amd) {
define(factory);
} else if (typeof exports === 'object') {
module.exports = factory();
} else {
root.Sifter = factory();
}
}(this, function() {
/**
* Textually searches arrays and hashes of objects
* by property (or multiple properties). Designed
* specifically for autocomplete.
*
* @constructor
* @param {array|object} items
* @param {object} items
*/
var Sifter = function(items, settings) {
this.items = items;
this.settings = settings || {diacritics: true};
};
/**
* Splits a search string into an array of individual
* regexps to be used to match results.
*
* @param {string} query
* @returns {array}
*/
Sifter.prototype.tokenize = function(query) {
query = trim(String(query || '').toLowerCase());
if (!query || !query.length) return [];
var i, n, regex, letter;
var tokens = [];
var words = query.split(/ +/);
for (i = 0, n = words.length; i < n; i++) {
regex = escape_regex(words[i]);
if (this.settings.diacritics) {
for (letter in DIACRITICS) {
if (DIACRITICS.hasOwnProperty(letter)) {
regex = regex.replace(new RegExp(letter, 'g'), DIACRITICS[letter]);
}
}
}
tokens.push({
string : words[i],
regex : new RegExp(regex, 'i')
});
}
return tokens;
};
/**
* Iterates over arrays and hashes.
*
* ```
* this.iterator(this.items, function(item, id) {
* // invoked for each item
* });
* ```
*
* @param {array|object} object
*/
Sifter.prototype.iterator = function(object, callback) {
var iterator;
if (is_array(object)) {
iterator = Array.prototype.forEach || function(callback) {
for (var i = 0, n = this.length; i < n; i++) {
callback(this[i], i, this);
}
};
} else {
iterator = function(callback) {
for (var key in this) {
if (this.hasOwnProperty(key)) {
callback(this[key], key, this);
}
}
};
}
iterator.apply(object, [callback]);
};
/**
* Returns a function to be used to score individual results.
*
* Good matches will have a higher score than poor matches.
* If an item is not a match, 0 will be returned by the function.
*
* @param {object|string} search
* @param {object} options (optional)
* @returns {function}
*/
Sifter.prototype.getScoreFunction = function(search, options) {
var self, fields, tokens, token_count;
self = this;
search = self.prepareSearch(search, options);
tokens = search.tokens;
fields = search.options.fields;
token_count = tokens.length;
/**
* Calculates how close of a match the
* given value is against a search token.
*
* @param {mixed} value
* @param {object} token
* @return {number}
*/
var scoreValue = function(value, token) {
var score, pos;
if (!value) return 0;
value = String(value || '');
pos = value.search(token.regex);
if (pos === -1) return 0;
score = token.string.length / value.length;
if (pos === 0) score += 0.5;
return score;
};
/**
* Calculates the score of an object
* against the search query.
*
* @param {object} token
* @param {object} data
* @return {number}
*/
var scoreObject = (function() {
var field_count = fields.length;
if (!field_count) {
return function() { return 0; };
}
if (field_count === 1) {
return function(token, data) {
return scoreValue(data[fields[0]], token);
};
}
return function(token, data) {
for (var i = 0, sum = 0; i < field_count; i++) {
sum += scoreValue(data[fields[i]], token);
}
return sum / field_count;
};
})();
if (!token_count) {
return function() { return 0; };
}
if (token_count === 1) {
return function(data) {
return scoreObject(tokens[0], data);
};
}
if (search.options.conjunction === 'and') {
return function(data) {
var score;
for (var i = 0, sum = 0; i < token_count; i++) {
score = scoreObject(tokens[i], data);
if (score <= 0) return 0;
sum += score;
}
return sum / token_count;
};
} else {
return function(data) {
for (var i = 0, sum = 0; i < token_count; i++) {
sum += scoreObject(tokens[i], data);
}
return sum / token_count;
};
}
};
/**
* Returns a function that can be used to compare two
* results, for sorting purposes. If no sorting should
* be performed, `null` will be returned.
*
* @param {string|object} search
* @param {object} options
* @return function(a,b)
*/
Sifter.prototype.getSortFunction = function(search, options) {
var i, n, self, field, fields, fields_count, multiplier, multipliers, get_field, implicit_score, sort;
self = this;
search = self.prepareSearch(search, options);
sort = (!search.query && options.sort_empty) || options.sort;
/**
* Fetches the specified sort field value
* from a search result item.
*
* @param {string} name
* @param {object} result
* @return {mixed}
*/
get_field = function(name, result) {
if (name === '$score') return result.score;
return self.items[result.id][name];
};
// parse options
fields = [];
if (sort) {
for (i = 0, n = sort.length; i < n; i++) {
if (search.query || sort[i].field !== '$score') {
fields.push(sort[i]);
}
}
}
// the "$score" field is implied to be the primary
// sort field, unless it's manually specified
if (search.query) {
implicit_score = true;
for (i = 0, n = fields.length; i < n; i++) {
if (fields[i].field === '$score') {
implicit_score = false;
break;
}
}
if (implicit_score) {
fields.unshift({field: '$score', direction: 'desc'});
}
} else {
for (i = 0, n = fields.length; i < n; i++) {
if (fields[i].field === '$score') {
fields.splice(i, 1);
break;
}
}
}
multipliers = [];
for (i = 0, n = fields.length; i < n; i++) {
multipliers.push(fields[i].direction === 'desc' ? -1 : 1);
}
// build function
fields_count = fields.length;
if (!fields_count) {
return null;
} else if (fields_count === 1) {
field = fields[0].field;
multiplier = multipliers[0];
return function(a, b) {
return multiplier * cmp(
get_field(field, a),
get_field(field, b)
);
};
} else {
return function(a, b) {
var i, result, a_value, b_value, field;
for (i = 0; i < fields_count; i++) {
field = fields[i].field;
result = multipliers[i] * cmp(
get_field(field, a),
get_field(field, b)
);
if (result) return result;
}
return 0;
};
}
};
/**
* Parses a search query and returns an object
* with tokens and fields ready to be populated
* with results.
*
* @param {string} query
* @param {object} options
* @returns {object}
*/
Sifter.prototype.prepareSearch = function(query, options) {
if (typeof query === 'object') return query;
options = extend({}, options);
var option_fields = options.fields;
var option_sort = options.sort;
var option_sort_empty = options.sort_empty;
if (option_fields && !is_array(option_fields)) options.fields = [option_fields];
if (option_sort && !is_array(option_sort)) options.sort = [option_sort];
if (option_sort_empty && !is_array(option_sort_empty)) options.sort_empty = [option_sort_empty];
return {
options : options,
query : String(query || '').toLowerCase(),
tokens : this.tokenize(query),
total : 0,
items : []
};
};
/**
* Searches through all items and returns a sorted array of matches.
*
* The `options` parameter can contain:
*
* - fields {string|array}
* - sort {array}
* - score {function}
* - filter {bool}
* - limit {integer}
*
* Returns an object containing:
*
* - options {object}
* - query {string}
* - tokens {array}
* - total {int}
* - items {array}
*
* @param {string} query
* @param {object} options
* @returns {object}
*/
Sifter.prototype.search = function(query, options) {
var self = this, value, score, search, calculateScore;
var fn_sort;
var fn_score;
search = this.prepareSearch(query, options);
options = search.options;
query = search.query;
// generate result scoring function
fn_score = options.score || self.getScoreFunction(search);
// perform search and sort
if (query.length) {
self.iterator(self.items, function(item, id) {
score = fn_score(item);
if (options.filter === false || score > 0) {
search.items.push({'score': score, 'id': id});
}
});
} else {
self.iterator(self.items, function(item, id) {
search.items.push({'score': 1, 'id': id});
});
}
fn_sort = self.getSortFunction(search, options);
if (fn_sort) search.items.sort(fn_sort);
// apply limits
search.total = search.items.length;
if (typeof options.limit === 'number') {
search.items = search.items.slice(0, options.limit);
}
return search;
};
// utilities
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
var cmp = function(a, b) {
if (typeof a === 'number' && typeof b === 'number') {
return a > b ? 1 : (a < b ? -1 : 0);
}
a = asciifold(String(a || ''));
b = asciifold(String(b || ''));
if (a > b) return 1;
if (b > a) return -1;
return 0;
};
var extend = function(a, b) {
var i, n, k, object;
for (i = 1, n = arguments.length; i < n; i++) {
object = arguments[i];
if (!object) continue;
for (k in object) {
if (object.hasOwnProperty(k)) {
a[k] = object[k];
}
}
}
return a;
};
var trim = function(str) {
return (str + '').replace(/^\s+|\s+$|/g, '');
};
var escape_regex = function(str) {
return (str + '').replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
};
var is_array = Array.isArray || (typeof $ !== 'undefined' && $.isArray) || function(object) {
return Object.prototype.toString.call(object) === '[object Array]';
};
var DIACRITICS = {
'a': '[aÀÁÂÃÄÅàáâãäåĀāąĄ]',
'c': '[cÇçćĆčČ]',
'd': '[dđĐďĎð]',
'e': '[eÈÉÊËèéêëěĚĒēęĘ]',
'i': '[iÌÍÎÏìíîïĪī]',
'l': '[lłŁ]',
'n': '[nÑñňŇńŃ]',
'o': '[oÒÓÔÕÕÖØòóôõöøŌō]',
'r': '[rřŘ]',
's': '[sŠšśŚ]',
't': '[tťŤ]',
'u': '[uÙÚÛÜùúûüůŮŪū]',
'y': '[yŸÿýÝ]',
'z': '[zŽžżŻźŹ]'
};
var asciifold = (function() {
var i, n, k, chunk;
var foreignletters = '';
var lookup = {};
for (k in DIACRITICS) {
if (DIACRITICS.hasOwnProperty(k)) {
chunk = DIACRITICS[k].substring(2, DIACRITICS[k].length - 1);
foreignletters += chunk;
for (i = 0, n = chunk.length; i < n; i++) {
lookup[chunk.charAt(i)] = k;
}
}
}
var regexp = new RegExp('[' + foreignletters + ']', 'g');
return function(str) {
return str.replace(regexp, function(foreignletter) {
return lookup[foreignletter];
}).toLowerCase();
};
})();
// export
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
return Sifter;
}));
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册