414 lines
10 KiB
JavaScript
414 lines
10 KiB
JavaScript
var previewWidth = 482,
|
|
previewHeight = 110;
|
|
|
|
$(document).ready(function () {
|
|
/* Removed as this is now (hopefully) unnecessary */
|
|
//$("#Panel").stickyPanel({
|
|
// topPadding: 1,
|
|
// afterDetachCSSClass: "floated-panel",
|
|
// savePanelSpace: true
|
|
//});
|
|
|
|
//this statement tells the browser to fade out any success message after 5 seconds
|
|
setTimeout(function () {
|
|
$(".success").fadeOut("slow");
|
|
}, 5000);
|
|
});
|
|
|
|
/*
|
|
* i18n_months and i18n_days_short are used in jquery datepickers
|
|
* which we use in multiple places
|
|
*/
|
|
var i18n_months = [
|
|
$.i18n._("January"),
|
|
$.i18n._("February"),
|
|
$.i18n._("March"),
|
|
$.i18n._("April"),
|
|
$.i18n._("May"),
|
|
$.i18n._("June"),
|
|
$.i18n._("July"),
|
|
$.i18n._("August"),
|
|
$.i18n._("September"),
|
|
$.i18n._("October"),
|
|
$.i18n._("November"),
|
|
$.i18n._("December"),
|
|
];
|
|
|
|
var i18n_months_short = [
|
|
$.i18n._("Jan"),
|
|
$.i18n._("Feb"),
|
|
$.i18n._("Mar"),
|
|
$.i18n._("Apr"),
|
|
$.i18n._("May"),
|
|
$.i18n._("Jun"),
|
|
$.i18n._("Jul"),
|
|
$.i18n._("Aug"),
|
|
$.i18n._("Sep"),
|
|
$.i18n._("Oct"),
|
|
$.i18n._("Nov"),
|
|
$.i18n._("Dec"),
|
|
];
|
|
|
|
var i18n_days_short = [
|
|
$.i18n._("Su"),
|
|
$.i18n._("Mo"),
|
|
$.i18n._("Tu"),
|
|
$.i18n._("We"),
|
|
$.i18n._("Th"),
|
|
$.i18n._("Fr"),
|
|
$.i18n._("Sa"),
|
|
];
|
|
|
|
var HTTPMethods = Object.freeze({
|
|
GET: "GET",
|
|
POST: "POST",
|
|
PUT: "PUT",
|
|
PATCH: "PATCH",
|
|
DELETE: "DELETE",
|
|
OPTIONS: "OPTIONS",
|
|
});
|
|
|
|
var dateStartId = "#sb_date_start",
|
|
timeStartId = "#sb_time_start",
|
|
dateEndId = "#sb_date_end",
|
|
timeEndId = "#sb_time_end";
|
|
|
|
function getDatatablesStrings(overrideDict) {
|
|
var dict = {
|
|
sEmptyTable: $.i18n._("No data available in table"),
|
|
sInfo: $.i18n._("Showing _START_ to _END_ of _TOTAL_ entries"),
|
|
sInfoEmpty: $.i18n._("Showing 0 to 0 of 0 entries"),
|
|
sInfoFiltered: "", // $.i18n._("(filtered from _MAX_ total entries)"),
|
|
sInfoPostFix: $.i18n._(""),
|
|
sInfoThousands: $.i18n._(","),
|
|
sLengthMenu: $.i18n._("Show _MENU_"),
|
|
sLoadingRecords: $.i18n._("Loading..."),
|
|
//"sProcessing": $.i18n._("Processing..."),
|
|
sProcessing: $.i18n._(""),
|
|
sSearch: $.i18n._(""),
|
|
sZeroRecords: $.i18n._("No matching records found"),
|
|
oPaginate: {
|
|
sFirst: "«",
|
|
sLast: "»",
|
|
sNext: "›",
|
|
sPrevious: "‹",
|
|
},
|
|
//"oPaginate": {
|
|
// "sFirst": $.i18n._("First"),
|
|
// "sLast": $.i18n._("Last"),
|
|
// "sNext": $.i18n._("Next"),
|
|
// "sPrevious": $.i18n._("Previous")
|
|
//},
|
|
oAria: {
|
|
sSortAscending: $.i18n._(": activate to sort column ascending"),
|
|
sSortDescending: $.i18n._(": activate to sort column descending"),
|
|
},
|
|
};
|
|
|
|
return $.extend({}, dict, overrideDict);
|
|
}
|
|
|
|
function adjustDateToServerDate(date, serverTimezoneOffset) {
|
|
//date object stores time in the browser's localtime. We need to artificially shift
|
|
//it to
|
|
var timezoneOffset = date.getTimezoneOffset() * 60 * 1000;
|
|
|
|
date.setTime(date.getTime() + timezoneOffset + serverTimezoneOffset * 1000);
|
|
|
|
/* date object has been shifted to artificial UTC time. Now let's
|
|
* shift it to the server's timezone */
|
|
return date;
|
|
}
|
|
|
|
/**
|
|
*handle to the jplayer window
|
|
*/
|
|
var _preview_window = null;
|
|
|
|
/**
|
|
*Gets the info from the view when menu action play choosen and opens the jplayer window.
|
|
*/
|
|
function openAudioPreview(p_event) {
|
|
p_event.stopPropagation();
|
|
|
|
var audioFileID = $(this).attr("audioFile");
|
|
var objId = $(".obj_id:first").attr("value");
|
|
var objType = $(".obj_type:first").attr("value");
|
|
var playIndex = $(this).parent().parent().attr("id");
|
|
playIndex = playIndex.substring(4); //remove the spl_
|
|
|
|
if (objType == "playlist") {
|
|
open_playlist_preview(objId, playIndex);
|
|
} else if (objType == "block") {
|
|
open_block_preview(objId, playIndex);
|
|
}
|
|
}
|
|
|
|
function open_audio_preview(type, id) {
|
|
// The reason that we need to encode artist and title string is that
|
|
// sometime they contain '/' or '\' and apache reject %2f or %5f
|
|
// so the work around is to encode it twice.
|
|
openPreviewWindow(
|
|
baseUrl + "audiopreview/audio-preview/audioFileID/" + id + "/type/" + type,
|
|
previewWidth,
|
|
previewHeight,
|
|
);
|
|
_preview_window.focus();
|
|
}
|
|
|
|
/**
|
|
*Opens a jPlayer window for the specified info, for either an audio file or playlist.
|
|
*If audioFile, audioFileTitle, audioFileArtist is supplied the jplayer opens for one file
|
|
*Otherwise the playlistID and playlistIndex was supplied and a playlist is played starting with the
|
|
*given index.
|
|
*/
|
|
function open_playlist_preview(p_playlistID, p_playlistIndex) {
|
|
if (p_playlistIndex == undefined)
|
|
//Use a resonable default.
|
|
p_playlistIndex = 0;
|
|
|
|
if (_preview_window != null && !_preview_window.closed)
|
|
_preview_window.playAllPlaylist(p_playlistID, p_playlistIndex);
|
|
else
|
|
openPreviewWindow(
|
|
baseUrl +
|
|
"audiopreview/playlist-preview/playlistIndex/" +
|
|
p_playlistIndex +
|
|
"/playlistID/" +
|
|
p_playlistID,
|
|
previewWidth,
|
|
previewHeight,
|
|
);
|
|
_preview_window.focus();
|
|
}
|
|
|
|
function open_block_preview(p_blockId, p_blockIndex) {
|
|
if (p_blockIndex == undefined)
|
|
//Use a resonable default.
|
|
p_blockIndex = 0;
|
|
|
|
if (_preview_window != null && !_preview_window.closed)
|
|
_preview_window.playBlock(p_blockId, p_blockIndex);
|
|
else
|
|
openPreviewWindow(
|
|
baseUrl +
|
|
"audiopreview/block-preview/blockIndex/" +
|
|
p_blockIndex +
|
|
"/blockId/" +
|
|
p_blockId,
|
|
previewWidth,
|
|
previewHeight,
|
|
);
|
|
_preview_window.focus();
|
|
}
|
|
|
|
/**
|
|
*Opens a jPlayer window for the specified info, for either an audio file or playlist.
|
|
*If audioFile, audioFileTitle, audioFileArtist is supplied the jplayer opens for one file
|
|
*Otherwise the playlistID and playlistIndex was supplied and a playlist is played starting with the
|
|
*given index.
|
|
*/
|
|
function open_show_preview(p_showID, p_showIndex) {
|
|
if (_preview_window != null && !_preview_window.closed)
|
|
_preview_window.playAllShow(p_showID, p_showIndex);
|
|
else
|
|
openPreviewWindow(
|
|
baseUrl +
|
|
"audiopreview/show-preview/showID/" +
|
|
p_showID +
|
|
"/showIndex/" +
|
|
p_showIndex,
|
|
previewWidth,
|
|
previewHeight,
|
|
);
|
|
_preview_window.focus();
|
|
}
|
|
|
|
function openPreviewWindow(url, w, h) {
|
|
var dim = w && h ? "width=" + w + ",height=" + h + "," : "";
|
|
// Hardcoding this here is kinda gross, but the alternatives aren't much better...
|
|
_preview_window = window.open(
|
|
url,
|
|
$.i18n._("Audio Player"),
|
|
dim + "scrollbars=yes",
|
|
);
|
|
return false;
|
|
}
|
|
|
|
function validateTimeRange() {
|
|
var oRange,
|
|
inputs = $(".sb-timerange > input"),
|
|
start,
|
|
end;
|
|
|
|
oRange = AIRTIME.utilities.fnGetScheduleRange(
|
|
dateStartId,
|
|
timeStartId,
|
|
dateEndId,
|
|
timeEndId,
|
|
);
|
|
|
|
start = oRange.start;
|
|
end = oRange.end;
|
|
|
|
if (end >= start) {
|
|
inputs.removeClass("error");
|
|
} else {
|
|
if (!inputs.hasClass("error")) {
|
|
inputs.addClass("error");
|
|
}
|
|
}
|
|
|
|
return {
|
|
start: start,
|
|
end: end,
|
|
isValid: end >= start,
|
|
};
|
|
}
|
|
|
|
// validate uploaded images
|
|
function validateImage(img, el) {
|
|
// remove any existing error messages
|
|
if ($("#img-err")) {
|
|
$("#img-err").remove();
|
|
}
|
|
|
|
if (img.size > 2048000) {
|
|
// 2MB - pull this from somewhere instead?
|
|
// hack way of inserting an error message
|
|
var err = $.i18n._("Selected file is too large");
|
|
el.parent().after(
|
|
"<ul id='img-err' class='errors'>" + "<li>" + err + "</li>" + "</ul>",
|
|
);
|
|
return false;
|
|
} else if (validateMimeType(img.type) < 0) {
|
|
var err = $.i18n._("File format is not supported");
|
|
el.parent().after(
|
|
"<ul id='img-err' class='errors'>" + "<li>" + err + "</li>" + "</ul>",
|
|
);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// validate image mime type
|
|
function validateMimeType(mime) {
|
|
var extensions = [
|
|
"image/jpeg",
|
|
"image/png",
|
|
"image/gif",
|
|
// BMP?
|
|
];
|
|
return $.inArray(mime, extensions);
|
|
}
|
|
|
|
function pad(number, length) {
|
|
return sprintf("%'0" + length + "d", number);
|
|
}
|
|
|
|
function removeSuccessMsg() {
|
|
var $status = $(".success");
|
|
|
|
$status.fadeOut("slow", function () {
|
|
$status.empty();
|
|
});
|
|
}
|
|
|
|
function hideHint(h) {
|
|
h.hide("slow").addClass("hidden");
|
|
}
|
|
|
|
function showHint(h) {
|
|
h.show("slow").removeClass("hidden");
|
|
}
|
|
|
|
function getUsabilityHint() {
|
|
var pathname = window.location.pathname;
|
|
$.getJSON(
|
|
baseUrl + "api/get-usability-hint",
|
|
{ format: "json", userPath: pathname },
|
|
function (json) {
|
|
var $hint_div = $(".usability_hint");
|
|
var current_hint = $hint_div.html();
|
|
if (json === "") {
|
|
// there are no more hints to display to the user
|
|
hideHint($hint_div);
|
|
} else if (current_hint !== json) {
|
|
// we only change the message if it is new
|
|
if ($hint_div.is(":visible")) {
|
|
hideHint($hint_div);
|
|
}
|
|
$hint_div.html(json);
|
|
showHint($hint_div);
|
|
} else {
|
|
// hint is the same before we hid it so we just need to show it
|
|
if ($hint_div.is(":hidden")) {
|
|
showHint($hint_div);
|
|
}
|
|
}
|
|
},
|
|
);
|
|
}
|
|
|
|
// TODO: build this out so we can use it as a fallback in fail cases
|
|
function buildErrorDialog(message) {
|
|
var el = $("<div id='error_dialog'></div>");
|
|
el.text(message);
|
|
$(document.body).append(el);
|
|
$("#error_dialog").dialog({
|
|
title: $.i18n._("Something went wrong!"),
|
|
resizable: false,
|
|
modal: true,
|
|
width: "auto",
|
|
height: "auto",
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Add title attributes (whose values are their inner text) to all elements in the calling parent matching selector
|
|
*
|
|
* @param selector jQuery selector to search descendants
|
|
* @returns {jQuery}
|
|
*/
|
|
jQuery.fn.addTitles = function (selector) {
|
|
this.each(function () {
|
|
// Put this in a mouseenter event handler so it's dynamic
|
|
// (newly created elements will have the title applied on hover)
|
|
$(this).on("mouseenter", selector, function () {
|
|
$(this).attr("title", $(this).text());
|
|
});
|
|
});
|
|
|
|
return this; // jQuery chaining
|
|
};
|
|
|
|
// XXX: Old code to pan selector text; keeping this around in case we want to use it later - Duncan
|
|
jQuery.fn.scrollText = function (selector) {
|
|
this.each(function () {
|
|
$(this).on("mouseenter", selector, function () {
|
|
var sw = $(this)[0].scrollWidth - parseFloat($(this).css("textIndent")),
|
|
iw = $(this).innerWidth();
|
|
if (sw > iw) {
|
|
$(this)
|
|
.stop()
|
|
.animate(
|
|
{
|
|
textIndent: "-" + (sw + 1 - iw) + "px",
|
|
},
|
|
sw * 8,
|
|
);
|
|
}
|
|
});
|
|
$(this).on("mouseleave", selector, function () {
|
|
$(this).stop().animate(
|
|
{
|
|
textIndent: "0",
|
|
},
|
|
500,
|
|
);
|
|
});
|
|
});
|
|
|
|
return this;
|
|
};
|