]> git.mxchange.org Git - friendica.git/blobdiff - view/theme/frio/js/theme.js
Replace path parameter with query string parameter in Module\Search\Saved
[friendica.git] / view / theme / frio / js / theme.js
index 3f3128be404116790273e03e8e84fb0120f58402..46cea59ba23c60ccefed8efad885d55ae210139d 100644 (file)
@@ -10,7 +10,7 @@ $(document).ready(function(){
                        $("#back-to-top").fadeOut();
                }
        });
+
        // scroll body to 0px on click
        $("#back-to-top").click(function () {
                $("body,html").animate({
@@ -40,9 +40,7 @@ $(document).ready(function(){
        $(".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
        //
@@ -56,7 +54,7 @@ $(document).ready(function(){
        }
 
        // 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,
@@ -66,9 +64,24 @@ $(document).ready(function(){
        });
 
        // 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
@@ -84,17 +97,17 @@ $(document).ready(function(){
                                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
@@ -108,7 +121,10 @@ $(document).ready(function(){
                delay: {
                        show: 500,
                        hide: 100
-               }
+               },
+               sanitizeFn: function (content) {
+                       return DOMPurify.sanitize(content)
+               },
        });
 
        // initialize the bootstrap-select
@@ -130,7 +146,7 @@ $(document).ready(function(){
                // 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();
 
@@ -153,7 +169,7 @@ $(document).ready(function(){
        }
 
        // 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.
@@ -210,47 +226,157 @@ $(document).ready(function(){
 
        // 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);
@@ -264,52 +390,80 @@ function openClose(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';
@@ -320,22 +474,10 @@ function loadScript(url, callback) {
        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) {
@@ -345,71 +487,6 @@ function qOrAmp(url) {
        }
 }
 
-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', '//');
@@ -544,31 +621,38 @@ String.prototype.rtrim = function() {
        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() {
                // Highlight post/commenent with ID  (GUID)
-               $(elm).animate(colWhite, 1000).animate(colShiny).animate(colWhite, 600);
+               $el.animate(colWhite, 1000).animate(colShiny).animate(colWhite, 600);
        });
 }
 
@@ -581,3 +665,89 @@ function htmlToText(htmlString) {
 
        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;
+}