diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index f887aac0939..bd67a77fd10 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -523,6 +523,9 @@ Other Changes * SOLR-7877: TestAuthenticationFramework.testBasics to preserve/restore the original request(Username|Password) (Christine Poerschke) +* SOLR-7900: example/files improvements - added language detection and faceting, added title field, relocated .js files. + (Esther Quansah and Erik Hatcher) + ================== 5.2.1 ================== Consult the LUCENE_CHANGES.txt file for additional, low level, changes in this release diff --git a/solr/example/files/browse-resources/velocity/resources.properties b/solr/example/files/browse-resources/velocity/resources.properties index 4397bacb610..4cc15b2eee2 100644 --- a/solr/example/files/browse-resources/velocity/resources.properties +++ b/solr/example/files/browse-resources/velocity/resources.properties @@ -11,7 +11,8 @@ results_found_in=results found in {0}ms results_found=results found # Facets -top_phrases=Top Phrases +facet.top_phrases=Top Phrases +facet.language=Language # Type labels type.all=All Types @@ -21,4 +22,61 @@ type.pdf.label=PDF type.presentation.label=Presentation type.spreadsheet.label=Spreadsheet type.text.label=text +type.image.label=image type.unknown=unknown + +# Language code mappings +# - from https://code.google.com/p/language-detection/wiki/LanguageList +language.af=Afrikaans +language.ar=Arabic +language.bg=Bulgarian +language.bn=Bengali +language.cs=Czech +language.da=Danish +language.de=German +language.el=Greek +language.en=English +language.es=Spanish +language.et=Estonian +language.fa=Persian +language.fi=Finnish +language.fr=French +language.gu=Gujarati +language.he=Hebrew +language.hi=Hindi +language.hr=Croatian +language.hu=Hungarian +language.id=Indonesian +language.it=Italian +language.ja=Japanese +language.kn=Kannada +language.ko=Korean +language.lt=Lithuanian +language.lv=Latvian +language.mk=Macedonian +language.ml=Malayalam +language.mr=Marathi +language.ne=Nepali +language.nl=Dutch +language.no=Norwegian +language.pa=Punjabi +language.pl=Polish +language.pt=Portuguese +language.ro=Romanian +language.ru=Russian +language.sk=Slovak +language.sl=Slovene +language.so=Somali +language.sq=Albanian +language.sv=Swedish +language.sw=Swahili +language.ta=Tamil +language.te=Telugu +language.th=Thai +language.tl=Tagalog +language.tr=Turkish +language.uk=Ukrainian +language.ur=Urdu +language.vi=Vietnamese +language.zh-cn=Simplified Chinese +language.zh-tw=Traditional Chinese diff --git a/solr/example/files/browse-resources/velocity/resources_de_DE.properties b/solr/example/files/browse-resources/velocity/resources_de_DE.properties index bc5f72ccdc9..1837bf5ceb8 100644 --- a/solr/example/files/browse-resources/velocity/resources_de_DE.properties +++ b/solr/example/files/browse-resources/velocity/resources_de_DE.properties @@ -9,9 +9,10 @@ type.text.label=Text type.pdf.label=PDF type.html.label=HTML type.presentation.label=Pr\u00e4sentation +type.image.label=Bild type.doc.label=Dokument type.spreadsheet.label=Kalkulationstabelle type.unknown=unbekannt type.all=alle Arten -top_phrases=Schl\u00fcssels\u00e4tze -submit=einreichen \ No newline at end of file +facet.top_phrases=Schl\u00fcssels\u00e4tze +submit=einreichen diff --git a/solr/example/files/browse-resources/velocity/resources_fr_FR.properties b/solr/example/files/browse-resources/velocity/resources_fr_FR.properties index 049c2596f16..5b62757b79e 100644 --- a/solr/example/files/browse-resources/velocity/resources_fr_FR.properties +++ b/solr/example/files/browse-resources/velocity/resources_fr_FR.properties @@ -8,12 +8,13 @@ powered_file_search=Recherches de Fichiers type.text.label=Texte type.pdf.label=PDF type.html.label=HTML +type.image.label=Image type.presentation.label=Pr\u00e9sentation type.doc.label=Documents type.spreadsheet.label=Tableur -type.unknown=inconnu +type.unknown=Inconnu type.all=Tous les Types -top_phrases=Phrases Cl\u00e9s +facet.top_phrases=Phrases Cl\u00e9s submit=Recherche diff --git a/solr/example/files/conf/managed-schema b/solr/example/files/conf/managed-schema index 9b1b820ea71..24880b06690 100644 --- a/solr/example/files/conf/managed-schema +++ b/solr/example/files/conf/managed-schema @@ -408,11 +408,17 @@ - - + + - + + + + + + + @@ -424,6 +430,8 @@ + + @@ -504,4 +512,6 @@ + + \ No newline at end of file diff --git a/solr/example/files/conf/params.json b/solr/example/files/conf/params.json index e1af6792f7c..d93c1d9232f 100644 --- a/solr/example/files/conf/params.json +++ b/solr/example/files/conf/params.json @@ -9,13 +9,12 @@ "facet":"on", "facet.mincount":"1", "f.doc_type.facet.mincount":"0", - "facet.field":["text_shingles","{!ex=type}doc_type"], + "facet.field":["text_shingles","{!ex=type}doc_type", "language"], "f.text_shingles.facet.limit":10, "facet.query":"{!ex=type key=all_types}*:*", "f.doc_type.facet.missing":true, "":{"v":0}}, "browse":{ - "fq":"{!switch v=$type tag=type case='*:*' case.all='*:*' case.unknown='-doc_type:[* TO *]' default=$type_fq}", "type_fq":"{!field f=doc_type v=$type}", "hl":"on", "hl.fl":"content", diff --git a/solr/example/files/conf/solrconfig.xml b/solr/example/files/conf/solrconfig.xml index e2da4f27a0a..7565f809da3 100644 --- a/solr/example/files/conf/solrconfig.xml +++ b/solr/example/files/conf/solrconfig.xml @@ -82,6 +82,7 @@ + diff --git a/solr/example/files/conf/update-script.js b/solr/example/files/conf/update-script.js index d2ac002cee0..25bfa0360d3 100644 --- a/solr/example/files/conf/update-script.js +++ b/solr/example/files/conf/update-script.js @@ -5,7 +5,7 @@ function processAdd(cmd) { doc = cmd.solrDoc; // org.apache.solr.common.SolrInputDocument - id = doc.getFieldValue("id"); + var id = doc.getFieldValue("id"); logger.info("update-script#processAdd: id=" + id); // The idea here is to use the file's content_type value to diff --git a/solr/example/files/conf/velocity/dropit.js b/solr/example/files/conf/velocity/dropit.js index 3094414f0ab..e69de29bb2d 100644 --- a/solr/example/files/conf/velocity/dropit.js +++ b/solr/example/files/conf/velocity/dropit.js @@ -1,97 +0,0 @@ -/* - * Dropit v1.1.0 - * http://dev7studios.com/dropit - * - * Copyright 2012, Dev7studios - * Free to use and abuse under the MIT license. - * http://www.opensource.org/licenses/mit-license.php - */ - -;(function($) { - - $.fn.dropit = function(method) { - - var methods = { - - init : function(options) { - this.dropit.settings = $.extend({}, this.dropit.defaults, options); - return this.each(function() { - var $el = $(this), - el = this, - settings = $.fn.dropit.settings; - - // Hide initial submenus - $el.addClass('dropit') - .find('>'+ settings.triggerParentEl +':has('+ settings.submenuEl +')').addClass('dropit-trigger') - .find(settings.submenuEl).addClass('dropit-submenu').hide(); - - // Open on click - $el.off(settings.action).on(settings.action, settings.triggerParentEl +':has('+ settings.submenuEl +') > '+ settings.triggerEl +'', function(){ - // Close click menu's if clicked again - if(settings.action == 'click' && $(this).parents(settings.triggerParentEl).hasClass('dropit-open')){ - settings.beforeHide.call(this); - $(this).parents(settings.triggerParentEl).removeClass('dropit-open').find(settings.submenuEl).hide(); - settings.afterHide.call(this); - return false; - } - - // Hide open menus - settings.beforeHide.call(this); - $('.dropit-open').removeClass('dropit-open').find('.dropit-submenu').hide(); - settings.afterHide.call(this); - - // Open this menu - settings.beforeShow.call(this); - $(this).parents(settings.triggerParentEl).addClass('dropit-open').find(settings.submenuEl).show(); - settings.afterShow.call(this); - - return false; - }); - - // Close if outside click - $(document).on('click', function(){ - settings.beforeHide.call(this); - $('.dropit-open').removeClass('dropit-open').find('.dropit-submenu').hide(); - settings.afterHide.call(this); - }); - - // If hover - if(settings.action == 'mouseenter'){ - $el.on('mouseleave', '.dropit-open', function(){ - settings.beforeHide.call(this); - $(this).removeClass('dropit-open').find(settings.submenuEl).hide(); - settings.afterHide.call(this); - }); - } - - settings.afterLoad.call(this); - }); - } - - }; - - if (methods[method]) { - return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); - } else if (typeof method === 'object' || !method) { - return methods.init.apply(this, arguments); - } else { - $.error( 'Method "' + method + '" does not exist in dropit plugin!'); - } - - }; - - $.fn.dropit.defaults = { - action: 'mouseenter', // The open action for the trigger - submenuEl: 'ul', // The submenu element - triggerEl: 'a', // The trigger element - triggerParentEl: 'li', // The trigger parent element - afterLoad: function(){}, // Triggers when plugin has loaded - beforeShow: function(){}, // Triggers before submenu is shown - afterShow: function(){}, // Triggers after submenu is shown - beforeHide: function(){}, // Triggers before submenu is hidden - afterHide: function(){} // Triggers before submenu is hidden - }; - - $.fn.dropit.settings = {}; - -})(jQuery); diff --git a/solr/example/files/conf/velocity/facet_text_shingles.vm b/solr/example/files/conf/velocity/facet_text_shingles.vm index 4375bd2d58c..ddd96933867 100644 --- a/solr/example/files/conf/velocity/facet_text_shingles.vm +++ b/solr/example/files/conf/velocity/facet_text_shingles.vm @@ -1,9 +1,9 @@
- $resource.top_phrases
+ $resource.facet.top_phrases
    #foreach($facet in $sort.sort($field.values,"name")) -
  • ## $math.random(0.345,0.845) ?! +
  • $facet.name
  • diff --git a/solr/example/files/conf/velocity/facets.vm b/solr/example/files/conf/velocity/facets.vm index 6be7dbfd40c..bb27b5cea71 100644 --- a/solr/example/files/conf/velocity/facets.vm +++ b/solr/example/files/conf/velocity/facets.vm @@ -5,11 +5,11 @@ #parse("facet_${field.name}.vm") #else
    - $field.name
    + #label("facet.${field.name}",$field.name)
    diff --git a/solr/example/files/conf/velocity/head.vm b/solr/example/files/conf/velocity/head.vm index 83141c77be3..1b3aec9434d 100644 --- a/solr/example/files/conf/velocity/head.vm +++ b/solr/example/files/conf/velocity/head.vm @@ -1,5 +1,3 @@ - ## section of the layout - Solr browse: #core_name @@ -8,31 +6,46 @@ - - + + + \ No newline at end of file + + .ac_results { + padding: 0px; + border: 1px solid black; + background-color: white; + overflow: hidden; + z-index: 99999; + } + + .ac_results ul { + width: 100%; + list-style-position: outside; + list-style: none; + padding: 0; + margin: 0; + } + + .ac_results li { + margin: 0px; + padding: 2px 5px; + cursor: default; + display: block; + font: menu; + font-size: 12px; + line-height: 16px; + overflow: hidden; + } + + .ac_loading { +// background: white url('˜indicator.gif') right center no-repeat; + } + + .ac_odd { + background-color: #eee; + } + + .ac_over { + background-color: #0A246A; + color: white; + } + diff --git a/solr/example/files/conf/velocity/hit.vm b/solr/example/files/conf/velocity/hit.vm index 3ce470d1267..359a55582c4 100644 --- a/solr/example/files/conf/velocity/hit.vm +++ b/solr/example/files/conf/velocity/hit.vm @@ -1,3 +1,4 @@ + #set($docId = $doc.getFirstValue($request.schema.uniqueKeyField.name)) ## Load Mime-Type List and Mapping @@ -10,6 +11,15 @@ #set($title = "$doc.getFirstValue('id').substring($math.add(1,$doc.getFirstValue('id').lastIndexOf('/')))") #end +## Date +#if($doc.getFieldValue('attr_meta_creation_date')) + #set($date = $esc.html($doc.getFirstValue('attr_meta_creation_date'))) +#else + #set($date = "No date found") +#end + + + ## URL #if($doc.getFieldValue('url')) #set($url = $doc.getFieldValue('url')) @@ -41,7 +51,7 @@
    - id: $docId + id: $docId
    #set($pad = "") @@ -64,3 +74,4 @@ #foreach($value in $doc.getFieldValues($fieldname))$esc.html($value)#end #end + diff --git a/solr/example/files/conf/velocity/jquery.tx3-tag-cloud.js b/solr/example/files/conf/velocity/jquery.tx3-tag-cloud.js index a33104ff016..e69de29bb2d 100644 --- a/solr/example/files/conf/velocity/jquery.tx3-tag-cloud.js +++ b/solr/example/files/conf/velocity/jquery.tx3-tag-cloud.js @@ -1,70 +0,0 @@ -/* - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * Tuxes3 wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return Tuxes3 - * ---------------------------------------------------------------------------- - */ -(function($) -{ - var settings; - $.fn.tx3TagCloud = function(options) - { - - // - // DEFAULT SETTINGS - // - settings = $.extend({ - multiplier : 1 - }, options); - main(this); - - } - - function main(element) - { - // adding style attr - element.addClass("tx3-tag-cloud"); - addListElementFontSize(element); - } - - /** - * calculates the font size on each li element - * according to their data-weight attribut - */ - function addListElementFontSize(element) - { - var hDataWeight = -9007199254740992; - var lDataWeight = 9007199254740992; - $.each(element.find("li"), function(){ - cDataWeight = getDataWeight(this); - if (cDataWeight == undefined) - { - logWarning("No \"data-weight\" attribut defined on
  • element"); - } - else - { - hDataWeight = cDataWeight > hDataWeight ? cDataWeight : hDataWeight; - lDataWeight = cDataWeight < lDataWeight ? cDataWeight : lDataWeight; - } - }); - $.each(element.find("li"), function(){ - var dataWeight = getDataWeight(this); - var percent = Math.abs((dataWeight - lDataWeight)/(lDataWeight - hDataWeight)); - $(this).css('font-size', (1 + (percent * settings['multiplier'])) + "em"); - }); - - } - - function getDataWeight(element) - { - return parseInt($(element).attr("data-weight")); - } - - function logWarning(message) - { - console.log("[WARNING] " + Date.now() + " : " + message); - } - -}(jQuery)); \ No newline at end of file diff --git a/solr/example/files/conf/velocity/js/dropit.js b/solr/example/files/conf/velocity/js/dropit.js new file mode 100644 index 00000000000..3094414f0ab --- /dev/null +++ b/solr/example/files/conf/velocity/js/dropit.js @@ -0,0 +1,97 @@ +/* + * Dropit v1.1.0 + * http://dev7studios.com/dropit + * + * Copyright 2012, Dev7studios + * Free to use and abuse under the MIT license. + * http://www.opensource.org/licenses/mit-license.php + */ + +;(function($) { + + $.fn.dropit = function(method) { + + var methods = { + + init : function(options) { + this.dropit.settings = $.extend({}, this.dropit.defaults, options); + return this.each(function() { + var $el = $(this), + el = this, + settings = $.fn.dropit.settings; + + // Hide initial submenus + $el.addClass('dropit') + .find('>'+ settings.triggerParentEl +':has('+ settings.submenuEl +')').addClass('dropit-trigger') + .find(settings.submenuEl).addClass('dropit-submenu').hide(); + + // Open on click + $el.off(settings.action).on(settings.action, settings.triggerParentEl +':has('+ settings.submenuEl +') > '+ settings.triggerEl +'', function(){ + // Close click menu's if clicked again + if(settings.action == 'click' && $(this).parents(settings.triggerParentEl).hasClass('dropit-open')){ + settings.beforeHide.call(this); + $(this).parents(settings.triggerParentEl).removeClass('dropit-open').find(settings.submenuEl).hide(); + settings.afterHide.call(this); + return false; + } + + // Hide open menus + settings.beforeHide.call(this); + $('.dropit-open').removeClass('dropit-open').find('.dropit-submenu').hide(); + settings.afterHide.call(this); + + // Open this menu + settings.beforeShow.call(this); + $(this).parents(settings.triggerParentEl).addClass('dropit-open').find(settings.submenuEl).show(); + settings.afterShow.call(this); + + return false; + }); + + // Close if outside click + $(document).on('click', function(){ + settings.beforeHide.call(this); + $('.dropit-open').removeClass('dropit-open').find('.dropit-submenu').hide(); + settings.afterHide.call(this); + }); + + // If hover + if(settings.action == 'mouseenter'){ + $el.on('mouseleave', '.dropit-open', function(){ + settings.beforeHide.call(this); + $(this).removeClass('dropit-open').find(settings.submenuEl).hide(); + settings.afterHide.call(this); + }); + } + + settings.afterLoad.call(this); + }); + } + + }; + + if (methods[method]) { + return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); + } else if (typeof method === 'object' || !method) { + return methods.init.apply(this, arguments); + } else { + $.error( 'Method "' + method + '" does not exist in dropit plugin!'); + } + + }; + + $.fn.dropit.defaults = { + action: 'mouseenter', // The open action for the trigger + submenuEl: 'ul', // The submenu element + triggerEl: 'a', // The trigger element + triggerParentEl: 'li', // The trigger parent element + afterLoad: function(){}, // Triggers when plugin has loaded + beforeShow: function(){}, // Triggers before submenu is shown + afterShow: function(){}, // Triggers after submenu is shown + beforeHide: function(){}, // Triggers before submenu is hidden + afterHide: function(){} // Triggers before submenu is hidden + }; + + $.fn.dropit.settings = {}; + +})(jQuery); diff --git a/solr/example/files/conf/velocity/js/jquery.autocomplete.js b/solr/example/files/conf/velocity/js/jquery.autocomplete.js new file mode 100644 index 00000000000..4a218dcf3d2 --- /dev/null +++ b/solr/example/files/conf/velocity/js/jquery.autocomplete.js @@ -0,0 +1,763 @@ +/* + * Autocomplete - jQuery plugin 1.1pre + * + * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + * Revision: Id: jquery.autocomplete.js 5785 2008-07-12 10:37:33Z joern.zaefferer $ + * + */ + +;(function($) { + +$.fn.extend({ + autocomplete: function(urlOrData, options) { + var isUrl = typeof urlOrData == "string"; + options = $.extend({}, $.Autocompleter.defaults, { + url: isUrl ? urlOrData : null, + data: isUrl ? null : urlOrData, + delay: isUrl ? $.Autocompleter.defaults.delay : 10, + max: options && !options.scroll ? 10 : 150 + }, options); + + // if highlight is set to false, replace it with a do-nothing function + options.highlight = options.highlight || function(value) { return value; }; + + // if the formatMatch option is not specified, then use formatItem for backwards compatibility + options.formatMatch = options.formatMatch || options.formatItem; + + return this.each(function() { + new $.Autocompleter(this, options); + }); + }, + result: function(handler) { + return this.bind("result", handler); + }, + search: function(handler) { + return this.trigger("search", [handler]); + }, + flushCache: function() { + return this.trigger("flushCache"); + }, + setOptions: function(options){ + return this.trigger("setOptions", [options]); + }, + unautocomplete: function() { + return this.trigger("unautocomplete"); + } +}); + +$.Autocompleter = function(input, options) { + + var KEY = { + UP: 38, + DOWN: 40, + DEL: 46, + TAB: 9, + RETURN: 13, + ESC: 27, + COMMA: 188, + PAGEUP: 33, + PAGEDOWN: 34, + BACKSPACE: 8 + }; + + // Create $ object for input element + var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass); + + var timeout; + var previousValue = ""; + var cache = $.Autocompleter.Cache(options); + var hasFocus = 0; + var lastKeyPressCode; + var config = { + mouseDownOnSelect: false + }; + var select = $.Autocompleter.Select(options, input, selectCurrent, config); + + var blockSubmit; + + // prevent form submit in opera when selecting with return key + $.browser.opera && $(input.form).bind("submit.autocomplete", function() { + if (blockSubmit) { + blockSubmit = false; + return false; + } + }); + + // only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all + $input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) { + // track last key pressed + lastKeyPressCode = event.keyCode; + switch(event.keyCode) { + + case KEY.UP: + event.preventDefault(); + if ( select.visible() ) { + select.prev(); + } else { + onChange(0, true); + } + break; + + case KEY.DOWN: + event.preventDefault(); + if ( select.visible() ) { + select.next(); + } else { + onChange(0, true); + } + break; + + case KEY.PAGEUP: + event.preventDefault(); + if ( select.visible() ) { + select.pageUp(); + } else { + onChange(0, true); + } + break; + + case KEY.PAGEDOWN: + event.preventDefault(); + if ( select.visible() ) { + select.pageDown(); + } else { + onChange(0, true); + } + break; + + // matches also semicolon + case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA: + case KEY.TAB: + case KEY.RETURN: + if( selectCurrent() ) { + // stop default to prevent a form submit, Opera needs special handling + event.preventDefault(); + blockSubmit = true; + return false; + } + break; + + case KEY.ESC: + select.hide(); + break; + + default: + clearTimeout(timeout); + timeout = setTimeout(onChange, options.delay); + break; + } + }).focus(function(){ + // track whether the field has focus, we shouldn't process any + // results if the field no longer has focus + hasFocus++; + }).blur(function() { + hasFocus = 0; + if (!config.mouseDownOnSelect) { + hideResults(); + } + }).click(function() { + // show select when clicking in a focused field + if ( hasFocus++ > 1 && !select.visible() ) { + onChange(0, true); + } + }).bind("search", function() { + // TODO why not just specifying both arguments? + var fn = (arguments.length > 1) ? arguments[1] : null; + function findValueCallback(q, data) { + var result; + if( data && data.length ) { + for (var i=0; i < data.length; i++) { + if( data[i].result.toLowerCase() == q.toLowerCase() ) { + result = data[i]; + break; + } + } + } + if( typeof fn == "function" ) fn(result); + else $input.trigger("result", result && [result.data, result.value]); + } + $.each(trimWords($input.val()), function(i, value) { + request(value, findValueCallback, findValueCallback); + }); + }).bind("flushCache", function() { + cache.flush(); + }).bind("setOptions", function() { + $.extend(options, arguments[1]); + // if we've updated the data, repopulate + if ( "data" in arguments[1] ) + cache.populate(); + }).bind("unautocomplete", function() { + select.unbind(); + $input.unbind(); + $(input.form).unbind(".autocomplete"); + }); + + + function selectCurrent() { + var selected = select.selected(); + if( !selected ) + return false; + + var v = selected.result; + previousValue = v; + + if ( options.multiple ) { + var words = trimWords($input.val()); + if ( words.length > 1 ) { + v = words.slice(0, words.length - 1).join( options.multipleSeparator ) + options.multipleSeparator + v; + } + v += options.multipleSeparator; + } + + $input.val(v); + hideResultsNow(); + $input.trigger("result", [selected.data, selected.value]); + return true; + } + + function onChange(crap, skipPrevCheck) { + if( lastKeyPressCode == KEY.DEL ) { + select.hide(); + return; + } + + var currentValue = $input.val(); + + if ( !skipPrevCheck && currentValue == previousValue ) + return; + + previousValue = currentValue; + + currentValue = lastWord(currentValue); + if ( currentValue.length >= options.minChars) { + $input.addClass(options.loadingClass); + if (!options.matchCase) + currentValue = currentValue.toLowerCase(); + request(currentValue, receiveData, hideResultsNow); + } else { + stopLoading(); + select.hide(); + } + }; + + function trimWords(value) { + if ( !value ) { + return [""]; + } + var words = value.split( options.multipleSeparator ); + var result = []; + $.each(words, function(i, value) { + if ( $.trim(value) ) + result[i] = $.trim(value); + }); + return result; + } + + function lastWord(value) { + if ( !options.multiple ) + return value; + var words = trimWords(value); + return words[words.length - 1]; + } + + // fills in the input box w/the first match (assumed to be the best match) + // q: the term entered + // sValue: the first matching result + function autoFill(q, sValue){ + // autofill in the complete box w/the first match as long as the user hasn't entered in more data + // if the last user key pressed was backspace, don't autofill + if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) { + // fill in the value (keep the case the user has typed) + $input.val($input.val() + sValue.substring(lastWord(previousValue).length)); + // select the portion of the value not typed by the user (so the next character will erase) + $.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length); + } + }; + + function hideResults() { + clearTimeout(timeout); + timeout = setTimeout(hideResultsNow, 200); + }; + + function hideResultsNow() { + var wasVisible = select.visible(); + select.hide(); + clearTimeout(timeout); + stopLoading(); + if (options.mustMatch) { + // call search and run callback + $input.search( + function (result){ + // if no value found, clear the input box + if( !result ) { + if (options.multiple) { + var words = trimWords($input.val()).slice(0, -1); + $input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") ); + } + else + $input.val( "" ); + } + } + ); + } + if (wasVisible) + // position cursor at end of input field + $.Autocompleter.Selection(input, input.value.length, input.value.length); + }; + + function receiveData(q, data) { + if ( data && data.length && hasFocus ) { + stopLoading(); + select.display(data, q); + autoFill(q, data[0].value); + select.show(); + } else { + hideResultsNow(); + } + }; + + function request(term, success, failure) { + if (!options.matchCase) + term = term.toLowerCase(); + var data = cache.load(term); + data = null; // Avoid buggy cache and go to Solr every time + // recieve the cached data + if (data && data.length) { + success(term, data); + // if an AJAX url has been supplied, try loading the data now + } else if( (typeof options.url == "string") && (options.url.length > 0) ){ + + var extraParams = { + timestamp: +new Date() + }; + $.each(options.extraParams, function(key, param) { + extraParams[key] = typeof param == "function" ? param() : param; + }); + + $.ajax({ + // try to leverage ajaxQueue plugin to abort previous requests + mode: "abort", + // limit abortion to this input + port: "autocomplete" + input.name, + dataType: options.dataType, + url: options.url, + data: $.extend({ + q: lastWord(term), + limit: options.max + }, extraParams), + success: function(data) { + var parsed = options.parse && options.parse(data) || parse(data); + cache.add(term, parsed); + success(term, parsed); + } + }); + } else { + // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match + select.emptyList(); + failure(term); + } + }; + + function parse(data) { + var parsed = []; + var rows = data.split("\n"); + for (var i=0; i < rows.length; i++) { + var row = $.trim(rows[i]); + if (row) { + row = row.split("|"); + parsed[parsed.length] = { + data: row, + value: row[0], + result: options.formatResult && options.formatResult(row, row[0]) || row[0] + }; + } + } + return parsed; + }; + + function stopLoading() { + $input.removeClass(options.loadingClass); + }; + +}; + +$.Autocompleter.defaults = { + inputClass: "ac_input", + resultsClass: "ac_results", + loadingClass: "ac_loading", + minChars: 1, + delay: 400, + matchCase: false, + matchSubset: true, + matchContains: false, + cacheLength: 10, + max: 100, + mustMatch: false, + extraParams: {}, + selectFirst: false, + formatItem: function(row) { return row[0]; }, + formatMatch: null, + autoFill: false, + width: 0, + multiple: false, + multipleSeparator: ", ", + highlight: function(value, term) { + return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "$1"); + }, + scroll: true, + scrollHeight: 180 +}; + +$.Autocompleter.Cache = function(options) { + + var data = {}; + var length = 0; + + function matchSubset(s, sub) { + if (!options.matchCase) + s = s.toLowerCase(); + var i = s.indexOf(sub); + if (options.matchContains == "word"){ + i = s.toLowerCase().search("\\b" + sub.toLowerCase()); + } + if (i == -1) return false; + return i == 0 || options.matchContains; + }; + + function add(q, value) { + if (length > options.cacheLength){ + flush(); + } + if (!data[q]){ + length++; + } + data[q] = value; + } + + function populate(){ + if( !options.data ) return false; + // track the matches + var stMatchSets = {}, + nullData = 0; + + // no url was specified, we need to adjust the cache length to make sure it fits the local data store + if( !options.url ) options.cacheLength = 1; + + // track all options for minChars = 0 + stMatchSets[""] = []; + + // loop through the array and create a lookup structure + for ( var i = 0, ol = options.data.length; i < ol; i++ ) { + var rawValue = options.data[i]; + // if rawValue is a string, make an array otherwise just reference the array + rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue; + + var value = options.formatMatch(rawValue, i+1, options.data.length); + if ( value === false ) + continue; + + var firstChar = value.charAt(0).toLowerCase(); + // if no lookup array for this character exists, look it up now + if( !stMatchSets[firstChar] ) + stMatchSets[firstChar] = []; + + // if the match is a string + var row = { + value: value, + data: rawValue, + result: options.formatResult && options.formatResult(rawValue) || value + }; + + // push the current match into the set list + stMatchSets[firstChar].push(row); + + // keep track of minChars zero items + if ( nullData++ < options.max ) { + stMatchSets[""].push(row); + } + }; + + // add the data items to the cache + $.each(stMatchSets, function(i, value) { + // increase the cache size + options.cacheLength++; + // add to the cache + add(i, value); + }); + } + + // populate any existing data + setTimeout(populate, 25); + + function flush(){ + data = {}; + length = 0; + } + + return { + flush: flush, + add: add, + populate: populate, + load: function(q) { + if (!options.cacheLength || !length) + return null; + /* + * if dealing w/local data and matchContains than we must make sure + * to loop through all the data collections looking for matches + */ + if( !options.url && options.matchContains ){ + // track all matches + var csub = []; + // loop through all the data grids for matches + for( var k in data ){ + // don't search through the stMatchSets[""] (minChars: 0) cache + // this prevents duplicates + if( k.length > 0 ){ + var c = data[k]; + $.each(c, function(i, x) { + // if we've got a match, add it to the array + if (matchSubset(x.value, q)) { + csub.push(x); + } + }); + } + } + return csub; + } else + // if the exact item exists, use it + if (data[q]){ + return data[q]; + } else + if (options.matchSubset) { + for (var i = q.length - 1; i >= options.minChars; i--) { + var c = data[q.substr(0, i)]; + if (c) { + var csub = []; + $.each(c, function(i, x) { + if (matchSubset(x.value, q)) { + csub[csub.length] = x; + } + }); + return csub; + } + } + } + return null; + } + }; +}; + +$.Autocompleter.Select = function (options, input, select, config) { + var CLASSES = { + ACTIVE: "ac_over" + }; + + var listItems, + active = -1, + data, + term = "", + needsInit = true, + element, + list; + + // Create results + function init() { + if (!needsInit) + return; + element = $("
    ") + .hide() + .addClass(options.resultsClass) + .css("position", "absolute") + .appendTo(document.body); + + list = $("
      ").appendTo(element).mouseover( function(event) { + if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') { + active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event)); + $(target(event)).addClass(CLASSES.ACTIVE); + } + }).click(function(event) { + $(target(event)).addClass(CLASSES.ACTIVE); + select(); + // TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus + input.focus(); + return false; + }).mousedown(function() { + config.mouseDownOnSelect = true; + }).mouseup(function() { + config.mouseDownOnSelect = false; + }); + + if( options.width > 0 ) + element.css("width", options.width); + + needsInit = false; + } + + function target(event) { + var element = event.target; + while(element && element.tagName != "LI") + element = element.parentNode; + // more fun with IE, sometimes event.target is empty, just ignore it then + if(!element) + return []; + return element; + } + + function moveSelect(step) { + listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE); + movePosition(step); + var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE); + if(options.scroll) { + var offset = 0; + listItems.slice(0, active).each(function() { + offset += this.offsetHeight; + }); + if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) { + list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight()); + } else if(offset < list.scrollTop()) { + list.scrollTop(offset); + } + } + }; + + function movePosition(step) { + active += step; + if (active < 0) { + active = listItems.size() - 1; + } else if (active >= listItems.size()) { + active = 0; + } + } + + function limitNumberOfItems(available) { + return options.max && options.max < available + ? options.max + : available; + } + + function fillList() { + list.empty(); + var max = limitNumberOfItems(data.length); + for (var i=0; i < max; i++) { + if (!data[i]) + continue; + var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term); + if ( formatted === false ) + continue; + var li = $("
    • ").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0]; + $.data(li, "ac_data", data[i]); + } + listItems = list.find("li"); + if ( options.selectFirst ) { + listItems.slice(0, 1).addClass(CLASSES.ACTIVE); + active = 0; + } + // apply bgiframe if available + if ( $.fn.bgiframe ) + list.bgiframe(); + } + + return { + display: function(d, q) { + init(); + data = d; + term = q; + fillList(); + }, + next: function() { + moveSelect(1); + }, + prev: function() { + moveSelect(-1); + }, + pageUp: function() { + if (active != 0 && active - 8 < 0) { + moveSelect( -active ); + } else { + moveSelect(-8); + } + }, + pageDown: function() { + if (active != listItems.size() - 1 && active + 8 > listItems.size()) { + moveSelect( listItems.size() - 1 - active ); + } else { + moveSelect(8); + } + }, + hide: function() { + element && element.hide(); + listItems && listItems.removeClass(CLASSES.ACTIVE); + active = -1; + }, + visible : function() { + return element && element.is(":visible"); + }, + current: function() { + return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]); + }, + show: function() { + var offset = $(input).offset(); + element.css({ + width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(), + top: offset.top + input.offsetHeight, + left: offset.left + }).show(); + if(options.scroll) { + list.scrollTop(0); + list.css({ + maxHeight: options.scrollHeight, + overflow: 'auto' + }); + + if($.browser.msie && typeof document.body.style.maxHeight === "undefined") { + var listHeight = 0; + listItems.each(function() { + listHeight += this.offsetHeight; + }); + var scrollbarsVisible = listHeight > options.scrollHeight; + list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight ); + if (!scrollbarsVisible) { + // IE doesn't recalculate width when scrollbar disappears + listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) ); + } + } + + } + }, + selected: function() { + var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE); + return selected && selected.length && $.data(selected[0], "ac_data"); + }, + emptyList: function (){ + list && list.empty(); + }, + unbind: function() { + element && element.remove(); + } + }; +}; + +$.Autocompleter.Selection = function(field, start, end) { + if( field.createTextRange ){ + var selRange = field.createTextRange(); + selRange.collapse(true); + selRange.moveStart("character", start); + selRange.moveEnd("character", end); + selRange.select(); + } else if( field.setSelectionRange ){ + field.setSelectionRange(start, end); + } else { + if( field.selectionStart ){ + field.selectionStart = start; + field.selectionEnd = end; + } + } + field.focus(); +}; + +})(jQuery); \ No newline at end of file diff --git a/solr/example/files/conf/velocity/js/jquery.tx3-tag-cloud.js b/solr/example/files/conf/velocity/js/jquery.tx3-tag-cloud.js new file mode 100644 index 00000000000..a33104ff016 --- /dev/null +++ b/solr/example/files/conf/velocity/js/jquery.tx3-tag-cloud.js @@ -0,0 +1,70 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * Tuxes3 wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return Tuxes3 + * ---------------------------------------------------------------------------- + */ +(function($) +{ + var settings; + $.fn.tx3TagCloud = function(options) + { + + // + // DEFAULT SETTINGS + // + settings = $.extend({ + multiplier : 1 + }, options); + main(this); + + } + + function main(element) + { + // adding style attr + element.addClass("tx3-tag-cloud"); + addListElementFontSize(element); + } + + /** + * calculates the font size on each li element + * according to their data-weight attribut + */ + function addListElementFontSize(element) + { + var hDataWeight = -9007199254740992; + var lDataWeight = 9007199254740992; + $.each(element.find("li"), function(){ + cDataWeight = getDataWeight(this); + if (cDataWeight == undefined) + { + logWarning("No \"data-weight\" attribut defined on
    • element"); + } + else + { + hDataWeight = cDataWeight > hDataWeight ? cDataWeight : hDataWeight; + lDataWeight = cDataWeight < lDataWeight ? cDataWeight : lDataWeight; + } + }); + $.each(element.find("li"), function(){ + var dataWeight = getDataWeight(this); + var percent = Math.abs((dataWeight - lDataWeight)/(lDataWeight - hDataWeight)); + $(this).css('font-size', (1 + (percent * settings['multiplier'])) + "em"); + }); + + } + + function getDataWeight(element) + { + return parseInt($(element).attr("data-weight")); + } + + function logWarning(message) + { + console.log("[WARNING] " + Date.now() + " : " + message); + } + +}(jQuery)); \ No newline at end of file diff --git a/solr/example/files/conf/velocity/macros.vm b/solr/example/files/conf/velocity/macros.vm index f5c12fb46cd..7d1bc1be101 100644 --- a/solr/example/files/conf/velocity/macros.vm +++ b/solr/example/files/conf/velocity/macros.vm @@ -11,3 +11,6 @@ #macro(current_type)#if($response.responseHeader.params.type)${response.responseHeader.params.type}#{else}all#end#end #macro(url_for_locale $locale)#url_for_home#lensNoLocale#if($locale!="")&locale=$locale#end&start=$page.start#end #macro(current_locale)$!{response.responseHeader.params.locale}#end + +## Usage: #label(resource_key[, default_value]) - resource_key is used as label if no default value specified and no resource exists +#macro(label $key $default)#if($resource.get($key).exists)${resource.get($key)}#else#if($default)$default#else${key}#end#end#end \ No newline at end of file diff --git a/solr/example/files/conf/velocity/results_list.vm b/solr/example/files/conf/velocity/results_list.vm index dd1119a6dfc..908e45b0c99 100644 --- a/solr/example/files/conf/velocity/results_list.vm +++ b/solr/example/files/conf/velocity/results_list.vm @@ -2,7 +2,7 @@
    • $resource.type.all ($response.response.facet_counts.facet_queries.all_types)
    • #foreach($type in $response.response.facet_counts.facet_fields.doc_type) #if($type.key) -
    • #if($resource.get("type.${type.key}.label"))$resource.get("type.${type.key}.label")#else$type.key#end ($type.value)
    • +
    • #label("type.${type.key}.label", $type.key) ($type.value)
    • #else #if($type.value > 0)
    • $resource.type.unknown ($type.value)