$("#back-to-top").fadeOut();
}
});
-
+
// scroll body to 0px on click
$("#back-to-top").click(function () {
$("body,html").animate({
$(".field.select > select, .field.custom > select").addClass("form-control");
// move the tabbar to the second nav bar
- if( $("ul.tabbar").length ) {
- $("ul.tabbar").appendTo("#topbar-second > .container > #tabmenu");
- }
+ $("section .tabbar-wrapper").first().appendTo("#topbar-second > .container > #tabmenu");
// add mask css url to the logo-img container
//
}
// make responsive tabmenu with flexmenu.js
- // the menupoints which doesn't fit in the second nav bar will moved to a
+ // the menupoints which doesn't fit in the second nav bar will moved to a
// dropdown menu. Look at common_tabs.tpl
$("ul.tabs.flex-nav").flexMenu({
'cutoff': 2,
});
// add Jot botton to the scecond navbar
- if( $("section #jotOpen").length ) {
- $("section #jotOpen").appendTo("#topbar-second > .container > #navbar-button");
- if( $("#jot-popup").is(":hidden")) $("#topbar-second > .container > #navbar-button #jotOpen").hide();
+ let $jotButton = $("#jotOpen");
+ let $composeButton = $("#composeOpen");
+ if (compose) {
+ $jotButton.hide();
+ if ($composeButton.length) {
+ $composeButton.appendTo("#topbar-second > .container > #navbar-button");
+ if($("#jot-popup").is(":hidden")) {
+ $composeButton.hide();
+ }
+ }
+ } else {
+ $composeButton.hide();
+ if ($jotButton.length) {
+ $jotButton.appendTo("#topbar-second > .container > #navbar-button");
+ if($("#jot-popup").is(":hidden")) {
+ $jotButton.hide();
+ }
+ }
}
// show bulk deletion button at network page if checkbox is checked
return false;
}
});
-
- if(checked == true) {
- $("a#item-delete-selected").fadeTo(400, 1);
- $("a#item-delete-selected").show();
+
+ if(checked) {
+ $("#item-delete-selected").fadeTo(400, 1);
+ $("#item-delete-selected").show();
} else {
- $("a#item-delete-selected").fadeTo(400, 0, function(){
- $("a#item-delete-selected").hide();
- });
+ $("#item-delete-selected").fadeTo(400, 0, function(){
+ $("#item-delete-selected").hide();
+ });
}
});
-
+
//$('ul.flex-nav').flexMenu();
// initialize the bootstrap tooltips
delay: {
show: 500,
hide: 100
- }
+ },
+ sanitizeFn: function (content) {
+ return DOMPurify.sanitize(content)
+ },
});
// initialize the bootstrap-select
// append the new heading to the navbar
$("#topbar-second > .container > #tabmenu").append(newText);
- // try to get the value of the original search input to insert it
+ // try to get the value of the original search input to insert it
// as value in the nav-search-input
var searchValue = $("#search-wrapper .form-group-search input").val();
}
// move the "Save the search" button to the second navbar
- $(".search-content-wrapper #search-save-form ").appendTo("#topbar-second > .container > #navbar-button");
+ $(".search-content-wrapper #search-save").appendTo("#topbar-second > .container > #navbar-button");
// append the vcard-short-info to the second nav after passing the element
// with .fn (vcard username). Use scrollspy to get the scroll position.
// Dropdown menus with the class "dropdown-head" will display the active tab
// as button text
- $("body").on('click', '.dropdown-head .dropdown-menu li a', function(){
- $(this).closest(".dropdown").find('.btn').html($(this).text() + ' <span class="caret"></span>');
- $(this).closest(".dropdown").find('.btn').val($(this).data('value'));
- $(this).closest("ul").children("li").show();
- $(this).parent("li").hide();
+ $("body").on('click', '.dropdown-head .dropdown-menu li a, .dropdown-head .dropdown-menu li button', function(){
+ toggleDropdownText(this);
+ });
+
+ /* setup onoff widgets */
+ // Add the correct class to the switcher according to the input
+ // value (On/Off)
+ $(".toggle input").each(function(){
+ // Get the value of the input element
+ val = $(this).val();
+ id = $(this).attr("id");
+
+ // The css classes for "on" and "off"
+ onstyle = "btn-primary";
+ offstyle = "btn-default off";
+
+ // Add the correct class in dependence of input value (On/Off)
+ toggleclass = (val == 0 ? offstyle : onstyle);
+ $("#"+id+"_onoff").addClass(toggleclass);
+
+ });
+
+ // Change the css class while clicking on the switcher elements
+ $(".toggle label, .toggle .toggle-handle").click(function(event){
+ event.preventDefault();
+ // Get the value of the input element
+ var input = $(this).siblings("input");
+ var val = 1-input.val();
+ var id = input.attr("id");
+
+ // The css classes for "on" and "off"
+ var onstyle = "btn-primary";
+ var offstyle = "btn-default off";
+
+ // According to the value of the input element we need to decide
+ // which class need to be added and removed when changing the switch
+ var removedclass = (val == 0 ? onstyle : offstyle);
+ var addedclass = (val == 0 ? offstyle : onstyle)
+ $("#"+id+"_onoff").addClass(addedclass).removeClass(removedclass);
+
+ // After changing the switch the input element is getting
+ // the newvalue
+ input.val(val);
+ });
+
+ // Set the padding for input elements with inline buttons
+ //
+ // In Frio we use some input elements where the submit button is visually
+ // inside the the input field (through css). We need to set a padding-right
+ // to the input element where the padding value would be at least the width
+ // of the button. Otherwise long user input would be invisible because it is
+ // behind the button.
+ $("body").on('click', '.form-group-search > input', function() {
+ // Get the width of the button (if the button isn't available
+ // buttonWidth will be null
+ var buttonWidth = $(this).next('.form-button-search').outerWidth();
+
+ if (buttonWidth) {
+ // Take the width of the button and ad 5px
+ var newWidth = buttonWidth + 5;
+ // Set the padding of the input element according
+ // to the width of the button
+ $(this).css('padding-right', newWidth);
+ }
+
+ });
+
+ /*
+ * This event handler hides all comment UI when the user clicks anywhere on the page
+ * It ensures that we aren't closing the current comment box
+ *
+ * We are making an exception for buttons because of a race condition with the
+ * comment opening button that results in an already closed comment UI.
+ */
+ $(document).on('mousedown', function(event) {
+ if (event.target.type === 'button') {
+ return true;
+ }
+
+ var $dontclosethis = $(event.target).closest('.wall-item-comment-wrapper').find('.comment-edit-form');
+ $('.wall-item-comment-wrapper .comment-edit-submit-wrapper:visible').each(function() {
+ var $parent = $(this).parent('.comment-edit-form');
+ var itemId = $parent.data('itemId');
+
+ if ($dontclosethis[0] != $parent[0]) {
+ var textarea = $parent.find('textarea').get(0)
+
+ commentCloseUI(textarea, itemId);
+ }
+ });
+ });
+
+ // Customize some elements when the app is used in standalone mode on Android
+ if (window.matchMedia('(display-mode: standalone)').matches) {
+ // Open links to source outside of the webview
+ $('body').on('click', '.plink', function (e) {
+ $(e.target).attr('target', '_blank');
+ });
+ }
+
+ /*
+ * This event listeners ensures that the textarea size is updated event if the
+ * value is changed externally (textcomplete, insertFormatting, fbrowser...)
+ */
+ $(document).on('change', 'textarea', function(event) {
+ autosize.update(event.target);
+ });
+
+ /*
+ * Sticky aside on page scroll
+ * We enable the sticky aside only when window is wider than
+ * 976px - which is the maximum width where the aside is shown in
+ * mobile style - because on chrome-based browsers (desktop and
+ * android) the sticky plugin in mobile style causes the browser to
+ * scroll back to top the main content, making it impossible
+ * to navigate.
+ * A side effect is that the sitky aside isn't really responsive,
+ * since is enabled or not at page loading time.
+ */
+ if ($(window).width() > 976) {
+ $("aside").stick_in_parent({
+ offset_top: 100, // px, header + tab bar + spacing
+ recalc_every: 10
+ });
+ // recalculate sticky aside on clicks on <a> elements
+ // this handle height changes on expanding submenus
+ $("aside").on("click", "a", function(){
+ $(document.body).trigger("sticky_kit:recalc");
+ });
+ }
+
+ /*
+ * Add or remove "aside-out" class to body tag
+ * when the mobile aside is shown or hidden.
+ * The class is used in css to disable scroll in page when the aside
+ * is shown.
+ */
+ $("aside")
+ .on("shown.bs.offcanvas", function() {
+ $("body").addClass("aside-out");
+ })
+ .on("hidden.bs.offcanvas", function() {
+ $("body").removeClass("aside-out");
+ });
+
+ // Event listener for 'Show & hide event map' button in the network stream.
+ $("body").on("click", ".event-map-btn", function() {
+ showHideEventMap(this);
});
});
-//function commentOpenUI(obj, id) {
-// $(document).unbind( "click.commentOpen", handler );
-//
-// var handler = function() {
-// if(obj.value == '{{$comment}}') {
-// obj.value = '';
-// $("#comment-edit-text-" + id).addClass("comment-edit-text-full").removeClass("comment-edit-text-empty");
-// // Choose an arbitrary tab index that's greater than what we're using in jot (3 of them)
-// // The submit button gets tabindex + 1
-// $("#comment-edit-text-" + id).attr('tabindex','9');
-// $("#comment-edit-submit-" + id).attr('tabindex','10');
-// $("#comment-edit-submit-wrapper-" + id).show();
-// }
-// };
-//
-// $(document).bind( "click.commentOpen", handler );
-//}
-//
-//function commentCloseUI(obj, id) {
-// $(document).unbind( "click.commentClose", handler );
-//
-// var handler = function() {
-// if(obj.value === '') {
-// obj.value = '{{$comment}}';
-// $("#comment-edit-text-" + id).removeClass("comment-edit-text-full").addClass("comment-edit-text-empty");
-// $("#comment-edit-text-" + id).removeAttr('tabindex');
-// $("#comment-edit-submit-" + id).removeAttr('tabindex');
-// $("#comment-edit-submit-wrapper-" + id).hide();
-// }
-// };
-//
-// $(document).bind( "click.commentClose", handler );
-//}
function openClose(theID) {
var elem = document.getElementById(theID);
}
function showHide(theID) {
- if(document.getElementById(theID).style.display == "block") {
- document.getElementById(theID).style.display = "none"
+ var elem = document.getElementById(theID);
+ var edit = document.getElementById("comment-edit-submit-wrapper-" + theID.match('[0-9$]+'));
+
+ if ($(elem).is(':visible')) {
+ if (!$(edit).is(':visible')) {
+ edit.style.display = "block";
+ }
+ else {
+ elem.style.display = "none";
+ }
}
else {
- document.getElementById(theID).style.display = "block"
+ elem.style.display = "block";
}
}
+// Show & hide event map in the network stream by button click.
+function showHideEventMap(elm) {
+ // Get the id of the map element - it should be provided through
+ // the atribute "data-map-id".
+ var mapID = elm.getAttribute('data-map-id');
+
+ // Get translation labels.
+ var mapshow = elm.getAttribute('data-show-label');
+ var maphide = elm.getAttribute('data-hide-label');
-function showHideComments(id) {
- if( $('#collapsed-comments-' + id).is(':visible')) {
- $('#collapsed-comments-' + id).slideUp();
- $('#hide-comments-' + id).html(window.showMore);
- $('#hide-comments-total-' + id).show();
+ // Change the button labels.
+ if (elm.innerText == mapshow) {
+ $('#' + elm.id).text(maphide);
+ } else {
+ $('#' + elm.id).text(mapshow);
}
- else {
- $('#collapsed-comments-' + id).slideDown();
- $('#hide-comments-' + id).html(window.showFewer);
- $('#hide-comments-total-' + id).hide();
+ // Because maps are iframe elements, we cant hide it through css (display: none).
+ // We solve this issue by putting the map outside the screen with css.
+ // So the first time the 'Show map' button is pressed we move the map
+ // element into the screen area.
+ var mappos = $('#' + mapID).css('position');
+
+ if (mappos === 'absolute') {
+ $('#' + mapID).hide();
+ $('#' + mapID).css({position: 'relative', left: 'auto', top: 'auto'});
+ openClose(mapID);
+ } else {
+ openClose(mapID);
}
+ return false;
}
-
function justifyPhotos() {
justifiedGalleryActive = true;
$('#photo-album-contents').justifiedGallery({
margins: 3,
border: 0,
sizeRangeSuffixes: {
- 'lt100': '-2',
- 'lt240': '-2',
+ 'lt48': '-6',
+ 'lt80': '-5',
+ 'lt300': '-4',
'lt320': '-2',
- 'lt500': '',
'lt640': '-1',
'lt1024': '-0'
}
}).on('jg.complete', function(e){ justifiedGalleryActive = false; });
}
-function justifyPhotosAjax() {
- justifiedGalleryActive = true;
- $('#photo-album-contents').justifiedGallery('norewind').on('jg.complete', function(e){ justifiedGalleryActive = false; });
-}
-
+// Load a js script to the html head.
function loadScript(url, callback) {
- // Adding the script tag to the head as suggested before
+ // Check if the script is already in the html head.
+ var oscript = $('head script[src="' + url + '"]');
+
+ // Delete the old script from head.
+ if (oscript.length > 0) {
+ oscript.remove();
+ }
+ // Adding the script tag to the head as suggested before.
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.onreadystatechange = callback;
script.onload = callback;
- // Fire the loading
+ // Fire the loading.
head.appendChild(script);
}
-function random_digits(digits) {
- var rn = "";
- var rnd = "";
-
- for(var i = 0; i < digits; i++) {
- var rn = Math.round(Math.random() * (9));
- rnd += rn;
- }
-
- return rnd;
-}
-
// Does we need a ? or a & to append values to a url
function qOrAmp(url) {
if(url.search('\\?') < 0) {
}
}
-function contact_filter(item) {
- // get the html content from the js template of the contact-wrapper
- contact_tpl = unescape($(".javascript-template[rel=contact-template]").html());
-
- var variables = {
- id: item.id,
- name: item.name,
- username: item.username,
- thumb: item.thumb,
- img_hover: item.img_hover,
- edit_hover: item.edit_hover,
- account_type: item.account_type,
- photo_menu: item.photo_menu,
- alt_text: item.alt_text,
- dir_icon: item.dir_icon,
- sparkle: item.sparkle,
- itemurl: item.itemurl,
- url: item.url,
- network: item.network,
- tags: item.tags,
- details: item.details,
- };
-
- // open a new jSmart instance with the template
- var tpl = new jSmart (contact_tpl);
-
- // replace the variable with the values
- var html = tpl.fetch(variables);
-
- return html;
-}
-
-function filter_replace(item) {
-
- return item.name;
-}
-
-(function( $ ) {
- $.fn.contact_filter = function(backend_url, typ, autosubmit, onselect) {
- if(typeof typ === 'undefined') typ = '';
- if(typeof autosubmit === 'undefined') autosubmit = false;
-
- // Autocomplete contacts
- contacts = {
- match: /(^)([^\n]+)$/,
- index: 2,
- search: function(term, callback) { contact_search(term, callback, backend_url, typ); },
- replace: filter_replace,
- template: contact_filter,
- };
-
- this.attr('autocomplete','off');
- var a = this.textcomplete([contacts], {className:'accontacts', appendTo: '#contact-list'});
-
- a.on('textComplete:select', function(e, value, strategy) { $(".dropdown-menu.textcomplete-dropdown.media-list").show(); });
- };
-})( jQuery );
-
-
-// current time in milliseconds, to send each request to make sure
-// we 're not getting 304 response
-function timeNow() {
- return new Date().getTime();
-}
-
String.prototype.normalizeLink = function () {
var ret = this.replace('https:', 'http:');
var ret = ret.replace('//www', '//');
return trimmed;
};
-// Scroll to a specific item and highlight it
-// Note: jquery.color.js is needed
-function scrollToItem(itemID) {
- if( typeof itemID === "undefined")
+/**
+ * Scroll the screen to the item element whose id is provided, then highlights it
+ *
+ * Note: jquery.color.js is required
+ *
+ * @param {string} elementId The item element id
+ * @returns {undefined}
+ */
+function scrollToItem(elementId) {
+ if (typeof elementId === "undefined") {
return;
+ }
- var elm = $('#'+itemID);
+ var $el = $('#' + elementId + ' > .media');
// Test if the Item exists
- if(!elm.length)
+ if (!$el.length) {
return;
+ }
// Define the colors which are used for highlighting
var colWhite = {backgroundColor:'#F5F5F5'};
var colShiny = {backgroundColor:'#FFF176'};
- // Get the Item Position (we need to substract 100 to match
- // correct position
- var itemPos = $(elm).offset().top - 100;
+ // Get the Item Position (we need to substract 100 to match correct position
+ var itemPos = $el.offset().top - 100;
// Scroll to the DIV with the ID (GUID)
$('html, body').animate({
scrollTop: itemPos
- }, 400, function() {
+ }, 400).promise().done( function() {
// Highlight post/commenent with ID (GUID)
- $(elm).animate(colWhite, 1000).animate(colShiny).animate(colWhite, 600);
+ $el.animate(colWhite, 1000).animate(colShiny).animate(colWhite, 600);
});
}
return text;
}
+
+/**
+ * Sends a /like API call and updates the display of the relevant action button
+ * before the update reloads the item.
+ *
+ * @param {string} ident The id of the relevant item
+ * @param {string} verb The verb of the action
+ * @returns {undefined}
+ */
+function doLikeAction(ident, verb) {
+ unpause();
+
+ if (verb.indexOf('attend') === 0) {
+ $('.item-' + ident + ' .button-event:not(#' + verb + '-' + ident + ')').removeClass('active');
+ }
+ $('#' + verb + '-' + ident).toggleClass('active');
+ $('#like-rotator-' + ident.toString()).show();
+ $.get('like/' + ident.toString() + '?verb=' + verb, NavUpdate );
+ liking = 1;
+ force_update = true;
+ update_item = ident.toString();
+}
+
+// Decodes a hexadecimally encoded binary string
+function hex2bin (s) {
+ // discuss at: http://locutus.io/php/hex2bin/
+ // original by: Dumitru Uzun (http://duzun.me)
+ // example 1: hex2bin('44696d61')
+ // returns 1: 'Dima'
+ // example 2: hex2bin('00')
+ // returns 2: '\x00'
+ // example 3: hex2bin('2f1q')
+ // returns 3: false
+ var ret = [];
+ var i = 0;
+ var l;
+ s += '';
+
+ for (l = s.length; i < l; i += 2) {
+ var c = parseInt(s.substr(i, 1), 16);
+ var k = parseInt(s.substr(i + 1, 1), 16);
+ if (isNaN(c) || isNaN(k)) {
+ return false;
+ }
+ ret.push((c << 4) | k);
+ }
+ return String.fromCharCode.apply(String, ret);
+}
+
+// Convert binary data into hexadecimal representation
+function bin2hex (s) {
+ // From: http://phpjs.org/functions
+ // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
+ // + bugfixed by: Onno Marsman
+ // + bugfixed by: Linuxworld
+ // + improved by: ntoniazzi (http://phpjs.org/functions/bin2hex:361#comment_177616)
+ // * example 1: bin2hex('Kev');
+ // * returns 1: '4b6576'
+ // * example 2: bin2hex(String.fromCharCode(0x00));
+ // * returns 2: '00'
+
+ var i, l, o = "", n;
+
+ s += "";
+
+ for (i = 0, l = s.length; i < l; i++) {
+ n = s.charCodeAt(i).toString(16);
+ o += n.length < 2 ? "0" + n : n;
+ }
+
+ return o;
+}
+
+// Dropdown menus with the class "dropdown-head" will display the active tab
+// as button text
+function toggleDropdownText(elm) {
+ $(elm).closest(".dropdown").find('.btn').html($(elm).text() + ' <span class="caret"></span>');
+ $(elm).closest(".dropdown").find('.btn').val($(elm).data('value'));
+ $(elm).closest("ul").children("li").show();
+ $(elm).parent("li").hide();
+}
+
+// Check if element does have a specific class
+function hasClass(elem, cls) {
+ return (" " + elem.className + " " ).indexOf( " "+cls+" " ) > -1;
+}