MediaWiki:ExpansionSelector.js
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Press Ctrl-F5.
//
// Expansion Selector organized in several tabs
//
// Constraints for Preferences
var PreferencesConstraintsArray =
[
// At least C1 or C2 or WE have to be selected (there may be on Edition selected at least)
function ( oNewVisibility, oPreferencesMap )
{
return ( oNewVisibility.C1 || oNewVisibility.C2 || oNewVisibility.WE );
},
// Validate that the fixed edition, if any, is selected
function ( oNewVisibility, oPreferencesMap )
{
var strFixedEdition = oPreferencesMap.fixedEdition;
var bRes = ( strFixedEdition ? oNewVisibility[ strFixedEdition ] : true );
return ( bRes );
}
];
// Open and close buttons
var BUTTON_OPEN = "[+]",
BUTTON_CLOSE = "[–]";
// Constants for hooks in HTML
var EXPANSION_SELECTOR_ID = "_Expansion_Selector_",
EXPANSION_RESULT_ID = "_Expansion_Result_",
EXPANSION_RESULT_LIST_ID = "_Expansion_Result_List_",
EXPANSION_COUNTER_ID = "_Expansion_Counter_",
EXPANSION_FILTER_ID = "_Expansion_Filter_",
SHOW_WHEN_DONE_CLASS = "showWhenDone",
HIDE_WHEN_DONE_CLASS = "hideWhenDone",
// CITE_ID_PREFIX = "cite_note-",
TABS_CONTAINER_ID = "_Tabs_Container_",
TABS_ID = "_Tabs_";
// HTML IDs that serve as anchor to insert checkboxes strings for each group
var SELECTOR_ID =
[
EXPANSION_SELECTOR_ID + "Major_",
EXPANSION_SELECTOR_ID + "Minor_",
// EXPANSION_SELECTOR_ID + "Licensed_",
EXPANSION_SELECTOR_ID + "Other_",
EXPANSION_SELECTOR_ID + "Fan_",
];
// HTML IDs that serve as anchor to insert result strings for each group
var RESULT_ID =
[
EXPANSION_RESULT_ID + "Major_",
EXPANSION_RESULT_ID + "Minor_",
// EXPANSION_RESULT_ID + "Licensed_",
EXPANSION_RESULT_ID + "Other_",
EXPANSION_RESULT_ID + "Fan_",
];
// Classes controlling visibility when some expansions are selected in a group
var RESULT_SELECTED_EXPANSIONS_CLASS =
[
"showMajorExpansions",
"showMinorExpansions",
// "showLicensedExpansions",
"showOtherExpansions",
"showFanExpansions",
];
// Classes controlling visibility when no expansions are selected in a group
var RESULT_NO_EXPANSIONS_CLASS =
[
"showNoMajorExpansions",
"showNoMinorExpansions",
// "showNoLicensedExpansions",
"showNoOtherExpansions",
"showNoFanExpansions",
];
var SELECTOR_COUNTER_ID =
[
EXPANSION_COUNTER_ID + "Major_",
EXPANSION_COUNTER_ID + "Minor_",
// EXPANSION_COUNTER_ID + "Licensed_",
EXPANSION_COUNTER_ID + "Other_",
EXPANSION_COUNTER_ID + "Fan_",
];
//
// Quick Selector Fields
//
var QUICK_SELECT_LIST = "quickSelectList";
var QUICK_SELECT_BUTTON = "quickSelectButton";
var QUICK_CLEAR_ALL_BUTTON = "quickClearAllButton";
var QUICK_SELECT_ALL_BUTTON = "quickSelectAllButton";
// Map with input fields by Id
var InputFieldMap = {};
// Map with class names (original + derived)
var ClassNameMap = {};
var QuickSelectorMap = {};
var QuickSelectorArray = [];
//===================================================================================
//
// Translation management - Allows the translation of labels that need localization
//
//===================================================================================
// Map to store translation strings
//
var LanguageMap = {};
// Get translated text for a give id. If no value available, returns default value
//
function getLabel( strId, strDefaultText )
{
var strRes = strDefaultText || "";
var strText = LanguageMap[ strId ];
if ( strText )
{
strRes = strText;
}
return strRes;
}
// Populates LanguageMap with all the language strings included in the contents of
// div#wica-translation-table > div[id]
//
function doInitLanguageMap()
{
var oHTMLDIV = $( "div#wica-translation-table > div" );
oHTMLDIV = oHTMLDIV.sort( function( a, b )
{
if ( !$(a).hasClass( 'addFanExpansion' ) || !$(b).hasClass( 'addFanExpansion' ) )
{
return 0;
}
const nameA = $(a).data( 'sorting-value' );
const nameB = $(b).data( 'sorting-value' );
if (nameA < nameB)
{
return -1;
}
else if (nameA > nameB)
{
return 1;
}
return 0;
} );
oHTMLDIV.each(
function () {
var strId = $( this ).attr('id');
var strHTML = $( this ).html();
var bFanExpansion = $( this ).hasClass( "addFanExpansion" );
if ( bFanExpansion )
{
var oExp = /^input(.*)_Label$/;
var arrExp = oExp.exec( strId );
var strSelector = arrExp[1];
if ( strSelector )
{
var strInput = "input" + strSelector;
var strClassName = "show" + strSelector;
var bHasC1 = $( this ).hasClass( "showC1" );
var bHasC2 = $( this ).hasClass( "showC2" );
var bHasWE = $( this ).hasClass( "showWE" );
var arrEditions = [];
if ( bHasC1 )
{
arrEditions.push( "C1" );
}
if ( bHasC2 )
{
arrEditions.push( "C2" );
}
if ( bHasWE )
{
arrEditions.push( "WE" );
}
ItemTree.push( {
label: strHTML,
inputFieldId: strInput,
className: strClassName,
edition: arrEditions,
group: GROUP_FAN,
selected: false
} );
}
}
LanguageMap[ strId ] = strHTML;
}
);
// Processes DIV/SPAN/A/B tags with class "wica-translate-contents"
// Their contents are replaced by their translated equivalent
//
var oHTMLItem = $( ".wica-translate-contents" );
oHTMLItem.each(
function () {
var strId = $( this ).attr('id');
var strDefaultText = $( this ).html();
var strTranslatedText = getLabel( strId, strDefaultText );
$( this ).html( strTranslatedText );
}
);
// Processes INPUT tags with class "wica-translate-attr-value"
// Their value property is replaced by its translated equivalent
//
var oHTMLItem = $( "input.wica-translate-attr-value" );
oHTMLItem.each(
function () {
var strId = $( this ).attr('id');
var strDefaultText = $( this ).prop( 'value' );
var strTranslatedText = getLabel( strId, strDefaultText );
$( this ).prop( 'value', strTranslatedText );
}
);
// Removes the translation table
$( "div#wica-translation-table" ).html( "" );
}
//===================================================================================
//
// Update management - Refreshes internal status and L&F depending on various events
//
//===================================================================================
var EVENT_EXPANSION_CHANGE = 0,
EVENT_FILTER_CHANGE = 1,
EVENT_EDITION_CHANGE = 2,
EVENT_MARK_ADAPTATION_CHANGE = 3;
var UpdateStatus =
{
initializing: true,
counter: 0,
events: {}
};
// Increments counter of nested updates
//
function doStartUpdate()
{
UpdateStatus.counter++;
}
// Decrements counter of nested updates. It if reaches 0 then runs all requested updates
//
function doEndUpdate()
{
UpdateStatus.counter--;
// Only
if ( UpdateStatus.counter == 0 )
{
var oEvents = UpdateStatus.events;
var bUpdateExpansions = oEvents[ EVENT_EXPANSION_CHANGE ] || false;
var bUpdateFilter = oEvents[ EVENT_FILTER_CHANGE ] || false;
var bUpdateEdition = oEvents[ EVENT_EDITION_CHANGE ] || false;
var bUpdateMark = oEvents[ EVENT_MARK_ADAPTATION_CHANGE ] || false;
// Update selected filters tab label (filter + edition), if necessary
if ( bUpdateFilter || bUpdateEdition || bUpdateMark )
{
doUpdateFilterLabel();
}
// Updates the elements visibility according to preferred edition
if ( bUpdateEdition )
{
doUpdatePreferredEdition();
}
// Re-evaluate derived classes if any change in expansions or in preferred edition
if ( bUpdateExpansions || bUpdateEdition )
{
doEvalDerivedClasses();
}
if ( bUpdateFilter )
{
doUpdateSelectedEdition();
}
if ( bUpdateExpansions )
{
doUpdateAdditionalStyles();
doUpdateFootnotes();
}
// Updates selection expansion lists and counters, if necessary
if ( bUpdateExpansions || bUpdateFilter )
{
doUpdateResultListSeparators();
doUpdateCounters();
}
// Updates rules adaptation marks
if ( bUpdateMark || bUpdateEdition )
{
doUpdateAdaptationMarks();
}
// Updates the cookie with the current selection
if ( bUpdateExpansions || bUpdateFilter || bUpdateEdition || bUpdateMark )
{
doRecordStatus();
}
// Resets triggered events
UpdateStatus.events = {};
}
}
// Marks an event for update
//
function doNotifyUpdateEvent ( iEvent1 /*, iEvent2,... */ )
{
var n = arguments.length;
for ( var i = 0; i < n; i++ )
{
var iEvent = arguments[ i ];
UpdateStatus.events[ iEvent ] = true;
}
}
//===================================================================================
//
// Footnote management - Manages conditional footnote visibility
//
//===================================================================================
var FootnoteTree = [];
//
// [
// // One entry per references group
// [
// // One object entry per foornote
// {
// className: showXXX,
// backLinkBlocks: // null for single backlinks
// {
// nodeSingle: ref to synth TAG /span.mw-cite-backlink.wica-single-backlink/
// nodeSingleRef: ref to synth TAG /span.mw-cite-backlink.wica-single-backlink a/
// nodeMulti: ref to synth TAG /span.mw-cite-backlink.wica-multiple-backlink/
// },
// backLinks: [
// // One entry per backlink
// {
// className: showYYYY
// nodeLabel: ref to /sup a [text node]/ OR null (if 1 back link only)
// nodeRef: ref to TAG /sup.reference a/
// nodeRefId: href to TAG /sup/
// },
// ...
// ]
// },
// ...
// ],
// ...
// ]
// Creates data structure to manage footnote conditional visibility and renumbering
//
function doInitFootnotes()
{
FootnoteTree = [];
// Get sample text for single back links
var oAHTML = $( "ol.references li span.mw-cite-backlink a span.cite-accessibility-label" ).first();
var strSingleBackLinkLabel = "";
if ( oAHTML.length )
{
strSingleBackLinkLabel = oAHTML.text();
}
var oSynthBackLinkHTMLModel = $( '<span class="mw-cite-backlink wica-single-backlink"><a href="#cite_ref-DUMMY"><span class="cite-accessibility-label">' + strSingleBackLinkLabel + '</span>↑</a></span>' );
var oAccessibilityLabelModel = $( '<span class="cite-accessibility-label">Jump up to: </span>' );
// Create data structure to support footnote renumbering
var oOlHTML = $( "ol.references" );
oOlHTML.each(
function ( iOlIndex )
{
var arrReferenceGroup = [];
var oLiHTML = $( this ).children( "li" );
oLiHTML.each (
function ( iIndex )
{
var oParentLiHTML = $( this );
var oFootnoteItem =
{
className: null,
backLinkBlocks: null
};
var oSpanTextHTML = oParentLiHTML.children( "span.reference-text" );
var arrClassNames = [];
var oSpanConditionHTML = oSpanTextHTML.children ( "span.showFootnote" );
if ( oSpanConditionHTML.length )
{
// This footnote is conditional
// Split classes and prepare info for backlinks processing
var strClassValue = oSpanConditionHTML.attr( "class" );
var arrClassNames = strClassValue.split( " " );
var iCount = arrClassNames.length;
var strFootnoteClassName = arrClassNames.shift();
if ( strFootnoteClassName === "showFootnote" )
{
strFootnoteClassName = arrClassNames.shift();
oParentLiHTML.addClass( strFootnoteClassName ); // Adds class to LI tag
oSpanConditionHTML.removeClass( strFootnoteClassName ); // Remove class from current SPAN tag
// Add className to Footnote info
oFootnoteItem.className = strFootnoteClassName;
}
}
var oBackLinksHTML = oParentLiHTML.children( "span.mw-cite-backlink" );
var oSupHTML = oBackLinksHTML.children( "sup" );
if ( oSupHTML.length )
{
// Process nested backlinks by SUP tags
oBackLinksHTML.addClass( "wica-multiple-backlink" );
var oSynthBackLinkHTML = oSynthBackLinkHTMLModel.clone().css( "display", "none" ).insertBefore( oBackLinksHTML );
var oSynthBackLinkAHTML = oSynthBackLinkHTML.children( "a" );
oFootnoteItem.backLinkBlocks =
{
nodeSingle: oSynthBackLinkHTML,
nodeSingleRef: oSynthBackLinkAHTML,
nodeMulti: oBackLinksHTML
};
var arrBackLinkInfo = [];
/*
<sup>
<a href="#cite_ref-ecclesiastical-building_3-0">
<span class="cite-accessibility-label">Jump up to: </span>3.0
</a>
</sup>
<sup>
<a href="#cite_ref-ecclesiastical-building_3-1">3.1</a>
</sup>
*/
oSupHTML.each(
function ( iBackLinkIndex )
{
var strBackLinkClassName = null;
var oParentSupHTML = $( this );
var strBackLinkClassNameTmp = arrClassNames[ iBackLinkIndex ];
if ( strBackLinkClassNameTmp )
{
var arrClassNameParts = strBackLinkClassNameTmp.split( "_" );
if ( arrClassNameParts.length == 2 )
{
strBackLinkClassName = arrClassNameParts[ 0 ];
var strBackLinkNumber = +(arrClassNameParts[ 1 ]);
if ( strBackLinkNumber == iBackLinkIndex )
{
oParentSupHTML.addClass( strBackLinkClassName );
oSpanConditionHTML.removeClass( strBackLinkClassNameTmp );
}
}
}
// Process span[href="#backlinkId"] span.cite-accessibility-label + text(X.Y) for iBackLinkIndex == 0
// Process span[href="#backlinkId"] text(X.Y) for iBackLinkIndex > 0
var oAHTML = oParentSupHTML.find( "a" ).first();
var strCallId = oAHTML.attr( "href" );
var oAccessibilityLabel = null;
if ( iBackLinkIndex > 0)
{
oAccessibilityLabel = oAccessibilityLabelModel.clone().prependTo( oAHTML );
}
else
{
oAccessibilityLabel = oAHTML.children( "span.cite-accessibility-label" );
}
var oTextNode = oAHTML.contents().last().filter(
function ()
{
return this.nodeType === Node.TEXT_NODE;
}
);
var oCallHTML = $( document ).find( "sup.reference" + strCallId + " a");
// oCallHTML.text( "[" + iFootnoteIndex + "]" );
// Add backlink info to footnote data
var oBackLinkInfo = {
className: strBackLinkClassName,
nodeLabel: oTextNode,
nodeRef: oCallHTML,
nodeRefId: strCallId,
nodeAccessibilitySpan: oAccessibilityLabel
};
arrBackLinkInfo.push( oBackLinkInfo );
}
);
// Add backlinks to footnote info
oFootnoteItem.backLinks = arrBackLinkInfo;
}
else
{
// Process span[href="#backlinkId"]
var oAHTML = oParentLiHTML.find( "a" ).first();
var strCallId = oAHTML.attr( "href" );
var oCallHTML = $( document ).find( "sup.reference" + strCallId + " a");
// oCallHTML.text( "[" + iFootnoteIndex + "]" );
// Check if there ia an associated className to the back link
var strBackLinkClassName = null;
/*
var strBackLinkClassNameTmp = arrClassNames[ 0 ];
if ( strBackLinkClassNameTmp )
{
var arrClassNameParts = strBackLinkClassNameTmp.split( "_" );
if ( arrClassNameParts.length == 2 )
{
strBackLinkClassName = arrClassNameParts[ 0 ];
var strBackLinkNumber = +(arrClassNameParts[ 1 ]);
if ( strBackLinkNumber == 0 )
{
oParentSupHTML.addClass( strBackLinkClassName );
oSpanConditionHTML.removeClass( strBackLinkClassNameTmp );
}
}
}
*/
// Add backlink info to footnote data
var oBackLinkInfo = {
className: strBackLinkClassName,
nodeLabel: null, // Not needed
nodeRef: oCallHTML,
nodeRefId: null, // Not needed
nodeAccessibilitySpan: null // Not needed
};
oFootnoteItem.backLinks = [ oBackLinkInfo ];
}
arrReferenceGroup.push( oFootnoteItem );
} // End function ( li )
);
FootnoteTree.push( arrReferenceGroup );
} // End function ( ol.references )
);
}
// Updates footnote visibility and numbering
//
function doUpdateFootnotes()
{
var nFootnoteGroups = FootnoteTree.length;
for ( var i = 0; i < nFootnoteGroups; i++ )
{
var iIndexFootnote = 1;
var arrFootnotes = FootnoteTree[ i ];
var nFootnotes = arrFootnotes.length;
for ( var j = 0; j < nFootnotes; j++ )
{
var oFootnote = arrFootnotes[ j ];
var strFootnoteClassName = oFootnote.className;
var bFootnoteVisible = strFootnoteClassName ? doEval( strFootnoteClassName ) : true;
if ( !bFootnoteVisible ) continue;
var iIndexBackLink = 0;
var iIndexVisibleBackLink = -1;
var arrBackLinks = oFootnote.backLinks;
var nBackLinks = arrBackLinks.length;
for ( var k = 0; k < nBackLinks; k++ )
{
var oBackLink = arrBackLinks[ k ];
var strBackLinkClassName = oBackLink.className;
var bBackLinkVisible = strBackLinkClassName ? doEval( strBackLinkClassName ) : true;
if ( !bBackLinkVisible ) continue;
var oBackLinkLabelHTML = oBackLink.nodeLabel;
iIndexVisibleBackLink = k;
if ( oBackLinkLabelHTML )
{
var strBackLinklLabel = "" + iIndexFootnote + "." + iIndexBackLink;
oBackLinkLabelHTML[0].textContent = ( strBackLinklLabel );
}
var oBackLinkRefHTML = oBackLink.nodeRef;
var strText = oBackLinkRefHTML.text();
var iBlank = strText.indexOf( " " );
if ( iBlank < 0 )
{
oBackLinkRefHTML.text( "[" + iIndexFootnote + "]" );
}
else
{
var strTextUpdated = strText.replace( /\s[^\]]+/, " " + iIndexFootnote );
oBackLinkRefHTML.text( strTextUpdated );
}
iIndexBackLink++;
}
if ( nBackLinks > 1 )
{
var oBackLinkBlocks = oFootnote.backLinkBlocks;
var oNodeSpanSingleHTML = oBackLinkBlocks.nodeSingle;
var oNodeSpanSingleRefHTML = oBackLinkBlocks.nodeSingleRef;
var oNodeSpanMultipleHTML = oBackLinkBlocks.nodeMulti;
if ( iIndexBackLink == 1 )
{
var oBackLink = arrBackLinks[ iIndexVisibleBackLink ];
var strCallId = oBackLink.nodeRefId;
oNodeSpanSingleHTML.show();
oNodeSpanMultipleHTML.hide();
oNodeSpanSingleRefHTML.attr( "href", strCallId );
}
else
{
oNodeSpanSingleHTML.hide();
oNodeSpanMultipleHTML.show();
}
}
iIndexFootnote++;
}
}
}
//===================================================================================
//
// Serialization management - Stores current selection in cookies
//
//===================================================================================
// Encodes state in a string of the format #+C1#*C2#-WE#M#!#name1#-name2#+name3#
// Receives preferences map in oPreference Map and classNames status in oTreeMap
//
function doEncodeStatus( oPreferenceMap, oTreeMap )
{
var strRes = "#";
//
// Encode Preferences Map
//
var oVisibility = oPreferenceMap.show;
var strPrefer = oPreferenceMap.prefer;
var bMark = oPreferenceMap.mark;
for ( var strEdition in oVisibility )
{
var bSelected = oVisibility[ strEdition ];
var strSelected = "";
if ( bSelected )
{
if ( strEdition === strPrefer )
{
strSelected = "*"; // Selected and preferred
}
else
{
strSelected = "+"; // Selected only
}
}
else
{
strSelected = "-"; // Not selected
}
var strItemRes = strSelected + strEdition;
strRes += strItemRes + "#";
}
// Encode mark
if ( bMark )
{
strRes += "M#";
}
//
// Encode Classes Map: with the format
//
strRes += "!#";
for ( var strKey in oTreeMap )
{
var oTreeItem = oTreeMap[ strKey ];
// Skip derived classes
if ( oTreeItem.expression )
{
continue;
}
var bSelected = oTreeItem.selected || false;
if ( bSelected )
{
var strOpen = "";
var oItemParent = oTreeItem.parent;
if ( oItemParent )
{
var bOpen = oItemParent.open;
strOpen = ( bOpen === true ? "+" : "-" );
}
var strItemRes = strOpen + strKey;
strRes += strItemRes + "#";
}
}
return strRes;
}
// Decodes state given in strInfo of the format #+C1#*C2#-WE#|#name1#-name2#+name3#
// Receives output preferences map in oPreference Map and classNames status in oTreeMap
//
function doDecodeStatus( oPreferenceMap, oTreeMap, strInfo )
{
var bOK = false;
var strData = strInfo || "";
var arrParts = strData.split ( "!" );
// If no entry string exists with error
bOK = ( arrParts.length == 2 );
if ( !bOK )
{
return bOK;
}
//
// Process info related to Preferences
//
var strPreferenceData = arrParts[ 0 ];
var arrPrefencesList = strPreferenceData.split( "#" );
var n = arrPrefencesList.length - 1;
bOK = ( ( n > 0 ) &&
( arrPrefencesList[ 0 ] === "" ) &&
( arrPrefencesList[ n ] === "" ) );
if ( !bOK )
{
return bOK;
}
// If not initialized, reset preferences map
if ( !oPreferenceMap.show )
{
oPreferenceMap.show = {};
oPreferenceMap.prefer = "";
}
oPreferenceMap.mark = false;
for ( var i = 1; i < n; i++ ) // entries 0 and n-1 have to be empty ("")
{
var strEntry = arrPrefencesList[ i ];
var strPrefix = strEntry.charAt( 0 );
var strEdition = strEntry.substr( 1 );
var bValue = ( ( strPrefix == "+" ) || ( strPrefix == "*" ) ) ;
var bPrefer = ( strPrefix == "*" );
var bMark = ( strPrefix == "M" );
// If the prefix is M, then it is the last entry - it is optional
if ( bMark )
{
oPreferenceMap.mark = bMark;
break;
}
oPreferenceMap.show[ strEdition ] = bValue;
if ( bPrefer )
{
oPreferenceMap.prefer = strEdition;
}
}
//
// Load class names
//
var strClassNamesData = arrParts[ 1 ];
var strClassNamesList = strClassNamesData.split( "#" );
var n = strClassNamesList.length - 1;
bOK = ( ( n > 0 ) &&
( strClassNamesList[ 0 ] === "" ) &&
( strClassNamesList[ n ] === "" ) );
if ( !bOK )
{
return bOK;
}
//
// Decodes array and creates intermediate info structure
//
var oLoadedInfo = {};
for ( var i = 1; i < n; i++ ) // entries 0 and n-1 have to be empty ("")
{
var strEntry = strClassNamesList[ i ];
var strPrefix = strEntry.charAt( 0 );
var bOpen = false;
if ( strPrefix == "+" )
{
strEntry = strEntry.substr ( 1 );
bOpen = true;
}
else if ( strPrefix == "-" )
{
strEntry = strEntry.substr ( 1 );
}
oLoadedInfo[ strEntry ] = { open: bOpen, selected: true };
}
//
// Resets class names (all classes and all nested groups) according to loaded info
//
for ( var strKey in oTreeMap )
{
var oEntry = oTreeMap[ strKey ];
var oInfo = oLoadedInfo[ strKey ];
var oHTMLCheck = $( "#" + oEntry.inputFieldId );
var bOldSelected = oEntry.selected;
var bNewSelected = ( oInfo ? oInfo.selected : false );
// Toggles checkbox if needed
if ( bOldSelected != bNewSelected )
{
oHTMLCheck.click();
}
// Toggles parent group if needed
var oParentEntry = oEntry.parent;
if ( oParentEntry && oInfo && ( oParentEntry.open != oInfo.open ) )
{
var oHTMLLink = $( "a#" + oParentEntry.inputFieldId );
doToggle( oHTMLLink );
}
}
return bOK;
}
var COOKIE_PREFIX = "WICA_",
COOKIE_NAME = "SELECTOR",
COOKIE_PATH = "/",
COOKIE_EXPIRES = null; // 365 * 24 * 3600 * 100;
var USE_LOCAL_STORAGE = false; // ( typeof( Storage ) !== "undefined" );
function doStoreInfo( strValue, strCookiePrefix )
{
if ( USE_LOCAL_STORAGE )
{
sessionStorage.setItem( strCookiePrefix + COOKIE_NAME, strValue );
}
else
{
mw.cookie.set( COOKIE_NAME, strValue, { path: COOKIE_PATH, expires: COOKIE_EXPIRES, prefix: strCookiePrefix } );
}
}
function doRestoreInfo( strCookiePrefix )
{
var strValue = "";
if ( USE_LOCAL_STORAGE )
{
strValue = sessionStorage.getItem( strCookiePrefix + COOKIE_NAME );
}
else
{
strValue = mw.cookie.get( COOKIE_NAME, strCookiePrefix );
}
return strValue;
}
function doRecordStatus()
{
var strStatus = doEncodeStatus( PreferencesMap, ClassNameMap );
var strFixedEdition = PreferencesMap.fixedEdition;
var strCookiePrefix = ( strFixedEdition ? ( COOKIE_PREFIX + strFixedEdition + "_" ) : COOKIE_PREFIX );
//mw.cookie.set( COOKIE_NAME, strStatus, { path: COOKIE_PATH, expires: COOKIE_EXPIRES, prefix: strCookiePrefix } );
doStoreInfo( strStatus, strCookiePrefix );
}
function doRestoreStatus()
{
var strFixedEdition = PreferencesMap.fixedEdition;
var strCookiePrefix = ( strFixedEdition ? ( COOKIE_PREFIX + strFixedEdition + "_" ) : COOKIE_PREFIX );
//var strStatus = mw.cookie.get( COOKIE_NAME, strCookiePrefix );
var strStatus = doRestoreInfo( strCookiePrefix );
if ( strStatus != null )
{
var bOK = doDecodeStatus( PreferencesMap, ClassNameMap, strStatus );
if ( bOK )
{
doStartUpdate();
doNotifyUpdateEvent(
EVENT_EXPANSION_CHANGE,
EVENT_FILTER_CHANGE,
EVENT_EDITION_CHANGE,
EVENT_MARK_ADAPTATION_CHANGE );
doEndUpdate();
}
}
}
//===================================================================================
//
// Presets management - Loading preset lists of expansions (Quick Selectors)
//
//===================================================================================
// Get URL Param
//
function getUrlParam( strParam )
{
var oRes = ( location.search.match( new RegExp( "[?|&]" + strParam + "=(.+?)(&|$)") ) || [, null] )[1] || '';
return oRes;
}
// Returns an array eliminating all oElements different than oElement
//
function doFilterArray( arrElements, oElement )
{
var arrRes = [];
var n = arrElements.length;
for ( var i = 0; i < n; i++ )
{
var o = arrElements[ i ];
if ( o == oElement )
{
arrRes.push ( o );
}
}
return arrRes;
}
// Allows to select/deselect all expansions. If an edition is specified
// (strEditionAllowed equals to C1, C2, WE), all expansions will be
// constrained to that edition
//
function doSelectAllExpansions( bValue, strEditionAllowed )
{
doStartUpdate();
var oVisibility = PreferencesMap.show;
for (var strClassName in ClassNameMap )
{
var o = ClassNameMap[ strClassName ];
// Only simple class names are processed
if ( !o.expression )
{
var arrEdition = o.edition || [];
var arrFilteredEdition = arrEdition;
if ( strEditionAllowed )
{
arrFilteredEdition = doFilterArray( arrEdition, strEditionAllowed );
}
var bIsVisible = isVisible( arrFilteredEdition, oVisibility )
if ( bIsVisible )
{
var oHTMLCheck = $( "#" + o.inputFieldId );
var bOldSelected = o.selected;
if ( bValue != bOldSelected )
{
oHTMLCheck.click();
}
}
}
}
doInitPreselectedExpansions();
doEndUpdate();
}
// Loads an expansion preset
//
function doLoadExpansionSet( strPresetName )
{
doStartUpdate();
var oVisibility = PreferencesMap.show;
var oExpansionPreset = QuickSelectorMap[ strPresetName ];
var arrExpansionPreset = oExpansionPreset.classNames;
var n = arrExpansionPreset.length;
for ( var i = 0; i < n; i++ )
{
var strClassName = arrExpansionPreset[ i ];
var o = ClassNameMap[ strClassName ];
// Only simple class names are processed
if ( !o.expression )
{
var arrEdition = o.edition || [];
var bIsVisible = isVisible( arrEdition, oVisibility )
if ( bIsVisible )
{
var oHTMLCheck = $( "#" + o.inputFieldId );
var bOldSelected = o.selected;
if ( bOldSelected == false )
{
oHTMLCheck.click();
}
}
}
}
doInitPreselectedExpansions();
doEndUpdate();
}
function doQuickSelectionAction( strAction, strPresetId )
{
if ( strAction == ACTION_CLEAR_ALL )
{
doSelectAllExpansions( false );
}
else if ( strAction == ACTION_SELECT_ALL )
{
doSelectAllExpansions( true );
}
else if ( strAction == ACTION_SELECT_ALL_C1 )
{
doSelectAllExpansions( true, "C1" );
}
else if ( strAction == ACTION_SELECT_ALL_C2 )
{
doSelectAllExpansions( true, "C2" );
}
else if ( strAction == ACTION_SELECT_ALL_WE )
{
doSelectAllExpansions( true, "WE" );
}
else if ( strAction == ACTION_LOAD_PRESET )
{
doLoadExpansionSet( strPresetId );
}
}
function doWrapQuickSelectAction( oHTMLButton )
{
var oHTMLList = $( "#" + QUICK_SELECT_LIST );
var strListValue = oHTMLList.val();
var oAction = QuickSelectorMap[ strListValue ];
if ( oAction )
{
var strAction = oAction.action || ACTION_LOAD_PRESET;
doQuickSelectionAction( strAction, strListValue );
}
oHTMLList.val( "defaultSetting" );
}
// Callback to clear the current selection
//
function doWrapClearAll( oHTMLButton )
{
doSelectAllExpansions( false );
}
// Callback to select all expansions
//
function doWrapSelectAll( oHTMLButton )
{
doSelectAllExpansions( true );
}
// Initializes Quick Selectors Tab
// Precond: DerivedClasses from the Result Strings have to be initialized, as
// we are using derived classes XXX_Full as a shortcut to avoid duplicating the
// definition of all the classes contained in each expansions
//
function doInitializeQuickSelectors()
{
var arrSelectors = QuickSelectorDefinition;
var oHTMLSelect = $( "#" + QUICK_SELECT_LIST );
oHTMLSelect.children('option:not(:first)').remove();
var nSelectors = arrSelectors.length;
for ( var i = 0; i < nSelectors; i++ )
{
var oSelector = arrSelectors[ i ];
var strDefaultLabel = oSelector.defaultLabel || null;
var strLabel = oSelector.label || strDefaultLabel;
var strId = oSelector._id;
var bReadOnly = oSelector.readOnly || false;
var strAction = oSelector.action || "";
var oSelectorRes = shallowCopy( oSelector );
var arrClassesRes = [];
oSelectorRes.classNames = arrClassesRes; // New version with full className listing
QuickSelectorMap[ strId ] = oSelectorRes;
QuickSelectorArray.push( oSelectorRes );
var arrClassNames = oSelector.classNames || [];
var nClassNames = arrClassNames.length;
for ( var j = 0 ; j < nClassNames; j++ )
{
var strClassName = arrClassNames[ j ];
var oClassName = ClassNameMap[ strClassName ];
var arrExpression = oClassName.expression;
if ( arrExpression )
{
// It is an array
var nExpressionLength = arrExpression.length;
// Adds all class names skipping the first array element (an operator function)
for ( var k = 1; k < nExpressionLength; k++ )
{
var strExpressionClassName = arrExpression[k];
arrClassesRes.push( strExpressionClassName );
}
}
else
{
// It is a class name
arrClassesRes.push( strClassName );
}
}
// Load Select options
if ( bReadOnly )
{
var strTranslatedLabel = getLabel( strId + "_Label", strLabel );
oHTMLSelect.append(
$( "<option></option>" )
.attr( "value", strId)
.text( strTranslatedLabel )
);
}
else // Custom
{
}
}
$( "#" + QUICK_SELECT_BUTTON ).click( doWrapQuickSelectAction );
$( "#" + QUICK_CLEAR_ALL_BUTTON ).click( doWrapClearAll );
$( "#" + QUICK_SELECT_ALL_BUTTON ).click( doWrapSelectAll );
}
//===================================================================================
//
// Visibility Management - Expansion selector Tabs
//
//===================================================================================
// Recursive function that evaluates an expresion for a Derived Class
//
function doEval( oParam )
{
var bRes = false;
if ( typeof( oParam ) === "string" )
{
//console.log( oParam )
var oClassEntry = ClassNameMap[ oParam ];
if ( oClassEntry )
{
bRes = oClassEntry.selected;
}
else if ( oParam === "showC1_Graphics" ) // Synth Class Name for C1 graphics
{
bRes = ( PreferencesMap.prefer === "C1" );
}
else if ( oParam === "showC2_Graphics" ) // Synth Class Name for C2 graphics
{
bRes = ( PreferencesMap.prefer === "C2" );
}
else if ( oParam === "showWE_Graphics" ) // Synth Class Name for WE graphics
{
bRes = ( PreferencesMap.prefer === "WE" );
}
else if ( oParam === "showC1" ) // Synth Class Name for C1 or WE
{
bRes = ( ( PreferencesMap.prefer === "C1" ) || ( PreferencesMap.prefer === "WE" ) );
}
else if ( oParam === "showC2" ) // Synth Class Name for C2
{
bRes = ( PreferencesMap.prefer === "C2" );
}
else if ( oParam === "showWE" ) // Synth Class Name for C1 or WE
{
bRes = ( ( PreferencesMap.prefer === "C1" ) || ( PreferencesMap.prefer === "WE" ) );
}
else if ( oParam === "showC1_Visible" ) // Synth Class Name for C1 Visible
{
bRes = ( PreferencesMap.show.C1 );
}
else if ( oParam === "showC2_Visible" ) // Synth Class Name for C2 Visible
{
bRes = ( PreferencesMap.show.C2 );
}
else if ( oParam === "showC1OrC2_Visible" ) // Synth Class Name for C1 or C2 Visible
{
bRes = ( PreferencesMap.show.C1 || PreferencesMap.show.C2 );
}
else if ( oParam === "showWE_Visible" ) // Synth Class Name for WE Visible
{
bRes = ( PreferencesMap.show.WE );
}
else if ( oParam === "showMark" ) // Synth Class Name for Mark Checkbox setting
{
bRes = ( PreferencesMap.mark === true );
}
else if ( oParam === "showAll" ) // Synth Class Name for "true"
{
bRes = true;
}
else
{
console.log( oParam + ": Unknown Class Name" );
}
}
else if ( typeof ( oParam ) === "object" )
{
var arrParams = oParam || [];
var nParams = arrParams.length;
var fnAction = arrParams[ 0 ];
var bRes = doEval( arrParams[ 1 ] );
if ( nParams == 2 )
{
// Unary Operator
bRes = fnAction( bRes );
}
else if ( nParams > 2 )
{
// Binary Operator
for ( var i = 2; i < nParams; i++ )
{
var bParam = doEval( arrParams[ i ] );
bRes = fnAction( bRes, bParam );
}
}
}
else if ( typeof ( oParam ) === "boolean" )
{
bRes = oParam;
}
return bRes;
}
// Reevaluates all derived classes and updates the visibility of the Items associated
//
function doEvalDerivedClasses()
{
var arrDerivedClasses = DerivedClassesTable || [];
var nDerivedClasses = arrDerivedClasses.length;
for ( i = 0; i < nDerivedClasses; i++ )
{
var o = arrDerivedClasses[ i ];
var strClassName = o.className;
var arrExpression = o.expression;
var bNewSelected = doEval( arrExpression );
var bOldSelected = o.selected;
if ( bNewSelected != bOldSelected )
{
var str = "." + strClassName;
if ( bNewSelected )
{
$( str ).show();
}
else
{
$( str ).hide();
}
o.selected = bNewSelected;
}
}
}
// This function handles the behavior of a group link (displayed as [+] when closed
// and [-] when open): the block of nested checkboxes is shown or hidden accordingly.
//
function doToggle ( oLinkHTML )
{
doStartUpdate();
var strInputFieldId = oLinkHTML.attr( "id" );
var o = InputFieldMap[ strInputFieldId ];
if ( !o )
{
// Error
console.error( "Unknown Field:" + strInputFieldId );
return;
}
var bOpen = o.open;
var strToggleId = "#toggle_" + strInputFieldId;
var oToggleHTML = $( strToggleId );
if ( bOpen )
{
oToggleHTML.slideUp();
oLinkHTML.html( BUTTON_OPEN );
}
else
{
oToggleHTML.slideDown();
oLinkHTML.html( BUTTON_CLOSE );
}
o.open = !bOpen;
doNotifyUpdateEvent( EVENT_EXPANSION_CHANGE );
doEndUpdate();
}
// This function handles the click on individual expansion checkbox: if so
// all associated HTML Items are shown/hidden accordingly
//
function doCheckboxSimple( oCheckHTML )
{
var strInputFieldReadOnly = oCheckHTML.attr( "readonly" );
if ( !UpdateStatus.initializing && ( strInputFieldReadOnly == "readonly" ) )
{
$( oCheckHTML ).prop( "checked", true );
return false;
}
doStartUpdate();
var strInputFieldId = oCheckHTML.attr( "id" );
var o = InputFieldMap[ strInputFieldId ];
var bSelected = o.selected;
var strClassName = o.className;
var str = '.' + strClassName;
if ( bSelected )
{
$( str ).hide();
}
else
{
$( str ).show();
}
o.selected = !bSelected;
if ( o.parent != null )
{
doCheckParent( o.parent );
}
doNotifyUpdateEvent( EVENT_EXPANSION_CHANGE );
doEndUpdate();
}
// This function handles the click on a group checkbox: if so
// all children are selected or deselected simultaneously and all
// associated HTML Items are shown/hidden accordingly
//
function doCheckboxGroup( oCheckHTML )
{
var strInputFieldReadOnly = oCheckHTML.attr( "readonly" );
if ( !UpdateStatus.initializing && ( strInputFieldReadOnly == "readonly" ) )
{
$( oCheckHTML ).prop( "checked", true );
return false;
}
doStartUpdate();
var strInputFieldId = oCheckHTML.attr( "id" );
var o = InputFieldMap[ strInputFieldId ];
var bSelected = o.selected;
//o.selected = !bSelected;
var arrChildren = o.children;
var nChildren = arrChildren.length;
for ( var i = 0; i < nChildren; i++ )
{
var oChild = arrChildren[ i ];
var bChildSelected = oChild.selected;
var strChildInputFieldId = oChild.inputFieldId;
if ( bSelected == bChildSelected )
{
$('#' + strChildInputFieldId ).prop( "checked", !bSelected );
var strChildClassName = oChild.className;
var str = '.' + strChildClassName;
if ( bSelected )
{
$( str ).hide();
}
else
{
$( str ).show();
}
oChild.selected = !bSelected;
}
}
o.selected = !bSelected;
doNotifyUpdateEvent( EVENT_EXPANSION_CHANGE );
doEndUpdate();
}
// If a nested checkbox is clicked, this functions forces its parent
// checkbox is checked too for the sake od consistency:
// group checkboxes are checked even if not all its children are sleected
//
function doCheckParent( oToggleCheck )
{
var arrChildren = oToggleCheck.children;
var nChildren = arrChildren.length;
var bNewSelected = false;
for ( var i = 0; i < nChildren; i++ )
{
var oChild = arrChildren[ i ];
bNewSelected = bNewSelected || oChild.selected;
}
var bOldSelected = oToggleCheck.selected;
if( bOldSelected != bNewSelected )
{
var strInputFieldName = oToggleCheck.inputFieldId;
$( "#" + strInputFieldName ).prop( "checked", bNewSelected );
oToggleCheck.selected = bNewSelected;
}
}
// Updates any additional styling dependent on classes
//
function doUpdateAdditionalStyles()
{
// Updates visibility of double turn grey box according to showBuilder
var oHTML = $( "div.wica-repeat-block" );
var bBuilder = doEval( "showBuilder" );
if ( bBuilder )
{
oHTML.addClass( "wica-visible" );
}
else
{
oHTML.removeClass( "wica-visible" );
}
}
// Update (X/Y) counters on expansion labels according to:
// a. Preferences - that control what expansion groups are elegible
// b. Selected expansions
//
// X indicates no. selected expansions on a tab
// Y indicates total no. expansions on a tab
//
function doUpdateCounters()
{
var arrCounters = new Array( GROUP_TOTAL );
for( var i = 0; i < GROUP_TOTAL; i++ )
{
arrCounters[ i ] = { selectedCount: 0, totalCount: 0 };
}
var n = ItemTree.length;
for ( var i = 0; i < n; i++ )
{
var o = ItemTree[ i ];
if ( !o.separator && o.visible )
{
var nGroup = o.group;
var oCounter = arrCounters[ nGroup ];
oCounter.totalCount++;
if ( o.selected )
{
oCounter.selectedCount++;
}
}
}
for( var i = 0; i < GROUP_TOTAL; i++ )
{
var oCounter = arrCounters[ i ];
var strText = "(" + oCounter.selectedCount + "/" + oCounter.totalCount + ")";
var strId = "#" + SELECTOR_COUNTER_ID[ i ];
$( strId ).html( strText );
}
}
// Ancillary function to assign the right classes to display separators:
// a. All visible LI tags have class "listSeparator" (class listSeparator is added) ...
// b. except the last visible item (class listSeparator is removed)
//
function doTraversePipeLists( nIndex )
{
var oThis = $( this );
var oVisibleChildren = oThis.children( "li:visible" );
var oVisibleChildrenNotLast = oVisibleChildren.filter( ":not(:last)" );
var oVisibleChildrenLast = oVisibleChildren.filter( ":last" );
oVisibleChildrenNotLast.addClass( "listSeparator" );
oVisibleChildrenLast.removeClass( "listSeparator" );
var oVisitChildren = oVisibleChildren.children( "ul" );
oVisitChildren.each( doTraversePipeLists );
}
function doUpdateResultListSeparators()
{
var oHTMLLists = $( "#" + EXPANSION_RESULT_LIST_ID + " ul" );
oHTMLLists.each( doTraversePipeLists );
}
// Initialize dynamic classes
//
function dynamicSelectorParse( arrExpression )
{
var arrRes = [];
arrExpression.forEach( function( e )
{
if ( Array.isArray( e ) )
{
var arrTemp = dynamicSelectorParse( e );
arrRes.push( arrTemp );
}
else
{
var oItem = OperatorLookup[ e ];
if ( oItem )
{
arrRes.push( oItem );
}
else
{
arrRes.push( e );
}
}
} );
return arrRes;
}
function doInitDynamicClasses()
{
var iCounter = 0;
var oCacheExpressionMap = {};
$( '*[data-dynamic-selector]' ).each( function()
{
var strArgument = $(this).data( 'dynamic-selector' );
var strCachedClass = oCacheExpressionMap[ strArgument ];
if ( strCachedClass )
{
$(this).addClass( strCachedClass );
$(this).removeAttr( 'data-dynamic-selector' );
}
else
{
var strArgumentTemp = strArgument.replaceAll( "'" , '"' );
try
{
var oExpression = JSON.parse( strArgumentTemp );
if ( Array.isArray( oExpression ) && ( oExpression.length > 0 ) )
{
var strClassName = 'showDynamicSelector' + iCounter++;
$(this).addClass( strClassName );
var arrParsedExpression = dynamicSelectorParse ( oExpression );
DerivedClassesTable.push( {
className: strClassName,
expression: arrParsedExpression
} );
oCacheExpressionMap[ strArgument ] = strClassName;
$(this).removeAttr( 'data-dynamic-selector' );
}
else
{
console.log( "Invalid Expression: " + strArgument );
}
}
catch ( e )
{
console.log( "Bad Code In Expression: " + strArgument, e );
}
}
} );
}
// Initialize Tabs with expansion checkbox selectors
//
function doInitTabs()
{
//
// Initialize tabs with expansion selector checkboxes
//
// Caches label "(Partial)"
var strTranslatedPartialLabel = getLabel( "textPartial_Label", "(Partial)" );
// Create empty structure to store checkbox strings
var arrGroupRes = new Array( GROUP_TOTAL );
for ( var i = 0; i < GROUP_TOTAL; i++ )
{
var strSelectedExpansionsClassName = RESULT_SELECTED_EXPANSIONS_CLASS[ i ];
var arrSelectedExpansionsClassRule = [ OR ];
var strNoSelectedExpansionsClassName = RESULT_NO_EXPANSIONS_CLASS[ i ];
var arrNoSelectedExpansionsClassRule = [ NOT, strSelectedExpansionsClassName ];
var oDerivedClassAny =
{
className: strSelectedExpansionsClassName,
expression: arrSelectedExpansionsClassRule
};
var oDerivedClassNone =
{
className: strNoSelectedExpansionsClassName,
expression: arrNoSelectedExpansionsClassRule
};
arrGroupRes[ i ] = {
strInput: "",
strResult: "",
derivedClassAny: oDerivedClassAny,
derivedClassNone: oDerivedClassNone
};
}
// Compute checkbox strings
var n = ItemTree.length;
for (var i = 0; i < n; i++ )
{
var o = ItemTree[ i ];
var strLabel = o.label;
var strInputFieldId = o.inputFieldId;
var bSelected= o.selected || false;
var arrChildren = o.children || [];
var nChildren = arrChildren.length;
var bOpen = o.open || false;
var strClassName = o.className || "";
var bDisabled = o.disabled || false;
var nGroup = o.group;
var oGroupRes = arrGroupRes[ nGroup ];
var arrGroupRule = oGroupRes.derivedClassAny.expression;
var arrEdition = o.edition;
// Manage separators with optional spacing and label
var bSeparator = o.separator;
if ( bSeparator )
{
var strInput = '<span id="show_' + strInputFieldId + '">';
var bSpacing = !o.labelOnly;
if ( bSpacing )
{
strInput += '<br />';
}
if ( strInputFieldId )
{
var strTranslatedLabel = getLabel( strInputFieldId + "_Label", strLabel );
strInput += '<b>' + strTranslatedLabel + '</b><br />';
}
strInput += '</span>';
oGroupRes.strInput += strInput;
continue;
}
InputFieldMap[ strInputFieldId ] = o;
if ( strClassName.length > 0 ) // nChildren == 0
{
ClassNameMap[ strClassName ] = o;
}
if ( !bDisabled )
{
//
// Create selector string for extension and its children if any
//
var strChecked = ( bSelected ? ' checked="checked"' : '' );
var strItemClassName = (nChildren > 0 ? 'checkboxGroup' : 'checkboxSimple' );
var strTranslatedLabel = getLabel( strInputFieldId + "_Label", strLabel );
var strInput = '<span id="show_' + strInputFieldId + '"><input class="' + strItemClassName +'" type="checkbox" name="' + strInputFieldId + '" id="' + strInputFieldId + '"' + strChecked + '/> ' + strTranslatedLabel;
var strResult = strTranslatedLabel;
var strResultVisibilityClass = "";
if ( nChildren > 0 )
{
//
// Prepare synthetic derived classes for the group
//
var strClassNamePrefix = o.classNamePrefix;
var strDerivedClassNameFull = strClassNamePrefix + "Full";
var arrDerivedClassRuleFull = [ AND ];
var strDerivedClassNameAny = strClassNamePrefix + "Any";
var arrDerivedClassRuleAny = [ OR ];
var strDerivedClassNameNone = strClassNamePrefix + "None";
var arrDerivedClassRuleNone = [ NOT, strDerivedClassNameAny ];
var strDerivedClassNamePartial = strClassNamePrefix + "Partial";
var arrDerivedClassRulePartial = [ AND, strDerivedClassNameAny, [ NOT, strDerivedClassNameFull ] ];
DerivedClassesTable.unshift(
{
className: strDerivedClassNameFull,
expression: arrDerivedClassRuleFull
},
{
className: strDerivedClassNameAny,
expression: arrDerivedClassRuleAny
},
{
className: strDerivedClassNameNone,
expression: arrDerivedClassRuleNone
},
{
className: strDerivedClassNamePartial,
expression: arrDerivedClassRulePartial
}
);
// Set derived class to control result visibility for this expansion
strResultVisibilityClass = strDerivedClassNameAny;
//
// Create Selector checkbox string for children
//
strInput += '<span class="' + strDerivedClassNamePartial + '"> <b>' + strTranslatedPartialLabel + '</b> </span>';
strInput += ' <a class="linkToggle" id="' + strInputFieldId + '" href="javascript:void(0);">' + ( bOpen ? BUTTON_CLOSE : BUTTON_OPEN ) + '</a><br />';
strResult += '<span class="' + strDerivedClassNamePartial + '"> (<ul class="commaList">';
var strOpen = ( bOpen ? "" : " style='display:none;'" );
strInput += '<blockquote id="toggle_' + strInputFieldId + '"' + strOpen + '>';
for ( var j = 0; j < nChildren; j++ )
{
var oChild = arrChildren[ j ];
oChild.selected = bSelected;
oChild.parent = o;
oChild.edition = arrEdition;
var strChildLabel = oChild.label;
var strChildinputFieldId = oChild.inputFieldId;
var bChildSelected = bSelected;
// Store information related to classes
var strClassName = oChild.className;
if ( strClassName.length > 0 )
{
InputFieldMap[ strChildinputFieldId ] = oChild;
ClassNameMap[ strClassName ] = oChild;
// Add children to derived classes
arrDerivedClassRuleFull.push( strClassName );
arrDerivedClassRuleAny.push( strClassName );
}
// Translated child label
var strTranslatedChildLabel = getLabel( strChildinputFieldId + "_Label", strChildLabel );
// Append checkbox text for expansion element
strInput += '<input class="checkboxSimple" type="checkbox" name="' + strChildinputFieldId + '" id="' + strChildinputFieldId + '"' + strChecked + '/> ' + strTranslatedChildLabel + '<br />';
// Append text for expansion element
strResult += '<li class="' + strClassName + '">' + strTranslatedChildLabel + '</li>';
}
strInput += '</blockquote>';
strResult += "</ul>)</span>";
}
else
{
strInput += '<br />';
// Set derived class to control result visibility for this expansion
strResultVisibilityClass = strClassName;
}
strInput += '</span>';
//
// Append computed strings to their respective groups
//
// Wrap result text in visibility class
strResult = '<li class="' + strResultVisibilityClass + '">' + strResult + '</li>';
oGroupRes.strInput += strInput;
oGroupRes.strResult += strResult;
// Add class to derived rule for result visibility
arrGroupRule.push( strResultVisibilityClass );
}
}
// Initialize expansion tabs with computed checkboxes strings and result
for ( var i = 0; i < GROUP_TOTAL; i++ )
{
var oGroupRes = arrGroupRes[ i ];
var strInput = oGroupRes.strInput;
var oHTMLInput = $( "#" + SELECTOR_ID[ i ] );
oHTMLInput.html( strInput );
var strResult = oGroupRes.strResult;
strResult = '<ul class="pipeList">' + strResult + '</ul>';
var oHTMLResult = $( "#" + RESULT_ID[ i ] );
oHTMLResult.html( strResult );
var oRuleAny = oGroupRes.derivedClassAny;
var oRuleNone = oGroupRes.derivedClassNone;
DerivedClassesTable.push ( oRuleAny, oRuleNone );
}
doInitDynamicClasses();
// Initialize and computes values for derived classes
var arrDerivedClasses = DerivedClassesTable || [];
var nDerivedClasses = arrDerivedClasses.length;
for ( i = 0; i < nDerivedClasses; i++ )
{
var o = arrDerivedClasses[ i ];
var strClassName = o.className;
var arrExpresion = o.expression;
var bSelected = doEval( arrExpresion );
ClassNameMap[ strClassName ] = o;
o.selected = bSelected;
}
// Initialize visibility of visible and hidden classes
for ( var strClassName in ClassNameMap )
{
var o = ClassNameMap[ strClassName ];
var oHTML = $( "." + strClassName );
if ( o.selected )
{
oHTML.show();
}
else
{
oHTML.hide();
}
}
//
// Register callbacks
//
$( ".linkToggle" ).click(
function() { doToggle( $(this) ); }
);
$( ".checkboxSimple" ).click(
function() { doCheckboxSimple( $(this) ); }
);
$( ".checkboxGroup" ).click(
function() { doCheckboxGroup( $(this) ); }
);
doStartUpdate();
doNotifyUpdateEvent( EVENT_EXPANSION_CHANGE );
doRestoreStatus();
doInitPreferences();
doInitializeQuickSelectors();
doEndUpdate();
}
//===================================================================================
//
// Filter management - Controls the preferences tab
//
//===================================================================================
// Updatess visibility for a list of class names
//
function doUpdateVisibilityForClasses( arrKeys )
{
for ( var iKey in arrKeys )
{
var strClassName = arrKeys[ iKey ];
var bVisible = doEval( strClassName );
if ( bVisible )
{
$( "." + strClassName ).show();
}
else
{
$( "." + strClassName ).hide();
}
}
}
// Updates visibility of images according to preferred edition
//
function doUpdatePreferredEdition()
{
var arrKeys = [ "showC1", "showC2", "showWE", "showC1_Graphics", "showC2_Graphics", "showWE_Graphics" ];
doUpdateVisibilityForClasses( arrKeys );
}
// Updates visibility of texts according to selected edition
//
function doUpdateSelectedEdition()
{
var arrKeys = [ "showC1_Visible", "showC2_Visible", "showWE_Visible", "showC1OrC2_Visible" ];
doUpdateVisibilityForClasses( arrKeys );
}
// Update the Label on Filter Tab to indicate what editions are visible and
// what edition is preferred (with precedence for images and rules)
// Example: the label will list the editions "(C1/C2/...) #" underlining the preferred one
// The # sign indicates rules adaptations are highlighted
//
function doUpdateFilterLabel()
{
var strText = "";
var bEmpty = true;
var oVisibility = PreferencesMap.show;
var strPrefer = PreferencesMap.prefer;
var bMark = PreferencesMap.mark;
for ( var strKey in oVisibility )
{
if ( oVisibility[ strKey ] )
{
if ( !bEmpty )
{
strText += "/";
}
var strTranslatedKey = getLabel( "tabFilters_" + strKey + "_Label", strKey );
var bPrefer = ( strKey == strPrefer );
if ( bPrefer )
{
strText += "<u>" + strTranslatedKey + "</u>";
}
else
{
strText += strTranslatedKey;
}
bEmpty = false;
}
}
if ( bEmpty )
{
strText = "–";
}
strText = "(" + strText + ")";
if ( bMark )
{
strText += " #";
}
var strFilterId = "#" + EXPANSION_FILTER_ID;
$( strFilterId ).html( strText );
}
// Check the current status (given by oStatus) allows an Item to be
// visible (arrEdition provides the editions of the Item)
//
function isVisible( arrEdition, oStatus )
{
var bRes = false;
var n = arrEdition.length;
for ( var i = 0; i < n; i++ )
{
var strEdition = arrEdition[ i ];
var bStatus = oStatus[ strEdition ] || false;
bRes = bRes || bStatus;
}
return bRes;
}
// Action that updates a Prefer radiobox (identified by its edition id) according
// to the new state (provided by bNewSelected)
//
function doPrefer( strEdition, bNewSelected )
{
doStartUpdate();
if ( bNewSelected )
{
PreferencesMap.prefer = strEdition;
doNotifyUpdateEvent( EVENT_EDITION_CHANGE );
}
else
{
doSearchNewPrefer( strEdition );
}
doEndUpdate();
}
// Callback for Radiobuttons (Prefer)
//
function doWrapPrefer( oHTMLRadio )
{
var strValue = oHTMLRadio.val();
var bSelected = oHTMLRadio.prop( "checked" );
doPrefer( strValue, bSelected );
}
// If currently selected Prefer radiobutton is disabled, this function tries to
// select a new Prefer radiobutton, if available
//
function doSearchNewPrefer( strAvoidEdition )
{
doStartUpdate();
var strNewPrefer = "";
var oVisibility = PreferencesMap.show;
for ( var strKey in oVisibility )
{
if ( strKey == strAvoidEdition )
{
continue;
}
var bVisible = oVisibility[ strKey ];
if ( bVisible )
{
var strNewRadioId = "#prefer" + strKey;
var oNewHTMLRadio = $( strNewRadioId );
if ( oNewHTMLRadio.length )
{
strNewPrefer = strKey;
oNewHTMLRadio.prop( "checked", true );
break;
}
}
}
PreferencesMap.prefer = strNewPrefer;
doNotifyUpdateEvent( EVENT_EDITION_CHANGE );
doEndUpdate();
}
// Ancillary function to do a shallow copy of a Javascript object
//
function shallowCopy( oPrototype )
{
var oRes = {};
for( var strKey in oPrototype )
{
oRes[ strKey ] = oPrototype[ strKey ];
}
return oRes;
}
// Highlights rules adapted for one edition to another
//
function doUpdateAdaptationMarks()
{
var oVisibility = PreferencesMap.show;
var strPrefer = PreferencesMap.prefer;
var bMark = PreferencesMap.mark;
// Remove all highlightings
for ( var strEdition in oVisibility )
{
var strMarkClassName = ".mark" + strEdition;
var oHTML = $( strMarkClassName );
oHTML.removeClass( "wica-highlight" );
}
if ( bMark )
{
// Only show highlighting triggered by preferred edition
var strMarkClassName = ".mark" + strPrefer;
var oHTML = $( strMarkClassName );
oHTML.addClass( "wica-highlight" );
// Show elements associated to the highlighting when it is on
$( ".showMark" ).show();
}
else
{
// Show elements associated to the highlighting when it is off
$( ".showMark" ).hide();
}
}
// Function that handles the highlighting of rules adaptations to other editions
//
function doMarkAdaptations( strValue, bSelected, bInit )
{
doStartUpdate();
var bOldSelected = PreferencesMap.mark;
var bHasChange = ( bOldSelected != bSelected );
if ( bHasChange || bInit )
{
doNotifyUpdateEvent( EVENT_MARK_ADAPTATION_CHANGE );
PreferencesMap.mark = bSelected;
}
doEndUpdate();
}
// Function that handles a click on a Filter checkbox (strEdition indicates the
// edition Id that was clicked and bNewSelected, the new expected state).
// It serves as initialization functions for Filter checkboxes (and Prefer
// radiobuttons as a secondary effect) when indicated by parameter bInit
//
function doFilter( strEdition, bNewSelected, bInit )
{
doStartUpdate();
// Check there is a change
var oVisibility = PreferencesMap.show;
var bOldSelected = oVisibility[ strEdition ];
var bHasChange = ( bOldSelected != bNewSelected );
// Check preconditions
if ( bHasChange && !bInit )
{
var bOk = true;
var oNewVisibility = shallowCopy( oVisibility );
oNewVisibility[ strEdition ] = bNewSelected;
var n = PreferencesConstraintsArray.length;
for ( i = 0; i < n; i++ )
{
var bOk = PreferencesConstraintsArray[i]( oNewVisibility, PreferencesMap );
if ( !bOk )
{
// If any precondition is not met undoes click and avoiding any further actions
var strCheckId = "#filter" + strEdition;
var oCheckHTML = $( strCheckId );
oCheckHTML.prop( "checked", !bNewSelected );
doEndUpdate();
return;
}
}
}
if ( !bHasChange && !bInit )
{
doEndUpdate();
return;
}
// If there is a change, then update preference and continue
oVisibility[ strEdition ] = bNewSelected;
doNotifyUpdateEvent( EVENT_FILTER_CHANGE );
// Enable/disable preference checkboxes
var strPreferId = "#prefer" + strEdition;
var oHTMLRadio = $( strPreferId );
if ( oHTMLRadio.length )
{
var strPrefer = PreferencesMap.prefer;
var strLabelId = "#label_prefer" + strEdition;
if ( bNewSelected )
{
// Ensure the radiobutton is enabled
oHTMLRadio.attr( "disabled", false );
$ ( strLabelId ).css('opacity', '1');
if ( bInit )
{
// Resets radios during initialization
if ( strPrefer == strEdition )
{
oHTMLRadio.prop( "checked", true );
doNotifyUpdateEvent( EVENT_EDITION_CHANGE );
}
}
else
{
if ( strPrefer == "" )
{
PreferencesMap.prefer = strEdition;
doNotifyUpdateEvent( EVENT_EDITION_CHANGE );
oHTMLRadio.prop( "checked", true );
doPrefer( strEdition, true );
}
}
}
else
{
// Disables the radiobutton
oHTMLRadio.attr( "disabled", true );
oHTMLRadio.prop( "checked", false );
$ ( strLabelId ).css('opacity', '.2');
// If this option was the preferred, tries to move it to another option if available
if ( strPrefer == strEdition )
{
doSearchNewPrefer( strEdition );
}
}
}
var n = ItemTree.length;
for (var i = 0; i < n; i++ )
{
var o = ItemTree[ i ];
var arrEdition = o.edition || [];
// Compute current visibility from preferences (or used stored value)
var bOldVisible = o.visible;
// Compute new visibility from input
var bNewVisible = isVisible( arrEdition, oVisibility )
// If they differ then... (two options)
if ( bOldVisible != bNewVisible )
{
var strInputId = o.inputFieldId;
var strVisibilitySpan = "#show_" + strInputId;
var oHTMLSpan = $( strVisibilitySpan );
// If new visibility is hidden then
if ( !bNewVisible )
{
// 1. hide input
oHTMLSpan.hide();
// 2. hide children group if open
// 3. clear current values
// 4. hide items associated to class
var oHTMLCheckbox = $( "#" + strInputId );
if ( o.children )
{
var bOldSelected = oHTMLCheckbox.prop( "checked" );
if ( bOldSelected )
{
//doCheckboxGroup( oHTMLCheckbox );
oHTMLCheckbox.click();
}
if ( o.open )
{
var oHTMLLink = $( "a#" + strInputId );
doToggle( oHTMLLink );
}
}
else
{
var strClassName = o.className;
var bOldSelected = doEval( strClassName );
if ( bOldSelected )
{
oHTMLCheckbox.click();
}
}
}
else
{
// If new visibility is visible the show
oHTMLSpan.show();
}
// Update preferences
o.visible = bNewVisible;
}
}
doEndUpdate();
}
function doWrapFilter( oHTMLCheck )
{
var strValue = oHTMLCheck.val();
var bSelected = oHTMLCheck.prop( "checked" );
doFilter( strValue, bSelected );
}
function doWrapMarkAdaptations( oHTMLCheck )
{
var strValue = oHTMLCheck.val();
var bSelected = oHTMLCheck.prop( "checked" );
doMarkAdaptations( strValue, bSelected );
}
//
// Initialize Filters Tab with Preferences
//
function doInitPreferences()
{
doStartUpdate();
var oVisibility = PreferencesMap.show;
for ( var strEdition in oVisibility )
{
var bSelected = oVisibility[ strEdition ];
doFilter( strEdition, bSelected, true );
$( "#filter" + strEdition ).prop( "checked", bSelected );
}
var bMark = PreferencesMap.mark;
doMarkAdaptations( null, bMark, true );
$( "#markAdaptations" ).prop( "checked", bMark );
doEndUpdate();
$( ".inputFilter" ).click(
function() { doWrapFilter( $(this) ); }
);
$( ".inputPrefer" ).click(
function() { doWrapPrefer( $(this) ); }
);
$( ".inputMark" ).click(
function() { doWrapMarkAdaptations( $(this) ); }
);
}
// Get Fixed edition from HTML
//
function getFixedEdition()
{
var strFixedEdition = $( "#" + TABS_CONTAINER_ID ).data( "fixedEdition" );
return strFixedEdition;
}
// Get fan expansions setting from HTML
//
function getFanExpansions()
{
var strFanExpansions = $( "#" + TABS_CONTAINER_ID ).data( "fanExpansions" );
return strFanExpansions;
}
// Get preselected expansions setting from HTML
//
function getPreselectedExpansions()
{
var strPreselectedExpansions = $( "#" + TABS_CONTAINER_ID ).data( "preselectedExpansions" );
return strPreselectedExpansions;
}
function setCheckAsReadOnly( strClassName, bComplex )
{
var oExpComplex = /^show(.*)_Full$/;
var oExpSimple = /^show(.*)$/;
var oExp = ( bComplex ? oExpComplex : oExpSimple );
var arrExp = oExp.exec( strClassName );
var strSelector = arrExp[1];
if ( strSelector )
{
var strInputId = "input" + strSelector;
$( "#" + strInputId ).attr( "readonly", "readonly" );
}
}
// Initializes th list of preselected classes
// Precond: DerivedClasses from the Result Strings have to be initialized, as
// we are using derived classes XXX_Full as a shortcut to avoid duplicating the
// definition of all the classes contained in each expansion
//
function doInitializePreselectedClasses()
{
var arrClassNames = PreferencesMap.preselectedExpansions || [];
var arrClassesRes = [];
var nClassNames = arrClassNames.length;
for ( var i = 0; i < nClassNames; i++ )
{
var strClassName = arrClassNames[ i ];
var oClassName = ClassNameMap[ strClassName ];
if( !oClassName )
{
console.log( "Undefined preselected class: " + strClassName );
continue;
}
var arrExpression = oClassName.expression;
if ( arrExpression )
{
setCheckAsReadOnly( strClassName, true ); // XXX_Full class name
// It is an array
var nExpressionLength = arrExpression.length;
// Adds all class names skipping the first array element (an operator function)
for ( var j = 1; j < nExpressionLength; j++ )
{
var strExpressionClassName = arrExpression[ j ];
arrClassesRes.push( strExpressionClassName );
setCheckAsReadOnly( strExpressionClassName, false );
}
}
else
{
// It is a class name
arrClassesRes.push( strClassName );
setCheckAsReadOnly( strClassName, false );
}
}
PreferencesMap.preselectedExpansions = arrClassesRes;
}
// Loads the preselected expansions and disable their associated checkboxes
//
function doInitPreselectedExpansions( bInit )
{
doStartUpdate();
var oVisibility = PreferencesMap.show;
// Resolves XXXX_Full classes
if ( bInit )
{
doInitializePreselectedClasses();
}
var arrExpansionPreset = PreferencesMap.preselectedExpansions || [];
var n = arrExpansionPreset.length;
for ( var i = 0; i < n; i++ )
{
var strClassName = arrExpansionPreset[ i ];
var o = ClassNameMap[ strClassName ];
if ( !o )
{
console.log( "Undefined preselected class: " + strClassName );
continue;
}
// Only simple class names are processed
if ( !o.expression )
{
var arrEdition = o.edition || [];
var bIsVisible = isVisible( arrEdition, oVisibility )
if ( bIsVisible )
{
var oHTMLCheck = $( "#" + o.inputFieldId );
var bOldSelected = o.selected;
if ( bOldSelected == false )
{
oHTMLCheck.click();
}
//oHTMLCheck.click( function () { return false; } );
}
}
}
doEndUpdate();
}
//
// Adjustment for Scoring pages
//
function updateHTMLScoringToTop() {
var height = 0;
var obj = $('#breadcrumbs');
if (obj.length>0) {
height+=obj.height()*1;
}
var obj = $('#summary_table');
if (obj.length>0) {
height+=obj.height()*1;
}
$('html').css('scroll-padding-top',height+'px');
}
// Runs all initialization for
// a. Expansion selector tabs
// b. Preference tab
//
function doInit()
{
/* --- Not used --
// Check if the URL specifies a preferred edition: C1, C2, WE
var strEdition = getUrlParam( "edition" );
*/
// Reads Fixed Edition setting indicated included page and resets resets
// PreferenceMap data structure
//
var strEdition = getFixedEdition();
if ( ( strEdition == "C1" ) || ( strEdition == "C2" ) || ( strEdition == "WE" ))
{
var oVisibilityMap = PreferencesMap.show;
for ( var strEditionKey in oVisibilityMap )
{
oVisibilityMap[ strEditionKey ] = ( strEditionKey == strEdition );
}
PreferencesMap.prefer = strEdition;
PreferencesMap.fixedEdition = strEdition;
PreferencesMap.marks = false;
}
// Reads Fan Expansions settings to indicate if fan expansions should be considered
//
var strFanExpansions = getFanExpansions();
if ( strFanExpansions != true )
{
var bShowfanExpansions = PreferencesMap.fanExpansions = ( strFanExpansions == "true" );
if ( !bShowfanExpansions )
{
$( "#tabs-fan-label" ).hide();
$( "#tabs-fan" ).hide();
$( "#tabs-fan-result" ).hide();
//var oTabs = $( "#" + TABS_ID ).tabs();
//oTabs.tabs( "refresh" );
}
}
// Reads Preselected Expansions to be marked permanently in the selector
//
var strPreselectedExpansions = getPreselectedExpansions();
if ( strPreselectedExpansions )
{
var arrPreselectedExpansions = strPreselectedExpansions.split( "," );
PreferencesMap.preselectedExpansions = arrPreselectedExpansions;
}
// Initialize footnotes
doInitFootnotes();
// Initialize language mmapings
doInitLanguageMap()
// Initialize tabs and visibility
doInitTabs();
// Initialize preselected expansions
doInitPreselectedExpansions( true );
UpdateStatus.initializing = false;
}
// Callback to do the all initialization
//
function doWrapInit()
{
if ( $( "#" + TABS_CONTAINER_ID ).hasClass( SHOW_WHEN_DONE_CLASS ) )
{
$( "#" + TABS_CONTAINER_ID ).html( strPage );
$( "#" + TABS_ID ).tabs( {
collapsible: true
} );
doInit();
$( "." + HIDE_WHEN_DONE_CLASS ).hide();
$( "." + SHOW_WHEN_DONE_CLASS ).show();
// Needed after the Result lists are visible, otherwise separators do not show
doUpdateResultListSeparators();
// Adjust top scrolling for Scoring pages
updateHTMLScoringToTop();
}
}
// Watchdog function to check if initialization is possible
//
function isActionPossible()
{
return ( !!( window.strPage ) && !!( $( "#" + TABS_ID ).tabs ) );
}
// Initialization action to be triggered when ready
//
function doAction()
{
doWrapInit();
}
// Wrapper for async loading
//
function doActionWrapper()
{
console.log( "Async Start Iteration: #" + ( iCounter++ ) );
if ( isActionPossible() )
{
clearInterval( iVal );
doAction()
}
}
var iVal = null;
var iCounter = 0;
// Kicks-off initialization. If sync loading is not ready, triggers async approach
//
function doStart()
{
if( isActionPossible() )
{
console.log( "Sync Start Done!" );
doAction();
}
else
{
console.log( "Async Start Iteration: #" + ( iCounter++ ) );
iVal = setInterval( doActionWrapper, 500);
}
}
$( document ).ready( doStart );