From 3096bd2b6c640d3252c9af3f16218b07e377f649 Mon Sep 17 00:00:00 2001 From: Cameron Date: Fri, 15 Mar 2013 20:44:37 -0700 Subject: [PATCH] Changed to bootstrap tags (instead of jquery-ui) --- e107_admin/header.php | 8 +- e107_themes/bootstrap/admin_style.css | 22 ++ e107_web/js/bootstrap-tag/bootstrap-tag.js | 193 ++++++++++ e107_web/js/core/admin.jquery.js | 2 +- e107_web/js/tags/jquery.tagit.css | 55 --- e107_web/js/tags/jquery.tagit.js | 394 --------------------- 6 files changed, 221 insertions(+), 453 deletions(-) create mode 100644 e107_web/js/bootstrap-tag/bootstrap-tag.js delete mode 100644 e107_web/js/tags/jquery.tagit.css delete mode 100644 e107_web/js/tags/jquery.tagit.js diff --git a/e107_admin/header.php b/e107_admin/header.php index 7e084b64d..d7d10ff02 100644 --- a/e107_admin/header.php +++ b/e107_admin/header.php @@ -76,9 +76,11 @@ function loadJSAddons() e107::js('core', 'password/jquery.pwdMeter.js', 'jquery', 2); - - e107::js("core", "tags/jquery.tagit.js","jquery",3); - e107::css('core', 'tags/jquery.tagit.css', 'jquery'); + // e107::css('core', 'bootstrap-tag/bootstrap-tag.css', 'jquery'); + e107::js('core', 'bootstrap-tag/bootstrap-tag.js', 'jquery', 2); + +// e107::js("core", "tags/jquery.tagit.js","jquery",3); +// e107::css('core', 'tags/jquery.tagit.css', 'jquery'); e107::css('core', 'core/admin.jquery.css', 'jquery'); e107::js("core", "core/admin.jquery.js","jquery",4); // Load all default functions. diff --git a/e107_themes/bootstrap/admin_style.css b/e107_themes/bootstrap/admin_style.css index b99c9cdfe..e13249675 100644 --- a/e107_themes/bootstrap/admin_style.css +++ b/e107_themes/bootstrap/admin_style.css @@ -758,6 +758,28 @@ ul#e-latest { line-height:17px } ul#e-latest li a span.badge { float:right; } ul#e-latest li a:hover { text-decoration: none; } +/* Bootstrap tags */ +.tags { + display: inline-block; +} + +.tag { + margin-right:5px; + display: inline-block; + float: none; + margin-left: 0; + vertical-align:top; + margin-top:3px; + +} + +span.tag button.close { + float: none; + padding-left:5px; +} + + + /* body { background-color: rgb(68, 68, 68); } diff --git a/e107_web/js/bootstrap-tag/bootstrap-tag.js b/e107_web/js/bootstrap-tag/bootstrap-tag.js new file mode 100644 index 000000000..7c54becfe --- /dev/null +++ b/e107_web/js/bootstrap-tag/bootstrap-tag.js @@ -0,0 +1,193 @@ +/* ========================================================== + * bootstrap-tag.js v2.2.2 + * https://github.com/fdeschenes/bootstrap-tag + * ========================================================== + * Copyright 2012 Francois Deschenes. + * + * 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. + * ========================================================== */ + +// https://github.com/soliantconsulting/tagmanager/blob/master/tagmanager.js + +!function ( $ ) { + + 'use strict' // jshint ;_; + + var Tag = function ( element, options ) { + this.element = $(element) + this.options = $.extend(true, {}, $.fn.tag.defaults, options) + this.values = $.grep($.map(this.element.val().split(','), $.trim), function ( value ) { return value.length > 0 }) + this.show() + } + + Tag.prototype = { + constructor: Tag + + , show: function () { + var that = this + + that.element.parent().prepend(that.element.detach().attr('type', 'hidden')) + that.element + .wrap($('
')) + .parent() + .on('click', function () { + that.input.focus() + }) + + if (that.values.length) { + $.each(that.values, function () { + that.createBadge(this) + }) + } + + that.input = $('') + .attr('placeholder', that.options.placeholder) + .insertAfter(that.element) + .on('focus', function () { + that.element.parent().addClass('tags-hover') + }) + .on('blur', function () { + that.process() + that.element.parent().removeClass('tags-hover') + that.element.siblings('.tag').removeClass('tag-important') + }) + .on('keydown', function ( event ) { + if ( event.keyCode == 188 || event.keyCode == 13 || event.keyCode == 9 ) { + if ( $.trim($(this).val()) && ( !that.element.siblings('.typeahead').length || that.element.siblings('.typeahead').is(':hidden') ) ) { + if ( event.keyCode != 9 ) event.preventDefault() + that.process() + } else if ( event.keyCode == 188 ) { + if ( !that.element.siblings('.typeahead').length || that.element.siblings('.typeahead').is(':hidden') ) { + event.preventDefault() + } else { + that.input.data('typeahead').select() + event.stopPropagation() + event.preventDefault() + } + } + } else if ( !$.trim($(this).val()) && event.keyCode == 8 ) { + var count = that.element.siblings('.tag').length + if (count) { + var tag = that.element.siblings('.tag:eq(' + (count - 1) + ')') + if (tag.hasClass('tag-important')) that.remove(count - 1) + else tag.addClass('tag-important') + } + } else { + that.element.siblings('.tag').removeClass('tag-important') + } + }) + .typeahead({ + source: that.options.source + , matcher: function ( value ) { + return ~value.toLowerCase().indexOf(this.query.toLowerCase()) && (that.inValues(value) == -1 || that.options.allowDuplicates) + } + , updater: $.proxy(that.add, that) + }) + } + , inValues: function ( value ) { + if (this.options.caseInsensitive) { + var index = -1 + $.each(this.values, function (indexInArray, valueOfElement) { + if ( valueOfElement.toLowerCase() == value.toLowerCase() ) { + index = indexInArray + return false + } + }) + return index + } else { + return $.inArray(value, this.values) + } + } + , createBadge: function ( value ) { + var that = this + + $('') + .text(value) + .append($('') + .on('click', function () { + that.remove(that.element.siblings('.tag').index($(this).closest('.tag'))) + }) + ) + .insertBefore(that.element) + } + , add: function ( value ) { + var that = this + + if ( !that.options.allowDuplicates ) { + var index = that.inValues(value) + if ( index != -1 ) { + var badge = that.element.siblings('.tag:eq(' + index + ')') + badge.addClass('tag-warning') + setTimeout(function () { + $(badge).removeClass('tag-warning') + }, 500) + return + } + } + + this.values.push(value) + this.createBadge(value) + + this.element.val(this.values.join(', ')) + } + , remove: function ( index ) { + if ( index >= 0 ) { + this.values.splice(index, 1) + this.element.siblings('.tag:eq(' + index + ')').remove() + this.element.val(this.values.join(', ')) + } + } + , process: function () { + var values = $.grep($.map(this.input.val().split(','), $.trim), function ( value ) { return value.length > 0 }), + that = this + $.each(values, function() { + that.add(this) + }) + this.input.val('') + } + } + + var old = $.fn.tag + + $.fn.tag = function ( option ) { + return this.each(function () { + var that = $(this) + , data = that.data('tag') + , options = typeof option == 'object' && option + if (!data) that.data('tag', (data = new Tag(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.tag.defaults = { + allowDuplicates: false + , caseInsensitive: true + , placeholder: '' + , source: [] + } + + $.fn.tag.Constructor = Tag + + $.fn.tag.noConflict = function () { + $.fn.tag = old + return this + } + + $(window).on('load', function () { + $('[data-provide="tag"]').each(function () { + var that = $(this) + if (that.data('tag')) return + that.tag(that.data()) + }) + }) +}(window.jQuery) \ No newline at end of file diff --git a/e107_web/js/core/admin.jquery.js b/e107_web/js/core/admin.jquery.js index 758043115..71c762bed 100644 --- a/e107_web/js/core/admin.jquery.js +++ b/e107_web/js/core/admin.jquery.js @@ -137,7 +137,7 @@ $(document).ready(function() }); - $(".e-tags").tagit(); + $(".e-tags").tag(); diff --git a/e107_web/js/tags/jquery.tagit.css b/e107_web/js/tags/jquery.tagit.css deleted file mode 100644 index 43f6ee7bd..000000000 --- a/e107_web/js/tags/jquery.tagit.css +++ /dev/null @@ -1,55 +0,0 @@ -ul.tagit { - padding: 1px 5px; - overflow: auto; - margin-left: inherit; /* usually we don't want the regular ul margins. */ - margin-right: inherit; - width:270px; -} -ul.tagit li { - display: block; - float: left; - margin: 2px 5px 2px 0; -} -ul.tagit li.tagit-choice { - padding: .2em 18px .2em .5em; - position: relative; - line-height: inherit; -} -ul.tagit li.tagit-new { - padding: .25em 4px .25em 0; -} - -ul.tagit li.tagit-choice a.tagit-label { - cursor: pointer; - text-decoration: none; -} -ul.tagit li.tagit-choice .tagit-close { - cursor: pointer; - position: absolute; - right: .1em; - top: 50%; - margin-top: -8px; -} - -/* used for some custom themes that don't need image icons */ -ul.tagit li.tagit-choice .tagit-close .text-icon { - display: none; -} - -ul.tagit li.tagit-choice input { - display: block; - float: left; - margin: 2px 5px 2px 0; -} -ul.tagit input[type="text"] { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; - - border: none; - margin: 0; - padding: 0; - width: inherit; - background-color: inherit; - outline: none; -} diff --git a/e107_web/js/tags/jquery.tagit.js b/e107_web/js/tags/jquery.tagit.js deleted file mode 100644 index bdfd73b6d..000000000 --- a/e107_web/js/tags/jquery.tagit.js +++ /dev/null @@ -1,394 +0,0 @@ -/* -* jQuery UI Tag-it! -* -* @version v2.0 (06/2011) -* -* Copyright 2011, Levy Carneiro Jr. -* Released under the MIT license. -* http://aehlke.github.com/tag-it/LICENSE -* -* Homepage: -* http://aehlke.github.com/tag-it/ -* -* Authors: -* Levy Carneiro Jr. -* Martin Rehfeld -* Tobias Schmidt -* Skylar Challand -* Alex Ehlke -* -* Maintainer: -* Alex Ehlke - Twitter: @aehlke -* -* Dependencies: -* jQuery v1.4+ -* jQuery UI v1.8+ -*/ -(function($) { - - $.widget('ui.tagit', { - options: { - itemName : 'item', - fieldName : 'tags', - availableTags : [], - tagSource : null, - removeConfirmation: false, - caseSensitive : true, - placeholderText : null, - - // When enabled, quotes are not neccesary - // for inputting multi-word tags. - allowSpaces: false, - - // Whether to animate tag removals or not. - animate: true, - - // The below options are for using a single field instead of several - // for our form values. - // - // When enabled, will use a single hidden field for the form, - // rather than one per tag. It will delimit tags in the field - // with singleFieldDelimiter. - // - // The easiest way to use singleField is to just instantiate tag-it - // on an INPUT element, in which case singleField is automatically - // set to true, and singleFieldNode is set to that element. This - // way, you don't need to fiddle with these options. - singleField: false, - - singleFieldDelimiter: ',', - - // Set this to an input DOM node to use an existing form field. - // Any text in it will be erased on init. But it will be - // populated with the text of tags as they are created, - // delimited by singleFieldDelimiter. - // - // If this is not set, we create an input node for it, - // with the name given in settings.fieldName, - // ignoring settings.itemName. - singleFieldNode: null, - - // Optionally set a tabindex attribute on the input that gets - // created for tag-it. - tabIndex: null, - - - // Event callbacks. - onTagAdded : null, - onTagRemoved: null, - onTagClicked: null - }, - - - _create: function() { - // for handling static scoping inside callbacks - var that = this; - - // There are 2 kinds of DOM nodes this widget can be instantiated on: - // 1. UL, OL, or some element containing either of these. - // 2. INPUT, in which case 'singleField' is overridden to true, - // a UL is created and the INPUT is hidden. - if (this.element.is('input')) { - this.tagList = $('
    ').insertAfter(this.element); - this.options.singleField = true; - this.options.singleFieldNode = this.element; - this.element.css('display', 'none'); - } else { - this.tagList = this.element.find('ul, ol').andSelf().last(); - } - - this._tagInput = $('').addClass('ui-widget-content'); - - if (this.options.tabIndex) { - - this._tagInput.attr('tabindex', this.options.tabIndex); - } - if (this.options.placeholderText) { - this._tagInput.attr('placeholder', this.options.placeholderText); - } - - this.options.tagSource = this.options.tagSource || function(search, showChoices) { - var filter = search.term.toLowerCase(); - var choices = $.grep(this.options.availableTags, function(element) { - // Only match autocomplete options that begin with the search term. - // (Case insensitive.) - return (element.toLowerCase().indexOf(filter) === 0); - }); - showChoices(this._subtractArray(choices, this.assignedTags())); - }; - - // Bind tagSource callback functions to this context. - if ($.isFunction(this.options.tagSource)) { - this.options.tagSource = $.proxy(this.options.tagSource, this); - } - - this.tagList - .addClass('tagit') - .addClass('ui-widget ui-widget-content ui-corner-all') - // Create the input field. - .append($('
  • ').append(this._tagInput)) - .click(function(e) { - var target = $(e.target); - if (target.hasClass('tagit-label')) { - that._trigger('onTagClicked', e, target.closest('.tagit-choice')); - } else { - // Sets the focus() to the input field, if the user - // clicks anywhere inside the UL. This is needed - // because the input field needs to be of a small size. - that._tagInput.focus(); - } - }); - - // Add existing tags from the list, if any. - this.tagList.children('li').each(function() { - if (!$(this).hasClass('tagit-new')) { - that.createTag($(this).html(), $(this).attr('class')); - $(this).remove(); - } - }); - - // Single field support. - if (this.options.singleField) { - if (this.options.singleFieldNode) { - // Add existing tags from the input field. - var node = $(this.options.singleFieldNode); - var tags = node.val().split(this.options.singleFieldDelimiter); - node.val(''); - $.each(tags, function(index, tag) { - that.createTag(tag); - }); - } else { - // Create our single field input after our list. - this.options.singleFieldNode = this.tagList.after(''); - } - } - - // Events. - this._tagInput - .keydown(function(event) { - // Backspace is not detected within a keypress, so it must use keydown. - if (event.which == $.ui.keyCode.BACKSPACE && that._tagInput.val() === '') { - var tag = that._lastTag(); - if (!that.options.removeConfirmation || tag.hasClass('remove')) { - // When backspace is pressed, the last tag is deleted. - that.removeTag(tag); - } else if (that.options.removeConfirmation) { - tag.addClass('remove ui-state-highlight'); - } - } else if (that.options.removeConfirmation) { - that._lastTag().removeClass('remove ui-state-highlight'); - } - - // Comma/Space/Enter are all valid delimiters for new tags, - // except when there is an open quote or if setting allowSpaces = true. - // Tab will also create a tag, unless the tag input is empty, in which case it isn't caught. - if ( - event.which == $.ui.keyCode.COMMA || - event.which == $.ui.keyCode.ENTER || - ( - event.which == $.ui.keyCode.TAB && - that._tagInput.val() !== '' - ) || - ( - event.which == $.ui.keyCode.SPACE && - that.options.allowSpaces !== true && - ( - $.trim(that._tagInput.val()).replace( /^s*/, '' ).charAt(0) != '"' || - ( - $.trim(that._tagInput.val()).charAt(0) == '"' && - $.trim(that._tagInput.val()).charAt($.trim(that._tagInput.val()).length - 1) == '"' && - $.trim(that._tagInput.val()).length - 1 !== 0 - ) - ) - ) - ) { - event.preventDefault(); - that.createTag(that._cleanedInput()); - - // The autocomplete doesn't close automatically when TAB is pressed. - // So let's ensure that it closes. - that._tagInput.autocomplete('close'); - } - }).blur(function(e){ - // Create a tag when the element loses focus (unless it's empty). - that.createTag(that._cleanedInput()); - }); - - - // Autocomplete. - if (this.options.availableTags || this.options.tagSource) { - this._tagInput.autocomplete({ - source: this.options.tagSource, - select: function(event, ui) { - // Delete the last tag if we autocomplete something despite the input being empty - // This happens because the input's blur event causes the tag to be created when - // the user clicks an autocomplete item. - // The only artifact of this is that while the user holds down the mouse button - // on the selected autocomplete item, a tag is shown with the pre-autocompleted text, - // and is changed to the autocompleted text upon mouseup. - if (that._tagInput.val() === '') { - that.removeTag(that._lastTag(), false); - } - that.createTag(ui.item.value); - // Preventing the tag input to be updated with the chosen value. - return false; - } - }); - } - }, - - _cleanedInput: function() { - // Returns the contents of the tag input, cleaned and ready to be passed to createTag - return $.trim(this._tagInput.val().replace(/^"(.*)"$/, '$1')); - }, - - _lastTag: function() { - return this.tagList.children('.tagit-choice:last'); - }, - - assignedTags: function() { - // Returns an array of tag string values - var that = this; - var tags = []; - if (this.options.singleField) { - tags = $(this.options.singleFieldNode).val().split(this.options.singleFieldDelimiter); - if (tags[0] === '') { - tags = []; - } - } else { - this.tagList.children('.tagit-choice').each(function() { - tags.push(that.tagLabel(this)); - }); - } - return tags; - }, - - _updateSingleTagsField: function(tags) { - // Takes a list of tag string values, updates this.options.singleFieldNode.val to the tags delimited by this.options.singleFieldDelimiter - $(this.options.singleFieldNode).val(tags.join(this.options.singleFieldDelimiter)); - }, - - _subtractArray: function(a1, a2) { - var result = []; - for (var i = 0; i < a1.length; i++) { - if ($.inArray(a1[i], a2) == -1) { - result.push(a1[i]); - } - } - return result; - }, - - tagLabel: function(tag) { - // Returns the tag's string label. - if (this.options.singleField) { - return $(tag).children('.tagit-label').text(); - } else { - return $(tag).children('input').val(); - } - }, - - _isNew: function(value) { - var that = this; - var isNew = true; - this.tagList.children('.tagit-choice').each(function(i) { - if (that._formatStr(value) == that._formatStr(that.tagLabel(this))) { - isNew = false; - return false; - } - }); - return isNew; - }, - - _formatStr: function(str) { - if (this.options.caseSensitive) { - return str; - } - return $.trim(str.toLowerCase()); - }, - - createTag: function(value, additionalClass) { - var that = this; - // Automatically trims the value of leading and trailing whitespace. - value = $.trim(value); - - if (!this._isNew(value) || value === '') { - return false; - } - - var label = $(this.options.onTagClicked ? '' : '').text(value); - - // Create tag. - var tag = $('
  • ') - .addClass('tagit-choice ui-widget-content ui-state-default ui-corner-all') - .addClass(additionalClass) - .append(label); - - // Button for removing the tag. - var removeTagIcon = $('') - .addClass('ui-icon ui-icon-close'); - var removeTag = $('\xd7') // \xd7 is an X - .addClass('tagit-close') - .append(removeTagIcon) - .click(function(e) { - // Removes a tag when the little 'x' is clicked. - that.removeTag(tag); - }); - tag.append(removeTag); - - // Unless options.singleField is set, each tag has a hidden input field inline. - if (this.options.singleField) { - var tags = this.assignedTags(); - tags.push(value); - this._updateSingleTagsField(tags); - } else { - var escapedValue = label.html(); - tag.append(''); - } - - this._trigger('onTagAdded', null, tag); - - // Cleaning the input. - this._tagInput.val(''); - - // insert tag - this._tagInput.parent().before(tag); - }, - - removeTag: function(tag, animate) { - animate = animate || this.options.animate; - - tag = $(tag); - - this._trigger('onTagRemoved', null, tag); - - if (this.options.singleField) { - var tags = this.assignedTags(); - var removedTagLabel = this.tagLabel(tag); - tags = $.grep(tags, function(el){ - return el != removedTagLabel; - }); - this._updateSingleTagsField(tags); - } - // Animate the removal. - if (animate) { - tag.fadeOut('fast').hide('blind', {direction: 'horizontal'}, 'fast', function(){ - tag.remove(); - }).dequeue(); - } else { - tag.remove(); - } - }, - - removeAll: function() { - // Removes all tags. - var that = this; - this.tagList.children('.tagit-choice').each(function(index, tag) { - that.removeTag(tag, false); - }); - } - - }); - -})(jQuery); - -