/** * Peafowl JS * Copyright 2016 Rodolfo Berrios */ /** * Peafowl DOM functions and event listeners */ $(function () { var ajaxSetup = { url: PF.obj.config.json_api, cache: false, dataType: "json", data: { auth_token: PF.obj.config.auth_token } }; if (typeof PF.obj.config.session_id !== typeof undefined) { ajaxSetup.data.session_id = PF.obj.config.session_id; } $.ajaxSetup(ajaxSetup); /** * WINDOW LISTENERS * ------------------------------------------------------------------------------------------------- */ $(window).bind("beforeunload", function () { if ( $("form", PF.obj.modal.selectors.root).data("beforeunload") == "continue" ) return; if ( $(PF.obj.modal.selectors.root).is(":visible") && PF.fn.form_modal_has_changed() ) { return PF.fn._s( "All the changes that you have made will be lost if you continue." ); } }); $(window).bind("hashchange", function () { // Call edit modal on #edit if ( window.location.hash == "#edit" && !$(PF.obj.modal.selectors.root).exists() ) $("[data-modal=edit]") .first() .click(); }); // Blind the tipTips on load PF.fn.bindtipTip(); var resizeTimer, scrollTimer, width = $(window).width(); // Fluid width on resize $(window).on("resize", function () { PF.fn.growl.fixPosition(); PF.fn.modal.fixScrollbars(); var device = PF.fn.getDeviceName(), handled = ["phone", "phablet"], desktop = ["tablet", "laptop", "desktop"]; clearTimeout(resizeTimer); clearTimeout(scrollTimer); scrollTimer = setTimeout(function () { $(".follow-scroll-wrapper, .follow-scroll-placeholder") .removeClass("position-fixed") .attr("style", ""); if ($("html").hasScrollBar().vertical) { PF.obj.follow_scroll.set(true); PF.obj.follow_scroll.process(true); } }, 25); //PF.fn.window_to_device(); // handled by window event parent var new_device = PF.fn.getDeviceName(); if ( (new_device !== device && ($.inArray(device, handled) >= 0 && $.inArray(new_device, handled) == -1)) || ($.inArray(device, desktop) >= 0 && $.inArray(new_device, desktop) == -1) ) { PF.fn.close_pops(); } $(".top-bar").css("top", ""); $(PF.fn.topMenu.vars.menu).css("height", $(window).height()); $("body").css({ position: "", height: "" }); $(".antiscroll") .removeClass("jsly") .data("antiscroll", ""); // Destroy for this? $(".antiscroll-inner").css({ height: "", width: "", maxheight: "" }); // .pop-box, .pop-box-inner ? PF.fn.list_fluid_width(); if (width !== $(window).width()) { if ( $("[data-action=top-bar-menu-full]", "#top-bar").hasClass("current") ) { PF.fn.topMenu.hide(0); } var cols_fn = function () { PF.fn.listing.columnizer(true, 0); $(PF.obj.listing.selectors.list_item).show(); }; cols_fn(); } width = $(window).width(); }); // Close the opened pop-boxes on HTML click $(document).on("click", "html", function () { PF.fn.close_pops(); }); /** * SMALL HELPERS AND THINGS --> "things" que chucha yo en ese tiempo wn * ------------------------------------------------------------------------------------------------- */ // Attemp to replace .svg with .png for browsers that doesn't support it if ($("html").hasClass("no-svg")) { $("img.replace-svg").replace_svg(); } // Keydown numeric input (prevents non numeric keys) $(document).on("keydown", ".numeric-input", function (e) { e.keydown_numeric(); }); // The handly data-scrollto. IT will scroll the elements to the target $(document).on("click", "[data-scrollto]", function (e) { var target = $(this).data("scrollto"), $target = $(!target.match(/^\#|\./) ? "#" + target : target); if ($target.exists()) { PF.fn.scroll($target); } else { console.log("PF scrollto error: target doesn't exists", $target); } }); $(document).on( "click focus", "[data-login-needed], [data-user-logged=must]", function (e) { if (!PF.fn.is_user_logged()) { e.preventDefault(); e.stopPropagation(); window.location.href = PF.obj.vars.urls.login; return false; } } ); // The handly data-trigger. It will trigger click for elements with data-trigger $(document).on("click", "[data-trigger]", function (e) { if (e.isPropagationStopped()) { return false; } var trigger = $(this).data("trigger"), $target = $(!trigger.match(/^\#|\./) ? "#" + trigger : trigger); if ($target.exists()) { e.stopPropagation(); e.preventDefault(); if (!$target.closest(PF.obj.modal.selectors.root).length) { PF.fn.modal.close(); } $target.click(); } else { console.log("PF trigger error: target doesn't exists", $target); } }); // Fix the auth_token inputs $("form[method=post]").each(function () { if (!$("input[name=auth_token]", this).exists()) { $(this).append( $("", { type: "hidden", name: "auth_token", value: PF.obj.config.auth_token }) ); } }); // Clear form like magic $(document).on("click", ".clear-form", function () { $(this) .closest("form")[0] .reset(); }); $(document).on("submit", "form[data-action=validate]", function (e) { var type = $(this).data("type"), errors = false, $validate = $(this).find("[required], [data-validate]"); $validate.each(function () { var input_type = $(this).attr("type"), pattern = $(this).attr("pattern"), errorFn = function (el) { $(el).highlight(); errors = true; }; if ($(this).is("[required]") && $(this).val() == "") { if ($(this).is(":hidden")) { var $hidden_target = $( $($(this).data("highlight")).exists() ? $(this).data("highlight") : "#" + $(this).data("highlight") ); $($hidden_target).highlight(); } errorFn(this); } if ( typeof pattern == "undefined" && /mail|url/.test(input_type) == false ) { return true; } if (pattern) { pattern = new RegExp(pattern); if (!pattern.test($(this).val())) { errorFn(this); } } if ( input_type == "email" && !$(this) .val() .isEmail() ) { errorFn(this); } }); if (errors) { PF.fn.growl.expirable( PF.fn._s("Check the errors in the form to continue.") ); return false; } }); // Co-combo breaker $(document).on("change", "select[data-combo]", function () { var $combo = $("#" + $(this).data("combo")); if ($combo.exists()) { $combo.children(".switch-combo").hide(); } var $combo_container = $( "#" + $(this) .closest("select") .data("combo") ), $combo_target = $( "[data-combo-value~=" + $("option:selected", this).attr("value") + "]", $combo_container ); if ($combo_target.exists()) { $combo_target .show() .find("[data-required]") .each(function () { $(this).attr("required", "required"); // re-enable any disabled required }); } // Disable [required] in hidden combos $(".switch-combo", $combo_container).each(function () { if ($(this).is(":visible")) return; $("[required]", this) .attr("data-required", true) .removeAttr("required"); }); }); // Y COMO DICE: ESCAPE FROM THE PLANET OF THE APES $(document).on("keyup", function (e) { $this = $(e.target); if (e.keyCode == 27) { if ( $(PF.obj.modal.selectors.root).is(":visible") && !$this.is(":input") ) { $( "[data-action=cancel],[data-action=close-modal]", PF.obj.modal.selectors.root ) .first() .click(); } } }); // Input events $(document).on("change", ":input", function (e) { PF.fn.growl.close(); }); $(document).on("keyup", ":input", function (e) { $(".input-warning", $(this).closest(".input-label")).html(""); }); $(document).on("blur", ":input", function () { var this_val = $.trim($(this).prop("value")); $(this).prop("value", this_val); }); // Select all on an input type $(document).on("click", ":input[data-focus=select-all]", function () { this.select(); }); // Input password strength $(document).on("keyup change blur", ":input[type=password]", function () { var password = testPassword($(this).val()), $parent = $(this).closest("div"); if ($(this).val() == "") { password.percent = 0; password.verdict = ""; } $("[data-content=password-meter-bar]", $parent) .attr("data-veredict", password.verdict.replace(/ /g, "-")) .width(password.percent); $("[data-text=password-meter-message]", $parent) .removeClass("red-warning") .text(password.verdict !== "" ? PF.fn._s(password.verdict) : ""); }); // Popup links $(document).on("click", "[rel=popup-link], .popup-link", function (e) { e.preventDefault(); var href = $(this)[ typeof $(this).attr("href") !== "undefined" ? "attr" : "data" ]("href"); if (typeof href == "undefined") { return; } if ( href.substring(0, 6) == "mailto" && PF.fn.isDevice(["phone", "phablet"]) ) { window.location = href; return false; } PF.fn.popup({ href: href }); }); /** * FOWLLOW SCROLL * ------------------------------------------------------------------------------------------------- */ $(window).scroll(function () { PF.obj.follow_scroll.process(); // todo:optimize }); /** * MODAL * ------------------------------------------------------------------------------------------------- */ // Call plain simple HTML modal $(document).on("click", "[data-modal=simple],[data-modal=html]", function () { var $target = $( "[data-modal=" + $(this).data("target") + "], #" + $(this).data("target") ).first(); PF.fn.modal.call({ template: $target.html(), buttons: false }); }); // Prevent modal submit form since we only use the form in the modal to trigger HTML5 validation $(document).on("submit", PF.obj.modal.selectors.root + " form", function (e) { if ($(this).data("prevented")) return false; // Don't send the form if is prevented if (typeof $(this).attr("method") !== "undefined") return; // Don't bind anything extra if is normal form return false; // Prevent default form handling }); // Form/editable/confirm modal $(document).on( "click", "[data-modal=edit],[data-modal=form],[data-confirm]", function (e) { e.preventDefault(); var $this = $(this); var $target; if ($this.is("[data-confirm]")) { $target = $this; PF.obj.modal.type = "confirm"; } else { $target = $( "[data-modal=" + $this.data("target") + "], #" + $this.data("target") ).first(); if ($target.length == 0) { $target = $("[data-modal=form-modal], #form-modal").first(); } if ($target.length == 0) { console.log("PF Error: Modal target doesn't exists."); } PF.obj.modal.type = $this.data("modal"); } var args = $this.data("args"), submit_function = window[$target.data("submit-fn")], cancel_function = window[$target.data("cancel-fn")], onload_function = window[$target.data("load-fn")], submit_done_msg = $target.data("submit-done"), ajax = { url: $target.data("ajax-url") || (typeof $target.data("is-xhr") !== typeof undefined ? PF.obj.config.json_api : null), deferred: window[$target.data("ajax-deferred")] }; // Window functions failed? Maybe those are named fn... if (typeof submit_function !== "function" && $target.data("submit-fn")) { var submit_fn_split = $target.data("submit-fn").split("."); submit_function = window; for (var i = 0; i < submit_fn_split.length; i++) { submit_function = submit_function[submit_fn_split[i]]; } } if (typeof cancel_function !== "function" && $target.data("cancel-fn")) { var cancel_fn_split = $target.data("cancel-fn").split("."); cancel_function = window; for (var i = 0; i < cancel_fn_split.length; i++) { cancel_function = cancel_function[cancel_fn_split[i]]; } } if (typeof load_function !== "function" && $target.data("load-fn")) { var load_fn_split = $target.data("load-fn").split("."); load_function = window; for (var i = 0; i < load_fn_split.length; i++) { load_function = load_function[load_fn_split[i]]; } } if (typeof ajax.deferred !== "object" && $target.data("ajax-deferred")) { var deferred_obj_split = $target.data("ajax-deferred").split("."); ajax.deferred = window; for (var i = 0; i < deferred_obj_split.length; i++) { ajax.deferred = ajax.deferred[deferred_obj_split[i]]; } } // Before fn var fn_before = window[$target.data("before-fn")]; if (typeof fn_before !== "function" && $target.data("before-fn")) { var before_obj_split = $target.data("before-fn").split("."); fn_before = window; for (var i = 0; i < before_obj_split.length; i++) { fn_before = fn_before[before_obj_split[i]]; } } if (typeof fn_before == "function") { fn_before(e); } var inline_options = $(this).data("options") || {}; // Confirm modal if ($this.is("[data-confirm]")) { var default_options = { message: $this.data("confirm"), confirm: typeof submit_function == "function" ? submit_function(args) : "", cancel: typeof cancel_function == "function" ? cancel_function(args) : "", ajax: ajax }; if ($this.attr("href") && default_options.confirm == "") { default_options.confirm = function () { return window.location.replace($this.attr("href")); }; } PF.fn.modal.confirm($.extend(default_options, inline_options)); } else { // Form/editable var default_options = { template: $target.html(), button_submit: $(this).is("[data-modal=edit]") ? PF.fn._s("Save changes") : PF.fn._s("Submit"), confirm: function () { var form_modal_has_changed = PF.fn.form_modal_has_changed(); // Conventional form handling var $form = $("form", PF.obj.modal.selectors.root); if (typeof $form.attr("action") !== "undefined") { $form.data("prevented", !form_modal_has_changed); PF.fn.modal.close(); return; } // Handle the required thing for non-visible elements $(":input[name]", $form).each(function () { if (!$(this).is(":visible")) { var input_attr = $(this).attr("required"); if ( typeof input_attr !== typeof undefined && input_attr !== false ) { $(this) .prop("required", false) .attr("data-required", "required"); } } else { if ($(this).attr("data-required") == "required") { $(this).prop("required", true); } } }); // Detect HTML5 validation if (!$form[0].checkValidity()) { return false; } // Run the full function only when the form changes if (!form_modal_has_changed && !inline_options.forced) { PF.fn.modal.close(); return; } if (typeof submit_function == "function") submit_fn = submit_function(args); if (typeof submit_fn !== "undefined" && submit_fn == false) { return false; } $(":input", PF.obj.modal.selectors.root).each(function () { $(this).val($.trim($(this).val())); }); if ($this.is("[data-modal=edit]")) { // Set the input values before cloning the html $target.html( $( PF.obj.modal.selectors.body, $(PF.obj.modal.selectors.root).bindFormData() ) .html() .replace(/rel=[\'"]tooltip[\'"]/g, 'rel="template-tooltip"') ); } if (typeof ajax.url !== "undefined") { return true; } else { PF.fn.modal.close(function () { if (typeof submit_done_msg !== "undefined") { PF.fn.growl.expirable( submit_done_msg !== "" ? submit_done_msg : PF.fn._s("Changes saved successfully.") ); } }); } }, cancel: function () { if (typeof cancel_fn == "function") cancel_fn = cancel_fn(); if (typeof cancel_fn !== "undefined" && cancel_fn == false) { return false; } // nota: falta template aca if ( $target.data("prompt") != "skip" && PF.fn.form_modal_has_changed() ) { if ($(PF.obj.modal.selectors.changes_confirm).exists()) return; $(PF.obj.modal.selectors.box, PF.obj.modal.selectors.root) .css({ transition: "none" }) .hide(); $(PF.obj.modal.selectors.root).append( '

' + PF.fn._s( "All the changes that you have made will be lost if you continue." ) + '

' + PF.fn._s("or") + ' ' + PF.fn._s("continue anyway") + "
" ); $(PF.obj.modal.selectors.changes_confirm) .css( "margin-top", -$(PF.obj.modal.selectors.changes_confirm).outerHeight(true) / 2 ) .hide() .fadeIn("fast"); } else { PF.fn.modal.close(); if (window.location.hash == "#edit") window.location.hash = ""; } }, load: function () { if (typeof load_function == "function") load_function(); }, callback: function () { }, ajax: ajax }; PF.fn.modal.call($.extend(default_options, inline_options)); } } ); // Check user login modal -> Must be login to continue if (!PF.fn.is_user_logged()) { $("[data-login-needed]:input, [data-user-logged=must]:input").each( function () { $(this).attr("readonly", true); } ); } // Modal form keydown listener $(document).on("keydown", PF.obj.modal.selectors.root + " input", function ( e ) { // nota: solia ser keyup var $this = $(e.target), key = e.charCode || e.keyCode; if (key !== 13) { PF.fn.growl.close(); return; } if ( key == 13 && $("[data-action=submit]", PF.obj.modal.selectors.root).exists() && !$this.is(".prevent-submit") ) { // 13 == enter key $("[data-action=submit]", PF.obj.modal.selectors.root).click(); } }); // Trigger modal edit on hash #edit // It must be placed after the event listener if (window.location.hash && window.location.hash == "#edit") { $("[data-modal=edit]") .first() .click(); } /** * MOBILE TOP BAR MENU * ------------------------------------------------------------------------------------------------- */ $(document).on("click", "[data-action=top-bar-menu-full]", function () { var hasClass = $("[data-action=top-bar-menu-full]", "#top-bar").hasClass( "current" ); PF.fn.topMenu[hasClass ? "hide" : "show"](); }); /** * SEARCH INPUT * ------------------------------------------------------------------------------------------------- */ // Top-search feature $(document).on("click", "[data-action=top-bar-search]", function () { $("[data-action=top-bar-search-input]", ".top-bar") .removeClass("hidden") .show(); $("[data-action=top-bar-search-input]:visible input") .first() .focus(); if ( is_ios() && !$(this) .closest(PF.fn.topMenu.vars.menu) .exists() ) { $(".top-bar").css("position", "absolute"); } $("[data-action=top-bar-search]", ".top-bar").hide(); }); // Search icon click -> focus input $(document).on("click", ".input-search .icon-search", function (e) { $("input", e.currentTarget.offsetParent).focus(); }); // Clean search input $(document).on( "click", ".input-search .icon-close, .input-search [data-action=clear-search]", function (e) { var $input = $("input", e.currentTarget.offsetParent); if ($input.val() == "") { if ( $(this) .closest("[data-action=top-bar-search-input]") .exists() ) { $("[data-action=top-bar-search-input]", ".top-bar").hide(); $("[data-action=top-bar-search]", ".top-bar") .removeClass("opened") .show(); if ( is_ios() && $(this) .closest("#top-bar") .css("position") !== "fixed" ) { $(".top-bar").css("position", "fixed"); } } } else { if ( !$(this) .closest("[data-action=top-bar-search-input]") .exists() ) { $(this).hide(); } $input.val("").change(); } } ); // Input search clear search toggle $(document).on("keyup change", "input.search", function (e) { var $input = $(this), $div = $(this).closest(".input-search"); if ( !$(this) .closest("[data-action=top-bar-search-input]") .exists() ) { var todo = $input.val() == "" ? "hide" : "show"; $(".icon-close, [data-action=clear-search]", $div)[todo](); } }); /** * POP BOXES (MENUS) * ------------------------------------------------------------------------------------------------- */ $(document) .on("click mouseenter", ".pop-btn", function (e) { if ( PF.fn.isDevice(["phone", "phablet"]) && (e.type == "mouseenter" || $(this).hasClass("pop-btn-desktop")) ) { return; } var $this_click = $(e.target); var $pop_btn; var $pop_box; var devices = $.makeArray(["phone", "phablet"]); var $this = $(this); if (e.type == "mouseenter" && !$(this).hasClass("pop-btn-auto")) return; if ( $(this).hasClass("disabled") || ($this_click.closest(".current").exists() && !PF.fn.isDevice("phone") && !$this_click.closest(".pop-btn-show").exists()) ) { return; } PF.fn.growl.close(); e.stopPropagation(); $pop_btn = $(this); $pop_box = $(".pop-box", $pop_btn); $pop_btn.addClass("opened"); $(".pop-box-inner", $pop_box).css("max-height", ""); if (PF.fn.isDevice(devices)) { var text = $(".btn-text,.text,.pop-btn-text", $pop_btn) .first() .text(); if (typeof text == "undefined" || text == "") { text = PF.fn._s("Select"); } if (!$(".pop-box-header", $pop_box).exists()) { $pop_box.prepend( $("
", { class: "pop-box-header", html: text + '' }) ); } } else { $(".pop-box-header", $pop_box).remove(); $pop_box.css({ bottom: "" }); } if ( $pop_box.hasClass("anchor-center") && typeof $pop_box.data("guidstr") == typeof undefined ) { if (!PF.fn.isDevice(devices)) { $pop_box.css("margin-left", -($pop_box.width() / 2)); } else { $pop_box.css("margin-left", ""); } } // Pop button changer if ($this_click.is("[data-change]")) { $("li", $pop_box).removeClass("current"); $this_click.closest("li").addClass("current"); $("[data-text-change]", $pop_btn).text( $("li.current a", $pop_box).text() ); e.preventDefault(); } if (!$pop_box.exists()) return; // Click inside the bubble only for .pop-keep-click var $this = e.istriggered ? $(e.target) : $(this); if ( $pop_box.is(":visible") && $(e.target) .closest(".pop-box-inner") .exists() && $this.hasClass("pop-keep-click") ) { return; } $(".pop-box:visible") .not($pop_box) .hide() .closest(".pop-btn") .removeClass("opened"); var callback = function ($pop_box) { if (!$pop_box.is(":visible")) { var guidstr = $pop_box.attr("data-guidstr"); $pop_box .css("marginLeft", "") .removeClass(guidstr) .removeAttr("data-guidstr") .closest(".pop-btn") .removeClass("opened"); if (typeof guidstr !== typeof undefined) { $("style#" + guidstr).remove(); } } else { if (!PF.fn.isDevice(devices)) { var posMargin = $pop_box.css("marginLeft"); if (typeof posMargin !== typeof undefined) { posMargin = parseFloat(posMargin); $pop_box.css("marginLeft", ""); } var cutoff = $pop_box.getWindowCutoff(); if ( cutoff && (cutoff.left || cutoff.right) && cutoff.right < posMargin ) { var guidstr = "guid-" + PF.fn.guid(); $pop_box .css("marginLeft", cutoff.right + "px") .addClass(guidstr) .attr("data-guidstr", guidstr); var posArrow = $this.outerWidth() / 2 + $this.offset().left - $pop_box.offset().left; var selectors = []; $.each(["top", "bottom"], function (i, v) { $.each(["after", "before"], function (ii, vv) { selectors.push("." + guidstr + ".arrow-box-" + v + ":" + vv); }); }); $( '" ).appendTo("head"); } else { $pop_box.css("marginLeft", posMargin + "px"); } $(".antiscroll-wrap:not(.jsly):visible", $pop_box) .addClass("jsly") .antiscroll(); } else { $(".antiscroll-inner", $pop_box).height("100%"); } } }; if (PF.fn.isDevice(devices)) { if ($(this).is("[data-action=top-bar-notifications]")) { $pop_box.css({ height: $(window).height() }); } var pop_box_h = $pop_box.height() + "px"; var menu_top = parseInt($(".top-bar").outerHeight()) + parseInt($(".top-bar").css("top")) + parseInt($(".top-bar").css("margin-top")) + parseInt($(".top-bar").css("margin-bottom")) + "px"; // hide if ($pop_box.is(":visible")) { $("#pop-box-mask").css({ opacity: 0 }); $pop_box.css({ transform: "none" }); if ($this.closest(PF.fn.topMenu.vars.menu).exists()) { $(".top-bar").css({ transform: "none" }); $(PF.fn.topMenu.vars.menu).css({ height: $(window).height() + parseInt(menu_top) }); } setTimeout(function () { $pop_box.hide().attr("style", ""); $("#pop-box-mask").remove(); callback($pop_box); if ($this.closest(PF.fn.topMenu.vars.menu).exists()) { $(PF.fn.topMenu.vars.menu).css({ height: "" }); $(PF.fn.topMenu.vars.menu).animate( { scrollTop: PF.fn.topMenu.vars.scrollTop }, PF.obj.config.animation.normal / 2 ); } }, PF.obj.config.animation.normal); if (!$("body").data("hasOverflowHidden")) { $("body").removeClass("overflow-hidden"); } } else { // show $("#pop-box-mask").remove(); $pop_box.parent().prepend( $("
", { id: "pop-box-mask", class: "fullscreen soft-black" }).css({ zIndex: 400, display: "block" }) ); PF.fn.topMenu.vars.scrollTop = $(PF.fn.topMenu.vars.menu).scrollTop(); setTimeout(function () { $("#pop-box-mask").css({ opacity: 1 }); setTimeout(function () { $pop_box.show().css({ bottom: "-" + pop_box_h, maxHeight: $(window).height(), zIndex: 1000, transform: "translate(0,0)" }); setTimeout(function () { $pop_box.css({ transform: "translate(0,-" + pop_box_h + ")" }); }, 1); setTimeout(function () { callback($pop_box); }, PF.obj.config.animation.normal); if ($("body").hasClass("overflow-hidden")) { $("body").data("hasOverflowHidden", 1); } else { $("body").addClass("overflow-hidden"); } if ($this.closest(PF.fn.topMenu.vars.menu).exists()) { $(".top-bar").css({ transform: "translate(0, -" + menu_top + ")" }); $(PF.fn.topMenu.vars.menu).css({ height: $(window).height() + parseInt(menu_top) }); } $(".pop-box-inner", $pop_box).css( "height", $pop_box.height() - $(".pop-box-header", $pop_box).outerHeight(true) ); }, 1); }, 1); } } else { $pop_box[$pop_box.is(":visible") ? "hide" : "show"](0, function () { callback($pop_box); }); } }) .on("mouseleave", ".pop-btn", function () { if (!PF.fn.isDevice(["laptop", "desktop"])) { return; } var $pop_btn = $(this), $pop_box = $(".pop-box", $pop_btn); if ( !$pop_btn.hasClass("pop-btn-auto") || (PF.fn.isDevice(["phone", "phablet"]) && $pop_btn.hasClass("pop-btn-auto")) ) { return; } if ( !PF.fn.isDevice(["phone", "phablet", "tablet"]) && $(this).hasClass("pop-btn-delayed") ) { $(this).removeClass("pop-btn-auto"); } $pop_box .hide() .closest(".pop-btn") .removeClass("opened"); }); $(".pop-btn-delayed").delayedAction({ delayedAction: function ($element) { if (PF.fn.isDevice(["phone", "phablet", "tablet"])) return; var $el = $(".pop-box-inner", $element); if ($el.is(":hidden")) { $element.addClass("pop-btn-auto").click(); } }, hoverTime: 2000 }); /** * TABS * ------------------------------------------------------------------------------------------------- */ // Hash on load (static tabs) changer if (window.location.hash) { /* var $hash_node = $("[href="+ window.location.hash +"]"); if($hash_node.exists()) { $.each($("[href="+ window.location.hash +"]")[0].attributes, function(){ PF.obj.tabs.hashdata[this.name] = this.value; }); PF.obj.tabs.hashdata.pushed = "tabs"; History.replaceState({ href: window.location.hash, "data-tab": $("[href="+ window.location.hash +"]").data("tab"), pushed: "tabs", statenum: 0 }, null, null); } */ } // Stock tab onload data if ($(".content-tabs").exists() /* && !window.location.hash*/) { var $tab = $("a", ".content-tabs .current"); History.replaceState( { href: $tab.attr("href"), "data-tab": $tab.data("tab"), pushed: "tabs", statenum: 0 }, null, null ); } // Keep scroll position (history.js) var State = History.getState(); if (typeof State.data == "undefined") { History.replaceState( { scrollTop: 0 }, document.title, window.location.href ); // Stock initial scroll } History.Adapter.bind(window, "popstate", function () { var State = History.getState(); if (State.data && typeof State.data.scrollTop !== "undefined") { if ($(window).scrollTop() !== State.data.scrollTop) { $(window).scrollTop(State.data.scrollTop); } } return; }); // Toggle tab display $("a", ".content-tabs").click(function (e) { if ($(this).data("link") == true) { $(this).data("tab", false); } if ( $(this) .closest(".current,.disabled") .exists() ) { e.preventDefault(); return; } if (typeof $(this).data("tab") == "undefined") return; var dataTab = {}; $.each(this.attributes, function () { dataTab[this.name] = this.value; }); dataTab.pushed = "tabs"; // This helps to avoid issues on ?same and ?same#else /*dataTab.statenum = 0; console.log({ data: History.getState().data, state: History.getState().data.statenum }) if(History.getState().data && typeof History.getState().data.statenum !== "undefined") { dataTab.statenum = History.getState().data.statenum + 1 }*/ /*if($(this).attr("href") && $(this).attr("href").indexOf("#") === 0) { // to ->#Hash PF.obj.tabs.hashdata = dataTab; if(typeof e.originalEvent == "undefined") { window.location.hash = PF.obj.tabs.hashdata.href.substring(1); } } else { // to ->?anything if($("#" + dataTab["data-tab"]).data("load") != "classic") { History.pushState(dataTab, document.title, $(this).attr("href")); e.preventDefault(); } } */ if ($("#" + dataTab["data-tab"]).data("load") != "classic") { if (window.location.hash) { var url = window.location.href; url = url.replace(window.location.hash, ""); } History.pushState( dataTab, document.title, typeof url !== "undefined" ? url : $(this).attr("href") ); e.preventDefault(); } var $tab_menu = $("[data-action=tab-menu]", $(this).closest(".header")); $tab_menu.find("[data-content=current-tab-label]").text($(this).text()); if ($tab_menu.is(":visible")) { $tab_menu.click(); } }); $(document).on("click", "[data-action=tab-menu]", function () { var $tabs = $(this) .closest(".header") .find(".content-tabs"), visible = $tabs.is(":visible"), $this = $(this); if (!visible) { $tabs.data("classes", $tabs.attr("class")); $tabs.removeClass(function (index, css) { return (css.match(/\b\w+-hide/g) || []).join(" "); }); $tabs.hide(); } if (!visible) { $this.removeClass("current"); } $tabs[visible ? "hide" : "show"](); if (visible) { $tabs.css("display", "").addClass($tabs.data("classes")); $this.addClass("current"); } }); // On state change bind tab changes $(window).bind("statechange", function (e) { PF.fn.growl.close(); var dataTab; dataTab = History.getState().data; if (dataTab && dataTab.pushed == "tabs") { PF.fn.show_tab(dataTab["data-tab"]); } }); /** * LISTING * ------------------------------------------------------------------------------------------------- */ // Stock the scroll position on list element click $(document).on("click", ".list-item a", function (e) { if ($(this).attr("src") == "") return; History.replaceState( { scrollTop: $(window).scrollTop() }, document.title, window.location.href ); }); // Load more (listing +1 page) $(document).on("click", "[data-action=load-more]", function (e) { $(this) .closest(".content-listing-more") .hide(); if ( !PF.fn.is_listing() || $(this) .closest(PF.obj.listing.selectors.content_listing) .is(":hidden") || $(this) .closest("#content-listing-template") .exists() || PF.obj.listing.calling ) return; PF.fn.listing.queryString.stock_new(); // Seek hack PF.obj.listing.query_string.seek = $(this).attr("data-seek"); // Page hack PF.obj.listing.query_string.page = $( PF.obj.listing.selectors.content_listing_visible ).data("page"); PF.obj.listing.query_string.page++; // Offset hack // var offset = $(PF.obj.listing.selectors.content_listing_visible).data("offset"); // if(typeof offset !== "undefined") { // PF.obj.listing.query_string.offset = offset; // if(typeof PF.obj.listing.params_hidden == "undefined") { // PF.obj.listing.params_hidden = {}; // } // PF.obj.listing.params_hidden.offset = offset; // } else { // if(typeof PF.obj.listing.query_string.offset !== "undefined") { // delete PF.obj.listing.query_string.offset; // } // if(PF.obj.listing.params_hidden && typeof PF.obj.listing.params_hidden.offset !== "undefined") { // delete PF.obj.listing.params_hidden.offset; // } // } PF.fn.listing.ajax(); e.preventDefault(); }); // List found on load html -> Do the columns! if ($(PF.obj.listing.selectors.list_item).length > 0) { PF.fn.listing.show(); // Bind the infinte scroll $(window).scroll(function () { var $loadMore = $( PF.obj.listing.selectors.content_listing_load_more, PF.obj.listing.selectors.content_listing_visible ).find("button[data-action=load-more]"); // console.log($loadMore.length); if ( $loadMore.length > 0 && $(window).scrollTop() + $(window).innerHeight() > $(document).height() - 300 && PF.obj.listing.calling == false ) { $loadMore.click(); } }); } // Multi-selection tools $(document).on( "click", PF.obj.modal.selectors.root + " [data-switch]", function () { var $this_modal = $(this).closest(PF.obj.modal.selectors.root); $("[data-view=switchable]", $this_modal).hide(); $("#" + $(this).attr("data-switch"), $this_modal).show(); } ); $(document).on("click", "[data-toggle]", function () { var $target = $("[data-content=" + $(this).data("toggle") + "]"); var show = !$target.is(":visible"); $(this).html($(this).data("html-" + (show ? "on" : "off"))); $target.toggle(); }); // Cookie law thing $(document).on("click", "[data-action=cookie-law-close]", function () { var $cookie = $(this).closest("#cookie-law-banner"); var cookieName = typeof $cookie.data("cookie") !== typeof undefined ? $cookie.data("cookie") : "PF_COOKIE_LAW_DISPLAY"; Cookies.set(cookieName, 0, { expires: 365 }); $cookie.remove(); }); // One-click input copy Clipboard = new Clipboard("[data-action=copy]", { text: function (trigger) { var $target = $(trigger.getAttribute("data-action-target")); var text = $target.is(":input") ? $target.val() : $target.text(); return text.trim(); } }); Clipboard.on("success", function (e) { var $target = $(e.trigger.getAttribute("data-action-target")); $target.highlight(); e.clearSelection(); }); }); /** * PEAFOWL OBJECT * ------------------------------------------------------------------------------------------------- */ var PF = { fn: {}, str: {}, obj: {} }; /** * PEAFOWL CONFIG * ------------------------------------------------------------------------------------------------- */ PF.obj.config = { base_url: "", json_api: "/json/", listing: { items_per_page: 24 }, animation: { easingFn: "ease", normal: 400, fast: 250 } }; /** * WINDOW VARS * ------------------------------------------------------------------------------------------------- */ /** * LANGUAGE FUNCTIONS * ------------------------------------------------------------------------------------------------- */ PF.obj.l10n = {}; /** * Get lang string by key * @argument string (lang key string) */ // pf: get_pf_lang PF.fn._s = function (string, s) { var string; if (typeof string == "undefined") { return string; } if ( typeof PF.obj.l10n !== "undefined" && typeof PF.obj.l10n[string] !== "undefined" ) { string = PF.obj.l10n[string][0]; if (typeof string == "undefined") { string = string; } } else { string = string; } string = string.toString(); if (typeof s !== "undefined") { string = sprintf(string, s); } return string; }; PF.fn._n = function (singular, plural, n) { var string; if ( typeof PF.obj.l10n !== "undefined" && typeof PF.obj.l10n[singular] !== "undefined" ) { string = PF.obj.l10n[singular][n == 1 ? 0 : 1]; } else { string = n == 1 ? singular : plural; } string = typeof string == "undefined" ? singular : string.toString(); if (typeof n !== "undefined") { string = sprintf(string, n); } return string; }; /** * Extend Peafowl lang * Useful to add or replace strings * @argument strings obj */ // pf: extend_pf_lang PF.fn.extend_lang = function (strings) { $.each(PF.obj.lang_strings, function (i, v) { if (typeof strings[i] !== "undefined") { $.extend(PF.obj.lang_strings[i], strings[i]); } }); }; /** * HELPER FUNCTIONS * ------------------------------------------------------------------------------------------------- */ PF.fn.get_url_vars = function () { var match, pl = /\+/g, // Regex for replacing addition symbol with a space search = /([^&=]+)=?([^&]*)/g, decode = function (s) { return decodeURIComponent(escape(s.replace(pl, " "))); }, query = window.location.search.substring(1), urlParams = {}; while ((match = search.exec(query))) { urlParams[decode(match[1])] = decode(match[2]); } return urlParams; }; PF.fn.get_url_var = function (name) { return PF.fn.get_url_vars()[name]; }; PF.fn.is_user_logged = function () { return $("#top-bar-user").exists(); // nota: default version // It should use backend conditional }; PF.fn.generate_random_string = function (len) { if (typeof len == "undefined") len = 5; var text = ""; var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; for (var i = 0; i < len; i++) { text += possible.charAt(Math.floor(Math.random() * possible.length)); } return text; }; PF.fn.getDateTime = function () { var now = new Date(); var year = now.getFullYear(); var month = now.getMonth() + 1; var day = now.getDate(); var hour = now.getHours(); var minute = now.getMinutes(); var second = now.getSeconds(); if (month.toString().length == 1) { var month = "0" + month; } if (day.toString().length == 1) { var day = "0" + day; } if (hour.toString().length == 1) { var hour = "0" + hour; } if (minute.toString().length == 1) { var minute = "0" + minute; } if (second.toString().length == 1) { var second = "0" + second; } var dateTime = year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second; return dateTime; }; PF.fn.htmlEncode = function (value) { return $("
") .text($.trim(value)) .html(); }; PF.fn.htmlDecode = function (value) { return $("
") .html($.trim(value)) .text(); }; PF.fn.nl2br = function (str) { var breakTag = "
"; return (str + "").replace( /([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, "$1" + breakTag + "$2" ); }; // https://raw.githubusercontent.com/johndwells/phpjs/master/functions/info/version_compare.js PF.fn.versionCompare = function (v1, v2, operator) { this.php_js = this.php_js || {}; this.php_js.ENV = this.php_js.ENV || {}; // END REDUNDANT // Important: compare must be initialized at 0. var i = 0, x = 0, compare = 0, // vm maps textual PHP versions to negatives so they're less than 0. // PHP currently defines these as CASE-SENSITIVE. It is important to // leave these as negatives so that they can come before numerical versions // and as if no letters were there to begin with. // (1alpha is < 1 and < 1.1 but > 1dev1) // If a non-numerical value can't be mapped to this table, it receives // -7 as its value. vm = { dev: -6, alpha: -5, a: -5, beta: -4, b: -4, RC: -3, rc: -3, "#": -2, p: 1, pl: 1 }, // This function will be called to prepare each version argument. // It replaces every _, -, and + with a dot. // It surrounds any nonsequence of numbers/dots with dots. // It replaces sequences of dots with a single dot. // version_compare('4..0', '4.0') == 0 // Important: A string of 0 length needs to be converted into a value // even less than an unexisting value in vm (-7), hence [-8]. // It's also important to not strip spaces because of this. // version_compare('', ' ') == 1 prepVersion = function (v) { v = ("" + v).replace(/[_\-+]/g, "."); v = v.replace(/([^.\d]+)/g, ".$1.").replace(/\.{2,}/g, "."); return !v.length ? [-8] : v.split("."); }; // This converts a version component to a number. // Empty component becomes 0. // Non-numerical component becomes a negative number. // Numerical component becomes itself as an integer. numVersion = function (v) { return !v ? 0 : isNaN(v) ? vm[v] || -7 : parseInt(v, 10); }; v1 = prepVersion(v1); v2 = prepVersion(v2); x = Math.max(v1.length, v2.length); for (i = 0; i < x; i++) { if (v1[i] == v2[i]) { continue; } v1[i] = numVersion(v1[i]); v2[i] = numVersion(v2[i]); if (v1[i] < v2[i]) { compare = -1; break; } else if (v1[i] > v2[i]) { compare = 1; break; } } if (!operator) { return compare; } // Important: operator is CASE-SENSITIVE. // "No operator" seems to be treated as "<." // Any other values seem to make the function return null. switch (operator) { case ">": case "gt": return compare > 0; case ">=": case "ge": return compare >= 0; case "<=": case "le": return compare <= 0; case "==": case "=": case "eq": return compare === 0; case "<>": case "!=": case "ne": return compare !== 0; case "": case "<": case "lt": return compare < 0; default: return null; } }; /** * Basename * http://stackoverflow.com/questions/3820381/need-a-basename-function-in-javascript */ PF.fn.baseName = function (str) { var base = new String(str).substring(str.lastIndexOf("/") + 1); if (base.lastIndexOf(".") != -1) { base = base.substring(0, base.lastIndexOf(".")); } return base; }; // https://stackoverflow.com/a/8809472 PF.fn.guid = function () { var d = new Date().getTime(); if ( typeof performance !== "undefined" && typeof performance.now === "function" ) { d += performance.now(); //use high-precision timer if available } return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) { var r = (d + Math.random() * 16) % 16 | 0; d = Math.floor(d / 16); return (c === "x" ? r : (r & 0x3) | 0x8).toString(16); }); }; PF.fn.md5 = function (string) { return SparkMD5.hash(string); }; /** * dataURI to BLOB * http://stackoverflow.com/questions/4998908/convert-data-uri-to-file-then-append-to-formdata */ PF.fn.dataURItoBlob = function (dataURI) { // convert base64/URLEncoded data component to raw binary data held in a string var byteString; if (dataURI.split(",")[0].indexOf("base64") >= 0) { byteString = atob(dataURI.split(",")[1]); } else { byteString = unescape(dataURI.split(",")[1]); } // separate out the mime component var mimeString = dataURI .split(",")[0] .split(":")[1] .split(";")[0]; // write the bytes of the string to a typed array var ia = new Uint8Array(byteString.length); for (var i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } return new Blob([ia], { type: mimeString }); }; PF.fn.clean_facebook_hash = function () { if (window.location.hash == "#_=_") { window.location.hash = ""; } }; PF.fn.clean_facebook_hash(); /** * Get the min and max value from 1D array */ Array.min = function (array) { return Math.min.apply(Math, array); }; Array.max = function (array) { return Math.max.apply(Math, array); }; /** * Return the sum of all the values in a 1D array */ Array.sum = function (array) { return array.reduce(function (pv, cv) { return cv + pv; }); }; /** * Return the size of an object */ Object.size = function (obj) { var size = 0, key; for (key in obj) { if (obj.hasOwnProperty(key)) size++; } return size; }; /** * Flatten an object */ Object.flatten = function (obj, prefix) { if (typeof prefix == "undefined") var prefix = ""; var result = {}; $.each(obj, function (key, value) { if (!value) return; if (typeof value == "object") { result = $.extend({}, result, Object.flatten(value, prefix + key + "_")); } else { result[prefix + key] = value; } }); return result; }; /** * Tells if the string is a number or not */ String.prototype.isNumeric = function () { return !isNaN(parseFloat(this)) && isFinite(this); }; /** * Repeats an string */ String.prototype.repeat = function (num) { return new Array(num + 1).join(this); }; /** * Ucfirst */ String.prototype.capitalizeFirstLetter = function () { return this.charAt(0).toUpperCase() + this.slice(1); }; /** * Replace all */ String.prototype.replaceAll = function (search, replacement) { var target = this; return target.replace(new RegExp(search, "g"), replacement); }; /** * Tells if the string is a email or not */ String.prototype.isEmail = function () { var regex = /^([a-zA-Z0-9_\.\-\+])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/; return regex.test(this); }; // http://phpjs.org/functions/round/ String.prototype.getRounded = function (precision, mode) { var m, f, isHalf, sgn; // helper variables precision |= 0; // making sure precision is integer m = Math.pow(10, precision); value = this; value *= m; sgn = (value > 0) | -(value < 0); // sign of the number isHalf = value % 1 === 0.5 * sgn; f = Math.floor(value); if (isHalf) { switch (mode) { case "PHP_ROUND_HALF_DOWN": value = f + (sgn < 0); // rounds .5 toward zero break; case "PHP_ROUND_HALF_EVEN": value = f + (f % 2) * sgn; // rouds .5 towards the next even integer break; case "PHP_ROUND_HALF_ODD": value = f + !(f % 2); // rounds .5 towards the next odd integer break; default: value = f + (sgn > 0); // rounds .5 away from zero } } return (isHalf ? value : Math.round(value)) / m; }; /** * Return bytes from Size + Suffix like "10 MB" */ String.prototype.getBytes = function () { var units = ["KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"], suffix = this.toUpperCase().substr(-2); if (units.indexOf(suffix) == -1) { return this; } var pow_factor = units.indexOf(suffix) + 1; return parseFloat(this) * Math.pow(1000, pow_factor); }; /** * Return size formatted from size bytes */ String.prototype.formatBytes = function (round) { var bytes = parseInt(this), units = ["KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; if (!$.isNumeric(this)) { return false; } if (bytes < 1000) return bytes + " B"; if (typeof round == "undefined") var round = 2; for (var i = 0; i < units.length; i++) { var multiplier = Math.pow(1000, i + 1), threshold = multiplier * 1000; if (bytes < threshold) { var size = bytes / multiplier; return this.getRounded.call(size, round) + " " + units[i]; } } }; /** * Returns the image url.matches (multiple) */ String.prototype.match_image_urls = function () { return this.match( /\b(?:(http[s]?|ftp[s]):\/\/)?([^:\/\s]+)(:[0-9]+)?((?:\/\w+)*\/)([\w\-\.]+[^#?\s]+)([^#\s]*)?(#[\w\-]+)?\.(?:jpe?g|gif|png|bmp)\b/gim ); }; String.prototype.match_urls = function () { return this.match( /\b(?:(http[s]?|ftp[s]):\/\/)?([^:\/\s]+)(:[0-9]+)?((?:\/\w+)*\/)([\w\-\.]+[^#?\s]+)([^#\s]*)?(#[\w\-]+)?\b/gim ); }; // Add ECMA262-5 Array methods if not supported natively if (!("indexOf" in Array.prototype)) { Array.prototype.indexOf = function (find, i /*opt*/) { if (i === undefined) i = 0; if (i < 0) i += this.length; if (i < 0) i = 0; for (var n = this.length; i < n; i++) { if (i in this && this[i] === find) { return i; } } return -1; }; } /** * Removes all the array duplicates without loosing the array order. */ Array.prototype.array_unique = function () { var result = []; $.each(this, function (i, e) { if ($.inArray(e, result) == -1) result.push(e); }); return result; }; PF.fn.deparam = function (querystring) { if (typeof querystring == "undefined" || !querystring) return; // Get rid of the URL part var querystring = querystring.substring(querystring.indexOf("?") + 1); var obj = {}, pairs = querystring .replace(/^[\?|&]*/, "") .replace(/[&|\?]*$/, "") .split("&"); for (var i = 0; i < pairs.length; i++) { var split = pairs[i].split("="); var key = decodeURIComponent(split[0]); var value = split[1] ? decodeURIComponent(split[1]) : null; // Aready in the object? if (obj.hasOwnProperty(key) && !value) { continue; } obj[key] = value; } return obj; }; // http://stackoverflow.com/a/1634841/1145912 String.prototype.removeURLParameter = function (key) { var url = "", deparam = PF.fn.deparam(this); if (typeof deparam[key] !== "undefined") { delete deparam[key]; } return decodeURIComponent($.param(deparam)); }; String.prototype.changeURLParameterValue = function (key, value) { var base = this.substring(0, this.indexOf("?")); var res = ""; var deparam = PF.fn.deparam(this); if (typeof deparam[key] !== "undefined") { deparam[key] = value; } return base + "?" + decodeURIComponent($.param(deparam)); }; /** * Truncate the middle of the URL just like Firebug * From http://stackoverflow.com/questions/10903002/shorten-url-for-display-with-beginning-and-end-preserved-firebug-net-panel-st */ String.prototype.truncate_middle = function (l) { var l = typeof l != "undefined" ? l : 40, chunk_l = l / 2, url = this.replace(/https?:\/\//g, ""); if (url.length <= l) { return url; } function shortString(s, l, reverse) { var stop_chars = [" ", "/", "&"], acceptable_shortness = l * 0.8, // When to start looking for stop characters reverse = typeof reverse != "undefined" ? reverse : false, s = reverse ? s .split("") .reverse() .join("") : s, short_s = ""; for (var i = 0; i < l - 1; i++) { short_s += s[i]; if (i >= acceptable_shortness && stop_chars.indexOf(s[i]) >= 0) { break; } } if (reverse) { return short_s .split("") .reverse() .join(""); } return short_s; } return ( shortString(url, chunk_l, false) + "..." + shortString(url, chunk_l, true) ); }; /** * Compare 2 arrays/objects * http://stackoverflow.com/questions/1773069/using-jquery-to-compare-two-arrays */ jQuery.extend({ compare: function (a, b) { var obj_str = "[object Object]", arr_str = "[object Array]", a_type = Object.prototype.toString.apply(a), b_type = Object.prototype.toString.apply(b); if (a_type !== b_type) { return false; } else if (a_type === obj_str) { return $.compareObject(a, b); } else if (a_type === arr_str) { return $.compareArray(a, b); } return a === b; }, compareArray: function (arrayA, arrayB) { var a, b, i, a_type, b_type; if (arrayA === arrayB) { return true; } if (arrayA.length != arrayB.length) { return false; } a = jQuery.extend(true, [], arrayA); b = jQuery.extend(true, [], arrayB); a.sort(); b.sort(); for (i = 0, l = a.length; i < l; i += 1) { a_type = Object.prototype.toString.apply(a[i]); b_type = Object.prototype.toString.apply(b[i]); if (a_type !== b_type) { return false; } if ($.compare(a[i], b[i]) === false) { return false; } } return true; }, compareObject: function (objA, objB) { var i, a_type, b_type; // Compare if they are references to each other if (objA === objB) { return true; } if (Object.keys(objA).length !== Object.keys(objB).length) { return false; } for (i in objA) { if (objA.hasOwnProperty(i)) { if (typeof objB[i] === "undefined") { return false; } else { a_type = Object.prototype.toString.apply(objA[i]); b_type = Object.prototype.toString.apply(objB[i]); if (a_type !== b_type) { return false; } } } if ($.compare(objA[i], objB[i]) === false) { return false; } } return true; } }); /** * Tells if a selector exits in the dom */ jQuery.fn.exists = function () { return this.length > 0; }; /** * Replace .svg for .png */ jQuery.fn.replace_svg = function () { if (!this.attr("src")) return; $(this).each(function () { $(this).attr( "src", $(this) .attr("src") .replace(".svg", ".png") ); }); }; /** * Detect fluid layout * nota: deberia ir en PF */ jQuery.fn.is_fluid = function () { return true; }; /** * jQueryfy the form data * Bind the attributes and values of form data to be manipulated by DOM fn */ jQuery.fn.bindFormData = function () { $(":input", this).each(function () { var safeVal = PF.fn.htmlEncode($(this).val()); if ($(this).is("input")) { this.setAttribute("value", this.value); if (this.checked) { this.setAttribute("checked", "checked"); } else { this.removeAttribute("checked"); } } if ($(this).is("textarea")) { $(this).html(safeVal); } if ($(this).is("select")) { var index = this.selectedIndex, i = 0; $(this) .children("option") .each(function () { if (i++ != index) { this.removeAttribute("selected"); } else { this.setAttribute("selected", "selected"); } }); } }); return this; }; /** jQuery.formValues: get or set all of the name/value pairs from child input controls * @argument data {array} If included, will populate all child controls. * @returns element if data was provided, or array of values if not * http://stackoverflow.com/questions/1489486/jquery-plugin-to-serialize-a-form-and-also-restore-populate-the-form */ jQuery.fn.formValues = function (data) { var els = $(":input", this); if (typeof data != "object") { data = {}; $.each(els, function () { if ( this.name && !this.disabled && (this.checked || /select|textarea/i.test(this.nodeName) || /color|date|datetime|datetime-local|email|month|range|search|tel|time|url|week|text|number|hidden|password/i.test( this.type )) ) { if (this.name.match(/^.*\[\]$/) && this.checked) { if (typeof data[this.name] == "undefined") { data[this.name] = []; } data[this.name].push($(this).val()); } else { data[this.name] = $(this).val(); } } }); return data; } else { $.each(els, function () { if (this.name.match(/^.*\[\]$/) && typeof data[this.name] == "object") { $(this).prop("checked", data[this.name].indexOf($(this).val()) !== -1); } else { if (this.name && data[this.name]) { if (/checkbox|radio/i.test(this.type)) { $(this).prop("checked", data[this.name] == $(this).val()); } else { $(this).val(data[this.name]); } } else if (/checkbox|radio/i.test(this.type)) { $(this).removeProp("checked"); } } }); return $(this); } }; jQuery.fn.storeformData = function (dataname) { if ( typeof dataname == "undefined" && typeof $(this).attr("id") !== "undefined" ) { dataname = $(this).attr("id"); } if (typeof dataname !== "undefined") $(this).data(dataname, $(this).formValues()); return this; }; /** * Compare the $.data values against the current DOM values * It relies in using $.data to store the previous value * Data must be stored using $.formValues() * * @argument dataname string name for the data key */ jQuery.fn.is_sameformData = function (dataname) { var $this = $(this); if (typeof dataname == "undefined") dataname = $this.attr("id"); return jQuery.compare($this.formValues(), $this.data(dataname)); }; /** * Prevent non-numeric keydown * Allows only numeric keys to be entered on the target event */ jQuery.Event.prototype.keydown_numeric = function () { var e = this; if (e.shiftKey) { e.preventDefault(); return false; } var key = e.charCode || e.keyCode, target = e.target, value = $(target).val() == "" ? 0 : parseInt($(target).val()); if (key == 13) { // Allow enter key return true; } if ( key == 46 || key == 8 || key == 9 || key == 27 || // Allow: Ctrl+A (key == 65 && e.ctrlKey === true) || // Allow: home, end, left, right (key >= 35 && key <= 40) ) { // let it happen, don't do anything return true; } else { // Ensure that it is a number and stop the keypress if ((key < 48 || key > 57) && (key < 96 || key > 105)) { e.preventDefault(); } } }; /** * Detect canvas support */ PF.fn.is_canvas_supported = function () { var elem = document.createElement("canvas"); return !!(elem.getContext && elem.getContext("2d")); }; /** * Detect validity support */ PF.fn.is_validity_supported = function () { var i = document.createElement("input"); return typeof i.validity === "object"; }; PF.fn.getScrollBarWidth = function () { var inner = document.createElement("p"); inner.style.width = "100%"; inner.style.height = "200px"; var outer = document.createElement("div"); outer.style.position = "absolute"; outer.style.top = "0px"; outer.style.left = "0px"; outer.style.visibility = "hidden"; outer.style.width = "200px"; outer.style.height = "150px"; outer.style.overflow = "hidden"; outer.appendChild(inner); document.body.appendChild(outer); var w1 = inner.offsetWidth; outer.style.overflow = "scroll"; var w2 = inner.offsetWidth; if (w1 == w2) w2 = outer.clientWidth; document.body.removeChild(outer); return w1 - w2; }; PF.str.ScrollBarWidth = PF.fn.getScrollBarWidth(); /** * Updates the notifications button */ PF.fn.top_notifications_viewed = function () { var $top_bar_notifications = $("[data-action=top-bar-notifications]"), $notifications_lists = $( ".top-bar-notifications-list", $top_bar_notifications ), $notifications_count = $(".top-btn-number", $top_bar_notifications); if ($(".persistent", $top_bar_notifications).exists()) { $notifications_count .text($(".persistent", $top_bar_notifications).length) .addClass("on"); } else { $notifications_count.removeClass("on"); } }; /** * bind tipTip for the $target with options * @argument $target selector or jQuery obj * @argument options obj */ PF.fn.bindtipTip = function ($target, options) { if (typeof $target == "undefined") $target = $("body"); if ($target instanceof jQuery == false) $target = $($target); var bindtipTipoptions = { delay: 0, content: false, fadeIn: 0 }; if (typeof options !== "undefined") { if (typeof options.delay !== "undefined") bindtipTipoptions.delay = options.delay; if (typeof options.content !== "undefined") bindtipTipoptions.content = options.content; if (typeof options.content !== "undefined") bindtipTipoptions.fadeIn = options.fadeIn; } if ($target.attr("rel") !== "tooltip") $target = $("[rel=tooltip]", $target); $target.each(function () { if ( (typeof $(this).attr("href") !== "undefined" || typeof $(this).data("href") !== "undefined") && PF.fn.isDevice(["phone", "phablet", "tablet"]) ) { return true; } var position = typeof $(this).data("tiptip") == "undefined" ? "bottom" : $(this).data("tiptip"); if (PF.fn.isDevice(["phone", "phablet"])) { position = "top"; } $(this).tipTip({ delay: bindtipTipoptions.delay, defaultPosition: position, content: bindtipTipoptions.content, fadeIn: bindtipTipoptions.fadeIn, fadeOut: 0 }); }); }; /** * form modal changed * Detects if the form modal (fullscreen) has changed or not * Note: It relies in that you save a serialized data to the */ PF.fn.form_modal_has_changed = function () { if ($(PF.obj.modal.selectors.root).is(":hidden")) return; if (typeof $("html").data("modal-form-values") == typeof undefined) return; var data_stored = $("html").data("modal-form-values"); var data_modal = PF.fn.deparam( $(":input:visible", PF.obj.modal.selectors.root).serialize() ); var has_changed = false; var keys = $.extend({}, data_stored, data_modal); for (var k in keys) { if (data_stored[k] !== data_modal[k]) { has_changed = true; break; } } return has_changed; }; /** * PEAFOWL CONDITIONALS * ------------------------------------------------------------------------------------------------- */ PF.fn.is_listing = function () { return $(PF.obj.listing.selectors.content_listing).exists(); }; PF.fn.is_tabs = function () { return $(".content-tabs").exists(); }; /** * PEAFOWL EFFECTS * ------------------------------------------------------------------------------------------------- */ /** * Shake effect * Shakes the element using CSS animations. * @argument callback fn */ jQuery.fn.shake = function (callback) { this.each(function (init) { var jqNode = $(this), jqNode_position = jqNode.css("position"); if (!jqNode_position.match("relative|absolute|fixed")) jqNode.css({ position: "relative" }); var jqNode_left = parseInt(jqNode.css("left")); if (!jqNode_left.toString().isNumeric()) jqNode_left = 0; if (!jqNode.is(":animated")) { for (var x = 1; x <= 2; x++) { jqNode .animate( { left: jqNode_left - 10 }, 0 ) .animate( { left: jqNode_left }, 30 ) .animate( { left: jqNode_left + 10 }, 30 ) .animate( { left: jqNode_left }, 30 ); } if (jqNode_position !== "static") jqNode.css({ position: jqNode_position }); } }); if (typeof callback == "function") callback(); return this; }; /** * Highlight effect * Changes the background of the element to a highlight color and revert to original * @argument string (yellow|red|hex-color) */ jQuery.fn.highlight = function (color) { if (this.is(":animated") || !this.exists()) return this; if (typeof color == "undefined") color = "yellow"; var fadecolor = color; switch (color) { case "yellow": fadecolor = "#FFFBA2"; break; case "red": fadecolor = "#FF7F7F"; break; default: fadecolor = color; break; } var base_background_color = $(this).css("background-color"), base_background = $(this).css("background"); $(this) .css({ background: "", backgroundColor: fadecolor }) .animate({ backgroundColor: base_background_color }, 800, function () { $(this).css("background", ""); }); return this; }; /** * Peafowl slidedown effect * Bring the element using slideDown-type effect * @argument speed (fast|normal|slow|int) * @argument callback fn */ jQuery.fn.pf_slideDown = function (speed, callback) { var default_speed = "normal", this_length = $(this).length, css_prechanges, css_animation, animation_speed; if (typeof speed == "function") { callback = speed; speed = default_speed; } if (typeof speed == "undefined") { speed = default_speed; } $(this).each(function (index) { var this_css_top = parseInt($(this).css("top")), to_top = this_css_top > 0 ? this_css_top : 0; if (speed == 0) { (css_prechanges = { display: "block", opacity: 0 }), (css_animation = { opacity: 1 }), (animation_speed = jQuery.speed("fast").duration); } else { css_prechanges = { top: -$(this).outerHeight(true), opacity: 1, display: "block" }; css_animation = { top: to_top }; animation_speed = jQuery.speed(speed).duration; } $(this).data("originalTop", $(this).css("top")); $(this) .css(css_prechanges) .animate(css_animation, animation_speed, function () { if (index == this_length - 1) { if (typeof callback == "function") { callback(); } } }); }); return this; }; /** * Peafowl slideUp effect * Move the element using slideUp-type effect * @argument speed (fast|normal|slow|int) * @argument callback fn */ jQuery.fn.pf_slideUp = function (speed, callback) { var default_speed = "normal", this_length = $(this).length; if (typeof speed == "function") { callback = speed; speed = default_speed; } if (typeof speed == "undefined") { speed = default_speed; } $(this).each(function (index) { $(this).animate( { top: -$(this).outerHeight(true) }, jQuery.speed(speed).duration, function () { $(this).css({ display: "none", top: $(this).data("originalTop") }); if (index == this_length - 1) { if (typeof callback == "function") { callback(); } } } ); }); return this; }; /** * Peafowl visible on viewport */ jQuery.fn.is_in_viewport = function () { var rect = $(this)[0].getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) /*or $(window).height() */ && rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */ ); }; /** * Visible on current window stuff */ jQuery.fn.getWindowCutoff = function () { var rect = { top: $(this).offset().top, left: $(this).offset().left, width: $(this).outerWidth(), height: $(this).outerHeight() }; rect.right = rect.left + rect.width; rect.bottom = rect.top + rect.height; var detected = false; var cutoff = { top: rect.top > 0 ? 0 : rect.top, right: document.body.clientWidth - rect.right, bottom: document.body.clientHeight - rect.bottom, left: rect.left > 0 ? 0 : rect.left }; for (var key in cutoff) { if (cutoff[key] < 0) { detected = true; } else { cutoff[key] = 0; } } if (!detected) return null; return cutoff; }; /** * Scroll the window to the target. * @argument target selector * @argument callback fn */ PF.fn.scroll = function (target, callback) { if (typeof target == "function") { var callback = target, target = ""; } var pxtop = parseInt($("body").css("margin-top")); if (pxtop == 0 && $(".top-bar-placeholder").exists()) { pxtop = $(".top-bar-placeholder").height(); } if (!$(target).exists()) target = "html"; $("body,html").animate( { scrollTop: $(target).offset().top - pxtop }, "normal", function () { if (typeof callback == "function") callback(); } ); }; PF.fn.close_pops = function (e) { $(".pop-box:visible").each(function () { $(this) .closest(".pop-btn") .click(); }); }; /** * Bring up a nice growl-like alert */ PF.fn.growl = { selectors: { root: "#growl" }, str: { timeout: null, timeoutcall: false }, /** * Fires the growl * @argument options object */ call: function (options) { if (typeof options == "undefined") return; if (typeof options == "string") { options = { message: options }; } if (typeof options.message == "undefined") return; var growl_options, $growl, growl_class, growl_color; growl_options = { message: options.message, insertTo: "body", where: "before", color: "default", css: {}, classes: "", expires: 0, callback: function () { } }; for (key in growl_options) { if (typeof options[key] !== "undefined") { if (key.match("/^(callback)$/")) { if (typeof options[key] == "function") { growl_options[key] = options[key]; } } else { growl_options[key] = options[key]; } } } if (!$(growl_options.insertTo).exists()) { growl_options.insertTo = "body"; } if ($(PF.fn.growl.selectors.root).exists()) { if ($(PF.fn.growl.selectors.root).text() == growl_options.message) { $(PF.fn.growl.selectors.root).shake(); return; } $(PF.fn.growl.selectors.root).remove(); } $growl = $( '
' + growl_options.message + '
' ) .css(growl_options.css) .addClass(growl_options.classes); growl_class = growl_options.insertTo !== "body" ? "static" : ""; switch (growl_options.color) { case "dark": growl_color = "dark"; break; default: growl_color = ""; break; } $growl.addClass(growl_class + " " + growl_color); if (growl_options.where == "before") { $(growl_options.insertTo).prepend($growl.hide()); } else { $(growl_options.insertTo).append($growl.hide()); } if ($(".fullscreen").is(":visible")) { $growl.css({ "z-index": parseInt($(".fullscreen").css("z-index")) + 1 }); } if ($(PF.obj.modal.selectors.root).is(":visible")) { var $modal_box = $( PF.obj.modal.selectors.box, PF.obj.modal.selectors.root ); $growl.show(); $growl.css( "top", ($("#top-bar").outerHeight(true) - $growl.outerHeight(true)) / 2 ); PF.fn.growl.fixPosition(); $growl.hide(); } $growl.pf_slideDown(growl_class == "static" ? 0 : 200, function () { if (typeof growl_options.callback == "function") { growl_options.callback(); } }); $(document).on("click", ".growl", function (e) { if ( PF.fn.isDevice(["phone", "phablet"]) || $(e.target).is("[data-action=close]") ) { PF.fn.growl.close(true); } }); if (growl_options.expires > 0) { if (typeof this.str.timeout == "number") { clearTimeout(this.str.timeout); } this.str.timeout = setTimeout(function () { PF.fn.growl.str.timeoutcall = true; PF.fn.growl.close(); }, growl_options.expires); } console.log(growl_options.message); }, /** * Fires an expirable growl (will close after time) * @argument msg string * @argument time int (ms) */ expirable: function (msg, time) { if (typeof msg == "undefined") return; if (typeof time == "undefined") time = 5000; PF.fn.growl.call({ message: msg, expires: time }); }, /** * Closes the growl * @argument callback fn */ close: function (forced, callback) { var $growl = $(PF.fn.growl.selectors.root); if (forced) { this.str.timeout = null; this.str.timeoutcall = false; clearTimeout(this.str.timeout); } if ( !$growl.exists() || (typeof this.str.timeout == "number" && !this.str.timeoutcall) ) { return; } $growl.fadeOut("fast", function () { $(this).remove(); if (typeof callback == "function") { callback(); } }); }, fixPosition: function () { var $growl = $(PF.fn.growl.selectors.root); if (!$growl.exists() || !$(PF.obj.modal.selectors.root).exists()) { return; } if ( $growl.data("fixedPosition") == "scrollbar" && $(PF.obj.modal.selectors.root).hasScrollBar().vertical ) { return; } var offsetX = { modal: $(PF.obj.modal.selectors.box).offset().left, growl: $growl.offset().left }, growlCompensate = offsetX.modal - offsetX.growl, marginLeft = growlCompensate < 0 ? "-=" + Math.abs(growlCompensate) : "-" + parseInt($growl.css("width")) / 2; if (!PF.fn.isDevice(["phone", "phablet"])) { $growl.css("marginLeft", marginLeft + "px"); } $growl.data( "fixedPosition", $(PF.obj.modal.selectors.root).hasScrollBar().vertical ? "scrollbar" : "no-scrollbar" ); } }; /** * Bring up a nice fullscreen modal */ PF.obj.modal = { type: "", selectors: { root: "#fullscreen-modal", box: "#fullscreen-modal-box", body: "#fullscreen-modal-body", login: "[data-modal=login]", changes_confirm: "#fullscreen-changes-confirm", btn_container: ".btn-container", close_buttons: ".close-modal,.cancel-modal,[data-action=cancel],[data-action-close]", submit_button: "[data-action=submit]", growl_placeholder: "#fullscreen-growl-placeholder" }, ajax: { url: "", deferred: {} }, locked: false, form_data: {}, XHR: {}, prevented: false }; PF.obj.modal.$close_buttons = $( PF.obj.modal.selectors.close_buttons, PF.obj.modal.selectors.root ); PF.obj.modal.$submit_button = $( PF.obj.modal.selectors.submit_button, PF.obj.modal.selectors.root ); PF.fn.modal = { str: { transition: "all " + PF.obj.config.animation.fast + "ms ease" }, /** * Fires the modal * @argument options object */ call: function (options) { var modal_options, modal_base_template, modal_message; if (typeof options == "undefined") return; if ( typeof options.template !== "undefined" && typeof options.type == "undefined" ) options.type = "html"; if ( (typeof options.title == "undefined" || typeof options.message == "undefined") && (options.type !== "login" && options.type !== "html") ) return; PF.fn.growl.close(); modal_options = { forced: false, type: "confirm", title: options.title, message: options.message, html: false, template: options.template, buttons: true, button_submit: PF.fn._s("Submit"), txt_or: PF.fn._s("or"), button_cancel: PF.fn._s("cancel"), ajax: { url: null, data: null, deferred: {} }, confirm: function () { }, cancel: function () { PF.fn.modal.close(); }, load: function () { }, callback: function () { } }; for (key in modal_options) { if (typeof options[key] !== "undefined") { if (/^cancel|confirm|callback$/.test(key)) { if (typeof options[key] == "function") { modal_options[key] = options[key]; } } else { modal_options[key] = options[key]; } } } if ( typeof options.ajax !== "undefined" && !options.ajax.url && options.ajax.deferred ) { modal_options.ajax.url = PF.obj.config.json_api; } if (modal_options.type == "login") { modal_options.buttons = false; } if (modal_options.type == "confirm") { modal_options.button_submit = PF.fn._s("Confirm"); } var overlay_background = "soft-black"; if ($("html").hasClass("tone-dark")) { overlay_background = "black"; } var modal_base_template = [ '
%MODAL_BODY%
%MODAL_BUTTONS%
' ].join(""); var modal_buttons = modal_options.buttons ? [ '
', modal_options.txt_or, '', modal_options.button_cancel, "
" ].join("") : ""; if (modal_options.type == "login") { modal_options.template = typeof modal_options.template == "undefined" ? $(PF.obj.modal.selectors.login).html() : modal_options.template; } var modalBodyHTML; switch (modal_options.type) { case "html": case "login": modalBodyHTML = modal_options.template; break; case "confirm": default: modal_message = modal_options.message; if (!modal_options.html) { modal_message = "

" + modal_message + "

"; } modalBodyHTML = "

" + modal_options.title + "

" + modal_message; break; } if (typeof modalBodyHTML == "undefined") { console.log("PF Error: Modal content is empty"); return; } modal_base_template = modal_base_template .replace("%MODAL_BODY%", modalBodyHTML) .replace("%MODAL_BUTTONS%", modal_buttons) .replace(/template-tooltip/g, "tooltip"); $(PF.obj.modal.selectors.root).remove(); $("body").data("overflow-hidden", $("body").hasClass("overflow-hidden")); $("body") .prepend(modal_base_template) .addClass("overflow-hidden"); this.fixScrollbars(); $("[rel=tooltip]", PF.obj.modal.selectors.root).each(function () { PF.fn.bindtipTip(this, { content: $(this).data("title") }); }); if ( $( ":button, input[type=submit], input[type=reset]", PF.obj.modal.selectors.root ).length > 0 ) { var $form = $("form", PF.obj.modal.selectors.root); if ($form.exists()) { $form.append( $( $( PF.obj.modal.selectors.btn_container, PF.obj.modal.selectors.root ).html() ).wrapInner(PF.obj.modal.selectors.btn_container.replace(".", "")) ); $( PF.obj.modal.selectors.btn_container, PF.obj.modal.selectors.root ).each(function () { if ( !$(this) .closest("form") .exists() ) { $(this).remove(); } }); } else { $(PF.obj.modal.selectors.box, PF.obj.modal.selectors.root).wrapInner( "
" ); } } modal_options.callback(); $(PF.obj.modal.selectors.box).css({ transform: "scale(0.7)", opacity: 0, transition: PF.fn.modal.str.transition }); $(PF.obj.modal.selectors.root).css({ display: "block" }); setTimeout(function () { $(PF.obj.modal.selectors.root).css({ opacity: 1 }); $(PF.obj.modal.selectors.box).css({ transform: "scale(1)", opacity: 1 }); if (typeof PFrecaptchaCallback !== typeof undefined) { PFrecaptchaCallback(); } setTimeout(function () { // Stock default modal values $("html").data( "modal-form-values", PF.fn.deparam( $(":input:visible", PF.obj.modal.selectors.root).serialize() ) ); if (typeof modal_options.load == "function") { modal_options.load(); } }, PF.obj.config.animation.fast); }, 1); // Bind the modal events $(PF.obj.modal.selectors.root).click(function (e) { var $this = $(e.target), _this = this; if (PF.obj.modal.locked) { return; } // Changes confirm? if ( $this.closest(PF.obj.modal.selectors.changes_confirm).exists() && ($this.is(PF.obj.modal.selectors.close_buttons) || $this.is(PF.obj.modal.selectors.submit_button)) ) { $(PF.obj.modal.selectors.changes_confirm).remove(); if ($this.is(PF.obj.modal.selectors.close_buttons)) { $(PF.obj.modal.selectors.box, _this).fadeIn("fast", function () { $(this).css("transition", PF.fn.modal.str.transition); }); } else { PF.fn.modal.close(); } // Modal } else { if ( !$this.closest(".clickable").exists() || $this.is(PF.obj.modal.selectors.close_buttons) ) { PF.fn.growl.close(); modal_options.cancel(); } if ($this.is(PF.obj.modal.selectors.submit_button)) { if (modal_options.confirm() === false) { return; } var modal_submit_continue = true; if ( $("input, textarea, select", PF.obj.modal.selectors.root).not( ":input[type=button], :input[type=submit], :input[type=reset]" ).length > 0 && !PF.fn.form_modal_has_changed() && !modal_options.forced ) { modal_submit_continue = false; } if (modal_submit_continue) { if (modal_options.ajax.url) { var $btn_container = $( PF.obj.modal.selectors.btn_container, PF.obj.modal.selectors.root ); PF.obj.modal.locked = true; $btn_container .first() .clone() .height($btn_container.height()) .html("") .addClass("loading") .appendTo(PF.obj.modal.selectors.root + " form"); $btn_container.hide(); PF.obj.modal.$close_buttons.hide(); var modal_loading_msg; switch (PF.obj.modal.type) { case "edit": modal_loading_msg = PF.fn._s("Saving"); break; case "confirm": case "form": default: modal_loading_msg = PF.fn._s("Sending"); break; } PF.fn.loading.inline( $( PF.obj.modal.selectors.btn_container + ".loading", PF.obj.modal.selectors.root ), { size: "small", message: modal_loading_msg, valign: "center" } ); $(PF.obj.modal.selectors.root).disableForm(); if ( !$.isEmptyObject(PF.obj.modal.form_data) || (typeof options.ajax !== "undefined" && typeof options.ajax.data == "undefined") ) { modal_options.ajax.data = PF.obj.modal.form_data; } PF.obj.modal.XHR = $.ajax({ url: modal_options.ajax.url, type: "POST", data: modal_options.ajax.data //PF.obj.modal.form_data // $.param ? }).complete(function (XHR) { PF.obj.modal.locked = false; if (XHR.status == 200) { var success_fn = typeof modal_options.ajax.deferred !== "undefined" && typeof modal_options.ajax.deferred.success !== "undefined" ? modal_options.ajax.deferred.success : null; if (typeof success_fn == "function") { PF.fn.modal.close(function () { if (typeof success_fn == "function") { success_fn(XHR); } }); } else if (typeof success_fn == "object") { if (typeof success_fn.before == "function") { success_fn.before(XHR); } if (typeof success_fn.done == "function") { success_fn.done(XHR); } } } else { $(PF.obj.modal.selectors.root).enableForm(); $( PF.obj.modal.selectors.btn_container + ".loading", PF.obj.modal.selectors.root ).remove(); $btn_container.css("display", ""); if ( typeof modal_options.ajax.deferred !== "undefined" && typeof modal_options.ajax.deferred.error == "function" ) { modal_options.ajax.deferred.error(XHR); } else { var message = PF.fn._s( "An error occurred. Please try again later." ); /* if(XHR.responseJSON.error.message) { message = XHR.responseJSON.error.message; } */ PF.fn.growl.call(message); } } }); } else { // No ajax behaviour PF.fn.modal.close(modal_options.callback()); } } } } }); }, /** * Fires a confirm modal * @argument options object */ confirm: function (options) { options.type = "confirm"; if (typeof options.title == "undefined") { options.title = PF.fn._s("Confirm action"); } PF.fn.modal.call(options); }, /** * Fires a simple info modal */ simple: function (options) { if (typeof options == "string") options = { message: options }; if (typeof options.buttons == "undefined") options.buttons = false; if (typeof options.title == "undefined") options.title = PF.fn._s("information"); PF.fn.modal.call(options); }, fixScrollbars: function () { if (!$(PF.obj.modal.selectors.root).exists()) { return; } var $targets = { padding: $(".top-bar, .fixed, .position-fixed"), margin: $("html") }; var properties = {}; if ( PF.str.ScrollBarWidth > 0 && $("html").hasScrollBar().vertical && !$("body").data("overflow-hidden") ) { properties.padding = PF.str.ScrollBarWidth + "px"; properties.margin = PF.str.ScrollBarWidth + "px"; } else { properties.padding = ""; properties.margin = ""; } $targets.padding.css({ paddingRight: properties.padding }); $targets.margin.css({ marginRight: properties.margin }); }, /** * Closes the modal * @argument callback fn */ close: function (callback) { if (!$(PF.obj.modal.selectors.root).exists()) { return; } PF.fn.growl.close(true); $("[rel=tooltip]", PF.obj.modal.selectors.root).tipTip("hide"); $(PF.obj.modal.selectors.box).css({ transform: "scale(0.5)", opacity: 0 }); $(PF.obj.modal.selectors.root).css({ opacity: 0 }); setTimeout(function () { if (PF.str.ScrollBarWidth > 0 && $("html").hasScrollBar().vertical) { $(".top-bar, .fixed, .position-fixed").css({ paddingRight: "" }); } $("html").css({ marginRight: "" }); if (!$("body").data("overflow-hidden")) { $("body").removeClass("overflow-hidden"); } $("body").removeData("overflow-hidden"); $(PF.obj.modal.selectors.root).remove(); if (typeof callback == "function") callback(); }, PF.obj.config.animation.normal); } }; /** * Peafowlesque popups */ PF.fn.popup = function (options) { var settings = { height: options.height || 500, width: options.width || 650, scrollTo: 0, resizable: 0, scrollbars: 0, location: 0 }; settings.top = screen.height / 2 - settings.height / 2; settings.left = screen.width / 2 - settings.width / 2; var settings_ = ""; for (var key in settings) { settings_ += key + "=" + settings[key] + ","; } settings_ = settings_.slice(0, -1); // remove the last comma window.open(options.href, "Popup", settings_); return; }; /** * PEAFOWL FLUID WIDTH FIXER * ------------------------------------------------------------------------------------------------- */ PF.fn.list_fluid_width = function () { if (!$("body").is_fluid()) return; var $content_listing = $(PF.obj.listing.selectors.content_listing_visible), $pad_content_listing = $( PF.obj.listing.selectors.pad_content, $content_listing ), $list_item = $(PF.obj.listing.selectors.list_item, $content_listing), list_item_width = $list_item.outerWidth(true), list_item_gutter = $list_item.outerWidth(true) - $list_item.width(); PF.obj.listing.content_listing_ratio = parseInt( ($content_listing.width() + list_item_gutter) / list_item_width ); if ($list_item.length < PF.obj.listing.content_listing_ratio) { $pad_content_listing.css("width", "100%"); return; } if (PF.fn.isDevice(["tablet", "laptop", "desktop"])) { // $pad_content_listing.width((PF.obj.listing.content_listing_ratio * list_item_width) - list_item_gutter); } if (PF.obj.follow_scroll.$node.hasClass("position-fixed")) { PF.obj.follow_scroll.$node.width( $(".content-width") .first() .width() ); } }; /** * PEAFOWL TABS * ------------------------------------------------------------------------------------------------- */ PF.obj.tabs = { hashdata: {} }; PF.fn.show_tab = function (tab) { if (typeof tab == "undefined") return; var $this = $("a[data-tab=" + tab + "]", ".content-tabs"); $("li", $this.closest("ul")).removeClass("current"); $this.closest("li").addClass("current"); var $tab_content_group = $("#tabbed-content-group"); $target = $("#" + $this.data("tab")); $(".tabbed-content", $tab_content_group) .removeClass("visible") .hide(); $($target, $tab_content_group) .addClass("visible") .show(); // Show/hide the listing sorting $("[data-content=list-selection]") .removeClass("visible") .addClass("hidden"); $("[data-content=list-selection][data-tab=" + $this.data("tab") + "]") .removeClass("hidden") .addClass("visible"); if ($tab_content_group.exists()) { var $list_item_target = $( PF.obj.listing.selectors.list_item + ":not(.jsly)", $target ), target_fade = !$target.hasClass("jsly"); if ( $target.data("load") == "ajax" && $target.data("empty") !== "true" && !$(PF.obj.listing.selectors.list_item, $target).exists() ) { PF.fn.listing.queryString.stock_load(); $target.html(PF.obj.listing.template.fill); PF.fn.loading.inline( $(PF.obj.listing.selectors.content_listing_loading, $target) ); PF.fn.listing.queryString.stock_new(); PF.fn.listing.ajax(); } else { PF.fn.listing.queryString.stock_current(); PF.fn.listing.columnizer(false, 0, false); $list_item_target[target_fade ? "fadeIn" : "show"](); } } PF.fn.listing.columnizerQueue(); if ( $(PF.obj.listing.selectors.content_listing_visible).data("queued") == true ) { PF.fn.listing.columnizer(true, 0); } }; /** * PEAFOWL LISTINGS * ------------------------------------------------------------------------------------------------- */ PF.obj.listing = { columns: "", columns_number: 1, current_column: "", current_column: "", XHR: {}, query_string: PF.fn.get_url_vars(), calling: false, content_listing_ratio: 1, selectors: { sort: ".sort-listing .current [data-sort]", content_listing: ".content-listing", content_listing_visible: ".content-listing:visible", content_listing_loading: ".content-listing-loading", content_listing_load_more: ".content-listing-more", content_listing_pagination: ".content-listing-pagination", empty_icon: ".icon icon-drawer", pad_content: ".pad-content-listing", list_item: ".list-item" }, template: { fill: $("[data-template=content-listing]").html(), empty: $("[data-template=content-listing-empty]").html(), loading: $("[data-template=content-listing-loading]").html() } }; PF.fn.listing = {}; PF.fn.listing.show = function (response, callback) { $content_listing = $("#content-listing-tabs").exists() ? $( PF.obj.listing.selectors.content_listing_visible, "#content-listing-tabs" ) : $(PF.obj.listing.selectors.content_listing); PF.fn.loading.inline(PF.obj.listing.selectors.content_listing_loading); $(PF.obj.listing.selectors.list_item + ":not(.jsly)", $content_listing).each( function () { $(this).imagesLoaded(function (i) { var items = PF.obj.listing.selectors.list_item, $subjects = $( items + ":visible", PF.obj.listing.selectors.content_listing_visible ), $targets = $(i.elements); if ( (typeof response !== "undefined" && $(response.html).length < PF.obj.config.listing.items_per_page) || $(PF.obj.listing.selectors.list_item, $content_listing).length < PF.obj.config.listing.items_per_page ) { PF.fn.listing.removeLoader($content_listing); } if ( $( PF.obj.listing.selectors.content_listing_pagination, $content_listing ).is("[data-type=classic]") || !$("[data-action=load-more]", $content_listing).exists() ) { $( PF.obj.listing.selectors.content_listing_loading, $content_listing ).remove(); } if ($subjects.length == 0) { $targets.show(); PF.fn.listing.columnizer(false, 0); PF.obj.listing.recolumnize = true; } //var animation_time = $subjects.length == 0 ? 0 : null; var animation_time = 0; PF.fn.listing.columnizer( PF.obj.listing.recolumnize, animation_time, $subjects.length == 0 ); $targets.hide(); PF.obj.listing.recolumnize = false; if (PF.fn.isDevice(["laptop", "desktop"])) { $targets.each(function () { // too much CPU for this $(this) .show() .find(".image-container") .hide(); var callTime = $.now(); var $this = $(this); var $target = $(".image-container", $this); $(".image-container", this).imagesLoaded(function () { var loadTime = $.now() - callTime; if ($subjects.length == 0) { if (loadTime > PF.obj.config.animation.normal) { $target.fadeIn(PF.obj.config.animation.normal); } else { $target.show(); } } else { $target.fadeIn(PF.obj.config.animation.normal); } }); }); } else { $targets.show(); } PF.obj.listing.calling = false; var visible_loading = $( PF.obj.listing.selectors.content_listing_loading, $content_listing ).exists() && $( PF.obj.listing.selectors.content_listing_loading, $content_listing ).is_in_viewport(); if (typeof PF.obj.listing.show_load_more == typeof undefined) { PF.obj.listing.show_load_more = visible_loading; } $(PF.obj.listing.selectors.content_listing_loading, $content_listing)[ (visible_loading ? "add" : "remove") + "Class" ]("visibility-hidden"); $(PF.obj.listing.selectors.content_listing_load_more, $content_listing)[ PF.obj.listing.show_load_more ? "show" : "hide" ](); var State = History.getState(); if (State.data && typeof State.data.scrollTop !== "undefined") { if ($(window).scrollTop() !== State.data.scrollTop) { //$(window).scrollTop(State.data.scrollTop); } } if (typeof callback == "function") { callback(); } }); } ); }; PF.fn.listing.removeLoader = function (obj) { var remove = [ PF.obj.listing.selectors.content_listing_load_more, PF.obj.listing.selectors.content_listing_loading ]; if ( $(PF.obj.listing.selectors.content_listing_pagination, $content_listing).is( "[data-type=endless]" ) ) { remove.push(PF.obj.listing.selectors.content_listing_pagination); } $.each(remove, function (i, v) { $(v, obj).remove(); }); }; PF.fn.listing.queryString = { // Stock the querystring values from initial load stock_load: function () { var $content_listing = $(PF.obj.listing.selectors.content_listing_visible), params = PF.fn.deparam($content_listing.data("params")); PF.obj.listing.params_hidden = typeof $content_listing.data("params-hidden") !== "undefined" ? PF.fn.deparam($content_listing.data("params-hidden")) : null; if (typeof PF.obj.listing.query_string.action == "undefined") { PF.obj.listing.query_string.action = $content_listing.data("action") || "list"; } if (typeof PF.obj.listing.query_string.list == "undefined") { PF.obj.listing.query_string.list = $content_listing.data("list"); } if (typeof PF.obj.listing.query_string.sort == "undefined") { if (typeof params !== "undefined" && typeof params.sort !== "undefined") { PF.obj.listing.query_string.sort = params.sort; } else { PF.obj.listing.query_string.sort = $( ":visible" + PF.obj.listing.selectors.sort ).data("sort"); } } if (typeof PF.obj.listing.query_string.page == "undefined") { PF.obj.listing.query_string.page = 1; } $content_listing.data("page", PF.obj.listing.query_string.page); // Stock the real ajaxed hrefs for ajax loads $(PF.obj.listing.selectors.content_listing + "[data-load=ajax]").each( function () { var $sortable_switch = $( "[data-tab=" + $(this).attr("id") + "]" + PF.obj.listing.selectors.sort ); var dataParams = PF.fn.deparam($(this).data("params")), dataParamsHidden = PF.fn.deparam($(this).data("params-hidden")), params = { q: dataParams && dataParams.q ? dataParams.q : null, list: $(this).data("list"), sort: $sortable_switch.exists() ? $sortable_switch.data("sort") : dataParams && dataParams.sort ? dataParams.sort : null, page: dataParams && dataParams.page ? dataParams.page : 1 }; if (dataParamsHidden && dataParamsHidden.list) { delete params.list; } for (var k in params) { if (!params[k]) delete params[k]; } } ); // The additional params setted in data-params="" for (var k in params) { if (/action|list|sort|page/.test(k) == false) { PF.obj.listing.query_string[k] = params[k]; } } if (typeof PF.obj.listing.params_hidden !== typeof undefined) { // The additional params setted in data-hidden-params="" for (var k in PF.obj.listing.params_hidden) { if (/action|list|sort|page/.test(k) == false) { PF.obj.listing.query_string[k] = PF.obj.listing.params_hidden[k]; } } PF.obj.listing.query_string["params_hidden"] = PF.obj.listing.params_hidden; PF.obj.listing.params_hidden["params_hidden"] = null; // Add this key for legacy, params_hidden v3.9.0 intro* } }, // Stock new querystring values for initial ajax call stock_new: function () { var $content_listing = $(PF.obj.listing.selectors.content_listing_visible), params = PF.fn.deparam($content_listing.data("params")); if ($content_listing.data("offset")) { PF.obj.listing.query_string.offset = $content_listing.data("offset"); } else { delete PF.obj.listing.query_string.offset; } PF.obj.listing.query_string.action = $content_listing.data("action") || "list"; PF.obj.listing.query_string.list = $content_listing.data("list"); if (typeof params !== "undefined" && typeof params.sort !== "undefined") { PF.obj.listing.query_string.sort = params.sort; } else { PF.obj.listing.query_string.sort = $( ":visible" + PF.obj.listing.selectors.sort ).data("sort"); } PF.obj.listing.query_string.page = 1; }, // Stock querystring values for static tab change stock_current: function () { this.stock_new(); PF.obj.listing.query_string.page = $( PF.obj.listing.selectors.content_listing_visible ).data("page"); } }; // Initial load -> Stock the current querystring PF.fn.listing.queryString.stock_load(); PF.fn.listing.ajax = function () { if (PF.obj.listing.calling == true) { return; } PF.obj.listing.calling = true; var $content_listing = $(PF.obj.listing.selectors.content_listing_visible); var $pad_content_listing = $( PF.obj.listing.selectors.pad_content, $content_listing ); var $content_listing_load_more = $( PF.obj.listing.selectors.content_listing_load_more, $content_listing ); $content_listing_load_more.hide(); $(PF.obj.listing.selectors.content_listing_loading, $content_listing) .removeClass("visibility-hidden") .show(); PF.obj.listing.XHR = $.ajax({ type: "POST", data: $.param( $.extend({}, PF.obj.listing.query_string, $.ajaxSettings.data) ) }).complete(function (XHR) { var response = XHR.responseJSON; var removePagination = function () { $( PF.obj.listing.selectors.content_listing_loading + "," + PF.obj.listing.selectors.content_listing_pagination + ":not([data-visibility=visible])", $content_listing ).remove(); }, setEmptyTemplate = function () { $content_listing .data("empty", "true") .html(PF.obj.listing.template.empty); $( "[data-content=list-selection][data-tab=" + $content_listing.attr("id") + "]" ).addClass("disabled"); }; if (XHR.readyState == 4 && typeof response !== "undefined") { $( "[data-content=list-selection][data-tab=" + $content_listing.attr("id") + "]" ).removeClass("disabled"); // Bad Request Bad Request what you gonna do when they come for ya? if (XHR.status !== 200) { // This is here to inherit the emptys var response_output = typeof response.error !== "undefined" && typeof response.error.message !== "undefined" ? response.error.message : "Bad request"; PF.fn.growl.call("Error: " + response_output); $content_listing.data("load", ""); } // Empty HTML if ( (typeof response.html == "undefined" || response.html == "") && $(PF.obj.listing.selectors.list_item, $content_listing).length == 0 ) { setEmptyTemplate(); } // End of the line if (typeof response.html == "undefined" || response.html == "") { removePagination(); PF.obj.listing.calling = false; if (typeof PF.fn.listing_end == "function") { PF.fn.listing_end(); } return; } // Listing stuff $content_listing.data({ load: "", page: PF.obj.listing.query_string.page }); var url_object = $.extend({}, PF.obj.listing.query_string); for (var k in PF.obj.listing.params_hidden) { if (typeof url_object[k] !== "undefined") { delete url_object[k]; } } delete url_object["action"]; for (var k in url_object) { if (!url_object[k]) delete url_object[k]; } // get the fancy URL with scrollTop attached if (document.URL.indexOf("?" + $.param(url_object)) == -1) { var url = window.location.href; url = url.split("?")[0].replace(/\/$/, "") + "/?" + $.param(url_object); if (window.location.hash) { url = url.replace(window.location.hash, ""); } History.pushState( { pushed: "pagination", scrollTop: $(window).scrollTop() }, document.title, url ); } $("a[data-tab=" + $content_listing.attr("id") + "]").attr( "href", document.URL ); $pad_content_listing.append(response.html); $("[data-action=load-more]", $content_listing_load_more).attr( "data-seek", response.seekEnd ); PF.fn.listing.show(response, function () { $( PF.obj.listing.selectors.content_listing_loading, $content_listing ).addClass("visibility-hidden"); }); } else { // Network error, abort or something similar PF.obj.listing.calling = false; $content_listing.data("load", ""); removePagination(); if ($(PF.obj.listing.selectors.list_item, $content_listing).length == 0) { setEmptyTemplate(); } if (XHR.readyState !== 0) { PF.fn.growl.call( PF.fn._s("An error occurred. Please try again later.") ); } } if (typeof PF.fn.listing.ajax.callback == "function") { PF.fn.listing.ajax.callback(XHR); } }); }; PF.fn.listing.columnizerQueue = function () { $(PF.obj.listing.selectors.content_listing + ":hidden").data("queued", true); }; PF.fn.listing.refresh = function (animation_time) { PF.fn.listing.columnizer(true, animation_time, false); $(PF.obj.listing.selectors.list_item).show(); }; // Peafowl's masonry approach... Just because godlike. var width = $(window).width(); PF.fn.listing.columnizer = function (forced, animation_time, hard_forced) { var device_to_columns = { // default phone: 1, phablet: 3, tablet: 4, laptop: 5, desktop: 6, largescreen: 7 }; if (typeof forced !== "boolean") var forced = false; if (typeof PF.obj.listing.mode == "undefined") forced = true; if (typeof hard_forced !== "boolean") { var hard_forced = false, default_hard_forced = true; } else { var default_hard_forced = false; } if (!hard_forced && default_hard_forced) { if (width !== $(window).width() || forced) { hard_forced = true; } } if (typeof animation_time == typeof undefined) var animation_time = PF.obj.config.animation.normal; //animation_time = 0; var $container = $("#content-listing-tabs").exists() ? $( PF.obj.listing.selectors.content_listing_visible, "#content-listing-tabs" ) : $(PF.obj.listing.selectors.content_listing), $pad_content_listing = $(PF.obj.listing.selectors.pad_content, $container), list_mode = "responsive", $list_item = $( forced || hard_forced ? PF.obj.listing.selectors.list_item : PF.obj.listing.selectors.list_item + ":not(.jsly)", $container ); $container.addClass("jsly"); // Get the device columns from global config if (typeof PF.obj.config.listing.device_to_columns !== "undefined") { device_to_columns = $.extend( {}, device_to_columns, PF.obj.config.listing.device_to_columns ); } // Get the device columns from the dom if ($container.data("device-columns")) { device_to_columns = $.extend( {}, device_to_columns, $container.data("device-columns") ); } PF.obj.listing.mode = list_mode; PF.obj.listing.device = PF.fn.getDeviceName(); if (!$list_item.exists()) return; if ( typeof $container.data("columns") !== "undefined" && !forced && !hard_forced ) { PF.obj.listing.columns = $container.data("columns"); PF.obj.listing.columns_number = $container.data("columns").length - 1; PF.obj.listing.current_column = $container.data("current_column"); } else { var $list_item_1st = $list_item.first(); $list_item_1st.css("width", ""); PF.obj.listing.columns = new Array(); PF.obj.listing.columns_number = device_to_columns[PF.fn.getDeviceName()]; for (i = 0; i < PF.obj.listing.columns_number; i++) { PF.obj.listing.columns[i + 1] = 0; } PF.obj.listing.current_column = 1; } var special_margin = PF.obj.listing.columns_number == 1 ? "-10px" : ""; $("#tabbed-content-group").css({ marginLeft: special_margin, marginRight: special_margin }); $container .removeClass("small-cols") .addClass(PF.obj.listing.columns_number > 6 ? "small-cols" : ""); $pad_content_listing.css("width", "100%"); var delay = 0; $list_item.each(function (index) { $(this).addClass("jsly"); var $list_item_img = $(".list-item-image", this), $list_item_src = $(".list-item-image img", this), $list_item_thumbs = $(".list-item-thumbs", this), isJslyLoaded = $list_item_src.hasClass("jsly-loaded"); $list_item_src.show(); if (hard_forced) { $(this).css({ top: "", left: "", height: "", position: "" }); $list_item_img.css({ maxHeight: "", height: "" }); $list_item_src .removeClass("jsly") .css({ width: "", height: "" }) .parent() .css({ marginLeft: "", marginTop: "" }); $("li", $list_item_thumbs).css({ width: "", height: "" }); } var width_responsive = PF.obj.listing.columns_number == 1 ? "100%" : parseInt( (1 / PF.obj.listing.columns_number) * ($container.width() - 10 * (PF.obj.listing.columns_number - 1)) + "px" ); $(this).css("width", width_responsive); if (PF.obj.listing.current_column > PF.obj.listing.columns_number) { PF.obj.listing.current_column = 1; } $(this).attr("data-col", PF.obj.listing.current_column); if (!$list_item_src.exists()) { var empty = true; $list_item_src = $(".image-container .empty", this); } var already_shown = $(this).is(":visible"); $list_item.show(); var isFixed = $list_item_img.hasClass("fixed-size"); var image = { w: parseInt($list_item_src.attr("width")), h: parseInt($list_item_src.attr("height")) }; image.ratio = image.w / image.h; //$list_item_src.removeAttr("width height"); // para fixed if (hard_forced && PF.obj.listing.columns_number > 1) { $list_item_src.css({ width: "auto", height: "auto" }); $(".image-container:not(.list-item-avatar-cover)", this).css({ width: "", height: "auto" }); } else { if (image.w > $container.width()) { $(".image-container:not(.list-item-avatar-cover)", this).css( image.ratio < 1 ? { maxWidth: "100%", height: "auto" } : { height: "100%", width: "auto" } ); $list_item_src.css( image.ratio < 1 ? { maxWidth: "100%", height: "auto" } : { height: "100%", width: "auto" } ); } } // Meet the minHeight? if ( empty || ($list_item_img.css("min-height") && !$list_item_src.hasClass("jsly")) ) { var list_item_img_min_height = parseInt($list_item_img.css("height")), col = { w: $(this).width(), h: isFixed ? $(this).width() : null }, magicWidth = Math.min(image.w, image.w < col.w ? image.w : col.w); if (isFixed) { $list_item_img.css({ height: col.w }); // Sets the item container height if (image.ratio <= 3 && (image.ratio > 1 || image.ratio == 1)) { // Landscape or square image.h = Math.min(image.h, image.w < col.w ? image.w : col.w); image.w = image.h * image.ratio; } else { // Portrait image.w = magicWidth; image.h = image.w / image.ratio; } var list_item_img_min_h = parseInt($list_item_img.css("min-height")); $list_item_img.css("min-height", 0); } else { // Fluid height image.w = magicWidth; if (image.ratio >= 3 || image.ratio < 1 || image.ratio == 1) { // Portrait or square image.h = image.w / image.ratio; } else { // Landscape image.h = Math.min(image.h, image.w); image.w = image.h * image.ratio; } if (empty) { image.h = col.w; } $list_item_img.css({ height: image.h }); // Fill some gaps } $list_item_src.css({ width: image.w, height: image.h }); if ($list_item_src.width() == 0) { $list_item_src.css({ width: magicWidth, height: magicWidth / image.ratio }); } if ($(".image-container", this).is(".list-item-avatar-cover")) { $list_item_src.css( isFixed ? { width: "auto", height: "100%" } : { width: "100%", height: "auto" } ); } if ( $list_item_src.height() !== 0 && ($list_item_img.height() > $list_item_src.height() || isFixed) ) { $list_item_src.parent().css({ marginTop: ($list_item_img.outerHeight() - $list_item_src.height()) / 2 }); } if ($list_item_img.width() < $list_item_src.width()) { $list_item_src.parent().css({ marginLeft: -(($list_item_src.outerWidth() - $list_item_img.width()) / 2) + "px" }); } var list_item_src_pitfall_x = Math.max( $list_item_src.position().left * 2, 0 ), list_item_src_pitfall_y = Math.max( $list_item_src.position().top * 2, 0 ); // Do we need upscale? It is safe to upscale? if ( PF.obj.listing.columns_number > 6 && (list_item_src_pitfall_x > 0 || list_item_src_pitfall_y > 0) ) { var pitfall_ratio_x = list_item_src_pitfall_x / $list_item_img.width(), pitfall_ratio_y = list_item_src_pitfall_y / $list_item_img.height(), pitfall = {}; if (pitfall_ratio_x <= 0.25 && pitfall_ratio_y <= 0.25) { if (pitfall_ratio_x > pitfall_ratio_y) { pitfall.width = list_item_src_pitfall_x + $list_item_img.width(); pitfall.height = pitfall.width / image.ratio; } else { pitfall.height = list_item_src_pitfall_y + $list_item_src.height(); pitfall.width = pitfall.height * image.ratio; } $list_item_src.css(pitfall); $list_item_src.parent().css({ marginLeft: -( ($list_item_src.width() - $list_item_img.width()) / 2 ), marginTop: 0 }); } } if ($list_item_thumbs.exists()) { $("li", $list_item_thumbs) .css({ width: 100 / $("li", $list_item_thumbs).length + "%" }) .css({ height: $("li", $list_item_thumbs).width() }); } if (!already_shown) { $list_item.hide(); } } //$pad_content_listing.css("visibility", "visible"); if (!$list_item_src.hasClass("jsly") && $(this).is(":hidden")) { $(this).css("top", "100%"); } PF.obj.listing.columns[PF.obj.listing.current_column] += $( this ).outerHeight(true); if (PF.obj.listing.columns_number == 1) { $(this).removeClass("position-absolute"); } else { if ($(this).is(":animated")) { animation_time = 0; } $(this).addClass("position-absolute"); var new_left = $(this).outerWidth(true) * (PF.obj.listing.current_column - 1); var must_change_left = parseInt($(this).css("left")) != new_left; if (must_change_left) { animate_grid = true; $(this).animate( { left: new_left }, animation_time ); } var new_top = PF.obj.listing.columns[PF.obj.listing.current_column] - $(this).outerHeight(true); if (parseInt($(this).css("top")) != new_top) { animate_grid = true; $(this).animate( { top: new_top }, animation_time ); if (must_change_left) { delay = 1; } } } if (already_shown) { $list_item.show(); } if (!isJslyLoaded) { $list_item_src .addClass("jsly") .hide() .imagesLoaded(function (i) { $(i.elements) .show() .addClass("jsly-loaded"); }); } // Fill the shortest column (fluid view only) if (!isFixed) { var minCol, minH, currentH; for (var i = 1; i <= PF.obj.listing.columns_number; i++) { currentH = PF.obj.listing.columns[i]; if (typeof minH == "undefined") { minH = currentH; minCol = i; } if (PF.obj.listing.columns[i] == 0) { minCol = i; break; } if (currentH < minH) { minH = PF.obj.listing.columns[i]; minCol = i; } } PF.obj.listing.current_column = minCol; } else { PF.obj.listing.current_column++; } }); $container.data({ columns: PF.obj.listing.columns, current_column: PF.obj.listing.current_column }); var content_listing_height = 0; $.each(PF.obj.listing.columns, function (i, v) { if (v > content_listing_height) { content_listing_height = v; } }); if (content_listing_height > 10) { content_listing_height -= 10; } PF.obj.listing.width = $container.width(); if (typeof PF.obj.listing.height !== typeof undefined) { var old_listing_height = PF.obj.listing.height; } PF.obj.listing.height = content_listing_height; var do_listing_h_resize = typeof old_listing_height !== typeof undefined && old_listing_height !== PF.obj.listing.height; if (!do_listing_h_resize) { $pad_content_listing.height(content_listing_height); PF.fn.list_fluid_width(); } // Magic! if (do_listing_h_resize) { $pad_content_listing.height(old_listing_height); setTimeout(function () { $pad_content_listing.animate( { height: content_listing_height }, animation_time, function () { PF.fn.list_fluid_width(); } ); }, animation_time * delay); } $container.data("list-mode", PF.obj.listing.mode); $(PF.obj.listing.selectors.content_listing_visible).data("queued", false); }; /** * PEAFOWL LOADERS * ------------------------------------------------------------------------------------------------- */ PF.fn.loading = { spin: { small: { lines: 11, length: 0, width: 3, radius: 7, speed: 1, trail: 45, blocksize: 20 }, // 20x20 normal: { lines: 11, length: 0, width: 5, radius: 10, speed: 1, trail: 45, blocksize: 30 }, // 30x30 big: { lines: 11, length: 0, width: 7, radius: 13, speed: 1, trail: 45, blocksize: 40 }, // 40x40 huge: { lines: 11, length: 0, width: 9, radius: 16, speed: 1, trail: 45, blocksize: 50 } // 50x50 }, inline: function ($target, options) { if (typeof $target == "undefined") return; if ($target instanceof jQuery == false) { var $target = $($target); } var defaultoptions = { size: "normal", color: $("body").css("color"), center: false, position: "absolute", shadow: false, valign: "top" }; if (typeof options == "undefined") { options = defaultoptions; } else { for (var k in defaultoptions) { if (typeof options[k] == "undefined") { options[k] = defaultoptions[k]; } } } var size = PF.fn.loading.spin[options.size]; PF.fn.loading.spin[options.size].color = options.color; PF.fn.loading.spin[options.size].shadow = options.shadow; $target .html( '' + (typeof options.message !== "undefined" ? '' + options.message + "" : "") ) .css({ "line-height": PF.fn.loading.spin[options.size].blocksize + "px" }); $(".loading-indicator", $target) .css({ width: PF.fn.loading.spin[options.size].blocksize, height: PF.fn.loading.spin[options.size].blocksize }) .spin(PF.fn.loading.spin[options.size]); if (options.center) { $(".loading-indicator", $target.css("textAlign", "center")).css({ position: options.position, top: "50%", left: "50%", marginTop: -(PF.fn.loading.spin[options.size].blocksize / 2), marginLeft: -(PF.fn.loading.spin[options.size].blocksize / 2) }); } if (options.valign == "center") { $(".loading-indicator,.loading-text", $target).css( "marginTop", ($target.height() - PF.fn.loading.spin[options.size].blocksize) / 2 + "px" ); } $(".spinner", $target).css({ top: PF.fn.loading.spin[options.size].blocksize / 2 + "px", left: PF.fn.loading.spin[options.size].blocksize / 2 + "px" }); }, fullscreen: function () { $("body").append( '
' + PF.fn._s("loading") + "
" ); $(".fullscreen-loader", "#pf-fullscreen-loader").spin( PF.fn.loading.spin.huge ); $("#pf-fullscreen-loader").css("opacity", 1); }, destroy: function ($target) { var $loader_fs = $("#pf-fullscreen-loader"), $loader_os = $("#pf-onscreen-loader"); if ($target == "fullscreen") $target = $loader_fs; if ($target == "onscreen") $target = $loader_os; if (typeof $target !== "undefined") { $target.remove(); } else { $loader_fs.remove(); $loader_os.remove(); } } }; /** * PEAFOWL FORM HELPERS * ------------------------------------------------------------------------------------------------- */ jQuery.fn.disableForm = function () { $(this).data("disabled", true); $(":input", this).each(function () { $(this).attr("disabled", true); }); return this; }; jQuery.fn.enableForm = function () { $(this).data("disabled", false); $(":input", this).removeAttr("disabled"); return this; }; /** * PEAFOWL FOLLOW SCROLL * ------------------------------------------------------------------------------------------------- */ PF.obj.follow_scroll = { Y: 0, y: 0, $node: $(".follow-scroll"), node_h: 0, base_h: $(".follow-scroll").outerHeight(), set: function (reset) { if (reset) { PF.obj.follow_scroll.base_h = $(".follow-scroll").outerHeight(); } var exists = PF.obj.follow_scroll.$node .closest(".follow-scroll-wrapper") .exists(); if (exists) { PF.obj.follow_scroll.$node .closest(".follow-scroll-wrapper") .css("position", "static"); } PF.obj.follow_scroll.y = PF.obj.follow_scroll.$node.exists() ? PF.obj.follow_scroll.$node.offset().top : null; PF.obj.follow_scroll.node_h = PF.obj.follow_scroll.$node.outerHeight(); if (exists) { PF.obj.follow_scroll.$node .closest(".follow-scroll-wrapper") .css("position", ""); } }, checkDocumentHeight: function () { var lastHeight = document.body.clientHeight, newHeight, timer; (function run() { newHeight = document.body.clientHeight; if (lastHeight != newHeight) { PF.obj.follow_scroll.set(); } lastHeight = newHeight; timer = setTimeout(run, 200); })(); } }; PF.obj.follow_scroll.set(); //PF.obj.follow_scroll.checkDocumentHeight(); PF.obj.follow_scroll.process = function (forced) { if (forced) { PF.obj.follow_scroll.node_h = PF.obj.follow_scroll.base_h; } if (!PF.obj.follow_scroll.$node.exists()) return; // Nothing to do here var $parent = PF.obj.follow_scroll.$node.closest( "[data-content=follow-scroll-parent]" ); if (!$parent.exists()) { $parent = PF.obj.follow_scroll.$node.closest(".content-width"); } var $wrapper = PF.obj.follow_scroll.$node.closest(".follow-scroll-wrapper"); var top = PF.obj.follow_scroll.node_h; var cond = $(window).scrollTop() > PF.obj.follow_scroll.y - top; if ($("#top-bar").css("position") !== "fixed") { PF.obj.follow_scroll.Y -= $(window).scrollTop(); if (PF.obj.follow_scroll.Y < 0) PF.obj.follow_scroll.Y = 0; cond = cond && $(window).scrollTop() > PF.obj.follow_scroll.y; } if ( (cond && $wrapper.hasClass("position-fixed")) || (!cond && !$wrapper.hasClass("position-fixed")) ) { return; } if (!$wrapper.exists()) { PF.obj.follow_scroll.$node.wrapAll('