diff options
Diffstat (limited to 'SemanticForms/libs')
-rw-r--r-- | SemanticForms/libs/SF_autoedit.js | 83 | ||||
-rw-r--r-- | SemanticForms/libs/SF_autogrow.js | 53 | ||||
-rw-r--r-- | SemanticForms/libs/SF_checkboxes.js | 57 | ||||
-rw-r--r-- | SemanticForms/libs/SF_collapsible.js | 55 | ||||
-rw-r--r-- | SemanticForms/libs/SF_imagePreview.js | 66 | ||||
-rw-r--r-- | SemanticForms/libs/SF_popupform.js | 829 | ||||
-rw-r--r-- | SemanticForms/libs/SF_preview.js | 213 | ||||
-rw-r--r-- | SemanticForms/libs/SF_submit.js | 197 | ||||
-rw-r--r-- | SemanticForms/libs/SF_wikieditor.js | 42 | ||||
-rw-r--r-- | SemanticForms/libs/SemanticForms.js | 1084 | ||||
-rw-r--r-- | SemanticForms/libs/ext.dynatree.js | 52 | ||||
-rw-r--r-- | SemanticForms/libs/ext.sf.js | 28 | ||||
-rw-r--r-- | SemanticForms/libs/ext.sf.select2.base.js | 271 | ||||
-rw-r--r-- | SemanticForms/libs/ext.sf.select2.combobox.js | 275 | ||||
-rw-r--r-- | SemanticForms/libs/ext.sf.select2.tokens.js | 314 | ||||
-rw-r--r-- | SemanticForms/libs/jquery.browser.js | 46 | ||||
-rw-r--r-- | SemanticForms/libs/jquery.dynatree.js | 3420 | ||||
-rw-r--r-- | SemanticForms/libs/jquery.fancybox.js | 1152 | ||||
-rw-r--r-- | SemanticForms/libs/select2.js | 3378 |
19 files changed, 0 insertions, 11615 deletions
diff --git a/SemanticForms/libs/SF_autoedit.js b/SemanticForms/libs/SF_autoedit.js deleted file mode 100644 index 904251c6..00000000 --- a/SemanticForms/libs/SF_autoedit.js +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Javascript handler for the autoedit parser function - * - * @author Stephan Gambke - */ - -/*global confirm */ - -( function ( $, mw ) { - - 'use strict'; - - var autoEditHandler = function handleAutoEdit(){ - - if ( mw.config.get( 'wgUserName' ) === null && - ! confirm( mw.msg( 'sf_autoedit_anoneditwarning' ) ) ) { - - return; - } - - var jtrigger = jQuery( this ); - var jautoedit = jtrigger.closest( '.autoedit' ); - var jresult = jautoedit.find( '.autoedit-result' ); - - var reload = jtrigger.hasClass( 'reload' ); - - jtrigger.attr( 'class', 'autoedit-trigger autoedit-trigger-wait' ); - jresult.attr( 'class', 'autoedit-result autoedit-result-wait' ); - - jresult.text( mw.msg( 'sf-autoedit-wait' ) ); - - - // data array to be sent to the server - var data = { - action: 'sfautoedit', - format: 'json' - }; - - // add form values to the data - data.query = jautoedit.find( 'form.autoedit-data' ).serialize(); - - $.ajax( { - - type: 'POST', // request type ( GET or POST ) - url: mw.util.wikiScript( 'api' ), // URL to which the request is sent - data: data, // data to be sent to the server - dataType: 'json', // type of data expected back from the server - success: function ( result ){ - jresult.empty().append( result.responseText ); - - if ( result.status === 200 ) { - - if ( reload ) { - window.location.reload(); - } - - jresult.removeClass( 'autoedit-result-wait' ).addClass( 'autoedit-result-ok' ); - jtrigger.removeClass( 'autoedit-trigger-wait' ).addClass( 'autoedit-trigger-ok' ); - } else { - jresult.removeClass( 'autoedit-result-wait' ).addClass( 'autoedit-result-error' ); - jtrigger.removeClass( 'autoedit-trigger-wait' ).addClass( 'autoedit-trigger-error' ); - } - }, // function to be called if the request succeeds - error: function ( jqXHR, textStatus, errorThrown ) { - var result = jQuery.parseJSON(jqXHR.responseText); - var text = result.responseText; - - for ( var i = 0; i < result.errors.length; i++ ) { - text += ' ' + result.errors[i].message; - } - - jresult.empty().append( text ); - jresult.removeClass( 'autoedit-result-wait' ).addClass( 'autoedit-result-error' ); - jtrigger.removeClass( 'autoedit-trigger-wait' ).addClass( 'autoedit-trigger-error' ); - } // function to be called if the request fails - } ); - }; - - jQuery( document ).ready( function ( $ ) { - $( '.autoedit-trigger' ).click( autoEditHandler ); - } ); - -}( jQuery, mediaWiki ) ); diff --git a/SemanticForms/libs/SF_autogrow.js b/SemanticForms/libs/SF_autogrow.js deleted file mode 100644 index 2c21a11f..00000000 --- a/SemanticForms/libs/SF_autogrow.js +++ /dev/null @@ -1,53 +0,0 @@ -/** - * SF_autogrow.js - * - * Allows for 'autogrow' textareas. Based heavily on the 'Autogrow Textarea - * Plugin' by Jevin O. Sewaruth: - * http://www.technoreply.com/autogrow-textarea-plugin/ - * - * Some modifications were made for the code to better work with Semantic - * Forms. - * - * @author Jevin O. Sewaruth - * @author Yaron Koren - */ - -var autoGrowColsDefault = []; -var autoGrowRowsDefault = []; - -function autoGrowSetDefaultValues(textArea) { - var id = textArea.id; - autoGrowColsDefault[id] = textArea.cols; - autoGrowRowsDefault[id] = textArea.rows; -} - -function autoGrow(textArea) { - var linesCount = 0; - var lines = textArea.value.split('\n'); - - for (var i = lines.length-1; i >= 0; --i) { - linesCount += Math.floor((lines[i].length / autoGrowColsDefault[textArea.id]) + 1); - } - - if (linesCount >= autoGrowRowsDefault[textArea.id]) { - textArea.rows = linesCount + 1; - } - else { - textArea.rows = autoGrowRowsDefault[textArea.id]; - } -} - -function autoGrowBindEvents(textArea) { - textArea.onkeyup = function() { - autoGrow(textArea); - }; -} - -// jQuery method -jQuery.fn.autoGrow = function() { - return this.each(function() { - autoGrowSetDefaultValues(this); - autoGrowBindEvents(this); - autoGrow(this); - }); -}; diff --git a/SemanticForms/libs/SF_checkboxes.js b/SemanticForms/libs/SF_checkboxes.js deleted file mode 100644 index 019e5021..00000000 --- a/SemanticForms/libs/SF_checkboxes.js +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Javascript handler for the checkboxes input type - * - * @author Stephan Gambke - */ - -( function ( $, mw ) { - - 'use strict'; - - // jQuery plugin that will attach a select all/select none switch to all checkboxes in "this" element - $.fn.appendSelectionSwitches = function () { - - function insertSwitch( switchesWrapper, label, checked ) { - - // create a link element that will trigger the selection of all checkboxes - var link = $( '<a href="#">' + label + '</a>' ); - - // will be initialized only when the event is triggered to avoid lag during page loading - var $checkboxes; - - // attach an event handler - link.click( function ( event ) { - - event.preventDefault(); - - // store checkboxes during first method call so the DOM is not searched on every click on the link - $checkboxes = $checkboxes || switchesWrapper.siblings().find( 'input[type="checkbox"]' ); - - $checkboxes.prop( 'checked', checked ); - } ); - - // wrap the link into a span to simplify styling - var switchWrapper = $('<span class="checkboxSwitch">' ).append( link ); - - // insert the complete switch into the DOM - switchesWrapper.append( switchWrapper ); - - } - - this.each( function ( index, element ) { - - var switchesWrapper = $( '<span class="checkboxSwitches">' ).prependTo( element ); - - insertSwitch( switchesWrapper, mw.message( 'sf_forminputs_checkboxes_select_all' ), true ); - insertSwitch( switchesWrapper, mw.message( 'sf_forminputs_checkboxes_select_none' ), false ); - - } ); - - return this; - }; - - $().ready( function ( $ ) { - $( '.checkboxesSpan.select-all' ).appendSelectionSwitches(); - } ); - -}( jQuery, mediaWiki ) ); diff --git a/SemanticForms/libs/SF_collapsible.js b/SemanticForms/libs/SF_collapsible.js deleted file mode 100644 index c945f407..00000000 --- a/SemanticForms/libs/SF_collapsible.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * SF_collapsible.js - * - * Allows for collapsible fieldsets. - * - * Based on the 'coolfieldset' jQuery plugin: - * http://w3shaman.com/article/jquery-plugin-collapsible-fieldset - */ - -function sfHideFieldsetContent(obj, options){ - obj.find('div').slideUp(options.speed); - obj.removeClass("sfExpandedFieldset"); - obj.addClass("sfCollapsedFieldset"); -} - -function sfShowFieldsetContent(obj, options){ - obj.find('div').slideDown(options.speed); - obj.removeClass("sfCollapsedFieldset"); - obj.addClass("sfExpandedFieldset"); -} - -jQuery.fn.sfMakeCollapsible = function(options){ - var setting = { collapsed: true, speed: 'medium' }; - jQuery.extend(setting, options); - - this.each(function(){ - var fieldset = jQuery(this); - var legend = fieldset.children('legend'); - if ( setting.collapsed === true ) { - legend.toggle( - function(){ - sfShowFieldsetContent(fieldset, setting); - }, - function(){ - sfHideFieldsetContent(fieldset, setting); - } - ); - - sfHideFieldsetContent(fieldset, {animation:false}); - } else { - legend.toggle( - function(){ - sfHideFieldsetContent(fieldset, setting); - }, - function(){ - sfShowFieldsetContent(fieldset, setting); - } - ); - } - }); -}; - -jQuery(document).ready(function() { - jQuery('.sfCollapsibleFieldset').sfMakeCollapsible(); -}); diff --git a/SemanticForms/libs/SF_imagePreview.js b/SemanticForms/libs/SF_imagePreview.js deleted file mode 100644 index c1f3affc..00000000 --- a/SemanticForms/libs/SF_imagePreview.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * JavaScript for the Semantic Forms MediaWiki extension. - * - * @licence GNU GPL v3+ - * @author Jeroen De Dauw <jeroendedauw at gmail dot com> - */ - -(function( $ ) { - var _this = this; - - this.getPreviewImage = function( args, callback ) { - $.getJSON( - mw.config.get( 'wgScriptPath' ) + '/api.php', - { - 'action': 'query', - 'format': 'json', - 'prop': 'imageinfo', - 'iiprop': 'url', - 'titles': 'File:' + args.title, - 'iiurlwidth': args.width - }, - function( data ) { - if ( data.query && data.query.pages ) { - var pages = data.query.pages; - - for ( var p = 0; p < pages.length; p++ ) { - var info = pages[p].imageinfo; - for ( var i = 0; i < info.length; i++ ) { - callback( info[i].thumburl ); - return; - } - } - } - callback( false ); - } - ); - }; - - $( document ).ready( function() { - $( '.sfImagePreview' ).each( function( index, domElement ) { - var $uploadLink = $( domElement ); - var inputId = $uploadLink.attr( 'data-input-id' ); - var $input = $( '#' + inputId ); - var $previewDiv = $( '#' + inputId + '_imagepreview' ); - - var showPreview = function() { - _this.getPreviewImage( - { - 'title': $input.val(), - 'width': 200 - }, - function( url ) { - if ( url === false ) { - $previewDiv.html( '' ); - } - else { - $previewDiv.html( $( '<img />' ).attr( { 'src': url } ) ); - } - } - ); - }; - - $input.change( showPreview ); - } ); - } ); -})( jQuery ); diff --git a/SemanticForms/libs/SF_popupform.js b/SemanticForms/libs/SF_popupform.js deleted file mode 100644 index 02b0e582..00000000 --- a/SemanticForms/libs/SF_popupform.js +++ /dev/null @@ -1,829 +0,0 @@ -/** - * Javascript code to be used with extension SemanticForms for popup forms. - * - * @author Stephan Gambke - * - */ -/*global escape*/ - -// initialise -jQuery( function() { - - // register eventhandlers on 'edit' links and buttons - - // register formlink with link - jQuery('a.popupformlink').click(function(evt){ - return ext.popupform.handlePopupFormLink( this.getAttribute('href'), this ); - }); - - // register formlink with button - jQuery( 'form.popupformlink' ).submit(function(evt){ - return ext.popupform.handlePopupFormLink( this.getAttribute( 'action' ), this ); - }); - - - // register forminput - jQuery( 'form.popupforminput' ).submit(function(evt){ - return ext.popupform.handlePopupFormInput( this.getAttribute( 'action' ), this ); - }); - -}); - -// create ext if it does not exist yet -if ( typeof( window.ext ) === "undefined" ) { - window.ext = {}; -} - -window.ext.popupform = new function() { - var wrapper; - var background; - var container; - var innerContainer; - var iframe; - var content; - var waitIndicator; - var instance = 0; - - var timer; - var needsRender = true; - - var doc; - - var brokenBrowser, brokenChrome; - - var padding = 20; - - function handlePopupFormInput( ptarget, elem ) { - showForm(); - - iframe.one( 'load', function(){ - // attach event handler to iframe - iframe.bind( 'load', handleLoadFrame ); - return false; - }); - - elem.target = 'popupform-iframe' + instance; - return true; - } - - function handlePopupFormLink( ptarget, elem ) { - showForm(); - - // store initial readystate - var readystate = iframe.contents()[0].readyState; - - // set up timer for waiting on the document in the iframe to be dom-ready - // this sucks, but there is no other way to catch that event - // onload is already too late - timer = setInterval(function(){ - // if the readystate changed - if ( readystate !== iframe.contents()[0].readyState ) { - // store new readystate - readystate = iframe.contents()[0].readyState; - - // if dom is built but document not yet displayed - if ( readystate === 'interactive' || readystate === 'complete' ) { - needsRender = false; // flag that rendering is already done - handleLoadFrame(); - } - } - }, 100 ); - - // fallback in case we did not catch the dom-ready state - iframe.on('load', function( event ){ - if ( needsRender ) { // rendering not already done? - handleLoadFrame( event ); - } - needsRender = true; - }); - - if ( elem.tagName == 'FORM' ) { - elem.target = 'popupform-iframe' + instance; - return true; - } else { - var delim = ptarget.indexOf( '?' ); - var form = document.createElement("form"); - - form.target = 'popupform-iframe' + instance; - - // Do we have parameters? - if ( delim > 0 ) { - form.action = ptarget.substr( 0, delim ); - var params = String( ptarget.substr( delim + 1 ) ).split("&"); - for ( var i = 0; i < params.length; ++i ) { - - var input = document.createElement("input"); - var param = String( params[i] ).split('='); - input.type = 'hidden'; - input.name = decodeURIComponent( param[0] ); - input.value = decodeURIComponent( param[1] ); - form.appendChild( input ); - } - } else { - form.action = ptarget; - } - - document.getElementsByTagName('body')[0].appendChild(form); - form.submit(); - document.getElementsByTagName('body')[0].removeChild(form); - - return false; - } - } - - function showForm() { - instance++; - - brokenChrome = - ( navigator.userAgent.indexOf("Chrome") >= 0 && - navigator.platform.indexOf("Linux x86_64") >= 0 ); - - brokenBrowser= jQuery.browser.msie || brokenChrome; - - var maxZIndex = 0; - - jQuery("*").each(function() { - var curr = parseInt( jQuery( this ).css( "z-index" ) ); - maxZIndex = curr > maxZIndex ? curr : maxZIndex; - }); - - - wrapper = jQuery( "<div class='popupform-wrapper' >" ); - background = jQuery( "<div class='popupform-background' >" ); - - var waitIndicatorWrapper = jQuery( "<div class='popupform-loading'>" ); - - waitIndicator = jQuery( "<div class='popupform-loadingbg'></div><div class='popupform-loadingfg'></div>" ); - - var anchor = jQuery( "<div class='popupform-anchor' >" ); - - container = jQuery( "<div class='popupform-container' >" ); - innerContainer = jQuery( "<div class='popupform-innercontainer' >" ); - iframe = jQuery( "<iframe class='popupform-innerdocument' name='popupform-iframe" + instance + "' id='popupform-iframe" + instance + "' >"); - - var closeBtn = jQuery( "<div class='popupform-close'></div> " ); - - // initially hide background and waitIndicator - if (brokenChrome) { - background.css("background", "transparent"); - } else { - background.css("opacity", 0.0); - } - - waitIndicator.hide(); - container.hide(); - - // insert background and wait indicator into wrapper and all into document - waitIndicatorWrapper - .append( waitIndicator ); - - innerContainer - .append( iframe ); - - container - .append( closeBtn ) - .append( innerContainer ); - - anchor - .append(container); - - wrapper - .css( "z-index", maxZIndex + 1 ) - .append( background ) - .append( waitIndicatorWrapper ) - .append( anchor ) - .appendTo( "body" ); - - // fade background in - if ( !brokenChrome ) { - background.fadeTo( 400, 0.3 ); - } - fadeIn( waitIndicator ); - - // attach event handler to close button - closeBtn.click( handleCloseFrame ); - } - - function handleLoadFrame() { - var iframecontents = iframe.contents(); - - var containerAlreadyVisible = container.is( ':visible' ); - - if ( !containerAlreadyVisible ) { - // no need to hide it again - if ( brokenBrowser ) { - container[0].style.visibility = "hidden"; - } else { - container[0].style.opacity = 0; - } - } - - container.show(); - - // GuMaxDD has #content but keeps headlines in #gumax-content-body - content = iframecontents.find("#gumax-content-body"); - - // normal skins use #content (e.g. Vector, Monobook) - if ( content.length === 0 ) { - content = iframecontents.find("#content"); - } - - // some skins use #mw_content (e.g. Modern) - if ( content.length === 0 ) { - content = iframecontents.find("#mw_content"); - } - - var iframebody = content.closest("body"); - var iframedoc = iframebody.parent(); - - // this is not a normal MW page (or it uses an unknown skin) - if ( content.length === 0 ) { - content = iframebody; - } - - // the huge left margin looks ugly in Vector, reduce it - // (How does this look for other skins?) - var siblings = content - .css( { - margin: 0, - padding: padding, - width: "auto", - height: "auto", - minWidth: "0px", - minHeight:"0px", -// overflow: "visible", -// position: "relative", -// top: "0", -// left: "0", - border: "none" - } ) - .parentsUntil('html') - .css( { - margin: 0, - padding: 0, - width: "auto", - height: "auto", - minWidth: "0px", - minHeight: "0px", - "float": "none", // Cavendish skin uses floating -> unfloat content -// position: "relative", -// top: "0", -// left: "0", - background: "transparent" - }) - .andSelf().siblings(); - - iframedoc.height('100%').width('100%'); - iframebody.height('100%').width('100%'); - - if ( jQuery.browser.msie && jQuery.browser.version < "8" ) { - siblings.hide(); - } else { - siblings - .each( function(){ - var elem = jQuery(this); - - // TODO: Does this really help? - if ( getStyle(this, "display") != "none" && ! ( - ( this.offsetLeft + elem.outerWidth(true) < 0 ) || // left of document - ( this.offsetTop + elem.outerHeight(true) < 0 ) || // above document - ( this.offsetLeft > 100000 ) || // right of document - ( this.offsetTop > 100000 ) // below document - ) - ) { - - jQuery(this).hide(); - // css({ - // height : "0px", - // width : "0px", - // minWidth : "0px", - // minHeight : "0px", - // margin : "0px", - // padding : "0px" - // border : "none", - // overflow: "hidden" - // //position: "static" - // }); - } - if ( ( this.offsetLeft + elem.outerWidth() < 0 ) || - ( this.offsetTop + elem.outerHeight() < 0 ) - ) { - this.style.left = (-elem.outerWidth(true)) + "px"; - this.style.top = (-elem.outerHeight(true)) + "px"; - } - }); - //.children().css("position", "static"); - } - - container.show(); - - // adjust frame size to dimensions just calculated - adjustFrameSize(); - - // and attach event handler to adjust frame size every time the window - // size changes - jQuery( window ).resize( function() { - adjustFrameSize(); - } ); - - //interval = setInterval(adjustFrameSize, 100); - - var form = content.find("#sfForm"); - var innerwdw = document.getElementById( 'popupform-iframe' + instance ).contentWindow; - var innerJ = innerwdw.jQuery; - - // if we have a form and it is not a RunQuery form - if (form.length > 0 && ( typeof form[0].wpRunQuery === 'undefined') ) { - var submitok = false; - var innersubmitprocessed = false; - - // catch form submit event - form - .bind( "submit", function( event ){ - var interval = setInterval(function(){ - if ( innersubmitprocessed ) { - clearInterval( interval ); - innersubmitprocessed = false; - if ( submitok ) { - handleSubmitData( event ); - } - } - - }, 10); - event.stopPropagation(); - return false; - }); - - // catch inner form submit event - if ( innerJ ) { - innerwdw.jQuery(form[0]) - .bind( "submit", function( event ) { - submitok = event.result; - innersubmitprocessed = true; - return false; - }); - } else { - submitok = true; - innersubmitprocessed = true; - } - } - - if (innerJ) { - // FIXME: Why did I put this in? - innerwdw.jQuery( innerwdw[0] ).unload(function (event) { - return false; - }); - - // - content.bind( 'click', function() { - var foundQueue = false; - innerJ('*', content[0]).each( function() { - if ( innerJ(this).queue().length > 0 ) { - foundQueue = true; - innerJ(this).queue( function(){ - setTimeout( adjustFrameSize, 100, true ); - innerJ(this).dequeue(); - }); - } - }); - if ( ! foundQueue ) { - adjustFrameSize( true ); - } - return true; - }); - } else { - content.bind( 'click', function() { - adjustFrameSize( true ); - }); - } - - // find all links. Have to use inner jQuery so event.result below - // reflects the result of inner event handlers. We (hopefully) come last - // in the chain of event handlers as we only attach when the frame is - // already completely loaded, i.e. every inner event handler is already - // attached. - var allLinks = (innerJ)?innerJ("a[href]"):jQuery("a[href]"); - - // catch 'Cancel'-Link (and other 'back'-links) and close frame instead of going back - var backlinks = allLinks.filter('a[href="javascript:history.go(-1);"]'); - backlinks.click(handleCloseFrame); - - // promote any other links to open in main window, prevent nested browsing - allLinks - .not('a[href*="javascript:"]') // scripted links - .not('a[target]') // targeted links - .not('a[href^="#"]') // local links - .not('a.sfFancyBox') // link to file upload - .click(function(event){ - if ( event.result !== false ) { // if not already caught by somebody else - closeFrameAndFollowLink( event.target.getAttribute('href') ); - } - return false; - }); - - // finally show the frame, but only if it is not already visible - if ( ! containerAlreadyVisible ) { - fadeOut ( waitIndicator, function(){ - fadeTo( container, 400, 1 ); - }); - } - - return false; - } - - function handleSubmitData( event ){ - fadeOut( container, function() { - fadeIn( waitIndicator ); - }); - - var form = jQuery( event.target ); - var formdata = form.serialize() + "&wpSave=" + escape(form.find("#wpSave").attr("value")); - - // Send form data off. SF will send back a fake edit page - // - // Normally we should check this.action first and only if it is empty - // revert to this.ownerDocument.URL. Tough luck, IE does not return an - // empty action but fills in some bogus - jQuery.post( event.target.ownerDocument.URL , formdata, handleInnerSubmit); - - return false; - - function handleInnerSubmit ( returnedData, textStatus, XMLHttpRequest ) { - // find form in fake edit page - var innerform = jQuery("<div>" + returnedData + "</div>").find("form"); - - // check if we got an error page - if ( innerform.length === 0 ) { - - form.unbind( event ); - - var iframe = container.find("iframe"); - var doc = iframe[0].contentWindow || iframe[0].contentDocument; - if (doc.document) { - doc = doc.document; - } - - doc.open(); - doc.write(returnedData); - doc.close(); - - return false; - } - - // Send the form data off, we do not care for the returned data - var innerformdata = innerform.serialize(); - jQuery.post( innerform.attr("action"), innerformdata ); - - // build new url for outer page (we have to ask for a purge) - - var url = location.href; - - // does a querystring exist? - var start = url.indexOf("action="); - - if ( start >= 0 ) { - - var stop = url.indexOf("&", start); - - if ( stop >= 0 ) { - url = url.substr( 0, start - 1 ) + url.substr(stop + 1); - } else { - url = url.substr( 0, start - 1 ); - } - - } - - form = jQuery('<form action="' + url + '" method="POST"><input type="hidden" name="action" value="purge"></form>') - .appendTo('body'); - - form - .submit(); - - fadeOut( container, function(){ - fadeIn( waitIndicator ); - }); - - return false; - } - } - - function adjustFrameSize( animate ) { - // set some inputs - var oldFrameW = container.width(); - var oldFrameH = container.height(); - var oldContW = content.width(); - var oldContH = content.height(); - - var availW = Math.floor( jQuery(window).width() * 0.8 ); - var availH = Math.floor( jQuery(window).height() * 0.8 ); - - var emergencyW = Math.floor( jQuery(window).width() * 0.85 ); - var emergencyH = Math.floor( jQuery(window).height() * 0.85 ); - - // FIXME: these might not be the true values - var scrollW = 25; - var scrollH = 25; - - - // find the dimensions of the document - - var body = content.closest('body'); - var html = body.parent(); - - var scrollTgt = html; - - if ( jQuery.browser.webkit || jQuery.browser.safari ) { - scrollTgt = body; - } - - var scrollTop = scrollTgt.scrollTop(); - var scrollLeft = scrollTgt.scrollLeft(); - - content - .css('position', 'absolute') - .width( 'auto' ) - .height( 'auto' ); - - // set max dimensions for layout of content - iframe - .width( emergencyW ) - .height( emergencyH ); - - // get dimension values - var docW = content.width(); - var docH = content.height(); - - // set old dimensions for layout of content - iframe - .width( '100%' ) - .height( '100%' ); - - content - .css('position', 'relative') - .width( oldContW ) - .height( oldContH ); - - if ( jQuery.browser.msie ) { - docW += 20; - docH += 20; - } - - var docpW = docW + 2 * padding; - var docpH = docH + 2 * padding; - - // Flags - - var needsHScroll = docpW > emergencyW || ( docpW > emergencyW - scrollW && docpH > emergencyH ); - var needsVScroll = docpH > emergencyH || ( docpH > emergencyH - scrollH && docpW > emergencyW ); - - var needsWStretch = - ( docpW > availW && docpW <= emergencyW ) && ( docpH <= emergencyH ) || - ( docpW > availW - scrollW && docpW <= emergencyW - scrollW ) && ( docpH > emergencyH ); - - var needsHStretch = - ( docpH > availH && docpH <= emergencyH ) && ( docpW <= emergencyW ) || - ( docpH > availH - scrollH && docpH <= emergencyH - scrollH ) && ( docpW > emergencyW ); - - // Outputs - - var frameW; - var frameH; - - var contW; - var contH; - - if ( needsWStretch ) { - contW = docW; - frameW = docpW; - } else if ( docpW > availW ) { // form does not even fit with stretching - contW = docW; - frameW = availW; - } else { - //contW = Math.max( Math.min( 1.5 * docW, availW ), availW / 2 ); - contW = docW; - frameW = docpW; - } - - if ( needsVScroll ){ - frameW += scrollW; - } else { - scrollTop = 0; - } - - if ( needsHStretch ) { - contH = docH; - frameH = docpH; - } else if ( docpH > availH ) { // form does not even fit with stretching - contH = docH; - frameH = availH; - } else { - //contH = Math.min( 1.1 * docH, availH); - contH = docH; - frameH = docpH; - } - - if ( needsHScroll ){ - frameH += scrollH; - } else { - scrollLeft = 0; - } - - if ( frameW != oldFrameW || frameH != oldFrameH ) { - - if ( jQuery.browser.safari ) { - html[0].style.overflow="hidden"; - } else { - iframe[0].style.overflow="hidden"; - } - - if ( animate ) { - content - .width ( 'auto' ) - .height ( 'auto' ); - - container.animate({ - width: frameW, - height: frameH, - top: Math.floor(( - frameH ) / 2), - left: Math.floor(( - frameW ) / 2) - }, { - duration: 500, - complete: function() { - - if ( jQuery.browser.safari ) { - html[0].style.overflow="visible"; - } else if ( jQuery.browser.msie ) { - iframe[0].style.overflow="auto"; - } else { - iframe[0].style.overflow="visible"; - } - - if ( jQuery.browser.mozilla ) { - content - .width ( contW ) - .height ( contH ); - } else { - content - .width ( 'auto' ) - .height ( 'auto' ); - } - } - }); - - } else { - container - .width( frameW ) - .height ( frameH ); - - container[0].style.top = (Math.floor(( - frameH ) / 2)) + "px"; - container[0].style.left = (Math.floor(( - frameW ) / 2)) + "px"; - - - setTimeout(function(){ - - if ( jQuery.browser.safari ) { - html[0].style.overflow="visible"; - } else if ( jQuery.browser.msie ) { - iframe[0].style.overflow="auto"; - } else { - iframe[0].style.overflow="visible"; - } - - }, 100); - - if ( jQuery.browser.mozilla ) { - content - .width ( contW ) - .height ( contH ); - } else { - content - .width ( 'auto' ) - .height ( 'auto' ); - } - - } - } else { - content - .width ( 'auto' ) - .height ( 'auto' ); - - if ( jQuery.browser.safari ) { // Google chrome needs a kick - - // turn scrollbars off and on again to really only show them when needed - html[0].style.overflow="hidden"; - - setTimeout(function(){ - html[0].style.overflow="visible"; - }, 1); - } - } - - scrollTgt - .css('overflow', 'auto') - .scrollTop(Math.min(scrollTop, docpH - frameH)) - .scrollLeft(scrollLeft); - - if ( jQuery.browser.mozilla ) { - body - .css('overflow', 'auto'); - } - - return true; - } - - function closeFrameAndFollowLink( link ){ - clearTimeout(timer); - - fadeOut( container, function(){ - fadeIn ( waitIndicator ); - window.location.href = link; - }); - } - - function handleCloseFrame( event ){ - jQuery(window).unbind( "resize", adjustFrameSize ); - clearTimeout(timer); - - fadeOut( container, function(){ - background.fadeOut( function(){ - wrapper.remove(); - }); - }); - return false; - } - - // Saw it on http://robertnyman.com/2006/04/24/get-the-rendered-style-of-an-element - // and liked it - function getStyle(oElm, strCssRule){ - var strValue = ""; - if(document.defaultView && document.defaultView.getComputedStyle){ - strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule); - } - else if(oElm.currentStyle){ - strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){ - return p1.toUpperCase(); - }); - strValue = oElm.currentStyle[strCssRule]; - } - return strValue; - } - - function fadeIn(elem, callback ) { - // no fading for broken browsers - if ( brokenBrowser ){ - - elem.show(); - if ( callback ) { - callback(); - } - } else { - // what an ugly hack - if ( elem === waitIndicator ) { - elem.fadeIn( 200, callback ); - } else { - elem.fadeIn( callback ); - } - } - } - - function fadeOut(elem, callback ) { - // no fading for broken browsers - if ( brokenBrowser ){ - elem.hide(); - if ( callback ) { - callback(); - } - } else { - // what an ugly hack - if ( elem === waitIndicator ) { - elem.fadeOut( 200, callback ); - } else { - elem.fadeOut( callback ); - } - } - } - - function fadeTo(elem, time, target, callback) { - // no fading for broken browsers - if ( brokenBrowser ){ - - if (target > 0) { - elem[0].style.visibility = "visible"; - } else { - elem[0].style.visibility = "hidden"; - } - - if ( callback ) { - callback(); - } - - } else { - elem.fadeTo(time, target, callback); - } - } - - // export public funcitons - this.handlePopupFormInput = handlePopupFormInput; - this.handlePopupFormLink = handlePopupFormLink; - this.adjustFrameSize = adjustFrameSize; -}();
\ No newline at end of file diff --git a/SemanticForms/libs/SF_preview.js b/SemanticForms/libs/SF_preview.js deleted file mode 100644 index 0d4f93b7..00000000 --- a/SemanticForms/libs/SF_preview.js +++ /dev/null @@ -1,213 +0,0 @@ -/** - * Handles dynamic Page Preview for Semantic Forms. - * - * @author Stephan Gambke - */ - -/*global validateAll */ - -( function ( $, mw ) { - - 'use strict'; - - var form; - var previewpane; - var previewHeight; - - /** - * Called when the content is loaded into the preview pane - */ - var loadFrameHandler = function handleLoadFrame() { - - var iframe = $( this ); - var iframecontents = iframe.contents(); - - // find div containing the preview - var content = iframecontents.find( '#wikiPreview' ); - - var iframebody = content.closest( 'body' ); - var iframedoc = iframebody.parent(); - iframedoc.height( 'auto' ); - - // this is not a normal MW page (or it uses an unknown skin) - if ( content.length === 0 ) { - content = iframebody; - } - - content.parentsUntil( 'html' ).andSelf() - .css( { - margin: 0, - padding: 0, - width: '100%', - height: 'auto', - minWidth: '0px', - minHeight: '0px', - 'float': 'none', // Cavendish skin uses floating -> unfloat content - border: 'none', - background: 'transparent' - } ) - .siblings() - .hide(); // FIXME: Some JS scripts don't like working on hidden elements - - // and attach event handler to adjust frame size every time the window - // size changes - $( window ).resize( function () { - iframe.height( iframedoc.height() ); - } ); - - previewpane.show(); - - var newPreviewHeight = iframedoc.height(); - - iframe.height( newPreviewHeight ); - - $( 'html, body' ) - .scrollTop( $( 'html, body' ).scrollTop() + newPreviewHeight - previewHeight ) - .animate( { - scrollTop: previewpane.offset().top - }, 1000 ); - - previewHeight = newPreviewHeight; - - return false; - }; - - /** - * Called when the server has sent the preview - */ - var resultReceivedHandler = function handleResultReceived( result ) { - - var htm = result.result; - - var iframe = previewpane.children(); - - if ( iframe.length === 0 ) { - - // set initial height of preview area - previewHeight = 0; - - iframe = $( '<iframe>' ) - .css( { //FIXME: Should this go in a style file? - 'width': '100%', - 'height': previewHeight, - 'border': 'none', - 'overflow': 'hidden' - } ) - .load( loadFrameHandler ) - .appendTo( previewpane ); - - } - - var ifr = iframe[0]; - var doc = ifr.contentDocument || ifr.contentWindow.document || ifr.Document; - - doc.open(); - doc.write( htm ); - doc.close(); - - }; - - /** - * Called when the preview button was clicked - */ - var previewButtonClickedHandler = function handlePreviewButtonClicked() { - - if ( !validateAll() ) { - return; - } - - // data array to be sent to the server - var data = { - action: 'sfautoedit', - format: 'json' - }; - - // do we have a URL like .../index.php?title=pagename&action=formedit ? - if ( mw.config.get( 'wgAction' ) === 'formedit' ) { - - // set the title, server has to find a suitable form - data.target = mw.config.get( 'wgPageName' ); - - // do we have a URL like .../Special:FormEdit/formname/pagename ? - } else if ( mw.config.get( 'wgCanonicalNamespace' ) === 'Special' && mw.config.get( 'wgCanonicalSpecialPageName' ) === 'FormEdit' ) { - - // get the pagename and split it into parts - var pageName = mw.config.get( 'wgPageName' ); - var parts = pageName.split( '/', 3 ); - - if ( parts.length > 1 ) { // found a formname - data.form = parts[1]; - } - - if ( parts.length > 2 ) { // found a pagename - data.target = parts[2]; - } - } - - // add form values to the data - data.query = form.serialize(); - - if ( data.query.length > 0 ) { - data.query += '&'; - } - - data.query += 'wpPreview=' + encodeURIComponent( $( this ).attr( 'value' ) ); - - $.ajax( { - - type: 'POST', // request type ( GET or POST ) - url: mw.util.wikiScript( 'api' ), // URL to which the request is sent - data: data, // data to be sent to the server - dataType: 'json', // type of data expected back from the server - success: resultReceivedHandler // function to be called if the request succeeds - } ); - }; - - /** - * Register plugin - */ - $.fn.sfAjaxPreview = function () { - - form = this.closest( 'form' ); - previewpane = $( '#wikiPreview' ); - - // do some sanity checks - if ( previewpane.length === 0 || // no ajax preview without preview area - previewpane.contents().length > 0 || // preview only on an empty previewpane - form.length === 0 ) { // no ajax preview without form - - return this; - } - - // IE does not allow setting of the 'type' attribute for inputs - // => completely replace the original preview button - var btn = $( '<input type=\'button\' />' ).insertBefore( this ); - - this.remove(); - - // copy all explicitly specified attributes (except 'type' attribute) - // from the old to the new button - var oldBtnElement = this[0]; - var i; - - for ( i = 0; i < oldBtnElement.attributes.length; i = i + 1 ) { - var attribute = oldBtnElement.attributes[i]; - if ( attribute.name !== 'type' ) { - btn.attr( attribute.name, attribute.value ); - } - } - - // register event handler - btn.click( previewButtonClickedHandler ); - - return btn; - }; - - $( document ).ready( function () { - if ( mw.config.get( 'wgAction' ) === 'formedit' || - mw.config.get( 'wgCanonicalSpecialPageName' ) === 'FormEdit' ) { - $( '#wpPreview' ).sfAjaxPreview(); - } - } ); - -}( jQuery, mediaWiki ) ); diff --git a/SemanticForms/libs/SF_submit.js b/SemanticForms/libs/SF_submit.js deleted file mode 100644 index 9a3dcdba..00000000 --- a/SemanticForms/libs/SF_submit.js +++ /dev/null @@ -1,197 +0,0 @@ -/** -* Javascript handler for the save-and-continue button -* - * @author Stephan Gambke -*/ - -/*global validateAll */ - -( function ( $, mw ) { - - 'use strict'; - - var sacButtons; - var form; - - function setChanged( event ) { - sacButtons - .removeAttr( 'disabled' ) - .addClass( 'sf-save_and_continue-changed' ); - - return true; - } - - /** - * Called when the server has sent the preview - */ - var resultReceivedHandler = function handleResultReceived( result, textStatus, jqXHR ) { - - // Store the target name - var target = form.find( 'input[name="target"]' ); - - if ( target.length === 0 ) { - target = $( '<input type="hidden" name="target">' ); - form.append ( target ); - } - - target.attr( 'value', result.target ); - - // Store the form name - target = form.find( 'input[name="form"]' ); - - if ( target.length === 0 ) { - target = $( '<input type="hidden" name="form">' ); - form.append ( target ); - } - - target.attr( 'value', result.form.title ); - - sacButtons - .addClass( 'sf-save_and_continue-ok' ) - .removeClass( 'sf-save_and_continue-wait' ) - .removeClass( 'sf-save_and_continue-error' ); - - }; - - var resultReceivedErrorHandler = function handleError( jqXHR ){ - - var errors = $.parseJSON( jqXHR.responseText ).errors; - - sacButtons - .addClass( 'sf-save_and_continue-error' ) - .removeClass( 'sf-save_and_continue-wait' ); - - // Remove all old error messages and set new ones - $( '.errorbox' ).remove(); - - - if ( errors.length > 0 ){ - var i; - for ( i = 0; i < errors.length; i += 1 ) { - if ( errors[i].level < 2 ) { // show errors and warnings - $( '#contentSub' ) - .append( '<div id="form_error_header" class="errorbox" style="font-size: medium"><img src="' + mw.config.get( 'sfgScriptPath' ) + '/skins/MW-Icon-AlertMark.png" /> ' + errors[i].message + '</div><br clear="both" />' ); - } - } - - $( 'html, body' ).scrollTop( $( '#contentSub' ).offset().top ); - } - }; - - function collectData( form ) { - var summaryfield = jQuery( '#wpSummary', form ); - var saveAndContinueSummary = mw.msg( 'sf_formedit_saveandcontinue_summary', mw.msg( 'sf_formedit_saveandcontinueediting' ) ); - var params; - - if ( summaryfield.length > 0 ) { - - var oldsummary = summaryfield.attr( 'value' ); - - if ( oldsummary !== '' ) { - summaryfield.attr( 'value', oldsummary + ' (' + saveAndContinueSummary + ')' ); - } else { - summaryfield.attr( 'value', saveAndContinueSummary ); - } - - params = form.serialize(); - - summaryfield.attr( 'value', oldsummary ); - } else { - params = form.serialize(); - params += '&wpSummary=' + saveAndContinueSummary; - } - - if ( mw.config.get( 'wgAction' ) === 'formedit' ) { - params += '&target=' + encodeURIComponent( mw.config.get( 'wgPageName' ) ); - } else if ( mw.config.get( 'wgCanonicalSpecialPageName' ) === 'FormEdit' ) { - var url = mw.config.get( 'wgPageName' ); - - var start = url.indexOf( '/' ) + 1; // find start of subpage - var stop; - - if ( start >= 0 ) { - stop = url.indexOf( '/', start ); // find end of first subpage - } else { - stop = -1; - } - - if ( stop >= 0 ) { - params += '&form=' + encodeURIComponent( url.substring( start, stop ) ); - - start = stop + 1; - params += '&target=' + encodeURIComponent( url.substr( start ) ); - - } else { - params += '&form=' + encodeURIComponent( url.substr( start ) ); - } - } - - params += '&wpMinoredit=1'; - - return params; - } - - function handleSaveAndContinue( event ) { - - event.stopImmediatePropagation(); - - // remove old error messages - var el = document.getElementById( 'form_error_header' ); - - if ( el ) { - el.parentNode.removeChild( el ); - } - - if ( validateAll() ) { - // disable save and continue button - sacButtons - .attr( 'disabled', 'disabled' ) - .addClass( 'sf-save_and_continue-wait' ) - .removeClass( 'sf-save_and_continue-changed' ); - - var form = $( '#sfForm' ); - - var data = { - action: 'sfautoedit', - format: 'json', - query: collectData( form ) // add form values to the data - }; - - data.query += '&wpSave=' + encodeURIComponent( $( event.currentTarget ).attr( 'value' ) ); - - $.ajax( { - - type: 'POST', // request type ( GET or POST ) - url: mw.util.wikiScript( 'api' ), // URL to which the request is sent - data: data, // data to be sent to the server - dataType: 'json', // type of data expected back from the server - success: resultReceivedHandler, // function to be called if the request succeeds - error: resultReceivedErrorHandler // function to be called on error - } ); - - } - - return false; - } - - if ( mw.config.get( 'wgAction' ) === 'formedit' || mw.config.get( 'wgCanonicalSpecialPageName' ) === 'FormEdit' ) { - form = $( '#sfForm' ); - - sacButtons = $( '.sf-save_and_continue', form ); - sacButtons.click( handleSaveAndContinue ); - - $( form ) - .on( 'keyup', 'input,select,textarea', function ( event ) { - if ( event.which < 32 ){ - return true; - } - - return setChanged( event ); - } ) - .on( 'change', 'input,select,textarea', setChanged ) - .on( 'click', '.multipleTemplateAdder,.removeButton,.rearrangerImage', setChanged ) - .on( 'mousedown', '.rearrangerImage',setChanged ); - - } - -}( jQuery, mediaWiki ) ); diff --git a/SemanticForms/libs/SF_wikieditor.js b/SemanticForms/libs/SF_wikieditor.js deleted file mode 100644 index 85270810..00000000 --- a/SemanticForms/libs/SF_wikieditor.js +++ /dev/null @@ -1,42 +0,0 @@ -// create ext if it does not exist yet -/*global wgWikiEditorEnabledModules*/ -if ( window.ext == null || typeof( window.ext ) === "undefined" ) { - window.ext = {}; -} - -window.ext.wikieditor = { - // initialize the wikieditor on the specified element - init : function init ( input_id, params ) { - jQuery( function() { - if ( window.mediaWiki ) { - var input = jQuery( '#' + input_id ); - - // load toolbar - mediaWiki.loader.using( ['jquery.wikiEditor.toolbar', 'jquery.wikiEditor.toolbar.config'] , function(){ - if ( jQuery.wikiEditor.isSupported( jQuery.wikiEditor.modules.toolbar ) ) { - input.wikiEditor( 'addModule', jQuery.wikiEditor.modules.toolbar.config.getDefaultConfig() ); - - // hide sig if required - if ( wgWikiEditorEnabledModules && wgWikiEditorEnabledModules.hidesig === true ) { - input.wikiEditor( 'removeFromToolbar', { - 'section': 'main', - 'group': 'insert', - 'tool': 'signature' - } ); - } - - } - }); - - // load dialogs - mediaWiki.loader.using( ['jquery.wikiEditor.dialogs', 'jquery.wikiEditor.dialogs.config'] , function(){ - if ( jQuery.wikiEditor.isSupported( jQuery.wikiEditor.modules.dialogs ) ) { - jQuery.wikiEditor.modules.dialogs.config.replaceIcons( input ); - input.wikiEditor( 'addModule', $.wikiEditor.modules.dialogs.config.getDefaultConfig() ); - - } - }); - } - }); - } -}; diff --git a/SemanticForms/libs/SemanticForms.js b/SemanticForms/libs/SemanticForms.js deleted file mode 100644 index 49e07ae7..00000000 --- a/SemanticForms/libs/SemanticForms.js +++ /dev/null @@ -1,1084 +0,0 @@ -/** - * SemanticForms.js - * - * Javascript utility functions for the Semantic Forms extension. - * - * @author Yaron Koren - * @author Sanyam Goyal - * @author Stephan Gambke - * @author Jeffrey Stuckman - * @author Harold Solbrig - * @author Eugene Mednikov - */ - /*global sfgShowOnSelect, sfgFieldProperties, validateAll, alert, sf*/ - -// Activate autocomplete functionality for the specified field -(function(jQuery) { - - /* extending jQuery functions for custom highlighting */ - jQuery.ui.autocomplete.prototype._renderItem = function( ul, item) { - - var delim = this.element.context.delimiter; - var term; - if ( delim === null ) { - term = this.term; - } else { - term = this.term.split( delim ).pop(); - } - var re = new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"); - var loc = item.label.search(re); - var t; - if (loc >= 0) { - t = item.label.substr(0, loc) + '<strong>' + item.label.substr(loc, term.length) + '</strong>' + item.label.substr(loc + term.length); - } else { - t = item.label; - } - return jQuery( "<li></li>" ) - .data( "item.autocomplete", item ) - .append( " <a>" + t + "</a>" ) - .appendTo( ul ); - }; - - jQuery.fn.attachAutocomplete = function() { - return this.each(function() { - // Get all the necessary values from the input's "autocompletesettings" - // attribute. This should probably be done as three separate attributes, - // instead. - var field_string = jQuery(this).attr("autocompletesettings"); - - if ( typeof field_string === 'undefined' ) { - return; - } - - var field_values = field_string.split(','); - var delimiter = null; - var data_source = field_values[0]; - if (field_values[1] == 'list') { - delimiter = ","; - if (field_values[2] !== null && field_values[2] !== undefined) { - delimiter = field_values[2]; - } - } - - // Modify the delimiter. If it's "\n", change it to an actual - // newline - otherwise, add a space to the end. - // This doesn't cover the case of a delimiter that's a newline - // plus something else, like ".\n" or "\n\n", but as far as we - // know no one has yet needed that. - if ( delimiter !== null && delimiter !== undefined ) { - if ( delimiter == "\\n" ) { - delimiter = "\n"; - } else { - delimiter += " "; - } - } - // Store this value within the object, so that it can be used - // during highlighting of the search term as well. - this.delimiter = delimiter; - - /* extending jquery functions */ - jQuery.extend( jQuery.ui.autocomplete, { - filter: function(array, term) { - var sfgAutocompleteOnAllChars = mw.config.get( 'sfgAutocompleteOnAllChars' ); - var matcher; - if ( sfgAutocompleteOnAllChars ) { - matcher = new RegExp(jQuery.ui.autocomplete.escapeRegex(term), "i" ); - } else { - matcher = new RegExp("\\b" + jQuery.ui.autocomplete.escapeRegex(term), "i" ); - } - return jQuery.grep( array, function(value) { - return matcher.test( value.label || value.value || value ); - }); - } - }); - - var values = jQuery(this).data('autocompletevalues'); - if ( !values ) { - var sfgAutocompleteValues = mw.config.get( 'sfgAutocompleteValues' ); - values = sfgAutocompleteValues[field_string]; - } - var split = function (val) { - return val.split(delimiter); - }; - var extractLast = function (term) { - return split(term).pop(); - }; - if (values !== null && values !== undefined) { - // Local autocompletion - - if (delimiter !== null && delimiter !== undefined) { - // Autocomplete for multiple values - - var thisInput = jQuery(this); - - jQuery(this).autocomplete({ - minLength: 0, - source: function(request, response) { - // We need to re-get the set of values, since - // the "values" variable gets overwritten. - values = thisInput.data( 'autocompletevalues' ); - if ( !values ) { - values = sfgAutocompleteValues[field_string]; - } - response(jQuery.ui.autocomplete.filter(values, extractLast(request.term))); - }, - focus: function() { - // prevent value inserted on focus - return false; - }, - select: function(event, ui) { - var terms = split( this.value ); - // remove the current input - terms.pop(); - // add the selected item - terms.push( ui.item.value ); - // add placeholder to get the comma-and-space at the end - terms.push(""); - this.value = terms.join(delimiter); - return false; - } - }); - - } else { - // Autocomplete for a single value - jQuery(this).autocomplete({ - source:values - }); - } - } else { - // Remote autocompletion. - var myServer = mw.util.wikiScript( 'api' ); - var data_type = jQuery(this).attr("autocompletedatatype"); - myServer += "?action=sfautocomplete&format=json&" + data_type + "=" + data_source; - - if (delimiter !== null && delimiter !== undefined) { - jQuery(this).autocomplete({ - source: function(request, response) { - jQuery.getJSON(myServer, { - substr: extractLast(request.term) - }, function( data ) { - response(jQuery.map(data.sfautocomplete, function(item) { - return { - value: item.title - }; - })); - }); - }, - search: function() { - // custom minLength - var term = extractLast(this.value); - if (term.length < 1) { - return false; - } - }, - focus: function() { - // prevent value inserted on focus - return false; - }, - select: function(event, ui) { - var terms = split( this.value ); - // remove the current input - terms.pop(); - // add the selected item - terms.push( ui.item.value ); - // add placeholder to get the comma-and-space at the end - terms.push(""); - this.value = terms.join(delimiter); - return false; - } - } ); - } else { - jQuery(this).autocomplete({ - minLength: 1, - source: function(request, response) { - jQuery.ajax({ - url: myServer, - dataType: "json", - data: { - substr:request.term - }, - success: function( data ) { - response(jQuery.map(data.sfautocomplete, function(item) { - return { - value: item.title - }; - })); - } - }); - }, - open: function() { - jQuery(this).removeClass("ui-corner-all").addClass("ui-corner-top"); - }, - close: function() { - jQuery(this).removeClass("ui-corner-top").addClass("ui-corner-all"); - } - } ); - } - } - }); - }; -})( jQuery ); - - -/* - * Functions to register/unregister methods for the initialization and - * validation of inputs. - */ - -// Initialize data object to hold initialization and validation data -function setupSF() { - - jQuery("#sfForm").data("SemanticForms",{ - initFunctions : [], - validationFunctions : [] - }); - -} - -// Register a validation method -// -// More than one method may be registered for one input by subsequent calls to -// SemanticForms_registerInputValidation. -// -// Validation functions and their data are stored in a numbered array -// -// @param valfunction The validation functions. Must take a string (the input's id) and an object as parameters -// @param param The parameter object given to the validation function -jQuery.fn.SemanticForms_registerInputValidation = function(valfunction, param) { - - if ( ! this.attr("id") ) { - return this; - } - - if ( ! jQuery("#sfForm").data("SemanticForms") ) { - setupSF(); - } - - jQuery("#sfForm").data("SemanticForms").validationFunctions.push({ - input : this.attr("id"), - valfunction : valfunction, - parameters : param - }); - - return this; -}; - -// Register an initialization method -// -// More than one method may be registered for one input by subsequent calls to -// SemanticForms_registerInputInit. This method also executes the initFunction -// if the element referenced by /this/ is not part of a multipleTemplateStarter. -// -// Initialization functions and their data are stored in a associative array -// -// @param initFunction The initialization function. Must take a string (the input's id) and an object as parameters -// @param param The parameter object given to the initialization function -// @param noexecute If set, the initialization method will not be executed here -jQuery.fn.SemanticForms_registerInputInit = function( initFunction, param, noexecute ) { - - // return if element has no id - if ( ! this.attr("id") ) { - return this; - } - - // setup data structure if necessary - if ( ! jQuery("#sfForm").data("SemanticForms") ) { - setupSF(); - } - - // if no initialization function for this input was registered yet, - // create entry - if ( ! jQuery("#sfForm").data("SemanticForms").initFunctions[this.attr("id")] ) { - jQuery("#sfForm").data("SemanticForms").initFunctions[this.attr("id")] = []; - } - - // record initialization function - jQuery("#sfForm").data("SemanticForms").initFunctions[this.attr("id")].push({ - initFunction : initFunction, - parameters : param - }); - - // execute initialization if input is not part of multipleTemplateStarter - // and if not forbidden - if ( this.closest(".multipleTemplateStarter").length === 0 && !noexecute) { - var input = this; - // ensure initFunction is only exectued after doc structure is complete - jQuery(function() {initFunction ( input.attr("id"), param );}); - } - - return this; -}; - -// Unregister all validation methods for the element referenced by /this/ -jQuery.fn.SemanticForms_unregisterInputValidation = function() { - - var sfdata = jQuery("#sfForm").data("SemanticForms"); - - if ( this.attr("id") && sfdata ) { - // delete every validation method for this input - for ( var i = 0; i < sfdata.validationFunctions.length; i++ ) { - if ( typeof sfdata.validationFunctions[i] !== 'undefined' && - sfdata.validationFunctions[i].input == this.attr("id") ) { - delete sfdata.validationFunctions[i]; - } - } - } - - return this; -}; - -// Unregister all initialization methods for the element referenced by /this/ -jQuery.fn.SemanticForms_unregisterInputInit = function() { - - if ( this.attr("id") && jQuery("#sfForm").data("SemanticForms") ) { - delete jQuery("#sfForm").data("SemanticForms").initFunctions[this.attr("id")]; - } - - return this; -}; - -/* - * Functions for handling 'show on select' - */ - -// Display a div that would otherwise be hidden by "show on select". -function showDiv(div_id, instanceWrapperDiv, speed) { - var elem = jQuery('[id="' + div_id + '"]', instanceWrapperDiv); - - elem - .find(".hiddenBySF") - .removeClass('hiddenBySF') - - .find(".disabledBySF") - .removeAttr('disabled') - .removeClass('disabledBySF'); - - elem.each( function() { - if ( jQuery(this).css('display') == 'none' ) { - - jQuery(this).slideDown(speed, function() { - jQuery(this).fadeTo(speed,1); - }); - - } - }); -} - -// Hide a div due to "show on select". The CSS class is there so that SF can -// ignore the div's contents when the form is submitted. -function hideDiv(div_id, instanceWrapperDiv, speed) { - // IDs can't contain spaces, and jQuery won't work with such IDs - if - // this one has a space, display an alert. - if ( div_id.indexOf( ' ' ) > -1 ) { - // TODO - this should probably be a language value, instead of - // hardcoded in English. - alert( "Warning: this form has \"show on select\" pointing to an invalid element ID (\"" + div_id + "\") - IDs in HTML cannot contain spaces." ); - } - - var elem = jQuery('[id="' + div_id + '"]', instanceWrapperDiv); - elem.find("span, div").addClass('hiddenBySF'); - - elem.each( function() { - if ( jQuery(this).css('display') != 'none' ) { - - // if 'display' is not 'hidden', but the element is hidden otherwise - // (e.g. by having height = 0), just hide it, else animate the hiding - if ( jQuery(this).is(':hidden') ) { - jQuery(this).hide(); - } else { - jQuery(this).fadeTo(speed, 0, function() { - jQuery(this).slideUp(speed); - }); - } - } - }); -} - -// Show this div if the current value is any of the relevant options - -// otherwise, hide it. -function showDivIfSelected(options, div_id, inputVal, instanceWrapperDiv, initPage) { - for ( var i = 0; i < options.length; i++ ) { - // If it's a listbox and the user has selected more than one - // value, it'll be an array - handle either case. - if ((jQuery.isArray(inputVal) && jQuery.inArray(options[i], inputVal) >= 0) || - (!jQuery.isArray(inputVal) && (inputVal == options[i]))) { - showDiv( div_id, instanceWrapperDiv, initPage ? 0 : 'fast' ); - return; - } - } - hideDiv(div_id, instanceWrapperDiv, initPage ? 0 : 'fast' ); -} - -// Used for handling 'show on select' for the 'dropdown' and 'listbox' inputs. -jQuery.fn.showIfSelected = function(initPage) { - var inputVal = this.val(); - var sfgShowOnSelect = mw.config.get( 'sfgShowOnSelect' ); - var showOnSelectVals = sfgShowOnSelect[this.attr("id")]; - - var instanceWrapperDiv = this.closest('.multipleTemplateInstance'); - if ( instanceWrapperDiv.length === 0 ) { - instanceWrapperDiv = null; - } - - if ( showOnSelectVals !== undefined ) { - for ( var i = 0; i < showOnSelectVals.length; i++ ) { - var options = showOnSelectVals[i][0]; - var div_id = showOnSelectVals[i][1]; - showDivIfSelected( options, div_id, inputVal, instanceWrapperDiv, initPage ); - } - } - - return this; -}; - -// Show this div if any of the relevant selections are checked - -// otherwise, hide it. -jQuery.fn.showDivIfChecked = function(options, div_id, instanceWrapperDiv, initPage ) { - for ( var i = 0; i < options.length; i++ ) { - if (jQuery(this).find('[value="' + options[i] + '"]').is(":checked")) { - showDiv(div_id, instanceWrapperDiv, initPage ? 0 : 'fast' ); - return this; - } - } - hideDiv(div_id, instanceWrapperDiv, initPage ? 0 : 'fast' ); - - return this; -}; - -// Used for handling 'show on select' for the 'checkboxes' and 'radiobutton' -// inputs. -jQuery.fn.showIfChecked = function(initPage) { - var sfgShowOnSelect = mw.config.get( 'sfgShowOnSelect' ); - var showOnSelectVals = sfgShowOnSelect[this.attr("id")]; - - var instanceWrapperDiv = this.closest('.multipleTemplateInstance'); - if ( instanceWrapperDiv.length === 0 ) { - instanceWrapperDiv = null; - } - - if ( showOnSelectVals !== undefined ) { - for ( var i = 0; i < showOnSelectVals.length; i++ ) { - var options = showOnSelectVals[i][0]; - var div_id = showOnSelectVals[i][1]; - this.showDivIfChecked(options, div_id, instanceWrapperDiv, initPage ); - } - } - - return this; -}; - -// Used for handling 'show on select' for the 'checkbox' input. -jQuery.fn.showIfCheckedCheckbox = function(initPage) { - var sfgShowOnSelect = mw.config.get( 'sfgShowOnSelect' ); - var div_id = sfgShowOnSelect[this.attr("id")]; - - var instanceWrapperDiv = this.closest('.multipleTemplateInstance'); - if ( instanceWrapperDiv.length === 0 ) { - instanceWrapperDiv = null; - } - - if (jQuery(this).is(":checked")) { - showDiv(div_id, instanceWrapperDiv, initPage ? 0 : 'fast' ); - } else { - hideDiv(div_id, instanceWrapperDiv, initPage ? 0 : 'fast' ); - } - - return this; -}; - -/* - * Validation functions - */ - -// Display an error message on the end of an input. -jQuery.fn.addErrorMessage = function(msg, val) { - this.append(' ').append( $('<span>').addClass( 'errorMessage' ).text( mw.msg( msg, val ) ) ); -}; - -jQuery.fn.validateNumInstances = function() { - var minimumInstances = this.attr("minimumInstances"); - var maximumInstances = this.attr("maximumInstances"); - var numInstances = this.find("div.multipleTemplateInstance").length; - if ( numInstances < minimumInstances ) { - this.parent().addErrorMessage( 'sf_too_few_instances_error', minimumInstances ); - return false; - } else if ( numInstances > maximumInstances ) { - this.parent().addErrorMessage( 'sf_too_many_instances_error', maximumInstances ); - return false; - } else { - return true; - } -}; - -jQuery.fn.validateMandatoryField = function() { - var fieldVal = this.find(".mandatoryField").val(); - var isEmpty; - if (fieldVal === null) { - isEmpty = true; - } else if (jQuery.isArray(fieldVal)) { - isEmpty = (fieldVal.length === 0); - } else { - isEmpty = (fieldVal.replace(/\s+/, '') === ''); - } - if (isEmpty) { - this.addErrorMessage( 'sf_blank_error' ); - return false; - } else { - return true; - } -}; - -jQuery.fn.validateMandatoryComboBox = function() { - var combobox = this.find( "input.sfComboBox" ); - if (combobox.val() === '') { - this.addErrorMessage( 'sf_blank_error' ); - return false; - } else { - return true; - } -}; - -jQuery.fn.validateMandatoryDateField = function() { - if (this.find(".dayInput").val() === '' || - this.find(".monthInput").val() === '' || - this.find(".yearInput").val() === '') { - this.addErrorMessage( 'sf_blank_error' ); - return false; - } else { - return true; - } -}; - -// Special handling for radiobuttons, because what's being checked -// is the first radiobutton, which has an empty value. -jQuery.fn.validateMandatoryRadioButton = function() { - if (this.find("[value='']").is(':checked')) { - this.addErrorMessage( 'sf_blank_error' ); - return false; - } else { - return true; - } -}; - -jQuery.fn.validateMandatoryCheckboxes = function() { - // Get the number of checked checkboxes within this span - must - // be at least one. - var numChecked = this.find("input:checked").size(); - if (numChecked === 0) { - this.addErrorMessage( 'sf_blank_error' ); - return false; - } else { - return true; - } -}; - -/* - * Type-based validation - */ - -jQuery.fn.validateURLField = function() { - var fieldVal = this.find("input").val(); - // code borrowed from http://snippets.dzone.com/posts/show/452 - var url_regexp = /(ftp|http|https|rtsp|news):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/; - if (fieldVal === "" || url_regexp.test(fieldVal)) { - return true; - } else { - this.addErrorMessage( 'sf_bad_url_error' ); - return false; - } -}; - -jQuery.fn.validateEmailField = function() { - var fieldVal = this.find("input").val(); - // code borrowed from http://javascript.internet.com/forms/email-validation---basic.html - var email_regexp = /^\s*\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,6})+\s*$/; - if (fieldVal === '' || email_regexp.test(fieldVal)) { - return true; - } else { - this.addErrorMessage( 'sf_bad_email_error' ); - return false; - } -}; - -jQuery.fn.validateNumberField = function() { - var fieldVal = this.find("input").val(); - // Handle "E notation"/scientific notation ("1.2e-3") in addition - // to regular numbers - if (fieldVal === '' || - fieldVal.match(/^\s*[\-+]?((\d+[\.,]?\d*)|(\d*[\.,]?\d+))([eE]?[\-\+]?\d+)?\s*$/)) { - return true; - } else { - this.addErrorMessage( 'sf_bad_number_error' ); - return false; - } -}; - -jQuery.fn.validateDateField = function() { - // validate only if day and year fields are both filled in - var dayVal = this.find(".dayInput").val(); - var yearVal = this.find(".yearInput").val(); - if (dayVal === '' || yearVal === '') { - return true; - } else if (dayVal.match(/^\d+$/) && dayVal <= 31) { - // no year validation, since it can also include - // 'BC' and possibly other non-number strings - return true; - } else { - this.addErrorMessage( 'sf_bad_date_error' ); - return false; - } -}; - -window.validateAll = function () { - var num_errors = 0; - - // Remove all old error messages. - jQuery(".errorMessage").remove(); - - // Make sure all inputs are ignored in the "starter" instance - // of any multiple-instance template. - jQuery(".multipleTemplateStarter").find("span, div").addClass("hiddenBySF"); - - jQuery(".multipleTemplateList").each( function() { - if (! jQuery(this).validateNumInstances() ) { - num_errors += 1; - } - }); - - jQuery("span.inputSpan.mandatoryFieldSpan").not(".hiddenBySF").each( function() { - if (! jQuery(this).validateMandatoryField() ) { - num_errors += 1; - } - }); - jQuery("div.ui-widget.mandatory").not(".hiddenBySF").each( function() { - if (! jQuery(this).validateMandatoryComboBox() ) { - num_errors += 1; - } - }); - jQuery("span.dateInput.mandatoryFieldSpan").not(".hiddenBySF").each( function() { - if (! jQuery(this).validateMandatoryDateField() ) { - num_errors += 1; - } - }); - jQuery("span.radioButtonSpan.mandatoryFieldSpan").not(".hiddenBySF").each( function() { - if (! jQuery(this).validateMandatoryRadioButton() ) { - num_errors += 1; - } - }); - jQuery("span.checkboxesSpan.mandatoryFieldSpan").not(".hiddenBySF").each( function() { - if (! jQuery(this).validateMandatoryCheckboxes() ) { - num_errors += 1; - } - }); - jQuery("span.URLInput").not(".hiddenBySF").each( function() { - if (! jQuery(this).validateURLField() ) { - num_errors += 1; - } - }); - jQuery("span.emailInput").not(".hiddenBySF").each( function() { - if (! jQuery(this).validateEmailField() ) { - num_errors += 1; - } - }); - jQuery("span.numberInput").not(".hiddenBySF").each( function() { - if (! jQuery(this).validateNumberField() ) { - num_errors += 1; - } - }); - jQuery("span.dateInput").not(".hiddenBySF").each( function() { - if (! jQuery(this).validateDateField() ) { - num_errors += 1; - } - }); - - // call registered validation functions - var sfdata = jQuery("#sfForm").data('SemanticForms'); - - if ( sfdata && sfdata.validationFunctions.length > 0 ) { // found data object? - - // for every registered input - for ( var i = 0; i < sfdata.validationFunctions.length; i++ ) { - - // if input is not part of multipleTemplateStarter - if ( typeof sfdata.validationFunctions[i] !== 'undefined' && - jQuery("#" + sfdata.validationFunctions[i].input).closest(".multipleTemplateStarter").length === 0 && - jQuery("#" + sfdata.validationFunctions[i].input).closest(".hiddenBySF").length === 0 ) { - - if (! sfdata.validationFunctions[i].valfunction( - sfdata.validationFunctions[i].input, - sfdata.validationFunctions[i].parameters) - ) { - num_errors += 1; - } - } - } - } - - if (num_errors > 0) { - // add error header, if it's not there already - if (jQuery("#form_error_header").size() === 0) { - jQuery("#contentSub").append('<div id="form_error_header" class="errorbox" style="font-size: medium"><img src="' + mw.config.get( 'sfgScriptPath' ) + '/skins/MW-Icon-AlertMark.png" /> ' + mw.message( 'sf_formerrors_header' ).escaped() + '</div><br clear="both" />'); - } - scroll(0, 0); - } else { - // Disable inputs hidden due to either "show on select" or - // because they're part of the "starter" div for - // multiple-instance templates, so that they aren't - // submitted by the form. - jQuery('.hiddenBySF').find("input, select, textarea").not(':disabled') - .attr('disabled', 'disabled') - .addClass('disabledBySF'); - //remove error box if it exists because there are no errors in the form now - jQuery("#contentSub").find(".errorbox").remove(); - } - return (num_errors === 0); -}; - -/** - * Functions for multiple-instance templates. - */ - -jQuery.fn.addInstance = function( addAboveCurInstance ) { - // Global variable. - num_elements++; - - // Create the new instance - var new_div = this.closest(".multipleTemplateWrapper") - .find(".multipleTemplateStarter") - .clone() - .removeClass('multipleTemplateStarter') - .addClass('multipleTemplateInstance') - .addClass('multipleTemplate') // backwards compatibility - .removeAttr("id") - .fadeTo(0,0) - .slideDown('fast', function() { - jQuery(this).fadeTo('fast', 1); - }); - - new_div.find('.hiddenBySF') - .removeClass('hiddenBySF') - - .find('.disabledBySF') - .removeAttr('disabled') - .removeClass('disabledBySF'); - - // Make internal ID unique for the relevant form elements, and replace - // the [num] index in the element names with an actual unique index - new_div.find("input, select, textarea").each( - function() { - // Add in a 'b' at the end of the name to reduce the - // chance of name collision with another field - if (this.name) { - var old_name = this.name.replace(/\[num\]/g, ''); - jQuery(this).attr('origName', old_name); - this.name = this.name.replace(/\[num\]/g, '[' + num_elements + 'b]'); - } - - if (this.id) { - - var old_id = this.id; - - this.id = this.id.replace(/input_/g, 'input_' + num_elements + '_'); - - // TODO: Data in sfgShowOnSelect should probably be stored in - // jQuery("#sfForm").data('SemanticForms') - if ( sfgShowOnSelect[ old_id ] ) { - sfgShowOnSelect[ this.id ] = sfgShowOnSelect[ old_id ]; - } - - // register initialization and validation methods for new inputs - - var sfdata = jQuery("#sfForm").data('SemanticForms'); - if ( sfdata ) { // found data object? - var i; - if ( sfdata.initFunctions[old_id] ) { - - // For every initialization method for - // input with id old_id, register the - // method for the new input. - for ( i = 0; i < sfdata.initFunctions[old_id].length; i++ ) { - - jQuery(this).SemanticForms_registerInputInit( - sfdata.initFunctions[old_id][i].initFunction, - sfdata.initFunctions[old_id][i].parameters, - true //do not yet execute - ); - } - } - - // For every validation method for the - // input with ID old_id, register it - // for the new input. - for ( i = 0; i < sfdata.validationFunctions.length; i++ ) { - - if ( typeof sfdata.validationFunctions[i] !== 'undefined' && - sfdata.validationFunctions[i].input == old_id ) { - - jQuery(this).SemanticForms_registerInputValidation( - sfdata.validationFunctions[i].valfunction, - sfdata.validationFunctions[i].parameters - ); - } - } - } - } - } - ); - - new_div.find('a').attr('href', function() { - return this.href.replace(/input_/g, 'input_' + num_elements + '_'); - }); - - new_div.find('span').attr('id', function() { - return this.id.replace(/span_/g, 'span_' + num_elements + '_'); - }); - - // Add the new instance - if ( addAboveCurInstance ) { - new_div.insertBefore(this.closest(".multipleTemplateInstance")); - } else { - this.closest(".multipleTemplateWrapper") - .find(".multipleTemplateList") - .append(new_div); - } - - new_div.initializeJSElements(true); - - // Initialize new inputs - new_div.find("input, select, textarea").each( - function() { - - if (this.id) { - - var sfdata = jQuery("#sfForm").data('SemanticForms'); - if ( sfdata ) { - - // have to store data array: the id attribute - // of 'this' might be changed in the init function - var thatData = sfdata.initFunctions[this.id] ; - - if ( thatData ) { // if anything registered at all - // Call every initialization method - // for this input - for ( var i = 0; i < thatData.length; i++ ) { - thatData[i].initFunction( - this.id, - thatData[i].parameters - ); - } - } - } - } - } - ); - -}; - -// The first argument is needed, even though it's an attribute of the element -// on which this function is called, because it's the 'name' attribute for -// regular inputs, and the 'origName' attribute for inputs in multiple-instance -// templates. -jQuery.fn.setDependentAutocompletion = function( dependentField, baseField, baseValue ) { - var propName = sfgFieldProperties[dependentField]; - var baseProp = sfgFieldProperties[baseField]; - var myServer = mw.config.get( 'wgScriptPath' ) + "/api.php"; - myServer += "?action=sfautocomplete&format=json&property=" + propName + "&baseprop=" + baseProp + "&basevalue=" + baseValue; - var dependentValues = []; - var thisInput = jQuery(this); - // We use jQuery.ajax() here instead of jQuery.getJSON() so that the - // 'async' parameter can be set. That, in turn, is set because - // if the 2nd, "dependent" field is a combo box, it can have weird - // behavior: clicking on the down arrow for the combo box leads to a - // "blur" event for the base field, which causes the possible - // values to get recalculated, but not in time for the dropdown to - // change values - it still shows the old values. By setting - // "async: false", we guarantee that old values won't be shown - if - // the values haven't been recalculated yet, the dropdown won't - // appear at all. - // @TODO - handle this the right way, by having special behavior for - // the dropdown - it should get delayed until the values are - // calculated, then appear. - jQuery.ajax({ - url: myServer, - dataType: 'json', - async: false, - success: function(data) { - var realData = data.sfautocomplete; - jQuery.each(realData, function(key, val) { - dependentValues.push(val.title); - }); - thisInput.data('autocompletevalues', dependentValues); - thisInput.attachAutocomplete(); - } - }); -}; - -/** - * Called on a 'base' field (e.g., for a country) - sets the autocompletion - * for its 'dependent' field (e.g., for a city). - */ -jQuery.fn.setAutocompleteForDependentField = function( partOfMultiple ) { - var curValue = jQuery(this).val(); - if ( curValue === null ) { return this; } - - var nameAttr = partOfMultiple ? 'origName' : 'name'; - var name = jQuery(this).attr(nameAttr); - var sfgDependentFields = mw.config.get( 'sfgDependentFields' ); - var dependent_on_me = []; - for ( var i = 0; i < sfgDependentFields.length; i++ ) { - var dependentFieldPair = sfgDependentFields[i]; - if ( dependentFieldPair[0] == name ) { - dependent_on_me.push(dependentFieldPair[1]); - } - } - dependent_on_me = jQuery.unique(dependent_on_me); - - var self = this; - jQuery.each( dependent_on_me, function() { - var dependentField = this; - var dependent_field_element; - if ( partOfMultiple ) { - dependent_field_element = jQuery(self).closest(".multipleTemplateInstance") - .find('[origName="' + dependentField + '"]'); - } else { - dependent_field_element = jQuery('[name="' + dependentField + '"]'); - } - var class_name = $(dependent_field_element).attr( 'class' ); - if ( class_name.indexOf( 'sfComboBox' ) != -1 ) { - var cmbox = new sf.select2.combobox(); - cmbox.refresh(dependent_field_element); - } else if ( class_name.indexOf( 'sfTokens' ) != -1 ) { - var tokens = new sf.select2.tokens(); - tokens.refresh(dependent_field_element); - } else { - dependent_field_element.setDependentAutocompletion(dependentField, name, curValue); - } - }); - - - return this; -}; - -/** - * Initialize all the JS-using elements contained within this block - can be - * called for either the entire HTML body, or for a div representing an - * instance of a multiple-instance template. - */ -jQuery.fn.initializeJSElements = function( partOfMultiple ) { - this.find(".sfShowIfSelected").each( function() { - jQuery(this) - .showIfSelected(true) - .change( function() { - jQuery(this).showIfSelected(false); - }); - }); - - this.find(".sfShowIfChecked").each( function() { - jQuery(this) - .showIfChecked(true) - .click( function() { - jQuery(this).showIfChecked(false); - }); - }); - - this.find(".sfShowIfCheckedCheckbox").each( function() { - jQuery(this) - .showIfCheckedCheckbox(true) - .click( function() { - jQuery(this).showIfCheckedCheckbox(false); - }); - }); - - // Enable the new remove button - this.find(".removeButton").click( function() { - - // Unregister initialization and validation for deleted inputs - jQuery(this).parentsUntil( '.multipleTemplateInstance' ).last().parent().find("input, select, textarea").each( - function() { - jQuery(this).SemanticForms_unregisterInputInit(); - jQuery(this).SemanticForms_unregisterInputValidation(); - } - ); - - // Remove the encompassing div for this instance. - jQuery(this).closest(".multipleTemplateInstance") - .fadeTo('fast', 0, function() { - jQuery(this).slideUp('fast', function() { - jQuery(this).remove(); - }); - }); - return false; - }); - - // ...and the new adder - if ( partOfMultiple ) { - this.find('.addAboveButton').click( function() { - jQuery(this).addInstance( true ); - return false; // needed to disable <a> behavior - }); - } - - this.find('.autocompleteInput').attachAutocomplete(); - - var combobox = new sf.select2.combobox(); - this.find('.sfComboBox').not('#semantic_property_starter, .multipleTemplateStarter .sfComboBox, .select2-container').each( function() { - combobox.apply($(this)); - }); - - var tokens = new sf.select2.tokens(); - this.find('.sfTokens').not('.multipleTemplateStarter .sfTokens, .select2-container').each( function() { - tokens.apply($(this)); - }); - - this.find('.autoGrow').autoGrow(); - this.find('.sfFancyBox').fancybox({ - 'width' : '75%', - 'height' : '75%', - 'autoScale' : false, - 'transitionIn' : 'none', - 'transitionOut' : 'none', - 'type' : 'iframe', - 'overlayColor' : '#222', - 'overlayOpacity' : '0.8' - }); - - // @TODO - this should ideally be called only for inputs that have - // a dependent field - which might involve changing the storage of - // "dependent fields" information from a global variable to a - // per-input HTML attribute. - this.find('input, select').each( function() { - jQuery(this) - .setAutocompleteForDependentField( partOfMultiple ) - .blur( function() { - jQuery(this).setAutocompleteForDependentField( partOfMultiple ); - }); - }); - // The 'blur' event doesn't get triggered for radio buttons for - // Chrome and Safari (the WebKit-based browsers) so use the 'change' - // event in addition. - // @TODO - blur() shuldn't be called at all for radio buttons. - this.find('input:radio') - .change( function() { - jQuery(this).setAutocompleteForDependentField( partOfMultiple ); - }); -}; - -var num_elements = 0; - -// Once the document has finished loading, set up everything! -jQuery(document).ready(function() { - jQuery('body').initializeJSElements(); - - jQuery('.multipleTemplateInstance').initializeJSElements(true); - jQuery('.multipleTemplateAdder').click( function() { - jQuery(this).addInstance( false ); - }); - jQuery('.multipleTemplateList').sortable({ - axis: 'y', - handle: '.rearrangerImage' - }); - - - // If the form is submitted, validate everything! - jQuery('#sfForm').submit( function() {return validateAll();} ); -}); diff --git a/SemanticForms/libs/ext.dynatree.js b/SemanticForms/libs/ext.dynatree.js deleted file mode 100644 index 116b04d9..00000000 --- a/SemanticForms/libs/ext.dynatree.js +++ /dev/null @@ -1,52 +0,0 @@ -$(function () { - // Attach the dynatree widget to an existing <div id="tree"> element - // and pass the tree options as an argument to the dynatree() function: - var nodeSelection = $("div[id*=treeinput]"); - nodeSelection.each (function (index) { - var node = nodeSelection.eq(index); - var selectMode = 2; - var checkboxClass = {checkbox: "dynatree-checkbox"}; - if (node.find(":input:radio").length) { - selectMode = 1; - checkboxClass = {checkbox: "dynatree-radio"}; - } - - node.dynatree({ - checkbox: true, - minExpandLevel: 1, - classNames: checkboxClass, - selectMode: selectMode, - onClick: function (node, event) { - var targetType = node.getEventTargetType(event); - if ( targetType == "expander" ) { - node.toggleExpand(); - } else if ( targetType == "checkbox" || - targetType == "title" ) { - node.toggleSelect(); - } - - return false; - }, - //Un/check real checkboxes recursively after selection - onSelect: function (select, dtnode) { - var inputkey = "chb-" + dtnode.data.key; - $("[id='" + inputkey + "']").attr("checked", select); - }, - //Prevent reappearing of checkbox when node is collapse - onExpand: function (select, dtnode) { - $("#chb-" + dtnode.data.key).attr("checked", - dtnode.isSelected()).addClass("hidden"); - } - }); - //Update real checkboxes according to selections - $.map(node.dynatree("getTree").getSelectedNodes(), - function (dtnode) { - $("#chb-" + dtnode.data.key).attr("checked", true); - dtnode.activate(); - }); - var activeNode = node.dynatree("getTree").getActiveNode(); - if (activeNode !== null) { - activeNode.deactivate(); - } - }); -}); diff --git a/SemanticForms/libs/ext.sf.js b/SemanticForms/libs/ext.sf.js deleted file mode 100644 index 5a75217f..00000000 --- a/SemanticForms/libs/ext.sf.js +++ /dev/null @@ -1,28 +0,0 @@ -/* -* ext.sf.js -* -* @file -* -* -* @licence GNU GPL v2+ -* @author Jatin Mehta -* -*/ - -var sf = ( function ( $, undefined ) { - 'use strict'; - /** - * - * Declares methods and properties that are available through the sf namespace - * - * @class sf - * @alternateClassName semanticforms - * @singleton - */ - return { - - }; -} )( jQuery ); - -//Assinging namespace -window.sf = window.semanticforms = sf;
\ No newline at end of file diff --git a/SemanticForms/libs/ext.sf.select2.base.js b/SemanticForms/libs/ext.sf.select2.base.js deleted file mode 100644 index 0a9c5900..00000000 --- a/SemanticForms/libs/ext.sf.select2.base.js +++ /dev/null @@ -1,271 +0,0 @@ -/* -* ext.sf.select2.base.js -* -* Base class to handle autocomplete -* for various input types using Select2 JS library -* -* @file -* -* -* @licence GNU GPL v2+ -* @author Jatin Mehta -* -*/ - -( function ( $, mw, sf ) { - 'use strict'; - /** - * Inheritance class for the sf.select2 constructor - * - * - * @class - */ - sf.select2 = sf.select2 || {}; - - /** - * Class constructor - * - * - * @class - * @constructor - */ - sf.select2.base = function() { - - }; - - sf.select2.base.prototype = { - /* - * Applies select2 to the HTML element - * - * @param {HTMLElement} element - * - */ - apply: function( element ) { - this.id = element.attr( "id" ); - var opts = this.setOptions(); - - element.select2(opts); - element.on( "change", this.onChange ); - }, - /* - * Used to remove the select2 applied to the HTML element, - * the selected value will remain preserved. - * - * @param {HTMLElement} element - * - */ - destroy: function( element ) { - element.select2( "destroy" ); - }, - /* - * Returns HTML text to be used by select2 for - * showing remote data retrieved - * - * @param {object} value - * @param {object} container - * @param {object} query - * - * @return {string} markup - * - */ - formatResult: function(value, container, query) { - var term = query.term; - var text = value.text; - var image = value.image; - var description = value.description; - var markup = ""; - - var text_highlight = sf.select2.base.prototype.textHighlight; - if ( text !== undefined && image !== undefined && description !== undefined ) { - markup += "<table class='sf-select2-result'> <tr>"; - markup += "<td class='sf-result-thumbnail'><img src='" + image + "'/></td>"; - markup += "<td class='sf-result-info'><div class='sf-result-title'>" + text_highlight(text, term) + "</div>"; - markup += "<div class='sf-result-description'>" + description + "</div>"; - markup += "</td></tr></table>"; - } else if ( text !== undefined && image !== undefined ) { - markup += "<img class='sf-icon' src='"+ image +"'/>" + text_highlight(text, term); - } else if ( text !== undefined && description !== undefined ) { - markup += "<table class='sf-select2-result'> <tr>"; - markup += "<td class='sf-result-info'><div class='sf-result-title'>" + text_highlight(text, term) + "</div>"; - markup += "<div class='sf-result-description'>" + description + "</div>"; - markup += "</td></tr></table>"; - } else { - markup += text_highlight(text, term); - } - - return markup; - }, - /* - * Returns string/HTML text to be used by select2 to - * show selection - * - * @param {object} value (The selected result object) - * - * @return {string} - * - */ - formatSelection: function(value) { - return value.text; - }, - /* - * If a field is dependent on some other field in the form - * then it returns its name. - * - * @return {string} - * - */ - dependentOn: function() { - var input_id = "#" + this.id; - var name_attr = this.nameAttr( $(input_id) ); - var name = $(input_id).attr( name_attr ); - - var sfgDependentFields = mw.config.get( 'sfgDependentFields' ); - for ( var i = 0; i < sfgDependentFields.length; i++ ) { - var dependentFieldPair = sfgDependentFields[i]; - if ( dependentFieldPair[1] == name ) { - return dependentFieldPair[0]; - } - } - return null; - }, - /* - * Returns the array of names of fields in the form which are dependent - * on the field passed as a param to this function, - * - * @param {HTMLElement} element - * - * @return {associative array} dependent_on_me - * - */ - dependentOnMe: function( element ) { - var name_attr = this.nameAttr(element); - var name = element.attr( name_attr ); - var dependent_on_me = []; - - var sfgDependentFields = mw.config.get( 'sfgDependentFields' ); - for ( var i = 0; i < sfgDependentFields.length; i++ ) { - var dependentFieldPair = sfgDependentFields[i]; - if ( dependentFieldPair[0] == name ) { - dependent_on_me.push(dependentFieldPair[1]); - } - } - - return dependent_on_me; - }, - /* - * Returns the name attribute of the field depending on - * whether it is a part of multiple instance template or not - * - * @param {HTMLElement} element - * - * @return {string} - * - */ - nameAttr: function( element ) { - return this.partOfMultiple( element ) ? "origname" : "name"; - }, - /* - * Checks whether the field is part of multiple instance template or not - * - * @param {HTMLElement} element - * - * @return {boolean} - * - */ - partOfMultiple: function( element ) { - return element.attr( "origname" ) !== undefined ? true : false; - }, - /* - * Gives dependent field options which include - * property, base property and base value - * - * @param {string} dep_on - * - * @return {object} dep_field_opts - * - */ - getDependentFieldOpts: function( dep_on ) { - var input_id = "#" + this.id; - var dep_field_opts = {}; - var base_element; - if ( this.partOfMultiple($(input_id)) ) { - base_element = $(input_id).closest( ".multipleTemplateInstance" ) - .find( '[origname ="' + dep_on + '" ]' ); - } else { - base_element = $('[name ="' + dep_on + '" ]'); - } - dep_field_opts.base_value = base_element.val(); - dep_field_opts.base_prop = base_element.attr( "autocompletesettings" ); - dep_field_opts.prop = $(input_id).attr( "autocompletesettings" ).split( "," )[0]; - - return dep_field_opts; - }, - /* - * Gives autocomplete options for a field - * - * - * @return {object} autocomplete_opts - * - */ - getAutocompleteOpts: function() { - var input_id = "#" + this.id; - var autocomplete_opts = {}; - autocomplete_opts.autocompletedatatype = $(input_id).attr( "autocompletedatatype" ); - autocomplete_opts.autocompletesettings = $(input_id).attr( "autocompletesettings" ); - - return autocomplete_opts; - }, - /* - * Refreshes the field if there is a change - * in the autocomplete vlaues - * - * @param {HTMLElement} element - * - */ - refresh: function( element ) { - this.destroy($(element)); - this.apply($(element)); - }, - /* - * Removes diacritics from the string and replaces - * them with english characters. - * This code is basically copied from: - * http://jsfiddle.net/potherca/Gtmr2/ - * - * @param {string} text - * - * @return {string} - * - */ - removeDiacritics: function( text ) { - var diacriticsMap = { 'Á': 'A', 'Ă': 'A', 'Ắ': 'A', 'Ặ': 'A', 'Ằ': 'A', 'Ẳ': 'A', 'Ẵ': 'A', 'Ǎ': 'A', 'Â': 'A', 'Ấ': 'A', 'Ậ': 'A', 'Ầ': 'A', 'Ẩ': 'A', 'Ẫ': 'A', 'Ä': 'A', 'Ǟ': 'A', 'Ȧ': 'A', 'Ǡ': 'A', 'Ạ': 'A', 'Ȁ': 'A', 'À': 'A', 'Ả': 'A', 'Ȃ': 'A', 'Ā': 'A', 'Ą': 'A', 'Å': 'A', 'Ǻ': 'A', 'Ḁ': 'A', 'Ⱥ': 'A', 'Ã': 'A', 'Ꜳ': 'AA', 'Æ': 'AE', 'Ǽ': 'AE', 'Ǣ': 'AE', 'Ꜵ': 'AO', 'Ꜷ': 'AU', 'Ꜹ': 'AV', 'Ꜻ': 'AV', 'Ꜽ': 'AY', 'Ḃ': 'B', 'Ḅ': 'B', 'Ɓ': 'B', 'Ḇ': 'B', 'Ƀ': 'B', 'Ƃ': 'B', 'Ć': 'C', 'Č': 'C', 'Ç': 'C', 'Ḉ': 'C', 'Ĉ': 'C', 'Ċ': 'C', 'Ƈ': 'C', 'Ȼ': 'C', 'Ď': 'D', 'Ḑ': 'D', 'Ḓ': 'D', 'Ḋ': 'D', 'Ḍ': 'D', 'Ɗ': 'D', 'Ḏ': 'D', 'Dz': 'D', 'Dž': 'D', 'Đ': 'D', 'Ƌ': 'D', 'DZ': 'DZ', 'DŽ': 'DZ', 'É': 'E', 'Ĕ': 'E', 'Ě': 'E', 'Ȩ': 'E', 'Ḝ': 'E', 'Ê': 'E', 'Ế': 'E', 'Ệ': 'E', 'Ề': 'E', 'Ể': 'E', 'Ễ': 'E', 'Ḙ': 'E', 'Ë': 'E', 'Ė': 'E', 'Ẹ': 'E', 'Ȅ': 'E', 'È': 'E', 'Ẻ': 'E', 'Ȇ': 'E', 'Ē': 'E', 'Ḗ': 'E', 'Ḕ': 'E', 'Ę': 'E', 'Ɇ': 'E', 'Ẽ': 'E', 'Ḛ': 'E', 'Ꝫ': 'ET', 'Ḟ': 'F', 'Ƒ': 'F', 'Ǵ': 'G', 'Ğ': 'G', 'Ǧ': 'G', 'Ģ': 'G', 'Ĝ': 'G', 'Ġ': 'G', 'Ɠ': 'G', 'Ḡ': 'G', 'Ǥ': 'G', 'Ḫ': 'H', 'Ȟ': 'H', 'Ḩ': 'H', 'Ĥ': 'H', 'Ⱨ': 'H', 'Ḧ': 'H', 'Ḣ': 'H', 'Ḥ': 'H', 'Ħ': 'H', 'Í': 'I', 'Ĭ': 'I', 'Ǐ': 'I', 'Î': 'I', 'Ï': 'I', 'Ḯ': 'I', 'İ': 'I', 'Ị': 'I', 'Ȉ': 'I', 'Ì': 'I', 'Ỉ': 'I', 'Ȋ': 'I', 'Ī': 'I', 'Į': 'I', 'Ɨ': 'I', 'Ĩ': 'I', 'Ḭ': 'I', 'Ꝺ': 'D', 'Ꝼ': 'F', 'Ᵹ': 'G', 'Ꞃ': 'R', 'Ꞅ': 'S', 'Ꞇ': 'T', 'Ꝭ': 'IS', 'Ĵ': 'J', 'Ɉ': 'J', 'Ḱ': 'K', 'Ǩ': 'K', 'Ķ': 'K', 'Ⱪ': 'K', 'Ꝃ': 'K', 'Ḳ': 'K', 'Ƙ': 'K', 'Ḵ': 'K', 'Ꝁ': 'K', 'Ꝅ': 'K', 'Ĺ': 'L', 'Ƚ': 'L', 'Ľ': 'L', 'Ļ': 'L', 'Ḽ': 'L', 'Ḷ': 'L', 'Ḹ': 'L', 'Ⱡ': 'L', 'Ꝉ': 'L', 'Ḻ': 'L', 'Ŀ': 'L', 'Ɫ': 'L', 'Lj': 'L', 'Ł': 'L', 'LJ': 'LJ', 'Ḿ': 'M', 'Ṁ': 'M', 'Ṃ': 'M', 'Ɱ': 'M', 'Ń': 'N', 'Ň': 'N', 'Ņ': 'N', 'Ṋ': 'N', 'Ṅ': 'N', 'Ṇ': 'N', 'Ǹ': 'N', 'Ɲ': 'N', 'Ṉ': 'N', 'Ƞ': 'N', 'Nj': 'N', 'Ñ': 'N', 'NJ': 'NJ', 'Ó': 'O', 'Ŏ': 'O', 'Ǒ': 'O', 'Ô': 'O', 'Ố': 'O', 'Ộ': 'O', 'Ồ': 'O', 'Ổ': 'O', 'Ỗ': 'O', 'Ö': 'O', 'Ȫ': 'O', 'Ȯ': 'O', 'Ȱ': 'O', 'Ọ': 'O', 'Ő': 'O', 'Ȍ': 'O', 'Ò': 'O', 'Ỏ': 'O', 'Ơ': 'O', 'Ớ': 'O', 'Ợ': 'O', 'Ờ': 'O', 'Ở': 'O', 'Ỡ': 'O', 'Ȏ': 'O', 'Ꝋ': 'O', 'Ꝍ': 'O', 'Ō': 'O', 'Ṓ': 'O', 'Ṑ': 'O', 'Ɵ': 'O', 'Ǫ': 'O', 'Ǭ': 'O', 'Ø': 'O', 'Ǿ': 'O', 'Õ': 'O', 'Ṍ': 'O', 'Ṏ': 'O', 'Ȭ': 'O', 'Ƣ': 'OI', 'Ꝏ': 'OO', 'Ɛ': 'E', 'Ɔ': 'O', 'Ȣ': 'OU', 'Ṕ': 'P', 'Ṗ': 'P', 'Ꝓ': 'P', 'Ƥ': 'P', 'Ꝕ': 'P', 'Ᵽ': 'P', 'Ꝑ': 'P', 'Ꝙ': 'Q', 'Ꝗ': 'Q', 'Ŕ': 'R', 'Ř': 'R', 'Ŗ': 'R', 'Ṙ': 'R', 'Ṛ': 'R', 'Ṝ': 'R', 'Ȑ': 'R', 'Ȓ': 'R', 'Ṟ': 'R', 'Ɍ': 'R', 'Ɽ': 'R', 'Ꜿ': 'C', 'Ǝ': 'E', 'Ś': 'S', 'Ṥ': 'S', 'Š': 'S', 'Ṧ': 'S', 'Ş': 'S', 'Ŝ': 'S', 'Ș': 'S', 'Ṡ': 'S', 'Ṣ': 'S', 'Ṩ': 'S', 'ẞ': 'SS', 'Ť': 'T', 'Ţ': 'T', 'Ṱ': 'T', 'Ț': 'T', 'Ⱦ': 'T', 'Ṫ': 'T', 'Ṭ': 'T', 'Ƭ': 'T', 'Ṯ': 'T', 'Ʈ': 'T', 'Ŧ': 'T', 'Ɐ': 'A', 'Ꞁ': 'L', 'Ɯ': 'M', 'Ʌ': 'V', 'Ꜩ': 'TZ', 'Ú': 'U', 'Ŭ': 'U', 'Ǔ': 'U', 'Û': 'U', 'Ṷ': 'U', 'Ü': 'U', 'Ǘ': 'U', 'Ǚ': 'U', 'Ǜ': 'U', 'Ǖ': 'U', 'Ṳ': 'U', 'Ụ': 'U', 'Ű': 'U', 'Ȕ': 'U', 'Ù': 'U', 'Ủ': 'U', 'Ư': 'U', 'Ứ': 'U', 'Ự': 'U', 'Ừ': 'U', 'Ử': 'U', 'Ữ': 'U', 'Ȗ': 'U', 'Ū': 'U', 'Ṻ': 'U', 'Ų': 'U', 'Ů': 'U', 'Ũ': 'U', 'Ṹ': 'U', 'Ṵ': 'U', 'Ꝟ': 'V', 'Ṿ': 'V', 'Ʋ': 'V', 'Ṽ': 'V', 'Ꝡ': 'VY', 'Ẃ': 'W', 'Ŵ': 'W', 'Ẅ': 'W', 'Ẇ': 'W', 'Ẉ': 'W', 'Ẁ': 'W', 'Ⱳ': 'W', 'Ẍ': 'X', 'Ẋ': 'X', 'Ý': 'Y', 'Ŷ': 'Y', 'Ÿ': 'Y', 'Ẏ': 'Y', 'Ỵ': 'Y', 'Ỳ': 'Y', 'Ƴ': 'Y', 'Ỷ': 'Y', 'Ỿ': 'Y', 'Ȳ': 'Y', 'Ɏ': 'Y', 'Ỹ': 'Y', 'Ź': 'Z', 'Ž': 'Z', 'Ẑ': 'Z', 'Ⱬ': 'Z', 'Ż': 'Z', 'Ẓ': 'Z', 'Ȥ': 'Z', 'Ẕ': 'Z', 'Ƶ': 'Z', 'IJ': 'IJ', 'Œ': 'OE', 'ᴀ': 'A', 'ᴁ': 'AE', 'ʙ': 'B', 'ᴃ': 'B', 'ᴄ': 'C', 'ᴅ': 'D', 'ᴇ': 'E', 'ꜰ': 'F', 'ɢ': 'G', 'ʛ': 'G', 'ʜ': 'H', 'ɪ': 'I', 'ʁ': 'R', 'ᴊ': 'J', 'ᴋ': 'K', 'ʟ': 'L', 'ᴌ': 'L', 'ᴍ': 'M', 'ɴ': 'N', 'ᴏ': 'O', 'ɶ': 'OE', 'ᴐ': 'O', 'ᴕ': 'OU', 'ᴘ': 'P', 'ʀ': 'R', 'ᴎ': 'N', 'ᴙ': 'R', 'ꜱ': 'S', 'ᴛ': 'T', 'ⱻ': 'E', 'ᴚ': 'R', 'ᴜ': 'U', 'ᴠ': 'V', 'ᴡ': 'W', 'ʏ': 'Y', 'ᴢ': 'Z', 'á': 'a', 'ă': 'a', 'ắ': 'a', 'ặ': 'a', 'ằ': 'a', 'ẳ': 'a', 'ẵ': 'a', 'ǎ': 'a', 'â': 'a', 'ấ': 'a', 'ậ': 'a', 'ầ': 'a', 'ẩ': 'a', 'ẫ': 'a', 'ä': 'a', 'ǟ': 'a', 'ȧ': 'a', 'ǡ': 'a', 'ạ': 'a', 'ȁ': 'a', 'à': 'a', 'ả': 'a', 'ȃ': 'a', 'ā': 'a', 'ą': 'a', 'ᶏ': 'a', 'ẚ': 'a', 'å': 'a', 'ǻ': 'a', 'ḁ': 'a', 'ⱥ': 'a', 'ã': 'a', 'ꜳ': 'aa', 'æ': 'ae', 'ǽ': 'ae', 'ǣ': 'ae', 'ꜵ': 'ao', 'ꜷ': 'au', 'ꜹ': 'av', 'ꜻ': 'av', 'ꜽ': 'ay', 'ḃ': 'b', 'ḅ': 'b', 'ɓ': 'b', 'ḇ': 'b', 'ᵬ': 'b', 'ᶀ': 'b', 'ƀ': 'b', 'ƃ': 'b', 'ɵ': 'o', 'ć': 'c', 'č': 'c', 'ç': 'c', 'ḉ': 'c', 'ĉ': 'c', 'ɕ': 'c', 'ċ': 'c', 'ƈ': 'c', 'ȼ': 'c', 'ď': 'd', 'ḑ': 'd', 'ḓ': 'd', 'ȡ': 'd', 'ḋ': 'd', 'ḍ': 'd', 'ɗ': 'd', 'ᶑ': 'd', 'ḏ': 'd', 'ᵭ': 'd', 'ᶁ': 'd', 'đ': 'd', 'ɖ': 'd', 'ƌ': 'd', 'ı': 'i', 'ȷ': 'j', 'ɟ': 'j', 'ʄ': 'j', 'dz': 'dz', 'dž': 'dz', 'é': 'e', 'ĕ': 'e', 'ě': 'e', 'ȩ': 'e', 'ḝ': 'e', 'ê': 'e', 'ế': 'e', 'ệ': 'e', 'ề': 'e', 'ể': 'e', 'ễ': 'e', 'ḙ': 'e', 'ë': 'e', 'ė': 'e', 'ẹ': 'e', 'ȅ': 'e', 'è': 'e', 'ẻ': 'e', 'ȇ': 'e', 'ē': 'e', 'ḗ': 'e', 'ḕ': 'e', 'ⱸ': 'e', 'ę': 'e', 'ᶒ': 'e', 'ɇ': 'e', 'ẽ': 'e', 'ḛ': 'e', 'ꝫ': 'et', 'ḟ': 'f', 'ƒ': 'f', 'ᵮ': 'f', 'ᶂ': 'f', 'ǵ': 'g', 'ğ': 'g', 'ǧ': 'g', 'ģ': 'g', 'ĝ': 'g', 'ġ': 'g', 'ɠ': 'g', 'ḡ': 'g', 'ᶃ': 'g', 'ǥ': 'g', 'ḫ': 'h', 'ȟ': 'h', 'ḩ': 'h', 'ĥ': 'h', 'ⱨ': 'h', 'ḧ': 'h', 'ḣ': 'h', 'ḥ': 'h', 'ɦ': 'h', 'ẖ': 'h', 'ħ': 'h', 'ƕ': 'hv', 'í': 'i', 'ĭ': 'i', 'ǐ': 'i', 'î': 'i', 'ï': 'i', 'ḯ': 'i', 'ị': 'i', 'ȉ': 'i', 'ì': 'i', 'ỉ': 'i', 'ȋ': 'i', 'ī': 'i', 'į': 'i', 'ᶖ': 'i', 'ɨ': 'i', 'ĩ': 'i', 'ḭ': 'i', 'ꝺ': 'd', 'ꝼ': 'f', 'ᵹ': 'g', 'ꞃ': 'r', 'ꞅ': 's', 'ꞇ': 't', 'ꝭ': 'is', 'ǰ': 'j', 'ĵ': 'j', 'ʝ': 'j', 'ɉ': 'j', 'ḱ': 'k', 'ǩ': 'k', 'ķ': 'k', 'ⱪ': 'k', 'ꝃ': 'k', 'ḳ': 'k', 'ƙ': 'k', 'ḵ': 'k', 'ᶄ': 'k', 'ꝁ': 'k', 'ꝅ': 'k', 'ĺ': 'l', 'ƚ': 'l', 'ɬ': 'l', 'ľ': 'l', 'ļ': 'l', 'ḽ': 'l', 'ȴ': 'l', 'ḷ': 'l', 'ḹ': 'l', 'ⱡ': 'l', 'ꝉ': 'l', 'ḻ': 'l', 'ŀ': 'l', 'ɫ': 'l', 'ᶅ': 'l', 'ɭ': 'l', 'ł': 'l', 'lj': 'lj', 'ſ': 's', 'ẜ': 's', 'ẛ': 's', 'ẝ': 's', 'ḿ': 'm', 'ṁ': 'm', 'ṃ': 'm', 'ɱ': 'm', 'ᵯ': 'm', 'ᶆ': 'm', 'ń': 'n', 'ň': 'n', 'ņ': 'n', 'ṋ': 'n', 'ȵ': 'n', 'ṅ': 'n', 'ṇ': 'n', 'ǹ': 'n', 'ɲ': 'n', 'ṉ': 'n', 'ƞ': 'n', 'ᵰ': 'n', 'ᶇ': 'n', 'ɳ': 'n', 'ñ': 'n', 'nj': 'nj', 'ó': 'o', 'ŏ': 'o', 'ǒ': 'o', 'ô': 'o', 'ố': 'o', 'ộ': 'o', 'ồ': 'o', 'ổ': 'o', 'ỗ': 'o', 'ö': 'o', 'ȫ': 'o', 'ȯ': 'o', 'ȱ': 'o', 'ọ': 'o', 'ő': 'o', 'ȍ': 'o', 'ò': 'o', 'ỏ': 'o', 'ơ': 'o', 'ớ': 'o', 'ợ': 'o', 'ờ': 'o', 'ở': 'o', 'ỡ': 'o', 'ȏ': 'o', 'ꝋ': 'o', 'ꝍ': 'o', 'ⱺ': 'o', 'ō': 'o', 'ṓ': 'o', 'ṑ': 'o', 'ǫ': 'o', 'ǭ': 'o', 'ø': 'o', 'ǿ': 'o', 'õ': 'o', 'ṍ': 'o', 'ṏ': 'o', 'ȭ': 'o', 'ƣ': 'oi', 'ꝏ': 'oo', 'ɛ': 'e', 'ᶓ': 'e', 'ɔ': 'o', 'ᶗ': 'o', 'ȣ': 'ou', 'ṕ': 'p', 'ṗ': 'p', 'ꝓ': 'p', 'ƥ': 'p', 'ᵱ': 'p', 'ᶈ': 'p', 'ꝕ': 'p', 'ᵽ': 'p', 'ꝑ': 'p', 'ꝙ': 'q', 'ʠ': 'q', 'ɋ': 'q', 'ꝗ': 'q', 'ŕ': 'r', 'ř': 'r', 'ŗ': 'r', 'ṙ': 'r', 'ṛ': 'r', 'ṝ': 'r', 'ȑ': 'r', 'ɾ': 'r', 'ᵳ': 'r', 'ȓ': 'r', 'ṟ': 'r', 'ɼ': 'r', 'ᵲ': 'r', 'ᶉ': 'r', 'ɍ': 'r', 'ɽ': 'r', 'ↄ': 'c', 'ꜿ': 'c', 'ɘ': 'e', 'ɿ': 'r', 'ś': 's', 'ṥ': 's', 'š': 's', 'ṧ': 's', 'ş': 's', 'ŝ': 's', 'ș': 's', 'ṡ': 's', 'ṣ': 's', 'ṩ': 's', 'ʂ': 's', 'ᵴ': 's', 'ᶊ': 's', 'ȿ': 's', 'ß': 'ss', 'ɡ': 'g', 'ᴑ': 'o', 'ᴓ': 'o', 'ᴝ': 'u', 'ť': 't', 'ţ': 't', 'ṱ': 't', 'ț': 't', 'ȶ': 't', 'ẗ': 't', 'ⱦ': 't', 'ṫ': 't', 'ṭ': 't', 'ƭ': 't', 'ṯ': 't', 'ᵵ': 't', 'ƫ': 't', 'ʈ': 't', 'ŧ': 't', 'ᵺ': 'th', 'ɐ': 'a', 'ᴂ': 'ae', 'ǝ': 'e', 'ᵷ': 'g', 'ɥ': 'h', 'ʮ': 'h', 'ʯ': 'h', 'ᴉ': 'i', 'ʞ': 'k', 'ꞁ': 'l', 'ɯ': 'm', 'ɰ': 'm', 'ᴔ': 'oe', 'ɹ': 'r', 'ɻ': 'r', 'ɺ': 'r', 'ⱹ': 'r', 'ʇ': 't', 'ʌ': 'v', 'ʍ': 'w', 'ʎ': 'y', 'ꜩ': 'tz', 'ú': 'u', 'ŭ': 'u', 'ǔ': 'u', 'û': 'u', 'ṷ': 'u', 'ü': 'u', 'ǘ': 'u', 'ǚ': 'u', 'ǜ': 'u', 'ǖ': 'u', 'ṳ': 'u', 'ụ': 'u', 'ű': 'u', 'ȕ': 'u', 'ù': 'u', 'ủ': 'u', 'ư': 'u', 'ứ': 'u', 'ự': 'u', 'ừ': 'u', 'ử': 'u', 'ữ': 'u', 'ȗ': 'u', 'ū': 'u', 'ṻ': 'u', 'ų': 'u', 'ᶙ': 'u', 'ů': 'u', 'ũ': 'u', 'ṹ': 'u', 'ṵ': 'u', 'ᵫ': 'ue', 'ꝸ': 'um', 'ⱴ': 'v', 'ꝟ': 'v', 'ṿ': 'v', 'ʋ': 'v', 'ᶌ': 'v', 'ⱱ': 'v', 'ṽ': 'v', 'ꝡ': 'vy', 'ẃ': 'w', 'ŵ': 'w', 'ẅ': 'w', 'ẇ': 'w', 'ẉ': 'w', 'ẁ': 'w', 'ⱳ': 'w', 'ẘ': 'w', 'ẍ': 'x', 'ẋ': 'x', 'ᶍ': 'x', 'ý': 'y', 'ŷ': 'y', 'ÿ': 'y', 'ẏ': 'y', 'ỵ': 'y', 'ỳ': 'y', 'ƴ': 'y', 'ỷ': 'y', 'ỿ': 'y', 'ȳ': 'y', 'ẙ': 'y', 'ɏ': 'y', 'ỹ': 'y', 'ź': 'z', 'ž': 'z', 'ẑ': 'z', 'ʑ': 'z', 'ⱬ': 'z', 'ż': 'z', 'ẓ': 'z', 'ȥ': 'z', 'ẕ': 'z', 'ᵶ': 'z', 'ᶎ': 'z', 'ʐ': 'z', 'ƶ': 'z', 'ɀ': 'z', 'ff': 'ff', 'ffi': 'ffi', 'ffl': 'ffl', 'fi': 'fi', 'fl': 'fl', 'ij': 'ij', 'œ': 'oe', 'st': 'st', 'ₐ': 'a', 'ₑ': 'e', 'ᵢ': 'i', 'ⱼ': 'j', 'ₒ': 'o', 'ᵣ': 'r', 'ᵤ': 'u', 'ᵥ': 'v', 'ₓ': 'x' }; - - return text.replace(/[\u007F-\uFFFF]/g, function(key) { - return diacriticsMap[key] || key; - }); - }, - textHighlight: function( text, term ) { - var markup = ""; - var remove_diacritics = sf.select2.base.prototype.removeDiacritics; - var no_diac_text = remove_diacritics(text); - var start = no_diac_text.toUpperCase().indexOf(term.toUpperCase()); - if (start !== 0 && !mw.config.get( 'sfgAutocompleteOnAllChars' )) { - start = no_diac_text.toUpperCase().indexOf(" " + term.toUpperCase()); - if ( start != -1 ) { - start = start + 1; - } - } - if ( start != -1 ) { - markup += text.substr(0, start) + - '<span class="select2-match">' + - text.substr(start,term.length) + - '</span>' + - text.substr(start + term.length, text.length); - } else { - markup += text; - } - - return markup; - }, - }; -} )( jQuery, mediaWiki, semanticforms );
\ No newline at end of file diff --git a/SemanticForms/libs/ext.sf.select2.combobox.js b/SemanticForms/libs/ext.sf.select2.combobox.js deleted file mode 100644 index cccfab9d..00000000 --- a/SemanticForms/libs/ext.sf.select2.combobox.js +++ /dev/null @@ -1,275 +0,0 @@ -/* - * ext.sf.select2.comboboxjs - * - * Javascript utility class to handle autocomplete - * for combobox input type using Select2 JS library - * - * @file - * - * @licence GNU GPL v2+ - * @author Jatin Mehta - */ - -( function( $, mw, sf ) { - 'use strict'; - - /** - * Inheritance class for the sf.select2 constructor - * - * - * @class - */ - sf.select2 = sf.select2 || {}; - - /** - * Class constructor - * - * - * @class - * @constructor - */ - sf.select2.combobox = function() { - - }; - - var combobox_proto = new sf.select2.base(); - - /* - * Returns options to be set by select2 - * - * @return {object} opts - * - */ - combobox_proto.setOptions = function() { - var input_id = this.id; - var opts = {}; - input_id = "#" + input_id; - var input_tagname = $(input_id).prop( "tagName" ); - var autocomplete_opts = this.getAutocompleteOpts(); - - if ( autocomplete_opts.autocompletedatatype !== undefined ) { - opts.ajax = this.getAjaxOpts(); - opts.minimumInputLength = 1; - opts.formatInputTooShort = mw.msg( "sf-select2-input-too-short", opts.minimumInputLength ); - opts.formatSelection = this.formatSelection; - opts.escapeMarkup = function (m) { return m; }; - } else if ( input_tagname == "INPUT" ) { - opts.data = this.getData( autocomplete_opts.autocompletesettings ); - } - var sfgAutocompleteOnAllChars = mw.config.get( 'sfgAutocompleteOnAllChars' ); - if ( !sfgAutocompleteOnAllChars ) { - opts.matcher = function( term, text ) { - var no_diac_text = sf.select2.base.prototype.removeDiacritics( text ); - var position = no_diac_text.toUpperCase().indexOf(term.toUpperCase()); - var position_with_space = no_diac_text.toUpperCase().indexOf(" " + term.toUpperCase()); - if ( (position != -1 && position === 0 ) || position_with_space != -1 ) { - return true; - } else { - return false; - } - }; - } - opts.formatResult = this.formatResult; - opts.formatSearching = mw.msg( "sf-select2-searching" ); - opts.formatNoMatches = mw.msg( "sf-select2-no-matches" ); - opts.placeholder = $(input_id).attr( "placeholder" ); - if ( $(input_id).attr( "existingvaluesonly" ) !== "true" && input_tagname == "INPUT" ) { - opts.createSearchChoice = function( term, data ) { if ( $(data).filter(function() { return this.text.localeCompare( term )===0; }).length===0 ) {return { id:term, text:term };} }; - } - if ( $(input_id).val() !== "" && input_tagname == "INPUT" ) { - opts.initSelection = function ( element, callback ) { var data = {id: element.val(), text: element.val()}; callback(data); }; - } - opts.allowClear = true; - var size = $(input_id).attr("size"); - if ( size === undefined ) { - size = 35; //default value - } - opts.containerCss = { 'min-width': size * 6 }; - opts.containerCssClass = 'sf-select2-container'; - opts.dropdownCssClass = 'sf-select2-dropdown'; - - return opts; - }; - /* - * Returns data to be used by select2 for combobox autocompletion - * - * @param {string} autocompletesettings - * @return {associative array} values - * - */ - combobox_proto.getData = function( autocompletesettings ) { - var input_id = "#" + this.id; - var values = [{id: 0, text: ""}]; - var dep_on = this.dependentOn(); - var i, data; - if ( dep_on === null ) { - if ( autocompletesettings == 'external data' ) { - var name = $(input_id).attr(this.nameAttr($(input_id))); - var sfgEDSettings = mw.config.get( 'sfgEDSettings' ); - var edgValues = mw.config.get( 'edgValues' ); - data = {}; - if ( sfgEDSettings[name].title !== undefined && sfgEDSettings[name].title !== "" ) { - data.title = edgValues[sfgEDSettings[name].title]; - i = 0; - if ( data.title !== undefined && data.title !== null ) { - data.title.forEach(function() { - values.push({ - id: i + 1, text: data.title[i] - }); - i++; - }); - } - if ( sfgEDSettings[name].image !== undefined && sfgEDSettings[name].image !== "" ) { - data.image = edgValues[sfgEDSettings[name].image]; - i = 0; - if ( data.image !== undefined && data.image !== null ) { - data.image.forEach(function() { - values[i+1].image = data.image[i]; - i++; - }); - } - } - if ( sfgEDSettings[name].description !== undefined && sfgEDSettings[name].description !== "" ) { - data.description = edgValues[sfgEDSettings[name].description]; - i = 0; - if ( data.description !== undefined && data.description !== null ) { - data.description.forEach(function() { - values[i+1].description = data.description[i]; - i++; - }); - } - } - } - - } else { - var sfgAutocompleteValues = mw.config.get( 'sfgAutocompleteValues' ); - data = sfgAutocompleteValues[autocompletesettings]; - i = 0; - //Convert data into the format accepted by Select2 - if (data !== undefined && data !== null ) { - data.forEach(function() - { - values.push({ - id: i + 1, text: data[i] - }); - i++; - }); - } - } - } else { //Dependent field autocompletion - var dep_field_opts = this.getDependentFieldOpts( dep_on ); - var my_server = mw.config.get( 'wgScriptPath' ) + "/api.php"; - my_server += "?action=sfautocomplete&format=json&property=" + dep_field_opts.prop + "&baseprop=" + dep_field_opts.base_prop + "&basevalue=" + dep_field_opts.base_value; - $.ajax({ - url: my_server, - dataType: 'json', - async: false, - success: function(data) { - var id = 1; - //Convert data into the format accepted by Select2 - data.sfautocomplete.forEach( function(item) { - values.push({ - id: id++, text: item.title - }); - }); - return values; - } - }); - } - - return values; - }; - /* - * Returns ajax options to be used by select2 for - * remote autocompletion of combobox - * - * @return {object} ajaxOpts - * - */ - combobox_proto.getAjaxOpts = function() { - var autocomplete_opts = this.getAutocompleteOpts(); - var my_server = mw.util.wikiScript( 'api' ); - my_server += "?action=sfautocomplete&format=json&" + autocomplete_opts.autocompletedatatype + "=" + autocomplete_opts.autocompletesettings; - - var ajaxOpts = { - url: my_server, - dataType: 'json', - data: function (term) { - return { - substr: term, // search term - }; - }, - results: function (data, page, query) { // parse the results into the format expected by Select2. - var id = 0; - if (data.sfautocomplete !== undefined) { - data.sfautocomplete.forEach( function(item) { - item.id = id++; - item.text = item.title; - }); - return {results: data.sfautocomplete}; - } else { - return {results: []}; - } - } - }; - - return ajaxOpts; - }; - /* - * Used to set the value of the HTMLInputElement - * when there is a change in the select2 value - * - */ - combobox_proto.onChange = function() { - var self = this; - var data = $(this).select2( "data" ); - if (data !== null) { - $(this).val( data.text ); - } else { - $(this).val( '' ); - } - - // Set the corresponding values for any other field - // in the form which is dependent on this element - var cmbox = new sf.select2.combobox(); - var dep_on_me = $.unique(cmbox.dependentOnMe( $(this) )); - dep_on_me.forEach( function( dependent_field_name ) { - var dependent_field; - if ( cmbox.partOfMultiple( $(self) ) ) { - dependent_field = $(self).closest( ".multipleTemplateInstance" ) - .find( '[origname ="' + dependent_field_name + '" ]' ); - } else { - dependent_field = $('[name ="' + dependent_field_name + '" ]'); - } - cmbox.dependentFieldAutocompleteHandler( dependent_field, self ); - }); - }; - /* - * Handles dependent field autocompletion - * - * @param {HTMLElement} dependent_field - * @param {HTMLElement} dependent_on - * - */ - combobox_proto.dependentFieldAutocompleteHandler = function( dependent_field, dependent_on ) { - var class_name = $(dependent_field).attr( 'class' ); - var cmbox = new sf.select2.combobox(); - var tokens = new sf.select2.tokens(); - - if ( class_name.indexOf( 'sfComboBox' ) != -1 ) { - cmbox.refresh(dependent_field); - } else if ( class_name.indexOf( 'sfTokens' ) != -1 ) { - tokens.refresh(dependent_field); - } else if ( class_name.indexOf( 'createboxInput' ) != -1 ) { - var name_attr = cmbox.nameAttr($(dependent_on)); - var field_name = $(dependent_field).attr(name_attr), - base_field_name = $(dependent_on).attr(name_attr), - base_value = $(dependent_on).val(); - $(dependent_field).setDependentAutocompletion(field_name, base_field_name, base_value); - } - - }; - - sf.select2.combobox.prototype = combobox_proto; - -} )( jQuery, mediaWiki, semanticforms );
\ No newline at end of file diff --git a/SemanticForms/libs/ext.sf.select2.tokens.js b/SemanticForms/libs/ext.sf.select2.tokens.js deleted file mode 100644 index 3be02233..00000000 --- a/SemanticForms/libs/ext.sf.select2.tokens.js +++ /dev/null @@ -1,314 +0,0 @@ -/* - * ext.sf.select2.tokens.js - * - * Javascript utility class to handle autocomplete - * for tokens input type using Select2 JS library - * - * @file - * - * @licence GNU GPL v2+ - * @author Jatin Mehta - */ - -( function( $, mw, sf ) { - 'use strict'; - - /** - * Inheritance class for the sf.select2 constructor - * - * - * @class - */ - sf.select2 = sf.select2 || {}; - - /** - * Class constructor - * - * - * @class - * @constructor - */ - sf.select2.tokens = function() { - - }; - - var tokens_proto = new sf.select2.base(); - /* - * Applies select2 to the HTML element - * - * @param {HTMLElement} element - * - */ - tokens_proto.apply = function( element ) { - this.id = element.attr( "id" ); - var opts = this.setOptions(); - var cur_val = element.val(); - - element.select2(opts); - this.sortable(element); - element.on( "change", this.onChange ); - element.val(cur_val); - }; - /* - * Returns options to be set by select2 - * - * @return {object} opts - * - */ - tokens_proto.setOptions = function() { - var self = this; - var input_id = this.id; - var opts = {}; - input_id = "#" + input_id; - var input_tagname = $(input_id).prop( "tagName" ); - var autocomplete_opts = this.getAutocompleteOpts(); - - if ( autocomplete_opts.autocompletedatatype !== undefined ) { - opts.ajax = this.getAjaxOpts(); - opts.minimumInputLength = 1; - opts.formatInputTooShort = ""; - opts.formatSelection = this.formatSelection; - opts.escapeMarkup = function (m) { return m; }; - } else if ( input_tagname == "INPUT" ) { - opts.data = this.getData( autocomplete_opts.autocompletesettings ); - } - var sfgAutocompleteOnAllChars = mw.config.get( 'sfgAutocompleteOnAllChars' ); - if ( !sfgAutocompleteOnAllChars ) { - opts.matcher = function( term, text ) { - var no_diac_text = sf.select2.base.prototype.removeDiacritics( text ); - var position = no_diac_text.toUpperCase().indexOf(term.toUpperCase()); - var position_with_space = no_diac_text.toUpperCase().indexOf(" " + term.toUpperCase()); - if ( (position != -1 && position === 0 ) || position_with_space != -1 ) { - return true; - } else { - return false; - } - }; - } - opts.formatResult = this.formatResult; - opts.formatSearching = mw.msg( "sf-select2-searching" ); - opts.formatNoMatches = ""; - opts.placeholder = $(input_id).attr( "placeholder" ); - if ( $(input_id).attr( "existingvaluesonly" ) !== "true" && input_tagname == "INPUT" ) { - opts.createSearchChoice = function( term, data ) { if ( $(data).filter(function() { return this.text.localeCompare( term )===0; }).length===0 ) {return { id:term, text:term };} }; - } - if ( $(input_id).val() !== "" && input_tagname == "INPUT" ) { - opts.initSelection = function ( element, callback ) { - var data = []; - var delim = self.getDelimiter($(input_id)); - var i = 0; - $(element.val().trim().split(delim)).each(function () { - if ( this !== "" ) { - data.push({id: i, text: this}); - i += 1; - } - }); - element.val( "" ); - callback(data); - }; - } - var size = $(input_id).attr("size"); - if ( size === undefined ) { - size = 100; //default value - } - opts.containerCss = { 'min-width': size * 6 }; - opts.containerCssClass = 'sf-select2-container'; - opts.dropdownCssClass = 'sf-select2-dropdown'; - - opts.multiple = true; - opts.tokenSeparators = this.getDelimiter($(input_id)); - opts.openOnEnter = true; - var maxvalues = $(input_id).attr( "maxvalues" ); - if ( maxvalues !== undefined ) { - opts.maximumSelectionSize = maxvalues; - opts.formatSelectionTooBig = mw.msg( "sf-select2-selection-too-big", maxvalues ); - } - opts.adaptContainerCssClass = function( clazz ) { - if (clazz == "mandatoryField") { - return ""; - } else { - return clazz; - } - }; - - return opts; - }; - /* - * Returns data to be used by select2 for tokens autocompletion - * - * @param {string} autocompletesettings - * @return {associative array} values - * - */ - tokens_proto.getData = function( autocompletesettings ) { - var input_id = "#" + this.id; - var values = []; - var data; - var dep_on = this.dependentOn(); - if ( dep_on === null ) { - if ( autocompletesettings == 'external data' ) { - var name = $(input_id).attr(this.nameAttr($(input_id))); - var sfgEDSettings = mw.config.get( 'sfgEDSettings' ); - var edgValues = mw.config.get( 'edgValues' ); - data = {}; - if ( sfgEDSettings[name].title !== undefined && sfgEDSettings[name].title !== "" ) { - data.title = edgValues[sfgEDSettings[name].title]; - i = 0; - if ( data.title !== undefined && data.title !== null ) { - data.title.forEach(function() { - values.push({ - id: i + 1, text: data.title[i] - }); - i++; - }); - } - if ( sfgEDSettings[name].image !== undefined && sfgEDSettings[name].image !== "" ) { - data.image = edgValues[sfgEDSettings[name].image]; - i = 0; - if ( data.image !== undefined && data.image !== null ) { - data.image.forEach(function() { - values[i].image = data.image[i]; - i++; - }); - } - } - if ( sfgEDSettings[name].description !== undefined && sfgEDSettings[name].description !== "" ) { - data.description = edgValues[sfgEDSettings[name].description]; - i = 0; - if ( data.description !== undefined && data.description !== null ) { - data.description.forEach(function() { - values[i].description = data.description[i]; - i++; - }); - } - } - } - - } else { - var sfgAutocompleteValues = mw.config.get( 'sfgAutocompleteValues' ); - data = sfgAutocompleteValues[autocompletesettings]; - var i = 0; - //Convert data into the format accepted by Select2 - if ( data !== undefined && data !== null ) { - data.forEach(function() - { - values.push({ - id: i, text: data[i] - }); - i++; - }); - } - } - } else { //Dependent field autocompletion - var dep_field_opts = this.getDependentFieldOpts( dep_on ); - var my_server = mw.config.get( 'wgScriptPath' ) + "/api.php"; - my_server += "?action=sfautocomplete&format=json&property=" + dep_field_opts.prop + "&baseprop=" + dep_field_opts.base_prop + "&basevalue=" + dep_field_opts.base_value; - $.ajax({ - url: my_server, - dataType: 'json', - async: false, - success: function(data) { - var id = 0; - //Convert data into the format accepted by Select2 - data.sfautocomplete.forEach( function(item) { - values.push({ - id: id++, text: item.title - }); - }); - return values; - } - }); - } - - return values; - }; - /* - * Returns ajax options to be used by select2 for - * remote autocompletion of tokens - * - * @return {object} ajaxOpts - * - */ - tokens_proto.getAjaxOpts = function() { - var autocomplete_opts = this.getAutocompleteOpts(); - var data_source = autocomplete_opts.autocompletesettings.split(',')[0]; - var my_server = mw.util.wikiScript( 'api' ); - my_server += "?action=sfautocomplete&format=json&" + autocomplete_opts.autocompletedatatype + "=" + data_source; - - var ajaxOpts = { - url: my_server, - dataType: 'json', - data: function (term) { - return { - substr: term, // search term - }; - }, - results: function (data, page, query) { // parse the results into the format expected by Select2. - var id = 0; - if (data.sfautocomplete !== undefined) { - data.sfautocomplete.forEach( function(item) { - item.id = id++; - item.text = item.title; - }); - return {results: data.sfautocomplete}; - } else { - return {results: []}; - } - } - }; - - return ajaxOpts; - }; - /* - * Used to set the value of the HTMLInputElement - * when there is a change in the select2 value - * - */ - tokens_proto.onChange = function() { - var self = this; - var data = $(this).select2( "data" ); - var tokens = new sf.select2.tokens(); - var delim = tokens.getDelimiter( $(this) ); - - if (data !== null) { - var tokens_value = ""; - data.forEach( function( token ) { - tokens_value += token.text.trim() + delim + " "; - }); - $(this).val( tokens_value ); - } else { - $(this).val( '' ); - } - }; - /* - * Returns delimiter for the token field - * - * @return {string} delimiter - * - */ - tokens_proto.getDelimiter = function ( element ) { - var field_values = element.attr('autocompletesettings').split( ',' ); - var delimiter = ","; - if (field_values[1] == 'list' && field_values[2] !== undefined ) { - delimiter = field_values[2]; - } - - return delimiter; - }; - /* - * Makes the choices rearrangable in tokens - * - * @param {HTMLElement} element - * - */ - tokens_proto.sortable = function( element ) { - element.select2("container").find("ul.select2-choices").sortable({ - containment: 'parent', - start: function() { $(".sfTokens").select2("onSortStart"); }, - update: function() { $(".sfTokens").select2("onSortEnd"); } - }); - }; - - sf.select2.tokens.prototype = tokens_proto; - -} )( jQuery, mediaWiki, semanticforms );
\ No newline at end of file diff --git a/SemanticForms/libs/jquery.browser.js b/SemanticForms/libs/jquery.browser.js deleted file mode 100644 index 53df7491..00000000 --- a/SemanticForms/libs/jquery.browser.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copy of some code from jquery.migrate.js to provide the jquery.browser functionality - * which was removed from recent jQuery versions - * - * TODO: Actually remove usage of jquery.browser from SF - * - * @author Stephan Gambke - */ - -; (function (jQuery) { - var uaMatch = function (ua) { - ua = ua.toLowerCase(); - - var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || - /(webkit)[ \/]([\w.]+)/.exec(ua) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || - /(msie) ([\w.]+)/.exec(ua) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || - []; - - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; - }; - -// Don't clobber any existing jQuery.browser in case it's different - if (!jQuery.browser) { - var matched = uaMatch(navigator.userAgent); - var browser = {}; - - if (matched.browser) { - browser[ matched.browser ] = true; - browser.version = matched.version; - } - - // Chrome is Webkit, but Webkit is also Safari. - if (browser.chrome) { - browser.webkit = true; - } else if (browser.webkit) { - browser.safari = true; - } - - jQuery.browser = browser; - } -})( jQuery ); diff --git a/SemanticForms/libs/jquery.dynatree.js b/SemanticForms/libs/jquery.dynatree.js deleted file mode 100644 index 308ad009..00000000 --- a/SemanticForms/libs/jquery.dynatree.js +++ /dev/null @@ -1,3420 +0,0 @@ -/************************************************************************* - jquery.dynatree.js - Dynamic tree view control, with support for lazy loading of branches. - - Copyright (c) 2006-2013, Martin Wendt (http://wwWendt.de) - Dual licensed under the MIT or GPL Version 2 licenses. - http://code.google.com/p/dynatree/wiki/LicenseInfo - - A current version and some documentation is available at - http://dynatree.googlecode.com/ - - $Version: 1.2.4$ - $Revision: 644, 2013-02-12 21:39:36$ - - @depends: jquery.js - @depends: jquery.ui.core.js - @depends: jquery.cookie.js -*************************************************************************/ - -/* jsHint options*/ -// Note: We currently allow eval() to parse the 'data' attribtes, when initializing from HTML. -// TODO: pass jsHint with the options given in grunt.js only. -// The following should not be required: -/*global alert */ -/*jshint nomen:false, smarttabs:true, eqeqeq:false, evil:true, regexp:false */ - -/************************************************************************* - * Debug functions - */ - -var _canLog = true; - -function _log(mode, msg) { - /** - * Usage: logMsg("%o was toggled", this); - */ - if( !_canLog ){ - return; - } - // Remove first argument - var args = Array.prototype.slice.apply(arguments, [1]); - // Prepend timestamp - var dt = new Date(); - var tag = dt.getHours()+":"+dt.getMinutes()+":"+dt.getSeconds()+"."+dt.getMilliseconds(); - args[0] = tag + " - " + args[0]; - - try { - switch( mode ) { - case "info": - window.console.info.apply(window.console, args); - break; - case "warn": - window.console.warn.apply(window.console, args); - break; - default: - window.console.log.apply(window.console, args); - break; - } - } catch(e) { - if( !window.console ){ - _canLog = false; // Permanently disable, when logging is not supported by the browser - }else if(e.number === -2146827850){ - // fix for IE8, where window.console.log() exists, but does not support .apply() - window.console.log(args.join(", ")); - } - } -} - -/* Check browser version, since $.browser was removed in jQuery 1.9 */ -function _checkBrowser(){ - var matched, browser; - function uaMatch( ua ) { - ua = ua.toLowerCase(); - var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) || - /(webkit)[ \/]([\w.]+)/.exec( ua ) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) || - /(msie) ([\w.]+)/.exec( ua ) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || - []; - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; - } - matched = uaMatch( navigator.userAgent ); - browser = {}; - if ( matched.browser ) { - browser[ matched.browser ] = true; - browser.version = matched.version; - } - if ( browser.chrome ) { - browser.webkit = true; - } else if ( browser.webkit ) { - browser.safari = true; - } - return browser; -} -var BROWSER = jQuery.browser || _checkBrowser(); - -function logMsg(msg) { - Array.prototype.unshift.apply(arguments, ["debug"]); - _log.apply(this, arguments); -} - - -// Forward declaration -var getDynaTreePersistData = null; - - - -/************************************************************************* - * Constants - */ -var DTNodeStatus_Error = -1; -var DTNodeStatus_Loading = 1; -var DTNodeStatus_Ok = 0; - - -// Start of local namespace -(function($) { - -/************************************************************************* - * Common tool functions. - */ - -var Class = { - create: function() { - return function() { - this.initialize.apply(this, arguments); - }; - } -}; - -// Tool function to get dtnode from the event target: -function getDtNodeFromElement(el) { - alert("getDtNodeFromElement is deprecated"); - return $.ui.dynatree.getNode(el); -/* - var iMax = 5; - while( el && iMax-- ) { - if(el.dtnode) { return el.dtnode; } - el = el.parentNode; - } - return null; -*/ -} - -function noop() { -} - -/** Compare two dotted version strings (like '10.2.3'). - * @returns {Integer} 0: v1 == v2, -1: v1 < v2, 1: v1 > v2 - */ -function versionCompare(v1, v2) { - var v1parts = ("" + v1).split("."), - v2parts = ("" + v2).split("."), - minLength = Math.min(v1parts.length, v2parts.length), - p1, p2, i; - // Compare tuple pair-by-pair. - for(i = 0; i < minLength; i++) { - // Convert to integer if possible, because "8" > "10". - p1 = parseInt(v1parts[i], 10); - p2 = parseInt(v2parts[i], 10); - if (isNaN(p1)){ p1 = v1parts[i]; } - if (isNaN(p2)){ p2 = v2parts[i]; } - if (p1 == p2) { - continue; - }else if (p1 > p2) { - return 1; - }else if (p1 < p2) { - return -1; - } - // one operand is NaN - return NaN; - } - // The longer tuple is always considered 'greater' - if (v1parts.length === v2parts.length) { - return 0; - } - return (v1parts.length < v2parts.length) ? -1 : 1; -} - - -/************************************************************************* - * Class DynaTreeNode - */ -var DynaTreeNode = Class.create(); - -DynaTreeNode.prototype = { - initialize: function(parent, tree, data) { - /** - * @constructor - */ - this.parent = parent; - this.tree = tree; - if ( typeof data === "string" ){ - data = { title: data }; - } - if( !data.key ){ - data.key = "_" + tree._nodeCount++; - }else{ - data.key = "" + data.key; // issue 371 - } - this.data = $.extend({}, $.ui.dynatree.nodedatadefaults, data); - this.li = null; // not yet created - this.span = null; // not yet created - this.ul = null; // not yet created - this.childList = null; // no subnodes yet - this._isLoading = false; // Lazy content is being loaded - this.hasSubSel = false; - this.bExpanded = false; - this.bSelected = false; - - }, - - toString: function() { - return "DynaTreeNode<" + this.data.key + ">: '" + this.data.title + "'"; - }, - - toDict: function(recursive, callback) { - var dict = $.extend({}, this.data); - dict.activate = ( this.tree.activeNode === this ); - dict.focus = ( this.tree.focusNode === this ); - dict.expand = this.bExpanded; - dict.select = this.bSelected; - if( callback ){ - callback(dict); - } - if( recursive && this.childList ) { - dict.children = []; - for(var i=0, l=this.childList.length; i<l; i++ ){ - dict.children.push(this.childList[i].toDict(true, callback)); - } - } else { - delete dict.children; - } - return dict; - }, - - fromDict: function(dict) { - /** - * Update node data. If dict contains 'children', then also replace - * the hole sub tree. - */ - var children = dict.children; - if(children === undefined){ - this.data = $.extend(this.data, dict); - this.render(); - return; - } - dict = $.extend({}, dict); - dict.children = undefined; - this.data = $.extend(this.data, dict); - this.removeChildren(); - this.addChild(children); - }, - - _getInnerHtml: function() { - var tree = this.tree, - opts = tree.options, - cache = tree.cache, - level = this.getLevel(), - data = this.data, - res = "", - imageSrc; - // connector (expanded, expandable or simple) - if( level < opts.minExpandLevel ) { - if(level > 1){ - res += cache.tagConnector; - } - // .. else (i.e. for root level) skip expander/connector altogether - } else if( this.hasChildren() !== false ) { - res += cache.tagExpander; - } else { - res += cache.tagConnector; - } - // Checkbox mode - if( opts.checkbox && data.hideCheckbox !== true && !data.isStatusNode ) { - res += cache.tagCheckbox; - } - // folder or doctype icon - if ( data.icon ) { - if (data.icon.charAt(0) === "/"){ - imageSrc = data.icon; - }else{ - imageSrc = opts.imagePath + data.icon; - } - res += "<img src='" + imageSrc + "' alt='' />"; - } else if ( data.icon === false ) { - // icon == false means 'no icon' -// noop(); // keep JSLint happy - } else if ( data.iconClass ) { - res += "<span class='" + " " + data.iconClass + "'></span>"; - } else { - // icon == null means 'default icon' - res += cache.tagNodeIcon; - } - // node title - var nodeTitle = ""; - if ( opts.onCustomRender ){ - nodeTitle = opts.onCustomRender.call(tree, this) || ""; - } - if(!nodeTitle){ - var tooltip = data.tooltip ? ' title="' + data.tooltip.replace(/\"/g, '"') + '"' : '', - href = data.href || "#"; - if( opts.noLink || data.noLink ) { - nodeTitle = '<span style="display:inline-block;" class="' + opts.classNames.title + '"' + tooltip + '>' + data.title + '</span>'; -// this.tree.logDebug("nodeTitle: " + nodeTitle); - } else { - nodeTitle = '<a href="' + href + '" class="' + opts.classNames.title + '"' + tooltip + '>' + data.title + '</a>'; - } - } - res += nodeTitle; - return res; - }, - - - _fixOrder: function() { - /** - * Make sure, that <li> order matches childList order. - */ - var cl = this.childList; - if( !cl || !this.ul ){ - return; - } - var childLI = this.ul.firstChild; - for(var i=0, l=cl.length-1; i<l; i++) { - var childNode1 = cl[i]; - var childNode2 = childLI.dtnode; - if( childNode1 !== childNode2 ) { - this.tree.logDebug("_fixOrder: mismatch at index " + i + ": " + childNode1 + " != " + childNode2); - this.ul.insertBefore(childNode1.li, childNode2.li); - } else { - childLI = childLI.nextSibling; - } - } - }, - - - render: function(useEffects, includeInvisible) { - /** - * Create <li><span>..</span> .. </li> tags for this node. - * - * <li id='KEY' dtnode=NODE> // This div contains the node's span and list of child div's. - * <span class='title'>S S S A</span> // Span contains graphic spans and title <a> tag - * <ul> // only present, when node has children - * <li id='KEY' dtnode=NODE>child1</li> - * <li id='KEY' dtnode=NODE>child2</li> - * </ul> - * </li> - */ -// this.tree.logDebug("%s.render(%s)", this, useEffects); - // --- - var tree = this.tree, - parent = this.parent, - data = this.data, - opts = tree.options, - cn = opts.classNames, - isLastSib = this.isLastSibling(), - firstTime = false; - - if( !parent && !this.ul ) { - // Root node has only a <ul> - this.li = this.span = null; - this.ul = document.createElement("ul"); - if( opts.minExpandLevel > 1 ){ - this.ul.className = cn.container + " " + cn.noConnector; - }else{ - this.ul.className = cn.container; - } - } else if( parent ) { - // Create <li><span /> </li> - if( ! this.li ) { - firstTime = true; - this.li = document.createElement("li"); - this.li.dtnode = this; - if( data.key && opts.generateIds ){ - this.li.id = opts.idPrefix + data.key; - } - this.span = document.createElement("span"); - this.span.className = cn.title; - this.li.appendChild(this.span); - - if( !parent.ul ) { - // This is the parent's first child: create UL tag - // (Hidden, because it will be - parent.ul = document.createElement("ul"); - parent.ul.style.display = "none"; - parent.li.appendChild(parent.ul); -// if( opts.minExpandLevel > this.getLevel() ){ -// parent.ul.className = cn.noConnector; -// } - } - // set node connector images, links and text -// this.span.innerHTML = this._getInnerHtml(); - - parent.ul.appendChild(this.li); - } - // set node connector images, links and text - this.span.innerHTML = this._getInnerHtml(); - // Set classes for current status - var cnList = []; - cnList.push(cn.node); - if( data.isFolder ){ - cnList.push(cn.folder); - } - if( this.bExpanded ){ - cnList.push(cn.expanded); - } - if( this.hasChildren() !== false ){ - cnList.push(cn.hasChildren); - } - if( data.isLazy && this.childList === null ){ - cnList.push(cn.lazy); - } - if( isLastSib ){ - cnList.push(cn.lastsib); - } - if( this.bSelected ){ - cnList.push(cn.selected); - } - if( this.hasSubSel ){ - cnList.push(cn.partsel); - } - if( tree.activeNode === this ){ - cnList.push(cn.active); - } - if( data.addClass ){ - cnList.push(data.addClass); - } - // IE6 doesn't correctly evaluate multiple class names, - // so we create combined class names that can be used in the CSS - cnList.push(cn.combinedExpanderPrefix + (this.bExpanded ? "e" : "c") + (data.isLazy && this.childList === null ? "d" : "") + (isLastSib ? "l" : "")); - cnList.push(cn.combinedIconPrefix + (this.bExpanded ? "e" : "c") + (data.isFolder ? "f" : "")); - this.span.className = cnList.join(" "); - - // TODO: we should not set this in the <span> tag also, if we set it here: - this.li.className = isLastSib ? cn.lastsib : ""; - - // Allow tweaking, binding, after node was created for the first time - if(firstTime && opts.onCreate){ - opts.onCreate.call(tree, this, this.span); - } - // Hide children, if node is collapsed -// this.ul.style.display = ( this.bExpanded || !parent ) ? "" : "none"; - // Allow tweaking after node state was rendered - if(opts.onRender){ - opts.onRender.call(tree, this, this.span); - } - } - // Visit child nodes - if( (this.bExpanded || includeInvisible === true) && this.childList ) { - for(var i=0, l=this.childList.length; i<l; i++) { - this.childList[i].render(false, includeInvisible); - } - // Make sure the tag order matches the child array - this._fixOrder(); - } - // Hide children, if node is collapsed - if( this.ul ) { - var isHidden = (this.ul.style.display === "none"); - var isExpanded = !!this.bExpanded; -// logMsg("isHidden:%s", isHidden); - if( useEffects && opts.fx && (isHidden === isExpanded) ) { - var duration = opts.fx.duration || 200; - $(this.ul).animate(opts.fx, duration); - } else { - this.ul.style.display = ( this.bExpanded || !parent ) ? "" : "none"; - } - } - }, - /** Return '/id1/id2/id3'. */ - getKeyPath: function(excludeSelf) { - var path = []; - this.visitParents(function(node){ - if(node.parent){ - path.unshift(node.data.key); - } - }, !excludeSelf); - return "/" + path.join(this.tree.options.keyPathSeparator); - }, - - getParent: function() { - return this.parent; - }, - - getChildren: function() { - if(this.hasChildren() === undefined){ - return undefined; // Lazy node: unloaded, currently loading, or load error - } - return this.childList; - }, - - /** Check if node has children (returns undefined, if not sure). */ - hasChildren: function() { - if(this.data.isLazy){ - if(this.childList === null || this.childList === undefined){ - // Not yet loaded - return undefined; - }else if(this.childList.length === 0){ - // Loaded, but response was empty - return false; - }else if(this.childList.length === 1 && this.childList[0].isStatusNode()){ - // Currently loading or load error - return undefined; - } - return true; - } - return !!this.childList; - }, - - isFirstSibling: function() { - var p = this.parent; - return !p || p.childList[0] === this; - }, - - isLastSibling: function() { - var p = this.parent; - return !p || p.childList[p.childList.length-1] === this; - }, - - isLoading: function() { - return !!this._isLoading; - }, - - getPrevSibling: function() { - if( !this.parent ){ - return null; - } - var ac = this.parent.childList; - for(var i=1, l=ac.length; i<l; i++){ // start with 1, so prev(first) = null - if( ac[i] === this ){ - return ac[i-1]; - } - } - return null; - }, - - getNextSibling: function() { - if( !this.parent ){ - return null; - } - var ac = this.parent.childList; - for(var i=0, l=ac.length-1; i<l; i++){ // up to length-2, so next(last) = null - if( ac[i] === this ){ - return ac[i+1]; - } - } - return null; - }, - - isStatusNode: function() { - return (this.data.isStatusNode === true); - }, - - isChildOf: function(otherNode) { - return (this.parent && this.parent === otherNode); - }, - - isDescendantOf: function(otherNode) { - if(!otherNode){ - return false; - } - var p = this.parent; - while( p ) { - if( p === otherNode ){ - return true; - } - p = p.parent; - } - return false; - }, - - countChildren: function() { - var cl = this.childList; - if( !cl ){ - return 0; - } - var n = cl.length; - for(var i=0, l=n; i<l; i++){ - var child = cl[i]; - n += child.countChildren(); - } - return n; - }, - - /**Sort child list by title. - * cmd: optional compare function. - * deep: optional: pass true to sort all descendant nodes. - */ - sortChildren: function(cmp, deep) { - var cl = this.childList; - if( !cl ){ - return; - } - cmp = cmp || function(a, b) { -// return a.data.title === b.data.title ? 0 : a.data.title > b.data.title ? 1 : -1; - var x = a.data.title.toLowerCase(), - y = b.data.title.toLowerCase(); - return x === y ? 0 : x > y ? 1 : -1; - }; - cl.sort(cmp); - if( deep ){ - for(var i=0, l=cl.length; i<l; i++){ - if( cl[i].childList ){ - cl[i].sortChildren(cmp, "$norender$"); - } - } - } - if( deep !== "$norender$" ){ - this.render(); - } - }, - - _setStatusNode: function(data) { - // Create, modify or remove the status child node (pass 'null', to remove it). - var firstChild = ( this.childList ? this.childList[0] : null ); - if( !data ) { - if ( firstChild && firstChild.isStatusNode()) { - try{ - // I've seen exceptions here with loadKeyPath... - if(this.ul){ - this.ul.removeChild(firstChild.li); - firstChild.li = null; // avoid leaks (issue 215) - } - }catch(e){} - if( this.childList.length === 1 ){ - this.childList = []; - }else{ - this.childList.shift(); - } - } - } else if ( firstChild ) { - data.isStatusNode = true; - data.key = "_statusNode"; - firstChild.data = data; - firstChild.render(); - } else { - data.isStatusNode = true; - data.key = "_statusNode"; - firstChild = this.addChild(data); - } - }, - - setLazyNodeStatus: function(lts, opts) { - var tooltip = (opts && opts.tooltip) ? opts.tooltip : null, - info = (opts && opts.info) ? " (" + opts.info + ")" : ""; - switch( lts ) { - case DTNodeStatus_Ok: - this._setStatusNode(null); - $(this.span).removeClass(this.tree.options.classNames.nodeLoading); - this._isLoading = false; -// this.render(); - if( this.tree.options.autoFocus ) { - if( this === this.tree.tnRoot && this.childList && this.childList.length > 0) { - // special case: using ajaxInit - this.childList[0].focus(); - } else { - this.focus(); - } - } - break; - case DTNodeStatus_Loading: - this._isLoading = true; - $(this.span).addClass(this.tree.options.classNames.nodeLoading); - // The root is hidden, so we set a temporary status child - if(!this.parent){ - this._setStatusNode({ - title: this.tree.options.strings.loading + info, - tooltip: tooltip, - addClass: this.tree.options.classNames.nodeWait - }); - } - break; - case DTNodeStatus_Error: - this._isLoading = false; -// $(this.span).addClass(this.tree.options.classNames.nodeError); - this._setStatusNode({ - title: this.tree.options.strings.loadError + info, - tooltip: tooltip, - addClass: this.tree.options.classNames.nodeError - }); - break; - default: - throw "Bad LazyNodeStatus: '" + lts + "'."; - } - }, - - _parentList: function(includeRoot, includeSelf) { - var l = []; - var dtn = includeSelf ? this : this.parent; - while( dtn ) { - if( includeRoot || dtn.parent ){ - l.unshift(dtn); - } - dtn = dtn.parent; - } - return l; - }, - getLevel: function() { - /** - * Return node depth. 0: System root node, 1: visible top-level node. - */ - var level = 0; - var dtn = this.parent; - while( dtn ) { - level++; - dtn = dtn.parent; - } - return level; - }, - - _getTypeForOuterNodeEvent: function(event) { - /** Return the inner node span (title, checkbox or expander) if - * event.target points to the outer span. - * This function should fix issue #93: - * FF2 ignores empty spans, when generating events (returning the parent instead). - */ - var cns = this.tree.options.classNames; - var target = event.target; - // Only process clicks on an outer node span (probably due to a FF2 event handling bug) - if( target.className.indexOf(cns.node) < 0 ) { - return null; - } - // Event coordinates, relative to outer node span: - var eventX = event.pageX - target.offsetLeft; - var eventY = event.pageY - target.offsetTop; - - for(var i=0, l=target.childNodes.length; i<l; i++) { - var cn = target.childNodes[i]; - var x = cn.offsetLeft - target.offsetLeft; - var y = cn.offsetTop - target.offsetTop; - var nx = cn.clientWidth, ny = cn.clientHeight; -// alert (cn.className + ": " + x + ", " + y + ", s:" + nx + ", " + ny); - if( eventX >= x && eventX <= (x+nx) && eventY >= y && eventY <= (y+ny) ) { -// alert("HIT "+ cn.className); - if( cn.className==cns.title ){ - return "title"; - }else if( cn.className==cns.expander ){ - return "expander"; - }else if( cn.className==cns.checkbox ){ - return "checkbox"; - }else if( cn.className==cns.nodeIcon ){ - return "icon"; - } - } - } - return "prefix"; - }, - - getEventTargetType: function(event) { - // Return the part of a node, that a click event occured on. - // Note: there is no check, if the event was fired on THIS node. - var tcn = event && event.target ? event.target.className : "", - cns = this.tree.options.classNames; - - if( tcn === cns.title ){ - return "title"; - }else if( tcn === cns.expander ){ - return "expander"; - }else if( tcn === cns.checkbox ){ - return "checkbox"; - }else if( tcn === cns.nodeIcon ){ - return "icon"; - }else if( tcn === cns.empty || tcn === cns.vline || tcn === cns.connector ){ - return "prefix"; - }else if( tcn.indexOf(cns.node) >= 0 ){ - // FIX issue #93 - return this._getTypeForOuterNodeEvent(event); - } - return null; - }, - - isVisible: function() { - // Return true, if all parents are expanded. - var parents = this._parentList(true, false); - for(var i=0, l=parents.length; i<l; i++){ - if( ! parents[i].bExpanded ){ return false; } - } - return true; - }, - - makeVisible: function() { - // Make sure, all parents are expanded - var parents = this._parentList(true, false); - for(var i=0, l=parents.length; i<l; i++){ - parents[i]._expand(true); - } - }, - - focus: function() { - // TODO: check, if we already have focus -// this.tree.logDebug("dtnode.focus(): %o", this); - this.makeVisible(); - try { - $(this.span).find(">a").focus(); - } catch(e) { } - }, - - isFocused: function() { - return (this.tree.tnFocused === this); - }, - - _activate: function(flag, fireEvents) { - // (De)Activate - but not focus - this node. - this.tree.logDebug("dtnode._activate(%o, fireEvents=%o) - %o", flag, fireEvents, this); - var opts = this.tree.options; - if( this.data.isStatusNode ){ - return; - } - if ( fireEvents && opts.onQueryActivate && opts.onQueryActivate.call(this.tree, flag, this) === false ){ - return; // Callback returned false - } - if( flag ) { - // Activate - if( this.tree.activeNode ) { - if( this.tree.activeNode === this ){ - return; - } - this.tree.activeNode.deactivate(); - } - if( opts.activeVisible ){ - this.makeVisible(); - } - this.tree.activeNode = this; - if( opts.persist ){ - $.cookie(opts.cookieId+"-active", this.data.key, opts.cookie); - } - this.tree.persistence.activeKey = this.data.key; - $(this.span).addClass(opts.classNames.active); - if ( fireEvents && opts.onActivate ){ - opts.onActivate.call(this.tree, this); - } - } else { - // Deactivate - if( this.tree.activeNode === this ) { - if ( opts.onQueryActivate && opts.onQueryActivate.call(this.tree, false, this) === false ){ - return; // Callback returned false - } - $(this.span).removeClass(opts.classNames.active); - if( opts.persist ) { - // Note: we don't pass null, but ''. So the cookie is not deleted. - // If we pass null, we also have to pass a COPY of opts, because $cookie will override opts.expires (issue 84) - $.cookie(opts.cookieId+"-active", "", opts.cookie); - } - this.tree.persistence.activeKey = null; - this.tree.activeNode = null; - if ( fireEvents && opts.onDeactivate ){ - opts.onDeactivate.call(this.tree, this); - } - } - } - }, - - activate: function() { - // Select - but not focus - this node. -// this.tree.logDebug("dtnode.activate(): %o", this); - this._activate(true, true); - }, - - activateSilently: function() { - this._activate(true, false); - }, - - deactivate: function() { -// this.tree.logDebug("dtnode.deactivate(): %o", this); - this._activate(false, true); - }, - - isActive: function() { - return (this.tree.activeNode === this); - }, - - _userActivate: function() { - // Handle user click / [space] / [enter], according to clickFolderMode. - var activate = true; - var expand = false; - if ( this.data.isFolder ) { - switch( this.tree.options.clickFolderMode ) { - case 2: - activate = false; - expand = true; - break; - case 3: - activate = expand = true; - break; - } - } - if( this.parent === null ) { - expand = false; - } - if( expand ) { - this.toggleExpand(); - this.focus(); - } - if( activate ) { - this.activate(); - } - }, - - _setSubSel: function(hasSubSel) { - if( hasSubSel ) { - this.hasSubSel = true; - $(this.span).addClass(this.tree.options.classNames.partsel); - } else { - this.hasSubSel = false; - $(this.span).removeClass(this.tree.options.classNames.partsel); - } - }, - /** - * Fix selection and partsel status, of parent nodes, according to current status of - * end nodes. - */ - _updatePartSelectionState: function() { -// alert("_updatePartSelectionState " + this); -// this.tree.logDebug("_updatePartSelectionState() - %o", this); - var sel; - // Return `true` or `false` for end nodes and remove part-sel flag - if( ! this.hasChildren() ){ - sel = (this.bSelected && !this.data.unselectable && !this.data.isStatusNode); - this._setSubSel(false); - return sel; - } - // Return `true`, `false`, or `undefined` for parent nodes - var i, l, - cl = this.childList, - allSelected = true, - allDeselected = true; - for(i=0, l=cl.length; i<l; i++) { - var n = cl[i], - s = n._updatePartSelectionState(); - if( s !== false){ - allDeselected = false; - } - if( s !== true){ - allSelected = false; - } - } - if( allSelected ){ - sel = true; - } else if ( allDeselected ){ - sel = false; - } else { - sel = undefined; - } - this._setSubSel(sel === undefined); - this.bSelected = (sel === true); - return sel; - }, - - /** - * Fix selection status, after this node was (de)selected in multi-hier mode. - * This includes (de)selecting all children. - */ - _fixSelectionState: function() { -// alert("_fixSelectionState " + this); -// this.tree.logDebug("_fixSelectionState(%s) - %o", this.bSelected, this); - var p, i, l; - if( this.bSelected ) { - // Select all children - this.visit(function(node){ - node.parent._setSubSel(true); - if(!node.data.unselectable){ - node._select(true, false, false); - } - }); - // Select parents, if all children are selected - p = this.parent; - while( p ) { - p._setSubSel(true); - var allChildsSelected = true; - for(i=0, l=p.childList.length; i<l; i++) { - var n = p.childList[i]; - if( !n.bSelected && !n.data.isStatusNode && !n.data.unselectable) { - // issue 305 proposes this: -// if( !n.bSelected && !n.data.isStatusNode ) { - allChildsSelected = false; - break; - } - } - if( allChildsSelected ){ - p._select(true, false, false); - } - p = p.parent; - } - } else { - // Deselect all children - this._setSubSel(false); - this.visit(function(node){ - node._setSubSel(false); - node._select(false, false, false); - }); - // Deselect parents, and recalc hasSubSel - p = this.parent; - while( p ) { - p._select(false, false, false); - var isPartSel = false; - for(i=0, l=p.childList.length; i<l; i++) { - if( p.childList[i].bSelected || p.childList[i].hasSubSel ) { - isPartSel = true; - break; - } - } - p._setSubSel(isPartSel); - p = p.parent; - } - } - }, - - _select: function(sel, fireEvents, deep) { - // Select - but not focus - this node. -// this.tree.logDebug("dtnode._select(%o) - %o", sel, this); - var opts = this.tree.options; - if( this.data.isStatusNode ){ - return; - } - // - if( this.bSelected === sel ) { -// this.tree.logDebug("dtnode._select(%o) IGNORED - %o", sel, this); - return; - } - // Allow event listener to abort selection - if ( fireEvents && opts.onQuerySelect && opts.onQuerySelect.call(this.tree, sel, this) === false ){ - return; // Callback returned false - } - // Force single-selection - if( opts.selectMode==1 && sel ) { - this.tree.visit(function(node){ - if( node.bSelected ) { - // Deselect; assuming that in selectMode:1 there's max. one other selected node - node._select(false, false, false); - return false; - } - }); - } - - this.bSelected = sel; -// this.tree._changeNodeList("select", this, sel); - - if( sel ) { - if( opts.persist ){ - this.tree.persistence.addSelect(this.data.key); - } - $(this.span).addClass(opts.classNames.selected); - - if( deep && opts.selectMode === 3 ){ - this._fixSelectionState(); - } - if ( fireEvents && opts.onSelect ){ - opts.onSelect.call(this.tree, true, this); - } - } else { - if( opts.persist ){ - this.tree.persistence.clearSelect(this.data.key); - } - $(this.span).removeClass(opts.classNames.selected); - - if( deep && opts.selectMode === 3 ){ - this._fixSelectionState(); - } - if ( fireEvents && opts.onSelect ){ - opts.onSelect.call(this.tree, false, this); - } - } - }, - - select: function(sel) { - // Select - but not focus - this node. -// this.tree.logDebug("dtnode.select(%o) - %o", sel, this); - if( this.data.unselectable ){ - return this.bSelected; - } - return this._select(sel!==false, true, true); - }, - - toggleSelect: function() { -// this.tree.logDebug("dtnode.toggleSelect() - %o", this); - return this.select(!this.bSelected); - }, - - isSelected: function() { - return this.bSelected; - }, - - isLazy: function() { - return !!this.data.isLazy; - }, - - _loadContent: function() { - try { - var opts = this.tree.options; - this.tree.logDebug("_loadContent: start - %o", this); - this.setLazyNodeStatus(DTNodeStatus_Loading); - if( true === opts.onLazyRead.call(this.tree, this) ) { - // If function returns 'true', we assume that the loading is done: - this.setLazyNodeStatus(DTNodeStatus_Ok); - // Otherwise (i.e. if the loading was started as an asynchronous process) - // the onLazyRead(dtnode) handler is expected to call dtnode.setLazyNodeStatus(DTNodeStatus_Ok/_Error) when done. - this.tree.logDebug("_loadContent: succeeded - %o", this); - } - } catch(e) { - this.tree.logWarning("_loadContent: failed - %o", e); - this.setLazyNodeStatus(DTNodeStatus_Error, {tooltip: ""+e}); - } - }, - - _expand: function(bExpand, forceSync) { - if( this.bExpanded === bExpand ) { - this.tree.logDebug("dtnode._expand(%o) IGNORED - %o", bExpand, this); - return; - } - this.tree.logDebug("dtnode._expand(%o) - %o", bExpand, this); - var opts = this.tree.options; - if( !bExpand && this.getLevel() < opts.minExpandLevel ) { - this.tree.logDebug("dtnode._expand(%o) prevented collapse - %o", bExpand, this); - return; - } - if ( opts.onQueryExpand && opts.onQueryExpand.call(this.tree, bExpand, this) === false ){ - return; // Callback returned false - } - this.bExpanded = bExpand; - - // Persist expand state - if( opts.persist ) { - if( bExpand ){ - this.tree.persistence.addExpand(this.data.key); - }else{ - this.tree.persistence.clearExpand(this.data.key); - } - } - // Do not apply animations in init phase, or before lazy-loading - var allowEffects = !(this.data.isLazy && this.childList === null) && !this._isLoading && !forceSync; - this.render(allowEffects); - - // Auto-collapse mode: collapse all siblings - if( this.bExpanded && this.parent && opts.autoCollapse ) { - var parents = this._parentList(false, true); - for(var i=0, l=parents.length; i<l; i++){ - parents[i].collapseSiblings(); - } - } - // If the currently active node is now hidden, deactivate it - if( opts.activeVisible && this.tree.activeNode && ! this.tree.activeNode.isVisible() ) { - this.tree.activeNode.deactivate(); - } - // Expanding a lazy node: set 'loading...' and call callback - if( bExpand && this.data.isLazy && this.childList === null && !this._isLoading ) { - this._loadContent(); - return; - } - if ( opts.onExpand ){ - opts.onExpand.call(this.tree, bExpand, this); - } - }, - - isExpanded: function() { - return this.bExpanded; - }, - - expand: function(flag) { - flag = (flag !== false); - if( !this.childList && !this.data.isLazy && flag ){ - return; // Prevent expanding empty nodes - } else if( this.parent === null && !flag ){ - return; // Prevent collapsing the root - } - this._expand(flag); - }, - - scheduleAction: function(mode, ms) { - /** Schedule activity for delayed execution (cancel any pending request). - * scheduleAction('cancel') will cancel the request. - */ - if( this.tree.timer ) { - clearTimeout(this.tree.timer); - this.tree.logDebug("clearTimeout(%o)", this.tree.timer); - } - var self = this; // required for closures - switch (mode) { - case "cancel": - // Simply made sure that timer was cleared - break; - case "expand": - this.tree.timer = setTimeout(function(){ - self.tree.logDebug("setTimeout: trigger expand"); - self.expand(true); - }, ms); - break; - case "activate": - this.tree.timer = setTimeout(function(){ - self.tree.logDebug("setTimeout: trigger activate"); - self.activate(); - }, ms); - break; - default: - throw "Invalid mode " + mode; - } - this.tree.logDebug("setTimeout(%s, %s): %s", mode, ms, this.tree.timer); - }, - - toggleExpand: function() { - this.expand(!this.bExpanded); - }, - - collapseSiblings: function() { - if( this.parent === null ){ - return; - } - var ac = this.parent.childList; - for (var i=0, l=ac.length; i<l; i++) { - if ( ac[i] !== this && ac[i].bExpanded ){ - ac[i]._expand(false); - } - } - }, - - _onClick: function(event) { -// this.tree.logDebug("dtnode.onClick(" + event.type + "): dtnode:" + this + ", button:" + event.button + ", which: " + event.which); - var targetType = this.getEventTargetType(event); - if( targetType === "expander" ) { - // Clicking the expander icon always expands/collapses - this.toggleExpand(); - this.focus(); // issue 95 - } else if( targetType === "checkbox" ) { - // Clicking the checkbox always (de)selects - this.toggleSelect(); - this.focus(); // issue 95 - } else { - this._userActivate(); - var aTag = this.span.getElementsByTagName("a"); - if(aTag[0]){ - // issue 154, 313 -// if(!($.browser.msie && parseInt($.browser.version, 10) < 9)){ - if(!(BROWSER.msie && parseInt(BROWSER.version, 10) < 9)){ - aTag[0].focus(); - } - }else{ - // 'noLink' option was set - return true; - } - } - // Make sure that clicks stop, otherwise <a href='#'> jumps to the top - event.preventDefault(); - }, - - _onDblClick: function(event) { -// this.tree.logDebug("dtnode.onDblClick(" + event.type + "): dtnode:" + this + ", button:" + event.button + ", which: " + event.which); - }, - - _onKeydown: function(event) { -// this.tree.logDebug("dtnode.onKeydown(" + event.type + "): dtnode:" + this + ", charCode:" + event.charCode + ", keyCode: " + event.keyCode + ", which: " + event.which); - var handled = true, - sib; -// alert("keyDown" + event.which); - - switch( event.which ) { - // charCodes: -// case 43: // '+' - case 107: // '+' - case 187: // '+' @ Chrome, Safari - if( !this.bExpanded ){ this.toggleExpand(); } - break; -// case 45: // '-' - case 109: // '-' - case 189: // '+' @ Chrome, Safari - if( this.bExpanded ){ this.toggleExpand(); } - break; - //~ case 42: // '*' - //~ break; - //~ case 47: // '/' - //~ break; - // case 13: // <enter> - // <enter> on a focused <a> tag seems to generate a click-event. - // this._userActivate(); - // break; - case 32: // <space> - this._userActivate(); - break; - case 8: // <backspace> - if( this.parent ){ - this.parent.focus(); - } - break; - case 37: // <left> - if( this.bExpanded ) { - this.toggleExpand(); - this.focus(); -// } else if( this.parent && (this.tree.options.rootVisible || this.parent.parent) ) { - } else if( this.parent && this.parent.parent ) { - this.parent.focus(); - } - break; - case 39: // <right> - if( !this.bExpanded && (this.childList || this.data.isLazy) ) { - this.toggleExpand(); - this.focus(); - } else if( this.childList ) { - this.childList[0].focus(); - } - break; - case 38: // <up> - sib = this.getPrevSibling(); - while( sib && sib.bExpanded && sib.childList ){ - sib = sib.childList[sib.childList.length-1]; - } -// if( !sib && this.parent && (this.tree.options.rootVisible || this.parent.parent) ) - if( !sib && this.parent && this.parent.parent ){ - sib = this.parent; - } - if( sib ){ - sib.focus(); - } - break; - case 40: // <down> - if( this.bExpanded && this.childList ) { - sib = this.childList[0]; - } else { - var parents = this._parentList(false, true); - for(var i=parents.length-1; i>=0; i--) { - sib = parents[i].getNextSibling(); - if( sib ){ break; } - } - } - if( sib ){ - sib.focus(); - } - break; - default: - handled = false; - } - // Return false, if handled, to prevent default processing -// return !handled; - if(handled){ - event.preventDefault(); - } - }, - - _onKeypress: function(event) { - // onKeypress is only hooked to allow user callbacks. - // We don't process it, because IE and Safari don't fire keypress for cursor keys. -// this.tree.logDebug("dtnode.onKeypress(" + event.type + "): dtnode:" + this + ", charCode:" + event.charCode + ", keyCode: " + event.keyCode + ", which: " + event.which); - }, - - _onFocus: function(event) { - // Handles blur and focus events. -// this.tree.logDebug("dtnode._onFocus(%o): %o", event, this); - var opts = this.tree.options; - if ( event.type == "blur" || event.type == "focusout" ) { - if ( opts.onBlur ){ - opts.onBlur.call(this.tree, this); - } - if( this.tree.tnFocused ){ - $(this.tree.tnFocused.span).removeClass(opts.classNames.focused); - } - this.tree.tnFocused = null; - if( opts.persist ){ - $.cookie(opts.cookieId+"-focus", "", opts.cookie); - } - } else if ( event.type=="focus" || event.type=="focusin") { - // Fix: sometimes the blur event is not generated - if( this.tree.tnFocused && this.tree.tnFocused !== this ) { - this.tree.logDebug("dtnode.onFocus: out of sync: curFocus: %o", this.tree.tnFocused); - $(this.tree.tnFocused.span).removeClass(opts.classNames.focused); - } - this.tree.tnFocused = this; - if ( opts.onFocus ){ - opts.onFocus.call(this.tree, this); - } - $(this.tree.tnFocused.span).addClass(opts.classNames.focused); - if( opts.persist ){ - $.cookie(opts.cookieId+"-focus", this.data.key, opts.cookie); - } - } - // TODO: return anything? -// return false; - }, - - visit: function(fn, includeSelf) { - // Call fn(node) for all child nodes. Stop iteration, if fn() returns false. - var res = true; - if( includeSelf === true ) { - res = fn(this); - if( res === false || res == "skip" ){ - return res; - } - } - if(this.childList){ - for(var i=0, l=this.childList.length; i<l; i++){ - res = this.childList[i].visit(fn, true); - if( res === false ){ - break; - } - } - } - return res; - }, - - visitParents: function(fn, includeSelf) { - // Visit parent nodes (bottom up) - if(includeSelf && fn(this) === false){ - return false; - } - var p = this.parent; - while( p ) { - if(fn(p) === false){ - return false; - } - p = p.parent; - } - return true; - }, - - remove: function() { - // Remove this node -// this.tree.logDebug ("%s.remove()", this); - if ( this === this.tree.root ){ - throw "Cannot remove system root"; - } - return this.parent.removeChild(this); - }, - - removeChild: function(tn) { - // Remove tn from list of direct children. - var ac = this.childList; - if( ac.length == 1 ) { - if( tn !== ac[0] ){ - throw "removeChild: invalid child"; - } - return this.removeChildren(); - } - if( tn === this.tree.activeNode ){ - tn.deactivate(); - } - if( this.tree.options.persist ) { - if( tn.bSelected ){ - this.tree.persistence.clearSelect(tn.data.key); - } - if ( tn.bExpanded ){ - this.tree.persistence.clearExpand(tn.data.key); - } - } - tn.removeChildren(true); - if(this.ul){ -// $("li", $(this.ul)).remove(); // issue 399 - this.ul.removeChild(tn.li); // issue 402 - } - for(var i=0, l=ac.length; i<l; i++) { - if( ac[i] === tn ) { - this.childList.splice(i, 1); -// delete tn; // JSLint complained - break; - } - } - }, - - removeChildren: function(isRecursiveCall, retainPersistence) { - // Remove all child nodes (more efficiently than recursive remove()) - this.tree.logDebug("%s.removeChildren(%o)", this, isRecursiveCall); - var tree = this.tree; - var ac = this.childList; - if( ac ) { - for(var i=0, l=ac.length; i<l; i++) { - var tn = ac[i]; - if ( tn === tree.activeNode && !retainPersistence ){ - tn.deactivate(); - } - if( this.tree.options.persist && !retainPersistence ) { - if( tn.bSelected ){ - this.tree.persistence.clearSelect(tn.data.key); - } - if ( tn.bExpanded ){ - this.tree.persistence.clearExpand(tn.data.key); - } - } - tn.removeChildren(true, retainPersistence); - if(this.ul){ -// this.ul.removeChild(tn.li); - $("li", $(this.ul)).remove(); // issue 231 - } -// delete tn; JSLint complained - } - // Set to 'null' which is interpreted as 'not yet loaded' for lazy - // nodes - this.childList = null; - } - if( ! isRecursiveCall ) { -// this._expand(false); -// this.isRead = false; - this._isLoading = false; - this.render(); - } - }, - - setTitle: function(title) { - this.fromDict({title: title}); - }, - - reload: function(force) { - throw "Use reloadChildren() instead"; - }, - - reloadChildren: function(callback) { - // Reload lazy content (expansion state is maintained). - if( this.parent === null ){ - throw "Use tree.reload() instead"; - }else if( ! this.data.isLazy ){ - throw "node.reloadChildren() requires lazy nodes."; - } - // appendAjax triggers 'nodeLoaded' event. - // We listen to this, if a callback was passed to reloadChildren - if(callback){ - var self = this; - var eventType = "nodeLoaded.dynatree." + this.tree.$tree.attr("id") + "." + this.data.key; - this.tree.$tree.bind(eventType, function(e, node, isOk){ - self.tree.$tree.unbind(eventType); - self.tree.logDebug("loaded %o, %o, %o", e, node, isOk); - if(node !== self){ - throw "got invalid load event"; - } - callback.call(self.tree, node, isOk); - }); - } - // The expansion state is maintained - this.removeChildren(); - this._loadContent(); -// if( this.bExpanded ) { -// // Remove children first, to prevent effects being applied -// this.removeChildren(); -// // then force re-expand to trigger lazy loading -//// this.expand(false); -//// this.expand(true); -// this._loadContent(); -// } else { -// this.removeChildren(); -// this._loadContent(); -// } - }, - - /** - * Make sure the node with a given key path is available in the tree. - */ - _loadKeyPath: function(keyPath, callback) { - var tree = this.tree; - tree.logDebug("%s._loadKeyPath(%s)", this, keyPath); - if(keyPath === ""){ - throw "Key path must not be empty"; - } - var segList = keyPath.split(tree.options.keyPathSeparator); - if(segList[0] === ""){ - throw "Key path must be relative (don't start with '/')"; - } - var seg = segList.shift(); - if(this.childList){ - for(var i=0, l=this.childList.length; i < l; i++){ - var child = this.childList[i]; - if( child.data.key === seg ){ - if(segList.length === 0) { - // Found the end node - callback.call(tree, child, "ok"); - - }else if(child.data.isLazy && (child.childList === null || child.childList === undefined)){ - tree.logDebug("%s._loadKeyPath(%s) -> reloading %s...", this, keyPath, child); - var self = this; - // Note: this line gives a JSLint warning (Don't make functions within a loop) - /*jshint loopfunc:true */ - child.reloadChildren(function(node, isOk){ - // After loading, look for direct child with that key - if(isOk){ - tree.logDebug("%s._loadKeyPath(%s) -> reloaded %s.", node, keyPath, node); - callback.call(tree, child, "loaded"); - node._loadKeyPath(segList.join(tree.options.keyPathSeparator), callback); - }else{ - tree.logWarning("%s._loadKeyPath(%s) -> reloadChildren() failed.", self, keyPath); - callback.call(tree, child, "error"); - } - }); - // we can ignore it, since it will only be exectuted once, the the loop is ended - // See also http://stackoverflow.com/questions/3037598/how-to-get-around-the-jslint-error-dont-make-functions-within-a-loop - } else { - callback.call(tree, child, "loaded"); - // Look for direct child with that key - child._loadKeyPath(segList.join(tree.options.keyPathSeparator), callback); - } - return; - } - } - } - // Could not find key - // Callback params: child: undefined, the segment, isEndNode (segList.length === 0) - callback.call(tree, undefined, "notfound", seg, segList.length === 0); - tree.logWarning("Node not found: " + seg); - return; - }, - - resetLazy: function() { - // Discard lazy content. - if( this.parent === null ){ - throw "Use tree.reload() instead"; - }else if( ! this.data.isLazy ){ - throw "node.resetLazy() requires lazy nodes."; - } - this.expand(false); - this.removeChildren(); - }, - - _addChildNode: function(dtnode, beforeNode) { - /** - * Internal function to add one single DynatreeNode as a child. - * - */ - var tree = this.tree, - opts = tree.options, - pers = tree.persistence; - -// tree.logDebug("%s._addChildNode(%o)", this, dtnode); - - // --- Update and fix dtnode attributes if necessary - dtnode.parent = this; -// if( beforeNode && (beforeNode.parent !== this || beforeNode === dtnode ) ) -// throw "<beforeNode> must be another child of <this>"; - - // --- Add dtnode as a child - if ( this.childList === null ) { - this.childList = []; - } else if( ! beforeNode ) { - // Fix 'lastsib' - if(this.childList.length > 0) { - $(this.childList[this.childList.length-1].span).removeClass(opts.classNames.lastsib); - } - } - if( beforeNode ) { - var iBefore = $.inArray(beforeNode, this.childList); - if( iBefore < 0 ){ - throw "<beforeNode> must be a child of <this>"; - } - this.childList.splice(iBefore, 0, dtnode); - } else { - // Append node - this.childList.push(dtnode); - } - - // --- Handle persistence - // Initial status is read from cookies, if persistence is active and - // cookies are already present. - // Otherwise the status is read from the data attributes and then persisted. - var isInitializing = tree.isInitializing(); - if( opts.persist && pers.cookiesFound && isInitializing ) { - // Init status from cookies -// tree.logDebug("init from cookie, pa=%o, dk=%o", pers.activeKey, dtnode.data.key); - if( pers.activeKey === dtnode.data.key ){ - tree.activeNode = dtnode; - } - if( pers.focusedKey === dtnode.data.key ){ - tree.focusNode = dtnode; - } - dtnode.bExpanded = ($.inArray(dtnode.data.key, pers.expandedKeyList) >= 0); - dtnode.bSelected = ($.inArray(dtnode.data.key, pers.selectedKeyList) >= 0); -// tree.logDebug(" key=%o, bSelected=%o", dtnode.data.key, dtnode.bSelected); - } else { - // Init status from data (Note: we write the cookies after the init phase) -// tree.logDebug("init from data"); - if( dtnode.data.activate ) { - tree.activeNode = dtnode; - if( opts.persist ){ - pers.activeKey = dtnode.data.key; - } - } - if( dtnode.data.focus ) { - tree.focusNode = dtnode; - if( opts.persist ){ - pers.focusedKey = dtnode.data.key; - } - } - dtnode.bExpanded = ( dtnode.data.expand === true ); // Collapsed by default - if( dtnode.bExpanded && opts.persist ){ - pers.addExpand(dtnode.data.key); - } - dtnode.bSelected = ( dtnode.data.select === true ); // Deselected by default -/* - Doesn't work, cause pers.selectedKeyList may be null - if( dtnode.bSelected && opts.selectMode==1 - && pers.selectedKeyList && pers.selectedKeyList.length>0 ) { - tree.logWarning("Ignored multi-selection in single-mode for %o", dtnode); - dtnode.bSelected = false; // Fixing bad input data (multi selection for mode:1) - } -*/ - if( dtnode.bSelected && opts.persist ){ - pers.addSelect(dtnode.data.key); - } - } - - // Always expand, if it's below minExpandLevel -// tree.logDebug ("%s._addChildNode(%o), l=%o", this, dtnode, dtnode.getLevel()); - if ( opts.minExpandLevel >= dtnode.getLevel() ) { -// tree.logDebug ("Force expand for %o", dtnode); - this.bExpanded = true; - } - - // In multi-hier mode, update the parents selection state - // issue #82: only if not initializing, because the children may not exist yet -// if( !dtnode.data.isStatusNode && opts.selectMode==3 && !isInitializing ) -// dtnode._fixSelectionState(); - - // In multi-hier mode, update the parents selection state - if( dtnode.bSelected && opts.selectMode==3 ) { - var p = this; - while( p ) { - if( !p.hasSubSel ){ - p._setSubSel(true); - } - p = p.parent; - } - } - // render this node and the new child - if ( tree.bEnableUpdate ){ - this.render(); - } - return dtnode; - }, - - addChild: function(obj, beforeNode) { - /** - * Add a node object as child. - * - * This should be the only place, where a DynaTreeNode is constructed! - * (Except for the root node creation in the tree constructor) - * - * @param obj A JS object (may be recursive) or an array of those. - * @param {DynaTreeNode} beforeNode (optional) sibling node. - * - * Data format: array of node objects, with optional 'children' attributes. - * [ - * { title: "t1", isFolder: true, ... } - * { title: "t2", isFolder: true, ..., - * children: [ - * {title: "t2.1", ..}, - * {..} - * ] - * } - * ] - * A simple object is also accepted instead of an array. - * - */ -// this.tree.logDebug("%s.addChild(%o, %o)", this, obj, beforeNode); - if(typeof(obj) == "string"){ - throw "Invalid data type for " + obj; - }else if( !obj || obj.length === 0 ){ // Passed null or undefined or empty array - return; - }else if( obj instanceof DynaTreeNode ){ - return this._addChildNode(obj, beforeNode); - } - - if( !obj.length ){ // Passed a single data object - obj = [ obj ]; - } - var prevFlag = this.tree.enableUpdate(false); - - var tnFirst = null; - for (var i=0, l=obj.length; i<l; i++) { - var data = obj[i]; - var dtnode = this._addChildNode(new DynaTreeNode(this, this.tree, data), beforeNode); - if( !tnFirst ){ - tnFirst = dtnode; - } - // Add child nodes recursively - if( data.children ){ - dtnode.addChild(data.children, null); - } - } - this.tree.enableUpdate(prevFlag); - return tnFirst; - }, - - append: function(obj) { - this.tree.logWarning("node.append() is deprecated (use node.addChild() instead)."); - return this.addChild(obj, null); - }, - - appendAjax: function(ajaxOptions) { - var self = this; - this.removeChildren(false, true); - this.setLazyNodeStatus(DTNodeStatus_Loading); - // Debug feature: force a delay, to simulate slow loading... - if(ajaxOptions.debugLazyDelay){ - var ms = ajaxOptions.debugLazyDelay; - ajaxOptions.debugLazyDelay = 0; - this.tree.logInfo("appendAjax: waiting for debugLazyDelay " + ms); - setTimeout(function(){self.appendAjax(ajaxOptions);}, ms); - return; - } - // Ajax option inheritance: $.ajaxSetup < $.ui.dynatree.prototype.options.ajaxDefaults < tree.options.ajaxDefaults < ajaxOptions - var orgSuccess = ajaxOptions.success, - orgError = ajaxOptions.error, - eventType = "nodeLoaded.dynatree." + this.tree.$tree.attr("id") + "." + this.data.key; - var options = $.extend({}, this.tree.options.ajaxDefaults, ajaxOptions, { - success: function(data, textStatus, jqXHR){ - // <this> is the request options -// self.tree.logDebug("appendAjax().success"); - var prevPhase = self.tree.phase; - self.tree.phase = "init"; - // postProcess is similar to the standard dataFilter hook, - // but it is also called for JSONP - if( options.postProcess ){ - data = options.postProcess.call(this, data, this.dataType); - } - // Process ASPX WebMethod JSON object inside "d" property - // http://code.google.com/p/dynatree/issues/detail?id=202 - else if (data && data.hasOwnProperty("d")) { - data = (typeof data.d) == "string" ? $.parseJSON(data.d) : data.d; - } - if(!$.isArray(data) || data.length !== 0){ - self.addChild(data, null); - } - self.tree.phase = "postInit"; - if( orgSuccess ){ - orgSuccess.call(options, self, data, textStatus); - } - self.tree.logDebug("trigger " + eventType); - self.tree.$tree.trigger(eventType, [self, true]); - self.tree.phase = prevPhase; - // This should be the last command, so node._isLoading is true - // while the callbacks run - self.setLazyNodeStatus(DTNodeStatus_Ok); - if($.isArray(data) && data.length === 0){ - // Set to [] which is interpreted as 'no children' for lazy - // nodes - self.childList = []; - self.render(); - } - }, - error: function(jqXHR, textStatus, errorThrown){ - // <this> is the request options - self.tree.logWarning("appendAjax failed:", textStatus, ":\n", jqXHR, "\n", errorThrown); - if( orgError ){ - orgError.call(options, self, jqXHR, textStatus, errorThrown); - } - self.tree.$tree.trigger(eventType, [self, false]); - self.setLazyNodeStatus(DTNodeStatus_Error, {info: textStatus, tooltip: "" + errorThrown}); - } - }); - $.ajax(options); - }, - - move: function(targetNode, mode) { - /**Move this node to targetNode. - * mode 'child': append this node as last child of targetNode. - * This is the default. To be compatble with the D'n'd - * hitMode, we also accept 'over'. - * mode 'before': add this node as sibling before targetNode. - * mode 'after': add this node as sibling after targetNode. - */ - var pos; - if(this === targetNode){ - return; - } - if( !this.parent ){ - throw "Cannot move system root"; - } - if(mode === undefined || mode == "over"){ - mode = "child"; - } - var prevParent = this.parent; - var targetParent = (mode === "child") ? targetNode : targetNode.parent; - if( targetParent.isDescendantOf(this) ){ - throw "Cannot move a node to it's own descendant"; - } - // Unlink this node from current parent - if( this.parent.childList.length == 1 ) { - this.parent.childList = this.parent.data.isLazy ? [] : null; - this.parent.bExpanded = false; - } else { - pos = $.inArray(this, this.parent.childList); - if( pos < 0 ){ - throw "Internal error"; - } - this.parent.childList.splice(pos, 1); - } - // Remove from source DOM parent - if(this.parent.ul){ - this.parent.ul.removeChild(this.li); - } - - // Insert this node to target parent's child list - this.parent = targetParent; - if( targetParent.hasChildren() ) { - switch(mode) { - case "child": - // Append to existing target children - targetParent.childList.push(this); - break; - case "before": - // Insert this node before target node - pos = $.inArray(targetNode, targetParent.childList); - if( pos < 0 ){ - throw "Internal error"; - } - targetParent.childList.splice(pos, 0, this); - break; - case "after": - // Insert this node after target node - pos = $.inArray(targetNode, targetParent.childList); - if( pos < 0 ){ - throw "Internal error"; - } - targetParent.childList.splice(pos+1, 0, this); - break; - default: - throw "Invalid mode " + mode; - } - } else { - targetParent.childList = [ this ]; - } - // Parent has no <ul> tag yet: - if( !targetParent.ul ) { - // This is the parent's first child: create UL tag - // (Hidden, because it will be - targetParent.ul = document.createElement("ul"); - targetParent.ul.style.display = "none"; - targetParent.li.appendChild(targetParent.ul); - } - // Issue 319: Add to target DOM parent (only if node was already rendered(expanded)) - if(this.li){ - targetParent.ul.appendChild(this.li); - } - - if( this.tree !== targetNode.tree ) { - // Fix node.tree for all source nodes - this.visit(function(node){ - node.tree = targetNode.tree; - }, null, true); - throw "Not yet implemented."; - } - // TODO: fix selection state - // TODO: fix active state - if( !prevParent.isDescendantOf(targetParent)) { - prevParent.render(); - } - if( !targetParent.isDescendantOf(prevParent) ) { - targetParent.render(); - } -// this.tree.redraw(); -/* - var tree = this.tree; - var opts = tree.options; - var pers = tree.persistence; - - - // Always expand, if it's below minExpandLevel -// tree.logDebug ("%s._addChildNode(%o), l=%o", this, dtnode, dtnode.getLevel()); - if ( opts.minExpandLevel >= dtnode.getLevel() ) { -// tree.logDebug ("Force expand for %o", dtnode); - this.bExpanded = true; - } - - // In multi-hier mode, update the parents selection state - // issue #82: only if not initializing, because the children may not exist yet -// if( !dtnode.data.isStatusNode && opts.selectMode==3 && !isInitializing ) -// dtnode._fixSelectionState(); - - // In multi-hier mode, update the parents selection state - if( dtnode.bSelected && opts.selectMode==3 ) { - var p = this; - while( p ) { - if( !p.hasSubSel ) - p._setSubSel(true); - p = p.parent; - } - } - // render this node and the new child - if ( tree.bEnableUpdate ) - this.render(); - - return dtnode; - -*/ - }, - - // --- end of class - lastentry: undefined -}; - -/************************************************************************* - * class DynaTreeStatus - */ - -var DynaTreeStatus = Class.create(); - - -DynaTreeStatus._getTreePersistData = function(cookieId, cookieOpts) { - // Static member: Return persistence information from cookies - var ts = new DynaTreeStatus(cookieId, cookieOpts); - ts.read(); - return ts.toDict(); -}; -// Make available in global scope -getDynaTreePersistData = DynaTreeStatus._getTreePersistData; // TODO: deprecated - - -DynaTreeStatus.prototype = { - // Constructor - initialize: function(cookieId, cookieOpts) { -// this._log("DynaTreeStatus: initialize"); - if( cookieId === undefined ){ - cookieId = $.ui.dynatree.prototype.options.cookieId; - } - cookieOpts = $.extend({}, $.ui.dynatree.prototype.options.cookie, cookieOpts); - - this.cookieId = cookieId; - this.cookieOpts = cookieOpts; - this.cookiesFound = undefined; - this.activeKey = null; - this.focusedKey = null; - this.expandedKeyList = null; - this.selectedKeyList = null; - }, - // member functions - _log: function(msg) { - // this.logDebug("_changeNodeList(%o): nodeList:%o, idx:%o", mode, nodeList, idx); - Array.prototype.unshift.apply(arguments, ["debug"]); - _log.apply(this, arguments); - }, - read: function() { -// this._log("DynaTreeStatus: read"); - // Read or init cookies. - this.cookiesFound = false; - - var cookie = $.cookie(this.cookieId + "-active"); - this.activeKey = ( cookie === null ) ? "" : cookie; - if( cookie !== null ){ - this.cookiesFound = true; - } - cookie = $.cookie(this.cookieId + "-focus"); - this.focusedKey = ( cookie === null ) ? "" : cookie; - if( cookie !== null ){ - this.cookiesFound = true; - } - cookie = $.cookie(this.cookieId + "-expand"); - this.expandedKeyList = ( cookie === null ) ? [] : cookie.split(","); - if( cookie !== null ){ - this.cookiesFound = true; - } - cookie = $.cookie(this.cookieId + "-select"); - this.selectedKeyList = ( cookie === null ) ? [] : cookie.split(","); - if( cookie !== null ){ - this.cookiesFound = true; - } - }, - write: function() { -// this._log("DynaTreeStatus: write"); - $.cookie(this.cookieId + "-active", ( this.activeKey === null ) ? "" : this.activeKey, this.cookieOpts); - $.cookie(this.cookieId + "-focus", ( this.focusedKey === null ) ? "" : this.focusedKey, this.cookieOpts); - $.cookie(this.cookieId + "-expand", ( this.expandedKeyList === null ) ? "" : this.expandedKeyList.join(","), this.cookieOpts); - $.cookie(this.cookieId + "-select", ( this.selectedKeyList === null ) ? "" : this.selectedKeyList.join(","), this.cookieOpts); - }, - addExpand: function(key) { -// this._log("addExpand(%o)", key); - if( $.inArray(key, this.expandedKeyList) < 0 ) { - this.expandedKeyList.push(key); - $.cookie(this.cookieId + "-expand", this.expandedKeyList.join(","), this.cookieOpts); - } - }, - clearExpand: function(key) { -// this._log("clearExpand(%o)", key); - var idx = $.inArray(key, this.expandedKeyList); - if( idx >= 0 ) { - this.expandedKeyList.splice(idx, 1); - $.cookie(this.cookieId + "-expand", this.expandedKeyList.join(","), this.cookieOpts); - } - }, - addSelect: function(key) { -// this._log("addSelect(%o)", key); - if( $.inArray(key, this.selectedKeyList) < 0 ) { - this.selectedKeyList.push(key); - $.cookie(this.cookieId + "-select", this.selectedKeyList.join(","), this.cookieOpts); - } - }, - clearSelect: function(key) { -// this._log("clearSelect(%o)", key); - var idx = $.inArray(key, this.selectedKeyList); - if( idx >= 0 ) { - this.selectedKeyList.splice(idx, 1); - $.cookie(this.cookieId + "-select", this.selectedKeyList.join(","), this.cookieOpts); - } - }, - isReloading: function() { - return this.cookiesFound === true; - }, - toDict: function() { - return { - cookiesFound: this.cookiesFound, - activeKey: this.activeKey, - focusedKey: this.activeKey, - expandedKeyList: this.expandedKeyList, - selectedKeyList: this.selectedKeyList - }; - }, - // --- end of class - lastentry: undefined -}; - - -/************************************************************************* - * class DynaTree - */ - -var DynaTree = Class.create(); - -// --- Static members ---------------------------------------------------------- - -DynaTree.version = "$Version: 1.2.4$"; - -/* -DynaTree._initTree = function() { -}; - -DynaTree._bind = function() { -}; -*/ -//--- Class members ------------------------------------------------------------ - -DynaTree.prototype = { - // Constructor -// initialize: function(divContainer, options) { - initialize: function($widget) { - // instance members - this.phase = "init"; - this.$widget = $widget; - this.options = $widget.options; - this.$tree = $widget.element; - this.timer = null; - // find container element - this.divTree = this.$tree.get(0); - -// var parentPos = $(this.divTree).parent().offset(); -// this.parentTop = parentPos.top; -// this.parentLeft = parentPos.left; - - _initDragAndDrop(this); - }, - - // member functions - - _load: function(callback) { - var $widget = this.$widget; - var opts = this.options, - self = this; - this.bEnableUpdate = true; - this._nodeCount = 1; - this.activeNode = null; - this.focusNode = null; - - // Some deprecation warnings to help with migration - if( opts.rootVisible !== undefined ){ - this.logWarning("Option 'rootVisible' is no longer supported."); - } - if( opts.minExpandLevel < 1 ) { - this.logWarning("Option 'minExpandLevel' must be >= 1."); - opts.minExpandLevel = 1; - } -// _log("warn", "jQuery.support.boxModel " + jQuery.support.boxModel); - - // If a 'options.classNames' dictionary was passed, still use defaults - // for undefined classes: - if( opts.classNames !== $.ui.dynatree.prototype.options.classNames ) { - opts.classNames = $.extend({}, $.ui.dynatree.prototype.options.classNames, opts.classNames); - } - if( opts.ajaxDefaults !== $.ui.dynatree.prototype.options.ajaxDefaults ) { - opts.ajaxDefaults = $.extend({}, $.ui.dynatree.prototype.options.ajaxDefaults, opts.ajaxDefaults); - } - if( opts.dnd !== $.ui.dynatree.prototype.options.dnd ) { - opts.dnd = $.extend({}, $.ui.dynatree.prototype.options.dnd, opts.dnd); - } - // Guess skin path, if not specified - if(!opts.imagePath) { - $("script").each( function () { - var _rexDtLibName = /.*dynatree[^\/]*\.js$/i; - if( this.src.search(_rexDtLibName) >= 0 ) { - if( this.src.indexOf("/")>=0 ){ // issue #47 - opts.imagePath = this.src.slice(0, this.src.lastIndexOf("/")) + "/skin/"; - }else{ - opts.imagePath = "skin/"; - } - self.logDebug("Guessing imagePath from '%s': '%s'", this.src, opts.imagePath); - return false; // first match - } - }); - } - - this.persistence = new DynaTreeStatus(opts.cookieId, opts.cookie); - if( opts.persist ) { - if( !$.cookie ){ - _log("warn", "Please include jquery.cookie.js to use persistence."); - } - this.persistence.read(); - } - this.logDebug("DynaTree.persistence: %o", this.persistence.toDict()); - - // Cached tag strings - this.cache = { - tagEmpty: "<span class='" + opts.classNames.empty + "'></span>", - tagVline: "<span class='" + opts.classNames.vline + "'></span>", - tagExpander: "<span class='" + opts.classNames.expander + "'></span>", - tagConnector: "<span class='" + opts.classNames.connector + "'></span>", - tagNodeIcon: "<span class='" + opts.classNames.nodeIcon + "'></span>", - tagCheckbox: "<span class='" + opts.classNames.checkbox + "'></span>", - lastentry: undefined - }; - - // Clear container, in case it contained some 'waiting' or 'error' text - // for clients that don't support JS. - // We don't do this however, if we try to load from an embedded UL element. - if( opts.children || (opts.initAjax && opts.initAjax.url) || opts.initId ){ - $(this.divTree).empty(); - } - var $ulInitialize = this.$tree.find(">ul:first").hide(); - - // Create the root element - this.tnRoot = new DynaTreeNode(null, this, {}); - this.tnRoot.bExpanded = true; - this.tnRoot.render(); - this.divTree.appendChild(this.tnRoot.ul); - - var root = this.tnRoot, - isReloading = ( opts.persist && this.persistence.isReloading() ), - isLazy = false, - prevFlag = this.enableUpdate(false); - - this.logDebug("Dynatree._load(): read tree structure..."); - - // Init tree structure - if( opts.children ) { - // Read structure from node array - root.addChild(opts.children); - - } else if( opts.initAjax && opts.initAjax.url ) { - // Init tree from AJAX request - isLazy = true; - root.data.isLazy = true; - this._reloadAjax(callback); - - } else if( opts.initId ) { - // Init tree from another UL element - this._createFromTag(root, $("#"+opts.initId)); - - } else { - // Init tree from the first UL element inside the container <div> -// var $ul = this.$tree.find(">ul:first").hide(); - this._createFromTag(root, $ulInitialize); - $ulInitialize.remove(); - } - - this._checkConsistency(); - // Fix part-sel flags - if(!isLazy && opts.selectMode == 3){ - root._updatePartSelectionState(); - } - // Render html markup - this.logDebug("Dynatree._load(): render nodes..."); - this.enableUpdate(prevFlag); - - // bind event handlers - this.logDebug("Dynatree._load(): bind events..."); - this.$widget.bind(); - - // --- Post-load processing - this.logDebug("Dynatree._load(): postInit..."); - this.phase = "postInit"; - - // In persist mode, make sure that cookies are written, even if they are empty - if( opts.persist ) { - this.persistence.write(); - } - // Set focus, if possible (this will also fire an event and write a cookie) - if( this.focusNode && this.focusNode.isVisible() ) { - this.logDebug("Focus on init: %o", this.focusNode); - this.focusNode.focus(); - } - if( !isLazy ) { - if( opts.onPostInit ) { - opts.onPostInit.call(this, isReloading, false); - } - if( callback ){ - callback.call(this, "ok"); - } - } - this.phase = "idle"; - }, - - _reloadAjax: function(callback) { - // Reload - var opts = this.options; - if( ! opts.initAjax || ! opts.initAjax.url ){ - throw "tree.reload() requires 'initAjax' mode."; - } - var pers = this.persistence; - var ajaxOpts = $.extend({}, opts.initAjax); - // Append cookie info to the request -// this.logDebug("reloadAjax: key=%o, an.key:%o", pers.activeKey, this.activeNode?this.activeNode.data.key:"?"); - if( ajaxOpts.addActiveKey ){ - ajaxOpts.data.activeKey = pers.activeKey; - } - if( ajaxOpts.addFocusedKey ){ - ajaxOpts.data.focusedKey = pers.focusedKey; - } - if( ajaxOpts.addExpandedKeyList ){ - ajaxOpts.data.expandedKeyList = pers.expandedKeyList.join(","); - } - if( ajaxOpts.addSelectedKeyList ){ - ajaxOpts.data.selectedKeyList = pers.selectedKeyList.join(","); - } - // Set up onPostInit callback to be called when Ajax returns - if( ajaxOpts.success ){ - this.logWarning("initAjax: success callback is ignored; use onPostInit instead."); - } - if( ajaxOpts.error ){ - this.logWarning("initAjax: error callback is ignored; use onPostInit instead."); - } - var isReloading = pers.isReloading(); - ajaxOpts.success = function(dtnode, data, textStatus) { - if(opts.selectMode == 3){ - dtnode.tree.tnRoot._updatePartSelectionState(); - } - if(opts.onPostInit){ - opts.onPostInit.call(dtnode.tree, isReloading, false); - } - if(callback){ - callback.call(dtnode.tree, "ok"); - } - }; - ajaxOpts.error = function(dtnode, XMLHttpRequest, textStatus, errorThrown) { - if(opts.onPostInit){ - opts.onPostInit.call(dtnode.tree, isReloading, true, XMLHttpRequest, textStatus, errorThrown); - } - if(callback){ - callback.call(dtnode.tree, "error", XMLHttpRequest, textStatus, errorThrown); - } - }; -// } - this.logDebug("Dynatree._init(): send Ajax request..."); - this.tnRoot.appendAjax(ajaxOpts); - }, - - toString: function() { -// return "DynaTree '" + this.options.title + "'"; - return "Dynatree '" + this.$tree.attr("id") + "'"; - }, - - toDict: function() { - return this.tnRoot.toDict(true); - }, - - serializeArray: function(stopOnParents) { - // Return a JavaScript array of objects, ready to be encoded as a JSON - // string for selected nodes - var nodeList = this.getSelectedNodes(stopOnParents), - name = this.$tree.attr("name") || this.$tree.attr("id"), - arr = []; - for(var i=0, l=nodeList.length; i<l; i++){ - arr.push({name: name, value: nodeList[i].data.key}); - } - return arr; - }, - - getPersistData: function() { - return this.persistence.toDict(); - }, - - logDebug: function(msg) { - if( this.options.debugLevel >= 2 ) { - Array.prototype.unshift.apply(arguments, ["debug"]); - _log.apply(this, arguments); - } - }, - - logInfo: function(msg) { - if( this.options.debugLevel >= 1 ) { - Array.prototype.unshift.apply(arguments, ["info"]); - _log.apply(this, arguments); - } - }, - - logWarning: function(msg) { - Array.prototype.unshift.apply(arguments, ["warn"]); - _log.apply(this, arguments); - }, - - isInitializing: function() { - return ( this.phase=="init" || this.phase=="postInit" ); - }, - isReloading: function() { - return ( this.phase=="init" || this.phase=="postInit" ) && this.options.persist && this.persistence.cookiesFound; - }, - isUserEvent: function() { - return ( this.phase=="userEvent" ); - }, - - redraw: function() { -// this.logDebug("dynatree.redraw()..."); - this.tnRoot.render(false, false); -// this.logDebug("dynatree.redraw() done."); - }, - renderInvisibleNodes: function() { - this.tnRoot.render(false, true); - }, - reload: function(callback) { - this._load(callback); - }, - - getRoot: function() { - return this.tnRoot; - }, - - enable: function() { - this.$widget.enable(); - }, - - disable: function() { - this.$widget.disable(); - }, - - getNodeByKey: function(key) { - // Search the DOM by element ID (assuming this is faster than traversing all nodes). - // $("#...") has problems, if the key contains '.', so we use getElementById() - var el = document.getElementById(this.options.idPrefix + key); - if( el ){ - return el.dtnode ? el.dtnode : null; - } - // Not found in the DOM, but still may be in an unrendered part of tree - var match = null; - this.visit(function(node){ -// window.console.log("%s", node); - if(node.data.key === key) { - match = node; - return false; - } - }, true); - return match; - }, - - getActiveNode: function() { - return this.activeNode; - }, - - reactivate: function(setFocus) { - // Re-fire onQueryActivate and onActivate events. - var node = this.activeNode; -// this.logDebug("reactivate %o", node); - if( node ) { - this.activeNode = null; // Force re-activating - node.activate(); - if( setFocus ){ - node.focus(); - } - } - }, - - getSelectedNodes: function(stopOnParents) { - var nodeList = []; - this.tnRoot.visit(function(node){ - if( node.bSelected ) { - nodeList.push(node); - if( stopOnParents === true ){ - return "skip"; // stop processing this branch - } - } - }); - return nodeList; - }, - - activateKey: function(key) { - var dtnode = (key === null) ? null : this.getNodeByKey(key); - if( !dtnode ) { - if( this.activeNode ){ - this.activeNode.deactivate(); - } - this.activeNode = null; - return null; - } - dtnode.focus(); - dtnode.activate(); - return dtnode; - }, - - loadKeyPath: function(keyPath, callback) { - var segList = keyPath.split(this.options.keyPathSeparator); - // Remove leading '/' - if(segList[0] === ""){ - segList.shift(); - } - // Remove leading system root key - if(segList[0] == this.tnRoot.data.key){ - this.logDebug("Removed leading root key."); - segList.shift(); - } - keyPath = segList.join(this.options.keyPathSeparator); - return this.tnRoot._loadKeyPath(keyPath, callback); - }, - - selectKey: function(key, select) { - var dtnode = this.getNodeByKey(key); - if( !dtnode ){ - return null; - } - dtnode.select(select); - return dtnode; - }, - - enableUpdate: function(bEnable) { - if ( this.bEnableUpdate==bEnable ){ - return bEnable; - } - this.bEnableUpdate = bEnable; - if ( bEnable ){ - this.redraw(); - } - return !bEnable; // return previous value - }, - - count: function() { - return this.tnRoot.countChildren(); - }, - - visit: function(fn, includeRoot) { - return this.tnRoot.visit(fn, includeRoot); - }, - - _createFromTag: function(parentTreeNode, $ulParent) { - // Convert a <UL>...</UL> list into children of the parent tree node. - var self = this; -/* -TODO: better? - this.$lis = $("li:has(a[href])", this.element); - this.$tabs = this.$lis.map(function() { return $("a", this)[0]; }); - */ - $ulParent.find(">li").each(function() { - var $li = $(this), - $liSpan = $li.find(">span:first"), - $liA = $li.find(">a:first"), - title, - href = null, - target = null, - tooltip; - if( $liSpan.length ) { - // If a <li><span> tag is specified, use it literally. - title = $liSpan.html(); - } else if( $liA.length ) { - title = $liA.html(); - href = $liA.attr("href"); - target = $liA.attr("target"); - tooltip = $liA.attr("title"); - } else { - // If only a <li> tag is specified, use the trimmed string up to - // the next child <ul> tag. - title = $li.html(); - var iPos = title.search(/<ul/i); - if( iPos >= 0 ){ - title = $.trim(title.substring(0, iPos)); - }else{ - title = $.trim(title); - } -// self.logDebug("%o", title); - } - // Parse node options from ID, title and class attributes - var data = { - title: title, - tooltip: tooltip, - isFolder: $li.hasClass("folder"), - isLazy: $li.hasClass("lazy"), - expand: $li.hasClass("expanded"), - select: $li.hasClass("selected"), - activate: $li.hasClass("active"), - focus: $li.hasClass("focused"), - noLink: $li.hasClass("noLink") - }; - if( href ){ - data.href = href; - data.target = target; - } - if( $li.attr("title") ){ - data.tooltip = $li.attr("title"); // overrides <a title='...'> - } - if( $li.attr("id") ){ - data.key = "" + $li.attr("id"); - } - // If a data attribute is present, evaluate as a JavaScript object - if( $li.attr("data") ) { - var dataAttr = $.trim($li.attr("data")); - if( dataAttr ) { - if( dataAttr.charAt(0) != "{" ){ - dataAttr = "{" + dataAttr + "}"; - } - try { - $.extend(data, eval("(" + dataAttr + ")")); - } catch(e) { - throw ("Error parsing node data: " + e + "\ndata:\n'" + dataAttr + "'"); - } - } - } - var childNode = parentTreeNode.addChild(data); - // Recursive reading of child nodes, if LI tag contains an UL tag - var $ul = $li.find(">ul:first"); - if( $ul.length ) { - self._createFromTag(childNode, $ul); // must use 'self', because 'this' is the each() context - } - }); - }, - - _checkConsistency: function() { -// this.logDebug("tree._checkConsistency() NOT IMPLEMENTED - %o", this); - }, - - _setDndStatus: function(sourceNode, targetNode, helper, hitMode, accept) { - // hitMode: 'after', 'before', 'over', 'out', 'start', 'stop' - var $source = sourceNode ? $(sourceNode.span) : null, - $target = $(targetNode.span); - if( !this.$dndMarker ) { - this.$dndMarker = $("<div id='dynatree-drop-marker'></div>") - .hide() - .css({"z-index": 1000}) - .prependTo($(this.divTree).parent()); - -// logMsg("Creating marker: %o", this.$dndMarker); - } -/* - if(hitMode === "start"){ - } - if(hitMode === "stop"){ -// sourceNode.removeClass("dynatree-drop-target"); - } -*/ - if(hitMode === "after" || hitMode === "before" || hitMode === "over"){ -// $source && $source.addClass("dynatree-drag-source"); -// $target.addClass("dynatree-drop-target"); - - var markerOffset = "0 0"; - - switch(hitMode){ - case "before": - this.$dndMarker.removeClass("dynatree-drop-after dynatree-drop-over"); - this.$dndMarker.addClass("dynatree-drop-before"); - markerOffset = "0 -8"; - break; - case "after": - this.$dndMarker.removeClass("dynatree-drop-before dynatree-drop-over"); - this.$dndMarker.addClass("dynatree-drop-after"); - markerOffset = "0 8"; - break; - default: - this.$dndMarker.removeClass("dynatree-drop-after dynatree-drop-before"); - this.$dndMarker.addClass("dynatree-drop-over"); - $target.addClass("dynatree-drop-target"); - markerOffset = "8 0"; - } -// logMsg("Creating marker: %o", this.$dndMarker); -// logMsg(" $target.offset=%o", $target); -// logMsg(" pos/$target.offset=%o", pos); -// logMsg(" $target.position=%o", $target.position()); -// logMsg(" $target.offsetParent=%o, ot:%o", $target.offsetParent(), $target.offsetParent().offset()); -// logMsg(" $(this.divTree).offset=%o", $(this.divTree).offset()); -// logMsg(" $(this.divTree).parent=%o", $(this.divTree).parent()); -// var pos = $target.offset(); -// var parentPos = $target.offsetParent().offset(); -// var bodyPos = $target.offsetParent().offset(); - - this.$dndMarker - .show() - .position({ - my: "left top", - at: "left top", - of: $target, - offset: markerOffset - }); - -// helper.addClass("dynatree-drop-hover"); - } else { -// $source && $source.removeClass("dynatree-drag-source"); - $target.removeClass("dynatree-drop-target"); - this.$dndMarker.hide(); -// helper.removeClass("dynatree-drop-hover"); - } - if(hitMode === "after"){ - $target.addClass("dynatree-drop-after"); - } else { - $target.removeClass("dynatree-drop-after"); - } - if(hitMode === "before"){ - $target.addClass("dynatree-drop-before"); - } else { - $target.removeClass("dynatree-drop-before"); - } - if(accept === true){ - if($source){ - $source.addClass("dynatree-drop-accept"); - } - $target.addClass("dynatree-drop-accept"); - helper.addClass("dynatree-drop-accept"); - }else{ - if($source){ - $source.removeClass("dynatree-drop-accept"); - } - $target.removeClass("dynatree-drop-accept"); - helper.removeClass("dynatree-drop-accept"); - } - if(accept === false){ - if($source){ - $source.addClass("dynatree-drop-reject"); - } - $target.addClass("dynatree-drop-reject"); - helper.addClass("dynatree-drop-reject"); - }else{ - if($source){ - $source.removeClass("dynatree-drop-reject"); - } - $target.removeClass("dynatree-drop-reject"); - helper.removeClass("dynatree-drop-reject"); - } - }, - - _onDragEvent: function(eventName, node, otherNode, event, ui, draggable) { - /** - * Handles drag'n'drop functionality. - * - * A standard jQuery drag-and-drop process may generate these calls: - * - * draggable helper(): - * _onDragEvent("helper", sourceNode, null, event, null, null); - * start: - * _onDragEvent("start", sourceNode, null, event, ui, draggable); - * drag: - * _onDragEvent("leave", prevTargetNode, sourceNode, event, ui, draggable); - * _onDragEvent("over", targetNode, sourceNode, event, ui, draggable); - * _onDragEvent("enter", targetNode, sourceNode, event, ui, draggable); - * stop: - * _onDragEvent("drop", targetNode, sourceNode, event, ui, draggable); - * _onDragEvent("leave", targetNode, sourceNode, event, ui, draggable); - * _onDragEvent("stop", sourceNode, null, event, ui, draggable); - */ -// if(eventName !== "over"){ -// this.logDebug("tree._onDragEvent(%s, %o, %o) - %o", eventName, node, otherNode, this); -// } - var opts = this.options, - dnd = this.options.dnd, - res = null, - nodeTag = $(node.span), - hitMode, - enterResponse; - - switch (eventName) { - case "helper": - // Only event and node argument is available - var $helper = $("<div class='dynatree-drag-helper'><span class='dynatree-drag-helper-img' /></div>") - .append($(event.target).closest(".dynatree-title").clone()); -// .append($(event.target).closest('a').clone()); - // issue 244: helper should be child of scrollParent - $("ul.dynatree-container", node.tree.divTree).append($helper); -// $(node.tree.divTree).append($helper); - // Attach node reference to helper object - $helper.data("dtSourceNode", node); -// this.logDebug("helper=%o", $helper); -// this.logDebug("helper.sourceNode=%o", $helper.data("dtSourceNode")); - res = $helper; - break; - case "start": - if(node.isStatusNode()) { - res = false; - } else if(dnd.onDragStart) { - res = dnd.onDragStart(node); - } - if(res === false) { - this.logDebug("tree.onDragStart() cancelled"); - //draggable._clear(); - // NOTE: the return value seems to be ignored (drag is not canceled, when false is returned) - ui.helper.trigger("mouseup"); - ui.helper.hide(); - } else { - nodeTag.addClass("dynatree-drag-source"); - } - break; - case "enter": - res = dnd.onDragEnter ? dnd.onDragEnter(node, otherNode) : null; - if(!res){ - // convert null, undefined, false to false - res = false; - }else{ - res = { - over: ((res === true) || (res === "over") || $.inArray("over", res) >= 0), - before: ((res === true) || (res === "before") || $.inArray("before", res) >= 0), - after: ((res === true) || (res === "after") || $.inArray("after", res) >= 0) - }; - } - ui.helper.data("enterResponse", res); -// this.logDebug("helper.enterResponse: %o", res); - break; - case "over": - enterResponse = ui.helper.data("enterResponse"); - hitMode = null; - if(enterResponse === false){ - // Don't call onDragOver if onEnter returned false. - // issue 332 -// break; - } else if(typeof enterResponse === "string") { - // Use hitMode from onEnter if provided. - hitMode = enterResponse; - } else { - // Calculate hitMode from relative cursor position. - var nodeOfs = nodeTag.offset(); -// var relPos = { x: event.clientX - nodeOfs.left, -// y: event.clientY - nodeOfs.top }; -// nodeOfs.top += this.parentTop; -// nodeOfs.left += this.parentLeft; - var relPos = { x: event.pageX - nodeOfs.left, - y: event.pageY - nodeOfs.top }; - var relPos2 = { x: relPos.x / nodeTag.width(), - y: relPos.y / nodeTag.height() }; -// this.logDebug("event.page: %s/%s", event.pageX, event.pageY); -// this.logDebug("event.client: %s/%s", event.clientX, event.clientY); -// this.logDebug("nodeOfs: %s/%s", nodeOfs.left, nodeOfs.top); -//// this.logDebug("parent: %s/%s", this.parentLeft, this.parentTop); -// this.logDebug("relPos: %s/%s", relPos.x, relPos.y); -// this.logDebug("relPos2: %s/%s", relPos2.x, relPos2.y); - if( enterResponse.after && relPos2.y > 0.75 ){ - hitMode = "after"; - } else if(!enterResponse.over && enterResponse.after && relPos2.y > 0.5 ){ - hitMode = "after"; - } else if(enterResponse.before && relPos2.y <= 0.25) { - hitMode = "before"; - } else if(!enterResponse.over && enterResponse.before && relPos2.y <= 0.5) { - hitMode = "before"; - } else if(enterResponse.over) { - hitMode = "over"; - } - // Prevent no-ops like 'before source node' - // TODO: these are no-ops when moving nodes, but not in copy mode - if( dnd.preventVoidMoves ){ - if(node === otherNode){ -// this.logDebug(" drop over source node prevented"); - hitMode = null; - }else if(hitMode === "before" && otherNode && node === otherNode.getNextSibling()){ -// this.logDebug(" drop after source node prevented"); - hitMode = null; - }else if(hitMode === "after" && otherNode && node === otherNode.getPrevSibling()){ -// this.logDebug(" drop before source node prevented"); - hitMode = null; - }else if(hitMode === "over" && otherNode && otherNode.parent === node && otherNode.isLastSibling() ){ -// this.logDebug(" drop last child over own parent prevented"); - hitMode = null; - } - } -// this.logDebug("hitMode: %s - %s - %s", hitMode, (node.parent === otherNode), node.isLastSibling()); - ui.helper.data("hitMode", hitMode); - } - // Auto-expand node (only when 'over' the node, not 'before', or 'after') - if(hitMode === "over" && dnd.autoExpandMS && node.hasChildren() !== false && !node.bExpanded) { - node.scheduleAction("expand", dnd.autoExpandMS); - } - if(hitMode && dnd.onDragOver){ - res = dnd.onDragOver(node, otherNode, hitMode); - if(res === "over" || res === "before" || res === "after") { - hitMode = res; - } - } - // issue 332 -// this._setDndStatus(otherNode, node, ui.helper, hitMode, res!==false); - this._setDndStatus(otherNode, node, ui.helper, hitMode, res!==false && hitMode !== null); - break; - case "drop": - // issue 286: don't trigger onDrop, if DnD status is 'reject' - var isForbidden = ui.helper.hasClass("dynatree-drop-reject"); - hitMode = ui.helper.data("hitMode"); - if(hitMode && dnd.onDrop && !isForbidden){ - dnd.onDrop(node, otherNode, hitMode, ui, draggable); - } - break; - case "leave": - // Cancel pending expand request - node.scheduleAction("cancel"); - ui.helper.data("enterResponse", null); - ui.helper.data("hitMode", null); - this._setDndStatus(otherNode, node, ui.helper, "out", undefined); - if(dnd.onDragLeave){ - dnd.onDragLeave(node, otherNode); - } - break; - case "stop": - nodeTag.removeClass("dynatree-drag-source"); - if(dnd.onDragStop){ - dnd.onDragStop(node); - } - break; - default: - throw "Unsupported drag event: " + eventName; - } - return res; - }, - - cancelDrag: function() { - var dd = $.ui.ddmanager.current; - if(dd){ - dd.cancel(); - } - }, - - // --- end of class - lastentry: undefined -}; - -/************************************************************************* - * Widget $(..).dynatree - */ - -$.widget("ui.dynatree", { -/* - init: function() { - // ui.core 1.6 renamed init() to _init(): this stub assures backward compatibility - _log("warn", "ui.dynatree.init() was called; you should upgrade to jquery.ui.core.js v1.8 or higher."); - return this._init(); - }, - */ - _init: function() { -// if( parseFloat($.ui.version) < 1.8 ) { - if(versionCompare($.ui.version, "1.8") < 0){ - // jquery.ui.core 1.8 renamed _init() to _create(): this stub assures backward compatibility - if(this.options.debugLevel >= 0){ - _log("warn", "ui.dynatree._init() was called; you should upgrade to jquery.ui.core.js v1.8 or higher."); - } - return this._create(); - } - // jquery.ui.core 1.8 still uses _init() to perform "default functionality" - if(this.options.debugLevel >= 2){ - _log("debug", "ui.dynatree._init() was called; no current default functionality."); - } - }, - - _create: function() { - var opts = this.options; - if(opts.debugLevel >= 1){ - logMsg("Dynatree._create(): version='%s', debugLevel=%o.", $.ui.dynatree.version, this.options.debugLevel); - } - // The widget framework supplies this.element and this.options. - this.options.event += ".dynatree"; // namespace event - - var divTree = this.element.get(0); -/* // Clear container, in case it contained some 'waiting' or 'error' text - // for clients that don't support JS - if( opts.children || (opts.initAjax && opts.initAjax.url) || opts.initId ) - $(divTree).empty(); -*/ - // Create the DynaTree object - this.tree = new DynaTree(this); - this.tree._load(); - this.tree.logDebug("Dynatree._init(): done."); - }, - - bind: function() { - // Prevent duplicate binding - this.unbind(); - - var eventNames = "click.dynatree dblclick.dynatree"; - if( this.options.keyboard ){ - // Note: leading ' '! - eventNames += " keypress.dynatree keydown.dynatree"; - } - this.element.bind(eventNames, function(event){ - var dtnode = $.ui.dynatree.getNode(event.target); - if( !dtnode ){ - return true; // Allow bubbling of other events - } - var tree = dtnode.tree; - var o = tree.options; - tree.logDebug("event(%s): dtnode: %s", event.type, dtnode); - var prevPhase = tree.phase; - tree.phase = "userEvent"; - try { - switch(event.type) { - case "click": - return ( o.onClick && o.onClick.call(tree, dtnode, event)===false ) ? false : dtnode._onClick(event); - case "dblclick": - return ( o.onDblClick && o.onDblClick.call(tree, dtnode, event)===false ) ? false : dtnode._onDblClick(event); - case "keydown": - return ( o.onKeydown && o.onKeydown.call(tree, dtnode, event)===false ) ? false : dtnode._onKeydown(event); - case "keypress": - return ( o.onKeypress && o.onKeypress.call(tree, dtnode, event)===false ) ? false : dtnode._onKeypress(event); - } - } catch(e) { - var _ = null; // issue 117 - tree.logWarning("bind(%o): dtnode: %o, error: %o", event, dtnode, e); - } finally { - tree.phase = prevPhase; - } - }); - - // focus/blur don't bubble, i.e. are not delegated to parent <div> tags, - // so we use the addEventListener capturing phase. - // See http://www.howtocreate.co.uk/tutorials/javascript/domevents - function __focusHandler(event) { - // Handles blur and focus. - // Fix event for IE: - // doesn't pass JSLint: -// event = arguments[0] = $.event.fix( event || window.event ); - // what jQuery does: -// var args = jQuery.makeArray( arguments ); -// event = args[0] = jQuery.event.fix( event || window.event ); - event = $.event.fix( event || window.event ); - var dtnode = $.ui.dynatree.getNode(event.target); - return dtnode ? dtnode._onFocus(event) : false; - } - var div = this.tree.divTree; - - if( div.addEventListener ) { - div.addEventListener("focus", __focusHandler, true); - div.addEventListener("blur", __focusHandler, true); - } else { - div.onfocusin = div.onfocusout = __focusHandler; - } - // EVENTS - // disable click if event is configured to something else -// if (!(/^click/).test(o.event)) -// this.$tabs.bind("click.tabs", function() { return false; }); - - }, - - unbind: function() { - this.element.unbind(".dynatree"); - }, - -/* TODO: we could handle option changes during runtime here (maybe to re-render, ...) - setData: function(key, value) { - this.tree.logDebug("dynatree.setData('" + key + "', '" + value + "')"); - }, -*/ - enable: function() { - this.bind(); - // Call default disable(): remove -disabled from css: - $.Widget.prototype.enable.apply(this, arguments); - }, - - disable: function() { - this.unbind(); - // Call default disable(): add -disabled to css: - $.Widget.prototype.disable.apply(this, arguments); - }, - - // --- getter methods (i.e. NOT returning a reference to $) - getTree: function() { - return this.tree; - }, - - getRoot: function() { - return this.tree.getRoot(); - }, - - getActiveNode: function() { - return this.tree.getActiveNode(); - }, - - getSelectedNodes: function() { - return this.tree.getSelectedNodes(); - }, - - // ------------------------------------------------------------------------ - lastentry: undefined -}); - - -// The following methods return a value (thus breaking the jQuery call chain): -if(versionCompare($.ui.version, "1.8") < 0){ -//if( parseFloat($.ui.version) < 1.8 ) { - $.ui.dynatree.getter = "getTree getRoot getActiveNode getSelectedNodes"; -} - -/******************************************************************************* - * Tools in ui.dynatree namespace - */ -$.ui.dynatree.version = "$Version: 1.2.4$"; - -/** - * Return a DynaTreeNode object for a given DOM element - */ -$.ui.dynatree.getNode = function(el) { - if(el instanceof DynaTreeNode){ - return el; // el already was a DynaTreeNode - } - if(el.selector !== undefined){ - el = el[0]; // el was a jQuery object: use the DOM element - } - // TODO: for some reason $el.parents("[dtnode]") does not work (jQuery 1.6.1) - // maybe, because dtnode is a property, not an attribute - while( el ) { - if(el.dtnode) { - return el.dtnode; - } - el = el.parentNode; - } - return null; -/* - var $el = el.selector === undefined ? $(el) : el, -// parent = $el.closest("[dtnode]"), -// parent = $el.parents("[dtnode]").first(), - useProp = (typeof $el.prop == "function"), - node; - $el.parents().each(function(){ - node = useProp ? $(this).prop("dtnode") : $(this).attr("dtnode"); - if(node){ - return false; - } - }); - return node; -*/ -}; - -/**Return persistence information from cookies.*/ -$.ui.dynatree.getPersistData = DynaTreeStatus._getTreePersistData; - -/******************************************************************************* - * Plugin default options: - */ -$.ui.dynatree.prototype.options = { - title: "Dynatree", // Tree's name (only used for debug output) - minExpandLevel: 1, // 1: root node is not collapsible - imagePath: null, // Path to a folder containing icons. Defaults to 'skin/' subdirectory. - children: null, // Init tree structure from this object array. - initId: null, // Init tree structure from a <ul> element with this ID. - initAjax: null, // Ajax options used to initialize the tree strucuture. - autoFocus: true, // Set focus to first child, when expanding or lazy-loading. - keyboard: true, // Support keyboard navigation. - persist: false, // Persist expand-status to a cookie - autoCollapse: false, // Automatically collapse all siblings, when a node is expanded. - clickFolderMode: 3, // 1:activate, 2:expand, 3:activate and expand - activeVisible: true, // Make sure, active nodes are visible (expanded). - checkbox: false, // Show checkboxes. - selectMode: 2, // 1:single, 2:multi, 3:multi-hier - fx: null, // Animations, e.g. null or { height: "toggle", duration: 200 } - noLink: false, // Use <span> instead of <a> tags for all nodes - // Low level event handlers: onEvent(dtnode, event): return false, to stop default processing - onClick: null, // null: generate focus, expand, activate, select events. - onDblClick: null, // (No default actions.) - onKeydown: null, // null: generate keyboard navigation (focus, expand, activate). - onKeypress: null, // (No default actions.) - onFocus: null, // null: set focus to node. - onBlur: null, // null: remove focus from node. - - // Pre-event handlers onQueryEvent(flag, dtnode): return false, to stop processing - onQueryActivate: null, // Callback(flag, dtnode) before a node is (de)activated. - onQuerySelect: null, // Callback(flag, dtnode) before a node is (de)selected. - onQueryExpand: null, // Callback(flag, dtnode) before a node is expanded/collpsed. - - // High level event handlers - onPostInit: null, // Callback(isReloading, isError) when tree was (re)loaded. - onActivate: null, // Callback(dtnode) when a node is activated. - onDeactivate: null, // Callback(dtnode) when a node is deactivated. - onSelect: null, // Callback(flag, dtnode) when a node is (de)selected. - onExpand: null, // Callback(flag, dtnode) when a node is expanded/collapsed. - onLazyRead: null, // Callback(dtnode) when a lazy node is expanded for the first time. - onCustomRender: null, // Callback(dtnode) before a node is rendered. Return a HTML string to override. - onCreate: null, // Callback(dtnode, nodeSpan) after a node was rendered for the first time. - onRender: null, // Callback(dtnode, nodeSpan) after a node was rendered. - // postProcess is similar to the standard dataFilter hook, - // but it is also called for JSONP - postProcess: null, // Callback(data, dataType) before an Ajax result is passed to dynatree - - // Drag'n'drop support - dnd: { - // Make tree nodes draggable: - onDragStart: null, // Callback(sourceNode), return true, to enable dnd - onDragStop: null, // Callback(sourceNode) -// helper: null, - // Make tree nodes accept draggables - autoExpandMS: 1000, // Expand nodes after n milliseconds of hovering. - preventVoidMoves: true, // Prevent dropping nodes 'before self', etc. - onDragEnter: null, // Callback(targetNode, sourceNode) - onDragOver: null, // Callback(targetNode, sourceNode, hitMode) - onDrop: null, // Callback(targetNode, sourceNode, hitMode) - onDragLeave: null // Callback(targetNode, sourceNode) - }, - ajaxDefaults: { // Used by initAjax option - cache: false, // false: Append random '_' argument to the request url to prevent caching. - timeout: 0, // >0: Make sure we get an ajax error for invalid URLs - dataType: "json" // Expect json format and pass json object to callbacks. - }, - strings: { - loading: "Loading…", - loadError: "Load error!" - }, - generateIds: false, // Generate id attributes like <span id='dynatree-id-KEY'> - idPrefix: "dynatree-id-", // Used to generate node id's like <span id="dynatree-id-<key>">. - keyPathSeparator: "/", // Used by node.getKeyPath() and tree.loadKeyPath(). -// cookieId: "dynatree-cookie", // Choose a more unique name, to allow multiple trees. - cookieId: "dynatree", // Choose a more unique name, to allow multiple trees. - cookie: { - expires: null //7, // Days or Date; null: session cookie -// path: "/", // Defaults to current page -// domain: "jquery.com", -// secure: true - }, - // Class names used, when rendering the HTML markup. - // Note: if only single entries are passed for options.classNames, all other - // values are still set to default. - classNames: { - container: "dynatree-container", - node: "dynatree-node", - folder: "dynatree-folder", -// document: "dynatree-document", - - empty: "dynatree-empty", - vline: "dynatree-vline", - expander: "dynatree-expander", - connector: "dynatree-connector", - checkbox: "dynatree-checkbox", - nodeIcon: "dynatree-icon", - title: "dynatree-title", - noConnector: "dynatree-no-connector", - - nodeError: "dynatree-statusnode-error", - nodeWait: "dynatree-statusnode-wait", - hidden: "dynatree-hidden", - combinedExpanderPrefix: "dynatree-exp-", - combinedIconPrefix: "dynatree-ico-", - nodeLoading: "dynatree-loading", -// disabled: "dynatree-disabled", - hasChildren: "dynatree-has-children", - active: "dynatree-active", - selected: "dynatree-selected", - expanded: "dynatree-expanded", - lazy: "dynatree-lazy", - focused: "dynatree-focused", - partsel: "dynatree-partsel", - lastsib: "dynatree-lastsib" - }, - debugLevel: 1, - - // ------------------------------------------------------------------------ - lastentry: undefined -}; -// -if(versionCompare($.ui.version, "1.8") < 0){ -//if( parseFloat($.ui.version) < 1.8 ) { - $.ui.dynatree.defaults = $.ui.dynatree.prototype.options; -} - -/******************************************************************************* - * Reserved data attributes for a tree node. - */ -$.ui.dynatree.nodedatadefaults = { - title: null, // (required) Displayed name of the node (html is allowed here) - key: null, // May be used with activate(), select(), find(), ... - isFolder: false, // Use a folder icon. Also the node is expandable but not selectable. - isLazy: false, // Call onLazyRead(), when the node is expanded for the first time to allow for delayed creation of children. - tooltip: null, // Show this popup text. - href: null, // Added to the generated <a> tag. - icon: null, // Use a custom image (filename relative to tree.options.imagePath). 'null' for default icon, 'false' for no icon. - addClass: null, // Class name added to the node's span tag. - noLink: false, // Use <span> instead of <a> tag for this node - activate: false, // Initial active status. - focus: false, // Initial focused status. - expand: false, // Initial expanded status. - select: false, // Initial selected status. - hideCheckbox: false, // Suppress checkbox display for this node. - unselectable: false, // Prevent selection. -// disabled: false, - // The following attributes are only valid if passed to some functions: - children: null, // Array of child nodes. - // NOTE: we can also add custom attributes here. - // This may then also be used in the onActivate(), onSelect() or onLazyTree() callbacks. - // ------------------------------------------------------------------------ - lastentry: undefined -}; - -/******************************************************************************* - * Drag and drop support - */ -function _initDragAndDrop(tree) { - var dnd = tree.options.dnd || null; - // Register 'connectToDynatree' option with ui.draggable - if(dnd && (dnd.onDragStart || dnd.onDrop)) { - _registerDnd(); - } - // Attach ui.draggable to this Dynatree instance - if(dnd && dnd.onDragStart ) { - tree.$tree.draggable({ - addClasses: false, - appendTo: "body", - containment: false, - delay: 0, - distance: 4, - revert: false, - scroll: true, // issue 244: enable scrolling (if ul.dynatree-container) - scrollSpeed: 7, - scrollSensitivity: 10, - // Delegate draggable.start, drag, and stop events to our handler - connectToDynatree: true, - // Let source tree create the helper element - helper: function(event) { - var sourceNode = $.ui.dynatree.getNode(event.target); - if(!sourceNode){ // issue 211 - return "<div></div>"; - } - return sourceNode.tree._onDragEvent("helper", sourceNode, null, event, null, null); - }, - start: function(event, ui) { - // See issues 211, 268, 278 -// var sourceNode = $.ui.dynatree.getNode(event.target); - var sourceNode = ui.helper.data("dtSourceNode"); - return !!sourceNode; // Abort dragging if no Node could be found - }, - _last: null - }); - } - // Attach ui.droppable to this Dynatree instance - if(dnd && dnd.onDrop) { - tree.$tree.droppable({ - addClasses: false, - tolerance: "intersect", - greedy: false, - _last: null - }); - } -} - -//--- Extend ui.draggable event handling -------------------------------------- -var didRegisterDnd = false; -var _registerDnd = function() { - if(didRegisterDnd){ - return; - } - // Register proxy-functions for draggable.start/drag/stop - $.ui.plugin.add("draggable", "connectToDynatree", { - start: function(event, ui) { - // issue 386 - var draggable = $(this).data("ui-draggable") || $(this).data("draggable"), - sourceNode = ui.helper.data("dtSourceNode") || null; -// logMsg("draggable-connectToDynatree.start, %s", sourceNode); -// logMsg(" this: %o", this); -// logMsg(" event: %o", event); -// logMsg(" draggable: %o", draggable); -// logMsg(" ui: %o", ui); - - if(sourceNode) { - // Adjust helper offset, so cursor is slightly outside top/left corner -// draggable.offset.click.top -= event.target.offsetTop; -// draggable.offset.click.left -= event.target.offsetLeft; - draggable.offset.click.top = -2; - draggable.offset.click.left = + 16; -// logMsg(" draggable2: %o", draggable); -// logMsg(" draggable.offset.click FIXED: %s/%s", draggable.offset.click.left, draggable.offset.click.top); - // Trigger onDragStart event - // TODO: when called as connectTo..., the return value is ignored(?) - return sourceNode.tree._onDragEvent("start", sourceNode, null, event, ui, draggable); - } - }, - drag: function(event, ui) { - // issue 386 - var draggable = $(this).data("ui-draggable") || $(this).data("draggable"), - sourceNode = ui.helper.data("dtSourceNode") || null, - prevTargetNode = ui.helper.data("dtTargetNode") || null, - targetNode = $.ui.dynatree.getNode(event.target); -// logMsg("$.ui.dynatree.getNode(%o): %s", event.target, targetNode); -// logMsg("connectToDynatree.drag: helper: %o", ui.helper[0]); - if(event.target && !targetNode){ - // We got a drag event, but the targetNode could not be found - // at the event location. This may happen, - // 1. if the mouse jumped over the drag helper, - // 2. or if non-dynatree element is dragged - // We ignore it: - var isHelper = $(event.target).closest("div.dynatree-drag-helper,#dynatree-drop-marker").length > 0; - if(isHelper){ -// logMsg("Drag event over helper: ignored."); - return; - } - } -// logMsg("draggable-connectToDynatree.drag: targetNode(from event): %s, dtTargetNode: %s", targetNode, ui.helper.data("dtTargetNode")); - ui.helper.data("dtTargetNode", targetNode); - // Leaving a tree node - if(prevTargetNode && prevTargetNode !== targetNode ) { - prevTargetNode.tree._onDragEvent("leave", prevTargetNode, sourceNode, event, ui, draggable); - } - if(targetNode){ - if(!targetNode.tree.options.dnd.onDrop) { - // not enabled as drop target -// noop(); // Keep JSLint happy - } else if(targetNode === prevTargetNode) { - // Moving over same node - targetNode.tree._onDragEvent("over", targetNode, sourceNode, event, ui, draggable); - }else{ - // Entering this node first time - targetNode.tree._onDragEvent("enter", targetNode, sourceNode, event, ui, draggable); - } - } - // else go ahead with standard event handling - }, - stop: function(event, ui) { - // issue 386 - var draggable = $(this).data("ui-draggable") || $(this).data("draggable"), - sourceNode = ui.helper.data("dtSourceNode") || null, - targetNode = ui.helper.data("dtTargetNode") || null, - mouseDownEvent = draggable._mouseDownEvent, - eventType = event.type, - dropped = (eventType == "mouseup" && event.which == 1); - logMsg("draggable-connectToDynatree.stop: targetNode(from event): %s, dtTargetNode: %s", targetNode, ui.helper.data("dtTargetNode")); -// logMsg("draggable-connectToDynatree.stop, %s", sourceNode); -// logMsg(" type: %o, downEvent: %o, upEvent: %o", eventType, mouseDownEvent, event); -// logMsg(" targetNode: %o", targetNode); - if(!dropped){ - logMsg("Drag was cancelled"); - } - if(targetNode) { - if(dropped){ - targetNode.tree._onDragEvent("drop", targetNode, sourceNode, event, ui, draggable); - } - targetNode.tree._onDragEvent("leave", targetNode, sourceNode, event, ui, draggable); - } - if(sourceNode){ - sourceNode.tree._onDragEvent("stop", sourceNode, null, event, ui, draggable); - } - } - }); - didRegisterDnd = true; -}; - -// --------------------------------------------------------------------------- -}(jQuery)); diff --git a/SemanticForms/libs/jquery.fancybox.js b/SemanticForms/libs/jquery.fancybox.js deleted file mode 100644 index 68d28659..00000000 --- a/SemanticForms/libs/jquery.fancybox.js +++ /dev/null @@ -1,1152 +0,0 @@ -/* - * FancyBox - jQuery Plugin - * Simple and fancy lightbox alternative - * - * Examples and documentation at: http://fancybox.net - * - * Copyright (c) 2008 - 2010 Janis Skarnelis - * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated. - * - * Version: 1.3.4 (11/11/2010) - * Requires: jQuery v1.3+ - * - * Dual licensed under the MIT and GPL licenses: - * http://www.opensource.org/licenses/mit-license.php - * http://www.gnu.org/licenses/gpl.html - */ - -;(function($) { - var tmp, loading, overlay, wrap, outer, content, close, title, nav_left, nav_right, - - selectedIndex = 0, selectedOpts = {}, selectedArray = [], currentIndex = 0, currentOpts = {}, currentArray = [], - - ajaxLoader = null, imgPreloader = new Image(), imgRegExp = /\.(jpg|gif|png|bmp|jpeg)(.*)?$/i, swfRegExp = /[^\.]\.(swf)\s*$/i, - - loadingTimer, loadingFrame = 1, - - titleHeight = 0, titleStr = '', start_pos, final_pos, busy = false, fx = $.extend($('<div/>')[0], { prop: 0 }), - - isIE6 = $.browser.msie && $.browser.version < 7 && !window.XMLHttpRequest, - - /* - * Private methods - */ - - _abort = function() { - loading.hide(); - - imgPreloader.onerror = imgPreloader.onload = null; - - if (ajaxLoader) { - ajaxLoader.abort(); - } - - tmp.empty(); - }, - - _error = function() { - if (false === selectedOpts.onError(selectedArray, selectedIndex, selectedOpts)) { - loading.hide(); - busy = false; - return; - } - - selectedOpts.titleShow = false; - - selectedOpts.width = 'auto'; - selectedOpts.height = 'auto'; - - tmp.html( '<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>' ); - - _process_inline(); - }, - - _start = function() { - var obj = selectedArray[ selectedIndex ], - href, - type, - title, - str, - emb, - ret; - - _abort(); - - selectedOpts = $.extend({}, $.fn.fancybox.defaults, (typeof $(obj).data('fancybox') == 'undefined' ? selectedOpts : $(obj).data('fancybox'))); - - ret = selectedOpts.onStart(selectedArray, selectedIndex, selectedOpts); - - if (ret === false) { - busy = false; - return; - } else if (typeof ret == 'object') { - selectedOpts = $.extend(selectedOpts, ret); - } - - title = selectedOpts.title || (obj.nodeName ? $(obj).attr('title') : obj.title) || ''; - - if (obj.nodeName && !selectedOpts.orig) { - selectedOpts.orig = $(obj).children("img:first").length ? $(obj).children("img:first") : $(obj); - } - - if (title === '' && selectedOpts.orig && selectedOpts.titleFromAlt) { - title = selectedOpts.orig.attr('alt'); - } - - href = selectedOpts.href || (obj.nodeName ? $(obj).attr('href') : obj.href) || null; - - if ((/^(?:javascript)/i).test(href) || href == '#') { - href = null; - } - - if (selectedOpts.type) { - type = selectedOpts.type; - - if (!href) { - href = selectedOpts.content; - } - - } else if (selectedOpts.content) { - type = 'html'; - - } else if (href) { - if (href.match(imgRegExp)) { - type = 'image'; - - } else if (href.match(swfRegExp)) { - type = 'swf'; - - } else if ($(obj).hasClass("iframe")) { - type = 'iframe'; - - } else if (href.indexOf("#") === 0) { - type = 'inline'; - - } else { - type = 'ajax'; - } - } - - if (!type) { - _error(); - return; - } - - if (type == 'inline') { - obj = href.substr(href.indexOf("#")); - type = $(obj).length > 0 ? 'inline' : 'ajax'; - } - - selectedOpts.type = type; - selectedOpts.href = href; - selectedOpts.title = title; - - if (selectedOpts.autoDimensions) { - if (selectedOpts.type == 'html' || selectedOpts.type == 'inline' || selectedOpts.type == 'ajax') { - selectedOpts.width = 'auto'; - selectedOpts.height = 'auto'; - } else { - selectedOpts.autoDimensions = false; - } - } - - if (selectedOpts.modal) { - selectedOpts.overlayShow = true; - selectedOpts.hideOnOverlayClick = false; - selectedOpts.hideOnContentClick = false; - selectedOpts.enableEscapeButton = false; - selectedOpts.showCloseButton = false; - } - - selectedOpts.padding = parseInt(selectedOpts.padding, 10); - selectedOpts.margin = parseInt(selectedOpts.margin, 10); - - tmp.css('padding', (selectedOpts.padding + selectedOpts.margin)); - - $('.fancybox-inline-tmp').unbind('fancybox-cancel').bind('fancybox-change', function() { - $(this).replaceWith(content.children()); - }); - - switch (type) { - case 'html' : - tmp.html( selectedOpts.content ); - _process_inline(); - break; - - case 'inline' : - if ( $(obj).parent().is('#fancybox-content') === true) { - busy = false; - return; - } - - $('<div class="fancybox-inline-tmp" />') - .hide() - .insertBefore( $(obj) ) - .bind('fancybox-cleanup', function() { - $(this).replaceWith(content.children()); - }).bind('fancybox-cancel', function() { - $(this).replaceWith(tmp.children()); - }); - - $(obj).appendTo(tmp); - - _process_inline(); - break; - - case 'image': - busy = false; - - $.fancybox.showActivity(); - - imgPreloader = new Image(); - - imgPreloader.onerror = function() { - _error(); - }; - - imgPreloader.onload = function() { - busy = true; - - imgPreloader.onerror = imgPreloader.onload = null; - - _process_image(); - }; - - imgPreloader.src = href; - break; - - case 'swf': - selectedOpts.scrolling = 'no'; - - str = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"><param name="movie" value="' + href + '"></param>'; - emb = ''; - - $.each(selectedOpts.swf, function(name, val) { - str += '<param name="' + name + '" value="' + val + '"></param>'; - emb += ' ' + name + '="' + val + '"'; - }); - - str += '<embed src="' + href + '" type="application/x-shockwave-flash" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"' + emb + '></embed></object>'; - - tmp.html(str); - - _process_inline(); - break; - - case 'ajax': - busy = false; - - $.fancybox.showActivity(); - - selectedOpts.ajax.win = selectedOpts.ajax.success; - - ajaxLoader = $.ajax($.extend({}, selectedOpts.ajax, { - url : href, - data : selectedOpts.ajax.data || {}, - error : function(XMLHttpRequest, textStatus, errorThrown) { - if ( XMLHttpRequest.status > 0 ) { - _error(); - } - }, - success : function(data, textStatus, XMLHttpRequest) { - var o = typeof XMLHttpRequest == 'object' ? XMLHttpRequest : ajaxLoader; - if (o.status == 200) { - if ( typeof selectedOpts.ajax.win == 'function' ) { - ret = selectedOpts.ajax.win(href, data, textStatus, XMLHttpRequest); - - if (ret === false) { - loading.hide(); - return; - } else if (typeof ret == 'string' || typeof ret == 'object') { - data = ret; - } - } - - tmp.html( data ); - _process_inline(); - } - } - })); - - break; - - case 'iframe': - _show(); - break; - } - }, - - _process_inline = function() { - var - w = selectedOpts.width, - h = selectedOpts.height; - - if (w.toString().indexOf('%') > -1) { - w = parseInt( ($(window).width() - (selectedOpts.margin * 2)) * parseFloat(w) / 100, 10) + 'px'; - - } else { - w = w == 'auto' ? 'auto' : w + 'px'; - } - - if (h.toString().indexOf('%') > -1) { - h = parseInt( ($(window).height() - (selectedOpts.margin * 2)) * parseFloat(h) / 100, 10) + 'px'; - - } else { - h = h == 'auto' ? 'auto' : h + 'px'; - } - - tmp.wrapInner('<div style="width:' + w + ';height:' + h + ';overflow: ' + (selectedOpts.scrolling == 'auto' ? 'auto' : (selectedOpts.scrolling == 'yes' ? 'scroll' : 'hidden')) + ';position:relative;"></div>'); - - selectedOpts.width = tmp.width(); - selectedOpts.height = tmp.height(); - - _show(); - }, - - _process_image = function() { - selectedOpts.width = imgPreloader.width; - selectedOpts.height = imgPreloader.height; - - $("<img />").attr({ - 'id' : 'fancybox-img', - 'src' : imgPreloader.src, - 'alt' : selectedOpts.title - }).appendTo( tmp ); - - _show(); - }, - - _show = function() { - var pos, equal; - - loading.hide(); - - if (wrap.is(":visible") && false === currentOpts.onCleanup(currentArray, currentIndex, currentOpts)) { - $.event.trigger('fancybox-cancel'); - - busy = false; - return; - } - - busy = true; - - $(content.add( overlay )).unbind(); - - $(window).unbind("resize.fb scroll.fb"); - $(document).unbind('keydown.fb'); - - if (wrap.is(":visible") && currentOpts.titlePosition !== 'outside') { - wrap.css('height', wrap.height()); - } - - currentArray = selectedArray; - currentIndex = selectedIndex; - currentOpts = selectedOpts; - - if (currentOpts.overlayShow) { - overlay.css({ - 'background-color' : currentOpts.overlayColor, - 'opacity' : currentOpts.overlayOpacity, - 'cursor' : currentOpts.hideOnOverlayClick ? 'pointer' : 'auto', - 'height' : $(document).height() - }); - - if (!overlay.is(':visible')) { - if (isIE6) { - $('select:not(#fancybox-tmp select)').filter(function() { - return this.style.visibility !== 'hidden'; - }).css({'visibility' : 'hidden'}).one('fancybox-cleanup', function() { - this.style.visibility = 'inherit'; - }); - } - - overlay.show(); - } - } else { - overlay.hide(); - } - - final_pos = _get_zoom_to(); - - _process_title(); - - if (wrap.is(":visible")) { - $( close.add( nav_left ).add( nav_right ) ).hide(); - - pos = wrap.position(); - - start_pos = { - top : pos.top, - left : pos.left, - width : wrap.width(), - height : wrap.height() - }; - - equal = (start_pos.width == final_pos.width && start_pos.height == final_pos.height); - - content.fadeTo(currentOpts.changeFade, 0.3, function() { - var finish_resizing = function() { - content.html( tmp.contents() ).fadeTo(currentOpts.changeFade, 1, _finish); - }; - - $.event.trigger('fancybox-change'); - - content - .empty() - .removeAttr('filter') - .css({ - 'border-width' : currentOpts.padding, - 'width' : final_pos.width - currentOpts.padding * 2, - 'height' : selectedOpts.autoDimensions ? 'auto' : final_pos.height - titleHeight - currentOpts.padding * 2 - }); - - if (equal) { - finish_resizing(); - - } else { - fx.prop = 0; - - $(fx).animate({prop: 1}, { - duration : currentOpts.changeSpeed, - easing : currentOpts.easingChange, - step : _draw, - complete : finish_resizing - }); - } - }); - - return; - } - - wrap.removeAttr("style"); - - content.css('border-width', currentOpts.padding); - - if (currentOpts.transitionIn == 'elastic') { - start_pos = _get_zoom_from(); - - content.html( tmp.contents() ); - - wrap.show(); - - if (currentOpts.opacity) { - final_pos.opacity = 0; - } - - fx.prop = 0; - - $(fx).animate({prop: 1}, { - duration : currentOpts.speedIn, - easing : currentOpts.easingIn, - step : _draw, - complete : _finish - }); - - return; - } - - if (currentOpts.titlePosition == 'inside' && titleHeight > 0) { - title.show(); - } - - content - .css({ - 'width' : final_pos.width - currentOpts.padding * 2, - 'height' : selectedOpts.autoDimensions ? 'auto' : final_pos.height - titleHeight - currentOpts.padding * 2 - }) - .html( tmp.contents() ); - - wrap - .css(final_pos) - .fadeIn( currentOpts.transitionIn == 'none' ? 0 : currentOpts.speedIn, _finish ); - }, - - _format_title = function(title) { - if (title && title.length) { - if (currentOpts.titlePosition == 'float') { - return '<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">' + title + '</td><td id="fancybox-title-float-right"></td></tr></table>'; - } - - return '<div id="fancybox-title-' + currentOpts.titlePosition + '">' + title + '</div>'; - } - - return false; - }, - - _process_title = function() { - titleStr = currentOpts.title || ''; - titleHeight = 0; - - title - .empty() - .removeAttr('style') - .removeClass(); - - if (currentOpts.titleShow === false) { - title.hide(); - return; - } - - titleStr = $.isFunction(currentOpts.titleFormat) ? currentOpts.titleFormat(titleStr, currentArray, currentIndex, currentOpts) : _format_title(titleStr); - - if (!titleStr || titleStr === '') { - title.hide(); - return; - } - - title - .addClass('fancybox-title-' + currentOpts.titlePosition) - .html( titleStr ) - .appendTo( 'body' ) - .show(); - - switch (currentOpts.titlePosition) { - case 'inside': - title - .css({ - 'width' : final_pos.width - (currentOpts.padding * 2), - 'marginLeft' : currentOpts.padding, - 'marginRight' : currentOpts.padding - }); - - titleHeight = title.outerHeight(true); - - title.appendTo( outer ); - - final_pos.height += titleHeight; - break; - - case 'over': - title - .css({ - 'marginLeft' : currentOpts.padding, - 'width' : final_pos.width - (currentOpts.padding * 2), - 'bottom' : currentOpts.padding - }) - .appendTo( outer ); - break; - - case 'float': - title - .css('left', parseInt((title.width() - final_pos.width - 40)/ 2, 10) * -1) - .appendTo( wrap ); - break; - - default: - title - .css({ - 'width' : final_pos.width - (currentOpts.padding * 2), - 'paddingLeft' : currentOpts.padding, - 'paddingRight' : currentOpts.padding - }) - .appendTo( wrap ); - break; - } - - title.hide(); - }, - - _set_navigation = function() { - if (currentOpts.enableEscapeButton || currentOpts.enableKeyboardNav) { - $(document).bind('keydown.fb', function(e) { - if (e.keyCode == 27 && currentOpts.enableEscapeButton) { - e.preventDefault(); - $.fancybox.close(); - - } else if ((e.keyCode == 37 || e.keyCode == 39) && currentOpts.enableKeyboardNav && e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA' && e.target.tagName !== 'SELECT') { - e.preventDefault(); - $.fancybox[ e.keyCode == 37 ? 'prev' : 'next'](); - } - }); - } - - if (!currentOpts.showNavArrows) { - nav_left.hide(); - nav_right.hide(); - return; - } - - if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex !== 0) { - nav_left.show(); - } - - if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex != (currentArray.length -1)) { - nav_right.show(); - } - }, - - _finish = function () { - if (!$.support.opacity) { - content.get(0).style.removeAttribute('filter'); - wrap.get(0).style.removeAttribute('filter'); - } - - if (selectedOpts.autoDimensions) { - content.css('height', 'auto'); - } - - wrap.css('height', 'auto'); - - if (titleStr && titleStr.length) { - title.show(); - } - - if (currentOpts.showCloseButton) { - close.show(); - } - - _set_navigation(); - - if (currentOpts.hideOnContentClick) { - content.bind('click', $.fancybox.close); - } - - if (currentOpts.hideOnOverlayClick) { - overlay.bind('click', $.fancybox.close); - } - - $(window).bind("resize.fb", $.fancybox.resize); - - if (currentOpts.centerOnScroll) { - $(window).bind("scroll.fb", $.fancybox.center); - } - - if (currentOpts.type == 'iframe') { - $('<iframe id="fancybox-frame" name="fancybox-frame' + new Date().getTime() + '" frameborder="0" hspace="0" ' + ($.browser.msie ? 'allowtransparency="true""' : '') + ' scrolling="' + selectedOpts.scrolling + '" src="' + currentOpts.href + '"></iframe>').appendTo(content); - } - - wrap.show(); - - busy = false; - - $.fancybox.center(); - - currentOpts.onComplete(currentArray, currentIndex, currentOpts); - - _preload_images(); - }, - - _preload_images = function() { - var href, - objNext; - - if ((currentArray.length -1) > currentIndex) { - href = currentArray[ currentIndex + 1 ].href; - - if (typeof href !== 'undefined' && href.match(imgRegExp)) { - objNext = new Image(); - objNext.src = href; - } - } - - if (currentIndex > 0) { - href = currentArray[ currentIndex - 1 ].href; - - if (typeof href !== 'undefined' && href.match(imgRegExp)) { - objNext = new Image(); - objNext.src = href; - } - } - }, - - _draw = function(pos) { - var dim = { - width : parseInt(start_pos.width + (final_pos.width - start_pos.width) * pos, 10), - height : parseInt(start_pos.height + (final_pos.height - start_pos.height) * pos, 10), - - top : parseInt(start_pos.top + (final_pos.top - start_pos.top) * pos, 10), - left : parseInt(start_pos.left + (final_pos.left - start_pos.left) * pos, 10) - }; - - if (typeof final_pos.opacity !== 'undefined') { - dim.opacity = pos < 0.5 ? 0.5 : pos; - } - - wrap.css(dim); - - content.css({ - 'width' : dim.width - currentOpts.padding * 2, - 'height' : dim.height - (titleHeight * pos) - currentOpts.padding * 2 - }); - }, - - _get_viewport = function() { - return [ - $(window).width() - (currentOpts.margin * 2), - $(window).height() - (currentOpts.margin * 2), - $(document).scrollLeft() + currentOpts.margin, - $(document).scrollTop() + currentOpts.margin - ]; - }, - - _get_zoom_to = function () { - var view = _get_viewport(), - to = {}, - resize = currentOpts.autoScale, - double_padding = currentOpts.padding * 2, - ratio; - - if (currentOpts.width.toString().indexOf('%') > -1) { - to.width = parseInt((view[0] * parseFloat(currentOpts.width)) / 100, 10); - } else { - to.width = currentOpts.width + double_padding; - } - - if (currentOpts.height.toString().indexOf('%') > -1) { - to.height = parseInt((view[1] * parseFloat(currentOpts.height)) / 100, 10); - } else { - to.height = currentOpts.height + double_padding; - } - - if (resize && (to.width > view[0] || to.height > view[1])) { - if (selectedOpts.type == 'image' || selectedOpts.type == 'swf') { - ratio = (currentOpts.width ) / (currentOpts.height ); - - if ((to.width ) > view[0]) { - to.width = view[0]; - to.height = parseInt(((to.width - double_padding) / ratio) + double_padding, 10); - } - - if ((to.height) > view[1]) { - to.height = view[1]; - to.width = parseInt(((to.height - double_padding) * ratio) + double_padding, 10); - } - - } else { - to.width = Math.min(to.width, view[0]); - to.height = Math.min(to.height, view[1]); - } - } - - to.top = parseInt(Math.max(view[3] - 20, view[3] + ((view[1] - to.height - 40) * 0.5)), 10); - to.left = parseInt(Math.max(view[2] - 20, view[2] + ((view[0] - to.width - 40) * 0.5)), 10); - - return to; - }, - - _get_obj_pos = function(obj) { - var pos = obj.offset(); - - pos.top += parseInt( obj.css('paddingTop'), 10 ) || 0; - pos.left += parseInt( obj.css('paddingLeft'), 10 ) || 0; - - pos.top += parseInt( obj.css('border-top-width'), 10 ) || 0; - pos.left += parseInt( obj.css('border-left-width'), 10 ) || 0; - - pos.width = obj.width(); - pos.height = obj.height(); - - return pos; - }, - - _get_zoom_from = function() { - var orig = selectedOpts.orig ? $(selectedOpts.orig) : false, - from = {}, - pos, - view; - - if (orig && orig.length) { - pos = _get_obj_pos(orig); - - from = { - width : pos.width + (currentOpts.padding * 2), - height : pos.height + (currentOpts.padding * 2), - top : pos.top - currentOpts.padding - 20, - left : pos.left - currentOpts.padding - 20 - }; - - } else { - view = _get_viewport(); - - from = { - width : currentOpts.padding * 2, - height : currentOpts.padding * 2, - top : parseInt(view[3] + view[1] * 0.5, 10), - left : parseInt(view[2] + view[0] * 0.5, 10) - }; - } - - return from; - }, - - _animate_loading = function() { - if (!loading.is(':visible')){ - clearInterval(loadingTimer); - return; - } - - $('div', loading).css('top', (loadingFrame * -40) + 'px'); - - loadingFrame = (loadingFrame + 1) % 12; - }; - - /** - * Public methods - */ - - $.fn.fancybox = function(options) { - if (!$(this).length) { - return this; - } - - $(this) - .data('fancybox', $.extend({}, options, ($.metadata ? $(this).metadata() : {}))) - .unbind('click.fb') - .bind('click.fb', function(e) { - e.preventDefault(); - - if (busy) { - return; - } - - busy = true; - - $(this).blur(); - - selectedArray = []; - selectedIndex = 0; - - var rel = $(this).attr('rel') || ''; - - if (!rel || rel === '' || rel === 'nofollow') { - selectedArray.push(this); - - } else { - selectedArray = $("a[rel=" + rel + "], area[rel=" + rel + "]"); - selectedIndex = selectedArray.index( this ); - } - - _start(); - }); - - return this; - }; - - $.fancybox = function(obj) { - var opts; - - if (busy) { - return; - } - - busy = true; - opts = typeof arguments[1] !== 'undefined' ? arguments[1] : {}; - - selectedArray = []; - selectedIndex = parseInt(opts.index, 10) || 0; - - if ($.isArray(obj)) { - for (var i = 0, j = obj.length; i < j; i++) { - if (typeof obj[i] == 'object') { - $(obj[i]).data('fancybox', $.extend({}, opts, obj[i])); - } else { - obj[i] = $({}).data('fancybox', $.extend({content : obj[i]}, opts)); - } - } - - selectedArray = jQuery.merge(selectedArray, obj); - - } else { - if (typeof obj == 'object') { - $(obj).data('fancybox', $.extend({}, opts, obj)); - } else { - obj = $({}).data('fancybox', $.extend({content : obj}, opts)); - } - - selectedArray.push(obj); - } - - if (selectedIndex > selectedArray.length || selectedIndex < 0) { - selectedIndex = 0; - } - - _start(); - }; - - $.fancybox.showActivity = function() { - clearInterval(loadingTimer); - - loading.show(); - loadingTimer = setInterval(_animate_loading, 66); - }; - - $.fancybox.hideActivity = function() { - loading.hide(); - }; - - $.fancybox.next = function() { - return $.fancybox.pos( currentIndex + 1); - }; - - $.fancybox.prev = function() { - return $.fancybox.pos( currentIndex - 1); - }; - - $.fancybox.pos = function(pos) { - if (busy) { - return; - } - - pos = parseInt(pos); - - selectedArray = currentArray; - - if (pos > -1 && pos < currentArray.length) { - selectedIndex = pos; - _start(); - - } else if (currentOpts.cyclic && currentArray.length > 1) { - selectedIndex = pos >= currentArray.length ? 0 : currentArray.length - 1; - _start(); - } - }; - - $.fancybox.cancel = function() { - if (busy) { - return; - } - - busy = true; - - $.event.trigger('fancybox-cancel'); - - _abort(); - - selectedOpts.onCancel(selectedArray, selectedIndex, selectedOpts); - - busy = false; - }; - - // Note: within an iframe use - parent.$.fancybox.close(); - $.fancybox.close = function() { - if (busy || wrap.is(':hidden')) { - return; - } - - busy = true; - - if (currentOpts && false === currentOpts.onCleanup(currentArray, currentIndex, currentOpts)) { - busy = false; - return; - } - - _abort(); - - $(close.add( nav_left ).add( nav_right )).hide(); - - $(content.add( overlay )).unbind(); - - $(window).unbind("resize.fb scroll.fb"); - $(document).unbind('keydown.fb'); - - content.find('iframe').attr('src', isIE6 && /^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank'); - - if (currentOpts.titlePosition !== 'inside') { - title.empty(); - } - - wrap.stop(); - - function _cleanup() { - overlay.fadeOut('fast'); - - title.empty().hide(); - wrap.hide(); - - $.event.trigger('fancybox-cleanup'); - - content.empty(); - - currentOpts.onClosed(currentArray, currentIndex, currentOpts); - - currentArray = selectedOpts = []; - currentIndex = selectedIndex = 0; - currentOpts = selectedOpts = {}; - - busy = false; - } - - if (currentOpts.transitionOut == 'elastic') { - start_pos = _get_zoom_from(); - - var pos = wrap.position(); - - final_pos = { - top : pos.top , - left : pos.left, - width : wrap.width(), - height : wrap.height() - }; - - if (currentOpts.opacity) { - final_pos.opacity = 1; - } - - title.empty().hide(); - - fx.prop = 1; - - $(fx).animate({ prop: 0 }, { - duration : currentOpts.speedOut, - easing : currentOpts.easingOut, - step : _draw, - complete : _cleanup - }); - - } else { - wrap.fadeOut( currentOpts.transitionOut == 'none' ? 0 : currentOpts.speedOut, _cleanup); - } - }; - - $.fancybox.resize = function() { - if (overlay.is(':visible')) { - overlay.css('height', $(document).height()); - } - - $.fancybox.center(true); - }; - - $.fancybox.center = function() { - var view, align; - - if (busy) { - return; - } - - align = arguments[0] === true ? 1 : 0; - view = _get_viewport(); - - if (!align && (wrap.width() > view[0] || wrap.height() > view[1])) { - return; - } - - wrap - .stop() - .animate({ - 'top' : parseInt(Math.max(view[3] - 20, view[3] + ((view[1] - content.height() - 40) * 0.5) - currentOpts.padding)), - 'left' : parseInt(Math.max(view[2] - 20, view[2] + ((view[0] - content.width() - 40) * 0.5) - currentOpts.padding)) - }, typeof arguments[0] == 'number' ? arguments[0] : 200); - }; - - $.fancybox.init = function() { - if ($("#fancybox-wrap").length) { - return; - } - - $('body').append( - tmp = $('<div id="fancybox-tmp"></div>'), - loading = $('<div id="fancybox-loading"><div></div></div>'), - overlay = $('<div id="fancybox-overlay"></div>'), - wrap = $('<div id="fancybox-wrap"></div>') - ); - - outer = $('<div id="fancybox-outer"></div>') - .append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>') - .appendTo( wrap ); - - outer.append( - content = $('<div id="fancybox-content"></div>'), - close = $('<a id="fancybox-close"></a>'), - title = $('<div id="fancybox-title"></div>'), - - nav_left = $('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'), - nav_right = $('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>') - ); - - close.click($.fancybox.close); - loading.click($.fancybox.cancel); - - nav_left.click(function(e) { - e.preventDefault(); - $.fancybox.prev(); - }); - - nav_right.click(function(e) { - e.preventDefault(); - $.fancybox.next(); - }); - - if ($.fn.mousewheel) { - wrap.bind('mousewheel.fb', function(e, delta) { - if (busy) { - e.preventDefault(); - - } else if ($(e.target).get(0).clientHeight === 0 || $(e.target).get(0).scrollHeight === $(e.target).get(0).clientHeight) { - e.preventDefault(); - $.fancybox[ delta > 0 ? 'prev' : 'next'](); - } - }); - } - - if (!$.support.opacity) { - wrap.addClass('fancybox-ie'); - } - - if (isIE6) { - loading.addClass('fancybox-ie6'); - wrap.addClass('fancybox-ie6'); - - $('<iframe id="fancybox-hide-sel-frame" src="' + (/^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank' ) + '" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(outer); - } - }; - - $.fn.fancybox.defaults = { - padding : 10, - margin : 40, - opacity : false, - modal : false, - cyclic : false, - scrolling : 'auto', // 'auto', 'yes' or 'no' - - width : 560, - height : 340, - - autoScale : true, - autoDimensions : true, - centerOnScroll : false, - - ajax : {}, - swf : { wmode: 'transparent' }, - - hideOnOverlayClick : true, - hideOnContentClick : false, - - overlayShow : true, - overlayOpacity : 0.7, - overlayColor : '#777', - - titleShow : true, - titlePosition : 'float', // 'float', 'outside', 'inside' or 'over' - titleFormat : null, - titleFromAlt : false, - - transitionIn : 'fade', // 'elastic', 'fade' or 'none' - transitionOut : 'fade', // 'elastic', 'fade' or 'none' - - speedIn : 300, - speedOut : 300, - - changeSpeed : 300, - changeFade : 'fast', - - easingIn : 'swing', - easingOut : 'swing', - - showCloseButton : true, - showNavArrows : true, - enableEscapeButton : true, - enableKeyboardNav : true, - - onStart : function(){}, - onCancel : function(){}, - onComplete : function(){}, - onCleanup : function(){}, - onClosed : function(){}, - onError : function(){} - }; - - $(document).ready(function() { - $.fancybox.init(); - }); - -})(jQuery); diff --git a/SemanticForms/libs/select2.js b/SemanticForms/libs/select2.js deleted file mode 100644 index fdd18a71..00000000 --- a/SemanticForms/libs/select2.js +++ /dev/null @@ -1,3378 +0,0 @@ -/* -Copyright 2012 Igor Vaynberg - -Version: @@ver@@ Timestamp: @@timestamp@@ - -This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU -General Public License version 2 (the "GPL License"). You may choose either license to govern your -use of this software only upon the condition that you accept all of the terms of either the Apache -License or the GPL License. - -You may obtain a copy of the Apache License and the GPL License at: - - http://www.apache.org/licenses/LICENSE-2.0 - http://www.gnu.org/licenses/gpl-2.0.html - -Unless required by applicable law or agreed to in writing, software distributed under the -Apache License or the GPL License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -CONDITIONS OF ANY KIND, either express or implied. See the Apache License and the GPL License for -the specific language governing permissions and limitations under the Apache License and the GPL License. -*/ -(function ($) { - if(typeof $.fn.each2 == "undefined") { - $.extend($.fn, { - /* - * 4-10 times faster .each replacement - * use it carefully, as it overrides jQuery context of element on each iteration - */ - each2 : function (c) { - var j = $([0]), i = -1, l = this.length; - while ( - ++i < l - && (j.context = j[0] = this[i]) - && c.call(j[0], i, j) !== false //"this"=DOM, i=index, j=jQuery object - ); - return this; - } - }); - } -})(jQuery); - -(function ($, undefined) { - "use strict"; - /*global document, window, jQuery, console */ - - if (window.Select2 !== undefined) { - return; - } - - var KEY, AbstractSelect2, SingleSelect2, MultiSelect2, nextUid, sizer, - lastMousePosition={x:0,y:0}, $document, scrollBarDimensions, - - KEY = { - TAB: 9, - ENTER: 13, - ESC: 27, - SPACE: 32, - LEFT: 37, - UP: 38, - RIGHT: 39, - DOWN: 40, - SHIFT: 16, - CTRL: 17, - ALT: 18, - PAGE_UP: 33, - PAGE_DOWN: 34, - HOME: 36, - END: 35, - BACKSPACE: 8, - DELETE: 46, - isArrow: function (k) { - k = k.which ? k.which : k; - switch (k) { - case KEY.LEFT: - case KEY.RIGHT: - case KEY.UP: - case KEY.DOWN: - return true; - } - return false; - }, - isControl: function (e) { - var k = e.which; - switch (k) { - case KEY.SHIFT: - case KEY.CTRL: - case KEY.ALT: - return true; - } - - if (e.metaKey) return true; - - return false; - }, - isFunctionKey: function (k) { - k = k.which ? k.which : k; - return k >= 112 && k <= 123; - } - }, - MEASURE_SCROLLBAR_TEMPLATE = "<div class='select2-measure-scrollbar'></div>", - - DIACRITICS = {"\u24B6":"A","\uFF21":"A","\u00C0":"A","\u00C1":"A","\u00C2":"A","\u1EA6":"A","\u1EA4":"A","\u1EAA":"A","\u1EA8":"A","\u00C3":"A","\u0100":"A","\u0102":"A","\u1EB0":"A","\u1EAE":"A","\u1EB4":"A","\u1EB2":"A","\u0226":"A","\u01E0":"A","\u00C4":"A","\u01DE":"A","\u1EA2":"A","\u00C5":"A","\u01FA":"A","\u01CD":"A","\u0200":"A","\u0202":"A","\u1EA0":"A","\u1EAC":"A","\u1EB6":"A","\u1E00":"A","\u0104":"A","\u023A":"A","\u2C6F":"A","\uA732":"AA","\u00C6":"AE","\u01FC":"AE","\u01E2":"AE","\uA734":"AO","\uA736":"AU","\uA738":"AV","\uA73A":"AV","\uA73C":"AY","\u24B7":"B","\uFF22":"B","\u1E02":"B","\u1E04":"B","\u1E06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24B8":"C","\uFF23":"C","\u0106":"C","\u0108":"C","\u010A":"C","\u010C":"C","\u00C7":"C","\u1E08":"C","\u0187":"C","\u023B":"C","\uA73E":"C","\u24B9":"D","\uFF24":"D","\u1E0A":"D","\u010E":"D","\u1E0C":"D","\u1E10":"D","\u1E12":"D","\u1E0E":"D","\u0110":"D","\u018B":"D","\u018A":"D","\u0189":"D","\uA779":"D","\u01F1":"DZ","\u01C4":"DZ","\u01F2":"Dz","\u01C5":"Dz","\u24BA":"E","\uFF25":"E","\u00C8":"E","\u00C9":"E","\u00CA":"E","\u1EC0":"E","\u1EBE":"E","\u1EC4":"E","\u1EC2":"E","\u1EBC":"E","\u0112":"E","\u1E14":"E","\u1E16":"E","\u0114":"E","\u0116":"E","\u00CB":"E","\u1EBA":"E","\u011A":"E","\u0204":"E","\u0206":"E","\u1EB8":"E","\u1EC6":"E","\u0228":"E","\u1E1C":"E","\u0118":"E","\u1E18":"E","\u1E1A":"E","\u0190":"E","\u018E":"E","\u24BB":"F","\uFF26":"F","\u1E1E":"F","\u0191":"F","\uA77B":"F","\u24BC":"G","\uFF27":"G","\u01F4":"G","\u011C":"G","\u1E20":"G","\u011E":"G","\u0120":"G","\u01E6":"G","\u0122":"G","\u01E4":"G","\u0193":"G","\uA7A0":"G","\uA77D":"G","\uA77E":"G","\u24BD":"H","\uFF28":"H","\u0124":"H","\u1E22":"H","\u1E26":"H","\u021E":"H","\u1E24":"H","\u1E28":"H","\u1E2A":"H","\u0126":"H","\u2C67":"H","\u2C75":"H","\uA78D":"H","\u24BE":"I","\uFF29":"I","\u00CC":"I","\u00CD":"I","\u00CE":"I","\u0128":"I","\u012A":"I","\u012C":"I","\u0130":"I","\u00CF":"I","\u1E2E":"I","\u1EC8":"I","\u01CF":"I","\u0208":"I","\u020A":"I","\u1ECA":"I","\u012E":"I","\u1E2C":"I","\u0197":"I","\u24BF":"J","\uFF2A":"J","\u0134":"J","\u0248":"J","\u24C0":"K","\uFF2B":"K","\u1E30":"K","\u01E8":"K","\u1E32":"K","\u0136":"K","\u1E34":"K","\u0198":"K","\u2C69":"K","\uA740":"K","\uA742":"K","\uA744":"K","\uA7A2":"K","\u24C1":"L","\uFF2C":"L","\u013F":"L","\u0139":"L","\u013D":"L","\u1E36":"L","\u1E38":"L","\u013B":"L","\u1E3C":"L","\u1E3A":"L","\u0141":"L","\u023D":"L","\u2C62":"L","\u2C60":"L","\uA748":"L","\uA746":"L","\uA780":"L","\u01C7":"LJ","\u01C8":"Lj","\u24C2":"M","\uFF2D":"M","\u1E3E":"M","\u1E40":"M","\u1E42":"M","\u2C6E":"M","\u019C":"M","\u24C3":"N","\uFF2E":"N","\u01F8":"N","\u0143":"N","\u00D1":"N","\u1E44":"N","\u0147":"N","\u1E46":"N","\u0145":"N","\u1E4A":"N","\u1E48":"N","\u0220":"N","\u019D":"N","\uA790":"N","\uA7A4":"N","\u01CA":"NJ","\u01CB":"Nj","\u24C4":"O","\uFF2F":"O","\u00D2":"O","\u00D3":"O","\u00D4":"O","\u1ED2":"O","\u1ED0":"O","\u1ED6":"O","\u1ED4":"O","\u00D5":"O","\u1E4C":"O","\u022C":"O","\u1E4E":"O","\u014C":"O","\u1E50":"O","\u1E52":"O","\u014E":"O","\u022E":"O","\u0230":"O","\u00D6":"O","\u022A":"O","\u1ECE":"O","\u0150":"O","\u01D1":"O","\u020C":"O","\u020E":"O","\u01A0":"O","\u1EDC":"O","\u1EDA":"O","\u1EE0":"O","\u1EDE":"O","\u1EE2":"O","\u1ECC":"O","\u1ED8":"O","\u01EA":"O","\u01EC":"O","\u00D8":"O","\u01FE":"O","\u0186":"O","\u019F":"O","\uA74A":"O","\uA74C":"O","\u01A2":"OI","\uA74E":"OO","\u0222":"OU","\u24C5":"P","\uFF30":"P","\u1E54":"P","\u1E56":"P","\u01A4":"P","\u2C63":"P","\uA750":"P","\uA752":"P","\uA754":"P","\u24C6":"Q","\uFF31":"Q","\uA756":"Q","\uA758":"Q","\u024A":"Q","\u24C7":"R","\uFF32":"R","\u0154":"R","\u1E58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1E5A":"R","\u1E5C":"R","\u0156":"R","\u1E5E":"R","\u024C":"R","\u2C64":"R","\uA75A":"R","\uA7A6":"R","\uA782":"R","\u24C8":"S","\uFF33":"S","\u1E9E":"S","\u015A":"S","\u1E64":"S","\u015C":"S","\u1E60":"S","\u0160":"S","\u1E66":"S","\u1E62":"S","\u1E68":"S","\u0218":"S","\u015E":"S","\u2C7E":"S","\uA7A8":"S","\uA784":"S","\u24C9":"T","\uFF34":"T","\u1E6A":"T","\u0164":"T","\u1E6C":"T","\u021A":"T","\u0162":"T","\u1E70":"T","\u1E6E":"T","\u0166":"T","\u01AC":"T","\u01AE":"T","\u023E":"T","\uA786":"T","\uA728":"TZ","\u24CA":"U","\uFF35":"U","\u00D9":"U","\u00DA":"U","\u00DB":"U","\u0168":"U","\u1E78":"U","\u016A":"U","\u1E7A":"U","\u016C":"U","\u00DC":"U","\u01DB":"U","\u01D7":"U","\u01D5":"U","\u01D9":"U","\u1EE6":"U","\u016E":"U","\u0170":"U","\u01D3":"U","\u0214":"U","\u0216":"U","\u01AF":"U","\u1EEA":"U","\u1EE8":"U","\u1EEE":"U","\u1EEC":"U","\u1EF0":"U","\u1EE4":"U","\u1E72":"U","\u0172":"U","\u1E76":"U","\u1E74":"U","\u0244":"U","\u24CB":"V","\uFF36":"V","\u1E7C":"V","\u1E7E":"V","\u01B2":"V","\uA75E":"V","\u0245":"V","\uA760":"VY","\u24CC":"W","\uFF37":"W","\u1E80":"W","\u1E82":"W","\u0174":"W","\u1E86":"W","\u1E84":"W","\u1E88":"W","\u2C72":"W","\u24CD":"X","\uFF38":"X","\u1E8A":"X","\u1E8C":"X","\u24CE":"Y","\uFF39":"Y","\u1EF2":"Y","\u00DD":"Y","\u0176":"Y","\u1EF8":"Y","\u0232":"Y","\u1E8E":"Y","\u0178":"Y","\u1EF6":"Y","\u1EF4":"Y","\u01B3":"Y","\u024E":"Y","\u1EFE":"Y","\u24CF":"Z","\uFF3A":"Z","\u0179":"Z","\u1E90":"Z","\u017B":"Z","\u017D":"Z","\u1E92":"Z","\u1E94":"Z","\u01B5":"Z","\u0224":"Z","\u2C7F":"Z","\u2C6B":"Z","\uA762":"Z","\u24D0":"a","\uFF41":"a","\u1E9A":"a","\u00E0":"a","\u00E1":"a","\u00E2":"a","\u1EA7":"a","\u1EA5":"a","\u1EAB":"a","\u1EA9":"a","\u00E3":"a","\u0101":"a","\u0103":"a","\u1EB1":"a","\u1EAF":"a","\u1EB5":"a","\u1EB3":"a","\u0227":"a","\u01E1":"a","\u00E4":"a","\u01DF":"a","\u1EA3":"a","\u00E5":"a","\u01FB":"a","\u01CE":"a","\u0201":"a","\u0203":"a","\u1EA1":"a","\u1EAD":"a","\u1EB7":"a","\u1E01":"a","\u0105":"a","\u2C65":"a","\u0250":"a","\uA733":"aa","\u00E6":"ae","\u01FD":"ae","\u01E3":"ae","\uA735":"ao","\uA737":"au","\uA739":"av","\uA73B":"av","\uA73D":"ay","\u24D1":"b","\uFF42":"b","\u1E03":"b","\u1E05":"b","\u1E07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24D2":"c","\uFF43":"c","\u0107":"c","\u0109":"c","\u010B":"c","\u010D":"c","\u00E7":"c","\u1E09":"c","\u0188":"c","\u023C":"c","\uA73F":"c","\u2184":"c","\u24D3":"d","\uFF44":"d","\u1E0B":"d","\u010F":"d","\u1E0D":"d","\u1E11":"d","\u1E13":"d","\u1E0F":"d","\u0111":"d","\u018C":"d","\u0256":"d","\u0257":"d","\uA77A":"d","\u01F3":"dz","\u01C6":"dz","\u24D4":"e","\uFF45":"e","\u00E8":"e","\u00E9":"e","\u00EA":"e","\u1EC1":"e","\u1EBF":"e","\u1EC5":"e","\u1EC3":"e","\u1EBD":"e","\u0113":"e","\u1E15":"e","\u1E17":"e","\u0115":"e","\u0117":"e","\u00EB":"e","\u1EBB":"e","\u011B":"e","\u0205":"e","\u0207":"e","\u1EB9":"e","\u1EC7":"e","\u0229":"e","\u1E1D":"e","\u0119":"e","\u1E19":"e","\u1E1B":"e","\u0247":"e","\u025B":"e","\u01DD":"e","\u24D5":"f","\uFF46":"f","\u1E1F":"f","\u0192":"f","\uA77C":"f","\u24D6":"g","\uFF47":"g","\u01F5":"g","\u011D":"g","\u1E21":"g","\u011F":"g","\u0121":"g","\u01E7":"g","\u0123":"g","\u01E5":"g","\u0260":"g","\uA7A1":"g","\u1D79":"g","\uA77F":"g","\u24D7":"h","\uFF48":"h","\u0125":"h","\u1E23":"h","\u1E27":"h","\u021F":"h","\u1E25":"h","\u1E29":"h","\u1E2B":"h","\u1E96":"h","\u0127":"h","\u2C68":"h","\u2C76":"h","\u0265":"h","\u0195":"hv","\u24D8":"i","\uFF49":"i","\u00EC":"i","\u00ED":"i","\u00EE":"i","\u0129":"i","\u012B":"i","\u012D":"i","\u00EF":"i","\u1E2F":"i","\u1EC9":"i","\u01D0":"i","\u0209":"i","\u020B":"i","\u1ECB":"i","\u012F":"i","\u1E2D":"i","\u0268":"i","\u0131":"i","\u24D9":"j","\uFF4A":"j","\u0135":"j","\u01F0":"j","\u0249":"j","\u24DA":"k","\uFF4B":"k","\u1E31":"k","\u01E9":"k","\u1E33":"k","\u0137":"k","\u1E35":"k","\u0199":"k","\u2C6A":"k","\uA741":"k","\uA743":"k","\uA745":"k","\uA7A3":"k","\u24DB":"l","\uFF4C":"l","\u0140":"l","\u013A":"l","\u013E":"l","\u1E37":"l","\u1E39":"l","\u013C":"l","\u1E3D":"l","\u1E3B":"l","\u017F":"l","\u0142":"l","\u019A":"l","\u026B":"l","\u2C61":"l","\uA749":"l","\uA781":"l","\uA747":"l","\u01C9":"lj","\u24DC":"m","\uFF4D":"m","\u1E3F":"m","\u1E41":"m","\u1E43":"m","\u0271":"m","\u026F":"m","\u24DD":"n","\uFF4E":"n","\u01F9":"n","\u0144":"n","\u00F1":"n","\u1E45":"n","\u0148":"n","\u1E47":"n","\u0146":"n","\u1E4B":"n","\u1E49":"n","\u019E":"n","\u0272":"n","\u0149":"n","\uA791":"n","\uA7A5":"n","\u01CC":"nj","\u24DE":"o","\uFF4F":"o","\u00F2":"o","\u00F3":"o","\u00F4":"o","\u1ED3":"o","\u1ED1":"o","\u1ED7":"o","\u1ED5":"o","\u00F5":"o","\u1E4D":"o","\u022D":"o","\u1E4F":"o","\u014D":"o","\u1E51":"o","\u1E53":"o","\u014F":"o","\u022F":"o","\u0231":"o","\u00F6":"o","\u022B":"o","\u1ECF":"o","\u0151":"o","\u01D2":"o","\u020D":"o","\u020F":"o","\u01A1":"o","\u1EDD":"o","\u1EDB":"o","\u1EE1":"o","\u1EDF":"o","\u1EE3":"o","\u1ECD":"o","\u1ED9":"o","\u01EB":"o","\u01ED":"o","\u00F8":"o","\u01FF":"o","\u0254":"o","\uA74B":"o","\uA74D":"o","\u0275":"o","\u01A3":"oi","\u0223":"ou","\uA74F":"oo","\u24DF":"p","\uFF50":"p","\u1E55":"p","\u1E57":"p","\u01A5":"p","\u1D7D":"p","\uA751":"p","\uA753":"p","\uA755":"p","\u24E0":"q","\uFF51":"q","\u024B":"q","\uA757":"q","\uA759":"q","\u24E1":"r","\uFF52":"r","\u0155":"r","\u1E59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1E5B":"r","\u1E5D":"r","\u0157":"r","\u1E5F":"r","\u024D":"r","\u027D":"r","\uA75B":"r","\uA7A7":"r","\uA783":"r","\u24E2":"s","\uFF53":"s","\u00DF":"s","\u015B":"s","\u1E65":"s","\u015D":"s","\u1E61":"s","\u0161":"s","\u1E67":"s","\u1E63":"s","\u1E69":"s","\u0219":"s","\u015F":"s","\u023F":"s","\uA7A9":"s","\uA785":"s","\u1E9B":"s","\u24E3":"t","\uFF54":"t","\u1E6B":"t","\u1E97":"t","\u0165":"t","\u1E6D":"t","\u021B":"t","\u0163":"t","\u1E71":"t","\u1E6F":"t","\u0167":"t","\u01AD":"t","\u0288":"t","\u2C66":"t","\uA787":"t","\uA729":"tz","\u24E4":"u","\uFF55":"u","\u00F9":"u","\u00FA":"u","\u00FB":"u","\u0169":"u","\u1E79":"u","\u016B":"u","\u1E7B":"u","\u016D":"u","\u00FC":"u","\u01DC":"u","\u01D8":"u","\u01D6":"u","\u01DA":"u","\u1EE7":"u","\u016F":"u","\u0171":"u","\u01D4":"u","\u0215":"u","\u0217":"u","\u01B0":"u","\u1EEB":"u","\u1EE9":"u","\u1EEF":"u","\u1EED":"u","\u1EF1":"u","\u1EE5":"u","\u1E73":"u","\u0173":"u","\u1E77":"u","\u1E75":"u","\u0289":"u","\u24E5":"v","\uFF56":"v","\u1E7D":"v","\u1E7F":"v","\u028B":"v","\uA75F":"v","\u028C":"v","\uA761":"vy","\u24E6":"w","\uFF57":"w","\u1E81":"w","\u1E83":"w","\u0175":"w","\u1E87":"w","\u1E85":"w","\u1E98":"w","\u1E89":"w","\u2C73":"w","\u24E7":"x","\uFF58":"x","\u1E8B":"x","\u1E8D":"x","\u24E8":"y","\uFF59":"y","\u1EF3":"y","\u00FD":"y","\u0177":"y","\u1EF9":"y","\u0233":"y","\u1E8F":"y","\u00FF":"y","\u1EF7":"y","\u1E99":"y","\u1EF5":"y","\u01B4":"y","\u024F":"y","\u1EFF":"y","\u24E9":"z","\uFF5A":"z","\u017A":"z","\u1E91":"z","\u017C":"z","\u017E":"z","\u1E93":"z","\u1E95":"z","\u01B6":"z","\u0225":"z","\u0240":"z","\u2C6C":"z","\uA763":"z"}; - - $document = $(document); - - nextUid=(function() { var counter=1; return function() { return counter++; }; }()); - - - function reinsertElement(element) { - var placeholder = $(document.createTextNode('')); - - element.before(placeholder); - placeholder.before(element); - placeholder.remove(); - } - - function stripDiacritics(str) { - var ret, i, l, c; - - if (!str || str.length < 1) return str; - - ret = ""; - for (i = 0, l = str.length; i < l; i++) { - c = str.charAt(i); - ret += DIACRITICS[c] || c; - } - return ret; - } - - function indexOf(value, array) { - var i = 0, l = array.length; - for (; i < l; i = i + 1) { - if (equal(value, array[i])) return i; - } - return -1; - } - - function measureScrollbar () { - var $template = $( MEASURE_SCROLLBAR_TEMPLATE ); - $template.appendTo('body'); - - var dim = { - width: $template.width() - $template[0].clientWidth, - height: $template.height() - $template[0].clientHeight - }; - $template.remove(); - - return dim; - } - - /** - * Compares equality of a and b - * @param a - * @param b - */ - function equal(a, b) { - if (a === b) return true; - if (a === undefined || b === undefined) return false; - if (a === null || b === null) return false; - // Check whether 'a' or 'b' is a string (primitive or object). - // The concatenation of an empty string (+'') converts its argument to a string's primitive. - if (a.constructor === String) return a+'' === b+''; // a+'' - in case 'a' is a String object - if (b.constructor === String) return b+'' === a+''; // b+'' - in case 'b' is a String object - return false; - } - - /** - * Splits the string into an array of values, trimming each value. An empty array is returned for nulls or empty - * strings - * @param string - * @param separator - */ - function splitVal(string, separator) { - var val, i, l; - if (string === null || string.length < 1) return []; - val = string.split(separator); - for (i = 0, l = val.length; i < l; i = i + 1) val[i] = $.trim(val[i]); - return val; - } - - function getSideBorderPadding(element) { - return element.outerWidth(false) - element.width(); - } - - function installKeyUpChangeEvent(element) { - var key="keyup-change-value"; - element.on("keydown", function () { - if ($.data(element, key) === undefined) { - $.data(element, key, element.val()); - } - }); - element.on("keyup", function () { - var val= $.data(element, key); - if (val !== undefined && element.val() !== val) { - $.removeData(element, key); - element.trigger("keyup-change"); - } - }); - } - - $document.on("mousemove", function (e) { - lastMousePosition.x = e.pageX; - lastMousePosition.y = e.pageY; - }); - - /** - * filters mouse events so an event is fired only if the mouse moved. - * - * filters out mouse events that occur when mouse is stationary but - * the elements under the pointer are scrolled. - */ - function installFilteredMouseMove(element) { - element.on("mousemove", function (e) { - var lastpos = lastMousePosition; - if (lastpos === undefined || lastpos.x !== e.pageX || lastpos.y !== e.pageY) { - $(e.target).trigger("mousemove-filtered", e); - } - }); - } - - /** - * Debounces a function. Returns a function that calls the original fn function only if no invocations have been made - * within the last quietMillis milliseconds. - * - * @param quietMillis number of milliseconds to wait before invoking fn - * @param fn function to be debounced - * @param ctx object to be used as this reference within fn - * @return debounced version of fn - */ - function debounce(quietMillis, fn, ctx) { - ctx = ctx || undefined; - var timeout; - return function () { - var args = arguments; - window.clearTimeout(timeout); - timeout = window.setTimeout(function() { - fn.apply(ctx, args); - }, quietMillis); - }; - } - - /** - * A simple implementation of a thunk - * @param formula function used to lazily initialize the thunk - * @return {Function} - */ - function thunk(formula) { - var evaluated = false, - value; - return function() { - if (evaluated === false) { value = formula(); evaluated = true; } - return value; - }; - }; - - function installDebouncedScroll(threshold, element) { - var notify = debounce(threshold, function (e) { element.trigger("scroll-debounced", e);}); - element.on("scroll", function (e) { - if (indexOf(e.target, element.get()) >= 0) notify(e); - }); - } - - function focus($el) { - if ($el[0] === document.activeElement) return; - - /* set the focus in a 0 timeout - that way the focus is set after the processing - of the current event has finished - which seems like the only reliable way - to set focus */ - window.setTimeout(function() { - var el=$el[0], pos=$el.val().length, range; - - $el.focus(); - - /* make sure el received focus so we do not error out when trying to manipulate the caret. - sometimes modals or others listeners may steal it after its set */ - var isVisible = (el.offsetWidth > 0 || el.offsetHeight > 0); - if (isVisible && el === document.activeElement) { - - /* after the focus is set move the caret to the end, necessary when we val() - just before setting focus */ - if(el.setSelectionRange) - { - el.setSelectionRange(pos, pos); - } - else if (el.createTextRange) { - range = el.createTextRange(); - range.collapse(false); - range.select(); - } - } - }, 0); - } - - function getCursorInfo(el) { - el = $(el)[0]; - var offset = 0; - var length = 0; - if ('selectionStart' in el) { - offset = el.selectionStart; - length = el.selectionEnd - offset; - } else if ('selection' in document) { - el.focus(); - var sel = document.selection.createRange(); - length = document.selection.createRange().text.length; - sel.moveStart('character', -el.value.length); - offset = sel.text.length - length; - } - return { offset: offset, length: length }; - } - - function killEvent(event) { - event.preventDefault(); - event.stopPropagation(); - } - function killEventImmediately(event) { - event.preventDefault(); - event.stopImmediatePropagation(); - } - - function measureTextWidth(e) { - if (!sizer){ - var style = e[0].currentStyle || window.getComputedStyle(e[0], null); - sizer = $(document.createElement("div")).css({ - position: "absolute", - left: "-10000px", - top: "-10000px", - display: "none", - fontSize: style.fontSize, - fontFamily: style.fontFamily, - fontStyle: style.fontStyle, - fontWeight: style.fontWeight, - letterSpacing: style.letterSpacing, - textTransform: style.textTransform, - whiteSpace: "nowrap" - }); - sizer.attr("class","select2-sizer"); - $("body").append(sizer); - } - sizer.text(e.val()); - return sizer.width(); - } - - function syncCssClasses(dest, src, adapter) { - var classes, replacements = [], adapted; - - classes = dest.attr("class"); - if (classes) { - classes = '' + classes; // for IE which returns object - $(classes.split(" ")).each2(function() { - if (this.indexOf("select2-") === 0) { - replacements.push(this); - } - }); - } - classes = src.attr("class"); - if (classes) { - classes = '' + classes; // for IE which returns object - $(classes.split(" ")).each2(function() { - if (this.indexOf("select2-") !== 0) { - adapted = adapter(this); - if (adapted) { - replacements.push(adapted); - } - } - }); - } - dest.attr("class", replacements.join(" ")); - } - - - function markMatch(text, term, markup, escapeMarkup) { - var match=stripDiacritics(text.toUpperCase()).indexOf(stripDiacritics(term.toUpperCase())), - tl=term.length; - - if (match<0) { - markup.push(escapeMarkup(text)); - return; - } - - markup.push(escapeMarkup(text.substring(0, match))); - markup.push("<span class='select2-match'>"); - markup.push(escapeMarkup(text.substring(match, match + tl))); - markup.push("</span>"); - markup.push(escapeMarkup(text.substring(match + tl, text.length))); - } - - function defaultEscapeMarkup(markup) { - var replace_map = { - '\\': '\', - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - "/": '/' - }; - - return String(markup).replace(/[&<>"'\/\\]/g, function (match) { - return replace_map[match]; - }); - } - - /** - * Produces an ajax-based query function - * - * @param options object containing configuration parameters - * @param options.params parameter map for the transport ajax call, can contain such options as cache, jsonpCallback, etc. see $.ajax - * @param options.transport function that will be used to execute the ajax request. must be compatible with parameters supported by $.ajax - * @param options.url url for the data - * @param options.data a function(searchTerm, pageNumber, context) that should return an object containing query string parameters for the above url. - * @param options.dataType request data type: ajax, jsonp, other datatypes supported by jQuery's $.ajax function or the transport function if specified - * @param options.quietMillis (optional) milliseconds to wait before making the ajaxRequest, helps debounce the ajax function if invoked too often - * @param options.results a function(remoteData, pageNumber) that converts data returned form the remote request to the format expected by Select2. - * The expected format is an object containing the following keys: - * results array of objects that will be used as choices - * more (optional) boolean indicating whether there are more results available - * Example: {results:[{id:1, text:'Red'},{id:2, text:'Blue'}], more:true} - */ - function ajax(options) { - var timeout, // current scheduled but not yet executed request - handler = null, - quietMillis = options.quietMillis || 100, - ajaxUrl = options.url, - self = this; - - return function (query) { - window.clearTimeout(timeout); - timeout = window.setTimeout(function () { - var data = options.data, // ajax data function - url = ajaxUrl, // ajax url string or function - transport = options.transport || $.fn.select2.ajaxDefaults.transport, - // deprecated - to be removed in 4.0 - use params instead - deprecated = { - type: options.type || 'GET', // set type of request (GET or POST) - cache: options.cache || false, - jsonpCallback: options.jsonpCallback||undefined, - dataType: options.dataType||"json" - }, - params = $.extend({}, $.fn.select2.ajaxDefaults.params, deprecated); - - data = data ? data.call(self, query.term, query.page, query.context) : null; - url = (typeof url === 'function') ? url.call(self, query.term, query.page, query.context) : url; - - if (handler && typeof handler.abort === "function") { handler.abort(); } - - if (options.params) { - if ($.isFunction(options.params)) { - $.extend(params, options.params.call(self)); - } else { - $.extend(params, options.params); - } - } - - $.extend(params, { - url: url, - dataType: options.dataType, - data: data, - success: function (data) { - // TODO - replace query.page with query so users have access to term, page, etc. - var results = options.results(data, query.page); - query.callback(results); - } - }); - handler = transport.call(self, params); - }, quietMillis); - }; - } - - /** - * Produces a query function that works with a local array - * - * @param options object containing configuration parameters. The options parameter can either be an array or an - * object. - * - * If the array form is used it is assumed that it contains objects with 'id' and 'text' keys. - * - * If the object form is used ti is assumed that it contains 'data' and 'text' keys. The 'data' key should contain - * an array of objects that will be used as choices. These objects must contain at least an 'id' key. The 'text' - * key can either be a String in which case it is expected that each element in the 'data' array has a key with the - * value of 'text' which will be used to match choices. Alternatively, text can be a function(item) that can extract - * the text. - */ - function local(options) { - var data = options, // data elements - dataText, - tmp, - text = function (item) { return ""+item.text; }; // function used to retrieve the text portion of a data item that is matched against the search - - if ($.isArray(data)) { - tmp = data; - data = { results: tmp }; - } - - if ($.isFunction(data) === false) { - tmp = data; - data = function() { return tmp; }; - } - - var dataItem = data(); - if (dataItem.text) { - text = dataItem.text; - // if text is not a function we assume it to be a key name - if (!$.isFunction(text)) { - dataText = dataItem.text; // we need to store this in a separate variable because in the next step data gets reset and data.text is no longer available - text = function (item) { return item[dataText]; }; - } - } - - return function (query) { - var t = query.term, filtered = { results: [] }, process; - if (t === "") { - query.callback(data()); - return; - } - - process = function(datum, collection) { - var group, attr; - datum = datum[0]; - if (datum.children) { - group = {}; - for (attr in datum) { - if (datum.hasOwnProperty(attr)) group[attr]=datum[attr]; - } - group.children=[]; - $(datum.children).each2(function(i, childDatum) { process(childDatum, group.children); }); - if (group.children.length || query.matcher(t, text(group), datum)) { - collection.push(group); - } - } else { - if (query.matcher(t, text(datum), datum)) { - collection.push(datum); - } - } - }; - - $(data().results).each2(function(i, datum) { process(datum, filtered.results); }); - query.callback(filtered); - }; - } - - // TODO javadoc - function tags(data) { - var isFunc = $.isFunction(data); - return function (query) { - var t = query.term, filtered = {results: []}; - $(isFunc ? data() : data).each(function () { - var isObject = this.text !== undefined, - text = isObject ? this.text : this; - if (t === "" || query.matcher(t, text)) { - filtered.results.push(isObject ? this : {id: this, text: this}); - } - }); - query.callback(filtered); - }; - } - - /** - * Checks if the formatter function should be used. - * - * Throws an error if it is not a function. Returns true if it should be used, - * false if no formatting should be performed. - * - * @param formatter - */ - function checkFormatter(formatter, formatterName) { - if ($.isFunction(formatter)) return true; - if (!formatter) return false; - if (typeof(formatter) === 'string') return true; - throw new Error(formatterName +" must be a string, function, or falsy value"); - } - - function evaluate(val) { - if ($.isFunction(val)) { - var args = Array.prototype.slice.call(arguments, 1); - return val.apply(null, args); - } - return val; - } - - function countResults(results) { - var count = 0; - $.each(results, function(i, item) { - if (item.children) { - count += countResults(item.children); - } else { - count++; - } - }); - return count; - } - - /** - * Default tokenizer. This function uses breaks the input on substring match of any string from the - * opts.tokenSeparators array and uses opts.createSearchChoice to create the choice object. Both of those - * two options have to be defined in order for the tokenizer to work. - * - * @param input text user has typed so far or pasted into the search field - * @param selection currently selected choices - * @param selectCallback function(choice) callback tho add the choice to selection - * @param opts select2's opts - * @return undefined/null to leave the current input unchanged, or a string to change the input to the returned value - */ - function defaultTokenizer(input, selection, selectCallback, opts) { - var original = input, // store the original so we can compare and know if we need to tell the search to update its text - dupe = false, // check for whether a token we extracted represents a duplicate selected choice - token, // token - index, // position at which the separator was found - i, l, // looping variables - separator; // the matched separator - - if (!opts.createSearchChoice || !opts.tokenSeparators || opts.tokenSeparators.length < 1) return undefined; - - while (true) { - index = -1; - - for (i = 0, l = opts.tokenSeparators.length; i < l; i++) { - separator = opts.tokenSeparators[i]; - index = input.indexOf(separator); - if (index >= 0) break; - } - - if (index < 0) break; // did not find any token separator in the input string, bail - - token = input.substring(0, index); - input = input.substring(index + separator.length); - - if (token.length > 0) { - token = opts.createSearchChoice.call(this, token, selection); - if (token !== undefined && token !== null && opts.id(token) !== undefined && opts.id(token) !== null) { - dupe = false; - for (i = 0, l = selection.length; i < l; i++) { - if (equal(opts.id(token), opts.id(selection[i]))) { - dupe = true; break; - } - } - - if (!dupe) selectCallback(token); - } - } - } - - if (original!==input) return input; - } - - /** - * Creates a new class - * - * @param superClass - * @param methods - */ - function clazz(SuperClass, methods) { - var constructor = function () {}; - constructor.prototype = new SuperClass; - constructor.prototype.constructor = constructor; - constructor.prototype.parent = SuperClass.prototype; - constructor.prototype = $.extend(constructor.prototype, methods); - return constructor; - } - - AbstractSelect2 = clazz(Object, { - - // abstract - bind: function (func) { - var self = this; - return function () { - func.apply(self, arguments); - }; - }, - - // abstract - init: function (opts) { - var results, search, resultsSelector = ".select2-results"; - - // prepare options - this.opts = opts = this.prepareOpts(opts); - - this.id=opts.id; - - // destroy if called on an existing component - if (opts.element.data("select2") !== undefined && - opts.element.data("select2") !== null) { - opts.element.data("select2").destroy(); - } - - this.container = this.createContainer(); - - this.liveRegion = $("<span>", { - role: "status", - "aria-live": "polite" - }) - .addClass("select2-hidden-accessible") - .appendTo(document.body); - - this.containerId="s2id_"+(opts.element.attr("id") || "autogen"+nextUid()).replace(/([;&,\-\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1'); - this.containerSelector="#"+this.containerId; - this.container.attr("id", this.containerId); - - // cache the body so future lookups are cheap - this.body = thunk(function() { return opts.element.closest("body"); }); - - syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass); - - this.container.attr("style", opts.element.attr("style")); - this.container.css(evaluate(opts.containerCss)); - this.container.addClass(evaluate(opts.containerCssClass)); - - this.elementTabIndex = this.opts.element.attr("tabindex"); - - // swap container for the element - this.opts.element - .data("select2", this) - .attr("tabindex", "-1") - .before(this.container) - .on("click.select2", killEvent); // do not leak click events - - this.container.data("select2", this); - - this.dropdown = this.container.find(".select2-drop"); - - syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass); - - this.dropdown.addClass(evaluate(opts.dropdownCssClass)); - this.dropdown.data("select2", this); - this.dropdown.on("click", killEvent); - - this.results = results = this.container.find(resultsSelector); - this.search = search = this.container.find("input.select2-input"); - - this.queryCount = 0; - this.resultsPage = 0; - this.context = null; - - // initialize the container - this.initContainer(); - - this.container.on("click", killEvent); - - installFilteredMouseMove(this.results); - this.dropdown.on("mousemove-filtered touchstart touchmove touchend", resultsSelector, this.bind(this.highlightUnderEvent)); - - installDebouncedScroll(80, this.results); - this.dropdown.on("scroll-debounced", resultsSelector, this.bind(this.loadMoreIfNeeded)); - - // do not propagate change event from the search field out of the component - $(this.container).on("change", ".select2-input", function(e) {e.stopPropagation();}); - $(this.dropdown).on("change", ".select2-input", function(e) {e.stopPropagation();}); - - // if jquery.mousewheel plugin is installed we can prevent out-of-bounds scrolling of results via mousewheel - if ($.fn.mousewheel) { - results.mousewheel(function (e, delta, deltaX, deltaY) { - var top = results.scrollTop(); - if (deltaY > 0 && top - deltaY <= 0) { - results.scrollTop(0); - killEvent(e); - } else if (deltaY < 0 && results.get(0).scrollHeight - results.scrollTop() + deltaY <= results.height()) { - results.scrollTop(results.get(0).scrollHeight - results.height()); - killEvent(e); - } - }); - } - - installKeyUpChangeEvent(search); - search.on("keyup-change input paste", this.bind(this.updateResults)); - search.on("focus", function () { search.addClass("select2-focused"); }); - search.on("blur", function () { search.removeClass("select2-focused");}); - - this.dropdown.on("mouseup", resultsSelector, this.bind(function (e) { - if ($(e.target).closest(".select2-result-selectable").length > 0) { - this.highlightUnderEvent(e); - this.selectHighlighted(e); - } - })); - - // trap all mouse events from leaving the dropdown. sometimes there may be a modal that is listening - // for mouse events outside of itself so it can close itself. since the dropdown is now outside the select2's - // dom it will trigger the popup close, which is not what we want - this.dropdown.on("click mouseup mousedown", function (e) { e.stopPropagation(); }); - - this.nextSearchTerm = undefined; - - if ($.isFunction(this.opts.initSelection)) { - // initialize selection based on the current value of the source element - this.initSelection(); - - // if the user has provided a function that can set selection based on the value of the source element - // we monitor the change event on the element and trigger it, allowing for two way synchronization - this.monitorSource(); - } - - if (opts.maximumInputLength !== null) { - this.search.attr("maxlength", opts.maximumInputLength); - } - - var disabled = opts.element.prop("disabled"); - if (disabled === undefined) disabled = false; - this.enable(!disabled); - - var readonly = opts.element.prop("readonly"); - if (readonly === undefined) readonly = false; - this.readonly(readonly); - - // Calculate size of scrollbar - scrollBarDimensions = scrollBarDimensions || measureScrollbar(); - - this.autofocus = opts.element.prop("autofocus"); - opts.element.prop("autofocus", false); - if (this.autofocus) this.focus(); - - this.search.attr("placeholder", opts.searchInputPlaceholder); - }, - - // abstract - destroy: function () { - var element=this.opts.element, select2 = element.data("select2"); - - this.close(); - - if (this.propertyObserver) { delete this.propertyObserver; this.propertyObserver = null; } - - if (select2 !== undefined) { - select2.container.remove(); - select2.liveRegion.remove(); - select2.dropdown.remove(); - element - .removeClass("select2-offscreen") - .removeData("select2") - .off(".select2") - .prop("autofocus", this.autofocus || false); - if (this.elementTabIndex) { - element.attr({tabindex: this.elementTabIndex}); - } else { - element.removeAttr("tabindex"); - } - element.show(); - } - }, - - // abstract - optionToData: function(element) { - if (element.is("option")) { - return { - id:element.prop("value"), - text:element.text(), - element: element.get(), - css: element.attr("class"), - disabled: element.prop("disabled"), - locked: equal(element.attr("locked"), "locked") || equal(element.data("locked"), true) - }; - } else if (element.is("optgroup")) { - return { - text:element.attr("label"), - children:[], - element: element.get(), - css: element.attr("class") - }; - } - }, - - // abstract - prepareOpts: function (opts) { - var element, select, idKey, ajaxUrl, self = this; - - element = opts.element; - - if (element.get(0).tagName.toLowerCase() === "select") { - this.select = select = opts.element; - } - - if (select) { - // these options are not allowed when attached to a select because they are picked up off the element itself - $.each(["id", "multiple", "ajax", "query", "createSearchChoice", "initSelection", "data", "tags"], function () { - if (this in opts) { - throw new Error("Option '" + this + "' is not allowed for Select2 when attached to a <select> element."); - } - }); - } - - opts = $.extend({}, { - populateResults: function(container, results, query) { - var populate, id=this.opts.id, liveRegion=this.liveRegion; - - populate=function(results, container, depth) { - - var i, l, result, selectable, disabled, compound, node, label, innerContainer, formatted; - - results = opts.sortResults(results, container, query); - - for (i = 0, l = results.length; i < l; i = i + 1) { - - result=results[i]; - - disabled = (result.disabled === true); - selectable = (!disabled) && (id(result) !== undefined); - - compound=result.children && result.children.length > 0; - - node=$("<li></li>"); - node.addClass("select2-results-dept-"+depth); - node.addClass("select2-result"); - node.addClass(selectable ? "select2-result-selectable" : "select2-result-unselectable"); - if (disabled) { node.addClass("select2-disabled"); } - if (compound) { node.addClass("select2-result-with-children"); } - node.addClass(self.opts.formatResultCssClass(result)); - node.attr("role", "presentation"); - - label=$(document.createElement("div")); - label.addClass("select2-result-label"); - label.attr("id", "select2-result-label-" + nextUid()); - label.attr("role", "option"); - - formatted=opts.formatResult(result, label, query, self.opts.escapeMarkup); - if (formatted!==undefined) { - label.html(formatted); - node.append(label); - } - - - if (compound) { - - innerContainer=$("<ul></ul>"); - innerContainer.addClass("select2-result-sub"); - populate(result.children, innerContainer, depth+1); - node.append(innerContainer); - } - - node.data("select2-data", result); - container.append(node); - } - - liveRegion.text(opts.formatMatches(results.length)); - }; - - populate(results, container, 0); - } - }, $.fn.select2.defaults, opts); - - if (typeof(opts.id) !== "function") { - idKey = opts.id; - opts.id = function (e) { return e[idKey]; }; - } - - if ($.isArray(opts.element.data("select2Tags"))) { - if ("tags" in opts) { - throw "tags specified as both an attribute 'data-select2-tags' and in options of Select2 " + opts.element.attr("id"); - } - opts.tags=opts.element.data("select2Tags"); - } - - if (select) { - opts.query = this.bind(function (query) { - var data = { results: [], more: false }, - term = query.term, - children, placeholderOption, process; - - process=function(element, collection) { - var group; - if (element.is("option")) { - if (query.matcher(term, element.text(), element)) { - collection.push(self.optionToData(element)); - } - } else if (element.is("optgroup")) { - group=self.optionToData(element); - element.children().each2(function(i, elm) { process(elm, group.children); }); - if (group.children.length>0) { - collection.push(group); - } - } - }; - - children=element.children(); - - // ignore the placeholder option if there is one - if (this.getPlaceholder() !== undefined && children.length > 0) { - placeholderOption = this.getPlaceholderOption(); - if (placeholderOption) { - children=children.not(placeholderOption); - } - } - - children.each2(function(i, elm) { process(elm, data.results); }); - - query.callback(data); - }); - // this is needed because inside val() we construct choices from options and there id is hardcoded - opts.id=function(e) { return e.id; }; - } else { - if (!("query" in opts)) { - - if ("ajax" in opts) { - ajaxUrl = opts.element.data("ajax-url"); - if (ajaxUrl && ajaxUrl.length > 0) { - opts.ajax.url = ajaxUrl; - } - opts.query = ajax.call(opts.element, opts.ajax); - } else if ("data" in opts) { - opts.query = local(opts.data); - } else if ("tags" in opts) { - opts.query = tags(opts.tags); - if (opts.createSearchChoice === undefined) { - opts.createSearchChoice = function (term) { return {id: $.trim(term), text: $.trim(term)}; }; - } - if (opts.initSelection === undefined) { - opts.initSelection = function (element, callback) { - var data = []; - $(splitVal(element.val(), opts.separator)).each(function () { - var obj = { id: this, text: this }, - tags = opts.tags; - if ($.isFunction(tags)) tags=tags(); - $(tags).each(function() { if (equal(this.id, obj.id)) { obj = this; return false; } }); - data.push(obj); - }); - - callback(data); - }; - } - } - } - } - if (typeof(opts.query) !== "function") { - throw "query function not defined for Select2 " + opts.element.attr("id"); - } - - if (opts.createSearchChoicePosition === 'top') { - opts.createSearchChoicePosition = function(list, item) { list.unshift(item); }; - } - else if (opts.createSearchChoicePosition === 'bottom') { - opts.createSearchChoicePosition = function(list, item) { list.push(item); }; - } - else if (typeof(opts.createSearchChoicePosition) !== "function") { - throw "invalid createSearchChoicePosition option must be 'top', 'bottom' or a custom function"; - } - - return opts; - }, - - /** - * Monitor the original element for changes and update select2 accordingly - */ - // abstract - monitorSource: function () { - var el = this.opts.element, sync, observer; - - el.on("change.select2", this.bind(function (e) { - if (this.opts.element.data("select2-change-triggered") !== true) { - this.initSelection(); - } - })); - - sync = this.bind(function () { - - // sync enabled state - var disabled = el.prop("disabled"); - if (disabled === undefined) disabled = false; - this.enable(!disabled); - - var readonly = el.prop("readonly"); - if (readonly === undefined) readonly = false; - this.readonly(readonly); - - syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass); - this.container.addClass(evaluate(this.opts.containerCssClass)); - - syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass); - this.dropdown.addClass(evaluate(this.opts.dropdownCssClass)); - - }); - - // IE8-10 - el.on("propertychange.select2", sync); - - // hold onto a reference of the callback to work around a chromium bug - if (this.mutationCallback === undefined) { - this.mutationCallback = function (mutations) { - mutations.forEach(sync); - } - } - - // safari, chrome, firefox, IE11 - observer = window.MutationObserver || window.WebKitMutationObserver|| window.MozMutationObserver; - if (observer !== undefined) { - if (this.propertyObserver) { delete this.propertyObserver; this.propertyObserver = null; } - this.propertyObserver = new observer(this.mutationCallback); - this.propertyObserver.observe(el.get(0), { attributes:true, subtree:false }); - } - }, - - // abstract - triggerSelect: function(data) { - var evt = $.Event("select2-selecting", { val: this.id(data), object: data }); - this.opts.element.trigger(evt); - return !evt.isDefaultPrevented(); - }, - - /** - * Triggers the change event on the source element - */ - // abstract - triggerChange: function (details) { - - details = details || {}; - details= $.extend({}, details, { type: "change", val: this.val() }); - // prevents recursive triggering - this.opts.element.data("select2-change-triggered", true); - this.opts.element.trigger(details); - this.opts.element.data("select2-change-triggered", false); - - // some validation frameworks ignore the change event and listen instead to keyup, click for selects - // so here we trigger the click event manually - this.opts.element.click(); - - // ValidationEngine ignores the change event and listens instead to blur - // so here we trigger the blur event manually if so desired - if (this.opts.blurOnChange) - this.opts.element.blur(); - }, - - //abstract - isInterfaceEnabled: function() - { - return this.enabledInterface === true; - }, - - // abstract - enableInterface: function() { - var enabled = this._enabled && !this._readonly, - disabled = !enabled; - - if (enabled === this.enabledInterface) return false; - - this.container.toggleClass("select2-container-disabled", disabled); - this.close(); - this.enabledInterface = enabled; - - return true; - }, - - // abstract - enable: function(enabled) { - if (enabled === undefined) enabled = true; - if (this._enabled === enabled) return; - this._enabled = enabled; - - this.opts.element.prop("disabled", !enabled); - this.enableInterface(); - }, - - // abstract - disable: function() { - this.enable(false); - }, - - // abstract - readonly: function(enabled) { - if (enabled === undefined) enabled = false; - if (this._readonly === enabled) return; - this._readonly = enabled; - - this.opts.element.prop("readonly", enabled); - this.enableInterface(); - }, - - // abstract - opened: function () { - return this.container.hasClass("select2-dropdown-open"); - }, - - // abstract - positionDropdown: function() { - var $dropdown = this.dropdown, - offset = this.container.offset(), - height = this.container.outerHeight(false), - width = this.container.outerWidth(false), - dropHeight = $dropdown.outerHeight(false), - $window = $(window), - windowWidth = $window.width(), - windowHeight = $window.height(), - viewPortRight = $window.scrollLeft() + windowWidth, - viewportBottom = $window.scrollTop() + windowHeight, - dropTop = offset.top + height, - dropLeft = offset.left, - enoughRoomBelow = dropTop + dropHeight <= viewportBottom, - enoughRoomAbove = (offset.top - dropHeight) >= this.body().scrollTop(), - dropWidth = $dropdown.outerWidth(false), - enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight, - aboveNow = $dropdown.hasClass("select2-drop-above"), - bodyOffset, - above, - changeDirection, - css, - resultsListNode; - - // always prefer the current above/below alignment, unless there is not enough room - if (aboveNow) { - above = true; - if (!enoughRoomAbove && enoughRoomBelow) { - changeDirection = true; - above = false; - } - } else { - above = false; - if (!enoughRoomBelow && enoughRoomAbove) { - changeDirection = true; - above = true; - } - } - - //if we are changing direction we need to get positions when dropdown is hidden; - if (changeDirection) { - $dropdown.hide(); - offset = this.container.offset(); - height = this.container.outerHeight(false); - width = this.container.outerWidth(false); - dropHeight = $dropdown.outerHeight(false); - viewPortRight = $window.scrollLeft() + windowWidth; - viewportBottom = $window.scrollTop() + windowHeight; - dropTop = offset.top + height; - dropLeft = offset.left; - dropWidth = $dropdown.outerWidth(false); - enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight; - $dropdown.show(); - } - - if (this.opts.dropdownAutoWidth) { - resultsListNode = $('.select2-results', $dropdown)[0]; - $dropdown.addClass('select2-drop-auto-width'); - $dropdown.css('width', ''); - // Add scrollbar width to dropdown if vertical scrollbar is present - dropWidth = $dropdown.outerWidth(false) + (resultsListNode.scrollHeight === resultsListNode.clientHeight ? 0 : scrollBarDimensions.width); - dropWidth > width ? width = dropWidth : dropWidth = width; - enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight; - } - else { - this.container.removeClass('select2-drop-auto-width'); - } - - //console.log("below/ droptop:", dropTop, "dropHeight", dropHeight, "sum", (dropTop+dropHeight)+" viewport bottom", viewportBottom, "enough?", enoughRoomBelow); - //console.log("above/ offset.top", offset.top, "dropHeight", dropHeight, "top", (offset.top-dropHeight), "scrollTop", this.body().scrollTop(), "enough?", enoughRoomAbove); - - // fix positioning when body has an offset and is not position: static - if (this.body().css('position') !== 'static') { - bodyOffset = this.body().offset(); - dropTop -= bodyOffset.top; - dropLeft -= bodyOffset.left; - } - - if (!enoughRoomOnRight) { - dropLeft = offset.left + this.container.outerWidth(false) - dropWidth; - } - - css = { - left: dropLeft, - width: width - }; - - if (above) { - css.top = offset.top - dropHeight; - css.bottom = 'auto'; - this.container.addClass("select2-drop-above"); - $dropdown.addClass("select2-drop-above"); - } - else { - css.top = dropTop; - css.bottom = 'auto'; - this.container.removeClass("select2-drop-above"); - $dropdown.removeClass("select2-drop-above"); - } - css = $.extend(css, evaluate(this.opts.dropdownCss)); - - $dropdown.css(css); - }, - - // abstract - shouldOpen: function() { - var event; - - if (this.opened()) return false; - - if (this._enabled === false || this._readonly === true) return false; - - event = $.Event("select2-opening"); - this.opts.element.trigger(event); - return !event.isDefaultPrevented(); - }, - - // abstract - clearDropdownAlignmentPreference: function() { - // clear the classes used to figure out the preference of where the dropdown should be opened - this.container.removeClass("select2-drop-above"); - this.dropdown.removeClass("select2-drop-above"); - }, - - /** - * Opens the dropdown - * - * @return {Boolean} whether or not dropdown was opened. This method will return false if, for example, - * the dropdown is already open, or if the 'open' event listener on the element called preventDefault(). - */ - // abstract - open: function () { - - if (!this.shouldOpen()) return false; - - this.opening(); - - return true; - }, - - /** - * Performs the opening of the dropdown - */ - // abstract - opening: function() { - var cid = this.containerId, - scroll = "scroll." + cid, - resize = "resize."+cid, - orient = "orientationchange."+cid, - mask; - - this.container.addClass("select2-dropdown-open").addClass("select2-container-active"); - - this.clearDropdownAlignmentPreference(); - - if(this.dropdown[0] !== this.body().children().last()[0]) { - this.dropdown.detach().appendTo(this.body()); - } - - // create the dropdown mask if doesn't already exist - mask = $("#select2-drop-mask"); - if (mask.length == 0) { - mask = $(document.createElement("div")); - mask.attr("id","select2-drop-mask").attr("class","select2-drop-mask"); - mask.hide(); - mask.appendTo(this.body()); - mask.on("mousedown touchstart click", function (e) { - // Prevent IE from generating a click event on the body - reinsertElement(mask); - - var dropdown = $("#select2-drop"), self; - if (dropdown.length > 0) { - self=dropdown.data("select2"); - if (self.opts.selectOnBlur) { - self.selectHighlighted({noFocus: true}); - } - self.close({focus:true}); - e.preventDefault(); - e.stopPropagation(); - } - }); - } - - // ensure the mask is always right before the dropdown - if (this.dropdown.prev()[0] !== mask[0]) { - this.dropdown.before(mask); - } - - // move the global id to the correct dropdown - $("#select2-drop").removeAttr("id"); - this.dropdown.attr("id", "select2-drop"); - - // show the elements - mask.show(); - - this.positionDropdown(); - this.dropdown.show(); - this.positionDropdown(); - - this.dropdown.addClass("select2-drop-active"); - - // attach listeners to events that can change the position of the container and thus require - // the position of the dropdown to be updated as well so it does not come unglued from the container - var that = this; - this.container.parents().add(window).each(function () { - $(this).on(resize+" "+scroll+" "+orient, function (e) { - that.positionDropdown(); - }); - }); - - - }, - - // abstract - close: function () { - if (!this.opened()) return; - - var cid = this.containerId, - scroll = "scroll." + cid, - resize = "resize."+cid, - orient = "orientationchange."+cid; - - // unbind event listeners - this.container.parents().add(window).each(function () { $(this).off(scroll).off(resize).off(orient); }); - - this.clearDropdownAlignmentPreference(); - - $("#select2-drop-mask").hide(); - this.dropdown.removeAttr("id"); // only the active dropdown has the select2-drop id - this.dropdown.hide(); - this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active"); - this.results.empty(); - - - this.clearSearch(); - this.search.removeClass("select2-active"); - this.opts.element.trigger($.Event("select2-close")); - }, - - /** - * Opens control, sets input value, and updates results. - */ - // abstract - externalSearch: function (term) { - this.open(); - this.search.val(term); - this.updateResults(false); - }, - - // abstract - clearSearch: function () { - - }, - - //abstract - getMaximumSelectionSize: function() { - return evaluate(this.opts.maximumSelectionSize); - }, - - // abstract - ensureHighlightVisible: function () { - var results = this.results, children, index, child, hb, rb, y, more; - - index = this.highlight(); - - if (index < 0) return; - - if (index == 0) { - - // if the first element is highlighted scroll all the way to the top, - // that way any unselectable headers above it will also be scrolled - // into view - - results.scrollTop(0); - return; - } - - children = this.findHighlightableChoices().find('.select2-result-label'); - - child = $(children[index]); - - hb = child.offset().top + child.outerHeight(true); - - // if this is the last child lets also make sure select2-more-results is visible - if (index === children.length - 1) { - more = results.find("li.select2-more-results"); - if (more.length > 0) { - hb = more.offset().top + more.outerHeight(true); - } - } - - rb = results.offset().top + results.outerHeight(true); - if (hb > rb) { - results.scrollTop(results.scrollTop() + (hb - rb)); - } - y = child.offset().top - results.offset().top; - - // make sure the top of the element is visible - if (y < 0 && child.css('display') != 'none' ) { - results.scrollTop(results.scrollTop() + y); // y is negative - } - }, - - // abstract - findHighlightableChoices: function() { - return this.results.find(".select2-result-selectable:not(.select2-disabled):not(.select2-selected)"); - }, - - // abstract - moveHighlight: function (delta) { - var choices = this.findHighlightableChoices(), - index = this.highlight(); - - while (index > -1 && index < choices.length) { - index += delta; - var choice = $(choices[index]); - if (choice.hasClass("select2-result-selectable") && !choice.hasClass("select2-disabled") && !choice.hasClass("select2-selected")) { - this.highlight(index); - break; - } - } - }, - - // abstract - highlight: function (index) { - var choices = this.findHighlightableChoices(), - choice, - data; - - if (arguments.length === 0) { - return indexOf(choices.filter(".select2-highlighted")[0], choices.get()); - } - - if (index >= choices.length) index = choices.length - 1; - if (index < 0) index = 0; - - this.removeHighlight(); - - choice = $(choices[index]); - choice.addClass("select2-highlighted"); - - // ensure assistive technology can determine the active choice - this.search.attr("aria-activedescendant", choice.find(".select2-result-label").attr("id")); - - this.ensureHighlightVisible(); - - this.liveRegion.text(choice.text()); - - data = choice.data("select2-data"); - if (data) { - this.opts.element.trigger({ type: "select2-highlight", val: this.id(data), choice: data }); - } - }, - - removeHighlight: function() { - this.results.find(".select2-highlighted").removeClass("select2-highlighted"); - }, - - // abstract - countSelectableResults: function() { - return this.findHighlightableChoices().length; - }, - - // abstract - highlightUnderEvent: function (event) { - var el = $(event.target).closest(".select2-result-selectable"); - if (el.length > 0 && !el.is(".select2-highlighted")) { - var choices = this.findHighlightableChoices(); - this.highlight(choices.index(el)); - } else if (el.length == 0) { - // if we are over an unselectable item remove all highlights - this.removeHighlight(); - } - }, - - // abstract - loadMoreIfNeeded: function () { - var results = this.results, - more = results.find("li.select2-more-results"), - below, // pixels the element is below the scroll fold, below==0 is when the element is starting to be visible - page = this.resultsPage + 1, - self=this, - term=this.search.val(), - context=this.context; - - if (more.length === 0) return; - below = more.offset().top - results.offset().top - results.height(); - - if (below <= this.opts.loadMorePadding) { - more.addClass("select2-active"); - this.opts.query({ - element: this.opts.element, - term: term, - page: page, - context: context, - matcher: this.opts.matcher, - callback: this.bind(function (data) { - - // ignore a response if the select2 has been closed before it was received - if (!self.opened()) return; - - - self.opts.populateResults.call(this, results, data.results, {term: term, page: page, context:context}); - self.postprocessResults(data, false, false); - - if (data.more===true) { - more.detach().appendTo(results).text(self.opts.formatLoadMore(page+1)); - window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10); - } else { - more.remove(); - } - self.positionDropdown(); - self.resultsPage = page; - self.context = data.context; - this.opts.element.trigger({ type: "select2-loaded", items: data }); - })}); - } - }, - - /** - * Default tokenizer function which does nothing - */ - tokenize: function() { - - }, - - /** - * @param initial whether or not this is the call to this method right after the dropdown has been opened - */ - // abstract - updateResults: function (initial) { - var search = this.search, - results = this.results, - opts = this.opts, - data, - self = this, - input, - term = search.val(), - lastTerm = $.data(this.container, "select2-last-term"), - // sequence number used to drop out-of-order responses - queryNumber; - - // prevent duplicate queries against the same term - if (initial !== true && lastTerm && equal(term, lastTerm)) return; - - $.data(this.container, "select2-last-term", term); - - // if the search is currently hidden we do not alter the results - if (initial !== true && (this.showSearchInput === false || !this.opened())) { - return; - } - - function postRender() { - search.removeClass("select2-active"); - self.positionDropdown(); - if (results.find('.select2-no-results,.select2-selection-limit,.select2-searching').length) { - self.liveRegion.text(results.text()); - } - else { - self.liveRegion.text(self.opts.formatMatches(results.find('.select2-result-selectable').length)); - } - } - - function render(html) { - results.html(html); - postRender(); - } - - queryNumber = ++this.queryCount; - - var maxSelSize = this.getMaximumSelectionSize(); - if (maxSelSize >=1) { - data = this.data(); - if ($.isArray(data) && data.length >= maxSelSize && checkFormatter(opts.formatSelectionTooBig, "formatSelectionTooBig")) { - render("<li class='select2-selection-limit'>" + evaluate(opts.formatSelectionTooBig, maxSelSize) + "</li>"); - return; - } - } - - if (search.val().length < opts.minimumInputLength) { - if (checkFormatter(opts.formatInputTooShort, "formatInputTooShort")) { - render("<li class='select2-no-results'>" + evaluate(opts.formatInputTooShort, search.val(), opts.minimumInputLength) + "</li>"); - } else { - render(""); - } - if (initial && this.showSearch) this.showSearch(true); - return; - } - - if (opts.maximumInputLength && search.val().length > opts.maximumInputLength) { - if (checkFormatter(opts.formatInputTooLong, "formatInputTooLong")) { - render("<li class='select2-no-results'>" + evaluate(opts.formatInputTooLong, search.val(), opts.maximumInputLength) + "</li>"); - } else { - render(""); - } - return; - } - - if (opts.formatSearching && this.findHighlightableChoices().length === 0) { - render("<li class='select2-searching'>" + evaluate(opts.formatSearching) + "</li>"); - } - - search.addClass("select2-active"); - - this.removeHighlight(); - - // give the tokenizer a chance to pre-process the input - input = this.tokenize(); - if (input != undefined && input != null) { - search.val(input); - } - - this.resultsPage = 1; - - opts.query({ - element: opts.element, - term: search.val(), - page: this.resultsPage, - context: null, - matcher: opts.matcher, - callback: this.bind(function (data) { - var def; // default choice - - // ignore old responses - if (queryNumber != this.queryCount) { - return; - } - - // ignore a response if the select2 has been closed before it was received - if (!this.opened()) { - this.search.removeClass("select2-active"); - return; - } - - // save context, if any - this.context = (data.context===undefined) ? null : data.context; - // create a default choice and prepend it to the list - if (this.opts.createSearchChoice && search.val() !== "") { - def = this.opts.createSearchChoice.call(self, search.val(), data.results); - if (def !== undefined && def !== null && self.id(def) !== undefined && self.id(def) !== null) { - if ($(data.results).filter( - function () { - return equal(self.id(this), self.id(def)); - }).length === 0) { - this.opts.createSearchChoicePosition(data.results, def); - } - } - } - - if (data.results.length === 0 && checkFormatter(opts.formatNoMatches, "formatNoMatches")) { - render("<li class='select2-no-results'>" + evaluate(opts.formatNoMatches, search.val()) + "</li>"); - return; - } - - results.empty(); - self.opts.populateResults.call(this, results, data.results, {term: search.val(), page: this.resultsPage, context:null}); - - if (data.more === true && checkFormatter(opts.formatLoadMore, "formatLoadMore")) { - results.append("<li class='select2-more-results'>" + self.opts.escapeMarkup(evaluate(opts.formatLoadMore, this.resultsPage)) + "</li>"); - window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10); - } - - this.postprocessResults(data, initial); - - postRender(); - - this.opts.element.trigger({ type: "select2-loaded", items: data }); - })}); - }, - - // abstract - cancel: function () { - this.close(); - }, - - // abstract - blur: function () { - // if selectOnBlur == true, select the currently highlighted option - if (this.opts.selectOnBlur) - this.selectHighlighted({noFocus: true}); - - this.close(); - this.container.removeClass("select2-container-active"); - // synonymous to .is(':focus'), which is available in jquery >= 1.6 - if (this.search[0] === document.activeElement) { this.search.blur(); } - this.clearSearch(); - this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); - }, - - // abstract - focusSearch: function () { - focus(this.search); - }, - - // abstract - selectHighlighted: function (options) { - var index=this.highlight(), - highlighted=this.results.find(".select2-highlighted"), - data = highlighted.closest('.select2-result').data("select2-data"); - - if (data) { - this.highlight(index); - this.onSelect(data, options); - } else if (options && options.noFocus) { - this.close(); - } - }, - - // abstract - getPlaceholder: function () { - var placeholderOption; - return this.opts.element.attr("placeholder") || - this.opts.element.attr("data-placeholder") || // jquery 1.4 compat - this.opts.element.data("placeholder") || - this.opts.placeholder || - ((placeholderOption = this.getPlaceholderOption()) !== undefined ? placeholderOption.text() : undefined); - }, - - // abstract - getPlaceholderOption: function() { - if (this.select) { - var firstOption = this.select.children('option').first(); - if (this.opts.placeholderOption !== undefined ) { - //Determine the placeholder option based on the specified placeholderOption setting - return (this.opts.placeholderOption === "first" && firstOption) || - (typeof this.opts.placeholderOption === "function" && this.opts.placeholderOption(this.select)); - } else if (firstOption.text() === "" && firstOption.val() === "") { - //No explicit placeholder option specified, use the first if it's blank - return firstOption; - } - } - }, - - /** - * Get the desired width for the container element. This is - * derived first from option `width` passed to select2, then - * the inline 'style' on the original element, and finally - * falls back to the jQuery calculated element width. - */ - // abstract - initContainerWidth: function () { - function resolveContainerWidth() { - var style, attrs, matches, i, l, attr; - - if (this.opts.width === "off") { - return null; - } else if (this.opts.width === "element"){ - return this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px'; - } else if (this.opts.width === "copy" || this.opts.width === "resolve") { - // check if there is inline style on the element that contains width - style = this.opts.element.attr('style'); - if (style !== undefined) { - attrs = style.split(';'); - for (i = 0, l = attrs.length; i < l; i = i + 1) { - attr = attrs[i].replace(/\s/g, ''); - matches = attr.match(/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i); - if (matches !== null && matches.length >= 1) - return matches[1]; - } - } - - if (this.opts.width === "resolve") { - // next check if css('width') can resolve a width that is percent based, this is sometimes possible - // when attached to input type=hidden or elements hidden via css - style = this.opts.element.css('width'); - if (style.indexOf("%") > 0) return style; - - // finally, fallback on the calculated width of the element - return (this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px'); - } - - return null; - } else if ($.isFunction(this.opts.width)) { - return this.opts.width(); - } else { - return this.opts.width; - } - }; - - var width = resolveContainerWidth.call(this); - if (width !== null) { - this.container.css("width", width); - } - } - }); - - SingleSelect2 = clazz(AbstractSelect2, { - - // single - - createContainer: function () { - var container = $(document.createElement("div")).attr({ - "class": "select2-container" - }).html([ - "<a href='javascript:void(0)' onclick='return false;' class='select2-choice' tabindex='-1'>", - " <span class='select2-chosen'> </span><abbr class='select2-search-choice-close'></abbr>", - " <span class='select2-arrow' role='presentation'><b role='presentation'></b></span>", - "</a>", - "<label for='' class='select2-offscreen'></label>", - "<input class='select2-focusser select2-offscreen' type='text' aria-haspopup='true' role='button' />", - "<div class='select2-drop select2-display-none'>", - " <div class='select2-search'>", - " <label for='' class='select2-offscreen'></label>", - " <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input' role='combobox' aria-expanded='true'", - " aria-autocomplete='list' />", - " </div>", - " <ul class='select2-results' role='listbox'>", - " </ul>", - "</div>"].join("")); - return container; - }, - - // single - enableInterface: function() { - if (this.parent.enableInterface.apply(this, arguments)) { - this.focusser.prop("disabled", !this.isInterfaceEnabled()); - } - }, - - // single - opening: function () { - var el, range, len; - - if (this.opts.minimumResultsForSearch >= 0) { - this.showSearch(true); - } - - this.parent.opening.apply(this, arguments); - - if (this.showSearchInput !== false) { - // IE appends focusser.val() at the end of field :/ so we manually insert it at the beginning using a range - // all other browsers handle this just fine - - this.search.val(this.focusser.val()); - } - this.search.focus(); - // move the cursor to the end after focussing, otherwise it will be at the beginning and - // new text will appear *before* focusser.val() - el = this.search.get(0); - if (el.createTextRange) { - range = el.createTextRange(); - range.collapse(false); - range.select(); - } else if (el.setSelectionRange) { - len = this.search.val().length; - el.setSelectionRange(len, len); - } - - // initializes search's value with nextSearchTerm (if defined by user) - // ignore nextSearchTerm if the dropdown is opened by the user pressing a letter - if(this.search.val() === "") { - if(this.nextSearchTerm != undefined){ - this.search.val(this.nextSearchTerm); - this.search.select(); - } - } - - this.focusser.prop("disabled", true).val(""); - this.updateResults(true); - this.opts.element.trigger($.Event("select2-open")); - }, - - // single - close: function (params) { - if (!this.opened()) return; - this.parent.close.apply(this, arguments); - - params = params || {focus: true}; - this.focusser.prop("disabled", false); - - if (params.focus) { - this.focusser.focus(); - } - }, - - // single - focus: function () { - if (this.opened()) { - this.close(); - } else { - this.focusser.prop("disabled", false); - this.focusser.focus(); - } - }, - - // single - isFocused: function () { - return this.container.hasClass("select2-container-active"); - }, - - // single - cancel: function () { - this.parent.cancel.apply(this, arguments); - this.focusser.prop("disabled", false); - this.focusser.focus(); - }, - - // single - destroy: function() { - $("label[for='" + this.focusser.attr('id') + "']") - .attr('for', this.opts.element.attr("id")); - this.parent.destroy.apply(this, arguments); - }, - - // single - initContainer: function () { - - var selection, - container = this.container, - dropdown = this.dropdown, - idSuffix = nextUid(), - elementLabel; - - if (this.opts.minimumResultsForSearch < 0) { - this.showSearch(false); - } else { - this.showSearch(true); - } - - this.selection = selection = container.find(".select2-choice"); - - this.focusser = container.find(".select2-focusser"); - - // add aria associations - selection.find(".select2-chosen").attr("id", "select2-chosen-"+idSuffix); - this.focusser.attr("aria-labelledby", "select2-chosen-"+idSuffix); - this.results.attr("id", "select2-results-"+idSuffix); - this.search.attr("aria-owns", "select2-results-"+idSuffix); - - // rewrite labels from original element to focusser - this.focusser.attr("id", "s2id_autogen"+idSuffix); - - elementLabel = $("label[for='" + this.opts.element.attr("id") + "']"); - - this.focusser.prev() - .text(elementLabel.text()) - .attr('for', this.focusser.attr('id')); - - // Ensure the original element retains an accessible name - var originalTitle = this.opts.element.attr("title"); - this.opts.element.attr("title", (originalTitle || elementLabel.text())); - - this.focusser.attr("tabindex", this.elementTabIndex); - - // write label for search field using the label from the focusser element - this.search.attr("id", this.focusser.attr('id') + '_search'); - - this.search.prev() - .text($("label[for='" + this.focusser.attr('id') + "']").text()) - .attr('for', this.search.attr('id')); - - this.search.on("keydown", this.bind(function (e) { - if (!this.isInterfaceEnabled()) return; - - if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) { - // prevent the page from scrolling - killEvent(e); - return; - } - - switch (e.which) { - case KEY.UP: - case KEY.DOWN: - this.moveHighlight((e.which === KEY.UP) ? -1 : 1); - killEvent(e); - return; - case KEY.ENTER: - this.selectHighlighted(); - killEvent(e); - return; - case KEY.TAB: - this.selectHighlighted({noFocus: true}); - return; - case KEY.ESC: - this.cancel(e); - killEvent(e); - return; - } - })); - - this.search.on("blur", this.bind(function(e) { - // a workaround for chrome to keep the search field focussed when the scroll bar is used to scroll the dropdown. - // without this the search field loses focus which is annoying - if (document.activeElement === this.body().get(0)) { - window.setTimeout(this.bind(function() { - if (this.opened()) { - this.search.focus(); - } - }), 0); - } - })); - - this.focusser.on("keydown", this.bind(function (e) { - if (!this.isInterfaceEnabled()) return; - - if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) { - return; - } - - if (this.opts.openOnEnter === false && e.which === KEY.ENTER) { - killEvent(e); - return; - } - - if (e.which == KEY.DOWN || e.which == KEY.UP - || (e.which == KEY.ENTER && this.opts.openOnEnter)) { - - if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) return; - - this.open(); - killEvent(e); - return; - } - - if (e.which == KEY.DELETE || e.which == KEY.BACKSPACE) { - if (this.opts.allowClear) { - this.clear(); - } - killEvent(e); - return; - } - })); - - - installKeyUpChangeEvent(this.focusser); - this.focusser.on("keyup-change input", this.bind(function(e) { - if (this.opts.minimumResultsForSearch >= 0) { - e.stopPropagation(); - if (this.opened()) return; - this.open(); - } - })); - - selection.on("mousedown touchstart", "abbr", this.bind(function (e) { - if (!this.isInterfaceEnabled()) return; - this.clear(); - killEventImmediately(e); - this.close(); - this.selection.focus(); - })); - - selection.on("mousedown touchstart", this.bind(function (e) { - // Prevent IE from generating a click event on the body - reinsertElement(selection); - - if (!this.container.hasClass("select2-container-active")) { - this.opts.element.trigger($.Event("select2-focus")); - } - - if (this.opened()) { - this.close(); - } else if (this.isInterfaceEnabled()) { - this.open(); - } - - killEvent(e); - })); - - dropdown.on("mousedown touchstart", this.bind(function() { this.search.focus(); })); - - selection.on("focus", this.bind(function(e) { - killEvent(e); - })); - - this.focusser.on("focus", this.bind(function(){ - if (!this.container.hasClass("select2-container-active")) { - this.opts.element.trigger($.Event("select2-focus")); - } - this.container.addClass("select2-container-active"); - })).on("blur", this.bind(function() { - if (!this.opened()) { - this.container.removeClass("select2-container-active"); - this.opts.element.trigger($.Event("select2-blur")); - } - })); - this.search.on("focus", this.bind(function(){ - if (!this.container.hasClass("select2-container-active")) { - this.opts.element.trigger($.Event("select2-focus")); - } - this.container.addClass("select2-container-active"); - })); - - this.initContainerWidth(); - this.opts.element.addClass("select2-offscreen"); - this.setPlaceholder(); - - }, - - // single - clear: function(triggerChange) { - var data=this.selection.data("select2-data"); - if (data) { // guard against queued quick consecutive clicks - var evt = $.Event("select2-clearing"); - this.opts.element.trigger(evt); - if (evt.isDefaultPrevented()) { - return; - } - var placeholderOption = this.getPlaceholderOption(); - this.opts.element.val(placeholderOption ? placeholderOption.val() : ""); - this.selection.find(".select2-chosen").empty(); - this.selection.removeData("select2-data"); - this.setPlaceholder(); - - if (triggerChange !== false){ - this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data }); - this.triggerChange({removed:data}); - } - } - }, - - /** - * Sets selection based on source element's value - */ - // single - initSelection: function () { - var selected; - if (this.isPlaceholderOptionSelected()) { - this.updateSelection(null); - this.close(); - this.setPlaceholder(); - } else { - var self = this; - this.opts.initSelection.call(null, this.opts.element, function(selected){ - if (selected !== undefined && selected !== null) { - self.updateSelection(selected); - self.close(); - self.setPlaceholder(); - self.nextSearchTerm = self.opts.nextSearchTerm(selected, self.search.val()); - } - }); - } - }, - - isPlaceholderOptionSelected: function() { - var placeholderOption; - if (!this.getPlaceholder()) return false; // no placeholder specified so no option should be considered - return ((placeholderOption = this.getPlaceholderOption()) !== undefined && placeholderOption.prop("selected")) - || (this.opts.element.val() === "") - || (this.opts.element.val() === undefined) - || (this.opts.element.val() === null); - }, - - // single - prepareOpts: function () { - var opts = this.parent.prepareOpts.apply(this, arguments), - self=this; - - if (opts.element.get(0).tagName.toLowerCase() === "select") { - // install the selection initializer - opts.initSelection = function (element, callback) { - var selected = element.find("option").filter(function() { return this.selected }); - // a single select box always has a value, no need to null check 'selected' - callback(self.optionToData(selected)); - }; - } else if ("data" in opts) { - // install default initSelection when applied to hidden input and data is local - opts.initSelection = opts.initSelection || function (element, callback) { - var id = element.val(); - //search in data by id, storing the actual matching item - var match = null; - opts.query({ - matcher: function(term, text, el){ - var is_match = equal(id, opts.id(el)); - if (is_match) { - match = el; - } - return is_match; - }, - callback: !$.isFunction(callback) ? $.noop : function() { - callback(match); - } - }); - }; - } - - return opts; - }, - - // single - getPlaceholder: function() { - // if a placeholder is specified on a single select without a valid placeholder option ignore it - if (this.select) { - if (this.getPlaceholderOption() === undefined) { - return undefined; - } - } - - return this.parent.getPlaceholder.apply(this, arguments); - }, - - // single - setPlaceholder: function () { - var placeholder = this.getPlaceholder(); - - if (this.isPlaceholderOptionSelected() && placeholder !== undefined) { - - // check for a placeholder option if attached to a select - if (this.select && this.getPlaceholderOption() === undefined) return; - - this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(placeholder)); - - this.selection.addClass("select2-default"); - - this.container.removeClass("select2-allowclear"); - } - }, - - // single - postprocessResults: function (data, initial, noHighlightUpdate) { - var selected = 0, selectedElm = null, self = this, showSearchInput = true; - - // find the selected element in the result list - - this.findHighlightableChoices().each2(function (i, elm) { - if (equal(self.id(elm.data("select2-data")), self.opts.element.val())) { - selected = i; - selectedElm = elm; - return false; - } - }); - - // and highlight it - if (noHighlightUpdate !== false) { - if (initial === true && selected >= 0) { - // By default, the selected item is displayed inside the result list from a single select - // User can provide an implementation for 'hideSelectionFromResult' and hide it - if(selectedElm !== null) { - if(this.opts.hideSelectionFromResult(selectedElm)) - selectedElm.addClass("select2-selected"); - } - else - this.highlight(selected); - } else { - this.highlight(0); - } - } - - // hide the search box if this is the first we got the results and there are enough of them for search - - if (initial === true) { - var min = this.opts.minimumResultsForSearch; - if (min >= 0) { - this.showSearch(countResults(data.results) >= min); - } - } - }, - - // single - showSearch: function(showSearchInput) { - if (this.showSearchInput === showSearchInput) return; - - this.showSearchInput = showSearchInput; - - this.dropdown.find(".select2-search").toggleClass("select2-search-hidden", !showSearchInput); - this.dropdown.find(".select2-search").toggleClass("select2-offscreen", !showSearchInput); - //add "select2-with-searchbox" to the container if search box is shown - $(this.dropdown, this.container).toggleClass("select2-with-searchbox", showSearchInput); - }, - - // single - onSelect: function (data, options) { - - if (!this.triggerSelect(data)) { return; } - - var old = this.opts.element.val(), - oldData = this.data(); - - this.opts.element.val(this.id(data)); - this.updateSelection(data); - - this.opts.element.trigger({ type: "select2-selected", val: this.id(data), choice: data }); - - this.nextSearchTerm = this.opts.nextSearchTerm(data, this.search.val()); - this.close(); - - if (!options || !options.noFocus) - this.focusser.focus(); - - if (!equal(old, this.id(data))) { this.triggerChange({added:data,removed:oldData}); } - }, - - // single - updateSelection: function (data) { - - var container=this.selection.find(".select2-chosen"), formatted, cssClass; - - this.selection.data("select2-data", data); - - container.empty(); - if (data !== null) { - formatted=this.opts.formatSelection(data, container, this.opts.escapeMarkup); - } - if (formatted !== undefined) { - container.append(formatted); - } - cssClass=this.opts.formatSelectionCssClass(data, container); - if (cssClass !== undefined) { - container.addClass(cssClass); - } - - this.selection.removeClass("select2-default"); - - if (this.opts.allowClear && this.getPlaceholder() !== undefined) { - this.container.addClass("select2-allowclear"); - } - }, - - // single - val: function () { - var val, - triggerChange = false, - data = null, - self = this, - oldData = this.data(); - - if (arguments.length === 0) { - return this.opts.element.val(); - } - - val = arguments[0]; - - if (arguments.length > 1) { - triggerChange = arguments[1]; - } - - if (this.select) { - this.select - .val(val) - .find("option").filter(function() { return this.selected }).each2(function (i, elm) { - data = self.optionToData(elm); - return false; - }); - this.updateSelection(data); - this.setPlaceholder(); - if (triggerChange) { - this.triggerChange({added: data, removed:oldData}); - } - } else { - // val is an id. !val is true for [undefined,null,'',0] - 0 is legal - if (!val && val !== 0) { - this.clear(triggerChange); - return; - } - if (this.opts.initSelection === undefined) { - throw new Error("cannot call val() if initSelection() is not defined"); - } - this.opts.element.val(val); - this.opts.initSelection(this.opts.element, function(data){ - self.opts.element.val(!data ? "" : self.id(data)); - self.updateSelection(data); - self.setPlaceholder(); - if (triggerChange) { - self.triggerChange({added: data, removed:oldData}); - } - }); - } - }, - - // single - clearSearch: function () { - this.search.val(""); - this.focusser.val(""); - }, - - // single - data: function(value) { - var data, - triggerChange = false; - - if (arguments.length === 0) { - data = this.selection.data("select2-data"); - if (data == undefined) data = null; - return data; - } else { - if (arguments.length > 1) { - triggerChange = arguments[1]; - } - if (!value) { - this.clear(triggerChange); - } else { - data = this.data(); - this.opts.element.val(!value ? "" : this.id(value)); - this.updateSelection(value); - if (triggerChange) { - this.triggerChange({added: value, removed:data}); - } - } - } - } - }); - - MultiSelect2 = clazz(AbstractSelect2, { - - // multi - createContainer: function () { - var container = $(document.createElement("div")).attr({ - "class": "select2-container select2-container-multi" - }).html([ - "<ul class='select2-choices'>", - " <li class='select2-search-field'>", - " <label for='' class='select2-offscreen'></label>", - " <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'>", - " </li>", - "</ul>", - "<div class='select2-drop select2-drop-multi select2-display-none'>", - " <ul class='select2-results'>", - " </ul>", - "</div>"].join("")); - return container; - }, - - // multi - prepareOpts: function () { - var opts = this.parent.prepareOpts.apply(this, arguments), - self=this; - - // TODO validate placeholder is a string if specified - - if (opts.element.get(0).tagName.toLowerCase() === "select") { - // install the selection initializer - opts.initSelection = function (element, callback) { - - var data = []; - - element.find("option").filter(function() { return this.selected }).each2(function (i, elm) { - data.push(self.optionToData(elm)); - }); - callback(data); - }; - } else if ("data" in opts) { - // install default initSelection when applied to hidden input and data is local - opts.initSelection = opts.initSelection || function (element, callback) { - var ids = splitVal(element.val(), opts.separator); - //search in data by array of ids, storing matching items in a list - var matches = []; - opts.query({ - matcher: function(term, text, el){ - var is_match = $.grep(ids, function(id) { - return equal(id, opts.id(el)); - }).length; - if (is_match) { - matches.push(el); - } - return is_match; - }, - callback: !$.isFunction(callback) ? $.noop : function() { - // reorder matches based on the order they appear in the ids array because right now - // they are in the order in which they appear in data array - var ordered = []; - for (var i = 0; i < ids.length; i++) { - var id = ids[i]; - for (var j = 0; j < matches.length; j++) { - var match = matches[j]; - if (equal(id, opts.id(match))) { - ordered.push(match); - matches.splice(j, 1); - break; - } - } - } - callback(ordered); - } - }); - }; - } - - return opts; - }, - - // multi - selectChoice: function (choice) { - - var selected = this.container.find(".select2-search-choice-focus"); - if (selected.length && choice && choice[0] == selected[0]) { - - } else { - if (selected.length) { - this.opts.element.trigger("choice-deselected", selected); - } - selected.removeClass("select2-search-choice-focus"); - if (choice && choice.length) { - this.close(); - choice.addClass("select2-search-choice-focus"); - this.opts.element.trigger("choice-selected", choice); - } - } - }, - - // multi - destroy: function() { - $("label[for='" + this.search.attr('id') + "']") - .attr('for', this.opts.element.attr("id")); - this.parent.destroy.apply(this, arguments); - }, - - // multi - initContainer: function () { - - var selector = ".select2-choices", selection; - - this.searchContainer = this.container.find(".select2-search-field"); - this.selection = selection = this.container.find(selector); - - var _this = this; - this.selection.on("click", ".select2-search-choice:not(.select2-locked)", function (e) { - //killEvent(e); - _this.search[0].focus(); - _this.selectChoice($(this)); - }); - - // rewrite labels from original element to focusser - this.search.attr("id", "s2id_autogen"+nextUid()); - - this.search.prev() - .text($("label[for='" + this.opts.element.attr("id") + "']").text()) - .attr('for', this.search.attr('id')); - - this.search.on("input paste", this.bind(function() { - if (!this.isInterfaceEnabled()) return; - if (!this.opened()) { - this.open(); - } - })); - - this.search.attr("tabindex", this.elementTabIndex); - - this.keydowns = 0; - this.search.on("keydown", this.bind(function (e) { - if (!this.isInterfaceEnabled()) return; - - ++this.keydowns; - var selected = selection.find(".select2-search-choice-focus"); - var prev = selected.prev(".select2-search-choice:not(.select2-locked)"); - var next = selected.next(".select2-search-choice:not(.select2-locked)"); - var pos = getCursorInfo(this.search); - - if (selected.length && - (e.which == KEY.LEFT || e.which == KEY.RIGHT || e.which == KEY.BACKSPACE || e.which == KEY.DELETE || e.which == KEY.ENTER)) { - var selectedChoice = selected; - if (e.which == KEY.LEFT && prev.length) { - selectedChoice = prev; - } - else if (e.which == KEY.RIGHT) { - selectedChoice = next.length ? next : null; - } - else if (e.which === KEY.BACKSPACE) { - this.unselect(selected.first()); - this.search.width(10); - selectedChoice = prev.length ? prev : next; - } else if (e.which == KEY.DELETE) { - this.unselect(selected.first()); - this.search.width(10); - selectedChoice = next.length ? next : null; - } else if (e.which == KEY.ENTER) { - selectedChoice = null; - } - - this.selectChoice(selectedChoice); - killEvent(e); - if (!selectedChoice || !selectedChoice.length) { - this.open(); - } - return; - } else if (((e.which === KEY.BACKSPACE && this.keydowns == 1) - || e.which == KEY.LEFT) && (pos.offset == 0 && !pos.length)) { - - this.selectChoice(selection.find(".select2-search-choice:not(.select2-locked)").last()); - killEvent(e); - return; - } else { - this.selectChoice(null); - } - - if (this.opened()) { - switch (e.which) { - case KEY.UP: - case KEY.DOWN: - this.moveHighlight((e.which === KEY.UP) ? -1 : 1); - killEvent(e); - return; - case KEY.ENTER: - this.selectHighlighted(); - killEvent(e); - return; - case KEY.TAB: - this.selectHighlighted({noFocus:true}); - this.close(); - return; - case KEY.ESC: - this.cancel(e); - killEvent(e); - return; - } - } - - if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) - || e.which === KEY.BACKSPACE || e.which === KEY.ESC) { - return; - } - - if (e.which === KEY.ENTER) { - if (this.opts.openOnEnter === false) { - return; - } else if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) { - return; - } - } - - this.open(); - - if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) { - // prevent the page from scrolling - killEvent(e); - } - - if (e.which === KEY.ENTER) { - // prevent form from being submitted - killEvent(e); - } - - })); - - this.search.on("keyup", this.bind(function (e) { - this.keydowns = 0; - this.resizeSearch(); - }) - ); - - this.search.on("blur", this.bind(function(e) { - this.container.removeClass("select2-container-active"); - this.search.removeClass("select2-focused"); - this.selectChoice(null); - if (!this.opened()) this.clearSearch(); - e.stopImmediatePropagation(); - this.opts.element.trigger($.Event("select2-blur")); - })); - - this.container.on("click", selector, this.bind(function (e) { - if (!this.isInterfaceEnabled()) return; - if ($(e.target).closest(".select2-search-choice").length > 0) { - // clicked inside a select2 search choice, do not open - return; - } - this.selectChoice(null); - this.clearPlaceholder(); - if (!this.container.hasClass("select2-container-active")) { - this.opts.element.trigger($.Event("select2-focus")); - } - this.open(); - this.focusSearch(); - e.preventDefault(); - })); - - this.container.on("focus", selector, this.bind(function () { - if (!this.isInterfaceEnabled()) return; - if (!this.container.hasClass("select2-container-active")) { - this.opts.element.trigger($.Event("select2-focus")); - } - this.container.addClass("select2-container-active"); - this.dropdown.addClass("select2-drop-active"); - this.clearPlaceholder(); - })); - - this.initContainerWidth(); - this.opts.element.addClass("select2-offscreen"); - - // set the placeholder if necessary - this.clearSearch(); - }, - - // multi - enableInterface: function() { - if (this.parent.enableInterface.apply(this, arguments)) { - this.search.prop("disabled", !this.isInterfaceEnabled()); - } - }, - - // multi - initSelection: function () { - var data; - if (this.opts.element.val() === "" && this.opts.element.text() === "") { - this.updateSelection([]); - this.close(); - // set the placeholder if necessary - this.clearSearch(); - } - if (this.select || this.opts.element.val() !== "") { - var self = this; - this.opts.initSelection.call(null, this.opts.element, function(data){ - if (data !== undefined && data !== null) { - self.updateSelection(data); - self.close(); - // set the placeholder if necessary - self.clearSearch(); - } - }); - } - }, - - // multi - clearSearch: function () { - var placeholder = this.getPlaceholder(), - maxWidth = this.getMaxSearchWidth(); - - if (placeholder !== undefined && this.getVal().length === 0 && this.search.hasClass("select2-focused") === false) { - this.search.val(placeholder).addClass("select2-default"); - // stretch the search box to full width of the container so as much of the placeholder is visible as possible - // we could call this.resizeSearch(), but we do not because that requires a sizer and we do not want to create one so early because of a firefox bug, see #944 - this.search.width(maxWidth > 0 ? maxWidth : this.container.css("width")); - } else { - this.search.val("").width(10); - } - }, - - // multi - clearPlaceholder: function () { - if (this.search.hasClass("select2-default")) { - this.search.val("").removeClass("select2-default"); - } - }, - - // multi - opening: function () { - this.clearPlaceholder(); // should be done before super so placeholder is not used to search - this.resizeSearch(); - - this.parent.opening.apply(this, arguments); - - this.focusSearch(); - - // initializes search's value with nextSearchTerm (if defined by user) - // ignore nextSearchTerm if the dropdown is opened by the user pressing a letter - if(this.search.val() === "") { - if(this.nextSearchTerm != undefined){ - this.search.val(this.nextSearchTerm); - this.search.select(); - } - } - - this.updateResults(true); - this.search.focus(); - this.opts.element.trigger($.Event("select2-open")); - }, - - // multi - close: function () { - if (!this.opened()) return; - this.parent.close.apply(this, arguments); - }, - - // multi - focus: function () { - this.close(); - this.search.focus(); - }, - - // multi - isFocused: function () { - return this.search.hasClass("select2-focused"); - }, - - // multi - updateSelection: function (data) { - var ids = [], filtered = [], self = this; - - // filter out duplicates - $(data).each(function () { - if (indexOf(self.id(this), ids) < 0) { - ids.push(self.id(this)); - filtered.push(this); - } - }); - data = filtered; - - this.selection.find(".select2-search-choice").remove(); - $(data).each(function () { - self.addSelectedChoice(this); - }); - self.postprocessResults(); - }, - - // multi - tokenize: function() { - var input = this.search.val(); - input = this.opts.tokenizer.call(this, input, this.data(), this.bind(this.onSelect), this.opts); - if (input != null && input != undefined) { - this.search.val(input); - if (input.length > 0) { - this.open(); - } - } - - }, - - // multi - onSelect: function (data, options) { - - if (!this.triggerSelect(data)) { return; } - - this.addSelectedChoice(data); - - this.opts.element.trigger({ type: "selected", val: this.id(data), choice: data }); - - // keep track of the search's value before it gets cleared - this.nextSearchTerm = this.opts.nextSearchTerm(data, this.search.val()); - - this.clearSearch(); - this.updateResults(); - - if (this.select || !this.opts.closeOnSelect) this.postprocessResults(data, false, this.opts.closeOnSelect===true); - - if (this.opts.closeOnSelect) { - this.close(); - this.search.width(10); - } else { - if (this.countSelectableResults()>0) { - this.search.width(10); - this.resizeSearch(); - if (this.getMaximumSelectionSize() > 0 && this.val().length >= this.getMaximumSelectionSize()) { - // if we reached max selection size repaint the results so choices - // are replaced with the max selection reached message - this.updateResults(true); - } else { - // initializes search's value with nextSearchTerm and update search result - if(this.nextSearchTerm != undefined){ - this.search.val(this.nextSearchTerm); - this.updateResults(); - this.search.select(); - } - } - this.positionDropdown(); - } else { - // if nothing left to select close - this.close(); - this.search.width(10); - } - } - - // since its not possible to select an element that has already been - // added we do not need to check if this is a new element before firing change - this.triggerChange({ added: data }); - - if (!options || !options.noFocus) - this.focusSearch(); - }, - - // multi - cancel: function () { - this.close(); - this.focusSearch(); - }, - - addSelectedChoice: function (data) { - var enableChoice = !data.locked, - enabledItem = $( - "<li class='select2-search-choice'>" + - " <div></div>" + - " <a href='#' onclick='return false;' class='select2-search-choice-close' tabindex='-1'></a>" + - "</li>"), - disabledItem = $( - "<li class='select2-search-choice select2-locked'>" + - "<div></div>" + - "</li>"); - var choice = enableChoice ? enabledItem : disabledItem, - id = this.id(data), - val = this.getVal(), - formatted, - cssClass; - - formatted=this.opts.formatSelection(data, choice.find("div"), this.opts.escapeMarkup); - if (formatted != undefined) { - choice.find("div").replaceWith("<div>"+formatted+"</div>"); - } - cssClass=this.opts.formatSelectionCssClass(data, choice.find("div")); - if (cssClass != undefined) { - choice.addClass(cssClass); - } - - if(enableChoice){ - choice.find(".select2-search-choice-close") - .on("mousedown", killEvent) - .on("click dblclick", this.bind(function (e) { - if (!this.isInterfaceEnabled()) return; - - $(e.target).closest(".select2-search-choice").fadeOut('fast', this.bind(function(){ - this.unselect($(e.target)); - this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); - this.close(); - this.focusSearch(); - })).dequeue(); - killEvent(e); - })).on("focus", this.bind(function () { - if (!this.isInterfaceEnabled()) return; - this.container.addClass("select2-container-active"); - this.dropdown.addClass("select2-drop-active"); - })); - } - - choice.data("select2-data", data); - choice.insertBefore(this.searchContainer); - - val.push(id); - this.setVal(val); - }, - - // multi - unselect: function (selected) { - var val = this.getVal(), - data, - index; - selected = selected.closest(".select2-search-choice"); - - if (selected.length === 0) { - throw "Invalid argument: " + selected + ". Must be .select2-search-choice"; - } - - data = selected.data("select2-data"); - - if (!data) { - // prevent a race condition when the 'x' is clicked really fast repeatedly the event can be queued - // and invoked on an element already removed - return; - } - - while((index = indexOf(this.id(data), val)) >= 0) { - val.splice(index, 1); - this.setVal(val); - if (this.select) this.postprocessResults(); - } - - var evt = $.Event("select2-removing"); - evt.val = this.id(data); - evt.choice = data; - this.opts.element.trigger(evt); - - if (evt.isDefaultPrevented()) { - return; - } - - selected.remove(); - - this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data }); - this.triggerChange({ removed: data }); - }, - - // multi - postprocessResults: function (data, initial, noHighlightUpdate) { - var val = this.getVal(), - choices = this.results.find(".select2-result"), - compound = this.results.find(".select2-result-with-children"), - self = this; - - choices.each2(function (i, choice) { - var id = self.id(choice.data("select2-data")); - if (indexOf(id, val) >= 0) { - // By default, the selected item is hidden from the result list inside a multi select - // User can provide an implementation for 'hideSelectionFromResult' and allow the same - // element to be selected multiple times. - if(self.opts.hideSelectionFromResult(choice) === undefined || self.opts.hideSelectionFromResult(choice)) { - choice.addClass("select2-selected"); - // mark all children of the selected parent as selected - choice.find(".select2-result-selectable").addClass("select2-selected"); - } - } - }); - - compound.each2(function(i, choice) { - // hide an optgroup if it doesn't have any selectable children - if (!choice.is('.select2-result-selectable') - && choice.find(".select2-result-selectable:not(.select2-selected)").length === 0) { - choice.addClass("select2-selected"); - } - }); - - if (this.highlight() == -1 && noHighlightUpdate !== false){ - self.highlight(0); - } - - //If all results are chosen render formatNoMatches - if(!this.opts.createSearchChoice && !choices.filter('.select2-result:not(.select2-selected)').length > 0){ - if(!data || data && !data.more && this.results.find(".select2-no-results").length === 0) { - if (checkFormatter(self.opts.formatNoMatches, "formatNoMatches")) { - this.results.append("<li class='select2-no-results'>" + evaluate(self.opts.formatNoMatches, self.search.val()) + "</li>"); - } - } - } - - }, - - // multi - getMaxSearchWidth: function() { - return this.selection.width() - getSideBorderPadding(this.search); - }, - - // multi - resizeSearch: function () { - var minimumWidth, left, maxWidth, containerLeft, searchWidth, - sideBorderPadding = getSideBorderPadding(this.search); - - minimumWidth = measureTextWidth(this.search) + 10; - - left = this.search.offset().left; - - maxWidth = this.selection.width(); - containerLeft = this.selection.offset().left; - - searchWidth = maxWidth - (left - containerLeft) - sideBorderPadding; - - if (searchWidth < minimumWidth) { - searchWidth = maxWidth - sideBorderPadding; - } - - if (searchWidth < 40) { - searchWidth = maxWidth - sideBorderPadding; - } - - if (searchWidth <= 0) { - searchWidth = minimumWidth; - } - - this.search.width(Math.floor(searchWidth)); - }, - - // multi - getVal: function () { - var val; - if (this.select) { - val = this.select.val(); - return val === null ? [] : val; - } else { - val = this.opts.element.val(); - return splitVal(val, this.opts.separator); - } - }, - - // multi - setVal: function (val) { - var unique; - if (this.select) { - this.select.val(val); - } else { - unique = []; - // filter out duplicates - $(val).each(function () { - if (indexOf(this, unique) < 0) unique.push(this); - }); - this.opts.element.val(unique.length === 0 ? "" : unique.join(this.opts.separator)); - } - }, - - // multi - buildChangeDetails: function (old, current) { - var current = current.slice(0), - old = old.slice(0); - - // remove intersection from each array - for (var i = 0; i < current.length; i++) { - for (var j = 0; j < old.length; j++) { - if (equal(this.opts.id(current[i]), this.opts.id(old[j]))) { - current.splice(i, 1); - if(i>0){ - i--; - } - old.splice(j, 1); - j--; - } - } - } - - return {added: current, removed: old}; - }, - - - // multi - val: function (val, triggerChange) { - var oldData, self=this; - - if (arguments.length === 0) { - return this.getVal(); - } - - oldData=this.data(); - if (!oldData.length) oldData=[]; - - // val is an id. !val is true for [undefined,null,'',0] - 0 is legal - if (!val && val !== 0) { - this.opts.element.val(""); - this.updateSelection([]); - this.clearSearch(); - if (triggerChange) { - this.triggerChange({added: this.data(), removed: oldData}); - } - return; - } - - // val is a list of ids - this.setVal(val); - - if (this.select) { - this.opts.initSelection(this.select, this.bind(this.updateSelection)); - if (triggerChange) { - this.triggerChange(this.buildChangeDetails(oldData, this.data())); - } - } else { - if (this.opts.initSelection === undefined) { - throw new Error("val() cannot be called if initSelection() is not defined"); - } - - this.opts.initSelection(this.opts.element, function(data){ - var ids=$.map(data, self.id); - self.setVal(ids); - self.updateSelection(data); - self.clearSearch(); - if (triggerChange) { - self.triggerChange(self.buildChangeDetails(oldData, self.data())); - } - }); - } - this.clearSearch(); - }, - - // multi - onSortStart: function() { - if (this.select) { - throw new Error("Sorting of elements is not supported when attached to <select>. Attach to <input type='hidden'/> instead."); - } - - // collapse search field into 0 width so its container can be collapsed as well - this.search.width(0); - // hide the container - this.searchContainer.hide(); - }, - - // multi - onSortEnd:function() { - - var val=[], self=this; - - // show search and move it to the end of the list - this.searchContainer.show(); - // make sure the search container is the last item in the list - this.searchContainer.appendTo(this.searchContainer.parent()); - // since we collapsed the width in dragStarted, we resize it here - this.resizeSearch(); - - // update selection - this.selection.find(".select2-search-choice").each(function() { - val.push(self.opts.id($(this).data("select2-data"))); - }); - this.setVal(val); - this.triggerChange(); - }, - - // multi - data: function(values, triggerChange) { - var self=this, ids, old; - if (arguments.length === 0) { - return this.selection - .children(".select2-search-choice") - .map(function() { return $(this).data("select2-data"); }) - .get(); - } else { - old = this.data(); - if (!values) { values = []; } - ids = $.map(values, function(e) { return self.opts.id(e); }); - this.setVal(ids); - this.updateSelection(values); - this.clearSearch(); - if (triggerChange) { - this.triggerChange(this.buildChangeDetails(old, this.data())); - } - } - } - }); - - $.fn.select2 = function () { - - var args = Array.prototype.slice.call(arguments, 0), - opts, - select2, - method, value, multiple, - allowedMethods = ["val", "destroy", "opened", "open", "close", "focus", "isFocused", "container", "dropdown", "onSortStart", "onSortEnd", "enable", "disable", "readonly", "positionDropdown", "data", "search"], - valueMethods = ["opened", "isFocused", "container", "dropdown"], - propertyMethods = ["val", "data"], - methodsMap = { search: "externalSearch" }; - - this.each(function () { - if (args.length === 0 || typeof(args[0]) === "object") { - opts = args.length === 0 ? {} : $.extend({}, args[0]); - opts.element = $(this); - - if (opts.element.get(0).tagName.toLowerCase() === "select") { - multiple = opts.element.prop("multiple"); - } else { - multiple = opts.multiple || false; - if ("tags" in opts) {opts.multiple = multiple = true;} - } - - select2 = multiple ? new window.Select2["class"].multi() : new window.Select2["class"].single(); - select2.init(opts); - } else if (typeof(args[0]) === "string") { - - if (indexOf(args[0], allowedMethods) < 0) { - throw "Unknown method: " + args[0]; - } - - value = undefined; - select2 = $(this).data("select2"); - if (select2 === undefined) return; - - method=args[0]; - - if (method === "container") { - value = select2.container; - } else if (method === "dropdown") { - value = select2.dropdown; - } else { - if (methodsMap[method]) method = methodsMap[method]; - - value = select2[method].apply(select2, args.slice(1)); - } - if (indexOf(args[0], valueMethods) >= 0 - || (indexOf(args[0], propertyMethods) && args.length == 1)) { - return false; // abort the iteration, ready to return first matched value - } - } else { - throw "Invalid arguments to select2 plugin: " + args; - } - }); - return (value === undefined) ? this : value; - }; - - // plugin defaults, accessible to users - $.fn.select2.defaults = { - width: "copy", - loadMorePadding: 0, - closeOnSelect: true, - openOnEnter: true, - containerCss: {}, - dropdownCss: {}, - containerCssClass: "", - dropdownCssClass: "", - formatResult: function(result, container, query, escapeMarkup) { - var markup=[]; - markMatch(result.text, query.term, markup, escapeMarkup); - return markup.join(""); - }, - formatSelection: function (data, container, escapeMarkup) { - return data ? escapeMarkup(data.text) : undefined; - }, - sortResults: function (results, container, query) { - return results; - }, - formatResultCssClass: function(data) {return data.css;}, - formatSelectionCssClass: function(data, container) {return undefined;}, - formatMatches: function (matches) { return matches + " results are available, use up and down arrow keys to navigate."; }, - formatNoMatches: function () { return "No matches found"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Please enter " + n + " or more character" + (n == 1? "" : "s"); }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Please delete " + n + " character" + (n == 1? "" : "s"); }, - formatSelectionTooBig: function (limit) { return "You can only select " + limit + " item" + (limit == 1 ? "" : "s"); }, - formatLoadMore: function (pageNumber) { return "Loading more results…"; }, - formatSearching: function () { return "Searching…"; }, - minimumResultsForSearch: 0, - minimumInputLength: 0, - maximumInputLength: null, - maximumSelectionSize: 0, - id: function (e) { return e == undefined ? null : e.id; }, - matcher: function(term, text) { - return stripDiacritics(''+text).toUpperCase().indexOf(stripDiacritics(''+term).toUpperCase()) >= 0; - }, - separator: ",", - tokenSeparators: [], - tokenizer: defaultTokenizer, - escapeMarkup: defaultEscapeMarkup, - blurOnChange: false, - selectOnBlur: false, - adaptContainerCssClass: function(c) { return c; }, - adaptDropdownCssClass: function(c) { return null; }, - nextSearchTerm: function(selectedObject, currentSearchTerm) { return undefined; }, - hideSelectionFromResult: function(selectedObject) { return undefined; }, - searchInputPlaceholder: '', - createSearchChoicePosition: 'top' - }; - - $.fn.select2.ajaxDefaults = { - transport: $.ajax, - params: { - type: "GET", - cache: false, - dataType: "json" - } - }; - - // exports - window.Select2 = { - query: { - ajax: ajax, - local: local, - tags: tags - }, util: { - debounce: debounce, - markMatch: markMatch, - escapeMarkup: defaultEscapeMarkup, - stripDiacritics: stripDiacritics - }, "class": { - "abstract": AbstractSelect2, - "single": SingleSelect2, - "multi": MultiSelect2 - } - }; - -}(jQuery)); |