/*!
* @name ElkArte Forum
* @copyright ElkArte Forum contributors
* @license BSD http://opensource.org/licenses/BSD-3-Clause
*
* This file contains code covered by:
* copyright: 2011 Simple Machines (http://www.simplemachines.org)
* license: BSD, See included LICENSE.TXT for terms and conditions.
*
* @version 1.1.10
*/
/**
* Handle the JavaScript surrounding the admin and moderation center.
*/
/**
* We like the globals cuz they is good to us
*/
/** global: previewTimeout, origText, valid, warningMessage, previewData, refreshPreviewCache, add_answer_template */
/** global: txt_add_another_answer, last_preview, txt_preview, elk_scripturl, txt_news_error_no_news, oThumbnails, elk_smiley_url */
/** global: db_vis, database_changes_area, elk_session_var, package_ftp_test, package_ftp_test_connection, package_ftp_test_failed */
/** global: onNewFolderReceived, elk_session_id, membersSwap, elk_images_url, maintain_members_choose, maintain_members_all */
/** global: reattribute_confirm, reattribute_confirm_email, reattribute_confirm_username, oModeratorSuggest, permission_profiles */
/** global: txt_save, txt_permissions_profile_rename, ajax_notification_cancel_text, txt_theme_remove_confirm, XMLHttpRequest */
/** global: theme_id, frames, editFilename, txt_ban_name_empty, txt_ban_restriction_empty, ElkInfoBar, txt_invalid_response */
/** global: feature_on_text, feature_off_text, core_settings_generic_error, startOptID, add_question_template, question_last_blank */
/** global: ourLanguageVersions, ourVersions, txt_add_another_answer, txt_permissions_commit, Image */
/**
* Admin index class with the following methods
* elk_AdminIndex(oOptions)
* {
* public init()
* public loadAdminIndex()
* public setAnnouncements()
* public showCurrentVersion()
* public checkUpdateAvailable()
* }
*
* @param {object} oOptions
*/
function elk_AdminIndex(oOptions)
{
this.opt = oOptions;
this.announcements = [];
this.current = {};
this.init_news = false;
this.init();
}
// Initialize the admin index to handle announcement, current version and updates
elk_AdminIndex.prototype.init = function ()
{
window.adminIndexInstanceRef = this;
var fHandlePageLoaded = function () {
window.adminIndexInstanceRef.loadAdminIndex();
};
addLoadEvent(fHandlePageLoaded);
};
elk_AdminIndex.prototype.loadAdminIndex = function ()
{
// Load the current master and your version numbers.
if (this.opt.bLoadVersions)
this.showCurrentVersion();
// Load the text box that says there's a new version available.
if (this.opt.bLoadUpdateNotification)
this.checkUpdateAvailable();
};
// Update the announcement container with news
elk_AdminIndex.prototype.setAnnouncement = function (announcement)
{
var oElem = document.getElementById(this.opt.sAnnouncementContainerId),
sMessages = this.init_news ? oElem.innerHTML : '',
sMessage = '';
sMessage = this.opt.sAnnouncementMessageTemplate.replace('%href%', announcement.html_url).replace('%subject%', announcement.name).replace('%time%', announcement.published_at.replace(/[TZ]/g, ' ')).replace('%message%', announcement.body).replace(/\n/g, '
').replace(/\r/g, '');
oElem.innerHTML = sMessages + this.opt.sAnnouncementTemplate.replace('%content%', sMessage);
this.init_news = true;
};
// Updates the current version container with the current version found in the repository
elk_AdminIndex.prototype.showCurrentVersion = function ()
{
var oElkVersionContainer = document.getElementById(this.opt.slatestVersionContainerId),
oinstalledVersionContainer = document.getElementById(this.opt.sinstalledVersionContainerId),
sCurrentVersion = oinstalledVersionContainer.innerHTML,
adminIndex = this,
elkVersion = '???',
verCompare = new elk_ViewVersions();
$.getJSON('https://api.github.com/repos/elkarte/Elkarte/releases', {format: "json"},
function(data, textStatus, jqXHR) {
var mostRecent = {},
previous = {};
adminIndex.current = adminIndex.normalizeVersion(sCurrentVersion);
$.each(data, function(idx, elem) {
// No drafts, thank you
if (elem.draft)
return;
var release = adminIndex.normalizeVersion(elem.tag_name);
let sCheckVersion = elem.tag_name.indexOf('v') === 0 ? elem.tag_name.substring(1) : elem.tag_name;
sCheckVersion.replace('-', '').substring(1);
if (!previous.hasOwnProperty('major') || verCompare.compareVersions(sCurrentVersion, sCheckVersion))
{
// Using a preprelease? Then you may need to know a new one is out!
if ((elem.prerelease && adminIndex.current.prerelease) || (!elem.prerelease))
{
previous = release;
mostRecent = elem;
}
}
// Load the text box containing the latest news items.
if (adminIndex.opt.bLoadAnnouncements)
adminIndex.setAnnouncement(elem);
});
elkVersion = mostRecent.name.replace(/elkarte/i, '').trim();
oElkVersionContainer.innerHTML = elkVersion;
if (verCompare.compareVersions(sCurrentVersion, elkVersion))
oinstalledVersionContainer.innerHTML = adminIndex.opt.sVersionOutdatedTemplate.replace('%currentVersion%', sCurrentVersion);
});
};
// Compare two different versions and return true if the firs is higher than the second
elk_AdminIndex.prototype.compareVersion = function (curVer, refVer)
{
if (curVer.major > refVer.major)
return true;
else if (curVer.major < refVer.major)
return false;
if (curVer.minor > refVer.minor)
return true;
else if (curVer.minor < refVer.minor)
return false;
if (curVer.micro > refVer.micro)
return true;
else if (curVer.micro < refVer.micro)
return false;
if (curVer.prerelease)
{
if (curVer.nano > refVer.nano)
return true;
else if (curVer.nano < refVer.nano)
return false;
}
return false;
};
// Split a string representing a version number into an object
elk_AdminIndex.prototype.normalizeVersion = function (sVersion)
{
var splitVersion = sVersion.split(/[\s-]/),
normalVersion = {
major: 0,
minor: 0,
micro: 0,
prerelease: false,
status: 0,
nano: 0
},
prerelease = false,
aDevConvert = {'dev': 0, 'alpha': 1, 'beta': 2, 'rc': 3, 'stable': 4};
for (var i = 0; i < splitVersion.length; i++)
{
if (splitVersion[i].toLowerCase() === 'elkarte')
continue;
if (splitVersion[i].substring(0, 3).toLowerCase() === 'dev' || splitVersion[i].substring(0, 5).toLowerCase() === 'alpha' || splitVersion[i].substring(0, 4).toLowerCase() === 'beta' || splitVersion[i].substring(0, 2).toLowerCase() === 'rc')
{
normalVersion.prerelease = true;
prerelease = true;
// the tag name comes with the number attached to the beta/rc
if (splitVersion[i].indexOf('.') > 0)
{
var splitPre = splitVersion[i].split('.');
normalVersion.nano = parseFloat(splitPre[1]);
normalVersion.nano = parseFloat(splitVersion[i].substr(splitVersion[i].indexOf('.') + 1));
normalVersion.status = aDevConvert[splitVersion[i].substr(0, splitVersion[i].indexOf('.')).toLowerCase()];
}
}
// If we have passed a "beta" or an "RC" string, no need to go further
if (prerelease)
{
// Only numbers and dots means a number
if (splitVersion[i].replace(/[\d\.]/g, '') === '')
normalVersion.nano = parseFloat(splitVersion[i]);
continue;
}
// Likely from the tag
if (splitVersion[i].substring(0, 1) === 'v')
splitVersion[i] = splitVersion[i].substring(1);
// Only numbers and dots means a number
if (splitVersion[i].replace(/[\d\.]/g, '') === '')
{
var ver = splitVersion[i].split('.');
normalVersion.major = parseInt(ver[0]);
normalVersion.minor = parseInt(ver[1]);
normalVersion.micro = ver.length > 2 ? parseInt(ver[2]) : 0;
}
}
return normalVersion;
};
// Checks if a new version of ElkArte is available and if so updates the admin info box
elk_AdminIndex.prototype.checkUpdateAvailable = function ()
{
if (!('ourUpdatePackage' in window))
return;
var oContainer = document.getElementById(this.opt.sUpdateNotificationContainerId);
// Are we setting a custom title and message?
var sTitle = 'ourUpdateTitle' in window ? window.ourUpdateTitle : this.opt.sUpdateNotificationDefaultTitle,
sMessage = 'ourUpdateNotice' in window ? window.ourUpdateNotice : this.opt.sUpdateNotificationDefaultMessage;
oContainer.innerHTML = this.opt.sUpdateNotificationTemplate.replace('%title%', sTitle).replace('%message%', sMessage);
// Parse in the package download URL if it exists in the string.
document.getElementById('update-link').href = this.opt.sUpdateNotificationLink.replace('%package%', window.ourUpdatePackage);
// If we decide to override life into "red" mode, do it.
if ('elkUpdateCritical' in window)
{
document.getElementById('update_title').style.backgroundColor = '#dd2222';
document.getElementById('update_title').style.color = 'white';
document.getElementById('update_message').style.backgroundColor = '#eebbbb';
document.getElementById('update_message').style.color = 'black';
}
};
/*
elk_ViewVersions(oOptions)
{
public init()
public loadViewVersions
public swapOption(oSendingElement, sName)
public compareVersions(sCurrent, sTarget)
public determineVersions()
}
*/
function elk_ViewVersions (oOptions)
{
this.opt = oOptions;
this.oSwaps = {};
this.init();
}
// initialize the version checker
elk_ViewVersions.prototype.init = function ()
{
// Load this on loading of the page.
window.viewVersionsInstanceRef = this;
var fHandlePageLoaded = function () {
window.viewVersionsInstanceRef.loadViewVersions();
};
addLoadEvent(fHandlePageLoaded);
};
// Load all the file versions
elk_ViewVersions.prototype.loadViewVersions = function ()
{
this.determineVersions();
};
elk_ViewVersions.prototype.swapOption = function (oSendingElement, sName)
{
// If it is undefined, or currently off, turn it on - otherwise off.
this.oSwaps[sName] = !(sName in this.oSwaps) || !this.oSwaps[sName];
if (this.oSwaps[sName])
$("#" + sName).show(300);
else
$("#" + sName).hide(300);
// Unselect the link and return false.
oSendingElement.blur();
return false;
};
// compare a current and target version to determine if one is newer/older
elk_ViewVersions.prototype.compareVersions = function (sCurrent, sTarget)
{
var aVersions = [],
aParts = [],
aCompare = [sCurrent, sTarget],
aDevConvert = {'dev': 0, 'alpha': 1, 'beta': 2, 'rc': 3};
for (var i = 0; i < 2; i++)
{
// Clean the version and extract the version parts.
var sClean = aCompare[i].toLowerCase().replace(/ /g, '').replace(/release candidate/g, 'rc');
aParts = sClean.match(/(\d+)(?:\.(\d+|))?(?:\.)?(\d+|)(?:(alpha|beta|rc)\.*(\d+|)(?:\.)?(\d+|))?(?:(dev))?(\d+|)/);
// No matches?
if (aParts === null)
return false;
// Build an array of parts.
aVersions[i] = [
aParts[1] > 0 ? parseInt(aParts[1]) : 0,
aParts[2] > 0 ? parseInt(aParts[2]) : 0,
aParts[3] > 0 ? parseInt(aParts[3]) : 0,
typeof(aParts[4]) === 'undefined' ? 'stable' : aDevConvert[aParts[4]],
aParts[5] > 0 ? parseInt(aParts[5]) : 0,
aParts[6] > 0 ? parseInt(aParts[6]) : 0,
typeof(aParts[7]) !== 'undefined' ? 'dev' : ''
];
}
// Loop through each category.
for (i = 0; i < 7; i++)
{
// Is there something for us to calculate?
if (aVersions[0][i] !== aVersions[1][i])
{
// Dev builds are a problematic exception.
// (stable) dev < (stable) but (unstable) dev = (unstable)
if (i === 3)
return aVersions[0][i] < aVersions[1][i] ? !aVersions[1][6] : aVersions[0][6];
else if (i === 6)
return aVersions[0][6] ? aVersions[1][3] === 'stable' : false;
// Otherwise a simple comparison.
else
return aVersions[0][i] < aVersions[1][i];
}
}
// They are the same!
return false;
};
// For each area of ElkArte, determine the current and installed versions
elk_ViewVersions.prototype.determineVersions = function ()
{
var oHighYour = {
sources: '??',
admin: '??',
controllers: '??',
database: '??',
subs: '??',
'default': '??',
Languages: '??',
Templates: '??'
};
var oHighCurrent = {
sources: '??',
admin: '??',
controllers: '??',
database: '??',
subs: '??',
'default': '??',
Languages: '??',
Templates: '??'
};
var oLowVersion = {
sources: false,
admin: false,
controllers: false,
database: false,
subs: false,
'default': false,
Languages: false,
Templates: false
};
var sSections = [
'sources',
'admin',
'controllers',
'database',
'subs',
'default',
'Languages',
'Templates'
];
var sCurVersionType = '',
sinstalledVersion,
oSection,
oSectionLink;
for (var i = 0, n = sSections.length; i < n; i++)
{
// Collapse all sections.
oSection = document.getElementById(sSections[i]);
if (typeof(oSection) === 'object' && oSection !== null)
oSection.style.display = 'none';
// Make all section links clickable.
oSectionLink = document.getElementById(sSections[i] + '-link');
if (typeof(oSectionLink) === 'object' && oSectionLink !== null)
{
oSectionLink.instanceRef = this;
oSectionLink.sSection = sSections[i];
oSectionLink.onclick = function () {
this.instanceRef.swapOption(this, this.sSection);
return false;
};
}
}
if (!('ourVersions' in window))
window.ourVersions = {};
// for each file in the detailed-version.js
for (var sFilename in window.ourVersions)
{
if (!window.ourVersions.hasOwnProperty(sFilename))
continue;
if (!document.getElementById('our' + sFilename))
continue;
sCurVersionType = '';
sinstalledVersion = document.getElementById('your' + sFilename).innerHTML;
for (var sVersionType in oLowVersion)
{
if (!oLowVersion.hasOwnProperty(sVersionType))
{
continue;
}
if (sFilename.substr(0, sVersionType.length) === sVersionType)
{
sCurVersionType = sVersionType;
break;
}
}
if (sCurVersionType === '')
continue;
// use compareVersion to determine which version is >< the other
if (typeof(sCurVersionType) !== 'undefined')
{
if ((this.compareVersions(oHighYour[sCurVersionType], sinstalledVersion) || oHighYour[sCurVersionType] === '??') && !oLowVersion[sCurVersionType])
oHighYour[sCurVersionType] = sinstalledVersion;
if (this.compareVersions(oHighCurrent[sCurVersionType], ourVersions[sFilename]) || oHighCurrent[sCurVersionType] === '??')
oHighCurrent[sCurVersionType] = ourVersions[sFilename];
if (this.compareVersions(sinstalledVersion, ourVersions[sFilename]))
{
oLowVersion[sCurVersionType] = sinstalledVersion;
document.getElementById('your' + sFilename).style.color = 'red';
}
}
else if (this.compareVersions(sinstalledVersion, ourVersions[sFilename]))
oLowVersion[sCurVersionType] = sinstalledVersion;
document.getElementById('our' + sFilename).innerHTML = ourVersions[sFilename];
document.getElementById('your' + sFilename).innerHTML = sinstalledVersion;
}
if (!('ourLanguageVersions' in window))
window.ourLanguageVersions = {};
for (sFilename in window.ourLanguageVersions)
{
for (i = 0; i < this.opt.aKnownLanguages.length; i++)
{
if (!document.getElementById('our' + sFilename + this.opt.aKnownLanguages[i]))
continue;
document.getElementById('our' + sFilename + this.opt.aKnownLanguages[i]).innerHTML = ourLanguageVersions[sFilename];
sinstalledVersion = document.getElementById('your' + sFilename + this.opt.aKnownLanguages[i]).innerHTML;
document.getElementById('your' + sFilename + this.opt.aKnownLanguages[i]).innerHTML = sinstalledVersion;
if ((this.compareVersions(oHighYour.Languages, sinstalledVersion) || oHighYour.Languages === '??') && !oLowVersion.Languages)
oHighYour.Languages = sinstalledVersion;
if (this.compareVersions(oHighCurrent.Languages, ourLanguageVersions[sFilename]) || oHighCurrent.Languages === '??')
oHighCurrent.Languages = ourLanguageVersions[sFilename];
if (this.compareVersions(sinstalledVersion, ourLanguageVersions[sFilename]))
{
oLowVersion.Languages = sinstalledVersion;
document.getElementById('your' + sFilename + this.opt.aKnownLanguages[i]).style.color = 'red';
}
}
}
// Set the column titles based on the files each contain
for (i = 0, n = sSections.length; i < n; i++)
{
if (sSections[i] === 'Templates')
continue;
document.getElementById('your' + sSections[i]).innerHTML = oLowVersion[sSections[i]] ? oLowVersion[sSections[i]] : oHighYour[sSections[i]];
document.getElementById('our' + sSections[i]).innerHTML = oHighCurrent[sSections[i]];
if (oLowVersion[sSections[i]])
document.getElementById('your' + sSections[i]).style.color = 'red';
}
// Custom theme in use?
if (document.getElementById('Templates'))
{
document.getElementById('yourTemplates').innerHTML = oLowVersion.Templates ? oLowVersion.Templates : oHighYour.Templates;
document.getElementById('ourTemplates').innerHTML = oHighCurrent.Templates;
if (oLowVersion.Templates)
document.getElementById('yourTemplates').style.color = 'red';
}
};
/**
* Adds a new word container to the censored word list
*/
function addNewWord()
{
setOuterHTML(document.getElementById('moreCensoredWords'), '