PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.10
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.10
4.4.10 4.4.9.1 4.4.9 4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 All 142 releases
← All changes | assets/js/dist/admin/addons.js +318 -25 4.4.9.1 → 4.4.10 View file →
@@ -1696,15 +1696,23 @@
1696 1696 this.urlParams = new URLSearchParams(window.location.search);
1697 1697 }
1698 1698 static selectors = {
1699 1699 elAddonsPage: '.lp-addons-page',
1700 + elToolbar: '.lp-addons-toolbar',
1700 1701 elLPAddons: '#lp-addons',
1701 1702 elAddonItem: '.lp-addon-item',
1702 1703 elBtnAction: '.btn-addon-action',
1703 1704 elNavTab: '.nav-tab',
1704 1705 elNavTabActive: '.nav-tab.nav-tab-active',
1706 + elFilter: '.lp-addons-filter',
1707 + elFilterToggle: '.lp-addons-filter__toggle',
1708 + elFilterMenu: '.lp-addons-filter__menu',
1705 1709 elCategory: '.lp-addons-category',
1706 1710 elCategoryActive: '.lp-addons-category.active',
1711 + elSearch: '.lp-addons-search',
1712 + elSearchBtn: '.lp-addons-search__btn',
1713 + elSearchBtnClear: '.lp-addons-search__btn-clear',
1714 + elSearchClose: '.lp-addons-search__close',
1707 1715 elSearchInput: '#lp-search-addons__input',
1708 1716 elItemPurchase: '.lp-addon-item__purchase',
1709 1717 elPurchaseInstall: '.purchase-install',
1710 1718 elPurchaseCode: '.enter-purchase-code',
@@ -1716,9 +1724,40 @@
1716 1724 this.elAddonsPage = document.querySelector(AdminAddons.selectors.elAddonsPage);
1717 1725 if (!this.elAddonsPage) {
1718 1726 return;
1719 1727 }
1728 + const selectors = AdminAddons.selectors;
1729 + const urlTab = this.urlParams.get('tab');
1730 + if (urlTab) {
1731 + const elMatchingTab = this.elAddonsPage.querySelector(`${selectors.elNavTab}[data-tab="${urlTab}"]`);
1732 + if (elMatchingTab) {
1733 + this.elAddonsPage.querySelectorAll(selectors.elNavTab).forEach(elTab => {
1734 + elTab.classList.remove('nav-tab-active');
1735 + elTab.setAttribute('aria-pressed', 'false');
1736 + });
1737 + elMatchingTab.classList.add('nav-tab-active');
1738 + elMatchingTab.setAttribute('aria-pressed', 'true');
1739 + }
1740 + }
1741 + let elActiveTab = this.elAddonsPage.querySelector(selectors.elNavTabActive);
1742 + if (!elActiveTab) {
1743 + elActiveTab = this.elAddonsPage.querySelector(`${selectors.elNavTab}[data-tab="all"]`) || this.elAddonsPage.querySelector(selectors.elNavTab);
1744 + if (elActiveTab) {
1745 + elActiveTab.classList.add('nav-tab-active');
1746 + elActiveTab.setAttribute('aria-pressed', 'true');
1747 + }
1748 + }
1749 + let elActiveCategory = this.elAddonsPage.querySelector(selectors.elCategoryActive);
1750 + if (!elActiveCategory) {
1751 + elActiveCategory = this.elAddonsPage.querySelector(`${selectors.elCategory}[data-category="all"]`) || this.elAddonsPage.querySelector(selectors.elCategory);
1752 + if (elActiveCategory) {
1753 + elActiveCategory.classList.add('active');
1754 + elActiveCategory.setAttribute('aria-pressed', 'true');
1755 + }
1756 + }
1720 1757 this.filterAddons();
1758 + this.updateSearchClearBtnState();
1759 + this.updateFilterToggleState();
1721 1760 this.events();
1722 1761 });
1723 1762 }
1724 1763
@@ -1740,11 +1779,23 @@
1740 1779 selector: AdminAddons.selectors.elCategory,
1741 1780 class: this,
1742 1781 callBack: this.handleCategoryClick.name
1743 1782 }, {
1744 - selector: AdminAddons.selectors.elPurchaseCode,
1783 + selector: AdminAddons.selectors.elFilterToggle,
1745 1784 class: this,
1746 - callBack: this.handlePurchaseCodeClick.name
1785 + callBack: this.handleFilterToggleClick.name
1786 + }, {
1787 + selector: AdminAddons.selectors.elSearchBtn,
1788 + class: this,
1789 + callBack: this.handleSearchBtnClick.name
1790 + }, {
1791 + selector: AdminAddons.selectors.elSearchBtnClear,
1792 + class: this,
1793 + callBack: this.handleSearchClearClick.name
1794 + }, {
1795 + selector: AdminAddons.selectors.elSearchClose,
1796 + class: this,
1797 + callBack: this.handleSearchCloseClick.name
1747 1798 }]);
1748 1799 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_1__.eventHandlers('input', [{
1749 1800 selector: AdminAddons.selectors.elSearchInput,
1750 1801 class: this,
@@ -1753,8 +1804,29 @@
1753 1804 selector: AdminAddons.selectors.elPurchaseCode,
1754 1805 class: this,
1755 1806 callBack: this.handlePurchaseCodeInput.name
1756 1807 }]);
1808 + lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_1__.eventHandlers('keydown', [{
1809 + selector: AdminAddons.selectors.elSearchInput,
1810 + class: this,
1811 + callBack: this.handleSearchKeydown.name
1812 + }]);
1813 + document.addEventListener('click', e => {
1814 + if (!this.elAddonsPage) {
1815 + return;
1816 + }
1817 + const elToolbar = this.elAddonsPage.querySelector(AdminAddons.selectors.elToolbar);
1818 + if (elToolbar && elToolbar.classList.contains('is-filter-open')) {
1819 + if (!elToolbar.contains(e.target)) {
1820 + this.toggleFilterMenu(false);
1821 + }
1822 + }
1823 + });
1824 + document.addEventListener('keydown', e => {
1825 + if ('Escape' === e.key) {
1826 + this.toggleFilterMenu(false);
1827 + }
1828 + });
1757 1829 }
1758 1830
1759 1831 /**
1760 1832 * Get addon data embedded on the item element.
@@ -1790,10 +1862,14 @@
1790 1862 addon,
1791 1863 purchase_code: data.purchase_code || '',
1792 1864 id_url: 'addon-action'
1793 1865 };
1866 + const releaseHandling = () => {
1867 + lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_1__.lpSetLoadingEl(el, 0);
1868 + };
1794 1869 window.lpAJAXG.fetchAJAX(params, {
1795 1870 success: response => {
1871 + releaseHandling();
1796 1872 const {
1797 1873 status,
1798 1874 message,
1799 1875 data: resData
@@ -1810,12 +1886,11 @@
1810 1886 }
1811 1887 }
1812 1888
1813 1889 //this.filterAddons();
1814 - lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_1__.lpSetLoadingEl(el, 0);
1815 1890 },
1816 1891 error: error => {
1817 - lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_1__.lpSetLoadingEl(el, 0);
1892 + releaseHandling();
1818 1893 lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_0__.show(`error js: ${error}`, 'error');
1819 1894 }
1820 1895 });
1821 1896 }
@@ -1888,28 +1963,8 @@
1888 1963 });
1889 1964 }
1890 1965
1891 1966 /**
1892 - * Handle click events.
1893 - *
1894 - * @param {Object} args Click event arguments.
1895 - * @return void
1896 - */
1897 - handlePurchaseCodeClick(args) {
1898 - const {
1899 - target: el
1900 - } = args;
1901 - if (!el.value.startsWith('***')) {
1902 - return;
1903 - }
1904 - el.value = '';
1905 - const elItemPurchase = el.closest(AdminAddons.selectors.elItemPurchase);
1906 - if (elItemPurchase) {
1907 - elItemPurchase.querySelector('input[name=purchase-code]').value = '';
1908 - }
1909 - }
1910 -
1911 - /**
1912 1967 * Handle addon action button click.
1913 1968 *
1914 1969 * @param {Object} args Click event arguments.
1915 1970 * @return void
@@ -1940,24 +1995,65 @@
1940 1995 if (action === 'purchase' || action === 'update-purchase-code') {
1941 1996 const elPurchaseInstall = elItemPurchase.querySelector(selectors.elPurchaseInstall);
1942 1997 const elPurchaseCode = elPurchaseInstall.querySelector(selectors.elPurchaseCode);
1943 1998 const elPurchaseSubmit = elPurchaseInstall.querySelector('.lp-addon-purchase__submit');
1999 + const elPurchaseClear = elPurchaseInstall.querySelector('.lp-addon-purchase__clear');
2000 + const elPurchaseCancelClear = elPurchaseInstall.querySelector('.lp-addon-purchase__cancel-clear');
2001 + let hasPurchaseCode = false;
1944 2002 if (action === 'update-purchase-code') {
1945 2003 const elLicense = elAddonItem.querySelector(selectors.elLicense);
1946 2004 elPurchaseCode.value = elLicense ? elLicense.dataset.purchaseCodeMasked || '' : '';
2005 + hasPurchaseCode = '' !== elPurchaseCode.value;
1947 2006 elPurchaseSubmit.dataset.action = 'update-purchase';
1948 2007 } else {
1949 2008 elPurchaseCode.value = '';
1950 2009 elPurchaseSubmit.dataset.action = 'install';
1951 2010 }
2011 + elPurchaseCode.disabled = hasPurchaseCode;
2012 + elPurchaseSubmit.classList.toggle('lp-hidden', hasPurchaseCode);
2013 + elPurchaseClear.classList.toggle('lp-hidden', !hasPurchaseCode);
2014 + elPurchaseCancelClear.classList.add('lp-hidden');
1952 2015 elPurchaseCode.classList.remove('is-error');
1953 2016 elPurchaseCode.removeAttribute('aria-invalid');
1954 2017 elItemPurchase.querySelector('input[name=purchase-code]').value = '';
1955 2018 elPurchaseInstall.style.display = 'flex';
1956 2019 elItemPurchase.style.display = 'block';
2020 + if (!hasPurchaseCode) {
2021 + elPurchaseCode.focus();
2022 + }
2023 + lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_1__.lpSetLoadingEl(el, 0);
2024 + return;
2025 + } else if (action === 'clear-license') {
2026 + const elPurchaseCode = elItemPurchase.querySelector(selectors.elPurchaseCode);
2027 + const elPurchaseSubmit = elItemPurchase.querySelector('.lp-addon-purchase__submit');
2028 + const elPurchaseClear = elItemPurchase.querySelector('.lp-addon-purchase__clear');
2029 + const elPurchaseCancelClear = elItemPurchase.querySelector('.lp-addon-purchase__cancel-clear');
2030 + elPurchaseCode.value = '';
2031 + elPurchaseCode.disabled = false;
2032 + elPurchaseCode.classList.remove('is-error');
2033 + elPurchaseCode.removeAttribute('aria-invalid');
2034 + elItemPurchase.querySelector('input[name=purchase-code]').value = '';
2035 + elPurchaseSubmit.classList.remove('lp-hidden');
2036 + elPurchaseClear.classList.add('lp-hidden');
2037 + elPurchaseCancelClear.classList.remove('lp-hidden');
1957 2038 elPurchaseCode.focus();
1958 2039 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_1__.lpSetLoadingEl(el, 0);
1959 2040 return;
2041 + } else if (action === 'cancel-clear-license') {
2042 + const elLicense = elAddonItem.querySelector(selectors.elLicense);
2043 + const elPurchaseCode = elItemPurchase.querySelector(selectors.elPurchaseCode);
2044 + const elPurchaseSubmit = elItemPurchase.querySelector('.lp-addon-purchase__submit');
2045 + const elPurchaseClear = elItemPurchase.querySelector('.lp-addon-purchase__clear');
2046 + elPurchaseCode.value = elLicense ? elLicense.dataset.purchaseCodeMasked || '' : '';
2047 + elPurchaseCode.disabled = true;
2048 + elPurchaseCode.classList.remove('is-error');
2049 + elPurchaseCode.removeAttribute('aria-invalid');
2050 + elItemPurchase.querySelector('input[name=purchase-code]').value = '';
2051 + elPurchaseSubmit.classList.add('lp-hidden');
2052 + elPurchaseClear.classList.remove('lp-hidden');
2053 + el.classList.add('lp-hidden');
2054 + lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_1__.lpSetLoadingEl(el, 0);
2055 + return;
1960 2056 } else if (action === 'cancel') {
1961 2057 elItemPurchase.style.display = 'none';
1962 2058 elItemPurchase.querySelector(selectors.elPurchaseInstall).style.display = 'none';
1963 2059 lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_1__.lpSetLoadingEl(el, 0);
@@ -1997,11 +2093,28 @@
1997 2093 elTab.setAttribute('aria-pressed', 'false');
1998 2094 });
1999 2095 el.classList.add('nav-tab-active');
2000 2096 el.setAttribute('aria-pressed', 'true');
2097 + if (el.scrollIntoView) {
2098 + el.scrollIntoView({
2099 + inline: 'center',
2100 + block: 'nearest',
2101 + behavior: 'smooth'
2102 + });
2103 + }
2001 2104 const tabName = el.dataset.tab;
2002 2105 const elSearch = this.elAddonsPage.querySelector(selectors.elSearchInput);
2003 - elSearch.value = '';
2106 + if (elSearch) {
2107 + elSearch.value = '';
2108 + }
2109 + const elSearchContainer = this.elAddonsPage.querySelector(selectors.elSearch);
2110 + if (elSearchContainer) {
2111 + elSearchContainer.classList.remove('is-open');
2112 + const btn = elSearchContainer.querySelector(selectors.elSearchBtn);
2113 + if (btn) {
2114 + btn.setAttribute('aria-expanded', 'false');
2115 + }
2116 + }
2004 2117 this.elAddonsPage.querySelectorAll(selectors.elCategory).forEach(elCategory => {
2005 2118 const isActive = 'all' === elCategory.dataset.category;
2006 2119 elCategory.classList.toggle('active', isActive);
2007 2120 elCategory.setAttribute('aria-pressed', isActive ? 'true' : 'false');
@@ -2007,12 +2120,73 @@
2007 2120 elCategory.setAttribute('aria-pressed', isActive ? 'true' : 'false');
2008 2121 });
2009 2122 this.urlParams.set('tab', tabName);
2010 2123 window.history.pushState({}, '', `${window.location.pathname}?${this.urlParams.toString()}`);
2124 + this.updateFilterToggleState();
2011 2125 this.filterAddons();
2012 2126 }
2013 2127
2014 2128 /**
2129 + * Handle filter toggle button click.
2130 + *
2131 + * @param {Object} args Click event arguments.
2132 + * @return void
2133 + */
2134 + handleFilterToggleClick(args) {
2135 + const {
2136 + e
2137 + } = args;
2138 + e.preventDefault();
2139 + e.stopPropagation();
2140 + this.toggleFilterMenu();
2141 + }
2142 +
2143 + /**
2144 + * Toggle or set filter menu dropdown open state.
2145 + *
2146 + * @param {boolean|undefined} open Optional boolean to force state.
2147 + * @return void
2148 + */
2149 + toggleFilterMenu(open) {
2150 + const selectors = AdminAddons.selectors;
2151 + const elToolbar = this.elAddonsPage.querySelector(selectors.elToolbar);
2152 + const elFilter = this.elAddonsPage.querySelector(selectors.elFilter);
2153 + if (!elToolbar && !elFilter) {
2154 + return;
2155 + }
2156 + const toggleBtn = this.elAddonsPage.querySelector(selectors.elFilterToggle);
2157 + const shouldOpen = undefined !== open ? open : elToolbar ? !elToolbar.classList.contains('is-filter-open') : !elFilter.classList.contains('is-open');
2158 + if (elToolbar) {
2159 + elToolbar.classList.toggle('is-filter-open', shouldOpen);
2160 + }
2161 + if (elFilter) {
2162 + elFilter.classList.toggle('is-open', shouldOpen);
2163 + }
2164 + if (toggleBtn) {
2165 + toggleBtn.setAttribute('aria-expanded', shouldOpen ? 'true' : 'false');
2166 + }
2167 + }
2168 +
2169 + /**
2170 + * Update filter toggle button has-filter state.
2171 + *
2172 + * @return void
2173 + */
2174 + updateFilterToggleState() {
2175 + const selectors = AdminAddons.selectors;
2176 + const toggleBtn = this.elAddonsPage.querySelector(selectors.elFilterToggle);
2177 + if (!toggleBtn) {
2178 + return;
2179 + }
2180 + const elActiveTab = this.elAddonsPage.querySelector(selectors.elNavTabActive);
2181 + const elActiveCategory = this.elAddonsPage.querySelector(selectors.elCategoryActive);
2182 + const tabName = elActiveTab ? elActiveTab.dataset.tab : 'all';
2183 + const category = elActiveCategory ? elActiveCategory.dataset.category : 'all';
2184 + const hasFilter = 'all' !== tabName || 'all' !== category;
2185 + toggleBtn.classList.toggle('has-filter', hasFilter);
2186 + }
2187 +
2188 + /**
2015 2189 * Handle category click.
2016 2190 *
2017 2191 * @param {Object} args Click event arguments.
2018 2192 * @return void
@@ -2028,8 +2202,9 @@
2028 2202 const isActive = item === elCategory;
2029 2203 item.classList.toggle('active', isActive);
2030 2204 item.setAttribute('aria-pressed', isActive ? 'true' : 'false');
2031 2205 });
2206 + this.updateFilterToggleState();
2032 2207 this.filterAddons();
2033 2208 }
2034 2209
2035 2210 /**
@@ -2037,9 +2212,127 @@
2037 2212 *
2038 2213 * @return void
2039 2214 */
2040 2215 handleSearchInput() {
2216 + this.updateSearchClearBtnState();
2041 2217 this.filterAddons();
2218 + }
2219 +
2220 + /**
2221 + * Handle search button click to open search overlay.
2222 + *
2223 + * @param {Object} args Click event arguments.
2224 + * @return void
2225 + */
2226 + handleSearchBtnClick(args) {
2227 + const {
2228 + e
2229 + } = args;
2230 + e.preventDefault();
2231 + this.toggleFilterMenu(false);
2232 + const selectors = AdminAddons.selectors;
2233 + const elSearch = this.elAddonsPage.querySelector(selectors.elSearch);
2234 + const elSearchInput = this.elAddonsPage.querySelector(selectors.elSearchInput);
2235 + if (elSearch) {
2236 + elSearch.classList.add('is-open');
2237 + const btn = elSearch.querySelector(selectors.elSearchBtn);
2238 + if (btn) {
2239 + btn.setAttribute('aria-expanded', 'true');
2240 + }
2241 + }
2242 + if (elSearchInput) {
2243 + this.updateSearchClearBtnState();
2244 + elSearchInput.focus();
2245 + }
2246 + }
2247 +
2248 + /**
2249 + * Handle search clear button click.
2250 + *
2251 + * @param {Object} args Click event arguments.
2252 + * @return void
2253 + */
2254 + handleSearchClearClick(args) {
2255 + const {
2256 + e
2257 + } = args;
2258 + e.preventDefault();
2259 + const selectors = AdminAddons.selectors;
2260 + const elSearchInput = this.elAddonsPage.querySelector(selectors.elSearchInput);
2261 + if (elSearchInput) {
2262 + elSearchInput.value = '';
2263 + this.updateSearchClearBtnState();
2264 + this.filterAddons();
2265 + elSearchInput.focus();
2266 + }
2267 + }
2268 +
2269 + /**
2270 + * Update disabled state of clear search button.
2271 + *
2272 + * @return void
2273 + */
2274 + updateSearchClearBtnState() {
2275 + const selectors = AdminAddons.selectors;
2276 + const elSearchInput = this.elAddonsPage.querySelector(selectors.elSearchInput);
2277 + const elClearBtn = this.elAddonsPage.querySelector(selectors.elSearchBtnClear);
2278 + if (elClearBtn && elSearchInput) {
2279 + elClearBtn.disabled = !elSearchInput.value.trim();
2280 + }
2281 + }
2282 +
2283 + /**
2284 + * Handle search close button click.
2285 + *
2286 + * @param {Object} args Click event arguments.
2287 + * @return void
2288 + */
2289 + handleSearchCloseClick(args) {
2290 + const {
2291 + e
2292 + } = args;
2293 + e.preventDefault();
2294 + this.closeSearch();
2295 + }
2296 +
2297 + /**
2298 + * Handle search input keydown.
2299 + *
2300 + * @param {Object} args Keydown event arguments.
2301 + * @return void
2302 + */
2303 + handleSearchKeydown(args) {
2304 + const {
2305 + e
2306 + } = args;
2307 + if ('Escape' === e.key) {
2308 + e.preventDefault();
2309 + this.closeSearch();
2310 + }
2311 + }
2312 +
2313 + /**
2314 + * Close search overlay and reset query if needed.
2315 + *
2316 + * @return void
2317 + */
2318 + closeSearch() {
2319 + const selectors = AdminAddons.selectors;
2320 + const elSearch = this.elAddonsPage.querySelector(selectors.elSearch);
2321 + const elSearchInput = this.elAddonsPage.querySelector(selectors.elSearchInput);
2322 + if (elSearch) {
2323 + elSearch.classList.remove('is-open');
2324 + const btn = elSearch.querySelector(selectors.elSearchBtn);
2325 + if (btn) {
2326 + btn.setAttribute('aria-expanded', 'false');
2327 + btn.focus();
2328 + }
2329 + }
2330 + if (elSearchInput && elSearchInput.value) {
2331 + elSearchInput.value = '';
2332 + this.filterAddons();
2333 + }
2334 + this.updateSearchClearBtnState();
2042 2335 }
2043 2336
2044 2337 /**
2045 2338 * Handle purchase code input.