/** * Peafowl JS * Copyright 2014 Rodolfo Berrios */ /** * Peafowl DOM functions and event listeners */ $(function(){ $.ajaxSetup({ "url": PF.obj.config.json_api, "cache": false, "dataType": "json", "data": {auth_token: PF.obj.config.auth_token} }); /** * 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() { PF.obj.follow_scroll.set(); }, 100); //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(); PF.obj.follow_scroll.process(); }); // Close the opened pop-boxes on HTML click $(document).on("click", "html", function(){ PF.fn.close_pops(); }); /** * SMALL HELPERS AND THINGS * ------------------------------------------------------------------------------------------------- */ // 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); } }); // The handly data-trigger. It will trigger click for elements with data-trigger $(document).on("click", "[data-trigger]", function(e) { 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).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), $target, submit_function, cancel_function, onload_function, submit_done_msg; 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"), 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

'+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); }); } // nota: update junkstr $(document).on("click focus", "[data-login-needed], [data-user-logged=must]", function(e) { if(!PF.fn.is_user_logged()){ e.preventDefault(); e.stopPropagation(); if($(this).is(":input")) $(this).attr("readonly", true).blur(); PF.fn.modal.call({type: "login"}); } }); // 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), $pop_btn, $pop_box, 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")){ 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")){ $pop_box.closest(".pop-btn").removeClass("opened"); } else { if(!PF.fn.isDevice(devices)) { $(".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,-"+pop_box_h+")" }); 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["fade" + ($pop_box.is(":visible") ? "Out" : "In")](50, function() { callback($pop_box); }); //$pop_box.toggle(); //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(e.type == "statechange"){ dataTab = History.getState().data; } else if(e.type == "hashchange"){ if(typeof PF.obj.tabs.hashdata !== "undefined" && typeof PF.obj.tabs.hashdata.href !== "undefined" && PF.obj.tabs.hashdata.href !== window.location.hash) { PF.obj.tabs.hashdata = null; } if(PF.obj.tabs.hashdata == null) { var $target = $("[href="+ window.location.hash +"]", ".content-tabs"); if(!$target.exists()) $target = $(window.location.hash); if(!$target.exists()) $target = $("a", ".content-tabs").first(); if(typeof $target.data("tab") !== "undefined") { PF.obj.tabs.hashdata = {}; $.each($target[0].attributes, function(){ PF.obj.tabs.hashdata[this.name] = this.value; }); PF.obj.tabs.hashdata.pushed = "tabs"; } } dataTab = (typeof PF.obj.tabs.hashdata !== "undefined") ? PF.obj.tabs.hashdata : null; } */ 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(); // 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.hidden_params == "undefined") { PF.obj.listing.hidden_params = {}; } PF.obj.listing.hidden_params.offset = offset; } else { if(typeof PF.obj.listing.query_string.offset !== "undefined") { delete PF.obj.listing.query_string.offset; } if(PF.obj.listing.hidden_params && typeof PF.obj.listing.hidden_params.offset !== "undefined") { delete PF.obj.listing.hidden_params.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() { if(($(window).scrollTop() + $(window).height() > $(document).height() - 200) && PF.obj.listing.calling == false) { $(PF.obj.listing.selectors.content_listing_visible).find(PF.obj.listing.selectors.content_listing_pagination).find("[data-action=load-more]").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") + "]"), 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(){ $("#cookie-law-banner").animate({bottom: "-100%"}, 300, function() { var cookieName = (typeof $(this).data("cookie") !== typeof undefined) ? $(this).data("cookie") : "PF_COOKIE_LAW_DISPLAY"; Cookies.set(cookieName, 0, {expires: 365}); $(this).remove(); }); }); // One-click input copy $(document).on("click", "[data-action=copy]", function() { }); 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").is(":visible"); // 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://gist.github.com/alexey-bass/1115557 PF.fn.versionCompare = function(left, right) { if (typeof left + typeof right != 'stringstring') return false; var a = left.split('.') , b = right.split('.') , i = 0, len = Math.max(a.length, b.length); for (; i < len; i++) { if ((a[i] && !b[i] && parseInt(a[i]) > 0) || (parseInt(a[i]) > parseInt(b[i]))) { return 1; } else if ((b[i] && !a[i] && parseInt(b[i]) > 0) || (parseInt(a[i]) < parseInt(b[i]))) { return -1; } } return 0; } /** * 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; } PF.fn.guid = function() { function s4() { return Math.floor((1 + Math.random()) * 0x10000) .toString(16) .substring(1); } return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); } 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); } /** * 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= 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; return(this.hasClass("fluid") || this.css("width")=="100%"); }; /** * 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() */ ); }; /** * 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); } }, /** * 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}); setTimeout(function() { if(typeof modal_options.load == "function") { modal_options.load(); } // Stock the default modal values $("html").data("modal-form-values", PF.fn.deparam($(":input:visible", PF.obj.modal.selectors.root).serialize())); }, 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).imagesLoaded(function(){ var items = PF.obj.listing.selectors.list_item, $subjects = $(items+":visible", PF.obj.listing.selectors.content_listing_visible), $targets = $(items+":hidden", PF.obj.listing.selectors.content_listing_visible); 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; 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.hidden_params = 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]; } } // The additional params setted in data-hidden-params="" for(var k in PF.obj.listing.hidden_params) { if(/action|list|sort|page/.test(k) == false) { PF.obj.listing.query_string[k] = PF.obj.listing.hidden_params[k]; } } }, // 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), $pad_content_listing = $(PF.obj.listing.selectors.pad_content, $content_listing); $(PF.obj.listing.selectors.content_listing_load_more, $content_listing).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.hidden_params) { 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); 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 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, and is safe to upscale the image? 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 <= .25 && pitfall_ratio_y <= .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(){ $(this).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; } }); 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, set: function() { 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(){ if(!PF.obj.follow_scroll.$node.exists() || PF.fn.isDevice("phone")) 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 top = PF.obj.follow_scroll.node_h, // - parseInt($("#top-bar").css("top")) 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; } var $wrapper = PF.obj.follow_scroll.$node.closest('.follow-scroll-wrapper'); if((cond && $wrapper.hasClass("position-fixed")) || (!cond && !$wrapper.hasClass("position-fixed"))) { return; } if(!$wrapper.exists()) { PF.obj.follow_scroll.$node.wrapAll('