JavDB/MissAV 双站增强工具箱:收藏管理、状态标签、屏蔽过滤、跨站同步、热播/Top250榜单、新作品检测、预告片、字幕搜索、WebDav云备份、演员信息、清单管理、快捷键等 36 个功能插件
// ==UserScript==
// @name JavDB Power Tools
// @namespace zerobiubiu.top
// @version 1.2.0
// @author zerobiubiu
// @description JavDB/MissAV 双站增强工具箱:收藏管理、状态标签、屏蔽过滤、跨站同步、热播/Top250榜单、新作品检测、预告片、字幕搜索、WebDav云备份、演员信息、清单管理、快捷键等 36 个功能插件
// @license MIT
// @icon https://cdn.jsdelivr.net/gh/zerobiubiu/Figure-bed/b507c13a-9f4e-41b5-bbbb-129d0a21f97d.png
// @homepageURL https://github.com/zerobiubiu/javdb-tools
// @include https://javdb*.com/*
// @include https://missav*.ws/*
// @include https://missav*.live/*
// @match https://javdb.com/*
// @match https://missav.ws/*
// @match https://missav.live/*
// @connect xunlei.com
// @connect missav.live
// @connect javdb.com
// @connect supjav.com
// @connect 127.0.0.1
// @connect *
// @grant GM_addStyle
// @grant GM_addValueChangeListener
// @grant GM_getValue
// @grant GM_openInTab
// @grant GM_registerMenuCommand
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// @grant window.close
// @run-at document-idle
// ==/UserScript==
(function() {
"use strict";
var s = new Set();
var _css = async (t) => {
if (s.has(t)) return;
s.add(t);
((c) => {
if (typeof GM_addStyle === "function") GM_addStyle(c);
else (document.head || document.documentElement).appendChild(document.createElement("style")).append(c);
})(t);
};
_css(" html #layuicss-skinlayercss{width:1989px;display:none;position:absolute}.layui-layer-shade,.layui-layer{_position:absolute;pointer-events:auto;position:fixed}.layui-layer-shade{width:100%;height:100%;top:0;left:0}.layui-layer{-webkit-overflow-scrolling:touch;background-color:#fff;-webkit-background-clip:content;margin:0;padding:0;top:150px;left:0;box-shadow:1px 1px 50px #0000004d}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #0000001a;box-shadow:1px 1px 5px #0003}.layui-layer-load{background:#eee url(data:image/gif;base64,R0lGODlhJQAlAJECAL3L2AYrTv///wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgACACwAAAAAJQAlAAACi5SPqcvtDyGYIFpF690i8xUw3qJBwUlSadmcLqYmGQu6KDIeM13beGzYWWy3DlB4IYaMk+Dso2RWkFCfLPcRvFbZxFLUDTt21BW56TyjRep1e20+i+eYMR145W2eefj+6VFmgTQi+ECVY8iGxcg35phGo/iDFwlTyXWphwlm1imGRdcnuqhHeop6UAAAIfkEBQoAAgAsEAACAAQACwAAAgWMj6nLXAAh+QQFCgACACwVAAUACgALAAACFZQvgRi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwXABEADAADAAACBYyPqcsFACH5BAUKAAIALBUAFQAKAAsAAAITlGKZwWoMHYxqtmplxlNT7ixGAQAh+QQFCgACACwQABgABAALAAACBYyPqctcACH5BAUKAAIALAUAFQAKAAsAAAIVlC+BGL3Z3IlxUmUuhtR2LzHhsiEFACH5BAUKAAIALAEAEQAMAAMAAAIFjI+pywUAIfkEBQoAAgAsBQAFAAoACwAAAhOUYJnAagwdjGq2amXGU1PuLEYBACH5BAUKAAIALBAAAgAEAAsAAAIFhI+py1wAIfkEBQoAAgAsFQAFAAoACwAAAhWUL4AIvdnciXFSZS6G1HYvMeGyIQUAIfkEBQoAAgAsFwARAAwAAwAAAgWEj6nLBQAh+QQFCgACACwVABUACgALAAACE5RgmcBqDB2MarZqZcZTU+4sRgEAIfkEBQoAAgAsEAAYAAQACwAAAgWEj6nLXAAh+QQFCgACACwFABUACgALAAACFZQvgAi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwBABEADAADAAACBYSPqcsFADs=) 50% no-repeat}.layui-layer-ico{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANIAAAA9CAYAAADYizcVAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAACAASURBVHic7Z15fFvVmfe/92qzJMtrvCQ2jp09TuwsQCAkISwJDVAoW0hombaQhgKlnU5pmc60A+3M0FK6dxhoGghLC0PCEjJAIW8gISQhwWSzHcfO4tix41heZNmSLFnS1T3vH7IUy1qdmPfTd8a/z8cfS/ee5/zuvbq/e855znOeKwkhBEkg3FYC1j0Eug6i2upQHU0ITycAkjEfOaMMOXcWmrz5aAoXIZkKk1WZEs563ezstVLV10WNy8bJfgedPg8A+XojU8wZVKbnsiAzj6VZhUwwmEaFV7Xb8NXV4D95DKWliYC1DbW3FwA5KwtNYRHakjJ0U6ajn1WJnJ07KrzCd5aAYyeqqwrVXYM6cBLhH7zOunzktCnIpkrk9AVoMpYi6SeMCq/D4aCpqYmWlhasVis2mw2n0wmAxWIhNzeXwsJCSkpKKCsrIyMjY1R41Z5ufLWH8R8/ir+5kUB7G2pvDwByVg6a8UXoSiejm1aOvmIucs64UeG1+vvY42rkQH8zRz1nOeXtplMJnm++1sIkwzjKjRO42FzKovTJFOoyk9YpJRKSam9AaXoLpfld1J6jKR2knFOOtvRGtGW3IGfPSPHUIlHXb2dTRxObO5updfakZFNhyeHW/FLuLChjljn7vHiV1tMM7N2Jt2oPyummlGy0E8swLFhE2sKlaC+aeF68qrsOxbaJQM9m1P7alGxkcwWanFvR5t6JbJp1XrwdHR3U1NRQV1dHe3t7Sjbjx49n1qxZVFZWUlBQcF68SksTA7u2M7D3Y5TmxpRstKWTSVt4JWlLrkFbUnZevA0DVt6yH+Sd3hqOes6mZFNunMAXsyq5JXs+M9LiNxBxhCTwNzyPv/4lVFstctZUNIWLkPPno8kuR7KUIBmyEV47wtlCwH4UtfMgAese1N4TAMi5FehmfhXdjHsAKaWDFsAfzzSwvq2eQw4bM8xZLM0pZEFGPhXp2ZQZLeRoDfQoXpo8TmpddqocnezssdLQH2wx5mXksrZoJvcXz0iRFRACz7Z38XzwV/xNJ9EWlaArr0A3ZQbaiWVo8guQ0zNQXQ4CnR0op5vwn2zAf7QWpa0FAF3ZFIzLbsC4/EaQUmUWKB1/xN+xHtV1CNk0AzljKZr0BcimCqS0MiRtDkLpQQw0obprCbiqUB07Ud0NweucPg9dwVq0Bfenfp2FoKqqik8//ZS2tjby8/MpKyujpKSEwsJCsrOzMZlMuN1u7HY7VquVlpYWmpqa6OwMtpBFRUVcdtllLFiwACnV8xUC93tv4dn6Nv7G42gvmoh+9jx002aiLZ2EpmACssWC6nQS6DiL0nwK//F6fEcOobSeDl7nydMwfuEmTNffkvJ1Fgie797DS92fUOM+w9S0AhalT2G+uZRZxvGU6HPJ1pqwK25afDbqPO0c7G9mj+skJwY6AKg0FfPVcVdwz7hFSDGuc5SQhKcTX+1/4K95GjlvLrpJt6It+xJS+kXJD9jTiXJyE/5Tm1G7DgdPvPJB9BXfRjLmJ7S1+jz88nQtv2mu4ZLMPFYVTGJlQRkT09KT8lp9Hv7SfpKNHafY39cFwPdKK/nBxAoK9caEtmqvnf7/3oT77TfQTZ5G2hVXYVh4JZq8xMcbsh34+EMGPvkIf+NxAEw33Y755juRsxK3isJvxX/2l/jbfoNsuQRt7iq0uSuRDMlbNeG3onT9BcW2EdW5HwBd0ffQTfgBki5xt9rpdLJz50527dpFcXExc+bMoaKiguzs5K240+nk0KFDVFdXc+bMGQCWLFnC0qVLsVgsCW1Vew/9b75C/+ZX0U2dSdqSa0hbfDWa/OTDANXeg2fHVgZ2bcd/oh4A862rMd/2ZeTsnIS2nX4Hf+j8kKc7djDXVMJt2fP5UvZcLtIntgvZburZz5v2gxx2Bx+YDxZczXfyryVfF9m91fzkJz/5SeiL8HTiO/AE/rpn0c28F8MlP0I78UYkffI+IoCkM6MpWICm6CpQ/ajdh1A7PgO/C03ePCSdOaad1efhscYDPNVSxwMXzeTxyZdwS/5EsrT6lHjTNTquyCpgeU4RPqGy39HN3t4OnAE/l2bmka7RxbRTe+24Nr2E570tmL5wE+l33YNhwRXI5tjHGXW+aUZ008vRV86HgIK/8Tj+4/WIAQ+6ydOR0mKLWPit+FofQ2l/Ct34B9Bf9DjanFuQtFmp8WrS0ViuQJu1HPChuvajOvciVCea9EuRNLEfPk6nk23btvHJJ5+wcOFCVqxYwaxZszAaEz9sQjAYDEycOJGpU6eiqipnzpyhpaUFr9dLcXExBoMhpp1q78H18nO433kD0w23YvnqWtIWXolsTv6QBJCMRvQzKzDMuxQUBf+JBvwNRxAeN7qpM5HiHH+n38HP29/j2a6PuTdvMT+e8EVuzKokU5Pa+Zo1Bhakl3FVxnT8IsAhdwuf9TfjVL3MN5Vg1pw73yFCEvgO/QLl+CvoL34Ew6WPIhnzUiKMOnFDFtqS5aDRoXYdINC5HySBtuhqhnc/BPCTU4d4oe04j06+mCemXkpBklYkHrJ1Bm4YV4JO1lDV18Xevk6EJHFdblF0YywErtdeYmDH/yF95d2kf3kNcub5ja1kczqGeQuQtFr8J4/hP34UEBgqL47R/RD4z/yEQNcL6C96FH3JE0i68xtrSNpsNNk3IMk61P4qVMdekASarOuIus5CsG3bNvbv38+yZctYsWIF6emp3cjDYTQamT59OhqNhtbWVlpaWhBCMHXq1OhunhC4XtmA54O/YrnrXixfvx85K3lrEAtyugXDJQuRtLqgg6LhCCCCApOG31eCJ6zv8YrtUx4Zfz2PFd1Eni5xqxkPWRoTyzPL0UlaDvSfZn9/E6okuDpjRribFxaSv+F5fJ/9DP3Fj6Cf8z1S7W/Hh4SmcCFIEDi7C7XjMyRTHppx8yJK/fFMAz8++RmPTr6YH5XNGQVWuDK7EIHE9p6z7O3toMBg4tKMSI+PZ9u7uP7rBdJX3o35ti+PYFwTj1hCP7MCEPiOHMZ/vB5NVg66ydMiiikdf8R3+sfoL3oUXdGPGJXrnHElIAj0bUd17kXWFyCnXxpRqqqqiq1bt7Js2TKuueaa1Mc18VglibKy4KC/sbGRlpYWMjIyKC4ujijnfu8tXH9ej+WuezGv+uroXOfZc5AE+GoO4G84gpydg27qzIhiz3fv4fGz7/LI+Ot5uPC6mOOaEdEicUX6ZASwy3mcz/qbyddlMM9UAgwKSbU34Nv/ONrSL2K49FGS/biuZ3PxHXwS38En0U6+HSkt/hNGU3g5wtON2n0I0W9FU3g5kjF4U9f12/lx435uzS/liamXXvAtNRRLsgvp9HvY7+jmrK+fxdmF5A+2dErrafpffYG0yxaR/uU1ET+u0taC0tqcUt8dVcV7sArZaAp3L/QzZiMcffgbj6PabehmzEbODHbZVHcdvtYfo829FX3JEyS6zsJ3FqVzA0rX86h9HyB87UhpU5Dk2N0nTcYSUDpRXfsR/rNoLIuRdMFxXkdHB1u3bmX27NmsWLEioYjcbjdbtmzh/fffp6GhAbPZTG5ufPd+aWkp/f39nDlzBofDQWlpabilU1qacP15PWkLr8Ty9fsvXERDoJ9VidrXi/9EA2qPLTgNMdijaBiw8vjZd7gxq5LHim66YBENxcL0SXQrLg65W7D6+7g8fTLjtOnIAErTWyBr0JXfy4U/IYdDQlf5EHLeXFRbbZBrEJs6mtBIMg8Wl48Ka31/L58OOhsk4AcTK7kkM49DDhubOs65swf27gRZxviFmyJ+XLXXjvvtN+h/4xUC7WeS8nmrD9D/2p/xbH+fQHfn4OlKmG5eiW7yNPxNJ4Ncg1Bsm0DSoC14kETXOdCzGc/hcnxN30Wx/gn/2T/gPbkGz+FyAn3b41hJ6Cb8ANlyCarrUJBrEDU1NUiSxMKFCxOKqKWlhccff5yOjg5mzJiBTqfjxRdf5NVXX41rI0kSV155JcXFxbS1tVFTUxPeN7BrO8gaTDfeGlNEgY52+t94hYGd2xCKP2q/6ujD/e5m3O9uRnU5hxNjvv3L6KbOxN94PMg1iLfsB5GRWTNuyaiKCIIt07cLrmWuqYQa9xnesh8EQBZuK0rzu+gm3YqcPTNJNecH2TIR3aRbAVCa30W4rZz1utnc2cyqgknMTj+/sclQ1Lrs3Fb9AbdWb2NfX/CmLjNaWFUwCYDNnc2c9bpR7Ta8VXtIu+IqtBeVRtThqz2E58P38NUewvHc0wQ6rXH5fEcO43pxHf7G4/Rv/i8Gtm8N79PkF5J2xVUAeKv2oNptwcnWns1oc1chm2bHrVftP8xAw+0IpS+4QdaDHHSWCO8ZBupXoHrqY9pKhjK0uauAoBiF7ywOh4O6ujrmzJmTdN5nw4YNXHXVVXzrW9/ihhtu4O677+ZHP/oRtbW11NfH5gTIyclhzpw5ANTV1eFwOFB7uhnY+3Fw3mfipBgnqjKwcxvu/36N/rc24a8/ElXEe2Af/Vs24v7v1/Dt3xu1X1MwnrQl1wAwsPdj1J5urP4+3umt4bbs+cw0jo+y2Ww/xEXVPyDn4HeYWP2PbO2ri9ivCJVvn36FcQf/npyD32H5sd/QrbgiykzU53Jb9nwA3umtwervQw5Y94DqR1v2pbgXajSgnXInctZU1J6jBKx72Nlrxa+qrCw4v8m1oTjstLGy5kMa+ntp97r59rFzF/3u8VOYYc6i1tnDzl4rvroaUAIYFl4ZfYxlUzBcthgAX/V+nM8+FVNMvrpqnM89hdLWgqTTY7zmevRzL4kok3bltWiLSlBON+GrqyHg2AnCjzZ3ZcJz8bX+M0EXjIy+9BeY5jdhmn8KXfEjgASqH3/rv8S11+bdjWyagdpfS8Cxk6amJgKBABUVFQl5jx8/TiAQYPny5RHbTSYTc+bMYdu2bQnt582bR35+Pu3t7TQ1NeGrPQwBhbTFV8c+z5oDuP7reQK2Lvwn6nG99CfU/nM3rNLajOvP6wmcPYPS1oLzz+tRWpuj6jFe/QW0F01EaW7EV3uYPa5G/CLAl7LnRnOKAOu6dtIf8ALgDHh4qvPDiDINA+28bNuHSnBW6EB/M+/1RYv8zpxLmJpWwFHPWfa4GpEDXQeDYT0pzBNdCCRjPprCRQAEug5S1dfF0pzClOaJEuGw08ZdtTs4Njgha9Ho+M5F52b6C/VGluYExztVfV34Tx5DV14Rc55IW1xCxpqHSBsUmfdQVVBMHedm/X1HDuN87j9RzrQg6Q2YbriF9LvXoJsW2ZrLWdnoyoM3r//kMVRXFXLG0sTzRKoX1fUZAJrsZegmPIKkn4CkL0Zf8gtkY/ChE3Dui1uFpCtEzlgarM5VRUtLC2VlZUnnibq7uzHHcfsXFxfjdrsT2lsslrDzoaWlBf/xo+hnz4s71gx0dyH8/iHfOxFOR/i72tdHoKvz3Hd7D6o9OspFzs5BPzvowPIfP8qB/mYWpU+JOU8kI6GXNBHb9JI24rt22H4AXYxt+boMFqVPAYJik1VbHXL+/JgnO9oI8ai2OmpcNhZkxJ70PODo5pi7L2l9Na4e7q77KBzVkK7R8Uz5Yv5u/JSIciGeGpcNpaUJ3ZT4oUtydg6Wex4g7fIlwKCYnn8Gpa0V39EanBueRmltRtLpMd14G+Y7/w5JH9sBEOJRWppQ3TVo0hckPB+h9CB83QBRghNKD0KxJ7QPIcSjumuwWq2UlJSkZHehCPFYrVb8zY1RD5eh0M+ei27S1PB3w+VL0OSd63pqJ5aStnDJuf0XX4Z2mAc0hBCPv7mRo56zzDeXxiynlWT+vmA5BYOxc0X6bB4u/EJEmelpBfx94bKweJZnzmJFZuwQrBDPUc9ZtKqjCU12edwTHk2EeFRHEyctDiqGjY0EsNNu5a7a7YzTG3ijchnTTLEng2tcPdx95CPqnMGby6LRsW7WEu4qiO6Ph3hO9jsIWNvQTkzcnZSzc7Hc8wBCCLyf7sZ7YB+qsw/hHQiKSKvFdMMtmG+/K66IgDBPwNqGOnAS2ZS4eyVpMzFMeRZEANk8J7xddVXhbbwX4Q+eqyZzWeLjH+RRB05is9koLBydIOJkCPHYbDYC7W1oS2OMjQahKZxA1g//De+hKiSTmbTLFoPm3JNftmSS8cDDGC6+HKGqpC1cEncCN8QTaG/jlDebWTHGRiFcmzGD96d/l5MDXcw0FjJBFzkJLiHx2ISbuSlzDv2qnwXmiRjk2BP6IZ5T3m60wtOJZPl/88QK8QhPJ50+D2XGyAkyu9/LQ8f2YPW6sXrdrKrdzqsV1zB9mJhqXD3cVbODo/3BGytDq+NP5VeyKs54K8TT6fOg9vaiyU8+ASrnjCPj3gdxpRnx7NyG/3hwsC2nWzCuuBnzzSuRDGkJ6wjxqL29CH8nUlqS8aBsQpu/JmKTv/23+JoehsE+u2ycgn7ikwmrCfEIfydOpzNpt+73v/89TqcTt9vNr3/966j9Ho8nvO+aa65h3rx5MWohzON0OlF7e9AUJI5O10woxjShOO5+OTsn6FlNghCP2ttDp+KkRJ84Gn+iPpeJScrMNycP1QrxdCpOtACS4cK9ZqlgOE+ONvJpbtJoebC4nEeOf0p/QOGww8aq2u28Mvtqys3BJ8dhp41VNds5Ptj1y9TqWT9rCSvz49+kw3nk9NSWAcg54zBcuhDP7u0QCATPwZxO2uVLkIzJl2wM55G0I5vRVz3H8DV9L/xdm/dl9GVPIWkT/17DeUymxMfa3t7OqlWrkh7Pzp07qa+vjyuk4Txykvi70cJwnmzt6CynSYahPLJkzEd4U+t7XyhCPJIxn3y9kR7FG7E/TdbwYPFMfjfjCkya4CCw2mHj7iM7OOVxUt/fy+raHWERZWh1rCtPLCIgzJOvNyJnZaG6HAnLh+Crq6Z/86thEQGoPTZcr/2ZgDV5GH6IR87KQtLlI5TUloSEILzN4c/agq9jmPpyUhEBYR5Jl4/FYknqKJAkiXnz5oX/AoEAW7Zs4eDBgxHbkwWmhngsFgtyVg6q05mw/GghxCNn5ZCvtWBXEp/vaCHEk6+1oJUzyhDOFqS00VmclgjCGYyglTPKmGLOoMnjZJwuunv0jQnTCAiVf2jYi0cNcMhh47aaD3ArCicGRWTR6Hhm5uK43bmhaPIEL/QUcwaawiICnR3IlsSBuL4jh3E+O+ji1hswLrsB1dnHwK7teD/dA34/lnu/haYgfn880BkMwdcUFiGnTUEMNCGlj2BxmiSHP2qyvpCgYCTEQHDyWU6bQm5uLna7Pa5HLhb27dtHTk4OJ06cSP1YAbs9+KDMzc1FM76IQMdZ5IzUAp4h2DVTXU5QFNDpkDMyk/5OAIGO4ENNM76ISYZxtPhs5GpTP9/zRYvPBsAkwzi0cu4sAvajyHmxm+tYSP+G7byIA/bg4kA5dxaV6bnUuuxcmhE7MPabRTOQkfjusb24AwrVjnOcGVodfyyP7ViIhVpX8AeuTM9FW1KGcropKgZuKHx11Tif/Q+UtlaQ5aBj4bYvIwY84PczsG8X3kOfIZ79DzK+8e24YgotDtSWlCGbfKju2qgYuIQQyrnPgdSf7qo7uDhQNlVSWFiI1WqNioFLhOuuu44NGzYwffr0lG0g6K2DoNNBhwel+VRUDFzUsTr7GNizE1/1AZRTJ1B7exBCIMky8ri84JKLhUvQz78MSRt70K80nwJAVzqZcuME6jzt4Ri4oWgYsPKh4yhr85ZGucHjoS/g4Xcd21honsJ1mZFOuTpPcFqk3DgBWZM3H7XzYEqVXihCPJq8+SzIzKPK0Zmw/Nqi6fx6+uVR29eNQERAmGdBZh66KdPxn2yIW9bfcATn+kERaTSYb7oD821fRjIaw65xw2WLQAh81QdwrP9DxDxTRF2DPLop05HTFxBwVaV8zACy+WLSyt8nbdZWNJmpt0ghHjl9ASUlJbS0tIyId9q0aVRWVnLbbbeNyC7EU1JSgm5aedhBEwuqy4l7yyZs3/0GjqeeZGDXhwRsXaDXB1sxnY6A9Syebe9i/9cfYv/JD/DVHopZV4hHN62ci82lHOxvjlnursZ1/MuZt7jz5B855E58TVwBL6/2fMaKY7/l99YP+H7rJmxKf0SZEM/F5lK0msJFKI2bEa7WlCdlXc+e6waaVn6KnDklQekghKuVgHUPck45msJFLNVksNHayOkBV8JJ2fuLZmD1evhp4wEA/lS+hNUjENHpARc7e6xUWHJYmlWIflYmA5/sJNDVGTUp66urxrHu98E4O40W8xdvw7zy7gjvnJwzjow1D+GUNQzs/RhfzUEcT/8a47UrSLvynFs60NWJ/2gt2oll6GdVIpmno9g2IrynU1q8B8ExjvA2IwJONJnLkxsAwnsa1bEzuBQ9Yyll+nSqq6ux2+1xvXdCiKh4OlmWee+99yK2Wa3W8KTrcNjtdpqamhg/fjxlZWXolaKgODqtUZOy/lMncP7p9/iODC7+nDkbw/zL0JdXIueOQzKkIbwDBLo68NUewrt3F77D+7E3HCH97rWYbznnGAl0WvEdOYS2dDL6irksStex2X6AVl9P1KTsV3Ov4FfWrXzsPMbyYye4KWsOV1umM8M4nkyNEa+qcNrXQ427lb/21VI/uBx9nNbCA/lXYdGcuw9afT3scZ2k3DiBRemT0UqmQuTc2ShNW9BVPJToN7ogKE1bUHtPoJ//AyRTIROAOZZcXuto4vsTE8+v/GTSPNJkDTk6A2uLRtbdeK2jiYb+Xh6dPD+YHMVgQls6Ce/ejzHdfEdEWeHpR+3uDM4T3bwS8x1fQdJFLy6Us3Ox3PstkKSgKDvOojoiHRjevR+jtLVgXnl3ODmKbJqDYnsN3YTvp3Tsgb4P8DbeD4Cky0Ob97WkNortNVR3A7qLHkXSTyBDH8yzUFtby5VXRodFAVx77bXYbMm765MnT+b666+Pua+2tpbOzk6WLVsWTo6iLZvCwO4dmG+7K6KscDrw1deiGV9E+sq/w3DZ4nCE/FBoiydimLcA0/Iv0v/GK7i3vYPa0x1RZmD3DpTW06TfdQ9yzjgKgdnGIrbYD/NQwTURZf+hcDmLLVN5sv19PnQcZYv9EFvsh9BIMmmyDkWoeNVz0RZZWhM3Z83lOwXLmGSIHNtusR/mxEAHj4xfQaEuM+j+1pbdgq/6d2js9Z9L4Kpqr8d/ajNybgXaslvC2+8sKOOJ5mqOuOxJA1d/WFo5Yt4jLjsbO04xLyOXO4c4JdIWLqX/rVdRWpsjAlf1FRdjWfttVFs3puu/FFNEIchZ2aR/ZQ1ybh6GOfPRzTgXiKq0NjPwyUfoyqaQtnBpeLs29078Z59AdR9JGLga5kibipRWAoF+ZFN07NhwqO4jKLaNyOnz0ObeGd5eWVnJRx99REdHR8zA1eHxdSNFR0cH1dXVFBUVUVl57ndKW3IN/a/9BeX0qYjAVf2sOeT89FfIWTloSycnrV8zvgjLfd/BuOz6iHqU06cY2LU9mCJgyTnR3JI9n99Zt1HvaY8KXL3UXMprU+5nj6uRrX1H2O6op83Xi08oaCWZLF0ms4wTuDZjJsszypmSFh19U+9p5037QSpNxdwyGLyKGISv/jkxsPv7QghVjC5UMbD7+8K5Pkf46p+L2vt0a714oH7358AqxAP1uwX/Z714urU+ar9769vCsf4PQqijzKyqwrH+D8J6x3Lh3vp21G6/9WnhPfWASPk6B9xCVfpSIRbeUw8I1x6E3/p01N59+/aJzZs3C3WUz1dVVbF582bxyCOPiH379kXt73/3TdH3n7/6XK5z33/+SrTfuEj0v/tm1O7nunaJh1s2CjXJdVaFKuxKv2ga6BZnvHYxoPqTln+4ZaPIPvBt8VzXrvD2sH9VN+Me0KUR6BjZgDgZfNW/xV+/AV3lg4MZhSJxf/EMjBode3o7RpX3Z03VPNNaz/dKK7m/ODq2zrj8RtDrB5eFjx76N/8X7q1vY7rp9iDHMGgL7gfZSMC5J7UKZSOSJvkEsr/tZ/jbn0FX9L3BjEKRWLBgAVqtdsSOh2TYsWMHe/fuZcmSJSxYEB1LaLr+FiSDAV9DdAT1haB/059x/3Uz5ltXBzMKDcM94xaRJuuociVOqyYhkaUxUWrIpUifhWFYEOtw/Ma6jQ1du3mw4GruGbfo3I4ItXl7hepzjeS5kFC73sO/Fq4XisXArn8Qqrsjbkm73yucim+UWIX491OHRfqHL4j7ju4S7V53/LIup1A98fePjFgVrjdeFh133yz61v1OBOw98Yv67UJVnKPDK1ThO/Pvov/TdDHQeJ9Qfe1xS7rdbuH1ekeHVVXFhx9+KH784x+LN954QzgcjrhlA6N9nV99UVhvXyb6/uNJEeixxS3aq7iFKzAwOrRCFb9q3yqKDn1ffPf0q6LDF9lLSJggkoAXNPGDMuNBtdfjP7oh3BKlko5rKLxqAIOcmp9/KI647Dx95mi4JUolHddQCL8fSRd7riIRlNZmPFvfDrdEqaTjioDqhThLyBOauY+gdDwdbolSSccVcdyKglab+AkcCx0dHezduzfcEqWSjmsozvs6nz4VXDE72BKlko5rKLxCSdrixEK9p53nuneFW6JY6bjiC0lV8DdsgIAv9bx2rlaUpi34T20GNTDiBJEQXKH49JkGfGog5bx2pwdcvNbRxMaOUwSEOvIEkQCBAO6tb4OipJzXLtDViXfvxwx88hGo6nkkiASEgr/jaVB9qee1855Gsb2GYtsIIjDiBJEAqqqyd+/e8KK/VPLa2e12amtrqa6uRggx8gSRELzO725GKP6U89oFOq0M7N4RXE6uBkacIBKC99Vz3bvwq4GU89q1+nrYYj/Mm/aDqKgjSxA5FKGUxartCJKxIKVMq8i6UUtZXO20UWgwppRpVSfLo5ayWGk+FVyYl0KmVbSaUUtZrLqrFPi7jAAADFNJREFUkXSFKWVaRdKNWsri9vZ20tPTU8q0qtFoRi1lsdJ0Ejk7N6VMq2i0o5ay+IinjXxtRkqZVnWS5kJSFkdiLIn+WBL9sST6iZGSkMYwhjEkxshHXmMYQ2zEHLAkGz+pqroUWAyUAIVAAOiSJKkJ2C1J0u5RPs7PhVsaa5DG8HkilpCEEHOFEA8At0qSlDAvthCiDdgMPCPL8gVP+n1e3GNCGsOoI14rJIQoEUI8IEnSD8+nXiHEYwRv6q7zsP1cuceENIZRR5xWaJkQ4jVJkiKiU7u6uqitraW3txeXy4UkSZjNZnJycqisrCQnJ2d4Pe3AalmWP071eOJxd/R5+bRFwTYgc6ZPBWDaOJk8k+DyEh2mNN3weuJyjwlpDKOO4UJSVfVrkiS9MHRbTU0NH3zwQfjFZfEwYcIErrvuOmbMiJxKEULcLMvy28mOJRb3p80DPLvfT1VLdJrkEEw6iWum6vnGJTrKxkUGL8fiHhPSGEYdQ4WkquoXJEl6P/Td6XTy8ssv09zcPKI6p06dyl133RWRYEUIsTRRyzScu6df4dFtHnadii+g4dBp4OuXGLn/cgNazbml/8O5x4Q0hlFHSEiqqpYBtZIkmQHa2tp48cUXcThSSz4zHLm5uaxZsybc3RNCnJYkaY4kSVHZRAe5qyVJsgA0dfv4zn97aOkNDC+aEhaV6vj1F00Y9ZqY3HJC6zGM4cLwQEhEDofjgkQEwcSTzz33XDhbkSRJE4EHEnBbAGz9Ab61xX3eIgLY0+znh+95CKgiJveYkMbwuUAIcbEkST8Iff/LX/5yQSIKwWazsWnTpqGbfq6qakSug+HcP3zPTdugM+FC8FGjj2erBmJyX/CE7B0b2/5ZkliSvOQ5CMGuN1YX/wxg2pRL/lkgjcheQuw6duKzn4W/D+mT37HxTOwMGTHw+qriqNRJ06ZekrL9seOfpZ566X8ZBl3NABw+fDjmOqgJEyZw9mz8/IB6vR6TyUTvYHhWCA0NDRw/fpxp08KZoB4AHo7Fve24L6ZTYXqehmNd8Vsok04iM02i3RkpwOeqBrh1toH89HAb9ADwsLayYrEEPFJTu/sXcWsFKisW/yPwZE3t7ohBlSSxUpZ4WBWklKNLlshV4ddAUAgSK0E8rKoiNXtZymWo/TBIEsnXZCeEdIH2YwCQJCmce/nDDz+M2j937lxWr15NY2MjL7zwAn5/5M1eWFjImjVrMJlM/PSnP8Xn80Xs37ZtW1hIg1xhIQ3lfmqPJ4r7hhl6fn5DOlUtfh56y4VXifQTTB2n4Y+3W8hMk7nyaTtu/7n9XkWwbp+Hf1lmjuDWAo8Aj1dWLJZranf/PNZFqaxY/E/Avw1+jRKcKvx1r68qi1rieturZ8fJcqA2sqwyFyL98xqNqDtx4kCUfVlZ5TitVl87rOxcNTDabxUcw2hCVdVwEojm5ma6uqLnMBsbG3E4HEyePJmvf/3rEWLKz89n7dq1mM1mTpw4ESUigNbWVqxWayhxf6aqqgtkWa4ayl3drtBsj251DrUpdPerLCjR8dQt6RFimpSrYf3KDLKNEntP+yNEFML7x3w8cpUJg1Y6x01QGP8C/KyyYvFPhxsNbvvZYJmErdZwvLl6Qvfrd140XlY0V0tC6peEFJ0qJgGammq6T5zYP14I+WoJqV8iub0QzE30l8w+oKpzE/2N5Pj/F2Nx6EO8bK1Op5N169ZFiEmn05Gfn883v/lNzGYzp06d4qWXXopLMqzuxcP+s+90bDd3u1Nl7evOCDEZtBKTcjVsuDMoov1nFP5+iyumvcsrONoRIdDF2pra3QA/r6xYnAY8WlmxmJra3Y9BWESPAv8ar7VKhttfPTtTyIF3VJVvSDKvMEJv+6RJl86UUd8RSN8A8Uqy8q+vKq5OtH/lpsTvhm1sPJDQftrUEWRK/d+LcM60WK1RCDabjXXr1vHNb36TyZMns2bNGvLy8sIiev7556O6fEMxrO7pw/7TaIs/BjplC7D2dSfr77CwoETHutstlOZowiJ68E1nVJdvKBq6FOYVhV0M08Ofamp3P1ZZsRiCYgqllAyJ6LG4NSbAqk2nywME3lFV1ryx+qIdd2xqHZH99EmXlKuyeEdI0poTJz7bMXXqJTHLpeJgiOVYCCEVB8PxE/vHHAspQpKk8II0lyv2Uz0Em83G+vXrWbt2LaWlpQApiShG3YXDuW39iT11Q8UUEkUqIgKwuyP2F0Z47QbF1M+5Ltw/1tTuTvwynjhY+XrLrIAqvS0GRQQgVLE41dXB06dfPEsN8DaDIgLQKPJiNNFPmTEHw//fkCQpwvMqy6MzKxM4j1gDzXkOvy/4iAf0hiWv31ka5SgQqrx0qIgA3lhd0hhVDu2ShoZoR4OqykuHigigoakqyn4Mf3sQQoTfYJ2enjjnRl5eHmvXrsVisdDc3IzT6aS0tJQ1a9agS5IgZVjd1uHc48yJb+/SbA3r77AwziyHHRDzirSsu90SciTERbYpYr81okUaMib6x8FNv6isWGxO1LUzeL33r3ytrYghYw9VVatev7P46YRHMghJBO6fOuWSoshtVB0/8VlK9mP4m8Sx0Ie8vPhLfvLy8rjvvvuwWCzh7lxWVhb33XdfWEwbNmyI6bWLUfexYf+ZlBM/E1Vptobn7gyKKNSdK8qUw928dbdbePBNZ0yvXch+KHdYssMcC08Odun+leCYKcqbF4Ik8RWEqEewD8E+wCNL0nVxzyCqAvEVCaleIO8TyPskJI+QR2A/hr9FhFeWTp06NWaBkGCGisjv99PV1cWf/vSncMv0ta99LW5Xb1jdu4f9Z+HE2C3aeIscJSKvIsJjplDL9PsvpSPHaJgMWon5RRFt0G65smJxaJ4oyrEw+Dkkpn8adEZEQaBseW1V8cbXVhVvVFV1Z8xCCSBr1S0nT1ZtPHmyaqOKGLH9GP62IEnS9tDnkpKSqDVFAEVFRVgsFhobG6McCyExORwOSktLY+beKyoqGvqS6T5ZlquGc8+ZoKUoM1qEMwu0jDPLVLX4oxwLITF1ulTmFelIi9HFu2GGfmjXr0+W5SotwW7cvwH/HMvFPeiAGBgsozLCuaS/NaQyl5QIY3NJySFJUkBV1b2SJC2UZZlly5YNj4+jrq6O3/zmN3HXI3V1dfHLX/4So9EYs2s3NPG/EOKFmNwSPLTIxD/9NdJzuP2kj1tf7ONUHPf4KVuAL27oIzNNiura6TRw74Jzr3cJcWuBJwEShQjV1O7+eWXFYjVUdjgCssHwdxuaDAADGlnHYIRsaNtQuGSDQaMOd0tqDUVFiw0AsvDoxKAHJ7QtEn5DMEfF+SHZPFMyJJtnGkMYDwOfQDAcaM+ePbS1tUUUSLaoz+/3x3SBT5o0afhCv2fica+Yruflg1qOWJWIAvFEFIJXEXS6osdHX5mXRklWxPjoGQDtYOxc0lYmgdDOatXAzgHzYPOrCoTE6wADZm3Uq/G0agAkaWt4g5DOBpTATpMxeGIimIzmdQCTcSDKPqAAEluHbx/D3xZkWd47tFVavXo1zzzzTNIXQydDRkYGq1evDn8XQjwuy/KxoWUiuCX47c3p3PWyg+4k80rJsKBEx0OLIhYWhrn/RyzsW7mpbU6yMolaosmTL05qH6sl+p9w7T4PDFnYNweokiRJD8GFfS+88EI4+eRIkZWVxb333kt+fjCdtBDCBsyRZblteNlB7k8lSTIAHO1Q+PZbrvMW07wiLb+92UK2UYrJ/T9CSGP428Kwpea3S5L0euh7b28vL730UsLlE7FQWlrKV77ylYhk/UKIFbIsx+2dDOfu7lf5/jsuDrUp8Uxi4o5KAz+82oxuSI9uOPeYkMYw6kgl+clnn33Gjh076OnpSVhXXl4ey5cvj3gTIIAQYpUsy5vimCXk3n7Sx/pPBzjakVhQV03W8+AVRqbnRc5HxeIeE9IYRh2x0nGpqnoDsEWSIt+r0tbWxtGjR3E6nXR2diLLMuPGjSMzM5NZs2YNdXEDIITolSRppSRJH6R6PPG4z/YpfHI6QH3nOUEZdRKzCzRcVqIl2xQloLjcY0Iaw6gjXoJIVVXLCeZSOK+3fgshnpAk6RlJkkb82sHPm3tMSGMYdaSQ73shwSXad0iSlOxNcH1CiNcHb+IDF3psnxf3mJDGMOoYyYvHBle0Lia4DKJckqSAEOIY0AbslmV5e8IKLgCjyf1/AfzC3EiJBPQWAAAAAElFTkSuQmCC) no-repeat}.layui-layer-dialog .layui-layer-ico,.layui-layer-setwin a,.layui-layer-btn a{vertical-align:top}.layui-layer-move{cursor:move;opacity:0;width:100%;height:100%;filter:alpha(opacity=0);z-index:2147483647;background-color:#fff;top:0;left:0}.layui-layer-resize{cursor:se-resize;width:15px;height:15px;position:absolute;bottom:0;right:0}.layui-layer{border-radius:2px;animation-duration:.3s;animation-fill-mode:both}@keyframes bounceIn{0%{opacity:0;transform:scale(.5)}to{opacity:1;transform:scale(1)}}.layer-anim{animation-name:bounceIn}@keyframes zoomInDown{0%{opacity:0;animation-timing-function:ease-in-out;transform:scale(.1)translateY(-2000px)}60%{opacity:1;animation-timing-function:ease-out;transform:scale(.475)translateY(60px)}}.layer-anim-01{animation-name:zoomInDown}@keyframes fadeInUpBig{0%{opacity:0;transform:translateY(2000px)}to{opacity:1;transform:translateY(0)}}.layer-anim-02{animation-name:fadeInUpBig}@keyframes zoomInLeft{0%{opacity:0;animation-timing-function:ease-in-out;transform:scale(.1)translate(-2000px)}60%{opacity:1;animation-timing-function:ease-out;transform:scale(.475)translate(48px)}}.layer-anim-03{animation-name:zoomInLeft}@keyframes rollIn{0%{opacity:0;transform:translate(-100%)rotate(-120deg)}to{opacity:1;transform:translate(0)rotate(0)}}.layer-anim-04{animation-name:rollIn}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.layer-anim-05{animation-name:fadeIn}@keyframes shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-10px)}20%,40%,60%,80%{transform:translate(10px)}}.layer-anim-06{animation-name:shake}@keyframes bounceOut{to{opacity:0;transform:scale(.7)}30%{transform:scale(1.05)}0%{transform:scale(1)}}.layer-anim-close{animation-name:bounceOut;animation-duration:.2s}.layui-layer-title{color:#333;text-overflow:ellipsis;white-space:nowrap;background-color:#f8f8f8;border-bottom:1px solid #eee;border-radius:2px 2px 0 0;height:42px;padding:0 80px 0 20px;font-size:14px;line-height:42px;overflow:hidden}.layui-layer-setwin{font-size:0;line-height:initial;top:15px}.layui-layer-setwin a{_overflow:hidden;width:16px;height:16px;margin-left:10px;font-size:12px;position:relative}.layui-layer-setwin .layui-layer-min cite{cursor:pointer;_overflow:hidden;background-color:#2e2d3c;width:14px;height:2px;margin-top:-1px;position:absolute;top:50%;left:0}.layui-layer-setwin .layui-layer-min:hover cite{background-color:#2d93ca}.layui-layer-setwin .layui-layer-max{background-position:-32px -40px}.layui-layer-setwin .layui-layer-max:hover{background-position:-16px -40px}.layui-layer-setwin .layui-layer-maxmin{background-position:-65px -40px}.layui-layer-setwin .layui-layer-maxmin:hover{background-position:-49px -40px}.layui-layer-setwin .layui-layer-close1{cursor:pointer;background-position:0 -40px}.layui-layer-setwin .layui-layer-close1:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{_display:none}.layui-layer-setwin .layui-layer-close2:hover{background-position:-180px -31px}.layui-layer-btn{text-align:right;pointer-events:auto;-webkit-user-select:none;user-select:none;padding:0 10px 12px}.layui-layer-btn a{color:#333;cursor:pointer;background-color:#f1f1f1;border:1px solid #dedede;border-radius:2px;height:28px;margin:0 6px;padding:0 15px;font-weight:400;line-height:28px;text-decoration:none}.layui-layer-btn a:hover{opacity:.9;text-decoration:none}.layui-layer-btn a:active{opacity:.8}.layui-layer-btn .layui-layer-btn0{color:#fff;background-color:#2e8ded;border-color:#4898d5}.layui-layer-btn-l{text-align:left}.layui-layer-btn-c{text-align:center}.layui-layer-dialog{min-width:260px}.layui-layer-dialog .layui-layer-content{word-break:break-all;padding:20px;font-size:14px;line-height:24px;position:relative;overflow:hidden auto}.layui-layer-dialog .layui-layer-content .layui-layer-ico{width:30px;height:30px;position:absolute;top:16px;left:15px}.layui-layer-ico1{background-position:-30px 0}.layui-layer-ico2{background-position:-60px 0}.layui-layer-ico3{background-position:-90px 0}.layui-layer-ico4{background-position:-120px 0}.layui-layer-ico5{background-position:-150px 0}.layui-layer-ico6{background-position:-180px 0}.layui-layer-rim{box-shadow:none;border:6px solid #0000004d;border-radius:5px}.layui-layer-msg{min-width:180px;box-shadow:none;border:1px solid #d3d4d3}.layui-layer-hui{min-width:100px;filter:alpha(opacity=60);color:#fff;background-color:#0009;border:none}.layui-layer-hui .layui-layer-content{text-align:center;padding:12px 25px}.layui-layer-dialog .layui-layer-padding{text-align:left;padding:20px 20px 20px 55px}.layui-layer-page .layui-layer-content{position:relative;overflow:auto}.layui-layer-page .layui-layer-btn,.layui-layer-iframe .layui-layer-btn{padding-top:10px}.layui-layer-nobg{background:0 0}.layui-layer-iframe iframe{width:100%;display:block}.layui-layer-loading{box-shadow:none;background:0 0;border:none;border-radius:100%}.layui-layer-loading .layui-layer-content{background:url(data:image/gif;base64,R0lGODlhPAAYALMPAPPJp/HYxfSwkf50Df5TD/+HAPe5bvqHR/twOviZavyrMu/m3f9EAP9mAP+ZAO7u7iH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wUmlnaHRzPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvcmlnaHRzLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcFJpZ2h0czpNYXJrZWQ9IkZhbHNlIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6QUNDRERBRjMxRTIwNjgxMTg4QzZERjVGQ0I0MDI1NDkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NTlDMEI5MzU5RTY2MTFFMTkxRDY5NkVCMDBGOTBFRUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTlDMEI5MzQ5RTY2MTFFMTkxRDY5NkVCMDBGOTBFRUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpENzU2N0YwMTMyMjA2ODExODhDNkRGNUZDQjQwMjU0OSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBQ0NEREFGMzFFMjA2ODExODhDNkRGNUZDQjQwMjU0OSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PgH//v38+/r5+Pf29fTz8vHw7+7t7Ovq6ejn5uXk4+Lh4N/e3dzb2tnY19bV1NPS0dDPzs3My8rJyMfGxcTDwsHAv769vLu6ubi3trW0s7KxsK+urayrqqmop6alpKOioaCfnp2cm5qZmJeWlZSTkpGQj46NjIuKiYiHhoWEg4KBgH9+fXx7enl4d3Z1dHNycXBvbm1sa2ppaGdmZWRjYmFgX15dXFtaWVhXVlVUU1JRUE9OTUxLSklIR0ZFRENCQUA/Pj08Ozo5ODc2NTQzMjEwLy4tLCsqKSgnJiUkIyIhIB8eHRwbGhkYFxYVFBMSERAPDg0MCwoJCAcGBQQDAgEAACH5BAkFAA8ALAAAAAA8ABgAAATy8MlJq7046827/2AWCEdpCkGodkHSvHCcLGttLUOsw0NqW4EDYog4+CyInbJxwAQMiqjCcMQkGNgsNmFxLZXcisFBLpMNGYF2zRBQAt9vFWCuOwCXAJt9FMSXbhILdnY0FQd7a00SB39Kiw9jhGZoFQSJWgQTjksTCpNmChaYa5ucOxOgdaOkWaanMamqZRaXrZoSObAvA56zDqKHrQyQjbtME5KqlW/DRwbHDcwBv1UTV5hhEnDHVcqEzF2J2te75BLflBsCCFoIgRU4pwOGFQCfZQp4PxUBSX8IrPELscDLkhkDB7bQxQthwocQI0rMEAEAIfkECQUADwAsAAAAADwAGAAABOjwyUmrvTjrzbv/ILcAiWCUQKh+y9G88DsIa40JcQ4ji30JCIZQeAhcAgOdMvEYKZ5PQA8UHFoZtEpSuVQ4vmCHwuhJXK+EqcTA5YbfYrUmcD4jKNt2rAB/GzoHdWdTAXo6fXByGASCV1k4hjADiG8pG41XTA9skS98lGB/l5hDmgmdnqChHIykWBKQnZOqDpYaVaRkAKgvtA6KFwCudxO8DZ+UCh64grYPp7yqwBgLzFYEWRNIvAlecGMhAq1DCGQVu7JNBn7THQDvAObBeVwJ7T4gLW2i+P0PAQkOCBQoxZ/BgwgTYogAACH5BAkFAA8ALAAAAAA8ABgAAATV8MlJq7046827/2AojmMgHE2aIslCckAcb8Kg3umQvFhCMEAgYXcR4HCFpEJhCPAkiKAUiLAEbMdGwcHtcg28w3R8qKCyA6/aASABxvC2JJBNrdcuURQ+rUqMWVt3XmAhC3xweWdHg2oKIm+IU3KLOI1qkJKTEpU3l14iAZpSTg+dKp9cjyKjQRMGdYKXhSFio2VzdQ2ppSEBP5IEvQ9YR7J3tCICmgIVALrHhE+/cMIXCboDxwpy0z5BQ8POxUcD3U88CwnkKQni6E8yMXnw9fb3+BURACH5BAkFAA8ALAAAAAA8ABgAAATe8MlJq7046827/2AojqQUCEeaJkC5CUgcJ0G2JE2u60jrVgICY0gcIhaXQ25QaDp1vt8jUKwaLbhGwcHtcgeNQe23EFqrAkogt/W6cwlp4mwlICW4gXvvyI1LZnRFaRJgfHtghCRUglUIJjmHbgUNBy4AjY4SAGGSXpSWJZiZRI8PnHqeXKAujKQMpmsNqquVP4GZioa0iT8Hrwx/Sqmefj8BuHRxE5xanmChPwKZRxVKznxgDX8/AAh00RQL18S1YYpSDzffpVEXAjvxB9zpiwnaOQfo9fz9/v8ApUQAACH5BAkFAA8ALAAAAAA8ABgAAATO8MlJq7046827/2AojmS1AIkhJEBQasFBMDRDHC62JE3v97iXJVEr1hKThUHBdBQGv99gIZwIjFiG4AFweL/eQtSHqD4Cs2yR0AW7xeOGoXpQYwvuPHQ8FabtNA15g3ENWyUBgEUDg3mFBy8AijV4jWB7UZAlkpMMlZZemD+aJImdjKBej0KdDIKpDoWHJXWdn42iPzmIrQagcGOkL0SKSG15wFF9ZgJ/WLMBvpeFCLtmMVhBOjxxB1RmJgDiAN8bAQkH6Qcs4O3u7/Dx4BEAIfkECQUADwAsAAAAADwAGAAABMrwyUmrvTjrzbv/YCiOV5AgKCosZIsFCCPPc5KZQ6M3QxK4lgWBRuMVFEgDS5LYOXc24CRGlBUc2CwW8BA8vw2BtFuVDbRoByAHdg6WrmG1kU63v9EWoMy41rVsdzoDQAllBH9oBYJOPy2GVYiJWYuMOlyPh5OUlpcuApqbDpWWjiQBfH6TgYxSVER0m50NeS2gZap1BrOmLpBVuVpcTYy1QLdzuQamAqxuYmMTMGUJcBYmeL3REgAJ3gkC2hgLAOUA1tvp6uvs7R8RACH5BAkFAA8ALAAAAAA8ABgAAATs8MlJq7046827/2AojpmQICgqBGSLCQgjz3OyZEFy7LvgXoDZoEAsDBoyxGWRaDifzgHgNwkQGA2HdqstyBKWA3TsZFEPDAJ37RjIzBIBmTy4uQKyAnuNPEwWR3NjPi4CWHtrXgQTcoJjAz8xA4hrbxJijmNwIzF6lFtXUw+YmU+iJJ2foAyipKUNp5wMk6oOV2aupZsihlmqioyvUT94DJ6USEoSAcINYJGHlF6sFE2lA7sjxQ3HXNN+FAu5ZIRUAlcEtF1IDAh2FQaC2FQUATE0NOVACYENAyv0LMCgQeBAtoAIEypcyLDhhAgAIfkECQUADwAsAAAAADwAGAAABODwyUmrvTjrzbv/YCiOWiAgTJoiSUC+V0KodEokZWIIugtPAYNCUSgMZjWV4BI4NJ7QxsH3Mjiu2OsgqaJKFoOoeLB4AbJoR4PLQFQQ4rh7tEin2QyqIM5fiqx2WVtcfg9hfGMjCoFZBWxzC4h8Xh6MaI8SAJJxACKWWZgPmptRnSGLn45ccwGkUWUhgJaDSTgSh6QDIwGfDkhJeq4Ntn+zbAQUYLmwI7Joa2ymQLhxA5QiAKhXBdBcBxcLcHEHzD+Zv0kEhRcACQfvCdLmFAEytdfzZgD7AOX5/wADCrwQAQAh+QQJBQAPACwAAAAAPAAYAAAE6fDJSau9OOvNu/8gFiQkKSxh+gkE474uEqj0tSBw/gq1twCKYBCAOuiOhJllkRg0no0BDxRQOK5YhyJx7BIsAKj4ifgsrNlsodtNUBbOsdjgMaTvA7buOznI5UoaC3eELXowSgF/cm4bAIR3DYcwUwKLYwMcdpBZkpMujQaXY5qcnZ+gEgmjYhyPpleen42WrFEcg7AOqC4AEoq2Bx1onGu8FAi2vriwvAzCE2Gj0B1VhApGqEkVAnFyByhmm1gGKDifUxULfmN0PerZbATLGD8A9+8ZLF0y+f4PAhAIFJgg0L+DCBMqrBABACH5BAkFAA8ALAAAAAA8ABgAAATz8MlJq7046827/2AWCEhpCkGodkHCvHCcpGtdBUSswwRt3waFUGHwVRC7JAOBaR2eh9nG4KhaqwaLS5lMaBvgMNiLAVzPDgAlwOUaBeJ4Q3BZoNGLiaCtpEsWcnJGElR3V1kSSHw7TBIJgXFkFAqGVwoTi0oTA5BiAxaVZ5iZOxOdcaChVqOkMaanYRaUqpcSOa0vBJuwDZ8VhaGID4q4jQ+PsJITAaoOPlu4kgG8g4TBa7gvRsiQyr+GwhMHuAcWBpDhFwCzVQpqFgu3iwR5FgAHYgfvP2vEXAj7+K1YMI7LgXoCf7SQx4CAlIQQI0qcmCECACH5BAkFAA8ALAAAAAA8ABgAAATe8MlJq7046827/2AXACQZnuCSEEzrEkmAzpjAunhLCDRmKI5g0LC4BHJIl+wRSByeh1hKSBUWKYtbMkdQNb7gb+IDrFIVlcR2iwi7GzwOwGwGTI7r5Pu91NDpEwJ5SAR7bmMaC39mVweDOYZuAxsBi1VLCI84kW6UllSYmi6cYZ6fQaGiDKRfkxunQRNqqoWkiBoGpwaBqi2sfRmKn1cPWb21hreUZWYKwA+zogkGhrsguVVEF5maCBIAB2EHdicLAecBxBYL3HkI6j0zgmvK8T1NWgwwz/b9/v8AMUQAACH5BAkFAA8ALAAAAAA8ABgAAATY8MlJq7046827/+AXACQQhCi4CATjvoSwpFww2nMWtG/vEieaZQFwGI8ORbCy4Pl6hMZhmlimFMiswypBPKGNsDicoBm02pxE8IWN3w0BaoHWGijOLxzO5RTrWRMBbT97b2UgWIBIQQmEDIZvAyGKi0aNj5FvlJZHmISaYyFnnVtrmaENkyCknRMAj1GhiB90nXcTeU+pfRytgGoPjoSyhrQqlWgATLo+xW+4NH9ZCsGCzT5vB8tCEkQG4Aa9EwtehAjW3TQLCdgJ6erdAgn0CXLx+Pn6+xwRACH5BAkFAA8ALAAAAAA8ABgAAATM8MlJq7046827/2AojuSzCAeiqsJSaoChzIoBaALB7DyfvJaAwkEsEhWBS6LHIDQaTt0PKFkMjViFiwLoOZ/gJ0FAfVyx2Ypu9w2HB9QAeu5ISgQ9t75BfhnoaAYTCDxte08HQIBzE2sMh25wL4toE3mQYYqURpY8mJmTm0WdO59gQH+ighKEbKaJLwCiDjd3l5h9L2eAChQBjoZ7di9ylMMSS4WHBFNUVnRaSkx6DM1lDwC7CgBbFwCOTAy51yQLCeDM3eTr7O3u7yMRACH5BAkFAA8ALAAAAAA8ABgAAATO8MlJq7046827/2AojiQVCEmaCEGpLYbizI5iLFlwMHzPHy1XJSCjGRVBU6JBYDZ8PEJSuCgaj7jJssHtMqGIrKt6LdeyAq/660sIHwaz2fBYrNdQxnRkldMUD1t3XQRQAi4BfmYBA4NqYIiKZQGOjz4IkZJGlJVdkCULmkYLjZ1Pl0KiNIGmhT6HLnGidJyVeXsioaJZgneuPZhviZJicIO/UcVjfVgWAAeWl7hjskY3GQsIeTxhbxcLAeEByhjPCOcIBwDe7O3u7/DxEhEAIfkECQUADwAsAAAAADwAGAAABMHwyUmrvTjrzbv/YCiOWGACgbcALEpygeHMtGNoAsLsPCG8GEBt6FAAEofkIRE48J68A7ASIBILjay2QYB6f9PHQmElDrbarveZmsrKRLR2/USE4dazXE1ntElVeENYcg19O2CAgoOFhocJQIGLM4RyhwyQL5KTlWiXiSSTNHpofHR/JG+TjZcEYQuinWmfYQ9CgrJZpmtStQ+bRAYAB1sHAAKHoLUxVjcZOV4+vhYxBtYACx0CCdwJytPg4eLj5B8RACH5BAkFAA8ALAAAAAA8ABgAAATI8MlJq7046827/2AojtgCGKgBLGSbLYojz7LClgnC7AyS3C7KgkacJQKWAIHHZBCQQQmsSG0khMsmkwB0GajUQkMg1WmbiO5oCKYOGsjE+Xz1tt3WR3a+DX7vRGIDAXxnUCQxgDRiDQCFWgAuiYoyjI6PTJEtk5SChJg8hyMAlDNvV3uPBEFspQ1wD3KgdZKlYnULqXNcUa2ADQYUn3xPURIBnFQHmkJmWmnGE1NUNi+yTD/RFQEGCt4KBqIvAOQr2ufo6errIhEAIfkECQUADwAsAAAAADwAGAAABLTwyUmrvTjrzbv/YCiO2QIYSqoYxkK+GODMdG1owoHsyCHAF0NtSLtZAgiGcqlEBIATGXEKqCwIzCyD4IIqplNFJanNIqBSMLEqAZTL7NdXTRRLDm/tAUgHT7B5TAR8fUQTgVqEhTWHiEyKizN/jkqDMHORdg9kjmcwaYtxApQMPzALkTNdEpx5nkBCi0YTAYgEcbCFsxQLrUwIq1APAXS4Fjm/AsHCDwsoQy3M0tPU1dbXGBEAIfkECQUADwAsAAAAADwAGAAABNbwyUmrvTjrzbv/4BWMZGiCC+CsrKMYyyljQWuvSqAFQA/os0kgcSjejoqYRYBgOJ8EQDDRqDYKR6Ql8ew+EzKBtTHIZqUTgHfNQKPGDXNWQWmyuwgTdSzPAgN3a0AfA2NYfTcGEgKBXgIhcIeILYoPXI1fkIaTNpWXmAxgIIVWZZwsaIygDI8ge1Wmpw5/qwyDHgFwsisUBKAEJ69XspUSapitJgabk0kVB40HQQAHsJy3ab5eUUEWCwpyzhkCCeUJbt0VCwZZMOnvxgbyBujw9vf4+RcRACH5BAUFAA8ALAAAAAA8ABgAAATi8MlJq7046827/2AWjGRogovirKyjAMspY0Zrr0owe0Fy/IeE7gG4GRWxS4LAaDIIiaQn0ahaq0KjVmEJMJ1gwpAjuJob2jSgggC7GYjO4nwdpLcUwfst4FDpVQV3WlJfe04EHAOAVYNaaw8Bh29jGIyNjjcGEgCTbpAZl2iZNptEnmCgGIuMpKUSkqhNlUqXgq4roIaTiRsBtrgrUgmyCR1/dHa4XBMLu28EUhsGgAYqrrReh2IgAAdXB2sLrqYWS24H0juR13flFwsA8jDr8DVq9fkB9ywKBur5AgocSPBCBAA7) no-repeat;width:60px;height:24px}.layui-layer-loading .layui-layer-loading1{background:url(data:image/gif;base64,R0lGODlhJQAlAJECAL3L2AYrTv///wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgACACwAAAAAJQAlAAACi5SPqcvtDyGYIFpF690i8xUw3qJBwUlSadmcLqYmGQu6KDIeM13beGzYWWy3DlB4IYaMk+Dso2RWkFCfLPcRvFbZxFLUDTt21BW56TyjRep1e20+i+eYMR145W2eefj+6VFmgTQi+ECVY8iGxcg35phGo/iDFwlTyXWphwlm1imGRdcnuqhHeop6UAAAIfkEBQoAAgAsEAACAAQACwAAAgWMj6nLXAAh+QQFCgACACwVAAUACgALAAACFZQvgRi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwXABEADAADAAACBYyPqcsFACH5BAUKAAIALBUAFQAKAAsAAAITlGKZwWoMHYxqtmplxlNT7ixGAQAh+QQFCgACACwQABgABAALAAACBYyPqctcACH5BAUKAAIALAUAFQAKAAsAAAIVlC+BGL3Z3IlxUmUuhtR2LzHhsiEFACH5BAUKAAIALAEAEQAMAAMAAAIFjI+pywUAIfkEBQoAAgAsBQAFAAoACwAAAhOUYJnAagwdjGq2amXGU1PuLEYBACH5BAUKAAIALBAAAgAEAAsAAAIFhI+py1wAIfkEBQoAAgAsFQAFAAoACwAAAhWUL4AIvdnciXFSZS6G1HYvMeGyIQUAIfkEBQoAAgAsFwARAAwAAwAAAgWEj6nLBQAh+QQFCgACACwVABUACgALAAACE5RgmcBqDB2MarZqZcZTU+4sRgEAIfkEBQoAAgAsEAAYAAQACwAAAgWEj6nLXAAh+QQFCgACACwFABUACgALAAACFZQvgAi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwBABEADAADAAACBYSPqcsFADs=) no-repeat;width:37px;height:37px}.layui-layer-loading .layui-layer-loading2,.layui-layer-ico16{background:url(data:image/gif;base64,R0lGODlhIAAgALMAAP///7Ozs/v7+9bW1uHh4fLy8rq6uoGBgTQ0NAEBARsbG8TExJeXl/39/VRUVAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFBQAAACwAAAAAIAAgAAAE5xDISSlLrOrNp0pKNRCdFhxVolJLEJQUoSgOpSYT4RowNSsvyW1icA16k8MMMRkCBjskBTFDAZyuAEkqCfxIQ2hgQRFvAQEEIjNxVDW6XNE4YagRjuBCwe60smQUDnd4Rz1ZAQZnFAGDd0hihh12CEE9kjAEVlycXIg7BAsMB6SlnJ87paqbSKiKoqusnbMdmDC2tXQlkUhziYtyWTxIfy6BE8WJt5YEvpJivxNaGmLHT0VnOgGYf0dZXS7APdpB309RnHOG5gDqXGLDaC457D1zZ/V/nmOM82XiHQjYKhKP1oZmADdEAAAh+QQFBQAAACwAAAAAGAAXAAAEchDISasKNeuJFKoHs4mUYlJIkmjIV54Soypsa0wmLSnqoTEtBw52mG0AjhYpBxioEqRNy8V0qFzNw+GGwlJki4lBqx1IBgjMkRIghwjrzcDti2/Gh7D9qN774wQGAYOEfwCChIV/gYmDho+QkZKTR3p7EQAh+QQFBQAAACwBAAAAHQAOAAAEchDISWdANesNHHJZwE2DUSEo5SjKKB2HOKGYFLD1CB/DnEoIlkti2PlyuKGEATMBaAACSyGbEDYD4zN1YIEmh0SCQQgYehNmTNNaKsQJXmBuuEYPi9ECAU/UFnNzeUp9VBQEBoFOLmFxWHNoQw6RWEocEQAh+QQFBQAAACwHAAAAGQARAAAEaRDICdZZNOvNDsvfBhBDdpwZgohBgE3nQaki0AYEjEqOGmqDlkEnAzBUjhrA0CoBYhLVSkm4SaAAWkahCFAWTU0A4RxzFWJnzXFWJJWb9pTihRu5dvghl+/7NQmBggo/fYKHCX8AiAmEEQAh+QQFBQAAACwOAAAAEgAYAAAEZXCwAaq9ODAMDOUAI17McYDhWA3mCYpb1RooXBktmsbt944BU6zCQCBQiwPB4jAihiCK86irTB20qvWp7Xq/FYV4TNWNz4oqWoEIgL0HX/eQSLi69boCikTkE2VVDAp5d1p0CW4RACH5BAUFAAAALA4AAAASAB4AAASAkBgCqr3YBIMXvkEIMsxXhcFFpiZqBaTXisBClibgAnd+ijYGq2I4HAamwXBgNHJ8BEbzgPNNjz7LwpnFDLvgLGJMdnw/5DRCrHaE3xbKm6FQwOt1xDnpwCvcJgcJMgEIeCYOCQlrF4YmBIoJVV2CCXZvCooHbwGRcAiKcmFUJhEAIfkEBQUAAAAsDwABABEAHwAABHsQyAkGoRivELInnOFlBjeM1BCiFBdcbMUtKQdTN0CUJru5NJQrYMh5VIFTTKJcOj2HqJQRhEqvqGuU+uw6AwgEwxkOO55lxIihoDjKY8pBoThPxmpAYi+hKzoeewkTdHkZghMIdCOIhIuHfBMOjxiNLR4KCW1ODAlxSxEAIfkEBQUAAAAsCAAOABgAEgAABGwQyEkrCDgbYvvMoOF5ILaNaIoGKroch9hacD3MFMHUBzMHiBtgwJMBFolDB4GoGGBCACKRcAAUWAmzOWJQExysQsJgWj0KqvKalTiYPhp1LBFTtp10Is6mT5gdVFx1bRN8FTsVCAqDOB9+KhEAIfkEBQUAAAAsAgASAB0ADgAABHgQyEmrBePS4bQdQZBdR5IcHmWEgUFQgWKaKbWwwSIhc4LonsXhBSCsQoOSScGQDJiWwOHQnAxWBIYJNXEoFCiEWDI9jCzESey7GwMM5doEwW4jJoypQQ743u1WcTV0CgFzbhJ5XClfHYd/EwZnHoYVDgiOfHKQNREAIfkEBQUAAAAsAAAPABkAEQAABGeQqUQruDjrW3vaYCZ5X2ie6EkcKaooTAsi7ytnTq046BBsNcTvItz4AotMwKZBIC6H6CVAJaCcT0CUBTgaTg5nTCu9GKiDEMPJg5YBBOpwlnVzLwtqyKnZagZWahoMB2M3GgsHSRsRACH5BAUFAAAALAEACAARABgAAARcMKR0gL34npkUyyCAcAmyhBijkGi2UW02VHFt33iu7yiDIDaD4/erEYGDlu/nuBAOJ9Dvc2EcDgFAYIuaXS3bbOh6MIC5IAP5Eh5fk2exC4tpgwZyiyFgvhEMBBEAIfkEBQUAAAAsAAACAA4AHQAABHMQyAnYoViSlFDGXBJ808Ep5KRwV8qEg+pRCOeoioKMwJK0Ekcu54h9AoghKgXIMZgAApQZcCCu2Ax2O6NUud2pmJcyHA4L0uDM/ljYDCnGfGakJQE5YH0wUBYBAUYfBIFkHwaBgxkDgX5lgXpHAXcpBIsRADs=) no-repeat;width:32px;height:32px}.layui-layer-tips{box-shadow:none;background:0 0;border:none}.layui-layer-tips .layui-layer-content{_float:left;color:#fff;background-color:#000;border-radius:2px;min-width:12px;padding:5px 10px;font-size:12px;line-height:22px;position:relative;box-shadow:1px 1px 3px #0003}.layui-layer-tips .layui-layer-close{top:-1px;right:-2px}.layui-layer-tips i.layui-layer-TipsT,.layui-layer-tips i.layui-layer-TipsB{border-right-style:solid;border-right-color:#000;left:5px}.layui-layer-tips i.layui-layer-TipsT{bottom:-8px}.layui-layer-tips i.layui-layer-TipsB{top:-8px}.layui-layer-tips i.layui-layer-TipsR,.layui-layer-tips i.layui-layer-TipsL{border-bottom-style:solid;border-bottom-color:#000;top:1px}.layui-layer-tips i.layui-layer-TipsR{left:-8px}.layui-layer-tips i.layui-layer-TipsL{right:-8px}.layui-layer-lan[type=dialog]{min-width:280px}.layui-layer-lan .layui-layer-title{color:#fff;background:#4476a7;border:none}.layui-layer-lan .layui-layer-btn{text-align:right;border-top:1px solid #e9e7e7;padding:10px}.layui-layer-lan .layui-layer-btn a{background:#bbb5b5;border:none}.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#c9c5c5}.layui-layer-molv .layui-layer-title{color:#fff;background:#009f95;border:none}.layui-layer-molv .layui-layer-btn a{background:#009f95}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92b8b1}.layui-layer-iconext{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAABkCAYAAAAv8xodAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK6wAACusBgosNWgAAABZ0RVh0Q3JlYXRpb24gVGltZQAwNS8xMS8xNNdPc0oAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAWb0lEQVR4nO2de2wU172Av5l92t4Hti/YQHmVmFcSE7+WR0h0uRRVVC2pKldpCFJQEJAiFwg4diikgLEghEhpVLVQNblBSFEUVYoi+hc0FQoE87B52JQAiQnBJDY2wfix633O7P1jdwbbxe9d7yx3PgnJc87iM2M+js+cx+8nhMNhdHQeFcRE34COTizRhdZ5pNCF1nmk0IXWeaQwPqxQEIRYtpEKOABL9NoLtAKhWDbSDRF4EsgAbEBHtL3LAIN9CV6+fHlSvS0fOXLkof9oj8pzDJZ499A2YCxgWbJkiSUnJ8cApADZgCEO7ZmAImAyYFuxYsV4Iv+ZpgIFcWhPR2PEU2gbkAlQU1Mz67PPPvvvq1ev/s/f/va3LCIyp8e4PROQD4wrLi7Oam9vP/Dhhx/+9f79+3/Kz8+3AxPi0KaOxoiX0KrM169ff6KgoGAKgMFgEF944YWZ0c9Y+vrLw8BEpAceV1xcnHX48OE3HQ7HRIAxY8ZM2bdv39Lo5zJi2KaOBomH0D1knjFjxsTulX6/Pxj9Uo5Re4rMY1esWDH+8OHDb6akpGR2/4Db7fZEv4zXuF1HI8Ra6H5lDgQC0ttvv/1l9NIfg/Z6yPzee+/t6S1zY2PjpdWrV/8retkagzZ1NEwshR5Q5j179pzfu3dvOxBg5HINKHNTU1Ody+WqbG1tDQENQOcI29TROA+dthsGGYAd+pd5165d94nIfHeE7Q1K5qKioorvv/8+ANwGakfYZlwIh8MEg0F1OtFoNGIwxGMCKL4Eg0G6urqQJAlRFElNTcVsNo/6fcSih84A7BaLRRiCzCMZy5qAQoYm86URtBc3FJnNZjMzZswgKyuLQCCAJEmJvrUhEQwGcbvdZGdn88ILL5CTk0NnZ2dCnmOkPbQqc11d3eMPk3n37t01lZWVbcRW5v966aWXJh44cKAyWWWWZZlgMIjD4aCoqIj09HRkWeb48eO0tbUlTS+tyDxz5kz2799Peno6LS0trFq1Cr/fT2pq6qjez0iE1mUeJorM6enpFBUVkZaWRigUIhgMEgwGB/4GGiEQCOB2u5kzZw779u0jPT0yze/xeJAkKdYrzoNiuELrMg8TSZIIBoNkZWVRWFiI2WwmHA7j8/k4d+4cnZ2dCRl7DhWlZ37iiSd46623cDgcANy5c4c33ngDj8eD0+kc9fsajtC6zMMkGAwiSRKTJk0iLy9PHVZ4PB7Onj1LR0cHZrMZUdT2njGlZ87Ly2P//v1YrVYAmpqaKC0tpaGhAbvdnpBh01CFHm2ZzURmMx4ZmadNm0Zubi6iKCIIAm1tbZw5cwav14vJZNK8zH6/H7fbTWFhIXv27Okh85YtW7h9+zY2mw2TyZSQ+xuK0KrMly9ffiInJ2dC98pEyNzY2HjJ5XJVJoPMoVCI2bNnM2vWLCCyo/Hu3bucPXuWUCiE2WxOyJhzKCgyL1y4kMrKSiyWyO6Fb7/9li1bttDS0pJQmWHwQidU5oMHD+6xWq09NhYlg8zKtJwsy+Tm5vLYY48RDocRRZGmpiaqq6uRZRmTyaR5mX0+Hx6Ph2eeeYbdu3er0jY0NFBaWqoJmWFwQg8kc2j37t3ndZl70l3mvLw8pk6dSjgcxmAw8O2333LhwgVEUUyKF0C/36/KXFFRoUpbX19PaWkp9+7dw263YzTGap1u+Ax0B7rMwyAcDhMIBDAajbhcLsaPH48sy4iiyNdff01tbS1GozHhvdlgUHrmpUuXsmPHDvU3ybVr1ygtLaW9vV0zMkP/QusyDwNljtlsNlNUVMS4ceNUma9evcrVq1eTSma3282yZcvYvn27KvP169cpKyujo6NDUzJD30Kn8UDmJ3NycsZ3r4yDzABzeURkTklJweVykZGRQTgcRhAEamtr+eabbzCZTJoSoC+UnvnnP/85W7duVWWuq6ujtLQUn8+XsKm5/ujrJ2sDuHDhwpxRktkJZC9evDg92WV2OBy4XC5sNhuyLCPLMpcuXaKhoQGj0ZgUMnu9XtxuN7/61a947bXX1PLa2lrKy8s1KzP0LbR18uTJ4uzZs3vMM0uSJMdBZohuOy0rK1vUW+bm5uZ/a11mgFAohM1mY8GCBaSmpiJJEj6fj9raWpqbmzGZTJoUoDfBYBCPx/MfMl+8eJGtW7fS1dWlWZmhn912zc3N4WCvjQUGg0H85S9/mR29NEf/xAIvQGNj43/skU5PT//xypUrp0YvHUQO2WoOWZZxOp04HA4kScJgMNDS0sKdO3cQRVGzAvQmGAwyZswY1q5dq5bduHGD9evX4/F4cDgcmn6WvoTu8vv94YMHD16WJKnHUamCgoIpNTU1s6KXY4mEKRgprQAlJSWn6+vrP+9eYTabUysqKirKy8tnEBmaFKFBqUVR5M6dO9y+fRuj0YgkSUyePJk5c+aoG4+SAYPBgMfj4cqVK2rZhAkT+NnPfoYsywQCgQTe3cD0JXQrENq4ceMPf/7zny+OgtR+4JbX65Vzc3PfSUapTSYTsixz7tw5Ghoa1F5s5syZ5Ofnq2NsraM8x86dO6mpqQEgJSWF7du3s3z5ctxuN16vN8F32Td9CS0BzYyu1HUksdSCIKiLJDU1Ndy4cQODwUA4HGbatGkUFhYC9DidokVEUcThcODz+Xj99deprq4GIs9XXl5OcXExbrebrq6uBN/pw+lvJ0wIXeoho2wwunTpEteuXUMURWRZZtKkSbhcLkRR1LzUBoMBu91OIBDg97//PefOnVPrNm/ezPPPP4/H49Gk1ANt7dKlHgbKXPOVK1e4fPkygiAgyzLZ2dksXLgQq9WaFFI7HA78fj9btmzhxIkTat2mTZt48cUXNSn1YPYq6lIPA5PJhMlk4uuvv+bChQuqvJmZmcyfP5/U1FQCgQCyHKvwJLFHGX4IgsCOHTt6SF1SUsKqVavweDx4PJ5+vsvoMtjNt7rUw0BZ4r516xbV1dWEQiHC4TBOp5OFCxfidDrVDUxaRZFalmXeeOMNjh8/rtatW7eOl19+ma6uLs1IPZTd5LrUw8BgMGAymWhsbOTs2bP4/ZH4OmlpaSxcuJCxY8eqm/+1iiiK2O12ALZv386xY8fUujVr1rBu3To8Hg9utztRt6gy1OMRutTDwGAwYDabaWlpoaqqSh13WiwWXC4X2dnZSSO10Whk9+7dHD16VK1btWoVJSUlmuiph3PeR5d6GCh7n9vb2zl16hSdnZ0IgoDRaKSoqIgpU6aoJ1u0ijL8EEWRHTt2cOTIEbVu5cqVbNiwIeE99XAPsOlSDwNRFDGZTHg8Hqqqqrh37x6CIGAwGMjPz2f69OlIkqRpqQVBwG63Y7Va2bt3L59++qlat2LFCkpLS+nq6kqY1CM5kalLPQyUntrn81FVVUVzc7N6MDY3N1cNOKNllOGHxWJh3759fPLJJ2pdcXExr776Kj6fLyHL5CM9YqxLPQwEQVCXmM+cOUNDQwMQ2bap5d65O0pPrUj90UcfqXW/+MUvyMjISMizxOLMvC71MFCkFgSB6upqTp06xcmTJ+no6EiKPdPwQOqUlBTeffddDh48yHfffcfHH39MW1tbQk7lxCoIxHCkHmkE/6FKnTvC9uKCsgBz7949fD5fUgSa6Y4gCDgcDiwWC4cOHWLdunUcOHAAs9mc1ELDIKU+fvz4tOilPQZtDkrq4uLiLGAcGk1JocxVJ0Ogmb5wOp2MGzcOg8FAdnY2NpstIfcR65/egFIXFRVNjn4ZqxwrA0q9fv36Z6KXmhRaJ3bEozvoV+qOjg5l5j2Wm4P7lbq+vv776JeJX8rSiSvxevtQpM7auHHjD62trTWrV6+e5vP5gqWlpV9HPxOLHCvdqQPwer1TcnNz3zly5MjN3Nxc16VLl86sXbv2dLQ9PcfKI47wsC2MMQxLZSTyAtj77KEXaIlVI73IBaY8pPwk0KZnktU2I80kG+/5oRDQRORwq5VIKjcf8f3VX0fkdHg2kTFza/Qe2uLYpo5GiHcPrTm0vKleZ+T010ObiaQStkavfUR6uViPfbujJJ13EOnFlaTzo74W/Kj8qn5UnmOw9DXLYQbGA9a8vDxTXl6eiYjY2TwQPNYUEEky74gmnbcRSUJfRCSKv47OgPQl9BiAo0ePTjl//vzi8+fPL/7nP/+pLIhkEXup04EJ+fn59vv37//pww8//Gt7e/uBbgsi+ehS6wyCvoROcTqdwpIlS2YIUX7yk5/M+Pzzz6dH62MtdQbAvn37lo4ZM2YKgMPhmHj48OE3dal1hkKfCys+nw9Jknpsl3r22Wcfi5PUIeiRZB6AlJSUzF5SF6BLrdMP/YYC++CDD/4d7jUt8Oyzzz526tSpx6KXsZK6FWD16tX/amxs7BGMUZE6Oq4eiy61Tj/0FwpMeuWVV+6+//77tb2lXrhw4fQYS90JNLS2toZcLldlU1NTXffKlJSUzPfee2+PLrXOQAwUCkxas2ZN8/vvv1/be5NRHKSuBW5///33gaKioopklFqSJPx+P36/n0AgkLRz3oFAgLa2NlpbW2lvb0+KmHwK/W1OCtJN6g8++KBuEFKPdBP9JZJUakmSCAQCZGVlkZOTg8lk0nx0pIchSRJut5ucnBx+85vfkJWVhdvtThqpB9ptFwTuMHipxzH6UheiAaklSSIzM5Onn36auXPnsmjRIjU+nNbPCHbH7/fjdDrZu3cvJSUlHDhwgJycnKSRerChwAaUuqqqKid6OWpSv/TSSxOB/0IjUgeDQfx+P6FQCKfTyfz580lPT9d8dKTuCIKAJElq7JDMzEz279/PrFmz6OzsTNr40L0ZUOoFCxb8eLSlPnDgQKVWpDYajbjdbk6fPo3f7yccDpOamsqCBQsYN24cgUBA04FkFMxmM263mz/84Q+0tEQ2RGZmZvL222/z+OOPa76nHmooMF3qPlBibrS2tlJVVaVGEDKbzcybN48f/ehHBINBTcsAD0Lp3rx5k82bN9Pc3AxEjli9++67PPXUU5ruqYcTCiyhUj9snlprUnd0dPDFF1/Q0dGhBpIpKChg6tSpSJKkealNJhM2m41bt26xefNm7ty5A4DVauXNN98kPz8ft9utxunTEsMNBZYwqV0uV+UgpU5IzmFFap/PxxdffMEPP/yAIAgIgsBTTz3FzJkzkyLniiJ1Q0MDJSUl3Lp1CwCbzcZbb73FvHnz8Hg8mpN6JKHAtC51AQmSWom5EQwGOX36tJoJC2DOnDk8+eSThEIhzc9VK1I3Nzfz2muvcfv2bQA1DNjTTz+N2+3G5/Ml+E4fMNJQYANKfe7cuVGV+uDBg3u0IrXZbEaWZU6fPq0mEgqHw+Tk5JCXl6cmEtK61Ha7naamJjZu3Mg333wDRN4NKioqWLRokaZ66liEAutX6qKiolGV2mq1pmtFaniQc6Wmpob6+no1PcW0adOYN28eoihqvqc2Go3Y7Xbu3r3Lpk2buH79OhAJB7x3716WLFmimZ46VqHAdKn7Qcki2z2RUDgcZuLEicybNw+z2az5BRhF6ra2NsrKyvjqq6+AyDvDrl27+OlPf4rH40m41LEMBTZUqUcaaGaoUs8dYXsjQomMdPXqVerq6hAEgXA4TFZWFvPnz1cTCSWD1Pfv3+d3v/sdly9fBiLDq+3bt7Ns2bKESx3rUGADSt0tFJgjBm32kPq777670L1SkXrx4sXpRI6POWPQ5rBRktffuHGDCxcuIEkSsiyTkZHBokWLcDgcmpdamaf2er2UlZVRVxdZGhBFkW3btiU8OWc8QoH1kLr3B+bNm6fEzIhVKDBV6vnz5+9pbm7+d/dKq9WaXlZWtih6mRmjNoeNkkiooaGB6upqvF4vsixjt9uZP38+NptN8yF1Fak9Hg/l5eXU1tYCkZ66rKyM5557Do/Hk5CpyXiEAnMABovFIixZsiS7d6XX61Veh2O1DpwSbZOVK1dOTU9P/3HvDzQ2NioRkzSR09dgMCCKIk1NTbS0tGAwGJAkCafTidPp1HQPraDkMXS73fz2t7/lxo0bQETqdevWqRm+RptYC50B2C0Wi3D16tXcadOm9RA6EAgEKysrlazosRhopRA5Fe4sLy+fUVFRUWE2m3vEnq6vr/+8pKTkdPRSE6HAlFwqc+bMYfLkyUiShNFo5Pbt2zQ1NSVNBFLlRXbZsmVMmDBBLf/yyy/p6upS852PJrGMnDSgzK+//nrNO++800Ektsf9EbY3KJlzc3Pf8Xq9MnCL+MYUGRTKGDk/P5+pU6ciyzIGg4GGhgY1QWci4ioPFa/Xi8fj4bnnnqOsrEwNTlRTU8POnTuRZTkhzxEroYcq890Rtjccmf9jPD+ahMNhdWxcWFjIpEmTVJlv3LhBXV2dmn9F6yjp237961+zefNmtby6upqtW7cSCATUbFmjTSyEzgRsQ5R5JOPnpJQ5GAxiMBgoLCxk/PjxyLKMKIpcu3aNK1euqC+LWkeR+fnnn2fTpk1q+blz59i2bRuBQAC73Z6Q4QaMXOhMwOZ0OoWLFy/qMj8ERWar1UpRUREZGRnIsowgCFy+fJmvvvoq6WR+8cUXKSkpUctPnDjBtm3b1PQUiXwHGInQuswDoOzVSEtLw+VyMWbMGMLhMOFwmIsXL3Lr1i1MJlNSJAnyeDx0dXWxatUq1q1bp5afOHGCHTt2aEJmGL7QuswDoMjsdDpxuVykpaWp4+jz58/T2NioLolrHUXml19+mTVr1qjlx48fZ+fOnQCakBmGJ7Qu8wAo2WDHjh1LYWEhFktkDcnv91NTU0NLS0vSyOx2u+nq6uKVV15h1apVavmxY8fYtWuXuhyuBZlh6ELrMg+AciJl/PjxFBQUqGPjrq4uzp49S1tbW9KkblN65pKSElauXKmWHz16lMrKSs3JDEMTWpd5AEKhEKFQiClTpjB37lxEUUQQBDo6Ojhz5gwejydpZFZ65g0bNrBixQq1/MiRI+zZsweLxYLD4dBccPzBCq3LPAChUAhJkpg+fTq5uQ9yfN67d0/ds5EseQgVmUtLSykuLlbLP/30U/bt24fVasVms2lOZhic0LrMg0CWZdLT01WZlb0a1dXVSJKE2WzWpAC9CQQC+P1+Xn311R4yf/LJJ+zfvx+LxYLdbtfsswwktC7zEAiFQni9XlJSUmhoaOD8+fM9cnonA6FQiIyMDJYvX66WffTRR/zxj38kJSVF0zJD/0LrMg8Bo9FIZ2cnJ0+eJC0tTd1FlwwLJt0xmUy0tbXx8ccfs3TpUv7xj39w6NChpJAZ+hY6jdGVGSL5BZNSZugZvsDn8yXNtFxvlJM1f/nLX/j73/9Oa2ur+gKYDPQltA2gqqpqzijJnAGMKy4uzkpGmRVEUUyKl76BsNlsavL5sWPHJvhuhkZfP32r0+kUZs+ePbF7YZxkhmiOlfXr1z+TrDLraIO+hA62t7eHOzo6upSCOMoM0cyy3ZLME73WZdYZEn0J7QcoLy+/ePPmzeabN2/e2bBhw9k4yQyRkyT+tWvXnj527Nj/trS0fPnZZ58d0mXWGSp9pUYWiIQa6J1mwgf8QGxlVhgDPPOQ8pjKrCev1zbxSl4fJpKOwsGD09l+oGMkjQ1AG3CSSAZbJen8HUZ+VEvn/xEP7aF1dJKV5J9j0tHphi60ziOFLrTOI4UutM4jhS60ziPF/wHgvbfirVNMHAAAAABJRU5ErkJggg==) no-repeat}.layui-layer-prompt .layui-layer-input{color:#333;border:1px solid #ccc;width:220px;height:30px;margin:0 auto;padding:0 5px;line-height:30px;display:block;box-shadow:inset 1px 1px 5px #0000001a}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px}.layui-layer-prompt .layui-layer-content{padding:20px}.layui-layer-prompt .layui-layer-btn{padding-top:0}.layui-layer-tab{box-shadow:1px 1px 50px #0006}.layui-layer-tab .layui-layer-title{background-color:#eee;border-bottom:1px solid #ccc;padding-left:0;overflow:visible}.layui-layer-tab .layui-layer-title span{float:left;text-align:center;cursor:default;text-overflow:ellipsis;white-space:nowrap;min-width:80px;max-width:260px;padding:0 20px;position:relative;overflow:hidden}.layui-layer-tab .layui-layer-title span.layui-layer-tabnow{z-index:10;background-color:#fff;border-left:1px solid #ccc;border-right:1px solid #ccc;height:43px}.layui-layer-tab .layui-layer-title span:first-child{border-left:none}.layui-layer-tabmain{clear:both;line-height:24px}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.xubox_tab_layer{display:block}.xubox_tabclose{cursor:pointer;position:absolute;top:5px;right:10px}.layui-layer-photos{animation-duration:1s}.layui-layer-photos .layui-layer-content{text-align:center;overflow:hidden}.layui-layer-photos .layui-layer-phimg img{vertical-align:top}.layui-layer-imguide,.layui-layer-imgbar{display:none}.layui-layer-imgprev,.layui-layer-imgnext{_width:44px;blr:expression(this.onFocus=this.blur());outline:none;width:27px;height:44px;margin-top:-22px;position:absolute;top:50%}.layui-layer-imgprev{background-position:-5px -5px;left:10px}.layui-layer-imgprev:hover{background-position:-33px -5px}.layui-layer-imgnext{background-position:-5px -50px;right:10px}.layui-layer-imgnext:hover{background-position:-33px -50px}.layui-layer-imgbar{background-color:#000c;background-color:#000 \\9 ;width:100%;height:32px;filter:Alpha(opacity=80);color:#fff;text-overflow:ellipsis;white-space:nowrap;font-size:0;line-height:32px;position:absolute;bottom:0;left:0;overflow:hidden}.layui-layer-imgtit *{vertical-align:top;font-size:12px}.layui-layer-imgtit a{text-overflow:ellipsis;white-space:nowrap;color:#fff;max-width:65%;overflow:hidden}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{padding-left:10px;font-style:normal}@media screen and (width<=1100px){.layui-layer-iframe{-webkit-overflow-scrolling:touch;overflow-y:auto}}\n/*$vite$:1*/ ");
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
key = keys[i];
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: ((k) => from[k]).bind(null, key),
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
value: mod,
enumerable: true
}) : target, mod));
var __require = ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { get: (a, b) => (typeof require !== "undefined" ? require : a)[b] }) : x)(function(x) {
if (typeof require !== "undefined") return require.apply(this, arguments);
throw Error("Calling `require` for \"" + x + "\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.");
});
var import_jquery = __toESM(__commonJSMin(((exports, module) => {
(function(global, factory) {
"use strict";
if (typeof module === "object" && typeof module.exports === "object") module.exports = global.document ? factory(global, true) : function(w) {
if (!w.document) throw new Error("jQuery requires a window with a document");
return factory(w);
};
else factory(global);
})(typeof window !== "undefined" ? window : exports, function(window, noGlobal) {
"use strict";
var arr = [];
var getProto = Object.getPrototypeOf;
var slice = arr.slice;
var flat = arr.flat ? function(array) {
return arr.flat.call(array);
} : function(array) {
return arr.concat.apply([], array);
};
var push = arr.push;
var indexOf = arr.indexOf;
var class2type = {};
var toString = class2type.toString;
var hasOwn = class2type.hasOwnProperty;
var fnToString = hasOwn.toString;
var ObjectFunctionString = fnToString.call(Object);
var support = {};
var isFunction = function isFunction(obj) {
return typeof obj === "function" && typeof obj.nodeType !== "number" && typeof obj.item !== "function";
};
var isWindow = function isWindow(obj) {
return obj != null && obj === obj.window;
};
var document = window.document;
var preservedScriptAttributes = {
type: true,
src: true,
nonce: true,
noModule: true
};
function DOMEval(code, node, doc) {
doc = doc || document;
var i, val, script = doc.createElement("script");
script.text = code;
if (node) for (i in preservedScriptAttributes) {
val = node[i] || node.getAttribute && node.getAttribute(i);
if (val) script.setAttribute(i, val);
}
doc.head.appendChild(script).parentNode.removeChild(script);
}
function toType(obj) {
if (obj == null) return obj + "";
return typeof obj === "object" || typeof obj === "function" ? class2type[toString.call(obj)] || "object" : typeof obj;
}
var version = "3.7.1", rhtmlSuffix = /HTML$/i, jQuery = function(selector, context) {
return new jQuery.fn.init(selector, context);
};
jQuery.fn = jQuery.prototype = {
jquery: version,
constructor: jQuery,
length: 0,
toArray: function() {
return slice.call(this);
},
get: function(num) {
if (num == null) return slice.call(this);
return num < 0 ? this[num + this.length] : this[num];
},
pushStack: function(elems) {
var ret = jQuery.merge(this.constructor(), elems);
ret.prevObject = this;
return ret;
},
each: function(callback) {
return jQuery.each(this, callback);
},
map: function(callback) {
return this.pushStack(jQuery.map(this, function(elem, i) {
return callback.call(elem, i, elem);
}));
},
slice: function() {
return this.pushStack(slice.apply(this, arguments));
},
first: function() {
return this.eq(0);
},
last: function() {
return this.eq(-1);
},
even: function() {
return this.pushStack(jQuery.grep(this, function(_elem, i) {
return (i + 1) % 2;
}));
},
odd: function() {
return this.pushStack(jQuery.grep(this, function(_elem, i) {
return i % 2;
}));
},
eq: function(i) {
var len = this.length, j = +i + (i < 0 ? len : 0);
return this.pushStack(j >= 0 && j < len ? [this[j]] : []);
},
end: function() {
return this.prevObject || this.constructor();
},
push,
sort: arr.sort,
splice: arr.splice
};
jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false;
if (typeof target === "boolean") {
deep = target;
target = arguments[i] || {};
i++;
}
if (typeof target !== "object" && !isFunction(target)) target = {};
if (i === length) {
target = this;
i--;
}
for (; i < length; i++) if ((options = arguments[i]) != null) for (name in options) {
copy = options[name];
if (name === "__proto__" || target === copy) continue;
if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) {
src = target[name];
if (copyIsArray && !Array.isArray(src)) clone = [];
else if (!copyIsArray && !jQuery.isPlainObject(src)) clone = {};
else clone = src;
copyIsArray = false;
target[name] = jQuery.extend(deep, clone, copy);
} else if (copy !== void 0) target[name] = copy;
}
return target;
};
jQuery.extend({
expando: "jQuery" + (version + Math.random()).replace(/\D/g, ""),
isReady: true,
error: function(msg) {
throw new Error(msg);
},
noop: function() {},
isPlainObject: function(obj) {
var proto, Ctor;
if (!obj || toString.call(obj) !== "[object Object]") return false;
proto = getProto(obj);
if (!proto) return true;
Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
},
isEmptyObject: function(obj) {
var name;
for (name in obj) return false;
return true;
},
globalEval: function(code, options, doc) {
DOMEval(code, { nonce: options && options.nonce }, doc);
},
each: function(obj, callback) {
var length, i = 0;
if (isArrayLike(obj)) {
length = obj.length;
for (; i < length; i++) if (callback.call(obj[i], i, obj[i]) === false) break;
} else for (i in obj) if (callback.call(obj[i], i, obj[i]) === false) break;
return obj;
},
text: function(elem) {
var node, ret = "", i = 0, nodeType = elem.nodeType;
if (!nodeType) while (node = elem[i++]) ret += jQuery.text(node);
if (nodeType === 1 || nodeType === 11) return elem.textContent;
if (nodeType === 9) return elem.documentElement.textContent;
if (nodeType === 3 || nodeType === 4) return elem.nodeValue;
return ret;
},
makeArray: function(arr, results) {
var ret = results || [];
if (arr != null) if (isArrayLike(Object(arr))) jQuery.merge(ret, typeof arr === "string" ? [arr] : arr);
else push.call(ret, arr);
return ret;
},
inArray: function(elem, arr, i) {
return arr == null ? -1 : indexOf.call(arr, elem, i);
},
isXMLDoc: function(elem) {
var namespace = elem && elem.namespaceURI, docElem = elem && (elem.ownerDocument || elem).documentElement;
return !rhtmlSuffix.test(namespace || docElem && docElem.nodeName || "HTML");
},
merge: function(first, second) {
var len = +second.length, j = 0, i = first.length;
for (; j < len; j++) first[i++] = second[j];
first.length = i;
return first;
},
grep: function(elems, callback, invert) {
var callbackInverse, matches = [], i = 0, length = elems.length, callbackExpect = !invert;
for (; i < length; i++) {
callbackInverse = !callback(elems[i], i);
if (callbackInverse !== callbackExpect) matches.push(elems[i]);
}
return matches;
},
map: function(elems, callback, arg) {
var length, value, i = 0, ret = [];
if (isArrayLike(elems)) {
length = elems.length;
for (; i < length; i++) {
value = callback(elems[i], i, arg);
if (value != null) ret.push(value);
}
} else for (i in elems) {
value = callback(elems[i], i, arg);
if (value != null) ret.push(value);
}
return flat(ret);
},
guid: 1,
support
});
if (typeof Symbol === "function") jQuery.fn[Symbol.iterator] = arr[Symbol.iterator];
jQuery.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "), function(_i, name) {
class2type["[object " + name + "]"] = name.toLowerCase();
});
function isArrayLike(obj) {
var length = !!obj && "length" in obj && obj.length, type = toType(obj);
if (isFunction(obj) || isWindow(obj)) return false;
return type === "array" || length === 0 || typeof length === "number" && length > 0 && length - 1 in obj;
}
function nodeName(elem, name) {
return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
}
var pop = arr.pop;
var sort = arr.sort;
var splice = arr.splice;
var whitespace = "[\\x20\\t\\r\\n\\f]";
var rtrimCSS = new RegExp("^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g");
jQuery.contains = function(a, b) {
var bup = b && b.parentNode;
return a === bup || !!(bup && bup.nodeType === 1 && (a.contains ? a.contains(bup) : a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16));
};
var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;
function fcssescape(ch, asCodePoint) {
if (asCodePoint) {
if (ch === "\0") return "�";
return ch.slice(0, -1) + "\\" + ch.charCodeAt(ch.length - 1).toString(16) + " ";
}
return "\\" + ch;
}
jQuery.escapeSelector = function(sel) {
return (sel + "").replace(rcssescape, fcssescape);
};
var preferredDoc = document, pushNative = push;
(function() {
var i, Expr, outermostContext, sortInput, hasDuplicate, push = pushNative, document, documentElement, documentIsHTML, rbuggyQSA, matches, expando = jQuery.expando, dirruns = 0, done = 0, classCache = createCache(), tokenCache = createCache(), compilerCache = createCache(), nonnativeSelectorCache = createCache(), sortOrder = function(a, b) {
if (a === b) hasDuplicate = true;
return 0;
}, booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + "*([*^$|!~]?=)" + whitespace + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + "*\\]", pseudos = ":(" + identifier + ")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|.*)\\)|)", rwhitespace = new RegExp(whitespace + "+", "g"), rcomma = new RegExp("^" + whitespace + "*," + whitespace + "*"), rleadingCombinator = new RegExp("^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*"), rdescend = new RegExp(whitespace + "|>"), rpseudo = new RegExp(pseudos), ridentifier = new RegExp("^" + identifier + "$"), matchExpr = {
ID: new RegExp("^#(" + identifier + ")"),
CLASS: new RegExp("^\\.(" + identifier + ")"),
TAG: new RegExp("^(" + identifier + "|[*])"),
ATTR: new RegExp("^" + attributes),
PSEUDO: new RegExp("^" + pseudos),
CHILD: new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i"),
bool: new RegExp("^(?:" + booleans + ")$", "i"),
needsContext: new RegExp("^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i")
}, rinputs = /^(?:input|select|textarea|button)$/i, rheader = /^h\d$/i, rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, rsibling = /[+~]/, runescape = new RegExp("\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g"), funescape = function(escape, nonHex) {
var high = "0x" + escape.slice(1) - 65536;
if (nonHex) return nonHex;
return high < 0 ? String.fromCharCode(high + 65536) : String.fromCharCode(high >> 10 | 55296, high & 1023 | 56320);
}, unloadHandler = function() {
setDocument();
}, inDisabledFieldset = addCombinator(function(elem) {
return elem.disabled === true && nodeName(elem, "fieldset");
}, {
dir: "parentNode",
next: "legend"
});
function safeActiveElement() {
try {
return document.activeElement;
} catch (err) {}
}
try {
push.apply(arr = slice.call(preferredDoc.childNodes), preferredDoc.childNodes);
arr[preferredDoc.childNodes.length].nodeType;
} catch (e) {
push = {
apply: function(target, els) {
pushNative.apply(target, slice.call(els));
},
call: function(target) {
pushNative.apply(target, slice.call(arguments, 1));
}
};
}
function find(selector, context, results, seed) {
var m, i, elem, nid, match, groups, newSelector, newContext = context && context.ownerDocument, nodeType = context ? context.nodeType : 9;
results = results || [];
if (typeof selector !== "string" || !selector || nodeType !== 1 && nodeType !== 9 && nodeType !== 11) return results;
if (!seed) {
setDocument(context);
context = context || document;
if (documentIsHTML) {
if (nodeType !== 11 && (match = rquickExpr.exec(selector))) {
if (m = match[1]) {
if (nodeType === 9) if (elem = context.getElementById(m)) {
if (elem.id === m) {
push.call(results, elem);
return results;
}
} else return results;
else if (newContext && (elem = newContext.getElementById(m)) && find.contains(context, elem) && elem.id === m) {
push.call(results, elem);
return results;
}
} else if (match[2]) {
push.apply(results, context.getElementsByTagName(selector));
return results;
} else if ((m = match[3]) && context.getElementsByClassName) {
push.apply(results, context.getElementsByClassName(m));
return results;
}
}
if (!nonnativeSelectorCache[selector + " "] && (!rbuggyQSA || !rbuggyQSA.test(selector))) {
newSelector = selector;
newContext = context;
if (nodeType === 1 && (rdescend.test(selector) || rleadingCombinator.test(selector))) {
newContext = rsibling.test(selector) && testContext(context.parentNode) || context;
if (newContext != context || !support.scope) if (nid = context.getAttribute("id")) nid = jQuery.escapeSelector(nid);
else context.setAttribute("id", nid = expando);
groups = tokenize(selector);
i = groups.length;
while (i--) groups[i] = (nid ? "#" + nid : ":scope") + " " + toSelector(groups[i]);
newSelector = groups.join(",");
}
try {
push.apply(results, newContext.querySelectorAll(newSelector));
return results;
} catch (qsaError) {
nonnativeSelectorCache(selector, true);
} finally {
if (nid === expando) context.removeAttribute("id");
}
}
}
}
return select(selector.replace(rtrimCSS, "$1"), context, results, seed);
}
function createCache() {
var keys = [];
function cache(key, value) {
if (keys.push(key + " ") > Expr.cacheLength) delete cache[keys.shift()];
return cache[key + " "] = value;
}
return cache;
}
function markFunction(fn) {
fn[expando] = true;
return fn;
}
function assert(fn) {
var el = document.createElement("fieldset");
try {
return !!fn(el);
} catch (e) {
return false;
} finally {
if (el.parentNode) el.parentNode.removeChild(el);
el = null;
}
}
function createInputPseudo(type) {
return function(elem) {
return nodeName(elem, "input") && elem.type === type;
};
}
function createButtonPseudo(type) {
return function(elem) {
return (nodeName(elem, "input") || nodeName(elem, "button")) && elem.type === type;
};
}
function createDisabledPseudo(disabled) {
return function(elem) {
if ("form" in elem) {
if (elem.parentNode && elem.disabled === false) {
if ("label" in elem) if ("label" in elem.parentNode) return elem.parentNode.disabled === disabled;
else return elem.disabled === disabled;
return elem.isDisabled === disabled || elem.isDisabled !== !disabled && inDisabledFieldset(elem) === disabled;
}
return elem.disabled === disabled;
} else if ("label" in elem) return elem.disabled === disabled;
return false;
};
}
function createPositionalPseudo(fn) {
return markFunction(function(argument) {
argument = +argument;
return markFunction(function(seed, matches) {
var j, matchIndexes = fn([], seed.length, argument), i = matchIndexes.length;
while (i--) if (seed[j = matchIndexes[i]]) seed[j] = !(matches[j] = seed[j]);
});
});
}
function testContext(context) {
return context && typeof context.getElementsByTagName !== "undefined" && context;
}
function setDocument(node) {
var subWindow, doc = node ? node.ownerDocument || node : preferredDoc;
if (doc == document || doc.nodeType !== 9 || !doc.documentElement) return document;
document = doc;
documentElement = document.documentElement;
documentIsHTML = !jQuery.isXMLDoc(document);
matches = documentElement.matches || documentElement.webkitMatchesSelector || documentElement.msMatchesSelector;
if (documentElement.msMatchesSelector && preferredDoc != document && (subWindow = document.defaultView) && subWindow.top !== subWindow) subWindow.addEventListener("unload", unloadHandler);
support.getById = assert(function(el) {
documentElement.appendChild(el).id = jQuery.expando;
return !document.getElementsByName || !document.getElementsByName(jQuery.expando).length;
});
support.disconnectedMatch = assert(function(el) {
return matches.call(el, "*");
});
support.scope = assert(function() {
return document.querySelectorAll(":scope");
});
support.cssHas = assert(function() {
try {
document.querySelector(":has(*,:jqfake)");
return false;
} catch (e) {
return true;
}
});
if (support.getById) {
Expr.filter.ID = function(id) {
var attrId = id.replace(runescape, funescape);
return function(elem) {
return elem.getAttribute("id") === attrId;
};
};
Expr.find.ID = function(id, context) {
if (typeof context.getElementById !== "undefined" && documentIsHTML) {
var elem = context.getElementById(id);
return elem ? [elem] : [];
}
};
} else {
Expr.filter.ID = function(id) {
var attrId = id.replace(runescape, funescape);
return function(elem) {
var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
return node && node.value === attrId;
};
};
Expr.find.ID = function(id, context) {
if (typeof context.getElementById !== "undefined" && documentIsHTML) {
var node, i, elems, elem = context.getElementById(id);
if (elem) {
node = elem.getAttributeNode("id");
if (node && node.value === id) return [elem];
elems = context.getElementsByName(id);
i = 0;
while (elem = elems[i++]) {
node = elem.getAttributeNode("id");
if (node && node.value === id) return [elem];
}
}
return [];
}
};
}
Expr.find.TAG = function(tag, context) {
if (typeof context.getElementsByTagName !== "undefined") return context.getElementsByTagName(tag);
else return context.querySelectorAll(tag);
};
Expr.find.CLASS = function(className, context) {
if (typeof context.getElementsByClassName !== "undefined" && documentIsHTML) return context.getElementsByClassName(className);
};
rbuggyQSA = [];
assert(function(el) {
var input;
documentElement.appendChild(el).innerHTML = "<a id='" + expando + "' href='' disabled='disabled'></a><select id='" + expando + "-\r\\' disabled='disabled'><option selected=''></option></select>";
if (!el.querySelectorAll("[selected]").length) rbuggyQSA.push("\\[" + whitespace + "*(?:value|" + booleans + ")");
if (!el.querySelectorAll("[id~=" + expando + "-]").length) rbuggyQSA.push("~=");
if (!el.querySelectorAll("a#" + expando + "+*").length) rbuggyQSA.push(".#.+[+~]");
if (!el.querySelectorAll(":checked").length) rbuggyQSA.push(":checked");
input = document.createElement("input");
input.setAttribute("type", "hidden");
el.appendChild(input).setAttribute("name", "D");
documentElement.appendChild(el).disabled = true;
if (el.querySelectorAll(":disabled").length !== 2) rbuggyQSA.push(":enabled", ":disabled");
input = document.createElement("input");
input.setAttribute("name", "");
el.appendChild(input);
if (!el.querySelectorAll("[name='']").length) rbuggyQSA.push("\\[" + whitespace + "*name" + whitespace + "*=" + whitespace + "*(?:''|\"\")");
});
if (!support.cssHas) rbuggyQSA.push(":has");
rbuggyQSA = rbuggyQSA.length && new RegExp(rbuggyQSA.join("|"));
sortOrder = function(a, b) {
if (a === b) {
hasDuplicate = true;
return 0;
}
var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
if (compare) return compare;
compare = (a.ownerDocument || a) == (b.ownerDocument || b) ? a.compareDocumentPosition(b) : 1;
if (compare & 1 || !support.sortDetached && b.compareDocumentPosition(a) === compare) {
if (a === document || a.ownerDocument == preferredDoc && find.contains(preferredDoc, a)) return -1;
if (b === document || b.ownerDocument == preferredDoc && find.contains(preferredDoc, b)) return 1;
return sortInput ? indexOf.call(sortInput, a) - indexOf.call(sortInput, b) : 0;
}
return compare & 4 ? -1 : 1;
};
return document;
}
find.matches = function(expr, elements) {
return find(expr, null, null, elements);
};
find.matchesSelector = function(elem, expr) {
setDocument(elem);
if (documentIsHTML && !nonnativeSelectorCache[expr + " "] && (!rbuggyQSA || !rbuggyQSA.test(expr))) try {
var ret = matches.call(elem, expr);
if (ret || support.disconnectedMatch || elem.document && elem.document.nodeType !== 11) return ret;
} catch (e) {
nonnativeSelectorCache(expr, true);
}
return find(expr, document, null, [elem]).length > 0;
};
find.contains = function(context, elem) {
if ((context.ownerDocument || context) != document) setDocument(context);
return jQuery.contains(context, elem);
};
find.attr = function(elem, name) {
if ((elem.ownerDocument || elem) != document) setDocument(elem);
var fn = Expr.attrHandle[name.toLowerCase()], val = fn && hasOwn.call(Expr.attrHandle, name.toLowerCase()) ? fn(elem, name, !documentIsHTML) : void 0;
if (val !== void 0) return val;
return elem.getAttribute(name);
};
find.error = function(msg) {
throw new Error("Syntax error, unrecognized expression: " + msg);
};
jQuery.uniqueSort = function(results) {
var elem, duplicates = [], j = 0, i = 0;
hasDuplicate = !support.sortStable;
sortInput = !support.sortStable && slice.call(results, 0);
sort.call(results, sortOrder);
if (hasDuplicate) {
while (elem = results[i++]) if (elem === results[i]) j = duplicates.push(i);
while (j--) splice.call(results, duplicates[j], 1);
}
sortInput = null;
return results;
};
jQuery.fn.uniqueSort = function() {
return this.pushStack(jQuery.uniqueSort(slice.apply(this)));
};
Expr = jQuery.expr = {
cacheLength: 50,
createPseudo: markFunction,
match: matchExpr,
attrHandle: {},
find: {},
relative: {
">": {
dir: "parentNode",
first: true
},
" ": { dir: "parentNode" },
"+": {
dir: "previousSibling",
first: true
},
"~": { dir: "previousSibling" }
},
preFilter: {
ATTR: function(match) {
match[1] = match[1].replace(runescape, funescape);
match[3] = (match[3] || match[4] || match[5] || "").replace(runescape, funescape);
if (match[2] === "~=") match[3] = " " + match[3] + " ";
return match.slice(0, 4);
},
CHILD: function(match) {
match[1] = match[1].toLowerCase();
if (match[1].slice(0, 3) === "nth") {
if (!match[3]) find.error(match[0]);
match[4] = +(match[4] ? match[5] + (match[6] || 1) : 2 * (match[3] === "even" || match[3] === "odd"));
match[5] = +(match[7] + match[8] || match[3] === "odd");
} else if (match[3]) find.error(match[0]);
return match;
},
PSEUDO: function(match) {
var excess, unquoted = !match[6] && match[2];
if (matchExpr.CHILD.test(match[0])) return null;
if (match[3]) match[2] = match[4] || match[5] || "";
else if (unquoted && rpseudo.test(unquoted) && (excess = tokenize(unquoted, true)) && (excess = unquoted.indexOf(")", unquoted.length - excess) - unquoted.length)) {
match[0] = match[0].slice(0, excess);
match[2] = unquoted.slice(0, excess);
}
return match.slice(0, 3);
}
},
filter: {
TAG: function(nodeNameSelector) {
var expectedNodeName = nodeNameSelector.replace(runescape, funescape).toLowerCase();
return nodeNameSelector === "*" ? function() {
return true;
} : function(elem) {
return nodeName(elem, expectedNodeName);
};
},
CLASS: function(className) {
var pattern = classCache[className + " "];
return pattern || (pattern = new RegExp("(^|" + whitespace + ")" + className + "(" + whitespace + "|$)")) && classCache(className, function(elem) {
return pattern.test(typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "");
});
},
ATTR: function(name, operator, check) {
return function(elem) {
var result = find.attr(elem, name);
if (result == null) return operator === "!=";
if (!operator) return true;
result += "";
if (operator === "=") return result === check;
if (operator === "!=") return result !== check;
if (operator === "^=") return check && result.indexOf(check) === 0;
if (operator === "*=") return check && result.indexOf(check) > -1;
if (operator === "$=") return check && result.slice(-check.length) === check;
if (operator === "~=") return (" " + result.replace(rwhitespace, " ") + " ").indexOf(check) > -1;
if (operator === "|=") return result === check || result.slice(0, check.length + 1) === check + "-";
return false;
};
},
CHILD: function(type, what, _argument, first, last) {
var simple = type.slice(0, 3) !== "nth", forward = type.slice(-4) !== "last", ofType = what === "of-type";
return first === 1 && last === 0 ? function(elem) {
return !!elem.parentNode;
} : function(elem, _context, xml) {
var cache, outerCache, node, nodeIndex, start, dir = simple !== forward ? "nextSibling" : "previousSibling", parent = elem.parentNode, name = ofType && elem.nodeName.toLowerCase(), useCache = !xml && !ofType, diff = false;
if (parent) {
if (simple) {
while (dir) {
node = elem;
while (node = node[dir]) if (ofType ? nodeName(node, name) : node.nodeType === 1) return false;
start = dir = type === "only" && !start && "nextSibling";
}
return true;
}
start = [forward ? parent.firstChild : parent.lastChild];
if (forward && useCache) {
outerCache = parent[expando] || (parent[expando] = {});
cache = outerCache[type] || [];
nodeIndex = cache[0] === dirruns && cache[1];
diff = nodeIndex && cache[2];
node = nodeIndex && parent.childNodes[nodeIndex];
while (node = ++nodeIndex && node && node[dir] || (diff = nodeIndex = 0) || start.pop()) if (node.nodeType === 1 && ++diff && node === elem) {
outerCache[type] = [
dirruns,
nodeIndex,
diff
];
break;
}
} else {
if (useCache) {
outerCache = elem[expando] || (elem[expando] = {});
cache = outerCache[type] || [];
nodeIndex = cache[0] === dirruns && cache[1];
diff = nodeIndex;
}
if (diff === false) {
while (node = ++nodeIndex && node && node[dir] || (diff = nodeIndex = 0) || start.pop()) if ((ofType ? nodeName(node, name) : node.nodeType === 1) && ++diff) {
if (useCache) {
outerCache = node[expando] || (node[expando] = {});
outerCache[type] = [dirruns, diff];
}
if (node === elem) break;
}
}
}
diff -= last;
return diff === first || diff % first === 0 && diff / first >= 0;
}
};
},
PSEUDO: function(pseudo, argument) {
var args, fn = Expr.pseudos[pseudo] || Expr.setFilters[pseudo.toLowerCase()] || find.error("unsupported pseudo: " + pseudo);
if (fn[expando]) return fn(argument);
if (fn.length > 1) {
args = [
pseudo,
pseudo,
"",
argument
];
return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase()) ? markFunction(function(seed, matches) {
var idx, matched = fn(seed, argument), i = matched.length;
while (i--) {
idx = indexOf.call(seed, matched[i]);
seed[idx] = !(matches[idx] = matched[i]);
}
}) : function(elem) {
return fn(elem, 0, args);
};
}
return fn;
}
},
pseudos: {
not: markFunction(function(selector) {
var input = [], results = [], matcher = compile(selector.replace(rtrimCSS, "$1"));
return matcher[expando] ? markFunction(function(seed, matches, _context, xml) {
var elem, unmatched = matcher(seed, null, xml, []), i = seed.length;
while (i--) if (elem = unmatched[i]) seed[i] = !(matches[i] = elem);
}) : function(elem, _context, xml) {
input[0] = elem;
matcher(input, null, xml, results);
input[0] = null;
return !results.pop();
};
}),
has: markFunction(function(selector) {
return function(elem) {
return find(selector, elem).length > 0;
};
}),
contains: markFunction(function(text) {
text = text.replace(runescape, funescape);
return function(elem) {
return (elem.textContent || jQuery.text(elem)).indexOf(text) > -1;
};
}),
lang: markFunction(function(lang) {
if (!ridentifier.test(lang || "")) find.error("unsupported lang: " + lang);
lang = lang.replace(runescape, funescape).toLowerCase();
return function(elem) {
var elemLang;
do
if (elemLang = documentIsHTML ? elem.lang : elem.getAttribute("xml:lang") || elem.getAttribute("lang")) {
elemLang = elemLang.toLowerCase();
return elemLang === lang || elemLang.indexOf(lang + "-") === 0;
}
while ((elem = elem.parentNode) && elem.nodeType === 1);
return false;
};
}),
target: function(elem) {
var hash = window.location && window.location.hash;
return hash && hash.slice(1) === elem.id;
},
root: function(elem) {
return elem === documentElement;
},
focus: function(elem) {
return elem === safeActiveElement() && document.hasFocus() && !!(elem.type || elem.href || ~elem.tabIndex);
},
enabled: createDisabledPseudo(false),
disabled: createDisabledPseudo(true),
checked: function(elem) {
return nodeName(elem, "input") && !!elem.checked || nodeName(elem, "option") && !!elem.selected;
},
selected: function(elem) {
if (elem.parentNode) elem.parentNode.selectedIndex;
return elem.selected === true;
},
empty: function(elem) {
for (elem = elem.firstChild; elem; elem = elem.nextSibling) if (elem.nodeType < 6) return false;
return true;
},
parent: function(elem) {
return !Expr.pseudos.empty(elem);
},
header: function(elem) {
return rheader.test(elem.nodeName);
},
input: function(elem) {
return rinputs.test(elem.nodeName);
},
button: function(elem) {
return nodeName(elem, "input") && elem.type === "button" || nodeName(elem, "button");
},
text: function(elem) {
var attr;
return nodeName(elem, "input") && elem.type === "text" && ((attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text");
},
first: createPositionalPseudo(function() {
return [0];
}),
last: createPositionalPseudo(function(_matchIndexes, length) {
return [length - 1];
}),
eq: createPositionalPseudo(function(_matchIndexes, length, argument) {
return [argument < 0 ? argument + length : argument];
}),
even: createPositionalPseudo(function(matchIndexes, length) {
var i = 0;
for (; i < length; i += 2) matchIndexes.push(i);
return matchIndexes;
}),
odd: createPositionalPseudo(function(matchIndexes, length) {
var i = 1;
for (; i < length; i += 2) matchIndexes.push(i);
return matchIndexes;
}),
lt: createPositionalPseudo(function(matchIndexes, length, argument) {
var i;
if (argument < 0) i = argument + length;
else if (argument > length) i = length;
else i = argument;
for (; --i >= 0;) matchIndexes.push(i);
return matchIndexes;
}),
gt: createPositionalPseudo(function(matchIndexes, length, argument) {
var i = argument < 0 ? argument + length : argument;
for (; ++i < length;) matchIndexes.push(i);
return matchIndexes;
})
}
};
Expr.pseudos.nth = Expr.pseudos.eq;
for (i in {
radio: true,
checkbox: true,
file: true,
password: true,
image: true
}) Expr.pseudos[i] = createInputPseudo(i);
for (i in {
submit: true,
reset: true
}) Expr.pseudos[i] = createButtonPseudo(i);
function setFilters() {}
setFilters.prototype = Expr.filters = Expr.pseudos;
Expr.setFilters = new setFilters();
function tokenize(selector, parseOnly) {
var matched, match, tokens, type, soFar, groups, preFilters, cached = tokenCache[selector + " "];
if (cached) return parseOnly ? 0 : cached.slice(0);
soFar = selector;
groups = [];
preFilters = Expr.preFilter;
while (soFar) {
if (!matched || (match = rcomma.exec(soFar))) {
if (match) soFar = soFar.slice(match[0].length) || soFar;
groups.push(tokens = []);
}
matched = false;
if (match = rleadingCombinator.exec(soFar)) {
matched = match.shift();
tokens.push({
value: matched,
type: match[0].replace(rtrimCSS, " ")
});
soFar = soFar.slice(matched.length);
}
for (type in Expr.filter) if ((match = matchExpr[type].exec(soFar)) && (!preFilters[type] || (match = preFilters[type](match)))) {
matched = match.shift();
tokens.push({
value: matched,
type,
matches: match
});
soFar = soFar.slice(matched.length);
}
if (!matched) break;
}
if (parseOnly) return soFar.length;
return soFar ? find.error(selector) : tokenCache(selector, groups).slice(0);
}
function toSelector(tokens) {
var i = 0, len = tokens.length, selector = "";
for (; i < len; i++) selector += tokens[i].value;
return selector;
}
function addCombinator(matcher, combinator, base) {
var dir = combinator.dir, skip = combinator.next, key = skip || dir, checkNonElements = base && key === "parentNode", doneName = done++;
return combinator.first ? function(elem, context, xml) {
while (elem = elem[dir]) if (elem.nodeType === 1 || checkNonElements) return matcher(elem, context, xml);
return false;
} : function(elem, context, xml) {
var oldCache, outerCache, newCache = [dirruns, doneName];
if (xml) {
while (elem = elem[dir]) if (elem.nodeType === 1 || checkNonElements) {
if (matcher(elem, context, xml)) return true;
}
} else while (elem = elem[dir]) if (elem.nodeType === 1 || checkNonElements) {
outerCache = elem[expando] || (elem[expando] = {});
if (skip && nodeName(elem, skip)) elem = elem[dir] || elem;
else if ((oldCache = outerCache[key]) && oldCache[0] === dirruns && oldCache[1] === doneName) return newCache[2] = oldCache[2];
else {
outerCache[key] = newCache;
if (newCache[2] = matcher(elem, context, xml)) return true;
}
}
return false;
};
}
function elementMatcher(matchers) {
return matchers.length > 1 ? function(elem, context, xml) {
var i = matchers.length;
while (i--) if (!matchers[i](elem, context, xml)) return false;
return true;
} : matchers[0];
}
function multipleContexts(selector, contexts, results) {
var i = 0, len = contexts.length;
for (; i < len; i++) find(selector, contexts[i], results);
return results;
}
function condense(unmatched, map, filter, context, xml) {
var elem, newUnmatched = [], i = 0, len = unmatched.length, mapped = map != null;
for (; i < len; i++) if (elem = unmatched[i]) {
if (!filter || filter(elem, context, xml)) {
newUnmatched.push(elem);
if (mapped) map.push(i);
}
}
return newUnmatched;
}
function setMatcher(preFilter, selector, matcher, postFilter, postFinder, postSelector) {
if (postFilter && !postFilter[expando]) postFilter = setMatcher(postFilter);
if (postFinder && !postFinder[expando]) postFinder = setMatcher(postFinder, postSelector);
return markFunction(function(seed, results, context, xml) {
var temp, i, elem, matcherOut, preMap = [], postMap = [], preexisting = results.length, elems = seed || multipleContexts(selector || "*", context.nodeType ? [context] : context, []), matcherIn = preFilter && (seed || !selector) ? condense(elems, preMap, preFilter, context, xml) : elems;
if (matcher) {
matcherOut = postFinder || (seed ? preFilter : preexisting || postFilter) ? [] : results;
matcher(matcherIn, matcherOut, context, xml);
} else matcherOut = matcherIn;
if (postFilter) {
temp = condense(matcherOut, postMap);
postFilter(temp, [], context, xml);
i = temp.length;
while (i--) if (elem = temp[i]) matcherOut[postMap[i]] = !(matcherIn[postMap[i]] = elem);
}
if (seed) {
if (postFinder || preFilter) {
if (postFinder) {
temp = [];
i = matcherOut.length;
while (i--) if (elem = matcherOut[i]) temp.push(matcherIn[i] = elem);
postFinder(null, matcherOut = [], temp, xml);
}
i = matcherOut.length;
while (i--) if ((elem = matcherOut[i]) && (temp = postFinder ? indexOf.call(seed, elem) : preMap[i]) > -1) seed[temp] = !(results[temp] = elem);
}
} else {
matcherOut = condense(matcherOut === results ? matcherOut.splice(preexisting, matcherOut.length) : matcherOut);
if (postFinder) postFinder(null, results, matcherOut, xml);
else push.apply(results, matcherOut);
}
});
}
function matcherFromTokens(tokens) {
var checkContext, matcher, j, len = tokens.length, leadingRelative = Expr.relative[tokens[0].type], implicitRelative = leadingRelative || Expr.relative[" "], i = leadingRelative ? 1 : 0, matchContext = addCombinator(function(elem) {
return elem === checkContext;
}, implicitRelative, true), matchAnyContext = addCombinator(function(elem) {
return indexOf.call(checkContext, elem) > -1;
}, implicitRelative, true), matchers = [function(elem, context, xml) {
var ret = !leadingRelative && (xml || context != outermostContext) || ((checkContext = context).nodeType ? matchContext(elem, context, xml) : matchAnyContext(elem, context, xml));
checkContext = null;
return ret;
}];
for (; i < len; i++) if (matcher = Expr.relative[tokens[i].type]) matchers = [addCombinator(elementMatcher(matchers), matcher)];
else {
matcher = Expr.filter[tokens[i].type].apply(null, tokens[i].matches);
if (matcher[expando]) {
j = ++i;
for (; j < len; j++) if (Expr.relative[tokens[j].type]) break;
return setMatcher(i > 1 && elementMatcher(matchers), i > 1 && toSelector(tokens.slice(0, i - 1).concat({ value: tokens[i - 2].type === " " ? "*" : "" })).replace(rtrimCSS, "$1"), matcher, i < j && matcherFromTokens(tokens.slice(i, j)), j < len && matcherFromTokens(tokens = tokens.slice(j)), j < len && toSelector(tokens));
}
matchers.push(matcher);
}
return elementMatcher(matchers);
}
function matcherFromGroupMatchers(elementMatchers, setMatchers) {
var bySet = setMatchers.length > 0, byElement = elementMatchers.length > 0, superMatcher = function(seed, context, xml, results, outermost) {
var elem, j, matcher, matchedCount = 0, i = "0", unmatched = seed && [], setMatched = [], contextBackup = outermostContext, elems = seed || byElement && Expr.find.TAG("*", outermost), dirrunsUnique = dirruns += contextBackup == null ? 1 : Math.random() || .1, len = elems.length;
if (outermost) outermostContext = context == document || context || outermost;
for (; i !== len && (elem = elems[i]) != null; i++) {
if (byElement && elem) {
j = 0;
if (!context && elem.ownerDocument != document) {
setDocument(elem);
xml = !documentIsHTML;
}
while (matcher = elementMatchers[j++]) if (matcher(elem, context || document, xml)) {
push.call(results, elem);
break;
}
if (outermost) dirruns = dirrunsUnique;
}
if (bySet) {
if (elem = !matcher && elem) matchedCount--;
if (seed) unmatched.push(elem);
}
}
matchedCount += i;
if (bySet && i !== matchedCount) {
j = 0;
while (matcher = setMatchers[j++]) matcher(unmatched, setMatched, context, xml);
if (seed) {
if (matchedCount > 0) {
while (i--) if (!(unmatched[i] || setMatched[i])) setMatched[i] = pop.call(results);
}
setMatched = condense(setMatched);
}
push.apply(results, setMatched);
if (outermost && !seed && setMatched.length > 0 && matchedCount + setMatchers.length > 1) jQuery.uniqueSort(results);
}
if (outermost) {
dirruns = dirrunsUnique;
outermostContext = contextBackup;
}
return unmatched;
};
return bySet ? markFunction(superMatcher) : superMatcher;
}
function compile(selector, match) {
var i, setMatchers = [], elementMatchers = [], cached = compilerCache[selector + " "];
if (!cached) {
if (!match) match = tokenize(selector);
i = match.length;
while (i--) {
cached = matcherFromTokens(match[i]);
if (cached[expando]) setMatchers.push(cached);
else elementMatchers.push(cached);
}
cached = compilerCache(selector, matcherFromGroupMatchers(elementMatchers, setMatchers));
cached.selector = selector;
}
return cached;
}
function select(selector, context, results, seed) {
var i, tokens, token, type, find, compiled = typeof selector === "function" && selector, match = !seed && tokenize(selector = compiled.selector || selector);
results = results || [];
if (match.length === 1) {
tokens = match[0] = match[0].slice(0);
if (tokens.length > 2 && (token = tokens[0]).type === "ID" && context.nodeType === 9 && documentIsHTML && Expr.relative[tokens[1].type]) {
context = (Expr.find.ID(token.matches[0].replace(runescape, funescape), context) || [])[0];
if (!context) return results;
else if (compiled) context = context.parentNode;
selector = selector.slice(tokens.shift().value.length);
}
i = matchExpr.needsContext.test(selector) ? 0 : tokens.length;
while (i--) {
token = tokens[i];
if (Expr.relative[type = token.type]) break;
if (find = Expr.find[type]) {
if (seed = find(token.matches[0].replace(runescape, funescape), rsibling.test(tokens[0].type) && testContext(context.parentNode) || context)) {
tokens.splice(i, 1);
selector = seed.length && toSelector(tokens);
if (!selector) {
push.apply(results, seed);
return results;
}
break;
}
}
}
}
(compiled || compile(selector, match))(seed, context, !documentIsHTML, results, !context || rsibling.test(selector) && testContext(context.parentNode) || context);
return results;
}
support.sortStable = expando.split("").sort(sortOrder).join("") === expando;
setDocument();
support.sortDetached = assert(function(el) {
return el.compareDocumentPosition(document.createElement("fieldset")) & 1;
});
jQuery.find = find;
jQuery.expr[":"] = jQuery.expr.pseudos;
jQuery.unique = jQuery.uniqueSort;
find.compile = compile;
find.select = select;
find.setDocument = setDocument;
find.tokenize = tokenize;
find.escape = jQuery.escapeSelector;
find.getText = jQuery.text;
find.isXML = jQuery.isXMLDoc;
find.selectors = jQuery.expr;
find.support = jQuery.support;
find.uniqueSort = jQuery.uniqueSort;
})();
var dir = function(elem, dir, until) {
var matched = [], truncate = until !== void 0;
while ((elem = elem[dir]) && elem.nodeType !== 9) if (elem.nodeType === 1) {
if (truncate && jQuery(elem).is(until)) break;
matched.push(elem);
}
return matched;
};
var siblings = function(n, elem) {
var matched = [];
for (; n; n = n.nextSibling) if (n.nodeType === 1 && n !== elem) matched.push(n);
return matched;
};
var rneedsContext = jQuery.expr.match.needsContext;
var rsingleTag = /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;
function winnow(elements, qualifier, not) {
if (isFunction(qualifier)) return jQuery.grep(elements, function(elem, i) {
return !!qualifier.call(elem, i, elem) !== not;
});
if (qualifier.nodeType) return jQuery.grep(elements, function(elem) {
return elem === qualifier !== not;
});
if (typeof qualifier !== "string") return jQuery.grep(elements, function(elem) {
return indexOf.call(qualifier, elem) > -1 !== not;
});
return jQuery.filter(qualifier, elements, not);
}
jQuery.filter = function(expr, elems, not) {
var elem = elems[0];
if (not) expr = ":not(" + expr + ")";
if (elems.length === 1 && elem.nodeType === 1) return jQuery.find.matchesSelector(elem, expr) ? [elem] : [];
return jQuery.find.matches(expr, jQuery.grep(elems, function(elem) {
return elem.nodeType === 1;
}));
};
jQuery.fn.extend({
find: function(selector) {
var i, ret, len = this.length, self = this;
if (typeof selector !== "string") return this.pushStack(jQuery(selector).filter(function() {
for (i = 0; i < len; i++) if (jQuery.contains(self[i], this)) return true;
}));
ret = this.pushStack([]);
for (i = 0; i < len; i++) jQuery.find(selector, self[i], ret);
return len > 1 ? jQuery.uniqueSort(ret) : ret;
},
filter: function(selector) {
return this.pushStack(winnow(this, selector || [], false));
},
not: function(selector) {
return this.pushStack(winnow(this, selector || [], true));
},
is: function(selector) {
return !!winnow(this, typeof selector === "string" && rneedsContext.test(selector) ? jQuery(selector) : selector || [], false).length;
}
});
var rootjQuery, rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, init = jQuery.fn.init = function(selector, context, root) {
var match, elem;
if (!selector) return this;
root = root || rootjQuery;
if (typeof selector === "string") {
if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) match = [
null,
selector,
null
];
else match = rquickExpr.exec(selector);
if (match && (match[1] || !context)) if (match[1]) {
context = context instanceof jQuery ? context[0] : context;
jQuery.merge(this, jQuery.parseHTML(match[1], context && context.nodeType ? context.ownerDocument || context : document, true));
if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) for (match in context) if (isFunction(this[match])) this[match](context[match]);
else this.attr(match, context[match]);
return this;
} else {
elem = document.getElementById(match[2]);
if (elem) {
this[0] = elem;
this.length = 1;
}
return this;
}
else if (!context || context.jquery) return (context || root).find(selector);
else return this.constructor(context).find(selector);
} else if (selector.nodeType) {
this[0] = selector;
this.length = 1;
return this;
} else if (isFunction(selector)) return root.ready !== void 0 ? root.ready(selector) : selector(jQuery);
return jQuery.makeArray(selector, this);
};
init.prototype = jQuery.fn;
rootjQuery = jQuery(document);
var rparentsprev = /^(?:parents|prev(?:Until|All))/, guaranteedUnique = {
children: true,
contents: true,
next: true,
prev: true
};
jQuery.fn.extend({
has: function(target) {
var targets = jQuery(target, this), l = targets.length;
return this.filter(function() {
var i = 0;
for (; i < l; i++) if (jQuery.contains(this, targets[i])) return true;
});
},
closest: function(selectors, context) {
var cur, i = 0, l = this.length, matched = [], targets = typeof selectors !== "string" && jQuery(selectors);
if (!rneedsContext.test(selectors)) {
for (; i < l; i++) for (cur = this[i]; cur && cur !== context; cur = cur.parentNode) if (cur.nodeType < 11 && (targets ? targets.index(cur) > -1 : cur.nodeType === 1 && jQuery.find.matchesSelector(cur, selectors))) {
matched.push(cur);
break;
}
}
return this.pushStack(matched.length > 1 ? jQuery.uniqueSort(matched) : matched);
},
index: function(elem) {
if (!elem) return this[0] && this[0].parentNode ? this.first().prevAll().length : -1;
if (typeof elem === "string") return indexOf.call(jQuery(elem), this[0]);
return indexOf.call(this, elem.jquery ? elem[0] : elem);
},
add: function(selector, context) {
return this.pushStack(jQuery.uniqueSort(jQuery.merge(this.get(), jQuery(selector, context))));
},
addBack: function(selector) {
return this.add(selector == null ? this.prevObject : this.prevObject.filter(selector));
}
});
function sibling(cur, dir) {
while ((cur = cur[dir]) && cur.nodeType !== 1);
return cur;
}
jQuery.each({
parent: function(elem) {
var parent = elem.parentNode;
return parent && parent.nodeType !== 11 ? parent : null;
},
parents: function(elem) {
return dir(elem, "parentNode");
},
parentsUntil: function(elem, _i, until) {
return dir(elem, "parentNode", until);
},
next: function(elem) {
return sibling(elem, "nextSibling");
},
prev: function(elem) {
return sibling(elem, "previousSibling");
},
nextAll: function(elem) {
return dir(elem, "nextSibling");
},
prevAll: function(elem) {
return dir(elem, "previousSibling");
},
nextUntil: function(elem, _i, until) {
return dir(elem, "nextSibling", until);
},
prevUntil: function(elem, _i, until) {
return dir(elem, "previousSibling", until);
},
siblings: function(elem) {
return siblings((elem.parentNode || {}).firstChild, elem);
},
children: function(elem) {
return siblings(elem.firstChild);
},
contents: function(elem) {
if (elem.contentDocument != null && getProto(elem.contentDocument)) return elem.contentDocument;
if (nodeName(elem, "template")) elem = elem.content || elem;
return jQuery.merge([], elem.childNodes);
}
}, function(name, fn) {
jQuery.fn[name] = function(until, selector) {
var matched = jQuery.map(this, fn, until);
if (name.slice(-5) !== "Until") selector = until;
if (selector && typeof selector === "string") matched = jQuery.filter(selector, matched);
if (this.length > 1) {
if (!guaranteedUnique[name]) jQuery.uniqueSort(matched);
if (rparentsprev.test(name)) matched.reverse();
}
return this.pushStack(matched);
};
});
var rnothtmlwhite = /[^\x20\t\r\n\f]+/g;
function createOptions(options) {
var object = {};
jQuery.each(options.match(rnothtmlwhite) || [], function(_, flag) {
object[flag] = true;
});
return object;
}
jQuery.Callbacks = function(options) {
options = typeof options === "string" ? createOptions(options) : jQuery.extend({}, options);
var firing, memory, fired, locked, list = [], queue = [], firingIndex = -1, fire = function() {
locked = locked || options.once;
fired = firing = true;
for (; queue.length; firingIndex = -1) {
memory = queue.shift();
while (++firingIndex < list.length) if (list[firingIndex].apply(memory[0], memory[1]) === false && options.stopOnFalse) {
firingIndex = list.length;
memory = false;
}
}
if (!options.memory) memory = false;
firing = false;
if (locked) if (memory) list = [];
else list = "";
}, self = {
add: function() {
if (list) {
if (memory && !firing) {
firingIndex = list.length - 1;
queue.push(memory);
}
(function add(args) {
jQuery.each(args, function(_, arg) {
if (isFunction(arg)) {
if (!options.unique || !self.has(arg)) list.push(arg);
} else if (arg && arg.length && toType(arg) !== "string") add(arg);
});
})(arguments);
if (memory && !firing) fire();
}
return this;
},
remove: function() {
jQuery.each(arguments, function(_, arg) {
var index;
while ((index = jQuery.inArray(arg, list, index)) > -1) {
list.splice(index, 1);
if (index <= firingIndex) firingIndex--;
}
});
return this;
},
has: function(fn) {
return fn ? jQuery.inArray(fn, list) > -1 : list.length > 0;
},
empty: function() {
if (list) list = [];
return this;
},
disable: function() {
locked = queue = [];
list = memory = "";
return this;
},
disabled: function() {
return !list;
},
lock: function() {
locked = queue = [];
if (!memory && !firing) list = memory = "";
return this;
},
locked: function() {
return !!locked;
},
fireWith: function(context, args) {
if (!locked) {
args = args || [];
args = [context, args.slice ? args.slice() : args];
queue.push(args);
if (!firing) fire();
}
return this;
},
fire: function() {
self.fireWith(this, arguments);
return this;
},
fired: function() {
return !!fired;
}
};
return self;
};
function Identity(v) {
return v;
}
function Thrower(ex) {
throw ex;
}
function adoptValue(value, resolve, reject, noValue) {
var method;
try {
if (value && isFunction(method = value.promise)) method.call(value).done(resolve).fail(reject);
else if (value && isFunction(method = value.then)) method.call(value, resolve, reject);
else resolve.apply(void 0, [value].slice(noValue));
} catch (value) {
reject.apply(void 0, [value]);
}
}
jQuery.extend({
Deferred: function(func) {
var tuples = [
[
"notify",
"progress",
jQuery.Callbacks("memory"),
jQuery.Callbacks("memory"),
2
],
[
"resolve",
"done",
jQuery.Callbacks("once memory"),
jQuery.Callbacks("once memory"),
0,
"resolved"
],
[
"reject",
"fail",
jQuery.Callbacks("once memory"),
jQuery.Callbacks("once memory"),
1,
"rejected"
]
], state = "pending", promise = {
state: function() {
return state;
},
always: function() {
deferred.done(arguments).fail(arguments);
return this;
},
"catch": function(fn) {
return promise.then(null, fn);
},
pipe: function() {
var fns = arguments;
return jQuery.Deferred(function(newDefer) {
jQuery.each(tuples, function(_i, tuple) {
var fn = isFunction(fns[tuple[4]]) && fns[tuple[4]];
deferred[tuple[1]](function() {
var returned = fn && fn.apply(this, arguments);
if (returned && isFunction(returned.promise)) returned.promise().progress(newDefer.notify).done(newDefer.resolve).fail(newDefer.reject);
else newDefer[tuple[0] + "With"](this, fn ? [returned] : arguments);
});
});
fns = null;
}).promise();
},
then: function(onFulfilled, onRejected, onProgress) {
var maxDepth = 0;
function resolve(depth, deferred, handler, special) {
return function() {
var that = this, args = arguments, mightThrow = function() {
var returned, then;
if (depth < maxDepth) return;
returned = handler.apply(that, args);
if (returned === deferred.promise()) throw new TypeError("Thenable self-resolution");
then = returned && (typeof returned === "object" || typeof returned === "function") && returned.then;
if (isFunction(then)) if (special) then.call(returned, resolve(maxDepth, deferred, Identity, special), resolve(maxDepth, deferred, Thrower, special));
else {
maxDepth++;
then.call(returned, resolve(maxDepth, deferred, Identity, special), resolve(maxDepth, deferred, Thrower, special), resolve(maxDepth, deferred, Identity, deferred.notifyWith));
}
else {
if (handler !== Identity) {
that = void 0;
args = [returned];
}
(special || deferred.resolveWith)(that, args);
}
}, process = special ? mightThrow : function() {
try {
mightThrow();
} catch (e) {
if (jQuery.Deferred.exceptionHook) jQuery.Deferred.exceptionHook(e, process.error);
if (depth + 1 >= maxDepth) {
if (handler !== Thrower) {
that = void 0;
args = [e];
}
deferred.rejectWith(that, args);
}
}
};
if (depth) process();
else {
if (jQuery.Deferred.getErrorHook) process.error = jQuery.Deferred.getErrorHook();
else if (jQuery.Deferred.getStackHook) process.error = jQuery.Deferred.getStackHook();
window.setTimeout(process);
}
};
}
return jQuery.Deferred(function(newDefer) {
tuples[0][3].add(resolve(0, newDefer, isFunction(onProgress) ? onProgress : Identity, newDefer.notifyWith));
tuples[1][3].add(resolve(0, newDefer, isFunction(onFulfilled) ? onFulfilled : Identity));
tuples[2][3].add(resolve(0, newDefer, isFunction(onRejected) ? onRejected : Thrower));
}).promise();
},
promise: function(obj) {
return obj != null ? jQuery.extend(obj, promise) : promise;
}
}, deferred = {};
jQuery.each(tuples, function(i, tuple) {
var list = tuple[2], stateString = tuple[5];
promise[tuple[1]] = list.add;
if (stateString) list.add(function() {
state = stateString;
}, tuples[3 - i][2].disable, tuples[3 - i][3].disable, tuples[0][2].lock, tuples[0][3].lock);
list.add(tuple[3].fire);
deferred[tuple[0]] = function() {
deferred[tuple[0] + "With"](this === deferred ? void 0 : this, arguments);
return this;
};
deferred[tuple[0] + "With"] = list.fireWith;
});
promise.promise(deferred);
if (func) func.call(deferred, deferred);
return deferred;
},
when: function(singleValue) {
var remaining = arguments.length, i = remaining, resolveContexts = Array(i), resolveValues = slice.call(arguments), primary = jQuery.Deferred(), updateFunc = function(i) {
return function(value) {
resolveContexts[i] = this;
resolveValues[i] = arguments.length > 1 ? slice.call(arguments) : value;
if (!--remaining) primary.resolveWith(resolveContexts, resolveValues);
};
};
if (remaining <= 1) {
adoptValue(singleValue, primary.done(updateFunc(i)).resolve, primary.reject, !remaining);
if (primary.state() === "pending" || isFunction(resolveValues[i] && resolveValues[i].then)) return primary.then();
}
while (i--) adoptValue(resolveValues[i], updateFunc(i), primary.reject);
return primary.promise();
}
});
var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
jQuery.Deferred.exceptionHook = function(error, asyncError) {
if (window.console && window.console.warn && error && rerrorNames.test(error.name)) window.console.warn("jQuery.Deferred exception: " + error.message, error.stack, asyncError);
};
jQuery.readyException = function(error) {
window.setTimeout(function() {
throw error;
});
};
var readyList = jQuery.Deferred();
jQuery.fn.ready = function(fn) {
readyList.then(fn).catch(function(error) {
jQuery.readyException(error);
});
return this;
};
jQuery.extend({
isReady: false,
readyWait: 1,
ready: function(wait) {
if (wait === true ? --jQuery.readyWait : jQuery.isReady) return;
jQuery.isReady = true;
if (wait !== true && --jQuery.readyWait > 0) return;
readyList.resolveWith(document, [jQuery]);
}
});
jQuery.ready.then = readyList.then;
function completed() {
document.removeEventListener("DOMContentLoaded", completed);
window.removeEventListener("load", completed);
jQuery.ready();
}
if (document.readyState === "complete" || document.readyState !== "loading" && !document.documentElement.doScroll) window.setTimeout(jQuery.ready);
else {
document.addEventListener("DOMContentLoaded", completed);
window.addEventListener("load", completed);
}
var access = function(elems, fn, key, value, chainable, emptyGet, raw) {
var i = 0, len = elems.length, bulk = key == null;
if (toType(key) === "object") {
chainable = true;
for (i in key) access(elems, fn, i, key[i], true, emptyGet, raw);
} else if (value !== void 0) {
chainable = true;
if (!isFunction(value)) raw = true;
if (bulk) if (raw) {
fn.call(elems, value);
fn = null;
} else {
bulk = fn;
fn = function(elem, _key, value) {
return bulk.call(jQuery(elem), value);
};
}
if (fn) for (; i < len; i++) fn(elems[i], key, raw ? value : value.call(elems[i], i, fn(elems[i], key)));
}
if (chainable) return elems;
if (bulk) return fn.call(elems);
return len ? fn(elems[0], key) : emptyGet;
};
var rmsPrefix = /^-ms-/, rdashAlpha = /-([a-z])/g;
function fcamelCase(_all, letter) {
return letter.toUpperCase();
}
function camelCase(string) {
return string.replace(rmsPrefix, "ms-").replace(rdashAlpha, fcamelCase);
}
var acceptData = function(owner) {
return owner.nodeType === 1 || owner.nodeType === 9 || !+owner.nodeType;
};
function Data() {
this.expando = jQuery.expando + Data.uid++;
}
Data.uid = 1;
Data.prototype = {
cache: function(owner) {
var value = owner[this.expando];
if (!value) {
value = {};
if (acceptData(owner)) if (owner.nodeType) owner[this.expando] = value;
else Object.defineProperty(owner, this.expando, {
value,
configurable: true
});
}
return value;
},
set: function(owner, data, value) {
var prop, cache = this.cache(owner);
if (typeof data === "string") cache[camelCase(data)] = value;
else for (prop in data) cache[camelCase(prop)] = data[prop];
return cache;
},
get: function(owner, key) {
return key === void 0 ? this.cache(owner) : owner[this.expando] && owner[this.expando][camelCase(key)];
},
access: function(owner, key, value) {
if (key === void 0 || key && typeof key === "string" && value === void 0) return this.get(owner, key);
this.set(owner, key, value);
return value !== void 0 ? value : key;
},
remove: function(owner, key) {
var i, cache = owner[this.expando];
if (cache === void 0) return;
if (key !== void 0) {
if (Array.isArray(key)) key = key.map(camelCase);
else {
key = camelCase(key);
key = key in cache ? [key] : key.match(rnothtmlwhite) || [];
}
i = key.length;
while (i--) delete cache[key[i]];
}
if (key === void 0 || jQuery.isEmptyObject(cache)) if (owner.nodeType) owner[this.expando] = void 0;
else delete owner[this.expando];
},
hasData: function(owner) {
var cache = owner[this.expando];
return cache !== void 0 && !jQuery.isEmptyObject(cache);
}
};
var dataPriv = new Data();
var dataUser = new Data();
var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, rmultiDash = /[A-Z]/g;
function getData(data) {
if (data === "true") return true;
if (data === "false") return false;
if (data === "null") return null;
if (data === +data + "") return +data;
if (rbrace.test(data)) return JSON.parse(data);
return data;
}
function dataAttr(elem, key, data) {
var name;
if (data === void 0 && elem.nodeType === 1) {
name = "data-" + key.replace(rmultiDash, "-$&").toLowerCase();
data = elem.getAttribute(name);
if (typeof data === "string") {
try {
data = getData(data);
} catch (e) {}
dataUser.set(elem, key, data);
} else data = void 0;
}
return data;
}
jQuery.extend({
hasData: function(elem) {
return dataUser.hasData(elem) || dataPriv.hasData(elem);
},
data: function(elem, name, data) {
return dataUser.access(elem, name, data);
},
removeData: function(elem, name) {
dataUser.remove(elem, name);
},
_data: function(elem, name, data) {
return dataPriv.access(elem, name, data);
},
_removeData: function(elem, name) {
dataPriv.remove(elem, name);
}
});
jQuery.fn.extend({
data: function(key, value) {
var i, name, data, elem = this[0], attrs = elem && elem.attributes;
if (key === void 0) {
if (this.length) {
data = dataUser.get(elem);
if (elem.nodeType === 1 && !dataPriv.get(elem, "hasDataAttrs")) {
i = attrs.length;
while (i--) if (attrs[i]) {
name = attrs[i].name;
if (name.indexOf("data-") === 0) {
name = camelCase(name.slice(5));
dataAttr(elem, name, data[name]);
}
}
dataPriv.set(elem, "hasDataAttrs", true);
}
}
return data;
}
if (typeof key === "object") return this.each(function() {
dataUser.set(this, key);
});
return access(this, function(value) {
var data;
if (elem && value === void 0) {
data = dataUser.get(elem, key);
if (data !== void 0) return data;
data = dataAttr(elem, key);
if (data !== void 0) return data;
return;
}
this.each(function() {
dataUser.set(this, key, value);
});
}, null, value, arguments.length > 1, null, true);
},
removeData: function(key) {
return this.each(function() {
dataUser.remove(this, key);
});
}
});
jQuery.extend({
queue: function(elem, type, data) {
var queue;
if (elem) {
type = (type || "fx") + "queue";
queue = dataPriv.get(elem, type);
if (data) if (!queue || Array.isArray(data)) queue = dataPriv.access(elem, type, jQuery.makeArray(data));
else queue.push(data);
return queue || [];
}
},
dequeue: function(elem, type) {
type = type || "fx";
var queue = jQuery.queue(elem, type), startLength = queue.length, fn = queue.shift(), hooks = jQuery._queueHooks(elem, type), next = function() {
jQuery.dequeue(elem, type);
};
if (fn === "inprogress") {
fn = queue.shift();
startLength--;
}
if (fn) {
if (type === "fx") queue.unshift("inprogress");
delete hooks.stop;
fn.call(elem, next, hooks);
}
if (!startLength && hooks) hooks.empty.fire();
},
_queueHooks: function(elem, type) {
var key = type + "queueHooks";
return dataPriv.get(elem, key) || dataPriv.access(elem, key, { empty: jQuery.Callbacks("once memory").add(function() {
dataPriv.remove(elem, [type + "queue", key]);
}) });
}
});
jQuery.fn.extend({
queue: function(type, data) {
var setter = 2;
if (typeof type !== "string") {
data = type;
type = "fx";
setter--;
}
if (arguments.length < setter) return jQuery.queue(this[0], type);
return data === void 0 ? this : this.each(function() {
var queue = jQuery.queue(this, type, data);
jQuery._queueHooks(this, type);
if (type === "fx" && queue[0] !== "inprogress") jQuery.dequeue(this, type);
});
},
dequeue: function(type) {
return this.each(function() {
jQuery.dequeue(this, type);
});
},
clearQueue: function(type) {
return this.queue(type || "fx", []);
},
promise: function(type, obj) {
var tmp, count = 1, defer = jQuery.Deferred(), elements = this, i = this.length, resolve = function() {
if (!--count) defer.resolveWith(elements, [elements]);
};
if (typeof type !== "string") {
obj = type;
type = void 0;
}
type = type || "fx";
while (i--) {
tmp = dataPriv.get(elements[i], type + "queueHooks");
if (tmp && tmp.empty) {
count++;
tmp.empty.add(resolve);
}
}
resolve();
return defer.promise(obj);
}
});
var pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source;
var rcssNum = new RegExp("^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i");
var cssExpand = [
"Top",
"Right",
"Bottom",
"Left"
];
var documentElement = document.documentElement;
var isAttached = function(elem) {
return jQuery.contains(elem.ownerDocument, elem);
}, composed = { composed: true };
if (documentElement.getRootNode) isAttached = function(elem) {
return jQuery.contains(elem.ownerDocument, elem) || elem.getRootNode(composed) === elem.ownerDocument;
};
var isHiddenWithinTree = function(elem, el) {
elem = el || elem;
return elem.style.display === "none" || elem.style.display === "" && isAttached(elem) && jQuery.css(elem, "display") === "none";
};
function adjustCSS(elem, prop, valueParts, tween) {
var adjusted, scale, maxIterations = 20, currentValue = tween ? function() {
return tween.cur();
} : function() {
return jQuery.css(elem, prop, "");
}, initial = currentValue(), unit = valueParts && valueParts[3] || (jQuery.cssNumber[prop] ? "" : "px"), initialInUnit = elem.nodeType && (jQuery.cssNumber[prop] || unit !== "px" && +initial) && rcssNum.exec(jQuery.css(elem, prop));
if (initialInUnit && initialInUnit[3] !== unit) {
initial = initial / 2;
unit = unit || initialInUnit[3];
initialInUnit = +initial || 1;
while (maxIterations--) {
jQuery.style(elem, prop, initialInUnit + unit);
if ((1 - scale) * (1 - (scale = currentValue() / initial || .5)) <= 0) maxIterations = 0;
initialInUnit = initialInUnit / scale;
}
initialInUnit = initialInUnit * 2;
jQuery.style(elem, prop, initialInUnit + unit);
valueParts = valueParts || [];
}
if (valueParts) {
initialInUnit = +initialInUnit || +initial || 0;
adjusted = valueParts[1] ? initialInUnit + (valueParts[1] + 1) * valueParts[2] : +valueParts[2];
if (tween) {
tween.unit = unit;
tween.start = initialInUnit;
tween.end = adjusted;
}
}
return adjusted;
}
var defaultDisplayMap = {};
function getDefaultDisplay(elem) {
var temp, doc = elem.ownerDocument, nodeName = elem.nodeName, display = defaultDisplayMap[nodeName];
if (display) return display;
temp = doc.body.appendChild(doc.createElement(nodeName));
display = jQuery.css(temp, "display");
temp.parentNode.removeChild(temp);
if (display === "none") display = "block";
defaultDisplayMap[nodeName] = display;
return display;
}
function showHide(elements, show) {
var display, elem, values = [], index = 0, length = elements.length;
for (; index < length; index++) {
elem = elements[index];
if (!elem.style) continue;
display = elem.style.display;
if (show) {
if (display === "none") {
values[index] = dataPriv.get(elem, "display") || null;
if (!values[index]) elem.style.display = "";
}
if (elem.style.display === "" && isHiddenWithinTree(elem)) values[index] = getDefaultDisplay(elem);
} else if (display !== "none") {
values[index] = "none";
dataPriv.set(elem, "display", display);
}
}
for (index = 0; index < length; index++) if (values[index] != null) elements[index].style.display = values[index];
return elements;
}
jQuery.fn.extend({
show: function() {
return showHide(this, true);
},
hide: function() {
return showHide(this);
},
toggle: function(state) {
if (typeof state === "boolean") return state ? this.show() : this.hide();
return this.each(function() {
if (isHiddenWithinTree(this)) jQuery(this).show();
else jQuery(this).hide();
});
}
});
var rcheckableType = /^(?:checkbox|radio)$/i;
var rtagName = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i;
var rscriptType = /^$|^module$|\/(?:java|ecma)script/i;
(function() {
var div = document.createDocumentFragment().appendChild(document.createElement("div")), input = document.createElement("input");
input.setAttribute("type", "radio");
input.setAttribute("checked", "checked");
input.setAttribute("name", "t");
div.appendChild(input);
support.checkClone = div.cloneNode(true).cloneNode(true).lastChild.checked;
div.innerHTML = "<textarea>x</textarea>";
support.noCloneChecked = !!div.cloneNode(true).lastChild.defaultValue;
div.innerHTML = "<option></option>";
support.option = !!div.lastChild;
})();
var wrapMap = {
thead: [
1,
"<table>",
"</table>"
],
col: [
2,
"<table><colgroup>",
"</colgroup></table>"
],
tr: [
2,
"<table><tbody>",
"</tbody></table>"
],
td: [
3,
"<table><tbody><tr>",
"</tr></tbody></table>"
],
_default: [
0,
"",
""
]
};
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;
if (!support.option) wrapMap.optgroup = wrapMap.option = [
1,
"<select multiple='multiple'>",
"</select>"
];
function getAll(context, tag) {
var ret;
if (typeof context.getElementsByTagName !== "undefined") ret = context.getElementsByTagName(tag || "*");
else if (typeof context.querySelectorAll !== "undefined") ret = context.querySelectorAll(tag || "*");
else ret = [];
if (tag === void 0 || tag && nodeName(context, tag)) return jQuery.merge([context], ret);
return ret;
}
function setGlobalEval(elems, refElements) {
var i = 0, l = elems.length;
for (; i < l; i++) dataPriv.set(elems[i], "globalEval", !refElements || dataPriv.get(refElements[i], "globalEval"));
}
var rhtml = /<|&#?\w+;/;
function buildFragment(elems, context, scripts, selection, ignored) {
var elem, tmp, tag, wrap, attached, j, fragment = context.createDocumentFragment(), nodes = [], i = 0, l = elems.length;
for (; i < l; i++) {
elem = elems[i];
if (elem || elem === 0) if (toType(elem) === "object") jQuery.merge(nodes, elem.nodeType ? [elem] : elem);
else if (!rhtml.test(elem)) nodes.push(context.createTextNode(elem));
else {
tmp = tmp || fragment.appendChild(context.createElement("div"));
tag = (rtagName.exec(elem) || ["", ""])[1].toLowerCase();
wrap = wrapMap[tag] || wrapMap._default;
tmp.innerHTML = wrap[1] + jQuery.htmlPrefilter(elem) + wrap[2];
j = wrap[0];
while (j--) tmp = tmp.lastChild;
jQuery.merge(nodes, tmp.childNodes);
tmp = fragment.firstChild;
tmp.textContent = "";
}
}
fragment.textContent = "";
i = 0;
while (elem = nodes[i++]) {
if (selection && jQuery.inArray(elem, selection) > -1) {
if (ignored) ignored.push(elem);
continue;
}
attached = isAttached(elem);
tmp = getAll(fragment.appendChild(elem), "script");
if (attached) setGlobalEval(tmp);
if (scripts) {
j = 0;
while (elem = tmp[j++]) if (rscriptType.test(elem.type || "")) scripts.push(elem);
}
}
return fragment;
}
var rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
function returnTrue() {
return true;
}
function returnFalse() {
return false;
}
function on(elem, types, selector, data, fn, one) {
var origFn, type;
if (typeof types === "object") {
if (typeof selector !== "string") {
data = data || selector;
selector = void 0;
}
for (type in types) on(elem, type, selector, data, types[type], one);
return elem;
}
if (data == null && fn == null) {
fn = selector;
data = selector = void 0;
} else if (fn == null) if (typeof selector === "string") {
fn = data;
data = void 0;
} else {
fn = data;
data = selector;
selector = void 0;
}
if (fn === false) fn = returnFalse;
else if (!fn) return elem;
if (one === 1) {
origFn = fn;
fn = function(event) {
jQuery().off(event);
return origFn.apply(this, arguments);
};
fn.guid = origFn.guid || (origFn.guid = jQuery.guid++);
}
return elem.each(function() {
jQuery.event.add(this, types, fn, data, selector);
});
}
jQuery.event = {
global: {},
add: function(elem, types, handler, data, selector) {
var handleObjIn, eventHandle, tmp, events, t, handleObj, special, handlers, type, namespaces, origType, elemData = dataPriv.get(elem);
if (!acceptData(elem)) return;
if (handler.handler) {
handleObjIn = handler;
handler = handleObjIn.handler;
selector = handleObjIn.selector;
}
if (selector) jQuery.find.matchesSelector(documentElement, selector);
if (!handler.guid) handler.guid = jQuery.guid++;
if (!(events = elemData.events)) events = elemData.events = Object.create(null);
if (!(eventHandle = elemData.handle)) eventHandle = elemData.handle = function(e) {
return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? jQuery.event.dispatch.apply(elem, arguments) : void 0;
};
types = (types || "").match(rnothtmlwhite) || [""];
t = types.length;
while (t--) {
tmp = rtypenamespace.exec(types[t]) || [];
type = origType = tmp[1];
namespaces = (tmp[2] || "").split(".").sort();
if (!type) continue;
special = jQuery.event.special[type] || {};
type = (selector ? special.delegateType : special.bindType) || type;
special = jQuery.event.special[type] || {};
handleObj = jQuery.extend({
type,
origType,
data,
handler,
guid: handler.guid,
selector,
needsContext: selector && jQuery.expr.match.needsContext.test(selector),
namespace: namespaces.join(".")
}, handleObjIn);
if (!(handlers = events[type])) {
handlers = events[type] = [];
handlers.delegateCount = 0;
if (!special.setup || special.setup.call(elem, data, namespaces, eventHandle) === false) {
if (elem.addEventListener) elem.addEventListener(type, eventHandle);
}
}
if (special.add) {
special.add.call(elem, handleObj);
if (!handleObj.handler.guid) handleObj.handler.guid = handler.guid;
}
if (selector) handlers.splice(handlers.delegateCount++, 0, handleObj);
else handlers.push(handleObj);
jQuery.event.global[type] = true;
}
},
remove: function(elem, types, handler, selector, mappedTypes) {
var j, origCount, tmp, events, t, handleObj, special, handlers, type, namespaces, origType, elemData = dataPriv.hasData(elem) && dataPriv.get(elem);
if (!elemData || !(events = elemData.events)) return;
types = (types || "").match(rnothtmlwhite) || [""];
t = types.length;
while (t--) {
tmp = rtypenamespace.exec(types[t]) || [];
type = origType = tmp[1];
namespaces = (tmp[2] || "").split(".").sort();
if (!type) {
for (type in events) jQuery.event.remove(elem, type + types[t], handler, selector, true);
continue;
}
special = jQuery.event.special[type] || {};
type = (selector ? special.delegateType : special.bindType) || type;
handlers = events[type] || [];
tmp = tmp[2] && new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)");
origCount = j = handlers.length;
while (j--) {
handleObj = handlers[j];
if ((mappedTypes || origType === handleObj.origType) && (!handler || handler.guid === handleObj.guid) && (!tmp || tmp.test(handleObj.namespace)) && (!selector || selector === handleObj.selector || selector === "**" && handleObj.selector)) {
handlers.splice(j, 1);
if (handleObj.selector) handlers.delegateCount--;
if (special.remove) special.remove.call(elem, handleObj);
}
}
if (origCount && !handlers.length) {
if (!special.teardown || special.teardown.call(elem, namespaces, elemData.handle) === false) jQuery.removeEvent(elem, type, elemData.handle);
delete events[type];
}
}
if (jQuery.isEmptyObject(events)) dataPriv.remove(elem, "handle events");
},
dispatch: function(nativeEvent) {
var i, j, ret, matched, handleObj, handlerQueue, args = new Array(arguments.length), event = jQuery.event.fix(nativeEvent), handlers = (dataPriv.get(this, "events") || Object.create(null))[event.type] || [], special = jQuery.event.special[event.type] || {};
args[0] = event;
for (i = 1; i < arguments.length; i++) args[i] = arguments[i];
event.delegateTarget = this;
if (special.preDispatch && special.preDispatch.call(this, event) === false) return;
handlerQueue = jQuery.event.handlers.call(this, event, handlers);
i = 0;
while ((matched = handlerQueue[i++]) && !event.isPropagationStopped()) {
event.currentTarget = matched.elem;
j = 0;
while ((handleObj = matched.handlers[j++]) && !event.isImmediatePropagationStopped()) if (!event.rnamespace || handleObj.namespace === false || event.rnamespace.test(handleObj.namespace)) {
event.handleObj = handleObj;
event.data = handleObj.data;
ret = ((jQuery.event.special[handleObj.origType] || {}).handle || handleObj.handler).apply(matched.elem, args);
if (ret !== void 0) {
if ((event.result = ret) === false) {
event.preventDefault();
event.stopPropagation();
}
}
}
}
if (special.postDispatch) special.postDispatch.call(this, event);
return event.result;
},
handlers: function(event, handlers) {
var i, handleObj, sel, matchedHandlers, matchedSelectors, handlerQueue = [], delegateCount = handlers.delegateCount, cur = event.target;
if (delegateCount && cur.nodeType && !(event.type === "click" && event.button >= 1)) {
for (; cur !== this; cur = cur.parentNode || this) if (cur.nodeType === 1 && !(event.type === "click" && cur.disabled === true)) {
matchedHandlers = [];
matchedSelectors = {};
for (i = 0; i < delegateCount; i++) {
handleObj = handlers[i];
sel = handleObj.selector + " ";
if (matchedSelectors[sel] === void 0) matchedSelectors[sel] = handleObj.needsContext ? jQuery(sel, this).index(cur) > -1 : jQuery.find(sel, this, null, [cur]).length;
if (matchedSelectors[sel]) matchedHandlers.push(handleObj);
}
if (matchedHandlers.length) handlerQueue.push({
elem: cur,
handlers: matchedHandlers
});
}
}
cur = this;
if (delegateCount < handlers.length) handlerQueue.push({
elem: cur,
handlers: handlers.slice(delegateCount)
});
return handlerQueue;
},
addProp: function(name, hook) {
Object.defineProperty(jQuery.Event.prototype, name, {
enumerable: true,
configurable: true,
get: isFunction(hook) ? function() {
if (this.originalEvent) return hook(this.originalEvent);
} : function() {
if (this.originalEvent) return this.originalEvent[name];
},
set: function(value) {
Object.defineProperty(this, name, {
enumerable: true,
configurable: true,
writable: true,
value
});
}
});
},
fix: function(originalEvent) {
return originalEvent[jQuery.expando] ? originalEvent : new jQuery.Event(originalEvent);
},
special: {
load: { noBubble: true },
click: {
setup: function(data) {
var el = this || data;
if (rcheckableType.test(el.type) && el.click && nodeName(el, "input")) leverageNative(el, "click", true);
return false;
},
trigger: function(data) {
var el = this || data;
if (rcheckableType.test(el.type) && el.click && nodeName(el, "input")) leverageNative(el, "click");
return true;
},
_default: function(event) {
var target = event.target;
return rcheckableType.test(target.type) && target.click && nodeName(target, "input") && dataPriv.get(target, "click") || nodeName(target, "a");
}
},
beforeunload: { postDispatch: function(event) {
if (event.result !== void 0 && event.originalEvent) event.originalEvent.returnValue = event.result;
} }
}
};
function leverageNative(el, type, isSetup) {
if (!isSetup) {
if (dataPriv.get(el, type) === void 0) jQuery.event.add(el, type, returnTrue);
return;
}
dataPriv.set(el, type, false);
jQuery.event.add(el, type, {
namespace: false,
handler: function(event) {
var result, saved = dataPriv.get(this, type);
if (event.isTrigger & 1 && this[type]) {
if (!saved) {
saved = slice.call(arguments);
dataPriv.set(this, type, saved);
this[type]();
result = dataPriv.get(this, type);
dataPriv.set(this, type, false);
if (saved !== result) {
event.stopImmediatePropagation();
event.preventDefault();
return result;
}
} else if ((jQuery.event.special[type] || {}).delegateType) event.stopPropagation();
} else if (saved) {
dataPriv.set(this, type, jQuery.event.trigger(saved[0], saved.slice(1), this));
event.stopPropagation();
event.isImmediatePropagationStopped = returnTrue;
}
}
});
}
jQuery.removeEvent = function(elem, type, handle) {
if (elem.removeEventListener) elem.removeEventListener(type, handle);
};
jQuery.Event = function(src, props) {
if (!(this instanceof jQuery.Event)) return new jQuery.Event(src, props);
if (src && src.type) {
this.originalEvent = src;
this.type = src.type;
this.isDefaultPrevented = src.defaultPrevented || src.defaultPrevented === void 0 && src.returnValue === false ? returnTrue : returnFalse;
this.target = src.target && src.target.nodeType === 3 ? src.target.parentNode : src.target;
this.currentTarget = src.currentTarget;
this.relatedTarget = src.relatedTarget;
} else this.type = src;
if (props) jQuery.extend(this, props);
this.timeStamp = src && src.timeStamp || Date.now();
this[jQuery.expando] = true;
};
jQuery.Event.prototype = {
constructor: jQuery.Event,
isDefaultPrevented: returnFalse,
isPropagationStopped: returnFalse,
isImmediatePropagationStopped: returnFalse,
isSimulated: false,
preventDefault: function() {
var e = this.originalEvent;
this.isDefaultPrevented = returnTrue;
if (e && !this.isSimulated) e.preventDefault();
},
stopPropagation: function() {
var e = this.originalEvent;
this.isPropagationStopped = returnTrue;
if (e && !this.isSimulated) e.stopPropagation();
},
stopImmediatePropagation: function() {
var e = this.originalEvent;
this.isImmediatePropagationStopped = returnTrue;
if (e && !this.isSimulated) e.stopImmediatePropagation();
this.stopPropagation();
}
};
jQuery.each({
altKey: true,
bubbles: true,
cancelable: true,
changedTouches: true,
ctrlKey: true,
detail: true,
eventPhase: true,
metaKey: true,
pageX: true,
pageY: true,
shiftKey: true,
view: true,
"char": true,
code: true,
charCode: true,
key: true,
keyCode: true,
button: true,
buttons: true,
clientX: true,
clientY: true,
offsetX: true,
offsetY: true,
pointerId: true,
pointerType: true,
screenX: true,
screenY: true,
targetTouches: true,
toElement: true,
touches: true,
which: true
}, jQuery.event.addProp);
jQuery.each({
focus: "focusin",
blur: "focusout"
}, function(type, delegateType) {
function focusMappedHandler(nativeEvent) {
if (document.documentMode) {
var handle = dataPriv.get(this, "handle"), event = jQuery.event.fix(nativeEvent);
event.type = nativeEvent.type === "focusin" ? "focus" : "blur";
event.isSimulated = true;
handle(nativeEvent);
if (event.target === event.currentTarget) handle(event);
} else jQuery.event.simulate(delegateType, nativeEvent.target, jQuery.event.fix(nativeEvent));
}
jQuery.event.special[type] = {
setup: function() {
var attaches;
leverageNative(this, type, true);
if (document.documentMode) {
attaches = dataPriv.get(this, delegateType);
if (!attaches) this.addEventListener(delegateType, focusMappedHandler);
dataPriv.set(this, delegateType, (attaches || 0) + 1);
} else return false;
},
trigger: function() {
leverageNative(this, type);
return true;
},
teardown: function() {
var attaches;
if (document.documentMode) {
attaches = dataPriv.get(this, delegateType) - 1;
if (!attaches) {
this.removeEventListener(delegateType, focusMappedHandler);
dataPriv.remove(this, delegateType);
} else dataPriv.set(this, delegateType, attaches);
} else return false;
},
_default: function(event) {
return dataPriv.get(event.target, type);
},
delegateType
};
jQuery.event.special[delegateType] = {
setup: function() {
var doc = this.ownerDocument || this.document || this, dataHolder = document.documentMode ? this : doc, attaches = dataPriv.get(dataHolder, delegateType);
if (!attaches) if (document.documentMode) this.addEventListener(delegateType, focusMappedHandler);
else doc.addEventListener(type, focusMappedHandler, true);
dataPriv.set(dataHolder, delegateType, (attaches || 0) + 1);
},
teardown: function() {
var doc = this.ownerDocument || this.document || this, dataHolder = document.documentMode ? this : doc, attaches = dataPriv.get(dataHolder, delegateType) - 1;
if (!attaches) {
if (document.documentMode) this.removeEventListener(delegateType, focusMappedHandler);
else doc.removeEventListener(type, focusMappedHandler, true);
dataPriv.remove(dataHolder, delegateType);
} else dataPriv.set(dataHolder, delegateType, attaches);
}
};
});
jQuery.each({
mouseenter: "mouseover",
mouseleave: "mouseout",
pointerenter: "pointerover",
pointerleave: "pointerout"
}, function(orig, fix) {
jQuery.event.special[orig] = {
delegateType: fix,
bindType: fix,
handle: function(event) {
var ret, target = this, related = event.relatedTarget, handleObj = event.handleObj;
if (!related || related !== target && !jQuery.contains(target, related)) {
event.type = handleObj.origType;
ret = handleObj.handler.apply(this, arguments);
event.type = fix;
}
return ret;
}
};
});
jQuery.fn.extend({
on: function(types, selector, data, fn) {
return on(this, types, selector, data, fn);
},
one: function(types, selector, data, fn) {
return on(this, types, selector, data, fn, 1);
},
off: function(types, selector, fn) {
var handleObj, type;
if (types && types.preventDefault && types.handleObj) {
handleObj = types.handleObj;
jQuery(types.delegateTarget).off(handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, handleObj.selector, handleObj.handler);
return this;
}
if (typeof types === "object") {
for (type in types) this.off(type, selector, types[type]);
return this;
}
if (selector === false || typeof selector === "function") {
fn = selector;
selector = void 0;
}
if (fn === false) fn = returnFalse;
return this.each(function() {
jQuery.event.remove(this, types, fn, selector);
});
}
});
var rnoInnerhtml = /<script|<style|<link/i, rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, rcleanScript = /^\s*<!\[CDATA\[|\]\]>\s*$/g;
function manipulationTarget(elem, content) {
if (nodeName(elem, "table") && nodeName(content.nodeType !== 11 ? content : content.firstChild, "tr")) return jQuery(elem).children("tbody")[0] || elem;
return elem;
}
function disableScript(elem) {
elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
return elem;
}
function restoreScript(elem) {
if ((elem.type || "").slice(0, 5) === "true/") elem.type = elem.type.slice(5);
else elem.removeAttribute("type");
return elem;
}
function cloneCopyEvent(src, dest) {
var i, l, type, pdataOld, udataOld, udataCur, events;
if (dest.nodeType !== 1) return;
if (dataPriv.hasData(src)) {
pdataOld = dataPriv.get(src);
events = pdataOld.events;
if (events) {
dataPriv.remove(dest, "handle events");
for (type in events) for (i = 0, l = events[type].length; i < l; i++) jQuery.event.add(dest, type, events[type][i]);
}
}
if (dataUser.hasData(src)) {
udataOld = dataUser.access(src);
udataCur = jQuery.extend({}, udataOld);
dataUser.set(dest, udataCur);
}
}
function fixInput(src, dest) {
var nodeName = dest.nodeName.toLowerCase();
if (nodeName === "input" && rcheckableType.test(src.type)) dest.checked = src.checked;
else if (nodeName === "input" || nodeName === "textarea") dest.defaultValue = src.defaultValue;
}
function domManip(collection, args, callback, ignored) {
args = flat(args);
var fragment, first, scripts, hasScripts, node, doc, i = 0, l = collection.length, iNoClone = l - 1, value = args[0], valueIsFunction = isFunction(value);
if (valueIsFunction || l > 1 && typeof value === "string" && !support.checkClone && rchecked.test(value)) return collection.each(function(index) {
var self = collection.eq(index);
if (valueIsFunction) args[0] = value.call(this, index, self.html());
domManip(self, args, callback, ignored);
});
if (l) {
fragment = buildFragment(args, collection[0].ownerDocument, false, collection, ignored);
first = fragment.firstChild;
if (fragment.childNodes.length === 1) fragment = first;
if (first || ignored) {
scripts = jQuery.map(getAll(fragment, "script"), disableScript);
hasScripts = scripts.length;
for (; i < l; i++) {
node = fragment;
if (i !== iNoClone) {
node = jQuery.clone(node, true, true);
if (hasScripts) jQuery.merge(scripts, getAll(node, "script"));
}
callback.call(collection[i], node, i);
}
if (hasScripts) {
doc = scripts[scripts.length - 1].ownerDocument;
jQuery.map(scripts, restoreScript);
for (i = 0; i < hasScripts; i++) {
node = scripts[i];
if (rscriptType.test(node.type || "") && !dataPriv.access(node, "globalEval") && jQuery.contains(doc, node)) if (node.src && (node.type || "").toLowerCase() !== "module") {
if (jQuery._evalUrl && !node.noModule) jQuery._evalUrl(node.src, { nonce: node.nonce || node.getAttribute("nonce") }, doc);
} else DOMEval(node.textContent.replace(rcleanScript, ""), node, doc);
}
}
}
}
return collection;
}
function remove(elem, selector, keepData) {
var node, nodes = selector ? jQuery.filter(selector, elem) : elem, i = 0;
for (; (node = nodes[i]) != null; i++) {
if (!keepData && node.nodeType === 1) jQuery.cleanData(getAll(node));
if (node.parentNode) {
if (keepData && isAttached(node)) setGlobalEval(getAll(node, "script"));
node.parentNode.removeChild(node);
}
}
return elem;
}
jQuery.extend({
htmlPrefilter: function(html) {
return html;
},
clone: function(elem, dataAndEvents, deepDataAndEvents) {
var i, l, srcElements, destElements, clone = elem.cloneNode(true), inPage = isAttached(elem);
if (!support.noCloneChecked && (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem)) {
destElements = getAll(clone);
srcElements = getAll(elem);
for (i = 0, l = srcElements.length; i < l; i++) fixInput(srcElements[i], destElements[i]);
}
if (dataAndEvents) if (deepDataAndEvents) {
srcElements = srcElements || getAll(elem);
destElements = destElements || getAll(clone);
for (i = 0, l = srcElements.length; i < l; i++) cloneCopyEvent(srcElements[i], destElements[i]);
} else cloneCopyEvent(elem, clone);
destElements = getAll(clone, "script");
if (destElements.length > 0) setGlobalEval(destElements, !inPage && getAll(elem, "script"));
return clone;
},
cleanData: function(elems) {
var data, elem, type, special = jQuery.event.special, i = 0;
for (; (elem = elems[i]) !== void 0; i++) if (acceptData(elem)) {
if (data = elem[dataPriv.expando]) {
if (data.events) for (type in data.events) if (special[type]) jQuery.event.remove(elem, type);
else jQuery.removeEvent(elem, type, data.handle);
elem[dataPriv.expando] = void 0;
}
if (elem[dataUser.expando]) elem[dataUser.expando] = void 0;
}
}
});
jQuery.fn.extend({
detach: function(selector) {
return remove(this, selector, true);
},
remove: function(selector) {
return remove(this, selector);
},
text: function(value) {
return access(this, function(value) {
return value === void 0 ? jQuery.text(this) : this.empty().each(function() {
if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) this.textContent = value;
});
}, null, value, arguments.length);
},
append: function() {
return domManip(this, arguments, function(elem) {
if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) manipulationTarget(this, elem).appendChild(elem);
});
},
prepend: function() {
return domManip(this, arguments, function(elem) {
if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) {
var target = manipulationTarget(this, elem);
target.insertBefore(elem, target.firstChild);
}
});
},
before: function() {
return domManip(this, arguments, function(elem) {
if (this.parentNode) this.parentNode.insertBefore(elem, this);
});
},
after: function() {
return domManip(this, arguments, function(elem) {
if (this.parentNode) this.parentNode.insertBefore(elem, this.nextSibling);
});
},
empty: function() {
var elem, i = 0;
for (; (elem = this[i]) != null; i++) if (elem.nodeType === 1) {
jQuery.cleanData(getAll(elem, false));
elem.textContent = "";
}
return this;
},
clone: function(dataAndEvents, deepDataAndEvents) {
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
return this.map(function() {
return jQuery.clone(this, dataAndEvents, deepDataAndEvents);
});
},
html: function(value) {
return access(this, function(value) {
var elem = this[0] || {}, i = 0, l = this.length;
if (value === void 0 && elem.nodeType === 1) return elem.innerHTML;
if (typeof value === "string" && !rnoInnerhtml.test(value) && !wrapMap[(rtagName.exec(value) || ["", ""])[1].toLowerCase()]) {
value = jQuery.htmlPrefilter(value);
try {
for (; i < l; i++) {
elem = this[i] || {};
if (elem.nodeType === 1) {
jQuery.cleanData(getAll(elem, false));
elem.innerHTML = value;
}
}
elem = 0;
} catch (e) {}
}
if (elem) this.empty().append(value);
}, null, value, arguments.length);
},
replaceWith: function() {
var ignored = [];
return domManip(this, arguments, function(elem) {
var parent = this.parentNode;
if (jQuery.inArray(this, ignored) < 0) {
jQuery.cleanData(getAll(this));
if (parent) parent.replaceChild(elem, this);
}
}, ignored);
}
});
jQuery.each({
appendTo: "append",
prependTo: "prepend",
insertBefore: "before",
insertAfter: "after",
replaceAll: "replaceWith"
}, function(name, original) {
jQuery.fn[name] = function(selector) {
var elems, ret = [], insert = jQuery(selector), last = insert.length - 1, i = 0;
for (; i <= last; i++) {
elems = i === last ? this : this.clone(true);
jQuery(insert[i])[original](elems);
push.apply(ret, elems.get());
}
return this.pushStack(ret);
};
});
var rnumnonpx = new RegExp("^(" + pnum + ")(?!px)[a-z%]+$", "i");
var rcustomProp = /^--/;
var getStyles = function(elem) {
var view = elem.ownerDocument.defaultView;
if (!view || !view.opener) view = window;
return view.getComputedStyle(elem);
};
var swap = function(elem, options, callback) {
var ret, name, old = {};
for (name in options) {
old[name] = elem.style[name];
elem.style[name] = options[name];
}
ret = callback.call(elem);
for (name in options) elem.style[name] = old[name];
return ret;
};
var rboxStyle = new RegExp(cssExpand.join("|"), "i");
(function() {
function computeStyleTests() {
if (!div) return;
container.style.cssText = "position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0";
div.style.cssText = "position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%";
documentElement.appendChild(container).appendChild(div);
var divStyle = window.getComputedStyle(div);
pixelPositionVal = divStyle.top !== "1%";
reliableMarginLeftVal = roundPixelMeasures(divStyle.marginLeft) === 12;
div.style.right = "60%";
pixelBoxStylesVal = roundPixelMeasures(divStyle.right) === 36;
boxSizingReliableVal = roundPixelMeasures(divStyle.width) === 36;
div.style.position = "absolute";
scrollboxSizeVal = roundPixelMeasures(div.offsetWidth / 3) === 12;
documentElement.removeChild(container);
div = null;
}
function roundPixelMeasures(measure) {
return Math.round(parseFloat(measure));
}
var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, reliableTrDimensionsVal, reliableMarginLeftVal, container = document.createElement("div"), div = document.createElement("div");
if (!div.style) return;
div.style.backgroundClip = "content-box";
div.cloneNode(true).style.backgroundClip = "";
support.clearCloneStyle = div.style.backgroundClip === "content-box";
jQuery.extend(support, {
boxSizingReliable: function() {
computeStyleTests();
return boxSizingReliableVal;
},
pixelBoxStyles: function() {
computeStyleTests();
return pixelBoxStylesVal;
},
pixelPosition: function() {
computeStyleTests();
return pixelPositionVal;
},
reliableMarginLeft: function() {
computeStyleTests();
return reliableMarginLeftVal;
},
scrollboxSize: function() {
computeStyleTests();
return scrollboxSizeVal;
},
reliableTrDimensions: function() {
var table, tr, trChild, trStyle;
if (reliableTrDimensionsVal == null) {
table = document.createElement("table");
tr = document.createElement("tr");
trChild = document.createElement("div");
table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate";
tr.style.cssText = "box-sizing:content-box;border:1px solid";
tr.style.height = "1px";
trChild.style.height = "9px";
trChild.style.display = "block";
documentElement.appendChild(table).appendChild(tr).appendChild(trChild);
trStyle = window.getComputedStyle(tr);
reliableTrDimensionsVal = parseInt(trStyle.height, 10) + parseInt(trStyle.borderTopWidth, 10) + parseInt(trStyle.borderBottomWidth, 10) === tr.offsetHeight;
documentElement.removeChild(table);
}
return reliableTrDimensionsVal;
}
});
})();
function curCSS(elem, name, computed) {
var width, minWidth, maxWidth, ret, isCustomProp = rcustomProp.test(name), style = elem.style;
computed = computed || getStyles(elem);
if (computed) {
ret = computed.getPropertyValue(name) || computed[name];
if (isCustomProp && ret) ret = ret.replace(rtrimCSS, "$1") || void 0;
if (ret === "" && !isAttached(elem)) ret = jQuery.style(elem, name);
if (!support.pixelBoxStyles() && rnumnonpx.test(ret) && rboxStyle.test(name)) {
width = style.width;
minWidth = style.minWidth;
maxWidth = style.maxWidth;
style.minWidth = style.maxWidth = style.width = ret;
ret = computed.width;
style.width = width;
style.minWidth = minWidth;
style.maxWidth = maxWidth;
}
}
return ret !== void 0 ? ret + "" : ret;
}
function addGetHookIf(conditionFn, hookFn) {
return { get: function() {
if (conditionFn()) {
delete this.get;
return;
}
return (this.get = hookFn).apply(this, arguments);
} };
}
var cssPrefixes = [
"Webkit",
"Moz",
"ms"
], emptyStyle = document.createElement("div").style, vendorProps = {};
function vendorPropName(name) {
var capName = name[0].toUpperCase() + name.slice(1), i = cssPrefixes.length;
while (i--) {
name = cssPrefixes[i] + capName;
if (name in emptyStyle) return name;
}
}
function finalPropName(name) {
var final = jQuery.cssProps[name] || vendorProps[name];
if (final) return final;
if (name in emptyStyle) return name;
return vendorProps[name] = vendorPropName(name) || name;
}
var rdisplayswap = /^(none|table(?!-c[ea]).+)/, cssShow = {
position: "absolute",
visibility: "hidden",
display: "block"
}, cssNormalTransform = {
letterSpacing: "0",
fontWeight: "400"
};
function setPositiveNumber(_elem, value, subtract) {
var matches = rcssNum.exec(value);
return matches ? Math.max(0, matches[2] - (subtract || 0)) + (matches[3] || "px") : value;
}
function boxModelAdjustment(elem, dimension, box, isBorderBox, styles, computedVal) {
var i = dimension === "width" ? 1 : 0, extra = 0, delta = 0, marginDelta = 0;
if (box === (isBorderBox ? "border" : "content")) return 0;
for (; i < 4; i += 2) {
if (box === "margin") marginDelta += jQuery.css(elem, box + cssExpand[i], true, styles);
if (!isBorderBox) {
delta += jQuery.css(elem, "padding" + cssExpand[i], true, styles);
if (box !== "padding") delta += jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles);
else extra += jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles);
} else {
if (box === "content") delta -= jQuery.css(elem, "padding" + cssExpand[i], true, styles);
if (box !== "margin") delta -= jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles);
}
}
if (!isBorderBox && computedVal >= 0) delta += Math.max(0, Math.ceil(elem["offset" + dimension[0].toUpperCase() + dimension.slice(1)] - computedVal - delta - extra - .5)) || 0;
return delta + marginDelta;
}
function getWidthOrHeight(elem, dimension, extra) {
var styles = getStyles(elem), isBorderBox = (!support.boxSizingReliable() || extra) && jQuery.css(elem, "boxSizing", false, styles) === "border-box", valueIsBorderBox = isBorderBox, val = curCSS(elem, dimension, styles), offsetProp = "offset" + dimension[0].toUpperCase() + dimension.slice(1);
if (rnumnonpx.test(val)) {
if (!extra) return val;
val = "auto";
}
if ((!support.boxSizingReliable() && isBorderBox || !support.reliableTrDimensions() && nodeName(elem, "tr") || val === "auto" || !parseFloat(val) && jQuery.css(elem, "display", false, styles) === "inline") && elem.getClientRects().length) {
isBorderBox = jQuery.css(elem, "boxSizing", false, styles) === "border-box";
valueIsBorderBox = offsetProp in elem;
if (valueIsBorderBox) val = elem[offsetProp];
}
val = parseFloat(val) || 0;
return val + boxModelAdjustment(elem, dimension, extra || (isBorderBox ? "border" : "content"), valueIsBorderBox, styles, val) + "px";
}
jQuery.extend({
cssHooks: { opacity: { get: function(elem, computed) {
if (computed) {
var ret = curCSS(elem, "opacity");
return ret === "" ? "1" : ret;
}
} } },
cssNumber: {
animationIterationCount: true,
aspectRatio: true,
borderImageSlice: true,
columnCount: true,
flexGrow: true,
flexShrink: true,
fontWeight: true,
gridArea: true,
gridColumn: true,
gridColumnEnd: true,
gridColumnStart: true,
gridRow: true,
gridRowEnd: true,
gridRowStart: true,
lineHeight: true,
opacity: true,
order: true,
orphans: true,
scale: true,
widows: true,
zIndex: true,
zoom: true,
fillOpacity: true,
floodOpacity: true,
stopOpacity: true,
strokeMiterlimit: true,
strokeOpacity: true
},
cssProps: {},
style: function(elem, name, value, extra) {
if (!elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style) return;
var ret, type, hooks, origName = camelCase(name), isCustomProp = rcustomProp.test(name), style = elem.style;
if (!isCustomProp) name = finalPropName(origName);
hooks = jQuery.cssHooks[name] || jQuery.cssHooks[origName];
if (value !== void 0) {
type = typeof value;
if (type === "string" && (ret = rcssNum.exec(value)) && ret[1]) {
value = adjustCSS(elem, name, ret);
type = "number";
}
if (value == null || value !== value) return;
if (type === "number" && !isCustomProp) value += ret && ret[3] || (jQuery.cssNumber[origName] ? "" : "px");
if (!support.clearCloneStyle && value === "" && name.indexOf("background") === 0) style[name] = "inherit";
if (!hooks || !("set" in hooks) || (value = hooks.set(elem, value, extra)) !== void 0) if (isCustomProp) style.setProperty(name, value);
else style[name] = value;
} else {
if (hooks && "get" in hooks && (ret = hooks.get(elem, false, extra)) !== void 0) return ret;
return style[name];
}
},
css: function(elem, name, extra, styles) {
var val, num, hooks, origName = camelCase(name);
if (!rcustomProp.test(name)) name = finalPropName(origName);
hooks = jQuery.cssHooks[name] || jQuery.cssHooks[origName];
if (hooks && "get" in hooks) val = hooks.get(elem, true, extra);
if (val === void 0) val = curCSS(elem, name, styles);
if (val === "normal" && name in cssNormalTransform) val = cssNormalTransform[name];
if (extra === "" || extra) {
num = parseFloat(val);
return extra === true || isFinite(num) ? num || 0 : val;
}
return val;
}
});
jQuery.each(["height", "width"], function(_i, dimension) {
jQuery.cssHooks[dimension] = {
get: function(elem, computed, extra) {
if (computed) return rdisplayswap.test(jQuery.css(elem, "display")) && (!elem.getClientRects().length || !elem.getBoundingClientRect().width) ? swap(elem, cssShow, function() {
return getWidthOrHeight(elem, dimension, extra);
}) : getWidthOrHeight(elem, dimension, extra);
},
set: function(elem, value, extra) {
var matches, styles = getStyles(elem), scrollboxSizeBuggy = !support.scrollboxSize() && styles.position === "absolute", isBorderBox = (scrollboxSizeBuggy || extra) && jQuery.css(elem, "boxSizing", false, styles) === "border-box", subtract = extra ? boxModelAdjustment(elem, dimension, extra, isBorderBox, styles) : 0;
if (isBorderBox && scrollboxSizeBuggy) subtract -= Math.ceil(elem["offset" + dimension[0].toUpperCase() + dimension.slice(1)] - parseFloat(styles[dimension]) - boxModelAdjustment(elem, dimension, "border", false, styles) - .5);
if (subtract && (matches = rcssNum.exec(value)) && (matches[3] || "px") !== "px") {
elem.style[dimension] = value;
value = jQuery.css(elem, dimension);
}
return setPositiveNumber(elem, value, subtract);
}
};
});
jQuery.cssHooks.marginLeft = addGetHookIf(support.reliableMarginLeft, function(elem, computed) {
if (computed) return (parseFloat(curCSS(elem, "marginLeft")) || elem.getBoundingClientRect().left - swap(elem, { marginLeft: 0 }, function() {
return elem.getBoundingClientRect().left;
})) + "px";
});
jQuery.each({
margin: "",
padding: "",
border: "Width"
}, function(prefix, suffix) {
jQuery.cssHooks[prefix + suffix] = { expand: function(value) {
var i = 0, expanded = {}, parts = typeof value === "string" ? value.split(" ") : [value];
for (; i < 4; i++) expanded[prefix + cssExpand[i] + suffix] = parts[i] || parts[i - 2] || parts[0];
return expanded;
} };
if (prefix !== "margin") jQuery.cssHooks[prefix + suffix].set = setPositiveNumber;
});
jQuery.fn.extend({ css: function(name, value) {
return access(this, function(elem, name, value) {
var styles, len, map = {}, i = 0;
if (Array.isArray(name)) {
styles = getStyles(elem);
len = name.length;
for (; i < len; i++) map[name[i]] = jQuery.css(elem, name[i], false, styles);
return map;
}
return value !== void 0 ? jQuery.style(elem, name, value) : jQuery.css(elem, name);
}, name, value, arguments.length > 1);
} });
function Tween(elem, options, prop, end, easing) {
return new Tween.prototype.init(elem, options, prop, end, easing);
}
jQuery.Tween = Tween;
Tween.prototype = {
constructor: Tween,
init: function(elem, options, prop, end, easing, unit) {
this.elem = elem;
this.prop = prop;
this.easing = easing || jQuery.easing._default;
this.options = options;
this.start = this.now = this.cur();
this.end = end;
this.unit = unit || (jQuery.cssNumber[prop] ? "" : "px");
},
cur: function() {
var hooks = Tween.propHooks[this.prop];
return hooks && hooks.get ? hooks.get(this) : Tween.propHooks._default.get(this);
},
run: function(percent) {
var eased, hooks = Tween.propHooks[this.prop];
if (this.options.duration) this.pos = eased = jQuery.easing[this.easing](percent, this.options.duration * percent, 0, 1, this.options.duration);
else this.pos = eased = percent;
this.now = (this.end - this.start) * eased + this.start;
if (this.options.step) this.options.step.call(this.elem, this.now, this);
if (hooks && hooks.set) hooks.set(this);
else Tween.propHooks._default.set(this);
return this;
}
};
Tween.prototype.init.prototype = Tween.prototype;
Tween.propHooks = { _default: {
get: function(tween) {
var result;
if (tween.elem.nodeType !== 1 || tween.elem[tween.prop] != null && tween.elem.style[tween.prop] == null) return tween.elem[tween.prop];
result = jQuery.css(tween.elem, tween.prop, "");
return !result || result === "auto" ? 0 : result;
},
set: function(tween) {
if (jQuery.fx.step[tween.prop]) jQuery.fx.step[tween.prop](tween);
else if (tween.elem.nodeType === 1 && (jQuery.cssHooks[tween.prop] || tween.elem.style[finalPropName(tween.prop)] != null)) jQuery.style(tween.elem, tween.prop, tween.now + tween.unit);
else tween.elem[tween.prop] = tween.now;
}
} };
Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { set: function(tween) {
if (tween.elem.nodeType && tween.elem.parentNode) tween.elem[tween.prop] = tween.now;
} };
jQuery.easing = {
linear: function(p) {
return p;
},
swing: function(p) {
return .5 - Math.cos(p * Math.PI) / 2;
},
_default: "swing"
};
jQuery.fx = Tween.prototype.init;
jQuery.fx.step = {};
var fxNow, inProgress, rfxtypes = /^(?:toggle|show|hide)$/, rrun = /queueHooks$/;
function schedule() {
if (inProgress) {
if (document.hidden === false && window.requestAnimationFrame) window.requestAnimationFrame(schedule);
else window.setTimeout(schedule, jQuery.fx.interval);
jQuery.fx.tick();
}
}
function createFxNow() {
window.setTimeout(function() {
fxNow = void 0;
});
return fxNow = Date.now();
}
function genFx(type, includeWidth) {
var which, i = 0, attrs = { height: type };
includeWidth = includeWidth ? 1 : 0;
for (; i < 4; i += 2 - includeWidth) {
which = cssExpand[i];
attrs["margin" + which] = attrs["padding" + which] = type;
}
if (includeWidth) attrs.opacity = attrs.width = type;
return attrs;
}
function createTween(value, prop, animation) {
var tween, collection = (Animation.tweeners[prop] || []).concat(Animation.tweeners["*"]), index = 0, length = collection.length;
for (; index < length; index++) if (tween = collection[index].call(animation, prop, value)) return tween;
}
function defaultPrefilter(elem, props, opts) {
var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, isBox = "width" in props || "height" in props, anim = this, orig = {}, style = elem.style, hidden = elem.nodeType && isHiddenWithinTree(elem), dataShow = dataPriv.get(elem, "fxshow");
if (!opts.queue) {
hooks = jQuery._queueHooks(elem, "fx");
if (hooks.unqueued == null) {
hooks.unqueued = 0;
oldfire = hooks.empty.fire;
hooks.empty.fire = function() {
if (!hooks.unqueued) oldfire();
};
}
hooks.unqueued++;
anim.always(function() {
anim.always(function() {
hooks.unqueued--;
if (!jQuery.queue(elem, "fx").length) hooks.empty.fire();
});
});
}
for (prop in props) {
value = props[prop];
if (rfxtypes.test(value)) {
delete props[prop];
toggle = toggle || value === "toggle";
if (value === (hidden ? "hide" : "show")) if (value === "show" && dataShow && dataShow[prop] !== void 0) hidden = true;
else continue;
orig[prop] = dataShow && dataShow[prop] || jQuery.style(elem, prop);
}
}
propTween = !jQuery.isEmptyObject(props);
if (!propTween && jQuery.isEmptyObject(orig)) return;
if (isBox && elem.nodeType === 1) {
opts.overflow = [
style.overflow,
style.overflowX,
style.overflowY
];
restoreDisplay = dataShow && dataShow.display;
if (restoreDisplay == null) restoreDisplay = dataPriv.get(elem, "display");
display = jQuery.css(elem, "display");
if (display === "none") if (restoreDisplay) display = restoreDisplay;
else {
showHide([elem], true);
restoreDisplay = elem.style.display || restoreDisplay;
display = jQuery.css(elem, "display");
showHide([elem]);
}
if (display === "inline" || display === "inline-block" && restoreDisplay != null) {
if (jQuery.css(elem, "float") === "none") {
if (!propTween) {
anim.done(function() {
style.display = restoreDisplay;
});
if (restoreDisplay == null) {
display = style.display;
restoreDisplay = display === "none" ? "" : display;
}
}
style.display = "inline-block";
}
}
}
if (opts.overflow) {
style.overflow = "hidden";
anim.always(function() {
style.overflow = opts.overflow[0];
style.overflowX = opts.overflow[1];
style.overflowY = opts.overflow[2];
});
}
propTween = false;
for (prop in orig) {
if (!propTween) {
if (dataShow) {
if ("hidden" in dataShow) hidden = dataShow.hidden;
} else dataShow = dataPriv.access(elem, "fxshow", { display: restoreDisplay });
if (toggle) dataShow.hidden = !hidden;
if (hidden) showHide([elem], true);
anim.done(function() {
if (!hidden) showHide([elem]);
dataPriv.remove(elem, "fxshow");
for (prop in orig) jQuery.style(elem, prop, orig[prop]);
});
}
propTween = createTween(hidden ? dataShow[prop] : 0, prop, anim);
if (!(prop in dataShow)) {
dataShow[prop] = propTween.start;
if (hidden) {
propTween.end = propTween.start;
propTween.start = 0;
}
}
}
}
function propFilter(props, specialEasing) {
var index, name, easing, value, hooks;
for (index in props) {
name = camelCase(index);
easing = specialEasing[name];
value = props[index];
if (Array.isArray(value)) {
easing = value[1];
value = props[index] = value[0];
}
if (index !== name) {
props[name] = value;
delete props[index];
}
hooks = jQuery.cssHooks[name];
if (hooks && "expand" in hooks) {
value = hooks.expand(value);
delete props[name];
for (index in value) if (!(index in props)) {
props[index] = value[index];
specialEasing[index] = easing;
}
} else specialEasing[name] = easing;
}
}
function Animation(elem, properties, options) {
var result, stopped, index = 0, length = Animation.prefilters.length, deferred = jQuery.Deferred().always(function() {
delete tick.elem;
}), tick = function() {
if (stopped) return false;
var currentTime = fxNow || createFxNow(), remaining = Math.max(0, animation.startTime + animation.duration - currentTime), percent = 1 - (remaining / animation.duration || 0), index = 0, length = animation.tweens.length;
for (; index < length; index++) animation.tweens[index].run(percent);
deferred.notifyWith(elem, [
animation,
percent,
remaining
]);
if (percent < 1 && length) return remaining;
if (!length) deferred.notifyWith(elem, [
animation,
1,
0
]);
deferred.resolveWith(elem, [animation]);
return false;
}, animation = deferred.promise({
elem,
props: jQuery.extend({}, properties),
opts: jQuery.extend(true, {
specialEasing: {},
easing: jQuery.easing._default
}, options),
originalProperties: properties,
originalOptions: options,
startTime: fxNow || createFxNow(),
duration: options.duration,
tweens: [],
createTween: function(prop, end) {
var tween = jQuery.Tween(elem, animation.opts, prop, end, animation.opts.specialEasing[prop] || animation.opts.easing);
animation.tweens.push(tween);
return tween;
},
stop: function(gotoEnd) {
var index = 0, length = gotoEnd ? animation.tweens.length : 0;
if (stopped) return this;
stopped = true;
for (; index < length; index++) animation.tweens[index].run(1);
if (gotoEnd) {
deferred.notifyWith(elem, [
animation,
1,
0
]);
deferred.resolveWith(elem, [animation, gotoEnd]);
} else deferred.rejectWith(elem, [animation, gotoEnd]);
return this;
}
}), props = animation.props;
propFilter(props, animation.opts.specialEasing);
for (; index < length; index++) {
result = Animation.prefilters[index].call(animation, elem, props, animation.opts);
if (result) {
if (isFunction(result.stop)) jQuery._queueHooks(animation.elem, animation.opts.queue).stop = result.stop.bind(result);
return result;
}
}
jQuery.map(props, createTween, animation);
if (isFunction(animation.opts.start)) animation.opts.start.call(elem, animation);
animation.progress(animation.opts.progress).done(animation.opts.done, animation.opts.complete).fail(animation.opts.fail).always(animation.opts.always);
jQuery.fx.timer(jQuery.extend(tick, {
elem,
anim: animation,
queue: animation.opts.queue
}));
return animation;
}
jQuery.Animation = jQuery.extend(Animation, {
tweeners: { "*": [function(prop, value) {
var tween = this.createTween(prop, value);
adjustCSS(tween.elem, prop, rcssNum.exec(value), tween);
return tween;
}] },
tweener: function(props, callback) {
if (isFunction(props)) {
callback = props;
props = ["*"];
} else props = props.match(rnothtmlwhite);
var prop, index = 0, length = props.length;
for (; index < length; index++) {
prop = props[index];
Animation.tweeners[prop] = Animation.tweeners[prop] || [];
Animation.tweeners[prop].unshift(callback);
}
},
prefilters: [defaultPrefilter],
prefilter: function(callback, prepend) {
if (prepend) Animation.prefilters.unshift(callback);
else Animation.prefilters.push(callback);
}
});
jQuery.speed = function(speed, easing, fn) {
var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : {
complete: fn || !fn && easing || isFunction(speed) && speed,
duration: speed,
easing: fn && easing || easing && !isFunction(easing) && easing
};
if (jQuery.fx.off) opt.duration = 0;
else if (typeof opt.duration !== "number") if (opt.duration in jQuery.fx.speeds) opt.duration = jQuery.fx.speeds[opt.duration];
else opt.duration = jQuery.fx.speeds._default;
if (opt.queue == null || opt.queue === true) opt.queue = "fx";
opt.old = opt.complete;
opt.complete = function() {
if (isFunction(opt.old)) opt.old.call(this);
if (opt.queue) jQuery.dequeue(this, opt.queue);
};
return opt;
};
jQuery.fn.extend({
fadeTo: function(speed, to, easing, callback) {
return this.filter(isHiddenWithinTree).css("opacity", 0).show().end().animate({ opacity: to }, speed, easing, callback);
},
animate: function(prop, speed, easing, callback) {
var empty = jQuery.isEmptyObject(prop), optall = jQuery.speed(speed, easing, callback), doAnimation = function() {
var anim = Animation(this, jQuery.extend({}, prop), optall);
if (empty || dataPriv.get(this, "finish")) anim.stop(true);
};
doAnimation.finish = doAnimation;
return empty || optall.queue === false ? this.each(doAnimation) : this.queue(optall.queue, doAnimation);
},
stop: function(type, clearQueue, gotoEnd) {
var stopQueue = function(hooks) {
var stop = hooks.stop;
delete hooks.stop;
stop(gotoEnd);
};
if (typeof type !== "string") {
gotoEnd = clearQueue;
clearQueue = type;
type = void 0;
}
if (clearQueue) this.queue(type || "fx", []);
return this.each(function() {
var dequeue = true, index = type != null && type + "queueHooks", timers = jQuery.timers, data = dataPriv.get(this);
if (index) {
if (data[index] && data[index].stop) stopQueue(data[index]);
} else for (index in data) if (data[index] && data[index].stop && rrun.test(index)) stopQueue(data[index]);
for (index = timers.length; index--;) if (timers[index].elem === this && (type == null || timers[index].queue === type)) {
timers[index].anim.stop(gotoEnd);
dequeue = false;
timers.splice(index, 1);
}
if (dequeue || !gotoEnd) jQuery.dequeue(this, type);
});
},
finish: function(type) {
if (type !== false) type = type || "fx";
return this.each(function() {
var index, data = dataPriv.get(this), queue = data[type + "queue"], hooks = data[type + "queueHooks"], timers = jQuery.timers, length = queue ? queue.length : 0;
data.finish = true;
jQuery.queue(this, type, []);
if (hooks && hooks.stop) hooks.stop.call(this, true);
for (index = timers.length; index--;) if (timers[index].elem === this && timers[index].queue === type) {
timers[index].anim.stop(true);
timers.splice(index, 1);
}
for (index = 0; index < length; index++) if (queue[index] && queue[index].finish) queue[index].finish.call(this);
delete data.finish;
});
}
});
jQuery.each([
"toggle",
"show",
"hide"
], function(_i, name) {
var cssFn = jQuery.fn[name];
jQuery.fn[name] = function(speed, easing, callback) {
return speed == null || typeof speed === "boolean" ? cssFn.apply(this, arguments) : this.animate(genFx(name, true), speed, easing, callback);
};
});
jQuery.each({
slideDown: genFx("show"),
slideUp: genFx("hide"),
slideToggle: genFx("toggle"),
fadeIn: { opacity: "show" },
fadeOut: { opacity: "hide" },
fadeToggle: { opacity: "toggle" }
}, function(name, props) {
jQuery.fn[name] = function(speed, easing, callback) {
return this.animate(props, speed, easing, callback);
};
});
jQuery.timers = [];
jQuery.fx.tick = function() {
var timer, i = 0, timers = jQuery.timers;
fxNow = Date.now();
for (; i < timers.length; i++) {
timer = timers[i];
if (!timer() && timers[i] === timer) timers.splice(i--, 1);
}
if (!timers.length) jQuery.fx.stop();
fxNow = void 0;
};
jQuery.fx.timer = function(timer) {
jQuery.timers.push(timer);
jQuery.fx.start();
};
jQuery.fx.interval = 13;
jQuery.fx.start = function() {
if (inProgress) return;
inProgress = true;
schedule();
};
jQuery.fx.stop = function() {
inProgress = null;
};
jQuery.fx.speeds = {
slow: 600,
fast: 200,
_default: 400
};
jQuery.fn.delay = function(time, type) {
time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
type = type || "fx";
return this.queue(type, function(next, hooks) {
var timeout = window.setTimeout(next, time);
hooks.stop = function() {
window.clearTimeout(timeout);
};
});
};
(function() {
var input = document.createElement("input"), opt = document.createElement("select").appendChild(document.createElement("option"));
input.type = "checkbox";
support.checkOn = input.value !== "";
support.optSelected = opt.selected;
input = document.createElement("input");
input.value = "t";
input.type = "radio";
support.radioValue = input.value === "t";
})();
var boolHook, attrHandle = jQuery.expr.attrHandle;
jQuery.fn.extend({
attr: function(name, value) {
return access(this, jQuery.attr, name, value, arguments.length > 1);
},
removeAttr: function(name) {
return this.each(function() {
jQuery.removeAttr(this, name);
});
}
});
jQuery.extend({
attr: function(elem, name, value) {
var ret, hooks, nType = elem.nodeType;
if (nType === 3 || nType === 8 || nType === 2) return;
if (typeof elem.getAttribute === "undefined") return jQuery.prop(elem, name, value);
if (nType !== 1 || !jQuery.isXMLDoc(elem)) hooks = jQuery.attrHooks[name.toLowerCase()] || (jQuery.expr.match.bool.test(name) ? boolHook : void 0);
if (value !== void 0) {
if (value === null) {
jQuery.removeAttr(elem, name);
return;
}
if (hooks && "set" in hooks && (ret = hooks.set(elem, value, name)) !== void 0) return ret;
elem.setAttribute(name, value + "");
return value;
}
if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) return ret;
ret = jQuery.find.attr(elem, name);
return ret == null ? void 0 : ret;
},
attrHooks: { type: { set: function(elem, value) {
if (!support.radioValue && value === "radio" && nodeName(elem, "input")) {
var val = elem.value;
elem.setAttribute("type", value);
if (val) elem.value = val;
return value;
}
} } },
removeAttr: function(elem, value) {
var name, i = 0, attrNames = value && value.match(rnothtmlwhite);
if (attrNames && elem.nodeType === 1) while (name = attrNames[i++]) elem.removeAttribute(name);
}
});
boolHook = { set: function(elem, value, name) {
if (value === false) jQuery.removeAttr(elem, name);
else elem.setAttribute(name, name);
return name;
} };
jQuery.each(jQuery.expr.match.bool.source.match(/\w+/g), function(_i, name) {
var getter = attrHandle[name] || jQuery.find.attr;
attrHandle[name] = function(elem, name, isXML) {
var ret, handle, lowercaseName = name.toLowerCase();
if (!isXML) {
handle = attrHandle[lowercaseName];
attrHandle[lowercaseName] = ret;
ret = getter(elem, name, isXML) != null ? lowercaseName : null;
attrHandle[lowercaseName] = handle;
}
return ret;
};
});
var rfocusable = /^(?:input|select|textarea|button)$/i, rclickable = /^(?:a|area)$/i;
jQuery.fn.extend({
prop: function(name, value) {
return access(this, jQuery.prop, name, value, arguments.length > 1);
},
removeProp: function(name) {
return this.each(function() {
delete this[jQuery.propFix[name] || name];
});
}
});
jQuery.extend({
prop: function(elem, name, value) {
var ret, hooks, nType = elem.nodeType;
if (nType === 3 || nType === 8 || nType === 2) return;
if (nType !== 1 || !jQuery.isXMLDoc(elem)) {
name = jQuery.propFix[name] || name;
hooks = jQuery.propHooks[name];
}
if (value !== void 0) {
if (hooks && "set" in hooks && (ret = hooks.set(elem, value, name)) !== void 0) return ret;
return elem[name] = value;
}
if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) return ret;
return elem[name];
},
propHooks: { tabIndex: { get: function(elem) {
var tabindex = jQuery.find.attr(elem, "tabindex");
if (tabindex) return parseInt(tabindex, 10);
if (rfocusable.test(elem.nodeName) || rclickable.test(elem.nodeName) && elem.href) return 0;
return -1;
} } },
propFix: {
"for": "htmlFor",
"class": "className"
}
});
if (!support.optSelected) jQuery.propHooks.selected = {
get: function(elem) {
var parent = elem.parentNode;
if (parent && parent.parentNode) parent.parentNode.selectedIndex;
return null;
},
set: function(elem) {
var parent = elem.parentNode;
if (parent) {
parent.selectedIndex;
if (parent.parentNode) parent.parentNode.selectedIndex;
}
}
};
jQuery.each([
"tabIndex",
"readOnly",
"maxLength",
"cellSpacing",
"cellPadding",
"rowSpan",
"colSpan",
"useMap",
"frameBorder",
"contentEditable"
], function() {
jQuery.propFix[this.toLowerCase()] = this;
});
function stripAndCollapse(value) {
return (value.match(rnothtmlwhite) || []).join(" ");
}
function getClass(elem) {
return elem.getAttribute && elem.getAttribute("class") || "";
}
function classesToArray(value) {
if (Array.isArray(value)) return value;
if (typeof value === "string") return value.match(rnothtmlwhite) || [];
return [];
}
jQuery.fn.extend({
addClass: function(value) {
var classNames, cur, curValue, className, i, finalValue;
if (isFunction(value)) return this.each(function(j) {
jQuery(this).addClass(value.call(this, j, getClass(this)));
});
classNames = classesToArray(value);
if (classNames.length) return this.each(function() {
curValue = getClass(this);
cur = this.nodeType === 1 && " " + stripAndCollapse(curValue) + " ";
if (cur) {
for (i = 0; i < classNames.length; i++) {
className = classNames[i];
if (cur.indexOf(" " + className + " ") < 0) cur += className + " ";
}
finalValue = stripAndCollapse(cur);
if (curValue !== finalValue) this.setAttribute("class", finalValue);
}
});
return this;
},
removeClass: function(value) {
var classNames, cur, curValue, className, i, finalValue;
if (isFunction(value)) return this.each(function(j) {
jQuery(this).removeClass(value.call(this, j, getClass(this)));
});
if (!arguments.length) return this.attr("class", "");
classNames = classesToArray(value);
if (classNames.length) return this.each(function() {
curValue = getClass(this);
cur = this.nodeType === 1 && " " + stripAndCollapse(curValue) + " ";
if (cur) {
for (i = 0; i < classNames.length; i++) {
className = classNames[i];
while (cur.indexOf(" " + className + " ") > -1) cur = cur.replace(" " + className + " ", " ");
}
finalValue = stripAndCollapse(cur);
if (curValue !== finalValue) this.setAttribute("class", finalValue);
}
});
return this;
},
toggleClass: function(value, stateVal) {
var classNames, className, i, self, type = typeof value, isValidValue = type === "string" || Array.isArray(value);
if (isFunction(value)) return this.each(function(i) {
jQuery(this).toggleClass(value.call(this, i, getClass(this), stateVal), stateVal);
});
if (typeof stateVal === "boolean" && isValidValue) return stateVal ? this.addClass(value) : this.removeClass(value);
classNames = classesToArray(value);
return this.each(function() {
if (isValidValue) {
self = jQuery(this);
for (i = 0; i < classNames.length; i++) {
className = classNames[i];
if (self.hasClass(className)) self.removeClass(className);
else self.addClass(className);
}
} else if (value === void 0 || type === "boolean") {
className = getClass(this);
if (className) dataPriv.set(this, "__className__", className);
if (this.setAttribute) this.setAttribute("class", className || value === false ? "" : dataPriv.get(this, "__className__") || "");
}
});
},
hasClass: function(selector) {
var className, elem, i = 0;
className = " " + selector + " ";
while (elem = this[i++]) if (elem.nodeType === 1 && (" " + stripAndCollapse(getClass(elem)) + " ").indexOf(className) > -1) return true;
return false;
}
});
var rreturn = /\r/g;
jQuery.fn.extend({ val: function(value) {
var hooks, ret, valueIsFunction, elem = this[0];
if (!arguments.length) {
if (elem) {
hooks = jQuery.valHooks[elem.type] || jQuery.valHooks[elem.nodeName.toLowerCase()];
if (hooks && "get" in hooks && (ret = hooks.get(elem, "value")) !== void 0) return ret;
ret = elem.value;
if (typeof ret === "string") return ret.replace(rreturn, "");
return ret == null ? "" : ret;
}
return;
}
valueIsFunction = isFunction(value);
return this.each(function(i) {
var val;
if (this.nodeType !== 1) return;
if (valueIsFunction) val = value.call(this, i, jQuery(this).val());
else val = value;
if (val == null) val = "";
else if (typeof val === "number") val += "";
else if (Array.isArray(val)) val = jQuery.map(val, function(value) {
return value == null ? "" : value + "";
});
hooks = jQuery.valHooks[this.type] || jQuery.valHooks[this.nodeName.toLowerCase()];
if (!hooks || !("set" in hooks) || hooks.set(this, val, "value") === void 0) this.value = val;
});
} });
jQuery.extend({ valHooks: {
option: { get: function(elem) {
var val = jQuery.find.attr(elem, "value");
return val != null ? val : stripAndCollapse(jQuery.text(elem));
} },
select: {
get: function(elem) {
var value, option, i, options = elem.options, index = elem.selectedIndex, one = elem.type === "select-one", values = one ? null : [], max = one ? index + 1 : options.length;
if (index < 0) i = max;
else i = one ? index : 0;
for (; i < max; i++) {
option = options[i];
if ((option.selected || i === index) && !option.disabled && (!option.parentNode.disabled || !nodeName(option.parentNode, "optgroup"))) {
value = jQuery(option).val();
if (one) return value;
values.push(value);
}
}
return values;
},
set: function(elem, value) {
var optionSet, option, options = elem.options, values = jQuery.makeArray(value), i = options.length;
while (i--) {
option = options[i];
if (option.selected = jQuery.inArray(jQuery.valHooks.option.get(option), values) > -1) optionSet = true;
}
if (!optionSet) elem.selectedIndex = -1;
return values;
}
}
} });
jQuery.each(["radio", "checkbox"], function() {
jQuery.valHooks[this] = { set: function(elem, value) {
if (Array.isArray(value)) return elem.checked = jQuery.inArray(jQuery(elem).val(), value) > -1;
} };
if (!support.checkOn) jQuery.valHooks[this].get = function(elem) {
return elem.getAttribute("value") === null ? "on" : elem.value;
};
});
var location = window.location;
var nonce = { guid: Date.now() };
var rquery = /\?/;
jQuery.parseXML = function(data) {
var xml, parserErrorElem;
if (!data || typeof data !== "string") return null;
try {
xml = new window.DOMParser().parseFromString(data, "text/xml");
} catch (e) {}
parserErrorElem = xml && xml.getElementsByTagName("parsererror")[0];
if (!xml || parserErrorElem) jQuery.error("Invalid XML: " + (parserErrorElem ? jQuery.map(parserErrorElem.childNodes, function(el) {
return el.textContent;
}).join("\n") : data));
return xml;
};
var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, stopPropagationCallback = function(e) {
e.stopPropagation();
};
jQuery.extend(jQuery.event, {
trigger: function(event, data, elem, onlyHandlers) {
var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, eventPath = [elem || document], type = hasOwn.call(event, "type") ? event.type : event, namespaces = hasOwn.call(event, "namespace") ? event.namespace.split(".") : [];
cur = lastElement = tmp = elem = elem || document;
if (elem.nodeType === 3 || elem.nodeType === 8) return;
if (rfocusMorph.test(type + jQuery.event.triggered)) return;
if (type.indexOf(".") > -1) {
namespaces = type.split(".");
type = namespaces.shift();
namespaces.sort();
}
ontype = type.indexOf(":") < 0 && "on" + type;
event = event[jQuery.expando] ? event : new jQuery.Event(type, typeof event === "object" && event);
event.isTrigger = onlyHandlers ? 2 : 3;
event.namespace = namespaces.join(".");
event.rnamespace = event.namespace ? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null;
event.result = void 0;
if (!event.target) event.target = elem;
data = data == null ? [event] : jQuery.makeArray(data, [event]);
special = jQuery.event.special[type] || {};
if (!onlyHandlers && special.trigger && special.trigger.apply(elem, data) === false) return;
if (!onlyHandlers && !special.noBubble && !isWindow(elem)) {
bubbleType = special.delegateType || type;
if (!rfocusMorph.test(bubbleType + type)) cur = cur.parentNode;
for (; cur; cur = cur.parentNode) {
eventPath.push(cur);
tmp = cur;
}
if (tmp === (elem.ownerDocument || document)) eventPath.push(tmp.defaultView || tmp.parentWindow || window);
}
i = 0;
while ((cur = eventPath[i++]) && !event.isPropagationStopped()) {
lastElement = cur;
event.type = i > 1 ? bubbleType : special.bindType || type;
handle = (dataPriv.get(cur, "events") || Object.create(null))[event.type] && dataPriv.get(cur, "handle");
if (handle) handle.apply(cur, data);
handle = ontype && cur[ontype];
if (handle && handle.apply && acceptData(cur)) {
event.result = handle.apply(cur, data);
if (event.result === false) event.preventDefault();
}
}
event.type = type;
if (!onlyHandlers && !event.isDefaultPrevented()) {
if ((!special._default || special._default.apply(eventPath.pop(), data) === false) && acceptData(elem)) {
if (ontype && isFunction(elem[type]) && !isWindow(elem)) {
tmp = elem[ontype];
if (tmp) elem[ontype] = null;
jQuery.event.triggered = type;
if (event.isPropagationStopped()) lastElement.addEventListener(type, stopPropagationCallback);
elem[type]();
if (event.isPropagationStopped()) lastElement.removeEventListener(type, stopPropagationCallback);
jQuery.event.triggered = void 0;
if (tmp) elem[ontype] = tmp;
}
}
}
return event.result;
},
simulate: function(type, elem, event) {
var e = jQuery.extend(new jQuery.Event(), event, {
type,
isSimulated: true
});
jQuery.event.trigger(e, null, elem);
}
});
jQuery.fn.extend({
trigger: function(type, data) {
return this.each(function() {
jQuery.event.trigger(type, data, this);
});
},
triggerHandler: function(type, data) {
var elem = this[0];
if (elem) return jQuery.event.trigger(type, data, elem, true);
}
});
var rbracket = /\[\]$/, rCRLF = /\r?\n/g, rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, rsubmittable = /^(?:input|select|textarea|keygen)/i;
function buildParams(prefix, obj, traditional, add) {
var name;
if (Array.isArray(obj)) jQuery.each(obj, function(i, v) {
if (traditional || rbracket.test(prefix)) add(prefix, v);
else buildParams(prefix + "[" + (typeof v === "object" && v != null ? i : "") + "]", v, traditional, add);
});
else if (!traditional && toType(obj) === "object") for (name in obj) buildParams(prefix + "[" + name + "]", obj[name], traditional, add);
else add(prefix, obj);
}
jQuery.param = function(a, traditional) {
var prefix, s = [], add = function(key, valueOrFunction) {
var value = isFunction(valueOrFunction) ? valueOrFunction() : valueOrFunction;
s[s.length] = encodeURIComponent(key) + "=" + encodeURIComponent(value == null ? "" : value);
};
if (a == null) return "";
if (Array.isArray(a) || a.jquery && !jQuery.isPlainObject(a)) jQuery.each(a, function() {
add(this.name, this.value);
});
else for (prefix in a) buildParams(prefix, a[prefix], traditional, add);
return s.join("&");
};
jQuery.fn.extend({
serialize: function() {
return jQuery.param(this.serializeArray());
},
serializeArray: function() {
return this.map(function() {
var elements = jQuery.prop(this, "elements");
return elements ? jQuery.makeArray(elements) : this;
}).filter(function() {
var type = this.type;
return this.name && !jQuery(this).is(":disabled") && rsubmittable.test(this.nodeName) && !rsubmitterTypes.test(type) && (this.checked || !rcheckableType.test(type));
}).map(function(_i, elem) {
var val = jQuery(this).val();
if (val == null) return null;
if (Array.isArray(val)) return jQuery.map(val, function(val) {
return {
name: elem.name,
value: val.replace(rCRLF, "\r\n")
};
});
return {
name: elem.name,
value: val.replace(rCRLF, "\r\n")
};
}).get();
}
});
var r20 = /%20/g, rhash = /#.*$/, rantiCache = /([?&])_=[^&]*/, rheaders = /^(.*?):[ \t]*([^\r\n]*)$/gm, rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, rnoContent = /^(?:GET|HEAD)$/, rprotocol = /^\/\//, prefilters = {}, transports = {}, allTypes = "*/".concat("*"), originAnchor = document.createElement("a");
originAnchor.href = location.href;
function addToPrefiltersOrTransports(structure) {
return function(dataTypeExpression, func) {
if (typeof dataTypeExpression !== "string") {
func = dataTypeExpression;
dataTypeExpression = "*";
}
var dataType, i = 0, dataTypes = dataTypeExpression.toLowerCase().match(rnothtmlwhite) || [];
if (isFunction(func)) while (dataType = dataTypes[i++]) if (dataType[0] === "+") {
dataType = dataType.slice(1) || "*";
(structure[dataType] = structure[dataType] || []).unshift(func);
} else (structure[dataType] = structure[dataType] || []).push(func);
};
}
function inspectPrefiltersOrTransports(structure, options, originalOptions, jqXHR) {
var inspected = {}, seekingTransport = structure === transports;
function inspect(dataType) {
var selected;
inspected[dataType] = true;
jQuery.each(structure[dataType] || [], function(_, prefilterOrFactory) {
var dataTypeOrTransport = prefilterOrFactory(options, originalOptions, jqXHR);
if (typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[dataTypeOrTransport]) {
options.dataTypes.unshift(dataTypeOrTransport);
inspect(dataTypeOrTransport);
return false;
} else if (seekingTransport) return !(selected = dataTypeOrTransport);
});
return selected;
}
return inspect(options.dataTypes[0]) || !inspected["*"] && inspect("*");
}
function ajaxExtend(target, src) {
var key, deep, flatOptions = jQuery.ajaxSettings.flatOptions || {};
for (key in src) if (src[key] !== void 0) (flatOptions[key] ? target : deep || (deep = {}))[key] = src[key];
if (deep) jQuery.extend(true, target, deep);
return target;
}
function ajaxHandleResponses(s, jqXHR, responses) {
var ct, type, finalDataType, firstDataType, contents = s.contents, dataTypes = s.dataTypes;
while (dataTypes[0] === "*") {
dataTypes.shift();
if (ct === void 0) ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
}
if (ct) {
for (type in contents) if (contents[type] && contents[type].test(ct)) {
dataTypes.unshift(type);
break;
}
}
if (dataTypes[0] in responses) finalDataType = dataTypes[0];
else {
for (type in responses) {
if (!dataTypes[0] || s.converters[type + " " + dataTypes[0]]) {
finalDataType = type;
break;
}
if (!firstDataType) firstDataType = type;
}
finalDataType = finalDataType || firstDataType;
}
if (finalDataType) {
if (finalDataType !== dataTypes[0]) dataTypes.unshift(finalDataType);
return responses[finalDataType];
}
}
function ajaxConvert(s, response, jqXHR, isSuccess) {
var conv2, current, conv, tmp, prev, converters = {}, dataTypes = s.dataTypes.slice();
if (dataTypes[1]) for (conv in s.converters) converters[conv.toLowerCase()] = s.converters[conv];
current = dataTypes.shift();
while (current) {
if (s.responseFields[current]) jqXHR[s.responseFields[current]] = response;
if (!prev && isSuccess && s.dataFilter) response = s.dataFilter(response, s.dataType);
prev = current;
current = dataTypes.shift();
if (current) {
if (current === "*") current = prev;
else if (prev !== "*" && prev !== current) {
conv = converters[prev + " " + current] || converters["* " + current];
if (!conv) for (conv2 in converters) {
tmp = conv2.split(" ");
if (tmp[1] === current) {
conv = converters[prev + " " + tmp[0]] || converters["* " + tmp[0]];
if (conv) {
if (conv === true) conv = converters[conv2];
else if (converters[conv2] !== true) {
current = tmp[0];
dataTypes.unshift(tmp[1]);
}
break;
}
}
}
if (conv !== true) if (conv && s.throws) response = conv(response);
else try {
response = conv(response);
} catch (e) {
return {
state: "parsererror",
error: conv ? e : "No conversion from " + prev + " to " + current
};
}
}
}
}
return {
state: "success",
data: response
};
}
jQuery.extend({
active: 0,
lastModified: {},
etag: {},
ajaxSettings: {
url: location.href,
type: "GET",
isLocal: rlocalProtocol.test(location.protocol),
global: true,
processData: true,
async: true,
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
accepts: {
"*": allTypes,
text: "text/plain",
html: "text/html",
xml: "application/xml, text/xml",
json: "application/json, text/javascript"
},
contents: {
xml: /\bxml\b/,
html: /\bhtml/,
json: /\bjson\b/
},
responseFields: {
xml: "responseXML",
text: "responseText",
json: "responseJSON"
},
converters: {
"* text": String,
"text html": true,
"text json": JSON.parse,
"text xml": jQuery.parseXML
},
flatOptions: {
url: true,
context: true
}
},
ajaxSetup: function(target, settings) {
return settings ? ajaxExtend(ajaxExtend(target, jQuery.ajaxSettings), settings) : ajaxExtend(jQuery.ajaxSettings, target);
},
ajaxPrefilter: addToPrefiltersOrTransports(prefilters),
ajaxTransport: addToPrefiltersOrTransports(transports),
ajax: function(url, options) {
if (typeof url === "object") {
options = url;
url = void 0;
}
options = options || {};
var transport, cacheURL, responseHeadersString, responseHeaders, timeoutTimer, urlAnchor, completed, fireGlobals, i, uncached, s = jQuery.ajaxSetup({}, options), callbackContext = s.context || s, globalEventContext = s.context && (callbackContext.nodeType || callbackContext.jquery) ? jQuery(callbackContext) : jQuery.event, deferred = jQuery.Deferred(), completeDeferred = jQuery.Callbacks("once memory"), statusCode = s.statusCode || {}, requestHeaders = {}, requestHeadersNames = {}, strAbort = "canceled", jqXHR = {
readyState: 0,
getResponseHeader: function(key) {
var match;
if (completed) {
if (!responseHeaders) {
responseHeaders = {};
while (match = rheaders.exec(responseHeadersString)) responseHeaders[match[1].toLowerCase() + " "] = (responseHeaders[match[1].toLowerCase() + " "] || []).concat(match[2]);
}
match = responseHeaders[key.toLowerCase() + " "];
}
return match == null ? null : match.join(", ");
},
getAllResponseHeaders: function() {
return completed ? responseHeadersString : null;
},
setRequestHeader: function(name, value) {
if (completed == null) {
name = requestHeadersNames[name.toLowerCase()] = requestHeadersNames[name.toLowerCase()] || name;
requestHeaders[name] = value;
}
return this;
},
overrideMimeType: function(type) {
if (completed == null) s.mimeType = type;
return this;
},
statusCode: function(map) {
var code;
if (map) if (completed) jqXHR.always(map[jqXHR.status]);
else for (code in map) statusCode[code] = [statusCode[code], map[code]];
return this;
},
abort: function(statusText) {
var finalText = statusText || strAbort;
if (transport) transport.abort(finalText);
done(0, finalText);
return this;
}
};
deferred.promise(jqXHR);
s.url = ((url || s.url || location.href) + "").replace(rprotocol, location.protocol + "//");
s.type = options.method || options.type || s.method || s.type;
s.dataTypes = (s.dataType || "*").toLowerCase().match(rnothtmlwhite) || [""];
if (s.crossDomain == null) {
urlAnchor = document.createElement("a");
try {
urlAnchor.href = s.url;
urlAnchor.href = urlAnchor.href;
s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== urlAnchor.protocol + "//" + urlAnchor.host;
} catch (e) {
s.crossDomain = true;
}
}
if (s.data && s.processData && typeof s.data !== "string") s.data = jQuery.param(s.data, s.traditional);
inspectPrefiltersOrTransports(prefilters, s, options, jqXHR);
if (completed) return jqXHR;
fireGlobals = jQuery.event && s.global;
if (fireGlobals && jQuery.active++ === 0) jQuery.event.trigger("ajaxStart");
s.type = s.type.toUpperCase();
s.hasContent = !rnoContent.test(s.type);
cacheURL = s.url.replace(rhash, "");
if (!s.hasContent) {
uncached = s.url.slice(cacheURL.length);
if (s.data && (s.processData || typeof s.data === "string")) {
cacheURL += (rquery.test(cacheURL) ? "&" : "?") + s.data;
delete s.data;
}
if (s.cache === false) {
cacheURL = cacheURL.replace(rantiCache, "$1");
uncached = (rquery.test(cacheURL) ? "&" : "?") + "_=" + nonce.guid++ + uncached;
}
s.url = cacheURL + uncached;
} else if (s.data && s.processData && (s.contentType || "").indexOf("application/x-www-form-urlencoded") === 0) s.data = s.data.replace(r20, "+");
if (s.ifModified) {
if (jQuery.lastModified[cacheURL]) jqXHR.setRequestHeader("If-Modified-Since", jQuery.lastModified[cacheURL]);
if (jQuery.etag[cacheURL]) jqXHR.setRequestHeader("If-None-Match", jQuery.etag[cacheURL]);
}
if (s.data && s.hasContent && s.contentType !== false || options.contentType) jqXHR.setRequestHeader("Content-Type", s.contentType);
jqXHR.setRequestHeader("Accept", s.dataTypes[0] && s.accepts[s.dataTypes[0]] ? s.accepts[s.dataTypes[0]] + (s.dataTypes[0] !== "*" ? ", " + allTypes + "; q=0.01" : "") : s.accepts["*"]);
for (i in s.headers) jqXHR.setRequestHeader(i, s.headers[i]);
if (s.beforeSend && (s.beforeSend.call(callbackContext, jqXHR, s) === false || completed)) return jqXHR.abort();
strAbort = "abort";
completeDeferred.add(s.complete);
jqXHR.done(s.success);
jqXHR.fail(s.error);
transport = inspectPrefiltersOrTransports(transports, s, options, jqXHR);
if (!transport) done(-1, "No Transport");
else {
jqXHR.readyState = 1;
if (fireGlobals) globalEventContext.trigger("ajaxSend", [jqXHR, s]);
if (completed) return jqXHR;
if (s.async && s.timeout > 0) timeoutTimer = window.setTimeout(function() {
jqXHR.abort("timeout");
}, s.timeout);
try {
completed = false;
transport.send(requestHeaders, done);
} catch (e) {
if (completed) throw e;
done(-1, e);
}
}
function done(status, nativeStatusText, responses, headers) {
var isSuccess, success, error, response, modified, statusText = nativeStatusText;
if (completed) return;
completed = true;
if (timeoutTimer) window.clearTimeout(timeoutTimer);
transport = void 0;
responseHeadersString = headers || "";
jqXHR.readyState = status > 0 ? 4 : 0;
isSuccess = status >= 200 && status < 300 || status === 304;
if (responses) response = ajaxHandleResponses(s, jqXHR, responses);
if (!isSuccess && jQuery.inArray("script", s.dataTypes) > -1 && jQuery.inArray("json", s.dataTypes) < 0) s.converters["text script"] = function() {};
response = ajaxConvert(s, response, jqXHR, isSuccess);
if (isSuccess) {
if (s.ifModified) {
modified = jqXHR.getResponseHeader("Last-Modified");
if (modified) jQuery.lastModified[cacheURL] = modified;
modified = jqXHR.getResponseHeader("etag");
if (modified) jQuery.etag[cacheURL] = modified;
}
if (status === 204 || s.type === "HEAD") statusText = "nocontent";
else if (status === 304) statusText = "notmodified";
else {
statusText = response.state;
success = response.data;
error = response.error;
isSuccess = !error;
}
} else {
error = statusText;
if (status || !statusText) {
statusText = "error";
if (status < 0) status = 0;
}
}
jqXHR.status = status;
jqXHR.statusText = (nativeStatusText || statusText) + "";
if (isSuccess) deferred.resolveWith(callbackContext, [
success,
statusText,
jqXHR
]);
else deferred.rejectWith(callbackContext, [
jqXHR,
statusText,
error
]);
jqXHR.statusCode(statusCode);
statusCode = void 0;
if (fireGlobals) globalEventContext.trigger(isSuccess ? "ajaxSuccess" : "ajaxError", [
jqXHR,
s,
isSuccess ? success : error
]);
completeDeferred.fireWith(callbackContext, [jqXHR, statusText]);
if (fireGlobals) {
globalEventContext.trigger("ajaxComplete", [jqXHR, s]);
if (!--jQuery.active) jQuery.event.trigger("ajaxStop");
}
}
return jqXHR;
},
getJSON: function(url, data, callback) {
return jQuery.get(url, data, callback, "json");
},
getScript: function(url, callback) {
return jQuery.get(url, void 0, callback, "script");
}
});
jQuery.each(["get", "post"], function(_i, method) {
jQuery[method] = function(url, data, callback, type) {
if (isFunction(data)) {
type = type || callback;
callback = data;
data = void 0;
}
return jQuery.ajax(jQuery.extend({
url,
type: method,
dataType: type,
data,
success: callback
}, jQuery.isPlainObject(url) && url));
};
});
jQuery.ajaxPrefilter(function(s) {
var i;
for (i in s.headers) if (i.toLowerCase() === "content-type") s.contentType = s.headers[i] || "";
});
jQuery._evalUrl = function(url, options, doc) {
return jQuery.ajax({
url,
type: "GET",
dataType: "script",
cache: true,
async: false,
global: false,
converters: { "text script": function() {} },
dataFilter: function(response) {
jQuery.globalEval(response, options, doc);
}
});
};
jQuery.fn.extend({
wrapAll: function(html) {
var wrap;
if (this[0]) {
if (isFunction(html)) html = html.call(this[0]);
wrap = jQuery(html, this[0].ownerDocument).eq(0).clone(true);
if (this[0].parentNode) wrap.insertBefore(this[0]);
wrap.map(function() {
var elem = this;
while (elem.firstElementChild) elem = elem.firstElementChild;
return elem;
}).append(this);
}
return this;
},
wrapInner: function(html) {
if (isFunction(html)) return this.each(function(i) {
jQuery(this).wrapInner(html.call(this, i));
});
return this.each(function() {
var self = jQuery(this), contents = self.contents();
if (contents.length) contents.wrapAll(html);
else self.append(html);
});
},
wrap: function(html) {
var htmlIsFunction = isFunction(html);
return this.each(function(i) {
jQuery(this).wrapAll(htmlIsFunction ? html.call(this, i) : html);
});
},
unwrap: function(selector) {
this.parent(selector).not("body").each(function() {
jQuery(this).replaceWith(this.childNodes);
});
return this;
}
});
jQuery.expr.pseudos.hidden = function(elem) {
return !jQuery.expr.pseudos.visible(elem);
};
jQuery.expr.pseudos.visible = function(elem) {
return !!(elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length);
};
jQuery.ajaxSettings.xhr = function() {
try {
return new window.XMLHttpRequest();
} catch (e) {}
};
var xhrSuccessStatus = {
0: 200,
1223: 204
}, xhrSupported = jQuery.ajaxSettings.xhr();
support.cors = !!xhrSupported && "withCredentials" in xhrSupported;
support.ajax = xhrSupported = !!xhrSupported;
jQuery.ajaxTransport(function(options) {
var callback, errorCallback;
if (support.cors || xhrSupported && !options.crossDomain) return {
send: function(headers, complete) {
var i, xhr = options.xhr();
xhr.open(options.type, options.url, options.async, options.username, options.password);
if (options.xhrFields) for (i in options.xhrFields) xhr[i] = options.xhrFields[i];
if (options.mimeType && xhr.overrideMimeType) xhr.overrideMimeType(options.mimeType);
if (!options.crossDomain && !headers["X-Requested-With"]) headers["X-Requested-With"] = "XMLHttpRequest";
for (i in headers) xhr.setRequestHeader(i, headers[i]);
callback = function(type) {
return function() {
if (callback) {
callback = errorCallback = xhr.onload = xhr.onerror = xhr.onabort = xhr.ontimeout = xhr.onreadystatechange = null;
if (type === "abort") xhr.abort();
else if (type === "error") if (typeof xhr.status !== "number") complete(0, "error");
else complete(xhr.status, xhr.statusText);
else complete(xhrSuccessStatus[xhr.status] || xhr.status, xhr.statusText, (xhr.responseType || "text") !== "text" || typeof xhr.responseText !== "string" ? { binary: xhr.response } : { text: xhr.responseText }, xhr.getAllResponseHeaders());
}
};
};
xhr.onload = callback();
errorCallback = xhr.onerror = xhr.ontimeout = callback("error");
if (xhr.onabort !== void 0) xhr.onabort = errorCallback;
else xhr.onreadystatechange = function() {
if (xhr.readyState === 4) window.setTimeout(function() {
if (callback) errorCallback();
});
};
callback = callback("abort");
try {
xhr.send(options.hasContent && options.data || null);
} catch (e) {
if (callback) throw e;
}
},
abort: function() {
if (callback) callback();
}
};
});
jQuery.ajaxPrefilter(function(s) {
if (s.crossDomain) s.contents.script = false;
});
jQuery.ajaxSetup({
accepts: { script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" },
contents: { script: /\b(?:java|ecma)script\b/ },
converters: { "text script": function(text) {
jQuery.globalEval(text);
return text;
} }
});
jQuery.ajaxPrefilter("script", function(s) {
if (s.cache === void 0) s.cache = false;
if (s.crossDomain) s.type = "GET";
});
jQuery.ajaxTransport("script", function(s) {
if (s.crossDomain || s.scriptAttrs) {
var script, callback;
return {
send: function(_, complete) {
script = jQuery("<script>").attr(s.scriptAttrs || {}).prop({
charset: s.scriptCharset,
src: s.url
}).on("load error", callback = function(evt) {
script.remove();
callback = null;
if (evt) complete(evt.type === "error" ? 404 : 200, evt.type);
});
document.head.appendChild(script[0]);
},
abort: function() {
if (callback) callback();
}
};
}
});
var oldCallbacks = [], rjsonp = /(=)\?(?=&|$)|\?\?/;
jQuery.ajaxSetup({
jsonp: "callback",
jsonpCallback: function() {
var callback = oldCallbacks.pop() || jQuery.expando + "_" + nonce.guid++;
this[callback] = true;
return callback;
}
});
jQuery.ajaxPrefilter("json jsonp", function(s, originalSettings, jqXHR) {
var callbackName, overwritten, responseContainer, jsonProp = s.jsonp !== false && (rjsonp.test(s.url) ? "url" : typeof s.data === "string" && (s.contentType || "").indexOf("application/x-www-form-urlencoded") === 0 && rjsonp.test(s.data) && "data");
if (jsonProp || s.dataTypes[0] === "jsonp") {
callbackName = s.jsonpCallback = isFunction(s.jsonpCallback) ? s.jsonpCallback() : s.jsonpCallback;
if (jsonProp) s[jsonProp] = s[jsonProp].replace(rjsonp, "$1" + callbackName);
else if (s.jsonp !== false) s.url += (rquery.test(s.url) ? "&" : "?") + s.jsonp + "=" + callbackName;
s.converters["script json"] = function() {
if (!responseContainer) jQuery.error(callbackName + " was not called");
return responseContainer[0];
};
s.dataTypes[0] = "json";
overwritten = window[callbackName];
window[callbackName] = function() {
responseContainer = arguments;
};
jqXHR.always(function() {
if (overwritten === void 0) jQuery(window).removeProp(callbackName);
else window[callbackName] = overwritten;
if (s[callbackName]) {
s.jsonpCallback = originalSettings.jsonpCallback;
oldCallbacks.push(callbackName);
}
if (responseContainer && isFunction(overwritten)) overwritten(responseContainer[0]);
responseContainer = overwritten = void 0;
});
return "script";
}
});
support.createHTMLDocument = (function() {
var body = document.implementation.createHTMLDocument("").body;
body.innerHTML = "<form></form><form></form>";
return body.childNodes.length === 2;
})();
jQuery.parseHTML = function(data, context, keepScripts) {
if (typeof data !== "string") return [];
if (typeof context === "boolean") {
keepScripts = context;
context = false;
}
var base, parsed, scripts;
if (!context) if (support.createHTMLDocument) {
context = document.implementation.createHTMLDocument("");
base = context.createElement("base");
base.href = document.location.href;
context.head.appendChild(base);
} else context = document;
parsed = rsingleTag.exec(data);
scripts = !keepScripts && [];
if (parsed) return [context.createElement(parsed[1])];
parsed = buildFragment([data], context, scripts);
if (scripts && scripts.length) jQuery(scripts).remove();
return jQuery.merge([], parsed.childNodes);
};
jQuery.fn.load = function(url, params, callback) {
var selector, type, response, self = this, off = url.indexOf(" ");
if (off > -1) {
selector = stripAndCollapse(url.slice(off));
url = url.slice(0, off);
}
if (isFunction(params)) {
callback = params;
params = void 0;
} else if (params && typeof params === "object") type = "POST";
if (self.length > 0) jQuery.ajax({
url,
type: type || "GET",
dataType: "html",
data: params
}).done(function(responseText) {
response = arguments;
self.html(selector ? jQuery("<div>").append(jQuery.parseHTML(responseText)).find(selector) : responseText);
}).always(callback && function(jqXHR, status) {
self.each(function() {
callback.apply(this, response || [
jqXHR.responseText,
status,
jqXHR
]);
});
});
return this;
};
jQuery.expr.pseudos.animated = function(elem) {
return jQuery.grep(jQuery.timers, function(fn) {
return elem === fn.elem;
}).length;
};
jQuery.offset = { setOffset: function(elem, options, i) {
var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition, position = jQuery.css(elem, "position"), curElem = jQuery(elem), props = {};
if (position === "static") elem.style.position = "relative";
curOffset = curElem.offset();
curCSSTop = jQuery.css(elem, "top");
curCSSLeft = jQuery.css(elem, "left");
calculatePosition = (position === "absolute" || position === "fixed") && (curCSSTop + curCSSLeft).indexOf("auto") > -1;
if (calculatePosition) {
curPosition = curElem.position();
curTop = curPosition.top;
curLeft = curPosition.left;
} else {
curTop = parseFloat(curCSSTop) || 0;
curLeft = parseFloat(curCSSLeft) || 0;
}
if (isFunction(options)) options = options.call(elem, i, jQuery.extend({}, curOffset));
if (options.top != null) props.top = options.top - curOffset.top + curTop;
if (options.left != null) props.left = options.left - curOffset.left + curLeft;
if ("using" in options) options.using.call(elem, props);
else curElem.css(props);
} };
jQuery.fn.extend({
offset: function(options) {
if (arguments.length) return options === void 0 ? this : this.each(function(i) {
jQuery.offset.setOffset(this, options, i);
});
var rect, win, elem = this[0];
if (!elem) return;
if (!elem.getClientRects().length) return {
top: 0,
left: 0
};
rect = elem.getBoundingClientRect();
win = elem.ownerDocument.defaultView;
return {
top: rect.top + win.pageYOffset,
left: rect.left + win.pageXOffset
};
},
position: function() {
if (!this[0]) return;
var offsetParent, offset, doc, elem = this[0], parentOffset = {
top: 0,
left: 0
};
if (jQuery.css(elem, "position") === "fixed") offset = elem.getBoundingClientRect();
else {
offset = this.offset();
doc = elem.ownerDocument;
offsetParent = elem.offsetParent || doc.documentElement;
while (offsetParent && (offsetParent === doc.body || offsetParent === doc.documentElement) && jQuery.css(offsetParent, "position") === "static") offsetParent = offsetParent.parentNode;
if (offsetParent && offsetParent !== elem && offsetParent.nodeType === 1) {
parentOffset = jQuery(offsetParent).offset();
parentOffset.top += jQuery.css(offsetParent, "borderTopWidth", true);
parentOffset.left += jQuery.css(offsetParent, "borderLeftWidth", true);
}
}
return {
top: offset.top - parentOffset.top - jQuery.css(elem, "marginTop", true),
left: offset.left - parentOffset.left - jQuery.css(elem, "marginLeft", true)
};
},
offsetParent: function() {
return this.map(function() {
var offsetParent = this.offsetParent;
while (offsetParent && jQuery.css(offsetParent, "position") === "static") offsetParent = offsetParent.offsetParent;
return offsetParent || documentElement;
});
}
});
jQuery.each({
scrollLeft: "pageXOffset",
scrollTop: "pageYOffset"
}, function(method, prop) {
var top = "pageYOffset" === prop;
jQuery.fn[method] = function(val) {
return access(this, function(elem, method, val) {
var win;
if (isWindow(elem)) win = elem;
else if (elem.nodeType === 9) win = elem.defaultView;
if (val === void 0) return win ? win[prop] : elem[method];
if (win) win.scrollTo(!top ? val : win.pageXOffset, top ? val : win.pageYOffset);
else elem[method] = val;
}, method, val, arguments.length);
};
});
jQuery.each(["top", "left"], function(_i, prop) {
jQuery.cssHooks[prop] = addGetHookIf(support.pixelPosition, function(elem, computed) {
if (computed) {
computed = curCSS(elem, prop);
return rnumnonpx.test(computed) ? jQuery(elem).position()[prop] + "px" : computed;
}
});
});
jQuery.each({
Height: "height",
Width: "width"
}, function(name, type) {
jQuery.each({
padding: "inner" + name,
content: type,
"": "outer" + name
}, function(defaultExtra, funcName) {
jQuery.fn[funcName] = function(margin, value) {
var chainable = arguments.length && (defaultExtra || typeof margin !== "boolean"), extra = defaultExtra || (margin === true || value === true ? "margin" : "border");
return access(this, function(elem, type, value) {
var doc;
if (isWindow(elem)) return funcName.indexOf("outer") === 0 ? elem["inner" + name] : elem.document.documentElement["client" + name];
if (elem.nodeType === 9) {
doc = elem.documentElement;
return Math.max(elem.body["scroll" + name], doc["scroll" + name], elem.body["offset" + name], doc["offset" + name], doc["client" + name]);
}
return value === void 0 ? jQuery.css(elem, type, extra) : jQuery.style(elem, type, value, extra);
}, type, chainable ? margin : void 0, chainable);
};
});
});
jQuery.each([
"ajaxStart",
"ajaxStop",
"ajaxComplete",
"ajaxError",
"ajaxSuccess",
"ajaxSend"
], function(_i, type) {
jQuery.fn[type] = function(fn) {
return this.on(type, fn);
};
});
jQuery.fn.extend({
bind: function(types, data, fn) {
return this.on(types, null, data, fn);
},
unbind: function(types, fn) {
return this.off(types, null, fn);
},
delegate: function(selector, types, data, fn) {
return this.on(types, selector, data, fn);
},
undelegate: function(selector, types, fn) {
return arguments.length === 1 ? this.off(selector, "**") : this.off(types, selector || "**", fn);
},
hover: function(fnOver, fnOut) {
return this.on("mouseenter", fnOver).on("mouseleave", fnOut || fnOver);
}
});
jQuery.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "), function(_i, name) {
jQuery.fn[name] = function(data, fn) {
return arguments.length > 0 ? this.on(name, null, data, fn) : this.trigger(name);
};
});
var rtrim = /^[\s\uFEFF\xA0]+|([^\s\uFEFF\xA0])[\s\uFEFF\xA0]+$/g;
jQuery.proxy = function(fn, context) {
var tmp, args, proxy;
if (typeof context === "string") {
tmp = fn[context];
context = fn;
fn = tmp;
}
if (!isFunction(fn)) return;
args = slice.call(arguments, 2);
proxy = function() {
return fn.apply(context || this, args.concat(slice.call(arguments)));
};
proxy.guid = fn.guid = fn.guid || jQuery.guid++;
return proxy;
};
jQuery.holdReady = function(hold) {
if (hold) jQuery.readyWait++;
else jQuery.ready(true);
};
jQuery.isArray = Array.isArray;
jQuery.parseJSON = JSON.parse;
jQuery.nodeName = nodeName;
jQuery.isFunction = isFunction;
jQuery.isWindow = isWindow;
jQuery.camelCase = camelCase;
jQuery.type = toType;
jQuery.now = Date.now;
jQuery.isNumeric = function(obj) {
var type = jQuery.type(obj);
return (type === "number" || type === "string") && !isNaN(obj - parseFloat(obj));
};
jQuery.trim = function(text) {
return text == null ? "" : (text + "").replace(rtrim, "$1");
};
if (typeof define === "function" && define.amd) define("jquery", [], function() {
return jQuery;
});
var _jQuery = window.jQuery, _$ = window.$;
jQuery.noConflict = function(deep) {
if (window.$ === jQuery) window.$ = _$;
if (deep && window.jQuery === jQuery) window.jQuery = _jQuery;
return jQuery;
};
if (typeof noGlobal === "undefined") window.jQuery = window.$ = jQuery;
return jQuery;
});
}))(), 1);
window.jQuery = import_jquery.default;
window.$ = import_jquery.default;
var require_layer$1 = __commonJSMin((() => {}));
var import_layer = __toESM(__commonJSMin(((exports, module) => {
require_layer$1();
var isLayui = window.layui && layui.define, $, win, ready = {
getPath: function() {
var js = document.scripts, script = js[js.length - 1], jsPath = script.src;
if (script.getAttribute("merge")) return;
return jsPath.substring(0, jsPath.lastIndexOf("/") + 1);
}(),
config: {},
end: {},
minIndex: 0,
minLeft: [],
btn: ["确定", "取消"],
type: [
"dialog",
"page",
"iframe",
"loading",
"tips"
]
};
var layer = {
v: "3.0.1",
ie: function() {
var agent = navigator.userAgent.toLowerCase();
return !!window.ActiveXObject || "ActiveXObject" in window ? (agent.match(/msie\s(\d+)/) || [])[1] || "11" : false;
}(),
index: window.layer && window.layer.v ? 1e5 : 0,
path: ready.getPath,
config: function(options, fn) {
options = options || {};
layer.cache = ready.config = $.extend({}, ready.config, options);
layer.path = ready.config.path || layer.path;
typeof options.extend === "string" && (options.extend = [options.extend]);
if (ready.config.path) layer.ready();
if (!options.extend) return this;
isLayui ? layui.addcss("modules/layer/" + options.extend) : layer.link("skin/" + options.extend);
return this;
},
link: function(href, fn, cssname) {
if (!layer.path) return;
var head = $("head")[0], link = document.createElement("link");
if (typeof fn === "string") cssname = fn;
var id = "layuicss-" + (cssname || href).replace(/\.|\//g, ""), timeout = 0;
link.rel = "stylesheet";
link.href = layer.path + href;
link.id = id;
if (!$("#" + id)[0]) head.appendChild(link);
if (typeof fn !== "function") return;
(function poll() {
if (++timeout > 8 * 1e3 / 100) return window.console && console.error("layer.css: Invalid");
parseInt($("#" + id).css("width")) === 1989 ? fn() : setTimeout(poll, 100);
})();
},
ready: function(callback) {
var cssname = "skinlayercss", ver = "1110";
isLayui ? layui.addcss("modules/layer/default/layer.css?v=" + layer.v + ver, callback, cssname) : layer.link("skin/default/layer.css?v=" + layer.v + ver, callback, cssname);
return this;
},
alert: function(content, options, yes) {
var type = typeof options === "function";
if (type) yes = options;
return layer.open($.extend({
content,
yes
}, type ? {} : options));
},
confirm: function(content, options, yes, cancel) {
var type = typeof options === "function";
if (type) {
cancel = yes;
yes = options;
}
return layer.open($.extend({
content,
btn: ready.btn,
yes,
btn2: cancel
}, type ? {} : options));
},
msg: function(content, options, end) {
var type = typeof options === "function", rskin = ready.config.skin;
var skin = (rskin ? rskin + " " + rskin + "-msg" : "") || "layui-layer-msg";
var anim = doms.anim.length - 1;
if (type) end = options;
return layer.open($.extend({
content,
time: 3e3,
shade: false,
skin,
title: false,
closeBtn: false,
btn: false,
resize: false,
end
}, type && !ready.config.skin ? {
skin: skin + " layui-layer-hui",
anim
} : function() {
options = options || {};
if (options.icon === -1 || options.icon === void 0 && !ready.config.skin) options.skin = skin + " " + (options.skin || "layui-layer-hui");
return options;
}()));
},
load: function(icon, options) {
return layer.open($.extend({
type: 3,
icon: icon || 0,
resize: false,
shade: .01
}, options));
},
tips: function(content, follow, options) {
return layer.open($.extend({
type: 4,
content: [content, follow],
closeBtn: false,
time: 3e3,
shade: false,
resize: false,
fixed: false,
maxWidth: 210
}, options));
}
};
var Class = function(setings) {
var that = this;
that.index = ++layer.index;
that.config = $.extend({}, that.config, ready.config, setings);
document.body ? that.creat() : setTimeout(function() {
that.creat();
}, 50);
};
Class.pt = Class.prototype;
var doms = [
"layui-layer",
".layui-layer-title",
".layui-layer-main",
".layui-layer-dialog",
"layui-layer-iframe",
"layui-layer-content",
"layui-layer-btn",
"layui-layer-close"
];
doms.anim = [
"layer-anim",
"layer-anim-01",
"layer-anim-02",
"layer-anim-03",
"layer-anim-04",
"layer-anim-05",
"layer-anim-06"
];
Class.pt.config = {
type: 0,
shade: .3,
fixed: true,
move: doms[1],
title: "信息",
offset: "auto",
area: "auto",
closeBtn: 1,
time: 0,
zIndex: 19891014,
maxWidth: 360,
anim: 0,
icon: -1,
moveType: 1,
resize: true,
scrollbar: true,
tips: 2
};
Class.pt.vessel = function(conType, callback) {
var that = this, times = that.index, config = that.config;
var zIndex = config.zIndex + times, titype = typeof config.title === "object";
var ismax = config.maxmin && (config.type === 1 || config.type === 2);
var titleHTML = config.title ? "<div class=\"layui-layer-title\" style=\"" + (titype ? config.title[1] : "") + "\">" + (titype ? config.title[0] : config.title) + "</div>" : "";
config.zIndex = zIndex;
callback([config.shade ? "<div class=\"layui-layer-shade\" id=\"layui-layer-shade" + times + "\" times=\"" + times + "\" style=\"" + ("z-index:" + (zIndex - 1) + "; background-color:" + (config.shade[1] || "#000") + "; opacity:" + (config.shade[0] || config.shade) + "; filter:alpha(opacity=" + (config.shade[0] * 100 || config.shade * 100) + ");") + "\"></div>" : "", "<div class=\"" + doms[0] + (" layui-layer-" + ready.type[config.type]) + ((config.type == 0 || config.type == 2) && !config.shade ? " layui-layer-border" : "") + " " + (config.skin || "") + "\" id=\"" + doms[0] + times + "\" type=\"" + ready.type[config.type] + "\" times=\"" + times + "\" showtime=\"" + config.time + "\" conType=\"" + (conType ? "object" : "string") + "\" style=\"z-index: " + zIndex + "; width:" + config.area[0] + ";height:" + config.area[1] + (config.fixed ? "" : ";position:absolute;") + "\">" + (conType && config.type != 2 ? "" : titleHTML) + "<div id=\"" + (config.id || "") + "\" class=\"layui-layer-content" + (config.type == 0 && config.icon !== -1 ? " layui-layer-padding" : "") + (config.type == 3 ? " layui-layer-loading" + config.icon : "") + "\">" + (config.type == 0 && config.icon !== -1 ? "<i class=\"layui-layer-ico layui-layer-ico" + config.icon + "\"></i>" : "") + (config.type == 1 && conType ? "" : config.content || "") + "</div><span class=\"layui-layer-setwin\">" + function() {
var closebtn = ismax ? "<a class=\"layui-layer-min\" href=\"javascript:;\"><cite></cite></a><a class=\"layui-layer-ico layui-layer-max\" href=\"javascript:;\"></a>" : "";
config.closeBtn && (closebtn += "<a class=\"layui-layer-ico " + doms[7] + " " + doms[7] + (config.title ? config.closeBtn : config.type == 4 ? "1" : "2") + "\" href=\"javascript:;\"></a>");
return closebtn;
}() + "</span>" + (config.btn ? function() {
var button = "";
typeof config.btn === "string" && (config.btn = [config.btn]);
for (var i = 0, len = config.btn.length; i < len; i++) button += "<a class=\"" + doms[6] + i + "\">" + config.btn[i] + "</a>";
return "<div class=\"" + doms[6] + " layui-layer-btn-" + (config.btnAlign || "") + "\">" + button + "</div>";
}() : "") + (config.resize ? "<span class=\"layui-layer-resize\"></span>" : "") + "</div>"], titleHTML, $("<div class=\"layui-layer-move\"></div>"));
return that;
};
Class.pt.creat = function() {
var that = this, config = that.config, times = that.index, content = config.content, conType = typeof content === "object", body = $("body");
if ($("#" + config.id)[0]) return;
if (typeof config.area === "string") config.area = config.area === "auto" ? ["", ""] : [config.area, ""];
if (config.shift) config.anim = config.shift;
if (layer.ie == 6) config.fixed = false;
switch (config.type) {
case 0:
config.btn = "btn" in config ? config.btn : ready.btn[0];
layer.closeAll("dialog");
break;
case 2:
var content = config.content = conType ? config.content : [config.content || "http://layer.layui.com", "auto"];
config.content = "<iframe scrolling=\"" + (config.content[1] || "auto") + "\" allowtransparency=\"true\" id=\"" + doms[4] + times + "\" name=\"" + doms[4] + times + "\" onload=\"this.className='';\" class=\"layui-layer-load\" frameborder=\"0\" src=\"" + config.content[0] + "\"></iframe>";
break;
case 3:
delete config.title;
delete config.closeBtn;
config.icon === -1 && config.icon;
layer.closeAll("loading");
break;
case 4:
conType || (config.content = [config.content, "body"]);
config.follow = config.content[1];
config.content = config.content[0] + "<i class=\"layui-layer-TipsG\"></i>";
delete config.title;
config.tips = typeof config.tips === "object" ? config.tips : [config.tips, true];
config.tipsMore || layer.closeAll("tips");
break;
}
that.vessel(conType, function(html, titleHTML, moveElem) {
body.append(html[0]);
conType ? function() {
config.type == 2 || config.type == 4 ? function() {
$("body").append(html[1]);
}() : function() {
if (!content.parents("." + doms[0])[0]) {
content.data("display", content.css("display")).show().addClass("layui-layer-wrap").wrap(html[1]);
$("#" + doms[0] + times).find("." + doms[5]).before(titleHTML);
}
}();
}() : body.append(html[1]);
$(".layui-layer-move")[0] || body.append(ready.moveElem = moveElem);
that.layero = $("#" + doms[0] + times);
config.scrollbar || doms.html.css("overflow", "hidden").attr("layer-full", times);
}).auto(times);
config.type == 2 && layer.ie == 6 && that.layero.find("iframe").attr("src", content[0]);
config.type == 4 ? that.tips() : that.offset();
if (config.fixed) win.on("resize", function() {
that.offset();
(/^\d+%$/.test(config.area[0]) || /^\d+%$/.test(config.area[1])) && that.auto(times);
config.type == 4 && that.tips();
});
config.time <= 0 || setTimeout(function() {
layer.close(that.index);
}, config.time);
that.move().callback();
if (doms.anim[config.anim]) that.layero.addClass(doms.anim[config.anim]).data("anim", true);
};
Class.pt.auto = function(index) {
var that = this, config = that.config, layero = $("#" + doms[0] + index);
if (config.area[0] === "" && config.maxWidth > 0) {
if (layer.ie && layer.ie < 8 && config.btn) layero.width(layero.innerWidth());
layero.outerWidth() > config.maxWidth && layero.width(config.maxWidth);
}
var area = [layero.innerWidth(), layero.innerHeight()];
var titHeight = layero.find(doms[1]).outerHeight() || 0;
var btnHeight = layero.find("." + doms[6]).outerHeight() || 0;
function setHeight(elem) {
elem = layero.find(elem);
elem.height(area[1] - titHeight - btnHeight - 2 * (parseFloat(elem.css("padding")) | 0));
}
switch (config.type) {
case 2:
setHeight("iframe");
break;
default:
if (config.area[1] === "") {
if (config.fixed && area[1] >= win.height()) {
area[1] = win.height();
setHeight("." + doms[5]);
}
} else setHeight("." + doms[5]);
break;
}
return that;
};
Class.pt.offset = function() {
var that = this, config = that.config, layero = that.layero;
var area = [layero.outerWidth(), layero.outerHeight()];
var type = typeof config.offset === "object";
that.offsetTop = (win.height() - area[1]) / 2;
that.offsetLeft = (win.width() - area[0]) / 2;
if (type) {
that.offsetTop = config.offset[0];
that.offsetLeft = config.offset[1] || that.offsetLeft;
} else if (config.offset !== "auto") if (config.offset === "t") that.offsetTop = 0;
else if (config.offset === "r") that.offsetLeft = win.width() - area[0];
else if (config.offset === "b") that.offsetTop = win.height() - area[1];
else if (config.offset === "l") that.offsetLeft = 0;
else if (config.offset === "lt") {
that.offsetTop = 0;
that.offsetLeft = 0;
} else if (config.offset === "lb") {
that.offsetTop = win.height() - area[1];
that.offsetLeft = 0;
} else if (config.offset === "rt") {
that.offsetTop = 0;
that.offsetLeft = win.width() - area[0];
} else if (config.offset === "rb") {
that.offsetTop = win.height() - area[1];
that.offsetLeft = win.width() - area[0];
} else that.offsetTop = config.offset;
if (!config.fixed) {
that.offsetTop = /%$/.test(that.offsetTop) ? win.height() * parseFloat(that.offsetTop) / 100 : parseFloat(that.offsetTop);
that.offsetLeft = /%$/.test(that.offsetLeft) ? win.width() * parseFloat(that.offsetLeft) / 100 : parseFloat(that.offsetLeft);
that.offsetTop += win.scrollTop();
that.offsetLeft += win.scrollLeft();
}
if (layero.attr("minLeft")) {
that.offsetTop = win.height() - (layero.find(doms[1]).outerHeight() || 0);
that.offsetLeft = layero.css("left");
}
layero.css({
top: that.offsetTop,
left: that.offsetLeft
});
};
Class.pt.tips = function() {
var that = this, config = that.config, layero = that.layero;
var layArea = [layero.outerWidth(), layero.outerHeight()], follow = $(config.follow);
if (!follow[0]) follow = $("body");
var goal = {
width: follow.outerWidth(),
height: follow.outerHeight(),
top: follow.offset().top,
left: follow.offset().left
}, tipsG = layero.find(".layui-layer-TipsG");
var guide = config.tips[0];
config.tips[1] || tipsG.remove();
goal.autoLeft = function() {
if (goal.left + layArea[0] - win.width() > 0) {
goal.tipLeft = goal.left + goal.width - layArea[0];
tipsG.css({
right: 12,
left: "auto"
});
} else goal.tipLeft = goal.left;
};
goal.where = [
function() {
goal.autoLeft();
goal.tipTop = goal.top - layArea[1] - 10;
tipsG.removeClass("layui-layer-TipsB").addClass("layui-layer-TipsT").css("border-right-color", config.tips[1]);
},
function() {
goal.tipLeft = goal.left + goal.width + 10;
goal.tipTop = goal.top;
tipsG.removeClass("layui-layer-TipsL").addClass("layui-layer-TipsR").css("border-bottom-color", config.tips[1]);
},
function() {
goal.autoLeft();
goal.tipTop = goal.top + goal.height + 10;
tipsG.removeClass("layui-layer-TipsT").addClass("layui-layer-TipsB").css("border-right-color", config.tips[1]);
},
function() {
goal.tipLeft = goal.left - layArea[0] - 10;
goal.tipTop = goal.top;
tipsG.removeClass("layui-layer-TipsR").addClass("layui-layer-TipsL").css("border-bottom-color", config.tips[1]);
}
];
goal.where[guide - 1]();
if (guide === 1) goal.top - (win.scrollTop() + layArea[1] + 16) < 0 && goal.where[2]();
else if (guide === 2) win.width() - (goal.left + goal.width + layArea[0] + 16) > 0 || goal.where[3]();
else if (guide === 3) goal.top - win.scrollTop() + goal.height + layArea[1] + 16 - win.height() > 0 && goal.where[0]();
else if (guide === 4) layArea[0] + 16 - goal.left > 0 && goal.where[1]();
layero.find("." + doms[5]).css({
"background-color": config.tips[1],
"padding-right": config.closeBtn ? "30px" : ""
});
layero.css({
left: goal.tipLeft - (config.fixed ? win.scrollLeft() : 0),
top: goal.tipTop - (config.fixed ? win.scrollTop() : 0)
});
};
Class.pt.move = function() {
var that = this, config = that.config, _DOC = $(document), layero = that.layero, moveElem = layero.find(config.move), resizeElem = layero.find(".layui-layer-resize"), dict = {};
if (config.move) moveElem.css("cursor", "move");
moveElem.on("mousedown", function(e) {
e.preventDefault();
if (config.move) {
dict.moveStart = true;
dict.offset = [e.clientX - parseFloat(layero.css("left")), e.clientY - parseFloat(layero.css("top"))];
ready.moveElem.css("cursor", "move").show();
}
});
resizeElem.on("mousedown", function(e) {
e.preventDefault();
dict.resizeStart = true;
dict.offset = [e.clientX, e.clientY];
dict.area = [layero.outerWidth(), layero.outerHeight()];
ready.moveElem.css("cursor", "se-resize").show();
});
_DOC.on("mousemove", function(e) {
if (dict.moveStart) {
var X = e.clientX - dict.offset[0], Y = e.clientY - dict.offset[1], fixed = layero.css("position") === "fixed";
e.preventDefault();
dict.stX = fixed ? 0 : win.scrollLeft();
dict.stY = fixed ? 0 : win.scrollTop();
if (!config.moveOut) {
var setRig = win.width() - layero.outerWidth() + dict.stX, setBot = win.height() - layero.outerHeight() + dict.stY;
X < dict.stX && (X = dict.stX);
X > setRig && (X = setRig);
Y < dict.stY && (Y = dict.stY);
Y > setBot && (Y = setBot);
}
layero.css({
left: X,
top: Y
});
}
if (config.resize && dict.resizeStart) {
var X = e.clientX - dict.offset[0], Y = e.clientY - dict.offset[1];
e.preventDefault();
layer.style(that.index, {
width: dict.area[0] + X,
height: dict.area[1] + Y
});
dict.isResize = true;
}
}).on("mouseup", function(e) {
if (dict.moveStart) {
delete dict.moveStart;
ready.moveElem.hide();
config.moveEnd && config.moveEnd();
}
if (dict.resizeStart) {
delete dict.resizeStart;
ready.moveElem.hide();
}
});
return that;
};
Class.pt.callback = function() {
var that = this, layero = that.layero, config = that.config;
that.openLayer();
if (config.success) if (config.type == 2) layero.find("iframe").on("load", function() {
config.success(layero, that.index);
});
else config.success(layero, that.index);
layer.ie == 6 && that.IE6(layero);
layero.find("." + doms[6]).children("a").on("click", function() {
var index = $(this).index();
if (index === 0) if (config.yes) config.yes(that.index, layero);
else if (config["btn1"]) config["btn1"](that.index, layero);
else layer.close(that.index);
else (config["btn" + (index + 1)] && config["btn" + (index + 1)](that.index, layero)) === false || layer.close(that.index);
});
function cancel() {
(config.cancel && config.cancel(that.index, layero)) === false || layer.close(that.index);
}
layero.find("." + doms[7]).on("click", cancel);
if (config.shadeClose) $("#layui-layer-shade" + that.index).on("click", function() {
layer.close(that.index);
});
layero.find(".layui-layer-min").on("click", function() {
(config.min && config.min(layero)) === false || layer.min(that.index, config);
});
layero.find(".layui-layer-max").on("click", function() {
if ($(this).hasClass("layui-layer-maxmin")) {
layer.restore(that.index);
config.restore && config.restore(layero);
} else {
layer.full(that.index, config);
setTimeout(function() {
config.full && config.full(layero);
}, 100);
}
});
config.end && (ready.end[that.index] = config.end);
};
ready.reselect = function() {
$.each($("select"), function(index, value) {
var sthis = $(this);
if (!sthis.parents("." + doms[0])[0]) sthis.attr("layer") == 1 && $("." + doms[0]).length < 1 && sthis.removeAttr("layer").show();
sthis = null;
});
};
Class.pt.IE6 = function(layero) {
$("select").each(function(index, value) {
var sthis = $(this);
if (!sthis.parents("." + doms[0])[0]) sthis.css("display") === "none" || sthis.attr({ "layer": "1" }).hide();
sthis = null;
});
};
Class.pt.openLayer = function() {
layer.zIndex = this.config.zIndex;
layer.setTop = function(layero) {
var setZindex = function() {
layer.zIndex++;
layero.css("z-index", layer.zIndex + 1);
};
layer.zIndex = parseInt(layero[0].style.zIndex);
layero.on("mousedown", setZindex);
return layer.zIndex;
};
};
ready.record = function(layero) {
var area = [
layero.width(),
layero.height(),
layero.position().top,
layero.position().left + parseFloat(layero.css("margin-left"))
];
layero.find(".layui-layer-max").addClass("layui-layer-maxmin");
layero.attr({ area });
};
ready.rescollbar = function(index) {
if (doms.html.attr("layer-full") == index) {
if (doms.html[0].style.removeProperty) doms.html[0].style.removeProperty("overflow");
else doms.html[0].style.removeAttribute("overflow");
doms.html.removeAttr("layer-full");
}
};
window.layer = layer;
layer.getChildFrame = function(selector, index) {
index = index || $("." + doms[4]).attr("times");
return $("#" + doms[0] + index).find("iframe").contents().find(selector);
};
layer.getFrameIndex = function(name) {
return $("#" + name).parents("." + doms[4]).attr("times");
};
layer.iframeAuto = function(index) {
if (!index) return;
var heg = layer.getChildFrame("html", index).outerHeight();
var layero = $("#" + doms[0] + index);
var titHeight = layero.find(doms[1]).outerHeight() || 0;
var btnHeight = layero.find("." + doms[6]).outerHeight() || 0;
layero.css({ height: heg + titHeight + btnHeight });
layero.find("iframe").css({ height: heg });
};
layer.iframeSrc = function(index, url) {
$("#" + doms[0] + index).find("iframe").attr("src", url);
};
layer.style = function(index, options, limit) {
var layero = $("#" + doms[0] + index), contElem = layero.find(".layui-layer-content"), type = layero.attr("type"), titHeight = layero.find(doms[1]).outerHeight() || 0, btnHeight = layero.find("." + doms[6]).outerHeight() || 0;
layero.attr("minLeft");
if (type === ready.type[3] || type === ready.type[4]) return;
if (!limit) {
if (parseFloat(options.width) <= 260) options.width = 260;
if (parseFloat(options.height) - titHeight - btnHeight <= 64) options.height = 64 + titHeight + btnHeight;
}
layero.css(options);
btnHeight = layero.find("." + doms[6]).outerHeight();
if (type === ready.type[2]) layero.find("iframe").css({ height: parseFloat(options.height) - titHeight - btnHeight });
else contElem.css({ height: parseFloat(options.height) - titHeight - btnHeight - parseFloat(contElem.css("padding-top")) - parseFloat(contElem.css("padding-bottom")) });
};
layer.min = function(index, options) {
var layero = $("#" + doms[0] + index), titHeight = layero.find(doms[1]).outerHeight() || 0, left = layero.attr("minLeft") || 181 * ready.minIndex + "px", position = layero.css("position");
ready.record(layero);
if (ready.minLeft[0]) {
left = ready.minLeft[0];
ready.minLeft.shift();
}
layero.attr("position", position);
layer.style(index, {
width: 180,
height: titHeight,
left,
top: win.height() - titHeight,
position: "fixed",
overflow: "hidden"
}, true);
layero.find(".layui-layer-min").hide();
layero.attr("type") === "page" && layero.find(doms[4]).hide();
ready.rescollbar(index);
if (!layero.attr("minLeft")) ready.minIndex++;
layero.attr("minLeft", left);
};
layer.restore = function(index) {
var layero = $("#" + doms[0] + index), area = layero.attr("area").split(",");
layero.attr("type");
layer.style(index, {
width: parseFloat(area[0]),
height: parseFloat(area[1]),
top: parseFloat(area[2]),
left: parseFloat(area[3]),
position: layero.attr("position"),
overflow: "visible"
}, true);
layero.find(".layui-layer-max").removeClass("layui-layer-maxmin");
layero.find(".layui-layer-min").show();
layero.attr("type") === "page" && layero.find(doms[4]).show();
ready.rescollbar(index);
};
layer.full = function(index) {
var layero = $("#" + doms[0] + index), timer;
ready.record(layero);
if (!doms.html.attr("layer-full")) doms.html.css("overflow", "hidden").attr("layer-full", index);
clearTimeout(timer);
timer = setTimeout(function() {
var isfix = layero.css("position") === "fixed";
layer.style(index, {
top: isfix ? 0 : win.scrollTop(),
left: isfix ? 0 : win.scrollLeft(),
width: win.width(),
height: win.height()
}, true);
layero.find(".layui-layer-min").hide();
}, 100);
};
layer.title = function(name, index) {
$("#" + doms[0] + (index || layer.index)).find(doms[1]).html(name);
};
layer.close = function(index) {
var layero = $("#" + doms[0] + index), type = layero.attr("type"), closeAnim = "layer-anim-close";
if (!layero[0]) return;
var WRAP = "layui-layer-wrap", remove = function() {
if (type === ready.type[1] && layero.attr("conType") === "object") {
layero.children(":not(." + doms[5] + ")").remove();
var wrap = layero.find("." + WRAP);
for (var i = 0; i < 2; i++) wrap.unwrap();
wrap.css("display", wrap.data("display")).removeClass(WRAP);
} else {
if (type === ready.type[2]) try {
var iframe = $("#" + doms[4] + index)[0];
iframe.contentWindow.document.write("");
iframe.contentWindow.close();
layero.find("." + doms[5])[0].removeChild(iframe);
} catch (e) {}
layero[0].innerHTML = "";
layero.remove();
}
typeof ready.end[index] === "function" && ready.end[index]();
delete ready.end[index];
};
if (layero.data("anim")) layero.addClass(closeAnim);
$("#layui-layer-moves, #layui-layer-shade" + index).remove();
layer.ie == 6 && ready.reselect();
ready.rescollbar(index);
if (layero.attr("minLeft")) {
ready.minIndex--;
ready.minLeft.push(layero.attr("minLeft"));
}
setTimeout(function() {
remove();
}, layer.ie && layer.ie < 10 || !layero.data("anim") ? 0 : 200);
};
layer.closeAll = function(type) {
$.each($("." + doms[0]), function() {
var othis = $(this);
var is = type ? othis.attr("type") === type : 1;
is && layer.close(othis.attr("times"));
is = null;
});
};
var cache = layer.cache || {}, skin = function(type) {
return cache.skin ? " " + cache.skin + " " + cache.skin + "-" + type : "";
};
layer.prompt = function(options, yes) {
var style = "";
options = options || {};
if (typeof options === "function") yes = options;
if (options.area) {
var area = options.area;
style = "style=\"width: " + area[0] + "; height: " + area[1] + ";\"";
delete options.area;
}
var prompt, content = options.formType == 2 ? "<textarea class=\"layui-layer-input\"" + style + ">" + (options.value || "") + "</textarea>" : function() {
return "<input type=\"" + (options.formType == 1 ? "password" : "text") + "\" class=\"layui-layer-input\" value=\"" + (options.value || "") + "\">";
}();
return layer.open($.extend({
type: 1,
btn: ["确定", "取消"],
content,
skin: "layui-layer-prompt" + skin("prompt"),
maxWidth: win.width(),
success: function(layero) {
prompt = layero.find(".layui-layer-input");
prompt.focus();
},
resize: false,
yes: function(index) {
var value = prompt.val();
if (value === "") prompt.focus();
else if (value.length > (options.maxlength || 500)) layer.tips("最多输入" + (options.maxlength || 500) + "个字数", prompt, { tips: 1 });
else yes && yes(value, index, prompt);
}
}, options));
};
layer.tab = function(options) {
options = options || {};
var tab = options.tab || {};
return layer.open($.extend({
type: 1,
skin: "layui-layer-tab" + skin("tab"),
resize: false,
title: function() {
var len = tab.length, ii = 1, str = "";
if (len > 0) {
str = "<span class=\"layui-layer-tabnow\">" + tab[0].title + "</span>";
for (; ii < len; ii++) str += "<span>" + tab[ii].title + "</span>";
}
return str;
}(),
content: "<ul class=\"layui-layer-tabmain\">" + function() {
var len = tab.length, ii = 1, str = "";
if (len > 0) {
str = "<li class=\"layui-layer-tabli xubox_tab_layer\">" + (tab[0].content || "no content") + "</li>";
for (; ii < len; ii++) str += "<li class=\"layui-layer-tabli\">" + (tab[ii].content || "no content") + "</li>";
}
return str;
}() + "</ul>",
success: function(layero) {
var btn = layero.find(".layui-layer-title").children();
var main = layero.find(".layui-layer-tabmain").children();
btn.on("mousedown", function(e) {
e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true;
var othis = $(this), index = othis.index();
othis.addClass("layui-layer-tabnow").siblings().removeClass("layui-layer-tabnow");
main.eq(index).show().siblings().hide();
typeof options.change === "function" && options.change(index);
});
}
}, options));
};
layer.photos = function(options, loop, key) {
var dict = {};
options = options || {};
if (!options.photos) return;
var type = options.photos.constructor === Object;
var photos = type ? options.photos : {}, data = photos.data || [];
var start = photos.start || 0;
dict.imgIndex = (start | 0) + 1;
options.img = options.img || "img";
if (!type) {
var parent = $(options.photos), pushData = function() {
data = [];
parent.find(options.img).each(function(index) {
var othis = $(this);
othis.attr("layer-index", index);
data.push({
alt: othis.attr("alt"),
pid: othis.attr("layer-pid"),
src: othis.attr("layer-src") || othis.attr("src"),
thumb: othis.attr("src")
});
});
};
pushData();
if (data.length === 0) return;
loop || parent.on("click", options.img, function() {
var index = $(this).attr("layer-index");
layer.photos($.extend(options, {
photos: {
start: index,
data,
tab: options.tab
},
full: options.full
}), true);
pushData();
});
if (!loop) return;
} else if (data.length === 0) return layer.msg("没有图片");
dict.imgprev = function(key) {
dict.imgIndex--;
if (dict.imgIndex < 1) dict.imgIndex = data.length;
dict.tabimg(key);
};
dict.imgnext = function(key, errorMsg) {
dict.imgIndex++;
if (dict.imgIndex > data.length) {
dict.imgIndex = 1;
if (errorMsg) return;
}
dict.tabimg(key);
};
dict.keyup = function(event) {
if (!dict.end) {
var code = event.keyCode;
event.preventDefault();
if (code === 37) dict.imgprev(true);
else if (code === 39) dict.imgnext(true);
else if (code === 27) layer.close(dict.index);
}
};
dict.tabimg = function(key) {
if (data.length <= 1) return;
photos.start = dict.imgIndex - 1;
layer.close(dict.index);
layer.photos(options, true, key);
};
dict.event = function() {
dict.bigimg.hover(function() {
dict.imgsee.show();
}, function() {
dict.imgsee.hide();
});
dict.bigimg.find(".layui-layer-imgprev").on("click", function(event) {
event.preventDefault();
dict.imgprev();
});
dict.bigimg.find(".layui-layer-imgnext").on("click", function(event) {
event.preventDefault();
dict.imgnext();
});
$(document).on("keyup", dict.keyup);
};
function loadImage(url, callback, error) {
var img = new Image();
img.src = url;
if (img.complete) return callback(img);
img.onload = function() {
img.onload = null;
callback(img);
};
img.onerror = function(e) {
img.onerror = null;
error(e);
};
}
dict.loadi = layer.load(1, {
shade: "shade" in options ? false : .9,
scrollbar: false
});
loadImage(data[start].src, function(img) {
layer.close(dict.loadi);
dict.index = layer.open($.extend({
type: 1,
area: function() {
var imgarea = [img.width, img.height];
var winarea = [$(window).width() - 100, $(window).height() - 100];
if (!options.full && (imgarea[0] > winarea[0] || imgarea[1] > winarea[1])) {
var wh = [imgarea[0] / winarea[0], imgarea[1] / winarea[1]];
if (wh[0] > wh[1]) {
imgarea[0] = imgarea[0] / wh[0];
imgarea[1] = imgarea[1] / wh[0];
} else if (wh[0] < wh[1]) {
imgarea[0] = imgarea[0] / wh[1];
imgarea[1] = imgarea[1] / wh[1];
}
}
return [imgarea[0] + "px", imgarea[1] + "px"];
}(),
title: false,
shade: .9,
shadeClose: true,
closeBtn: false,
move: ".layui-layer-phimg img",
moveType: 1,
scrollbar: false,
moveOut: true,
anim: Math.random() * 5 | 0,
skin: "layui-layer-photos" + skin("photos"),
content: "<div class=\"layui-layer-phimg\"><img src=\"" + data[start].src + "\" alt=\"" + (data[start].alt || "") + "\" layer-pid=\"" + data[start].pid + "\"><div class=\"layui-layer-imgsee\">" + (data.length > 1 ? "<span class=\"layui-layer-imguide\"><a href=\"javascript:;\" class=\"layui-layer-iconext layui-layer-imgprev\"></a><a href=\"javascript:;\" class=\"layui-layer-iconext layui-layer-imgnext\"></a></span>" : "") + "<div class=\"layui-layer-imgbar\" style=\"display:" + (key ? "block" : "") + "\"><span class=\"layui-layer-imgtit\"><a href=\"javascript:;\">" + (data[start].alt || "") + "</a><em>" + dict.imgIndex + "/" + data.length + "</em></span></div></div></div>",
success: function(layero, index) {
dict.bigimg = layero.find(".layui-layer-phimg");
dict.imgsee = layero.find(".layui-layer-imguide,.layui-layer-imgbar");
dict.event(layero);
options.tab && options.tab(data[start], layero);
},
end: function() {
dict.end = true;
$(document).off("keyup", dict.keyup);
}
}, options));
}, function() {
layer.close(dict.loadi);
layer.msg("当前图片地址异常<br>是否继续查看下一张?", {
time: 3e4,
btn: ["下一张", "不看了"],
yes: function() {
data.length > 1 && dict.imgnext(true, true);
}
});
});
};
ready.run = function(_$) {
$ = _$;
win = $(window);
doms.html = $("html");
layer.open = function(deliver) {
return new Class(deliver).index;
};
};
ready.run(jQuery);
module.exports = layer;
}))(), 1);
var CoreFeature = class {
constructor(table) {
this.table = table;
}
reloadData(data, silent, columnsChanged) {
return this.table.dataLoader.load(data, void 0, void 0, void 0, silent, columnsChanged);
}
langText() {
return this.table.modules.localize.getText(...arguments);
}
langBind() {
return this.table.modules.localize.bind(...arguments);
}
langLocale() {
return this.table.modules.localize.getLocale(...arguments);
}
commsConnections() {
return this.table.modules.comms.getConnections(...arguments);
}
commsSend() {
return this.table.modules.comms.send(...arguments);
}
layoutMode() {
return this.table.modules.layout.getMode();
}
layoutRefresh(force) {
return this.table.modules.layout.layout(force);
}
subscribe() {
return this.table.eventBus.subscribe(...arguments);
}
unsubscribe() {
return this.table.eventBus.unsubscribe(...arguments);
}
subscribed(key) {
return this.table.eventBus.subscribed(key);
}
subscriptionChange() {
return this.table.eventBus.subscriptionChange(...arguments);
}
dispatch() {
return this.table.eventBus.dispatch(...arguments);
}
chain() {
return this.table.eventBus.chain(...arguments);
}
confirm() {
return this.table.eventBus.confirm(...arguments);
}
dispatchExternal() {
return this.table.externalEvents.dispatch(...arguments);
}
subscribedExternal(key) {
return this.table.externalEvents.subscribed(key);
}
subscriptionChangeExternal() {
return this.table.externalEvents.subscriptionChange(...arguments);
}
options(key) {
return this.table.options[key];
}
setOption(key, value) {
if (typeof value !== "undefined") this.table.options[key] = value;
return this.table.options[key];
}
deprecationCheck(oldOption, newOption, convert) {
return this.table.deprecationAdvisor.check(oldOption, newOption, convert);
}
deprecationCheckMsg(oldOption, msg) {
return this.table.deprecationAdvisor.checkMsg(oldOption, msg);
}
deprecationMsg(msg) {
return this.table.deprecationAdvisor.msg(msg);
}
module(key) {
return this.table.module(key);
}
};
var Helpers = class {
static elVisible(el) {
return !(el.offsetWidth <= 0 && el.offsetHeight <= 0);
}
static elOffset(el) {
var box = el.getBoundingClientRect();
return {
top: box.top + window.pageYOffset - document.documentElement.clientTop,
left: box.left + window.pageXOffset - document.documentElement.clientLeft
};
}
static retrieveNestedData(separator, field, data) {
var structure = separator ? field.split(separator) : [field], length = structure.length, output;
for (let i = 0; i < length; i++) {
data = data[structure[i]];
output = data;
if (!data) break;
}
return output;
}
static deepClone(obj, clone, list = []) {
var objectProto = {}.__proto__, arrayProto = [].__proto__;
if (!clone) clone = Object.assign(Array.isArray(obj) ? [] : {}, obj);
for (var i in obj) {
let subject = obj[i], match, copy;
if (subject != null && typeof subject === "object" && (subject.__proto__ === objectProto || subject.__proto__ === arrayProto)) {
match = list.findIndex((item) => {
return item.subject === subject;
});
if (match > -1) clone[i] = list[match].copy;
else {
copy = Object.assign(Array.isArray(subject) ? [] : {}, subject);
list.unshift({
subject,
copy
});
clone[i] = this.deepClone(subject, copy, list);
}
}
}
return clone;
}
};
var Popup$1 = class Popup extends CoreFeature {
constructor(table, element, parent) {
super(table);
this.element = element;
this.container = this._lookupContainer();
this.parent = parent;
this.reversedX = false;
this.childPopup = null;
this.blurable = false;
this.blurCallback = null;
this.blurEventsBound = false;
this.renderedCallback = null;
this.visible = false;
this.hideable = true;
this.element.classList.add("tabulator-popup-container");
this.blurEvent = this.hide.bind(this, false);
this.escEvent = this._escapeCheck.bind(this);
this.destroyBinding = this.tableDestroyed.bind(this);
this.destroyed = false;
}
tableDestroyed() {
this.destroyed = true;
this.hide(true);
}
_lookupContainer() {
var container = this.table.options.popupContainer;
if (typeof container === "string") {
container = document.querySelector(container);
if (!container) console.warn("Menu Error - no container element found matching selector:", this.table.options.popupContainer, "(defaulting to document body)");
} else if (container === true) container = this.table.element;
if (container && !this._checkContainerIsParent(container)) {
container = false;
console.warn("Menu Error - container element does not contain this table:", this.table.options.popupContainer, "(defaulting to document body)");
}
if (!container) container = document.body;
return container;
}
_checkContainerIsParent(container, element = this.table.element) {
if (container === element) return true;
else return element.parentNode ? this._checkContainerIsParent(container, element.parentNode) : false;
}
renderCallback(callback) {
this.renderedCallback = callback;
}
containerEventCoords(e) {
var touch = !(e instanceof MouseEvent);
var x = touch ? e.touches[0].pageX : e.pageX;
var y = touch ? e.touches[0].pageY : e.pageY;
if (this.container !== document.body) {
let parentOffset = Helpers.elOffset(this.container);
x -= parentOffset.left;
y -= parentOffset.top;
}
return {
x,
y
};
}
elementPositionCoords(element, position = "right") {
var offset = Helpers.elOffset(element), containerOffset, x, y;
if (this.container !== document.body) {
containerOffset = Helpers.elOffset(this.container);
offset.left -= containerOffset.left;
offset.top -= containerOffset.top;
}
switch (position) {
case "right":
x = offset.left + element.offsetWidth;
y = offset.top - 1;
break;
case "bottom":
x = offset.left;
y = offset.top + element.offsetHeight;
break;
case "left":
x = offset.left;
y = offset.top - 1;
break;
case "top":
x = offset.left;
y = offset.top;
break;
case "center":
x = offset.left + element.offsetWidth / 2;
y = offset.top + element.offsetHeight / 2;
break;
}
return {
x,
y,
offset
};
}
show(origin, position) {
var x, y, parentEl, parentOffset, coords;
if (this.destroyed || this.table.destroyed) return this;
if (origin instanceof HTMLElement) {
parentEl = origin;
coords = this.elementPositionCoords(origin, position);
parentOffset = coords.offset;
x = coords.x;
y = coords.y;
} else if (typeof origin === "number") {
parentOffset = {
top: 0,
left: 0
};
x = origin;
y = position;
} else {
coords = this.containerEventCoords(origin);
x = coords.x;
y = coords.y;
this.reversedX = false;
}
this.element.style.top = y + "px";
this.element.style.left = x + "px";
this.container.appendChild(this.element);
if (typeof this.renderedCallback === "function") this.renderedCallback();
this._fitToScreen(x, y, parentEl, parentOffset, position);
this.visible = true;
this.subscribe("table-destroy", this.destroyBinding);
this.element.addEventListener("mousedown", (e) => {
e.stopPropagation();
});
return this;
}
_fitToScreen(x, y, parentEl, parentOffset, position) {
var scrollTop = this.container === document.body ? document.documentElement.scrollTop : this.container.scrollTop;
if (x + this.element.offsetWidth >= this.container.offsetWidth || this.reversedX) {
this.element.style.left = "";
if (parentEl) this.element.style.right = this.container.offsetWidth - parentOffset.left + "px";
else this.element.style.right = this.container.offsetWidth - x + "px";
this.reversedX = true;
}
let offsetHeight = Math.max(this.container.offsetHeight, scrollTop ? this.container.scrollHeight : 0);
if (y + this.element.offsetHeight > offsetHeight) if (parentEl) switch (position) {
case "bottom":
this.element.style.top = parseInt(this.element.style.top) - this.element.offsetHeight - parentEl.offsetHeight - 1 + "px";
break;
default: this.element.style.top = parseInt(this.element.style.top) - this.element.offsetHeight + parentEl.offsetHeight + 1 + "px";
}
else this.element.style.height = offsetHeight + "px";
}
isVisible() {
return this.visible;
}
hideOnBlur(callback) {
this.blurable = true;
if (this.visible) {
setTimeout(() => {
if (this.visible) {
this.table.rowManager.element.addEventListener("scroll", this.blurEvent);
this.subscribe("cell-editing", this.blurEvent);
document.body.addEventListener("click", this.blurEvent);
document.body.addEventListener("contextmenu", this.blurEvent);
document.body.addEventListener("mousedown", this.blurEvent);
window.addEventListener("resize", this.blurEvent);
document.body.addEventListener("keydown", this.escEvent);
this.blurEventsBound = true;
}
}, 100);
this.blurCallback = callback;
}
return this;
}
_escapeCheck(e) {
if (e.keyCode == 27) this.hide();
}
blockHide() {
this.hideable = false;
}
restoreHide() {
this.hideable = true;
}
hide(silent = false) {
if (this.visible && this.hideable) {
if (this.blurable && this.blurEventsBound) {
document.body.removeEventListener("keydown", this.escEvent);
document.body.removeEventListener("click", this.blurEvent);
document.body.removeEventListener("contextmenu", this.blurEvent);
document.body.removeEventListener("mousedown", this.blurEvent);
window.removeEventListener("resize", this.blurEvent);
this.table.rowManager.element.removeEventListener("scroll", this.blurEvent);
this.unsubscribe("cell-editing", this.blurEvent);
this.blurEventsBound = false;
}
if (this.childPopup) this.childPopup.hide();
if (this.parent) this.parent.childPopup = null;
if (this.element.parentNode) this.element.parentNode.removeChild(this.element);
this.visible = false;
if (this.blurCallback && !silent) this.blurCallback();
this.unsubscribe("table-destroy", this.destroyBinding);
}
return this;
}
child(element) {
if (this.childPopup) this.childPopup.hide();
this.childPopup = new Popup(this.table, element, this);
return this.childPopup;
}
};
var Module = class extends CoreFeature {
constructor(table, name) {
super(table);
this._handler = null;
}
initialize() {}
registerTableOption(key, value) {
this.table.optionsList.register(key, value);
}
registerColumnOption(key, value) {
this.table.columnManager.optionsList.register(key, value);
}
registerTableFunction(name, func) {
if (typeof this.table[name] === "undefined") this.table[name] = (...args) => {
this.table.initGuard(name);
return func(...args);
};
else console.warn("Unable to bind table function, name already in use", name);
}
registerComponentFunction(component, func, handler) {
return this.table.componentFunctionBinder.bind(component, func, handler);
}
registerDataHandler(handler, priority) {
this.table.rowManager.registerDataPipelineHandler(handler, priority);
this._handler = handler;
}
registerDisplayHandler(handler, priority) {
this.table.rowManager.registerDisplayPipelineHandler(handler, priority);
this._handler = handler;
}
displayRows(adjust) {
var index = this.table.rowManager.displayRows.length - 1, lookupIndex;
if (this._handler) {
lookupIndex = this.table.rowManager.displayPipeline.findIndex((item) => {
return item.handler === this._handler;
});
if (lookupIndex > -1) index = lookupIndex;
}
if (adjust) index = index + adjust;
if (this._handler) if (index > -1) return this.table.rowManager.getDisplayRows(index);
else return this.activeRows();
}
activeRows() {
return this.table.rowManager.activeRows;
}
refreshData(renderInPosition, handler) {
if (!handler) handler = this._handler;
if (handler) this.table.rowManager.refreshActiveData(handler, false, renderInPosition);
}
footerAppend(element) {
return this.table.footerManager.append(element);
}
footerPrepend(element) {
return this.table.footerManager.prepend(element);
}
footerRemove(element) {
return this.table.footerManager.remove(element);
}
popup(menuEl, menuContainer) {
return new Popup$1(this.table, menuEl, menuContainer);
}
alert(content, type) {
return this.table.alertManager.alert(content, type);
}
clearAlert() {
return this.table.alertManager.clear();
}
};
var defaultAccessors = { rownum: function(value, data, type, params, column, row) {
return row.getPosition();
} };
var Accessor = class Accessor extends Module {
static moduleName = "accessor";
static accessors = defaultAccessors;
constructor(table) {
super(table);
this.allowedTypes = [
"",
"data",
"download",
"clipboard",
"print",
"htmlOutput"
];
this.registerColumnOption("accessor");
this.registerColumnOption("accessorParams");
this.registerColumnOption("accessorData");
this.registerColumnOption("accessorDataParams");
this.registerColumnOption("accessorDownload");
this.registerColumnOption("accessorDownloadParams");
this.registerColumnOption("accessorClipboard");
this.registerColumnOption("accessorClipboardParams");
this.registerColumnOption("accessorPrint");
this.registerColumnOption("accessorPrintParams");
this.registerColumnOption("accessorHtmlOutput");
this.registerColumnOption("accessorHtmlOutputParams");
}
initialize() {
this.subscribe("column-layout", this.initializeColumn.bind(this));
this.subscribe("row-data-retrieve", this.transformRow.bind(this));
}
initializeColumn(column) {
var match = false, config = {};
this.allowedTypes.forEach((type) => {
var key = "accessor" + (type.charAt(0).toUpperCase() + type.slice(1)), accessor;
if (column.definition[key]) {
accessor = this.lookupAccessor(column.definition[key]);
if (accessor) {
match = true;
config[key] = {
accessor,
params: column.definition[key + "Params"] || {}
};
}
}
});
if (match) column.modules.accessor = config;
}
lookupAccessor(value) {
var accessor = false;
switch (typeof value) {
case "string":
if (Accessor.accessors[value]) accessor = Accessor.accessors[value];
else console.warn("Accessor Error - No such accessor found, ignoring: ", value);
break;
case "function":
accessor = value;
break;
}
return accessor;
}
transformRow(row, type) {
var key = "accessor" + (type.charAt(0).toUpperCase() + type.slice(1)), rowComponent = row.getComponent();
var data = Helpers.deepClone(row.data || {});
this.table.columnManager.traverse(function(column) {
var value, accessor, params, colComponent;
if (column.modules.accessor) {
accessor = column.modules.accessor[key] || column.modules.accessor.accessor || false;
if (accessor) {
value = column.getFieldValue(data);
if (value != "undefined") {
colComponent = column.getComponent();
params = typeof accessor.params === "function" ? accessor.params(value, data, type, colComponent, rowComponent) : accessor.params;
column.setFieldValue(data, accessor.accessor(value, data, type, params, colComponent, rowComponent));
}
}
}
});
return data;
}
};
var defaultConfig = { method: "GET" };
function generateParamsList$1(data, prefix) {
var output = [];
prefix = prefix || "";
if (Array.isArray(data)) data.forEach((item, i) => {
output = output.concat(generateParamsList$1(item, prefix ? prefix + "[" + i + "]" : i));
});
else if (typeof data === "object") for (var key in data) output = output.concat(generateParamsList$1(data[key], prefix ? prefix + "[" + key + "]" : key));
else output.push({
key: prefix,
value: data
});
return output;
}
function serializeParams(params) {
var output = generateParamsList$1(params), encoded = [];
output.forEach(function(item) {
encoded.push(encodeURIComponent(item.key) + "=" + encodeURIComponent(item.value));
});
return encoded.join("&");
}
function urlBuilder(url, config, params) {
if (url) {
if (params && Object.keys(params).length) {
if (!config.method || config.method.toLowerCase() == "get") {
config.method = "get";
url += (url.includes("?") ? "&" : "?") + serializeParams(params);
}
}
}
return url;
}
function defaultLoaderPromise(url, config, params) {
var contentType;
return new Promise((resolve, reject) => {
url = this.urlGenerator.call(this.table, url, config, params);
if (config.method.toUpperCase() != "GET") {
contentType = typeof this.table.options.ajaxContentType === "object" ? this.table.options.ajaxContentType : this.contentTypeFormatters[this.table.options.ajaxContentType];
if (contentType) {
for (var key in contentType.headers) {
if (!config.headers) config.headers = {};
if (typeof config.headers[key] === "undefined") config.headers[key] = contentType.headers[key];
}
config.body = contentType.body.call(this, url, config, params);
} else console.warn("Ajax Error - Invalid ajaxContentType value:", this.table.options.ajaxContentType);
}
if (url) {
if (typeof config.headers === "undefined") config.headers = {};
if (typeof config.headers.Accept === "undefined") config.headers.Accept = "application/json";
if (typeof config.headers["X-Requested-With"] === "undefined") config.headers["X-Requested-With"] = "XMLHttpRequest";
if (typeof config.mode === "undefined") config.mode = "cors";
if (config.mode == "cors") {
if (typeof config.headers["Origin"] === "undefined") config.headers["Origin"] = window.location.origin;
if (typeof config.credentials === "undefined") config.credentials = "same-origin";
} else if (typeof config.credentials === "undefined") config.credentials = "include";
fetch(url, config).then((response) => {
if (response.ok) response.json().then((data) => {
resolve(data);
}).catch((error) => {
reject(error);
console.warn("Ajax Load Error - Invalid JSON returned", error);
});
else {
console.error("Ajax Load Error - Connection Error: " + response.status, response.statusText);
reject(response);
}
}).catch((error) => {
console.error("Ajax Load Error - Connection Error: ", error);
reject(error);
});
} else {
console.warn("Ajax Load Error - No URL Set");
resolve([]);
}
});
}
function generateParamsList(data, prefix) {
var output = [];
prefix = prefix || "";
if (Array.isArray(data)) data.forEach((item, i) => {
output = output.concat(generateParamsList(item, prefix ? prefix + "[" + i + "]" : i));
});
else if (typeof data === "object") for (var key in data) output = output.concat(generateParamsList(data[key], prefix ? prefix + "[" + key + "]" : key));
else output.push({
key: prefix,
value: data
});
return output;
}
var defaultContentTypeFormatters = {
"json": {
headers: { "Content-Type": "application/json" },
body: function(url, config, params) {
return JSON.stringify(params);
}
},
"form": {
headers: {},
body: function(url, config, params) {
var output = generateParamsList(params), form = new FormData();
output.forEach(function(item) {
form.append(item.key, item.value);
});
return form;
}
}
};
var Ajax = class Ajax extends Module {
static moduleName = "ajax";
static defaultConfig = defaultConfig;
static defaultURLGenerator = urlBuilder;
static defaultLoaderPromise = defaultLoaderPromise;
static contentTypeFormatters = defaultContentTypeFormatters;
constructor(table) {
super(table);
this.config = {};
this.url = "";
this.urlGenerator = false;
this.params = false;
this.loaderPromise = false;
this.registerTableOption("ajaxURL", false);
this.registerTableOption("ajaxURLGenerator", false);
this.registerTableOption("ajaxParams", {});
this.registerTableOption("ajaxConfig", "get");
this.registerTableOption("ajaxContentType", "form");
this.registerTableOption("ajaxRequestFunc", false);
this.registerTableOption("ajaxRequesting", function() {});
this.registerTableOption("ajaxResponse", false);
this.contentTypeFormatters = Ajax.contentTypeFormatters;
}
initialize() {
this.loaderPromise = this.table.options.ajaxRequestFunc || Ajax.defaultLoaderPromise;
this.urlGenerator = this.table.options.ajaxURLGenerator || Ajax.defaultURLGenerator;
if (this.table.options.ajaxURL) this.setUrl(this.table.options.ajaxURL);
this.setDefaultConfig(this.table.options.ajaxConfig);
this.registerTableFunction("getAjaxUrl", this.getUrl.bind(this));
this.subscribe("data-loading", this.requestDataCheck.bind(this));
this.subscribe("data-params", this.requestParams.bind(this));
this.subscribe("data-load", this.requestData.bind(this));
}
requestParams(data, config, silent, params) {
var ajaxParams = this.table.options.ajaxParams;
if (ajaxParams) {
if (typeof ajaxParams === "function") ajaxParams = ajaxParams.call(this.table);
params = Object.assign(Object.assign({}, ajaxParams), params);
}
return params;
}
requestDataCheck(data, params, config, silent) {
return !!(!data && this.url || typeof data === "string");
}
requestData(url, params, config, silent, previousData) {
var ajaxConfig;
if (!previousData && this.requestDataCheck(url)) {
if (url) this.setUrl(url);
ajaxConfig = this.generateConfig(config);
return this.sendRequest(this.url, params, ajaxConfig);
} else return previousData;
}
setDefaultConfig(config = {}) {
this.config = Object.assign({}, Ajax.defaultConfig);
if (typeof config == "string") this.config.method = config;
else Object.assign(this.config, config);
}
generateConfig(config = {}) {
var ajaxConfig = Object.assign({}, this.config);
if (typeof config == "string") ajaxConfig.method = config;
else Object.assign(ajaxConfig, config);
return ajaxConfig;
}
setUrl(url) {
this.url = url;
}
getUrl() {
return this.url;
}
sendRequest(url, params, config) {
if (this.table.options.ajaxRequesting.call(this.table, url, params) !== false) return this.loaderPromise(url, config, params).then((data) => {
if (this.table.options.ajaxResponse) data = this.table.options.ajaxResponse.call(this.table, url, params, data);
return data;
});
else return Promise.reject();
}
};
var defaultPasteActions = {
replace: function(data) {
return this.table.setData(data);
},
update: function(data) {
return this.table.updateOrAddData(data);
},
insert: function(data) {
return this.table.addData(data);
}
};
var defaultPasteParsers = { table: function(clipboard) {
var data = [], headerFindSuccess = true, columns = this.table.columnManager.columns, columnMap = [], rows = [];
clipboard = clipboard.split("\n");
clipboard.forEach(function(row) {
data.push(row.split(" "));
});
if (data.length && !(data.length === 1 && data[0].length < 2)) {
data[0].forEach(function(value) {
var column = columns.find(function(column) {
return value && column.definition.title && value.trim() && column.definition.title.trim() === value.trim();
});
if (column) columnMap.push(column);
else headerFindSuccess = false;
});
if (!headerFindSuccess) {
headerFindSuccess = true;
columnMap = [];
data[0].forEach(function(value) {
var column = columns.find(function(column) {
return value && column.field && value.trim() && column.field.trim() === value.trim();
});
if (column) columnMap.push(column);
else headerFindSuccess = false;
});
if (!headerFindSuccess) columnMap = this.table.columnManager.columnsByIndex;
}
if (headerFindSuccess) data.shift();
data.forEach(function(item) {
var row = {};
item.forEach(function(value, i) {
if (columnMap[i]) row[columnMap[i].field] = value;
});
rows.push(row);
});
return rows;
} else return false;
} };
var extensions$4 = { keybindings: {
bindings: { copyToClipboard: ["ctrl + 67", "meta + 67"] },
actions: { copyToClipboard: function(e) {
if (!this.table.modules.edit.currentCell) {
if (this.table.modExists("clipboard", true)) this.table.modules.clipboard.copy(false, true);
}
} }
} };
var Clipboard = class Clipboard extends Module {
static moduleName = "clipboard";
static moduleExtensions = extensions$4;
static pasteActions = defaultPasteActions;
static pasteParsers = defaultPasteParsers;
constructor(table) {
super(table);
this.mode = true;
this.pasteParser = function() {};
this.pasteAction = function() {};
this.customSelection = false;
this.rowRange = false;
this.blocked = true;
this.registerTableOption("clipboard", false);
this.registerTableOption("clipboardCopyStyled", true);
this.registerTableOption("clipboardCopyConfig", false);
this.registerTableOption("clipboardCopyFormatter", false);
this.registerTableOption("clipboardCopyRowRange", "active");
this.registerTableOption("clipboardPasteParser", "table");
this.registerTableOption("clipboardPasteAction", "insert");
this.registerColumnOption("clipboard");
this.registerColumnOption("titleClipboard");
}
initialize() {
this.mode = this.table.options.clipboard;
this.rowRange = this.table.options.clipboardCopyRowRange;
if (this.mode === true || this.mode === "copy") this.table.element.addEventListener("copy", (e) => {
var plain, html, list;
if (!this.blocked) {
e.preventDefault();
if (this.customSelection) {
plain = this.customSelection;
if (this.table.options.clipboardCopyFormatter) plain = this.table.options.clipboardCopyFormatter("plain", plain);
} else {
list = this.table.modules.export.generateExportList(this.table.options.clipboardCopyConfig, this.table.options.clipboardCopyStyled, this.rowRange, "clipboard");
html = this.table.modules.export.generateHTMLTable(list);
plain = html ? this.generatePlainContent(list) : "";
if (this.table.options.clipboardCopyFormatter) {
plain = this.table.options.clipboardCopyFormatter("plain", plain);
html = this.table.options.clipboardCopyFormatter("html", html);
}
}
if (window.clipboardData && window.clipboardData.setData) window.clipboardData.setData("Text", plain);
else if (e.clipboardData && e.clipboardData.setData) {
e.clipboardData.setData("text/plain", plain);
if (html) e.clipboardData.setData("text/html", html);
} else if (e.originalEvent && e.originalEvent.clipboardData.setData) {
e.originalEvent.clipboardData.setData("text/plain", plain);
if (html) e.originalEvent.clipboardData.setData("text/html", html);
}
this.dispatchExternal("clipboardCopied", plain, html);
this.reset();
}
});
if (this.mode === true || this.mode === "paste") this.table.element.addEventListener("paste", (e) => {
this.paste(e);
});
this.setPasteParser(this.table.options.clipboardPasteParser);
this.setPasteAction(this.table.options.clipboardPasteAction);
this.registerTableFunction("copyToClipboard", this.copy.bind(this));
}
reset() {
this.blocked = true;
this.customSelection = false;
}
generatePlainContent(list) {
var output = [];
list.forEach((row) => {
var rowData = [];
row.columns.forEach((col) => {
var value = "";
if (col) {
if (row.type === "group") col.value = col.component.getKey();
if (col.value === null) value = "";
else switch (typeof col.value) {
case "object":
value = JSON.stringify(col.value);
break;
case "undefined":
value = "";
break;
default: value = col.value;
}
}
rowData.push(value);
});
output.push(rowData.join(" "));
});
return output.join("\n");
}
copy(range, internal) {
var sel, textRange;
this.blocked = false;
this.customSelection = false;
if (this.mode === true || this.mode === "copy") {
this.rowRange = range || this.table.options.clipboardCopyRowRange;
if (typeof window.getSelection != "undefined" && typeof document.createRange != "undefined") {
range = document.createRange();
range.selectNodeContents(this.table.element);
sel = window.getSelection();
if (sel.toString() && internal) this.customSelection = sel.toString();
sel.removeAllRanges();
sel.addRange(range);
} else if (typeof document.selection != "undefined" && typeof document.body.createTextRange != "undefined") {
textRange = document.body.createTextRange();
textRange.moveToElementText(this.table.element);
textRange.select();
}
document.execCommand("copy");
if (sel) sel.removeAllRanges();
}
}
setPasteAction(action) {
switch (typeof action) {
case "string":
this.pasteAction = Clipboard.pasteActions[action];
if (!this.pasteAction) console.warn("Clipboard Error - No such paste action found:", action);
break;
case "function":
this.pasteAction = action;
break;
}
}
setPasteParser(parser) {
switch (typeof parser) {
case "string":
this.pasteParser = Clipboard.pasteParsers[parser];
if (!this.pasteParser) console.warn("Clipboard Error - No such paste parser found:", parser);
break;
case "function":
this.pasteParser = parser;
break;
}
}
paste(e) {
var data, rowData, rows;
if (this.checkPasteOrigin(e)) {
data = this.getPasteData(e);
rowData = this.pasteParser.call(this, data);
if (rowData) {
e.preventDefault();
if (this.table.modExists("mutator")) rowData = this.mutateData(rowData);
rows = this.pasteAction.call(this, rowData);
this.dispatchExternal("clipboardPasted", data, rowData, rows);
} else this.dispatchExternal("clipboardPasteError", data);
}
}
mutateData(data) {
var output = [];
if (Array.isArray(data)) data.forEach((row) => {
output.push(this.table.modules.mutator.transformRow(row, "clipboard"));
});
else output = data;
return output;
}
checkPasteOrigin(e) {
var valid = true;
if (this.confirm("clipboard-paste", [e]) || !["DIV", "SPAN"].includes(e.target.tagName)) valid = false;
return valid;
}
getPasteData(e) {
var data;
if (window.clipboardData && window.clipboardData.getData) data = window.clipboardData.getData("Text");
else if (e.clipboardData && e.clipboardData.getData) data = e.clipboardData.getData("text/plain");
else if (e.originalEvent && e.originalEvent.clipboardData.getData) data = e.originalEvent.clipboardData.getData("text/plain");
return data;
}
};
var CalcComponent = class {
constructor(row) {
this._row = row;
return new Proxy(this, { get: function(target, name, receiver) {
if (typeof target[name] !== "undefined") return target[name];
else return target._row.table.componentFunctionBinder.handle("row", target._row, name);
} });
}
getData(transform) {
return this._row.getData(transform);
}
getElement() {
return this._row.getElement();
}
getTable() {
return this._row.table;
}
getCells() {
var cells = [];
this._row.getCells().forEach(function(cell) {
cells.push(cell.getComponent());
});
return cells;
}
getCell(column) {
var cell = this._row.getCell(column);
return cell ? cell.getComponent() : false;
}
_getSelf() {
return this._row;
}
};
var CellComponent = class {
constructor(cell) {
this._cell = cell;
return new Proxy(this, { get: function(target, name, receiver) {
if (typeof target[name] !== "undefined") return target[name];
else return target._cell.table.componentFunctionBinder.handle("cell", target._cell, name);
} });
}
getValue() {
return this._cell.getValue();
}
getOldValue() {
return this._cell.getOldValue();
}
getInitialValue() {
return this._cell.initialValue;
}
getElement() {
return this._cell.getElement();
}
getRow() {
return this._cell.row.getComponent();
}
getData(transform) {
return this._cell.row.getData(transform);
}
getType() {
return "cell";
}
getField() {
return this._cell.column.getField();
}
getColumn() {
return this._cell.column.getComponent();
}
setValue(value, mutate) {
if (typeof mutate == "undefined") mutate = true;
this._cell.setValue(value, mutate);
}
restoreOldValue() {
this._cell.setValueActual(this._cell.getOldValue());
}
restoreInitialValue() {
this._cell.setValueActual(this._cell.initialValue);
}
checkHeight() {
this._cell.checkHeight();
}
getTable() {
return this._cell.table;
}
_getSelf() {
return this._cell;
}
};
var Cell = class extends CoreFeature {
constructor(column, row) {
super(column.table);
this.table = column.table;
this.column = column;
this.row = row;
this.element = null;
this.value = null;
this.initialValue;
this.oldValue = null;
this.modules = {};
this.height = null;
this.width = null;
this.minWidth = null;
this.component = null;
this.loaded = false;
this.build();
}
build() {
this.generateElement();
this.setWidth();
this._configureCell();
this.setValueActual(this.column.getFieldValue(this.row.data));
this.initialValue = this.value;
}
generateElement() {
this.element = document.createElement("div");
this.element.className = "tabulator-cell";
this.element.setAttribute("role", "gridcell");
if (this.column.isRowHeader) this.element.classList.add("tabulator-row-header");
}
_configureCell() {
var element = this.element, field = this.column.getField(), vertAligns = {
top: "flex-start",
bottom: "flex-end",
middle: "center"
}, hozAligns = {
left: "flex-start",
right: "flex-end",
center: "center"
};
element.style.textAlign = this.column.hozAlign;
if (this.column.vertAlign) {
element.style.display = "inline-flex";
element.style.alignItems = vertAligns[this.column.vertAlign] || "";
if (this.column.hozAlign) element.style.justifyContent = hozAligns[this.column.hozAlign] || "";
}
if (field) element.setAttribute("tabulator-field", field);
if (this.column.definition.cssClass) this.column.definition.cssClass.split(" ").forEach((className) => {
element.classList.add(className);
});
this.dispatch("cell-init", this);
if (!this.column.visible) this.hide();
}
_generateContents() {
var val = this.chain("cell-format", this, null, () => {
return this.element.innerHTML = this.value;
});
switch (typeof val) {
case "object":
if (val instanceof Node) {
while (this.element.firstChild) this.element.removeChild(this.element.firstChild);
this.element.appendChild(val);
} else {
this.element.innerHTML = "";
if (val != null) console.warn("Format Error - Formatter has returned a type of object, the only valid formatter object return is an instance of Node, the formatter returned:", val);
}
break;
case "undefined":
this.element.innerHTML = "";
break;
default: this.element.innerHTML = val;
}
}
cellRendered() {
this.dispatch("cell-rendered", this);
}
getElement(containerOnly) {
if (!this.loaded) {
this.loaded = true;
if (!containerOnly) this.layoutElement();
}
return this.element;
}
getValue() {
return this.value;
}
getOldValue() {
return this.oldValue;
}
setValue(value, mutate, force) {
if (this.setValueProcessData(value, mutate, force)) {
this.dispatch("cell-value-updated", this);
this.cellRendered();
if (this.column.definition.cellEdited) this.column.definition.cellEdited.call(this.table, this.getComponent());
this.dispatchExternal("cellEdited", this.getComponent());
if (this.subscribedExternal("dataChanged")) this.dispatchExternal("dataChanged", this.table.rowManager.getData());
}
}
setValueProcessData(value, mutate, force) {
var changed = false;
if (this.value !== value || force) {
changed = true;
if (mutate) value = this.chain("cell-value-changing", [this, value], null, value);
}
this.setValueActual(value);
if (changed) this.dispatch("cell-value-changed", this);
return changed;
}
setValueActual(value) {
this.oldValue = this.value;
this.value = value;
this.dispatch("cell-value-save-before", this);
this.column.setFieldValue(this.row.data, value);
this.dispatch("cell-value-save-after", this);
if (this.loaded) this.layoutElement();
}
layoutElement() {
this._generateContents();
this.dispatch("cell-layout", this);
}
setWidth() {
this.width = this.column.width;
this.element.style.width = this.column.widthStyled;
}
clearWidth() {
this.width = "";
this.element.style.width = "";
}
getWidth() {
return this.width || this.element.offsetWidth;
}
setMinWidth() {
this.minWidth = this.column.minWidth;
this.element.style.minWidth = this.column.minWidthStyled;
}
setMaxWidth() {
this.maxWidth = this.column.maxWidth;
this.element.style.maxWidth = this.column.maxWidthStyled;
}
checkHeight() {
this.row.reinitializeHeight();
}
clearHeight() {
this.element.style.height = "";
this.height = null;
this.dispatch("cell-height", this, "");
}
setHeight() {
this.height = this.row.height;
this.element.style.height = this.row.heightStyled;
this.dispatch("cell-height", this, this.row.heightStyled);
}
getHeight() {
return this.height || this.element.offsetHeight;
}
show() {
this.element.style.display = this.column.vertAlign ? "inline-flex" : "";
}
hide() {
this.element.style.display = "none";
}
delete() {
this.dispatch("cell-delete", this);
if (!this.table.rowManager.redrawBlock && this.element.parentNode) this.element.parentNode.removeChild(this.element);
this.element = false;
this.column.deleteCell(this);
this.row.deleteCell(this);
this.calcs = {};
}
getIndex() {
return this.row.getCellIndex(this);
}
getComponent() {
if (!this.component) this.component = new CellComponent(this);
return this.component;
}
};
var ColumnComponent = class {
constructor(column) {
this._column = column;
this.type = "ColumnComponent";
return new Proxy(this, { get: function(target, name, receiver) {
if (typeof target[name] !== "undefined") return target[name];
else return target._column.table.componentFunctionBinder.handle("column", target._column, name);
} });
}
getElement() {
return this._column.getElement();
}
getDefinition() {
return this._column.getDefinition();
}
getField() {
return this._column.getField();
}
getTitleDownload() {
return this._column.getTitleDownload();
}
getCells() {
var cells = [];
this._column.cells.forEach(function(cell) {
cells.push(cell.getComponent());
});
return cells;
}
isVisible() {
return this._column.visible;
}
show() {
if (this._column.isGroup) this._column.columns.forEach(function(column) {
column.show();
});
else this._column.show();
}
hide() {
if (this._column.isGroup) this._column.columns.forEach(function(column) {
column.hide();
});
else this._column.hide();
}
toggle() {
if (this._column.visible) this.hide();
else this.show();
}
delete() {
return this._column.delete();
}
getSubColumns() {
var output = [];
if (this._column.columns.length) this._column.columns.forEach(function(column) {
output.push(column.getComponent());
});
return output;
}
getParentColumn() {
return this._column.getParentComponent();
}
_getSelf() {
return this._column;
}
scrollTo(position, ifVisible) {
return this._column.table.columnManager.scrollToColumn(this._column, position, ifVisible);
}
getTable() {
return this._column.table;
}
move(to, after) {
var toColumn = this._column.table.columnManager.findColumn(to);
if (toColumn) this._column.table.columnManager.moveColumn(this._column, toColumn, after);
else console.warn("Move Error - No matching column found:", toColumn);
}
getNextColumn() {
var nextCol = this._column.nextColumn();
return nextCol ? nextCol.getComponent() : false;
}
getPrevColumn() {
var prevCol = this._column.prevColumn();
return prevCol ? prevCol.getComponent() : false;
}
updateDefinition(updates) {
return this._column.updateDefinition(updates);
}
getWidth() {
return this._column.getWidth();
}
setWidth(width) {
var result;
if (width === true) result = this._column.reinitializeWidth(true);
else result = this._column.setWidth(width);
this._column.table.columnManager.rerenderColumns(true);
return result;
}
};
var defaultColumnOptions = {
"title": void 0,
"field": void 0,
"columns": void 0,
"visible": void 0,
"hozAlign": void 0,
"vertAlign": void 0,
"width": void 0,
"minWidth": 40,
"maxWidth": void 0,
"maxInitialWidth": void 0,
"cssClass": void 0,
"variableHeight": void 0,
"headerVertical": void 0,
"headerHozAlign": void 0,
"headerWordWrap": false,
"editableTitle": void 0
};
var Column = class Column extends CoreFeature {
static defaultOptionList = defaultColumnOptions;
constructor(def, parent, rowHeader) {
super(parent.table);
this.definition = def;
this.parent = parent;
this.type = "column";
this.columns = [];
this.cells = [];
this.isGroup = false;
this.isRowHeader = rowHeader;
this.element = this.createElement();
this.contentElement = false;
this.titleHolderElement = false;
this.titleElement = false;
this.groupElement = this.createGroupElement();
this.hozAlign = "";
this.vertAlign = "";
this.field = "";
this.fieldStructure = "";
this.getFieldValue = "";
this.setFieldValue = "";
this.titleDownload = null;
this.titleFormatterRendered = false;
this.mapDefinitions();
this.setField(this.definition.field);
this.modules = {};
this.width = null;
this.widthStyled = "";
this.maxWidth = null;
this.maxWidthStyled = "";
this.maxInitialWidth = null;
this.minWidth = null;
this.minWidthStyled = "";
this.widthFixed = false;
this.visible = true;
this.component = null;
if (this.definition.columns) {
this.isGroup = true;
this.definition.columns.forEach((def, i) => {
var newCol = new Column(def, this);
this.attachColumn(newCol);
});
this.checkColumnVisibility();
} else parent.registerColumnField(this);
this._initialize();
}
createElement() {
var el = document.createElement("div");
el.classList.add("tabulator-col");
el.setAttribute("role", "columnheader");
el.setAttribute("aria-sort", "none");
if (this.isRowHeader) el.classList.add("tabulator-row-header");
switch (this.table.options.columnHeaderVertAlign) {
case "middle":
el.style.justifyContent = "center";
break;
case "bottom":
el.style.justifyContent = "flex-end";
break;
}
return el;
}
createGroupElement() {
var el = document.createElement("div");
el.classList.add("tabulator-col-group-cols");
return el;
}
mapDefinitions() {
var defaults = this.table.options.columnDefaults;
if (defaults) {
for (let key in defaults) if (typeof this.definition[key] === "undefined") this.definition[key] = defaults[key];
}
this.definition = this.table.columnManager.optionsList.generate(Column.defaultOptionList, this.definition);
}
checkDefinition() {
Object.keys(this.definition).forEach((key) => {
if (Column.defaultOptionList.indexOf(key) === -1) console.warn("Invalid column definition option in '" + (this.field || this.definition.title) + "' column:", key);
});
}
setField(field) {
this.field = field;
this.fieldStructure = field ? this.table.options.nestedFieldSeparator ? field.split(this.table.options.nestedFieldSeparator) : [field] : [];
this.getFieldValue = this.fieldStructure.length > 1 ? this._getNestedData : this._getFlatData;
this.setFieldValue = this.fieldStructure.length > 1 ? this._setNestedData : this._setFlatData;
}
registerColumnPosition(column) {
this.parent.registerColumnPosition(column);
}
registerColumnField(column) {
this.parent.registerColumnField(column);
}
reRegisterPosition() {
if (this.isGroup) this.columns.forEach(function(column) {
column.reRegisterPosition();
});
else this.registerColumnPosition(this);
}
_initialize() {
var def = this.definition;
while (this.element.firstChild) this.element.removeChild(this.element.firstChild);
if (def.headerVertical) {
this.element.classList.add("tabulator-col-vertical");
if (def.headerVertical === "flip") this.element.classList.add("tabulator-col-vertical-flip");
}
this.contentElement = this._buildColumnHeaderContent();
this.element.appendChild(this.contentElement);
if (this.isGroup) this._buildGroupHeader();
else this._buildColumnHeader();
this.dispatch("column-init", this);
}
_buildColumnHeader() {
var def = this.definition;
this.dispatch("column-layout", this);
if (typeof def.visible != "undefined") if (def.visible) this.show(true);
else this.hide(true);
if (def.cssClass) def.cssClass.split(" ").forEach((className) => {
this.element.classList.add(className);
});
if (def.field) this.element.setAttribute("tabulator-field", def.field);
this.setMinWidth(parseInt(def.minWidth));
if (def.maxInitialWidth) this.maxInitialWidth = parseInt(def.maxInitialWidth);
if (def.maxWidth) this.setMaxWidth(parseInt(def.maxWidth));
this.reinitializeWidth();
this.hozAlign = this.definition.hozAlign;
this.vertAlign = this.definition.vertAlign;
this.titleElement.style.textAlign = this.definition.headerHozAlign;
}
_buildColumnHeaderContent() {
var contentElement = document.createElement("div");
contentElement.classList.add("tabulator-col-content");
this.titleHolderElement = document.createElement("div");
this.titleHolderElement.classList.add("tabulator-col-title-holder");
contentElement.appendChild(this.titleHolderElement);
this.titleElement = this._buildColumnHeaderTitle();
this.titleHolderElement.appendChild(this.titleElement);
return contentElement;
}
_buildColumnHeaderTitle() {
var def = this.definition;
var titleHolderElement = document.createElement("div");
titleHolderElement.classList.add("tabulator-col-title");
if (def.headerWordWrap) titleHolderElement.classList.add("tabulator-col-title-wrap");
if (def.editableTitle) {
var titleElement = document.createElement("input");
titleElement.classList.add("tabulator-title-editor");
titleElement.addEventListener("click", (e) => {
e.stopPropagation();
titleElement.focus();
});
titleElement.addEventListener("mousedown", (e) => {
e.stopPropagation();
});
titleElement.addEventListener("change", () => {
def.title = titleElement.value;
this.dispatchExternal("columnTitleChanged", this.getComponent());
});
titleHolderElement.appendChild(titleElement);
if (def.field) this.langBind("columns|" + def.field, (text) => {
titleElement.value = text || def.title || " ";
});
else titleElement.value = def.title || " ";
} else if (def.field) this.langBind("columns|" + def.field, (text) => {
this._formatColumnHeaderTitle(titleHolderElement, text || def.title || " ");
});
else this._formatColumnHeaderTitle(titleHolderElement, def.title || " ");
return titleHolderElement;
}
_formatColumnHeaderTitle(el, title) {
var contents = this.chain("column-format", [
this,
title,
el
], null, () => {
return title;
});
switch (typeof contents) {
case "object":
if (contents instanceof Node) el.appendChild(contents);
else {
el.innerHTML = "";
console.warn("Format Error - Title formatter has returned a type of object, the only valid formatter object return is an instance of Node, the formatter returned:", contents);
}
break;
case "undefined":
el.innerHTML = "";
break;
default: el.innerHTML = contents;
}
}
_buildGroupHeader() {
this.element.classList.add("tabulator-col-group");
this.element.setAttribute("role", "columngroup");
this.element.setAttribute("aria-title", this.definition.title);
if (this.definition.cssClass) this.definition.cssClass.split(" ").forEach((className) => {
this.element.classList.add(className);
});
this.titleElement.style.textAlign = this.definition.headerHozAlign;
this.element.appendChild(this.groupElement);
}
_getFlatData(data) {
return data[this.field];
}
_getNestedData(data) {
var dataObj = data, structure = this.fieldStructure, length = structure.length, output;
for (let i = 0; i < length; i++) {
dataObj = dataObj[structure[i]];
output = dataObj;
if (!dataObj) break;
}
return output;
}
_setFlatData(data, value) {
if (this.field) data[this.field] = value;
}
_setNestedData(data, value) {
var dataObj = data, structure = this.fieldStructure, length = structure.length;
for (let i = 0; i < length; i++) if (i == length - 1) dataObj[structure[i]] = value;
else {
if (!dataObj[structure[i]]) if (typeof value !== "undefined") dataObj[structure[i]] = {};
else break;
dataObj = dataObj[structure[i]];
}
}
attachColumn(column) {
if (this.groupElement) {
this.columns.push(column);
this.groupElement.appendChild(column.getElement());
column.columnRendered();
} else console.warn("Column Warning - Column being attached to another column instead of column group");
}
verticalAlign(alignment, height) {
var parentHeight = this.parent.isGroup ? this.parent.getGroupElement().clientHeight : height || this.parent.getHeadersElement().clientHeight;
this.element.style.height = parentHeight + "px";
this.dispatch("column-height", this, this.element.style.height);
if (this.isGroup) this.groupElement.style.minHeight = parentHeight - this.contentElement.offsetHeight + "px";
this.columns.forEach(function(column) {
column.verticalAlign(alignment);
});
}
clearVerticalAlign() {
this.element.style.paddingTop = "";
this.element.style.height = "";
this.element.style.minHeight = "";
this.groupElement.style.minHeight = "";
this.columns.forEach(function(column) {
column.clearVerticalAlign();
});
this.dispatch("column-height", this, "");
}
getElement() {
return this.element;
}
getGroupElement() {
return this.groupElement;
}
getField() {
return this.field;
}
getTitleDownload() {
return this.titleDownload;
}
getFirstColumn() {
if (!this.isGroup) return this;
else if (this.columns.length) return this.columns[0].getFirstColumn();
else return false;
}
getLastColumn() {
if (!this.isGroup) return this;
else if (this.columns.length) return this.columns[this.columns.length - 1].getLastColumn();
else return false;
}
getColumns(traverse) {
var columns = [];
if (traverse) this.columns.forEach((column) => {
columns.push(column);
columns = columns.concat(column.getColumns(true));
});
else columns = this.columns;
return columns;
}
getCells() {
return this.cells;
}
getTopColumn() {
if (this.parent.isGroup) return this.parent.getTopColumn();
else return this;
}
getDefinition(updateBranches) {
var colDefs = [];
if (this.isGroup && updateBranches) {
this.columns.forEach(function(column) {
colDefs.push(column.getDefinition(true));
});
this.definition.columns = colDefs;
}
return this.definition;
}
checkColumnVisibility() {
var visible = false;
this.columns.forEach(function(column) {
if (column.visible) visible = true;
});
if (visible) {
this.show();
this.dispatchExternal("columnVisibilityChanged", this.getComponent(), false);
} else this.hide();
}
show(silent, responsiveToggle) {
if (!this.visible) {
this.visible = true;
this.element.style.display = "";
if (this.parent.isGroup) this.parent.checkColumnVisibility();
this.cells.forEach(function(cell) {
cell.show();
});
if (!this.isGroup && this.width === null) this.reinitializeWidth();
this.table.columnManager.verticalAlignHeaders();
this.dispatch("column-show", this, responsiveToggle);
if (!silent) this.dispatchExternal("columnVisibilityChanged", this.getComponent(), true);
if (this.parent.isGroup) this.parent.matchChildWidths();
if (!this.silent) this.table.columnManager.rerenderColumns();
}
}
hide(silent, responsiveToggle) {
if (this.visible) {
this.visible = false;
this.element.style.display = "none";
this.table.columnManager.verticalAlignHeaders();
if (this.parent.isGroup) this.parent.checkColumnVisibility();
this.cells.forEach(function(cell) {
cell.hide();
});
this.dispatch("column-hide", this, responsiveToggle);
if (!silent) this.dispatchExternal("columnVisibilityChanged", this.getComponent(), false);
if (this.parent.isGroup) this.parent.matchChildWidths();
if (!this.silent) this.table.columnManager.rerenderColumns();
}
}
matchChildWidths() {
var childWidth = 0;
if (this.contentElement && this.columns.length) {
this.columns.forEach(function(column) {
if (column.visible) childWidth += column.getWidth();
});
this.contentElement.style.maxWidth = childWidth - 1 + "px";
if (this.table.initialized) this.element.style.width = childWidth + "px";
if (this.parent.isGroup) this.parent.matchChildWidths();
}
}
removeChild(child) {
var index = this.columns.indexOf(child);
if (index > -1) this.columns.splice(index, 1);
if (!this.columns.length) this.delete();
}
setWidth(width) {
this.widthFixed = true;
this.setWidthActual(width);
}
setWidthActual(width) {
if (isNaN(width)) width = Math.floor(this.table.element.clientWidth / 100 * parseInt(width));
width = Math.max(this.minWidth, width);
if (this.maxWidth) width = Math.min(this.maxWidth, width);
this.width = width;
this.widthStyled = width ? width + "px" : "";
this.element.style.width = this.widthStyled;
if (!this.isGroup) this.cells.forEach(function(cell) {
cell.setWidth();
});
if (this.parent.isGroup) this.parent.matchChildWidths();
this.dispatch("column-width", this);
if (this.subscribedExternal("columnWidth")) this.dispatchExternal("columnWidth", this.getComponent());
}
checkCellHeights() {
var rows = [];
this.cells.forEach(function(cell) {
if (cell.row.heightInitialized) if (cell.row.getElement().offsetParent !== null) {
rows.push(cell.row);
cell.row.clearCellHeight();
} else cell.row.heightInitialized = false;
});
rows.forEach(function(row) {
row.calcHeight();
});
rows.forEach(function(row) {
row.setCellHeight();
});
}
getWidth() {
var width = 0;
if (this.isGroup) this.columns.forEach(function(column) {
if (column.visible) width += column.getWidth();
});
else width = this.width;
return width;
}
getLeftOffset() {
var offset = this.element.offsetLeft;
if (this.parent.isGroup) offset += this.parent.getLeftOffset();
return offset;
}
getHeight() {
return Math.ceil(this.element.getBoundingClientRect().height);
}
setMinWidth(minWidth) {
if (this.maxWidth && minWidth > this.maxWidth) {
minWidth = this.maxWidth;
console.warn("the minWidth (" + minWidth + "px) for column '" + this.field + "' cannot be bigger that its maxWidth (" + this.maxWidthStyled + ")");
}
this.minWidth = minWidth;
this.minWidthStyled = minWidth ? minWidth + "px" : "";
this.element.style.minWidth = this.minWidthStyled;
this.cells.forEach(function(cell) {
cell.setMinWidth();
});
}
setMaxWidth(maxWidth) {
if (this.minWidth && maxWidth < this.minWidth) {
maxWidth = this.minWidth;
console.warn("the maxWidth (" + maxWidth + "px) for column '" + this.field + "' cannot be smaller that its minWidth (" + this.minWidthStyled + ")");
}
this.maxWidth = maxWidth;
this.maxWidthStyled = maxWidth ? maxWidth + "px" : "";
this.element.style.maxWidth = this.maxWidthStyled;
this.cells.forEach(function(cell) {
cell.setMaxWidth();
});
}
delete() {
return new Promise((resolve, reject) => {
if (this.isGroup) this.columns.forEach(function(column) {
column.delete();
});
this.dispatch("column-delete", this);
var cellCount = this.cells.length;
for (let i = 0; i < cellCount; i++) this.cells[0].delete();
if (this.element.parentNode) this.element.parentNode.removeChild(this.element);
this.element = false;
this.contentElement = false;
this.titleElement = false;
this.groupElement = false;
if (this.parent.isGroup) this.parent.removeChild(this);
this.table.columnManager.deregisterColumn(this);
this.table.columnManager.rerenderColumns(true);
this.dispatch("column-deleted", this);
resolve();
});
}
columnRendered() {
if (this.titleFormatterRendered) this.titleFormatterRendered();
this.dispatch("column-rendered", this);
}
generateCell(row) {
var cell = new Cell(this, row);
this.cells.push(cell);
return cell;
}
nextColumn() {
var index = this.table.columnManager.findColumnIndex(this);
return index > -1 ? this._nextVisibleColumn(index + 1) : false;
}
_nextVisibleColumn(index) {
var column = this.table.columnManager.getColumnByIndex(index);
return !column || column.visible ? column : this._nextVisibleColumn(index + 1);
}
prevColumn() {
var index = this.table.columnManager.findColumnIndex(this);
return index > -1 ? this._prevVisibleColumn(index - 1) : false;
}
_prevVisibleColumn(index) {
var column = this.table.columnManager.getColumnByIndex(index);
return !column || column.visible ? column : this._prevVisibleColumn(index - 1);
}
reinitializeWidth(force) {
this.widthFixed = false;
if (typeof this.definition.width !== "undefined" && !force) this.setWidth(this.definition.width);
this.dispatch("column-width-fit-before", this);
this.fitToData(force);
this.dispatch("column-width-fit-after", this);
}
fitToData(force) {
if (this.isGroup) return;
if (!this.widthFixed) {
this.element.style.width = "";
this.cells.forEach((cell) => {
cell.clearWidth();
});
}
var maxWidth = this.element.offsetWidth;
if (!this.width || !this.widthFixed) {
this.cells.forEach((cell) => {
var width = cell.getWidth();
if (width > maxWidth) maxWidth = width;
});
if (maxWidth) {
var setTo = maxWidth + 1;
if (force) this.setWidth(setTo);
else {
if (this.maxInitialWidth && !force) setTo = Math.min(setTo, this.maxInitialWidth);
this.setWidthActual(setTo);
}
}
}
}
updateDefinition(updates) {
var definition;
if (!this.isGroup) if (!this.parent.isGroup) {
definition = Object.assign({}, this.getDefinition());
definition = Object.assign(definition, updates);
return this.table.columnManager.addColumn(definition, false, this).then((column) => {
if (definition.field == this.field) this.field = false;
return this.delete().then(() => {
return column.getComponent();
});
});
} else {
console.error("Column Update Error - The updateDefinition function is only available on ungrouped columns");
return Promise.reject("Column Update Error - The updateDefinition function is only available on columns, not column groups");
}
else {
console.error("Column Update Error - The updateDefinition function is only available on ungrouped columns");
return Promise.reject("Column Update Error - The updateDefinition function is only available on columns, not column groups");
}
}
deleteCell(cell) {
var index = this.cells.indexOf(cell);
if (index > -1) this.cells.splice(index, 1);
}
getComponent() {
if (!this.component) this.component = new ColumnComponent(this);
return this.component;
}
getPosition() {
return this.table.columnManager.getVisibleColumnsByIndex().indexOf(this) + 1;
}
getParentComponent() {
return this.parent instanceof Column ? this.parent.getComponent() : false;
}
};
var RowComponent = class {
constructor(row) {
this._row = row;
return new Proxy(this, { get: function(target, name, receiver) {
if (typeof target[name] !== "undefined") return target[name];
else return target._row.table.componentFunctionBinder.handle("row", target._row, name);
} });
}
getData(transform) {
return this._row.getData(transform);
}
getElement() {
return this._row.getElement();
}
getCells() {
var cells = [];
this._row.getCells().forEach(function(cell) {
cells.push(cell.getComponent());
});
return cells;
}
getCell(column) {
var cell = this._row.getCell(column);
return cell ? cell.getComponent() : false;
}
getIndex() {
return this._row.getData("data")[this._row.table.options.index];
}
getPosition() {
return this._row.getPosition();
}
watchPosition(callback) {
return this._row.watchPosition(callback);
}
delete() {
return this._row.delete();
}
scrollTo(position, ifVisible) {
return this._row.table.rowManager.scrollToRow(this._row, position, ifVisible);
}
move(to, after) {
this._row.moveToRow(to, after);
}
update(data) {
return this._row.updateData(data);
}
normalizeHeight() {
this._row.normalizeHeight(true);
}
_getSelf() {
return this._row;
}
reformat() {
return this._row.reinitialize();
}
getTable() {
return this._row.table;
}
getNextRow() {
var row = this._row.nextRow();
return row ? row.getComponent() : row;
}
getPrevRow() {
var row = this._row.prevRow();
return row ? row.getComponent() : row;
}
};
var Row = class extends CoreFeature {
constructor(data, parent, type = "row") {
super(parent.table);
this.parent = parent;
this.data = {};
this.type = type;
this.element = false;
this.modules = {};
this.cells = [];
this.height = 0;
this.heightStyled = "";
this.manualHeight = false;
this.outerHeight = 0;
this.initialized = false;
this.heightInitialized = false;
this.position = 0;
this.positionWatchers = [];
this.component = null;
this.created = false;
this.setData(data);
}
create() {
if (!this.created) {
this.created = true;
this.generateElement();
}
}
createElement() {
var el = document.createElement("div");
el.classList.add("tabulator-row");
el.setAttribute("role", "row");
this.element = el;
}
getElement() {
this.create();
return this.element;
}
detachElement() {
if (this.element && this.element.parentNode) this.element.parentNode.removeChild(this.element);
}
generateElement() {
this.createElement();
this.dispatch("row-init", this);
}
generateCells() {
this.cells = this.table.columnManager.generateCells(this);
}
initialize(force, inFragment) {
this.create();
if (!this.initialized || force) {
this.deleteCells();
while (this.element.firstChild) this.element.removeChild(this.element.firstChild);
this.dispatch("row-layout-before", this);
this.generateCells();
this.initialized = true;
this.table.columnManager.renderer.renderRowCells(this, inFragment);
if (force) this.normalizeHeight();
this.dispatch("row-layout", this);
if (this.table.options.rowFormatter) this.table.options.rowFormatter(this.getComponent());
this.dispatch("row-layout-after", this);
} else this.table.columnManager.renderer.rerenderRowCells(this, inFragment);
}
rendered() {
this.cells.forEach((cell) => {
cell.cellRendered();
});
}
reinitializeHeight() {
this.heightInitialized = false;
if (this.element && this.element.offsetParent !== null) this.normalizeHeight(true);
}
deinitialize() {
this.initialized = false;
}
deinitializeHeight() {
this.heightInitialized = false;
}
reinitialize(children) {
this.initialized = false;
this.heightInitialized = false;
if (!this.manualHeight) {
this.height = 0;
this.heightStyled = "";
}
if (this.element && this.element.offsetParent !== null) this.initialize(true);
this.dispatch("row-relayout", this);
}
calcHeight(force) {
var maxHeight = 0, minHeight = 0;
if (this.table.options.rowHeight) this.height = this.table.options.rowHeight;
else {
minHeight = this.calcMinHeight();
maxHeight = this.calcMaxHeight();
if (force) this.height = Math.max(maxHeight, minHeight);
else this.height = this.manualHeight ? this.height : Math.max(maxHeight, minHeight);
}
this.heightStyled = this.height ? this.height + "px" : "";
this.outerHeight = this.element.offsetHeight;
}
calcMinHeight() {
return this.table.options.resizableRows ? this.element.clientHeight : 0;
}
calcMaxHeight() {
var maxHeight = 0;
this.cells.forEach(function(cell) {
var height = cell.getHeight();
if (height > maxHeight) maxHeight = height;
});
return maxHeight;
}
setCellHeight() {
this.cells.forEach(function(cell) {
cell.setHeight();
});
this.heightInitialized = true;
}
clearCellHeight() {
this.cells.forEach(function(cell) {
cell.clearHeight();
});
}
normalizeHeight(force) {
if (force && !this.table.options.rowHeight) this.clearCellHeight();
this.calcHeight(force);
this.setCellHeight();
}
setHeight(height, force) {
if (this.height != height || force) {
this.manualHeight = true;
this.height = height;
this.heightStyled = height ? height + "px" : "";
this.setCellHeight();
this.outerHeight = this.element.offsetHeight;
if (this.subscribedExternal("rowHeight")) this.dispatchExternal("rowHeight", this.getComponent());
}
}
getHeight() {
return this.outerHeight;
}
getWidth() {
return this.element.offsetWidth;
}
deleteCell(cell) {
var index = this.cells.indexOf(cell);
if (index > -1) this.cells.splice(index, 1);
}
setData(data) {
this.data = this.chain("row-data-init-before", [this, data], void 0, data);
this.dispatch("row-data-init-after", this);
}
updateData(updatedData) {
var visible = this.element && Helpers.elVisible(this.element), tempData = {}, newRowData;
return new Promise((resolve, reject) => {
if (typeof updatedData === "string") updatedData = JSON.parse(updatedData);
this.dispatch("row-data-save-before", this);
if (this.subscribed("row-data-changing")) {
tempData = Object.assign(tempData, this.data);
tempData = Object.assign(tempData, updatedData);
}
newRowData = this.chain("row-data-changing", [
this,
tempData,
updatedData
], null, updatedData);
for (let attrname in newRowData) this.data[attrname] = newRowData[attrname];
this.dispatch("row-data-save-after", this);
for (let attrname in updatedData) this.table.columnManager.getColumnsByFieldRoot(attrname).forEach((column) => {
let cell = this.getCell(column.getField());
if (cell) {
let value = column.getFieldValue(newRowData);
if (cell.getValue() !== value) {
cell.setValueProcessData(value);
if (visible) cell.cellRendered();
}
}
});
if (visible) {
this.normalizeHeight(true);
if (this.table.options.rowFormatter) this.table.options.rowFormatter(this.getComponent());
} else {
this.initialized = false;
this.height = 0;
this.heightStyled = "";
}
this.dispatch("row-data-changed", this, visible, updatedData);
this.dispatchExternal("rowUpdated", this.getComponent());
if (this.subscribedExternal("dataChanged")) this.dispatchExternal("dataChanged", this.table.rowManager.getData());
resolve();
});
}
getData(transform) {
if (transform) return this.chain("row-data-retrieve", [this, transform], null, this.data);
return this.data;
}
getCell(column) {
var match = false;
column = this.table.columnManager.findColumn(column);
if (!this.initialized && this.cells.length === 0) this.generateCells();
match = this.cells.find(function(cell) {
return cell.column === column;
});
return match;
}
getCellIndex(findCell) {
return this.cells.findIndex(function(cell) {
return cell === findCell;
});
}
findCell(subject) {
return this.cells.find((cell) => {
return cell.element === subject;
});
}
getCells() {
if (!this.initialized && this.cells.length === 0) this.generateCells();
return this.cells;
}
nextRow() {
return this.table.rowManager.nextDisplayRow(this, true) || false;
}
prevRow() {
return this.table.rowManager.prevDisplayRow(this, true) || false;
}
moveToRow(to, before) {
var toRow = this.table.rowManager.findRow(to);
if (toRow) {
this.table.rowManager.moveRowActual(this, toRow, !before);
this.table.rowManager.refreshActiveData("display", false, true);
} else console.warn("Move Error - No matching row found:", to);
}
delete() {
this.dispatch("row-delete", this);
this.deleteActual();
return Promise.resolve();
}
deleteActual(blockRedraw) {
this.detachModules();
this.table.rowManager.deleteRow(this, blockRedraw);
this.deleteCells();
this.initialized = false;
this.heightInitialized = false;
this.element = false;
this.dispatch("row-deleted", this);
}
detachModules() {
this.dispatch("row-deleting", this);
}
deleteCells() {
var cellCount = this.cells.length;
for (let i = 0; i < cellCount; i++) this.cells[0].delete();
}
wipe() {
this.detachModules();
this.deleteCells();
if (this.element) {
while (this.element.firstChild) this.element.removeChild(this.element.firstChild);
if (this.element.parentNode) this.element.parentNode.removeChild(this.element);
}
this.element = false;
this.modules = {};
}
isDisplayed() {
return this.table.rowManager.getDisplayRows().includes(this);
}
getPosition() {
return this.isDisplayed() ? this.position : false;
}
setPosition(position) {
if (position != this.position) {
this.position = position;
this.positionWatchers.forEach((callback) => {
callback(this.position);
});
}
}
watchPosition(callback) {
this.positionWatchers.push(callback);
callback(this.position);
}
getGroup() {
return this.modules.group || false;
}
getComponent() {
if (!this.component) this.component = new RowComponent(this);
return this.component;
}
};
var defaultCalculations = {
"avg": function(values, data, calcParams) {
var output = 0, precision = typeof calcParams.precision !== "undefined" ? calcParams.precision : 2;
if (values.length) {
output = values.reduce(function(sum, value) {
return Number(sum) + Number(value);
});
output = output / values.length;
output = precision !== false ? output.toFixed(precision) : output;
}
return parseFloat(output).toString();
},
"max": function(values, data, calcParams) {
var output = null, precision = typeof calcParams.precision !== "undefined" ? calcParams.precision : false;
values.forEach(function(value) {
value = Number(value);
if (value > output || output === null) output = value;
});
return output !== null ? precision !== false ? output.toFixed(precision) : output : "";
},
"min": function(values, data, calcParams) {
var output = null, precision = typeof calcParams.precision !== "undefined" ? calcParams.precision : false;
values.forEach(function(value) {
value = Number(value);
if (value < output || output === null) output = value;
});
return output !== null ? precision !== false ? output.toFixed(precision) : output : "";
},
"sum": function(values, data, calcParams) {
var output = 0, precision = typeof calcParams.precision !== "undefined" ? calcParams.precision : false;
if (values.length) values.forEach(function(value) {
value = Number(value);
output += !isNaN(value) ? Number(value) : 0;
});
return precision !== false ? output.toFixed(precision) : output;
},
"concat": function(values, data, calcParams) {
var output = 0;
if (values.length) output = values.reduce(function(sum, value) {
return String(sum) + String(value);
});
return output;
},
"count": function(values, data, calcParams) {
var output = 0;
if (values.length) values.forEach(function(value) {
if (value) output++;
});
return output;
},
"unique": function(values, data, calcParams) {
return values.filter((value, index) => {
return (values || value === 0) && values.indexOf(value) === index;
}).length;
}
};
var ColumnCalcs = class ColumnCalcs extends Module {
static moduleName = "columnCalcs";
static calculations = defaultCalculations;
constructor(table) {
super(table);
this.topCalcs = [];
this.botCalcs = [];
this.genColumn = false;
this.topElement = this.createElement();
this.botElement = this.createElement();
this.topRow = false;
this.botRow = false;
this.topInitialized = false;
this.botInitialized = false;
this.blocked = false;
this.recalcAfterBlock = false;
this.registerTableOption("columnCalcs", true);
this.registerColumnOption("topCalc");
this.registerColumnOption("topCalcParams");
this.registerColumnOption("topCalcFormatter");
this.registerColumnOption("topCalcFormatterParams");
this.registerColumnOption("bottomCalc");
this.registerColumnOption("bottomCalcParams");
this.registerColumnOption("bottomCalcFormatter");
this.registerColumnOption("bottomCalcFormatterParams");
}
createElement() {
var el = document.createElement("div");
el.classList.add("tabulator-calcs-holder");
return el;
}
initialize() {
this.genColumn = new Column({ field: "value" }, this);
this.subscribe("cell-value-changed", this.cellValueChanged.bind(this));
this.subscribe("column-init", this.initializeColumnCheck.bind(this));
this.subscribe("row-deleted", this.rowsUpdated.bind(this));
this.subscribe("scroll-horizontal", this.scrollHorizontal.bind(this));
this.subscribe("row-added", this.rowsUpdated.bind(this));
this.subscribe("column-moved", this.recalcActiveRows.bind(this));
this.subscribe("column-add", this.recalcActiveRows.bind(this));
this.subscribe("data-refreshed", this.recalcActiveRowsRefresh.bind(this));
this.subscribe("table-redraw", this.tableRedraw.bind(this));
this.subscribe("rows-visible", this.visibleRows.bind(this));
this.subscribe("scrollbar-vertical", this.adjustForScrollbar.bind(this));
this.subscribe("redraw-blocked", this.blockRedraw.bind(this));
this.subscribe("redraw-restored", this.restoreRedraw.bind(this));
this.subscribe("table-redrawing", this.resizeHolderWidth.bind(this));
this.subscribe("column-resized", this.resizeHolderWidth.bind(this));
this.subscribe("column-show", this.resizeHolderWidth.bind(this));
this.subscribe("column-hide", this.resizeHolderWidth.bind(this));
this.registerTableFunction("getCalcResults", this.getResults.bind(this));
this.registerTableFunction("recalc", this.userRecalc.bind(this));
this.resizeHolderWidth();
}
resizeHolderWidth() {
this.topElement.style.minWidth = this.table.columnManager.headersElement.offsetWidth + "px";
}
tableRedraw(force) {
this.recalc(this.table.rowManager.activeRows);
if (force) this.redraw();
}
blockRedraw() {
this.blocked = true;
this.recalcAfterBlock = false;
}
restoreRedraw() {
this.blocked = false;
if (this.recalcAfterBlock) {
this.recalcAfterBlock = false;
this.recalcActiveRowsRefresh();
}
}
userRecalc() {
this.recalc(this.table.rowManager.activeRows);
}
blockCheck() {
if (this.blocked) this.recalcAfterBlock = true;
return this.blocked;
}
visibleRows(viewable, rows) {
if (this.topRow) rows.unshift(this.topRow);
if (this.botRow) rows.push(this.botRow);
return rows;
}
rowsUpdated(row) {
if (this.table.options.groupBy) this.recalcRowGroup(row);
else this.recalcActiveRows();
}
recalcActiveRowsRefresh() {
if (this.table.options.groupBy && this.table.options.dataTreeStartExpanded && this.table.options.dataTree) this.recalcAll();
else this.recalcActiveRows();
}
recalcActiveRows() {
this.recalc(this.table.rowManager.activeRows);
}
cellValueChanged(cell) {
if (cell.column.definition.topCalc || cell.column.definition.bottomCalc) if (this.table.options.groupBy) {
if (this.table.options.columnCalcs == "table" || this.table.options.columnCalcs == "both") this.recalcActiveRows();
if (this.table.options.columnCalcs != "table") this.recalcRowGroup(cell.row);
} else this.recalcActiveRows();
}
initializeColumnCheck(column) {
if (column.definition.topCalc || column.definition.bottomCalc) this.initializeColumn(column);
}
initializeColumn(column) {
var def = column.definition;
var config = {
topCalcParams: def.topCalcParams || {},
botCalcParams: def.bottomCalcParams || {}
};
if (def.topCalc) {
switch (typeof def.topCalc) {
case "string":
if (ColumnCalcs.calculations[def.topCalc]) config.topCalc = ColumnCalcs.calculations[def.topCalc];
else console.warn("Column Calc Error - No such calculation found, ignoring: ", def.topCalc);
break;
case "function":
config.topCalc = def.topCalc;
break;
}
if (config.topCalc) {
column.modules.columnCalcs = config;
this.topCalcs.push(column);
if (this.table.options.columnCalcs != "group") this.initializeTopRow();
}
}
if (def.bottomCalc) {
switch (typeof def.bottomCalc) {
case "string":
if (ColumnCalcs.calculations[def.bottomCalc]) config.botCalc = ColumnCalcs.calculations[def.bottomCalc];
else console.warn("Column Calc Error - No such calculation found, ignoring: ", def.bottomCalc);
break;
case "function":
config.botCalc = def.bottomCalc;
break;
}
if (config.botCalc) {
column.modules.columnCalcs = config;
this.botCalcs.push(column);
if (this.table.options.columnCalcs != "group") this.initializeBottomRow();
}
}
}
registerColumnField() {}
removeCalcs() {
var changed = false;
if (this.topInitialized) {
this.topInitialized = false;
this.topElement.parentNode.removeChild(this.topElement);
changed = true;
}
if (this.botInitialized) {
this.botInitialized = false;
this.footerRemove(this.botElement);
changed = true;
}
if (changed) this.table.rowManager.adjustTableSize();
}
reinitializeCalcs() {
if (this.topCalcs.length) this.initializeTopRow();
if (this.botCalcs.length) this.initializeBottomRow();
}
initializeTopRow() {
var fragment = document.createDocumentFragment();
if (!this.topInitialized) {
fragment.appendChild(document.createElement("br"));
fragment.appendChild(this.topElement);
this.table.columnManager.getContentsElement().insertBefore(fragment, this.table.columnManager.headersElement.nextSibling);
this.topInitialized = true;
}
}
initializeBottomRow() {
if (!this.botInitialized) {
this.footerPrepend(this.botElement);
this.botInitialized = true;
}
}
scrollHorizontal(left) {
if (this.botInitialized && this.botRow) this.botElement.scrollLeft = left;
}
recalc(rows) {
var data, row;
if (!this.blockCheck()) {
if (this.topInitialized || this.botInitialized) {
data = this.rowsToData(rows);
if (this.topInitialized) {
if (this.topRow) this.topRow.deleteCells();
row = this.generateRow("top", data);
this.topRow = row;
while (this.topElement.firstChild) this.topElement.removeChild(this.topElement.firstChild);
this.topElement.appendChild(row.getElement());
row.initialize(true);
}
if (this.botInitialized) {
if (this.botRow) this.botRow.deleteCells();
row = this.generateRow("bottom", data);
this.botRow = row;
while (this.botElement.firstChild) this.botElement.removeChild(this.botElement.firstChild);
this.botElement.appendChild(row.getElement());
row.initialize(true);
}
this.table.rowManager.adjustTableSize();
if (this.table.modExists("frozenColumns")) this.table.modules.frozenColumns.layout();
}
}
}
recalcRowGroup(row) {
this.recalcGroup(this.table.modules.groupRows.getRowGroup(row));
}
recalcAll() {
if (this.topCalcs.length || this.botCalcs.length) {
if (this.table.options.columnCalcs !== "group") this.recalcActiveRows();
if (this.table.options.groupBy && this.table.options.columnCalcs !== "table") this.table.modules.groupRows.getChildGroups().forEach((group) => {
this.recalcGroup(group);
});
}
}
recalcGroup(group) {
var data, rowData;
if (!this.blockCheck()) {
if (group) {
if (group.calcs) {
if (group.calcs.bottom) {
data = this.rowsToData(group.rows);
rowData = this.generateRowData("bottom", data);
group.calcs.bottom.updateData(rowData);
group.calcs.bottom.reinitialize();
}
if (group.calcs.top) {
data = this.rowsToData(group.rows);
rowData = this.generateRowData("top", data);
group.calcs.top.updateData(rowData);
group.calcs.top.reinitialize();
}
}
}
}
}
generateTopRow(rows) {
return this.generateRow("top", this.rowsToData(rows));
}
generateBottomRow(rows) {
return this.generateRow("bottom", this.rowsToData(rows));
}
rowsToData(rows) {
var data = [], hasDataTreeColumnCalcs = this.table.options.dataTree && this.table.options.dataTreeChildColumnCalcs, dataTree = this.table.modules.dataTree;
rows.forEach((row) => {
data.push(row.getData());
if (hasDataTreeColumnCalcs && row.modules.dataTree?.open) this.rowsToData(dataTree.getFilteredTreeChildren(row)).forEach((dataRow) => {
data.push(row);
});
});
return data;
}
generateRow(pos, data) {
var rowData = this.generateRowData(pos, data), row;
if (this.table.modExists("mutator")) this.table.modules.mutator.disable();
row = new Row(rowData, this, "calc");
if (this.table.modExists("mutator")) this.table.modules.mutator.enable();
row.getElement().classList.add("tabulator-calcs", "tabulator-calcs-" + pos);
row.component = false;
row.getComponent = () => {
if (!row.component) row.component = new CalcComponent(row);
return row.component;
};
row.generateCells = () => {
var cells = [];
this.table.columnManager.columnsByIndex.forEach((column) => {
this.genColumn.setField(column.getField());
this.genColumn.hozAlign = column.hozAlign;
if (column.definition[pos + "CalcFormatter"] && this.table.modExists("format")) this.genColumn.modules.format = {
formatter: this.table.modules.format.lookupFormatter(column.definition[pos + "CalcFormatter"]),
params: column.definition[pos + "CalcFormatterParams"] || {}
};
else this.genColumn.modules.format = {
formatter: this.table.modules.format.lookupFormatter("plaintext"),
params: {}
};
this.genColumn.definition.cssClass = column.definition.cssClass;
var cell = new Cell(this.genColumn, row);
cell.getElement();
cell.column = column;
cell.setWidth();
column.cells.push(cell);
cells.push(cell);
if (!column.visible) cell.hide();
});
row.cells = cells;
};
return row;
}
generateRowData(pos, data) {
var rowData = {}, calcs = pos == "top" ? this.topCalcs : this.botCalcs, type = pos == "top" ? "topCalc" : "botCalc", params, paramKey;
calcs.forEach(function(column) {
var values = [];
if (column.modules.columnCalcs && column.modules.columnCalcs[type]) {
data.forEach(function(item) {
values.push(column.getFieldValue(item));
});
paramKey = type + "Params";
params = typeof column.modules.columnCalcs[paramKey] === "function" ? column.modules.columnCalcs[paramKey](values, data) : column.modules.columnCalcs[paramKey];
column.setFieldValue(rowData, column.modules.columnCalcs[type](values, data, params));
}
});
return rowData;
}
hasTopCalcs() {
return !!this.topCalcs.length;
}
hasBottomCalcs() {
return !!this.botCalcs.length;
}
redraw() {
if (this.topRow) this.topRow.normalizeHeight(true);
if (this.botRow) this.botRow.normalizeHeight(true);
}
getResults() {
var results = {}, groups;
if (this.table.options.groupBy && this.table.modExists("groupRows")) {
groups = this.table.modules.groupRows.getGroups(true);
groups.forEach((group) => {
results[group.getKey()] = this.getGroupResults(group);
});
} else results = {
top: this.topRow ? this.topRow.getData() : {},
bottom: this.botRow ? this.botRow.getData() : {}
};
return results;
}
getGroupResults(group) {
var groupObj = group._getSelf(), subGroups = group.getSubGroups(), subGroupResults = {}, results = {};
subGroups.forEach((subgroup) => {
subGroupResults[subgroup.getKey()] = this.getGroupResults(subgroup);
});
results = {
top: groupObj.calcs.top ? groupObj.calcs.top.getData() : {},
bottom: groupObj.calcs.bottom ? groupObj.calcs.bottom.getData() : {},
groups: subGroupResults
};
return results;
}
adjustForScrollbar(width) {
if (this.botRow) if (this.table.rtl) this.botElement.style.paddingLeft = width + "px";
else this.botElement.style.paddingRight = width + "px";
}
};
var DataTree = class extends Module {
static moduleName = "dataTree";
constructor(table) {
super(table);
this.indent = 10;
this.field = "";
this.collapseEl = null;
this.expandEl = null;
this.branchEl = null;
this.elementField = false;
this.startOpen = function() {};
this.registerTableOption("dataTree", false);
this.registerTableOption("dataTreeFilter", true);
this.registerTableOption("dataTreeSort", true);
this.registerTableOption("dataTreeElementColumn", false);
this.registerTableOption("dataTreeBranchElement", true);
this.registerTableOption("dataTreeChildIndent", 9);
this.registerTableOption("dataTreeChildField", "_children");
this.registerTableOption("dataTreeCollapseElement", false);
this.registerTableOption("dataTreeExpandElement", false);
this.registerTableOption("dataTreeStartExpanded", false);
this.registerTableOption("dataTreeChildColumnCalcs", false);
this.registerTableOption("dataTreeSelectPropagate", false);
this.registerComponentFunction("row", "treeCollapse", this.collapseRow.bind(this));
this.registerComponentFunction("row", "treeExpand", this.expandRow.bind(this));
this.registerComponentFunction("row", "treeToggle", this.toggleRow.bind(this));
this.registerComponentFunction("row", "getTreeParent", this.getTreeParent.bind(this));
this.registerComponentFunction("row", "getTreeChildren", this.getRowChildren.bind(this));
this.registerComponentFunction("row", "addTreeChild", this.addTreeChildRow.bind(this));
this.registerComponentFunction("row", "isTreeExpanded", this.isRowExpanded.bind(this));
}
initialize() {
if (this.table.options.dataTree) {
var dummyEl = null, options = this.table.options;
this.field = options.dataTreeChildField;
this.indent = options.dataTreeChildIndent;
if (this.options("movableRows")) console.warn("The movableRows option is not available with dataTree enabled, moving of child rows could result in unpredictable behavior");
if (options.dataTreeBranchElement) if (options.dataTreeBranchElement === true) {
this.branchEl = document.createElement("div");
this.branchEl.classList.add("tabulator-data-tree-branch");
} else if (typeof options.dataTreeBranchElement === "string") {
dummyEl = document.createElement("div");
dummyEl.innerHTML = options.dataTreeBranchElement;
this.branchEl = dummyEl.firstChild;
} else this.branchEl = options.dataTreeBranchElement;
else {
this.branchEl = document.createElement("div");
this.branchEl.classList.add("tabulator-data-tree-branch-empty");
}
if (options.dataTreeCollapseElement) if (typeof options.dataTreeCollapseElement === "string") {
dummyEl = document.createElement("div");
dummyEl.innerHTML = options.dataTreeCollapseElement;
this.collapseEl = dummyEl.firstChild;
} else this.collapseEl = options.dataTreeCollapseElement;
else {
this.collapseEl = document.createElement("div");
this.collapseEl.classList.add("tabulator-data-tree-control");
this.collapseEl.tabIndex = 0;
this.collapseEl.innerHTML = "<div class='tabulator-data-tree-control-collapse'></div>";
}
if (options.dataTreeExpandElement) if (typeof options.dataTreeExpandElement === "string") {
dummyEl = document.createElement("div");
dummyEl.innerHTML = options.dataTreeExpandElement;
this.expandEl = dummyEl.firstChild;
} else this.expandEl = options.dataTreeExpandElement;
else {
this.expandEl = document.createElement("div");
this.expandEl.classList.add("tabulator-data-tree-control");
this.expandEl.tabIndex = 0;
this.expandEl.innerHTML = "<div class='tabulator-data-tree-control-expand'></div>";
}
switch (typeof options.dataTreeStartExpanded) {
case "boolean":
this.startOpen = function(row, index) {
return options.dataTreeStartExpanded;
};
break;
case "function":
this.startOpen = options.dataTreeStartExpanded;
break;
default:
this.startOpen = function(row, index) {
return options.dataTreeStartExpanded[index];
};
break;
}
this.subscribe("row-init", this.initializeRow.bind(this));
this.subscribe("row-layout-after", this.layoutRow.bind(this));
this.subscribe("row-deleting", this.rowDeleting.bind(this));
this.subscribe("row-deleted", this.rowDelete.bind(this), 0);
this.subscribe("row-data-changed", this.rowDataChanged.bind(this), 10);
this.subscribe("cell-value-updated", this.cellValueChanged.bind(this));
this.subscribe("edit-cancelled", this.cellValueChanged.bind(this));
this.subscribe("column-moving-rows", this.columnMoving.bind(this));
this.subscribe("table-built", this.initializeElementField.bind(this));
this.subscribe("table-redrawing", this.tableRedrawing.bind(this));
this.registerDisplayHandler(this.getRows.bind(this), 30);
}
}
tableRedrawing(force) {
var rows;
if (force) {
rows = this.table.rowManager.getRows();
rows.forEach((row) => {
this.reinitializeRowChildren(row);
});
}
}
initializeElementField() {
var firstCol = this.table.columnManager.getFirstVisibleColumn();
this.elementField = this.table.options.dataTreeElementColumn || (firstCol ? firstCol.field : false);
}
getRowChildren(row) {
return this.getTreeChildren(row, true);
}
columnMoving() {
var rows = [];
this.table.rowManager.rows.forEach((row) => {
rows = rows.concat(this.getTreeChildren(row, false, true));
});
return rows;
}
rowDataChanged(row, visible, updatedData) {
if (this.redrawNeeded(updatedData)) {
this.initializeRow(row);
if (visible) {
this.layoutRow(row);
this.refreshData(true);
}
}
}
cellValueChanged(cell) {
if (cell.column.getField() === this.elementField) this.layoutRow(cell.row);
}
initializeRow(row) {
var childArray = row.getData()[this.field];
var isArray = Array.isArray(childArray);
var children = isArray || !isArray && typeof childArray === "object" && childArray !== null;
if (!children && row.modules.dataTree && row.modules.dataTree.branchEl) row.modules.dataTree.branchEl.parentNode.removeChild(row.modules.dataTree.branchEl);
if (!children && row.modules.dataTree && row.modules.dataTree.controlEl) row.modules.dataTree.controlEl.parentNode.removeChild(row.modules.dataTree.controlEl);
row.modules.dataTree = {
index: row.modules.dataTree ? row.modules.dataTree.index : 0,
open: children ? row.modules.dataTree ? row.modules.dataTree.open : this.startOpen(row.getComponent(), 0) : false,
controlEl: row.modules.dataTree && children ? row.modules.dataTree.controlEl : false,
branchEl: row.modules.dataTree && children ? row.modules.dataTree.branchEl : false,
parent: row.modules.dataTree ? row.modules.dataTree.parent : false,
children
};
}
reinitializeRowChildren(row) {
this.getTreeChildren(row, false, true).forEach(function(child) {
child.reinitialize(true);
});
}
layoutRow(row) {
var el = (this.elementField ? row.getCell(this.elementField) : row.getCells()[0]).getElement(), config = row.modules.dataTree;
if (config.branchEl) {
if (config.branchEl.parentNode) config.branchEl.parentNode.removeChild(config.branchEl);
config.branchEl = false;
}
if (config.controlEl) {
if (config.controlEl.parentNode) config.controlEl.parentNode.removeChild(config.controlEl);
config.controlEl = false;
}
this.generateControlElement(row, el);
row.getElement().classList.add("tabulator-tree-level-" + config.index);
if (config.index) if (this.branchEl) {
config.branchEl = this.branchEl.cloneNode(true);
el.insertBefore(config.branchEl, el.firstChild);
if (this.table.rtl) config.branchEl.style.marginRight = (config.branchEl.offsetWidth + config.branchEl.style.marginLeft) * (config.index - 1) + config.index * this.indent + "px";
else config.branchEl.style.marginLeft = (config.branchEl.offsetWidth + config.branchEl.style.marginRight) * (config.index - 1) + config.index * this.indent + "px";
} else if (this.table.rtl) el.style.paddingRight = parseInt(window.getComputedStyle(el, null).getPropertyValue("padding-right")) + config.index * this.indent + "px";
else el.style.paddingLeft = parseInt(window.getComputedStyle(el, null).getPropertyValue("padding-left")) + config.index * this.indent + "px";
}
generateControlElement(row, el) {
var config = row.modules.dataTree, oldControl = config.controlEl;
el = el || row.getCells()[0].getElement();
if (config.children !== false) {
if (config.open) {
config.controlEl = this.collapseEl.cloneNode(true);
config.controlEl.addEventListener("click", (e) => {
e.stopPropagation();
this.collapseRow(row);
});
} else {
config.controlEl = this.expandEl.cloneNode(true);
config.controlEl.addEventListener("click", (e) => {
e.stopPropagation();
this.expandRow(row);
});
}
config.controlEl.addEventListener("mousedown", (e) => {
e.stopPropagation();
});
if (oldControl && oldControl.parentNode === el) oldControl.parentNode.replaceChild(config.controlEl, oldControl);
else el.insertBefore(config.controlEl, el.firstChild);
}
}
getRows(rows) {
var output = [];
rows.forEach((row, i) => {
var config, children;
output.push(row);
if (row instanceof Row) {
row.create();
config = row.modules.dataTree;
if (!config.index && config.children !== false) {
children = this.getChildren(row, false, true);
children.forEach((child) => {
child.create();
output.push(child);
});
}
}
});
return output;
}
getChildren(row, allChildren, sortOnly) {
var config = row.modules.dataTree, children = [], output = [];
if (config.children !== false && (config.open || allChildren)) {
if (!Array.isArray(config.children)) config.children = this.generateChildren(row);
if (this.table.modExists("filter") && this.table.options.dataTreeFilter) children = this.table.modules.filter.filter(config.children);
else children = config.children;
if (this.table.modExists("sort") && this.table.options.dataTreeSort) this.table.modules.sort.sort(children, sortOnly);
children.forEach((child) => {
output.push(child);
this.getChildren(child, false, true).forEach((sub) => {
output.push(sub);
});
});
}
return output;
}
generateChildren(row) {
var children = [];
var childArray = row.getData()[this.field];
if (!Array.isArray(childArray)) childArray = [childArray];
childArray.forEach((childData) => {
var childRow = new Row(childData || {}, this.table.rowManager);
childRow.create();
childRow.modules.dataTree.index = row.modules.dataTree.index + 1;
childRow.modules.dataTree.parent = row;
if (childRow.modules.dataTree.children) childRow.modules.dataTree.open = this.startOpen(childRow.getComponent(), childRow.modules.dataTree.index);
children.push(childRow);
});
return children;
}
expandRow(row, silent) {
var config = row.modules.dataTree;
if (config.children !== false) {
config.open = true;
row.reinitialize();
this.refreshData(true);
this.dispatchExternal("dataTreeRowExpanded", row.getComponent(), row.modules.dataTree.index);
}
}
collapseRow(row) {
var config = row.modules.dataTree;
if (config.children !== false) {
config.open = false;
row.reinitialize();
this.refreshData(true);
this.dispatchExternal("dataTreeRowCollapsed", row.getComponent(), row.modules.dataTree.index);
}
}
toggleRow(row) {
var config = row.modules.dataTree;
if (config.children !== false) if (config.open) this.collapseRow(row);
else this.expandRow(row);
}
isRowExpanded(row) {
return row.modules.dataTree.open;
}
getTreeParent(row) {
return row.modules.dataTree.parent ? row.modules.dataTree.parent.getComponent() : false;
}
getTreeParentRoot(row) {
return row.modules.dataTree && row.modules.dataTree.parent ? this.getTreeParentRoot(row.modules.dataTree.parent) : row;
}
getFilteredTreeChildren(row) {
var config = row.modules.dataTree, output = [], children;
if (config.children) {
if (!Array.isArray(config.children)) config.children = this.generateChildren(row);
if (this.table.modExists("filter") && this.table.options.dataTreeFilter) children = this.table.modules.filter.filter(config.children);
else children = config.children;
children.forEach((childRow) => {
if (childRow instanceof Row) output.push(childRow);
});
}
return output;
}
rowDeleting(row) {
var config = row.modules.dataTree;
if (config && config.children && Array.isArray(config.children)) config.children.forEach((childRow) => {
if (childRow instanceof Row) childRow.wipe();
});
}
rowDelete(row) {
var parent = row.modules.dataTree.parent, childIndex;
if (parent) {
childIndex = this.findChildIndex(row, parent);
if (childIndex !== false) parent.data[this.field].splice(childIndex, 1);
if (!parent.data[this.field].length) delete parent.data[this.field];
this.initializeRow(parent);
this.layoutRow(parent);
}
this.refreshData(true);
}
addTreeChildRow(row, data, top, index) {
var childIndex = false;
if (typeof data === "string") data = JSON.parse(data);
if (!Array.isArray(row.data[this.field])) {
row.data[this.field] = [];
row.modules.dataTree.open = this.startOpen(row.getComponent(), row.modules.dataTree.index);
}
if (typeof index !== "undefined") {
childIndex = this.findChildIndex(index, row);
if (childIndex !== false) row.data[this.field].splice(top ? childIndex : childIndex + 1, 0, data);
}
if (childIndex === false) if (top) row.data[this.field].unshift(data);
else row.data[this.field].push(data);
this.initializeRow(row);
this.layoutRow(row);
this.refreshData(true);
}
findChildIndex(subject, parent) {
var match = false;
if (typeof subject == "object") {
if (subject instanceof Row) match = subject.data;
else if (subject instanceof RowComponent) match = subject._getSelf().data;
else if (typeof HTMLElement !== "undefined" && subject instanceof HTMLElement) {
if (parent.modules.dataTree) {
match = parent.modules.dataTree.children.find((childRow) => {
return childRow instanceof Row ? childRow.element === subject : false;
});
if (match) match = match.data;
}
} else if (subject === null) match = false;
} else if (typeof subject == "undefined") match = false;
else match = parent.data[this.field].find((row) => {
return row.data[this.table.options.index] == subject;
});
if (match) {
if (Array.isArray(parent.data[this.field])) match = parent.data[this.field].indexOf(match);
if (match == -1) match = false;
}
return match;
}
getTreeChildren(row, component, recurse) {
var config = row.modules.dataTree, output = [];
if (config && config.children) {
if (!Array.isArray(config.children)) config.children = this.generateChildren(row);
config.children.forEach((childRow) => {
if (childRow instanceof Row) {
output.push(component ? childRow.getComponent() : childRow);
if (recurse) this.getTreeChildren(childRow, component, recurse).forEach((child) => {
output.push(child);
});
}
});
}
return output;
}
getChildField() {
return this.field;
}
redrawNeeded(data) {
return (this.field ? typeof data[this.field] !== "undefined" : false) || (this.elementField ? typeof data[this.elementField] !== "undefined" : false);
}
};
function csv$1(list, options = {}, setFileContents) {
var delimiter = options.delimiter ? options.delimiter : ",", fileContents = [], headers = [];
list.forEach((row) => {
var item = [];
switch (row.type) {
case "group":
console.warn("Download Warning - CSV downloader cannot process row groups");
break;
case "calc":
console.warn("Download Warning - CSV downloader cannot process column calculations");
break;
case "header":
row.columns.forEach((col, i) => {
if (col && col.depth === 1) headers[i] = typeof col.value == "undefined" || col.value === null ? "" : "\"" + String(col.value).split("\"").join("\"\"") + "\"";
});
break;
case "row":
row.columns.forEach((col) => {
if (col) {
switch (typeof col.value) {
case "object":
col.value = col.value !== null ? JSON.stringify(col.value) : "";
break;
case "undefined":
col.value = "";
break;
}
item.push("\"" + String(col.value).split("\"").join("\"\"") + "\"");
}
});
fileContents.push(item.join(delimiter));
break;
}
});
if (headers.length) fileContents.unshift(headers.join(delimiter));
fileContents = fileContents.join("\n");
if (options.bom) fileContents = "" + fileContents;
setFileContents(fileContents, "text/csv");
}
function json$2(list, options, setFileContents) {
var fileContents = [];
list.forEach((row) => {
var item = {};
switch (row.type) {
case "header": break;
case "group":
console.warn("Download Warning - JSON downloader cannot process row groups");
break;
case "calc":
console.warn("Download Warning - JSON downloader cannot process column calculations");
break;
case "row":
row.columns.forEach((col) => {
if (col) item[col.component.getTitleDownload() || col.component.getField()] = col.value;
});
fileContents.push(item);
break;
}
});
fileContents = JSON.stringify(fileContents, null, " ");
setFileContents(fileContents, "application/json");
}
function pdf(list, options = {}, setFileContents) {
var header = [], body = [], autoTableParams = {}, rowGroupStyles = options.rowGroupStyles || {
fontStyle: "bold",
fontSize: 12,
cellPadding: 6,
fillColor: 220
}, rowCalcStyles = options.rowCalcStyles || {
fontStyle: "bold",
fontSize: 10,
cellPadding: 4,
fillColor: 232
}, jsPDFParams = options.jsPDF || {}, title = options.title ? options.title : "", jspdfLib, doc;
if (!jsPDFParams.orientation) jsPDFParams.orientation = options.orientation || "landscape";
if (!jsPDFParams.unit) jsPDFParams.unit = "pt";
list.forEach((row) => {
switch (row.type) {
case "header":
header.push(parseRow(row));
break;
case "group":
body.push(parseRow(row, rowGroupStyles));
break;
case "calc":
body.push(parseRow(row, rowCalcStyles));
break;
case "row":
body.push(parseRow(row));
break;
}
});
function parseRow(row, styles) {
var rowData = [];
row.columns.forEach((col) => {
var cell;
if (col) {
switch (typeof col.value) {
case "object":
col.value = col.value !== null ? JSON.stringify(col.value) : "";
break;
case "undefined":
col.value = "";
break;
}
cell = {
content: col.value,
colSpan: col.width,
rowSpan: col.height
};
if (styles) cell.styles = styles;
rowData.push(cell);
}
});
return rowData;
}
jspdfLib = this.dependencyRegistry.lookup("jspdf", "jsPDF");
doc = new jspdfLib(jsPDFParams);
if (options.autoTable) if (typeof options.autoTable === "function") autoTableParams = options.autoTable(doc) || {};
else autoTableParams = options.autoTable;
if (title) autoTableParams.didDrawPage = function(data) {
doc.text(title, 40, 30);
};
autoTableParams.head = header;
autoTableParams.body = body;
doc.autoTable(autoTableParams);
if (options.documentProcessing) options.documentProcessing(doc);
setFileContents(doc.output("arraybuffer"), "application/pdf");
}
function xlsx$1(list, options, setFileContents) {
var self = this, sheetName = options.sheetName || "Sheet1", XLSXLib = this.dependencyRegistry.lookup("XLSX"), workbook = XLSXLib.utils.book_new(), tableFeatures = new CoreFeature(this), compression = "compress" in options ? options.compress : true, writeOptions = options.writeOptions || {
bookType: "xlsx",
bookSST: true,
compression
}, output;
writeOptions.type = "binary";
workbook.SheetNames = [];
workbook.Sheets = {};
function generateSheet() {
var rows = [], merges = [], worksheet = {}, range = {
s: {
c: 0,
r: 0
},
e: {
c: list[0] ? list[0].columns.reduce((a, b) => a + (b && b.width ? b.width : 1), 0) : 0,
r: list.length
}
};
list.forEach((row, i) => {
var rowData = [];
row.columns.forEach(function(col, j) {
if (col) {
rowData.push(!(col.value instanceof Date) && typeof col.value === "object" ? JSON.stringify(col.value) : col.value);
if (col.width > 1 || col.height > -1) {
if (col.height > 1 || col.width > 1) merges.push({
s: {
r: i,
c: j
},
e: {
r: i + col.height - 1,
c: j + col.width - 1
}
});
}
} else rowData.push("");
});
rows.push(rowData);
});
XLSXLib.utils.sheet_add_aoa(worksheet, rows);
worksheet["!ref"] = XLSXLib.utils.encode_range(range);
if (merges.length) worksheet["!merges"] = merges;
return worksheet;
}
if (options.sheetOnly) {
setFileContents(generateSheet());
return;
}
if (options.sheets) for (var sheet in options.sheets) if (options.sheets[sheet] === true) {
workbook.SheetNames.push(sheet);
workbook.Sheets[sheet] = generateSheet();
} else {
workbook.SheetNames.push(sheet);
tableFeatures.commsSend(options.sheets[sheet], "download", "intercept", {
type: "xlsx",
options: { sheetOnly: true },
active: self.active,
intercept: function(data) {
workbook.Sheets[sheet] = data;
}
});
}
else {
workbook.SheetNames.push(sheetName);
workbook.Sheets[sheetName] = generateSheet();
}
if (options.documentProcessing) workbook = options.documentProcessing(workbook);
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 255;
return buf;
}
output = XLSXLib.write(workbook, writeOptions);
setFileContents(s2ab(output), "application/octet-stream");
}
function html$1(list, options, setFileContents) {
if (this.modExists("export", true)) setFileContents(this.modules.export.generateHTMLTable(list), "text/html");
}
function jsonLines(list, options, setFileContents) {
const fileContents = [];
list.forEach((row) => {
const item = {};
switch (row.type) {
case "header": break;
case "group":
console.warn("Download Warning - JSON downloader cannot process row groups");
break;
case "calc":
console.warn("Download Warning - JSON downloader cannot process column calculations");
break;
case "row":
row.columns.forEach((col) => {
if (col) item[col.component.getTitleDownload() || col.component.getField()] = col.value;
});
fileContents.push(JSON.stringify(item));
break;
}
});
setFileContents(fileContents.join("\n"), "application/x-ndjson");
}
var defaultDownloaders = {
csv: csv$1,
json: json$2,
jsonLines,
pdf,
xlsx: xlsx$1,
html: html$1
};
var Download = class Download extends Module {
static moduleName = "download";
static downloaders = defaultDownloaders;
constructor(table) {
super(table);
this.registerTableOption("downloadEncoder", function(data, mimeType) {
return new Blob([data], { type: mimeType });
});
this.registerTableOption("downloadConfig", {});
this.registerTableOption("downloadRowRange", "active");
this.registerColumnOption("download");
this.registerColumnOption("titleDownload");
}
initialize() {
this.deprecatedOptionsCheck();
this.registerTableFunction("download", this.download.bind(this));
this.registerTableFunction("downloadToTab", this.downloadToTab.bind(this));
}
deprecatedOptionsCheck() {}
downloadToTab(type, filename, options, active) {
this.download(type, filename, options, active, true);
}
download(type, filename, options, range, interceptCallback) {
var downloadFunc = false;
function buildLink(data, mime) {
if (interceptCallback) if (interceptCallback === true) this.triggerDownload(data, mime, type, filename, true);
else interceptCallback(data);
else this.triggerDownload(data, mime, type, filename);
}
if (typeof type == "function") downloadFunc = type;
else if (Download.downloaders[type]) downloadFunc = Download.downloaders[type];
else console.warn("Download Error - No such download type found: ", type);
if (downloadFunc) {
var list = this.generateExportList(range);
downloadFunc.call(this.table, list, options || {}, buildLink.bind(this));
}
}
generateExportList(range) {
var list = this.table.modules.export.generateExportList(this.table.options.downloadConfig, false, range || this.table.options.downloadRowRange, "download");
var groupHeader = this.table.options.groupHeaderDownload;
if (groupHeader && !Array.isArray(groupHeader)) groupHeader = [groupHeader];
list.forEach((row) => {
var group;
if (row.type === "group") {
group = row.columns[0];
if (groupHeader && groupHeader[row.indent]) group.value = groupHeader[row.indent](group.value, row.component._group.getRowCount(), row.component._group.getData(), row.component);
}
});
return list;
}
triggerDownload(data, mime, type, filename, newTab) {
var element = document.createElement("a"), blob = this.table.options.downloadEncoder(data, mime);
if (blob) {
if (newTab) window.open(window.URL.createObjectURL(blob));
else {
filename = filename || "Tabulator." + (typeof type === "function" ? "txt" : type);
if (navigator.msSaveOrOpenBlob) navigator.msSaveOrOpenBlob(blob, filename);
else {
element.setAttribute("href", window.URL.createObjectURL(blob));
element.setAttribute("download", filename);
element.style.display = "none";
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
}
this.dispatchExternal("downloadComplete");
}
}
commsReceived(table, action, data) {
switch (action) {
case "intercept":
this.download(data.type, "", data.options, data.active, data.intercept);
break;
}
}
};
function maskInput(el, options) {
var mask = options.mask, maskLetter = typeof options.maskLetterChar !== "undefined" ? options.maskLetterChar : "A", maskNumber = typeof options.maskNumberChar !== "undefined" ? options.maskNumberChar : "9", maskWildcard = typeof options.maskWildcardChar !== "undefined" ? options.maskWildcardChar : "*";
function fillSymbols(index) {
var symbol = mask[index];
if (typeof symbol !== "undefined" && symbol !== maskWildcard && symbol !== maskLetter && symbol !== maskNumber) {
el.value = el.value + "" + symbol;
fillSymbols(index + 1);
}
}
el.addEventListener("keydown", (e) => {
var index = el.value.length, char = e.key;
if (e.keyCode > 46 && !e.ctrlKey && !e.metaKey) if (index >= mask.length) {
e.preventDefault();
e.stopPropagation();
return false;
} else switch (mask[index]) {
case maskLetter:
if (char.toUpperCase() == char.toLowerCase()) {
e.preventDefault();
e.stopPropagation();
return false;
}
break;
case maskNumber:
if (isNaN(char)) {
e.preventDefault();
e.stopPropagation();
return false;
}
break;
case maskWildcard: break;
default: if (char !== mask[index]) {
e.preventDefault();
e.stopPropagation();
return false;
}
}
});
el.addEventListener("keyup", (e) => {
if (e.keyCode > 46) {
if (options.maskAutoFill) fillSymbols(el.value.length);
}
});
if (!el.placeholder) el.placeholder = mask;
if (options.maskAutoFill) fillSymbols(el.value.length);
}
function input(cell, onRendered, success, cancel, editorParams) {
var cellValue = cell.getValue(), input = document.createElement("input");
input.setAttribute("type", editorParams.search ? "search" : "text");
input.style.padding = "4px";
input.style.width = "100%";
input.style.boxSizing = "border-box";
if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
key = key.slice(1);
input.setAttribute(key, input.getAttribute(key) + editorParams.elementAttributes["+" + key]);
} else input.setAttribute(key, editorParams.elementAttributes[key]);
input.value = typeof cellValue !== "undefined" ? cellValue : "";
onRendered(function() {
if (cell.getType() === "cell") {
input.focus({ preventScroll: true });
input.style.height = "100%";
if (editorParams.selectContents) input.select();
}
});
function onChange(e) {
if ((cellValue === null || typeof cellValue === "undefined") && input.value !== "" || input.value !== cellValue) {
if (success(input.value)) cellValue = input.value;
} else cancel();
}
input.addEventListener("change", onChange);
input.addEventListener("blur", onChange);
input.addEventListener("keydown", function(e) {
switch (e.keyCode) {
case 13:
onChange();
break;
case 27:
cancel();
break;
case 35:
case 36:
e.stopPropagation();
break;
}
});
if (editorParams.mask) maskInput(input, editorParams);
return input;
}
function textarea$1(cell, onRendered, success, cancel, editorParams) {
var cellValue = cell.getValue(), vertNav = editorParams.verticalNavigation || "hybrid", value = String(cellValue !== null && typeof cellValue !== "undefined" ? cellValue : ""), input = document.createElement("textarea"), scrollHeight = 0;
input.style.display = "block";
input.style.padding = "2px";
input.style.height = "100%";
input.style.width = "100%";
input.style.boxSizing = "border-box";
input.style.whiteSpace = "pre-wrap";
input.style.resize = "none";
if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
key = key.slice(1);
input.setAttribute(key, input.getAttribute(key) + editorParams.elementAttributes["+" + key]);
} else input.setAttribute(key, editorParams.elementAttributes[key]);
input.value = value;
onRendered(function() {
if (cell.getType() === "cell") {
input.focus({ preventScroll: true });
input.style.height = "100%";
input.scrollHeight;
input.style.height = input.scrollHeight + "px";
cell.getRow().normalizeHeight();
if (editorParams.selectContents) input.select();
}
});
function onChange(e) {
if ((cellValue === null || typeof cellValue === "undefined") && input.value !== "" || input.value !== cellValue) {
if (success(input.value)) cellValue = input.value;
setTimeout(function() {
cell.getRow().normalizeHeight();
}, 300);
} else cancel();
}
input.addEventListener("change", onChange);
input.addEventListener("blur", onChange);
input.addEventListener("keyup", function() {
input.style.height = "";
var heightNow = input.scrollHeight;
input.style.height = heightNow + "px";
if (heightNow != scrollHeight) {
scrollHeight = heightNow;
cell.getRow().normalizeHeight();
}
});
input.addEventListener("keydown", function(e) {
switch (e.keyCode) {
case 13:
if (e.shiftKey && editorParams.shiftEnterSubmit) onChange();
break;
case 27:
cancel();
break;
case 38:
if (vertNav == "editor" || vertNav == "hybrid" && input.selectionStart) {
e.stopImmediatePropagation();
e.stopPropagation();
}
break;
case 40:
if (vertNav == "editor" || vertNav == "hybrid" && input.selectionStart !== input.value.length) {
e.stopImmediatePropagation();
e.stopPropagation();
}
break;
case 35:
case 36:
e.stopPropagation();
break;
}
});
if (editorParams.mask) maskInput(input, editorParams);
return input;
}
function number$1(cell, onRendered, success, cancel, editorParams) {
var cellValue = cell.getValue(), vertNav = editorParams.verticalNavigation || "editor", input = document.createElement("input");
input.setAttribute("type", "number");
if (typeof editorParams.max != "undefined") input.setAttribute("max", editorParams.max);
if (typeof editorParams.min != "undefined") input.setAttribute("min", editorParams.min);
if (typeof editorParams.step != "undefined") input.setAttribute("step", editorParams.step);
input.style.padding = "4px";
input.style.width = "100%";
input.style.boxSizing = "border-box";
if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
key = key.slice(1);
input.setAttribute(key, input.getAttribute(key) + editorParams.elementAttributes["+" + key]);
} else input.setAttribute(key, editorParams.elementAttributes[key]);
input.value = cellValue;
var blurFunc = function(e) {
onChange();
};
onRendered(function() {
if (cell.getType() === "cell") {
input.removeEventListener("blur", blurFunc);
input.focus({ preventScroll: true });
input.style.height = "100%";
input.addEventListener("blur", blurFunc);
if (editorParams.selectContents) input.select();
}
});
function onChange() {
var value = input.value;
if (!isNaN(value) && value !== "") value = Number(value);
if (value !== cellValue) {
if (success(value)) cellValue = value;
} else cancel();
}
input.addEventListener("keydown", function(e) {
switch (e.keyCode) {
case 13:
onChange();
break;
case 27:
cancel();
break;
case 38:
case 40:
if (vertNav == "editor") {
e.stopImmediatePropagation();
e.stopPropagation();
}
break;
case 35:
case 36:
e.stopPropagation();
break;
}
});
if (editorParams.mask) maskInput(input, editorParams);
return input;
}
function range(cell, onRendered, success, cancel, editorParams) {
var cellValue = cell.getValue(), input = document.createElement("input");
input.setAttribute("type", "range");
if (typeof editorParams.max != "undefined") input.setAttribute("max", editorParams.max);
if (typeof editorParams.min != "undefined") input.setAttribute("min", editorParams.min);
if (typeof editorParams.step != "undefined") input.setAttribute("step", editorParams.step);
input.style.padding = "4px";
input.style.width = "100%";
input.style.boxSizing = "border-box";
if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
key = key.slice(1);
input.setAttribute(key, input.getAttribute(key) + editorParams.elementAttributes["+" + key]);
} else input.setAttribute(key, editorParams.elementAttributes[key]);
input.value = cellValue;
onRendered(function() {
if (cell.getType() === "cell") {
input.focus({ preventScroll: true });
input.style.height = "100%";
}
});
function onChange() {
var value = input.value;
if (!isNaN(value) && value !== "") value = Number(value);
if (value != cellValue) {
if (success(value)) cellValue = value;
} else cancel();
}
input.addEventListener("blur", function(e) {
onChange();
});
input.addEventListener("keydown", function(e) {
switch (e.keyCode) {
case 13:
onChange();
break;
case 27:
cancel();
break;
}
});
return input;
}
function date$1(cell, onRendered, success, cancel, editorParams) {
var inputFormat = editorParams.format, vertNav = editorParams.verticalNavigation || "editor", DT = inputFormat ? window.DateTime || luxon.DateTime : null;
var cellValue = cell.getValue(), input = document.createElement("input");
function convertDate(value) {
var newDatetime;
if (DT.isDateTime(value)) newDatetime = value;
else if (inputFormat === "iso") newDatetime = DT.fromISO(String(value));
else newDatetime = DT.fromFormat(String(value), inputFormat);
return newDatetime.toFormat("yyyy-MM-dd");
}
input.type = "date";
input.style.padding = "4px";
input.style.width = "100%";
input.style.boxSizing = "border-box";
if (editorParams.max) input.setAttribute("max", inputFormat ? convertDate(editorParams.max) : editorParams.max);
if (editorParams.min) input.setAttribute("min", inputFormat ? convertDate(editorParams.min) : editorParams.min);
if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
key = key.slice(1);
input.setAttribute(key, input.getAttribute(key) + editorParams.elementAttributes["+" + key]);
} else input.setAttribute(key, editorParams.elementAttributes[key]);
cellValue = typeof cellValue !== "undefined" ? cellValue : "";
if (inputFormat) if (DT) cellValue = convertDate(cellValue);
else console.error("Editor Error - 'date' editor 'format' param is dependant on luxon.js");
input.value = cellValue;
onRendered(function() {
if (cell.getType() === "cell") {
input.focus({ preventScroll: true });
input.style.height = "100%";
if (editorParams.selectContents) input.select();
}
});
function onChange() {
var value = input.value, luxDate;
if ((cellValue === null || typeof cellValue === "undefined") && value !== "" || value !== cellValue) {
if (value && inputFormat) {
luxDate = DT.fromFormat(String(value), "yyyy-MM-dd");
switch (inputFormat) {
case true:
value = luxDate;
break;
case "iso":
value = luxDate.toISO();
break;
default: value = luxDate.toFormat(inputFormat);
}
}
if (success(value)) cellValue = input.value;
} else cancel();
}
input.addEventListener("blur", function(e) {
if (e.relatedTarget || e.rangeParent || e.explicitOriginalTarget !== input) onChange();
});
input.addEventListener("keydown", function(e) {
switch (e.keyCode) {
case 13:
onChange();
break;
case 27:
cancel();
break;
case 35:
case 36:
e.stopPropagation();
break;
case 38:
case 40:
if (vertNav == "editor") {
e.stopImmediatePropagation();
e.stopPropagation();
}
break;
}
});
return input;
}
function time$1(cell, onRendered, success, cancel, editorParams) {
var inputFormat = editorParams.format, vertNav = editorParams.verticalNavigation || "editor", DT = inputFormat ? window.DateTime || luxon.DateTime : null, newDatetime;
var cellValue = cell.getValue(), input = document.createElement("input");
input.type = "time";
input.style.padding = "4px";
input.style.width = "100%";
input.style.boxSizing = "border-box";
if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
key = key.slice(1);
input.setAttribute(key, input.getAttribute(key) + editorParams.elementAttributes["+" + key]);
} else input.setAttribute(key, editorParams.elementAttributes[key]);
cellValue = typeof cellValue !== "undefined" ? cellValue : "";
if (inputFormat) if (DT) {
if (DT.isDateTime(cellValue)) newDatetime = cellValue;
else if (inputFormat === "iso") newDatetime = DT.fromISO(String(cellValue));
else newDatetime = DT.fromFormat(String(cellValue), inputFormat);
cellValue = newDatetime.toFormat("HH:mm");
} else console.error("Editor Error - 'date' editor 'format' param is dependant on luxon.js");
input.value = cellValue;
onRendered(function() {
if (cell.getType() == "cell") {
input.focus({ preventScroll: true });
input.style.height = "100%";
if (editorParams.selectContents) input.select();
}
});
function onChange() {
var value = input.value, luxTime;
if ((cellValue === null || typeof cellValue === "undefined") && value !== "" || value !== cellValue) {
if (value && inputFormat) {
luxTime = DT.fromFormat(String(value), "hh:mm");
switch (inputFormat) {
case true:
value = luxTime;
break;
case "iso":
value = luxTime.toISO();
break;
default: value = luxTime.toFormat(inputFormat);
}
}
if (success(value)) cellValue = input.value;
} else cancel();
}
input.addEventListener("blur", function(e) {
if (e.relatedTarget || e.rangeParent || e.explicitOriginalTarget !== input) onChange();
});
input.addEventListener("keydown", function(e) {
switch (e.keyCode) {
case 13:
onChange();
break;
case 27:
cancel();
break;
case 35:
case 36:
e.stopPropagation();
break;
case 38:
case 40:
if (vertNav == "editor") {
e.stopImmediatePropagation();
e.stopPropagation();
}
break;
}
});
return input;
}
function datetime$2(cell, onRendered, success, cancel, editorParams) {
var inputFormat = editorParams.format, vertNav = editorParams.verticalNavigation || "editor", DT = inputFormat ? this.table.dependencyRegistry.lookup(["luxon", "DateTime"], "DateTime") : null, newDatetime;
var cellValue = cell.getValue(), input = document.createElement("input");
input.type = "datetime-local";
input.style.padding = "4px";
input.style.width = "100%";
input.style.boxSizing = "border-box";
if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
key = key.slice(1);
input.setAttribute(key, input.getAttribute(key) + editorParams.elementAttributes["+" + key]);
} else input.setAttribute(key, editorParams.elementAttributes[key]);
cellValue = typeof cellValue !== "undefined" ? cellValue : "";
if (inputFormat) if (DT) {
if (DT.isDateTime(cellValue)) newDatetime = cellValue;
else if (inputFormat === "iso") newDatetime = DT.fromISO(String(cellValue));
else newDatetime = DT.fromFormat(String(cellValue), inputFormat);
cellValue = newDatetime.toFormat("yyyy-MM-dd") + "T" + newDatetime.toFormat("HH:mm");
} else console.error("Editor Error - 'date' editor 'format' param is dependant on luxon.js");
input.value = cellValue;
onRendered(function() {
if (cell.getType() === "cell") {
input.focus({ preventScroll: true });
input.style.height = "100%";
if (editorParams.selectContents) input.select();
}
});
function onChange() {
var value = input.value, luxDateTime;
if ((cellValue === null || typeof cellValue === "undefined") && value !== "" || value !== cellValue) {
if (value && inputFormat) {
luxDateTime = DT.fromISO(String(value));
switch (inputFormat) {
case true:
value = luxDateTime;
break;
case "iso":
value = luxDateTime.toISO();
break;
default: value = luxDateTime.toFormat(inputFormat);
}
}
if (success(value)) cellValue = input.value;
} else cancel();
}
input.addEventListener("blur", function(e) {
if (e.relatedTarget || e.rangeParent || e.explicitOriginalTarget !== input) onChange();
});
input.addEventListener("keydown", function(e) {
switch (e.keyCode) {
case 13:
onChange();
break;
case 27:
cancel();
break;
case 35:
case 36:
e.stopPropagation();
break;
case 38:
case 40:
if (vertNav == "editor") {
e.stopImmediatePropagation();
e.stopPropagation();
}
break;
}
});
return input;
}
var Edit$1 = class Edit {
constructor(editor, cell, onRendered, success, cancel, editorParams) {
this.edit = editor;
this.table = editor.table;
this.cell = cell;
this.params = this._initializeParams(editorParams);
this.data = [];
this.displayItems = [];
this.currentItems = [];
this.focusedItem = null;
this.input = this._createInputElement();
this.listEl = this._createListElement();
this.initialValues = null;
this.isFilter = cell.getType() === "header";
this.filterTimeout = null;
this.filtered = false;
this.typing = false;
this.values = [];
this.popup = null;
this.listIteration = 0;
this.lastAction = "";
this.filterTerm = "";
this.blurable = true;
this.actions = {
success,
cancel
};
this._deprecatedOptionsCheck();
this._initializeValue();
onRendered(this._onRendered.bind(this));
}
_deprecatedOptionsCheck() {}
_initializeValue() {
var initialValue = this.cell.getValue();
if (typeof initialValue === "undefined" && typeof this.params.defaultValue !== "undefined") initialValue = this.params.defaultValue;
this.initialValues = this.params.multiselect ? initialValue : [initialValue];
if (this.isFilter) {
this.input.value = this.initialValues ? this.initialValues.join(",") : "";
this.headerFilterInitialListGen();
}
}
_onRendered() {
var cellEl = this.cell.getElement();
function clickStop(e) {
e.stopPropagation();
}
if (!this.isFilter) {
this.input.style.height = "100%";
this.input.focus({ preventScroll: true });
}
cellEl.addEventListener("click", clickStop);
setTimeout(() => {
cellEl.removeEventListener("click", clickStop);
}, 1e3);
this.input.addEventListener("mousedown", this._preventPopupBlur.bind(this));
}
_createListElement() {
var listEl = document.createElement("div");
listEl.classList.add("tabulator-edit-list");
listEl.addEventListener("mousedown", this._preventBlur.bind(this));
listEl.addEventListener("keydown", this._inputKeyDown.bind(this));
return listEl;
}
_setListWidth() {
var element = this.isFilter ? this.input : this.cell.getElement();
this.listEl.style.minWidth = element.offsetWidth + "px";
if (this.params.maxWidth) if (this.params.maxWidth === true) this.listEl.style.maxWidth = element.offsetWidth + "px";
else if (typeof this.params.maxWidth === "number") this.listEl.style.maxWidth = this.params.maxWidth + "px";
else this.listEl.style.maxWidth = this.params.maxWidth;
}
_createInputElement() {
var attribs = this.params.elementAttributes;
var input = document.createElement("input");
input.setAttribute("type", this.params.clearable ? "search" : "text");
input.style.padding = "4px";
input.style.width = "100%";
input.style.boxSizing = "border-box";
if (!this.params.autocomplete) {
input.style.cursor = "default";
input.style.caretColor = "transparent";
}
if (attribs && typeof attribs == "object") for (let key in attribs) if (key.charAt(0) == "+") {
key = key.slice(1);
input.setAttribute(key, input.getAttribute(key) + attribs["+" + key]);
} else input.setAttribute(key, attribs[key]);
if (this.params.mask) maskInput(input, this.params);
this._bindInputEvents(input);
return input;
}
_initializeParams(params) {
var valueKeys = [
"values",
"valuesURL",
"valuesLookup"
], valueCheck;
params = Object.assign({}, params);
params.verticalNavigation = params.verticalNavigation || "editor";
params.placeholderLoading = typeof params.placeholderLoading === "undefined" ? "Searching ..." : params.placeholderLoading;
params.placeholderEmpty = typeof params.placeholderEmpty === "undefined" ? "No Results Found" : params.placeholderEmpty;
params.filterDelay = typeof params.filterDelay === "undefined" ? 300 : params.filterDelay;
params.emptyValue = Object.keys(params).includes("emptyValue") ? params.emptyValue : "";
valueCheck = Object.keys(params).filter((key) => valueKeys.includes(key)).length;
if (!valueCheck) console.warn("list editor config error - either the values, valuesURL, or valuesLookup option must be set");
else if (valueCheck > 1) console.warn("list editor config error - only one of the values, valuesURL, or valuesLookup options can be set on the same editor");
if (params.autocomplete) {
if (params.multiselect) {
params.multiselect = false;
console.warn("list editor config error - multiselect option is not available when autocomplete is enabled");
}
} else {
if (params.freetext) {
params.freetext = false;
console.warn("list editor config error - freetext option is only available when autocomplete is enabled");
}
if (params.filterFunc) {
params.filterFunc = false;
console.warn("list editor config error - filterFunc option is only available when autocomplete is enabled");
}
if (params.filterRemote) {
params.filterRemote = false;
console.warn("list editor config error - filterRemote option is only available when autocomplete is enabled");
}
if (params.mask) {
params.mask = false;
console.warn("list editor config error - mask option is only available when autocomplete is enabled");
}
if (params.allowEmpty) {
params.allowEmpty = false;
console.warn("list editor config error - allowEmpty option is only available when autocomplete is enabled");
}
if (params.listOnEmpty) {
params.listOnEmpty = false;
console.warn("list editor config error - listOnEmpty option is only available when autocomplete is enabled");
}
}
if (params.filterRemote && !(typeof params.valuesLookup === "function" || params.valuesURL)) {
params.filterRemote = false;
console.warn("list editor config error - filterRemote option should only be used when values list is populated from a remote source");
}
return params;
}
_bindInputEvents(input) {
input.addEventListener("focus", this._inputFocus.bind(this));
input.addEventListener("click", this._inputClick.bind(this));
input.addEventListener("blur", this._inputBlur.bind(this));
input.addEventListener("keydown", this._inputKeyDown.bind(this));
input.addEventListener("search", this._inputSearch.bind(this));
if (this.params.autocomplete) input.addEventListener("keyup", this._inputKeyUp.bind(this));
}
_inputFocus(e) {
this.rebuildOptionsList();
}
_filter() {
if (this.params.filterRemote) {
clearTimeout(this.filterTimeout);
this.filterTimeout = setTimeout(() => {
this.rebuildOptionsList();
}, this.params.filterDelay);
} else this._filterList();
}
_inputClick(e) {
e.stopPropagation();
}
_inputBlur(e) {
if (this.blurable) if (this.popup) this.popup.hide();
else this._resolveValue(true);
}
_inputSearch() {
this._clearChoices();
}
_inputKeyDown(e) {
switch (e.keyCode) {
case 38:
this._keyUp(e);
break;
case 40:
this._keyDown(e);
break;
case 37:
case 39:
this._keySide(e);
break;
case 13:
this._keyEnter();
break;
case 27:
this._keyEsc();
break;
case 36:
case 35:
this._keyHomeEnd(e);
break;
case 9:
this._keyTab(e);
break;
default: this._keySelectLetter(e);
}
}
_inputKeyUp(e) {
switch (e.keyCode) {
case 38:
case 37:
case 39:
case 40:
case 13:
case 27: break;
default: this._keyAutoCompLetter(e);
}
}
_preventPopupBlur() {
if (this.popup) this.popup.blockHide();
setTimeout(() => {
if (this.popup) this.popup.restoreHide();
}, 10);
}
_preventBlur() {
this.blurable = false;
setTimeout(() => {
this.blurable = true;
}, 10);
}
_keyTab(e) {
if (this.params.autocomplete && this.lastAction === "typing") this._resolveValue(true);
else if (this.focusedItem) this._chooseItem(this.focusedItem, true);
}
_keyUp(e) {
var index = this.displayItems.indexOf(this.focusedItem);
if (this.params.verticalNavigation == "editor" || this.params.verticalNavigation == "hybrid" && index) {
e.stopImmediatePropagation();
e.stopPropagation();
e.preventDefault();
if (index > 0) this._focusItem(this.displayItems[index - 1]);
}
}
_keyDown(e) {
var index = this.displayItems.indexOf(this.focusedItem);
if (this.params.verticalNavigation == "editor" || this.params.verticalNavigation == "hybrid" && index < this.displayItems.length - 1) {
e.stopImmediatePropagation();
e.stopPropagation();
e.preventDefault();
if (index < this.displayItems.length - 1) if (index == -1) this._focusItem(this.displayItems[0]);
else this._focusItem(this.displayItems[index + 1]);
}
}
_keySide(e) {
if (!this.params.autocomplete) {
e.stopImmediatePropagation();
e.stopPropagation();
e.preventDefault();
}
}
_keyEnter(e) {
if (this.params.autocomplete && this.lastAction === "typing") this._resolveValue(true);
else if (this.focusedItem) this._chooseItem(this.focusedItem);
}
_keyEsc(e) {
this._cancel();
}
_keyHomeEnd(e) {
if (this.params.autocomplete) e.stopImmediatePropagation();
}
_keySelectLetter(e) {
if (!this.params.autocomplete) {
e.preventDefault();
if (e.keyCode >= 38 && e.keyCode <= 90) this._scrollToValue(e.keyCode);
}
}
_keyAutoCompLetter(e) {
this._filter();
this.lastAction = "typing";
this.typing = true;
}
_scrollToValue(char) {
clearTimeout(this.filterTimeout);
var character = String.fromCharCode(char).toLowerCase();
this.filterTerm += character.toLowerCase();
var match = this.displayItems.find((item) => {
return typeof item.label !== "undefined" && item.label.toLowerCase().startsWith(this.filterTerm);
});
if (match) this._focusItem(match);
this.filterTimeout = setTimeout(() => {
this.filterTerm = "";
}, 800);
}
_focusItem(item) {
this.lastAction = "focus";
if (this.focusedItem && this.focusedItem.element) this.focusedItem.element.classList.remove("focused");
this.focusedItem = item;
if (item && item.element) {
item.element.classList.add("focused");
item.element.scrollIntoView({
behavior: "smooth",
block: "nearest",
inline: "start"
});
}
}
headerFilterInitialListGen() {
this._generateOptions(true);
}
rebuildOptionsList() {
this._generateOptions().then(this._sortOptions.bind(this)).then(this._buildList.bind(this)).then(this._showList.bind(this)).catch((e) => {
if (!Number.isInteger(e)) console.error("List generation error", e);
});
}
_filterList() {
this._buildList(this._filterOptions());
this._showList();
}
_generateOptions(silent) {
var values = [];
var iteration = ++this.listIteration;
this.filtered = false;
if (this.params.values) values = this.params.values;
else if (this.params.valuesURL) values = this._ajaxRequest(this.params.valuesURL, this.input.value);
else if (typeof this.params.valuesLookup === "function") values = this.params.valuesLookup(this.cell, this.input.value);
else if (this.params.valuesLookup) values = this._uniqueColumnValues(this.params.valuesLookupField);
if (values instanceof Promise) {
if (!silent) this._addPlaceholder(this.params.placeholderLoading);
return values.then().then((responseValues) => {
if (this.listIteration === iteration) return this._parseList(responseValues);
else return Promise.reject(iteration);
});
} else return Promise.resolve(this._parseList(values));
}
_addPlaceholder(contents) {
var placeholder = document.createElement("div");
if (typeof contents === "function") contents = contents(this.cell.getComponent(), this.listEl);
if (contents) {
this._clearList();
if (contents instanceof HTMLElement) placeholder = contents;
else {
placeholder.classList.add("tabulator-edit-list-placeholder");
placeholder.innerHTML = contents;
}
this.listEl.appendChild(placeholder);
this._showList();
}
}
_ajaxRequest(url, term) {
var params = this.params.filterRemote ? { term } : {};
url = urlBuilder(url, {}, params);
return fetch(url).then((response) => {
if (response.ok) return response.json().catch((error) => {
console.warn("List Ajax Load Error - Invalid JSON returned", error);
return Promise.reject(error);
});
else {
console.error("List Ajax Load Error - Connection Error: " + response.status, response.statusText);
return Promise.reject(response);
}
}).catch((error) => {
console.error("List Ajax Load Error - Connection Error: ", error);
return Promise.reject(error);
});
}
_uniqueColumnValues(field) {
var output = {}, data = this.table.getData(this.params.valuesLookup), column;
if (field) column = this.table.columnManager.getColumnByField(field);
else column = this.cell.getColumn()._getSelf();
if (column) data.forEach((row) => {
var val = column.getFieldValue(row);
if (!this._emptyValueCheck(val)) if (this.params.multiselect && Array.isArray(val)) val.forEach((item) => {
if (!this._emptyValueCheck(item)) output[item] = true;
});
else output[val] = true;
});
else {
console.warn("unable to find matching column to create select lookup list:", field);
output = [];
}
return Object.keys(output);
}
_emptyValueCheck(value) {
return value === null || typeof value === "undefined" || value === "";
}
_parseList(inputValues) {
var data = [];
if (!Array.isArray(inputValues)) inputValues = Object.entries(inputValues).map(([key, value]) => {
return {
label: value,
value: key
};
});
inputValues.forEach((value) => {
if (typeof value !== "object") value = {
label: value,
value
};
this._parseListItem(value, data, 0);
});
if (!this.currentItems.length && this.params.freetext) {
this.input.value = this.initialValues;
this.typing = true;
this.lastAction = "typing";
}
this.data = data;
return data;
}
_parseListItem(option, data, level) {
var item = {};
if (option.options) item = this._parseListGroup(option, level + 1);
else {
item = {
label: option.label,
value: option.value,
itemParams: option.itemParams,
elementAttributes: option.elementAttributes,
element: false,
selected: false,
visible: true,
level,
original: option
};
if (this.initialValues && this.initialValues.indexOf(option.value) > -1) this._chooseItem(item, true);
}
data.push(item);
}
_parseListGroup(option, level) {
var item = {
label: option.label,
group: true,
itemParams: option.itemParams,
elementAttributes: option.elementAttributes,
element: false,
visible: true,
level,
options: [],
original: option
};
option.options.forEach((child) => {
this._parseListItem(child, item.options, level);
});
return item;
}
_sortOptions(options) {
var sorter;
if (this.params.sort) {
sorter = typeof this.params.sort === "function" ? this.params.sort : this._defaultSortFunction.bind(this);
this._sortGroup(sorter, options);
}
return options;
}
_sortGroup(sorter, options) {
options.sort((a, b) => {
return sorter(a.label, b.label, a.value, b.value, a.original, b.original);
});
options.forEach((option) => {
if (option.group) this._sortGroup(sorter, option.options);
});
}
_defaultSortFunction(as, bs) {
var a, b, a1, b1, i = 0, L, rx = /(\d+)|(\D+)/g, rd = /\d/;
var emptyAlign = 0;
if (this.params.sort === "desc") [as, bs] = [bs, as];
if (!as && as !== 0) emptyAlign = !bs && bs !== 0 ? 0 : -1;
else if (!bs && bs !== 0) emptyAlign = 1;
else {
if (isFinite(as) && isFinite(bs)) return as - bs;
a = String(as).toLowerCase();
b = String(bs).toLowerCase();
if (a === b) return 0;
if (!(rd.test(a) && rd.test(b))) return a > b ? 1 : -1;
a = a.match(rx);
b = b.match(rx);
L = a.length > b.length ? b.length : a.length;
while (i < L) {
a1 = a[i];
b1 = b[i++];
if (a1 !== b1) if (isFinite(a1) && isFinite(b1)) {
if (a1.charAt(0) === "0") a1 = "." + a1;
if (b1.charAt(0) === "0") b1 = "." + b1;
return a1 - b1;
} else return a1 > b1 ? 1 : -1;
}
return a.length > b.length;
}
return emptyAlign;
}
_filterOptions() {
var filterFunc = this.params.filterFunc || this._defaultFilterFunc, term = this.input.value;
if (term) {
this.filtered = true;
this.data.forEach((item) => {
this._filterItem(filterFunc, term, item);
});
} else this.filtered = false;
return this.data;
}
_filterItem(func, term, item) {
var matches = false;
if (!item.group) item.visible = func(term, item.label, item.value, item.original);
else {
item.options.forEach((option) => {
if (this._filterItem(func, term, option)) matches = true;
});
item.visible = matches;
}
return item.visible;
}
_defaultFilterFunc(term, label, value, item) {
term = String(term).toLowerCase();
if (label !== null && typeof label !== "undefined") {
if (String(label).toLowerCase().indexOf(term) > -1 || String(value).toLowerCase().indexOf(term) > -1) return true;
}
return false;
}
_clearList() {
while (this.listEl.firstChild) this.listEl.removeChild(this.listEl.firstChild);
this.displayItems = [];
}
_buildList(data) {
this._clearList();
data.forEach((option) => {
this._buildItem(option);
});
if (!this.displayItems.length) this._addPlaceholder(this.params.placeholderEmpty);
}
_buildItem(item) {
var el = item.element, contents;
if (!this.filtered || item.visible) {
if (!el) {
el = document.createElement("div");
el.tabIndex = 0;
contents = this.params.itemFormatter ? this.params.itemFormatter(item.label, item.value, item.original, el) : item.label;
if (contents instanceof HTMLElement) el.appendChild(contents);
else el.innerHTML = contents;
if (item.group) el.classList.add("tabulator-edit-list-group");
else el.classList.add("tabulator-edit-list-item");
el.classList.add("tabulator-edit-list-group-level-" + item.level);
if (item.elementAttributes && typeof item.elementAttributes == "object") for (let key in item.elementAttributes) if (key.charAt(0) == "+") {
key = key.slice(1);
el.setAttribute(key, this.input.getAttribute(key) + item.elementAttributes["+" + key]);
} else el.setAttribute(key, item.elementAttributes[key]);
if (item.group) el.addEventListener("click", this._groupClick.bind(this, item));
else el.addEventListener("click", this._itemClick.bind(this, item));
el.addEventListener("mousedown", this._preventBlur.bind(this));
item.element = el;
}
this._styleItem(item);
this.listEl.appendChild(el);
if (item.group) item.options.forEach((option) => {
this._buildItem(option);
});
else this.displayItems.push(item);
}
}
_showList() {
var startVis = this.popup && this.popup.isVisible();
if (this.input.parentNode) {
if (this.params.autocomplete && this.input.value === "" && !this.params.listOnEmpty) {
if (this.popup) this.popup.hide(true);
return;
}
this._setListWidth();
if (!this.popup) this.popup = this.edit.popup(this.listEl);
this.popup.show(this.cell.getElement(), "bottom");
if (!startVis) setTimeout(() => {
this.popup.hideOnBlur(this._resolveValue.bind(this, true));
}, 10);
}
}
_styleItem(item) {
if (item && item.element) if (item.selected) item.element.classList.add("active");
else item.element.classList.remove("active");
}
_itemClick(item, e) {
e.stopPropagation();
this._chooseItem(item);
}
_groupClick(item, e) {
e.stopPropagation();
}
_cancel() {
this.popup.hide(true);
this.actions.cancel();
}
_clearChoices() {
this.typing = true;
this.currentItems.forEach((item) => {
item.selected = false;
this._styleItem(item);
});
this.currentItems = [];
this.focusedItem = null;
}
_chooseItem(item, silent) {
var index;
this.typing = false;
if (this.params.multiselect) {
index = this.currentItems.indexOf(item);
if (index > -1) {
this.currentItems.splice(index, 1);
item.selected = false;
} else {
this.currentItems.push(item);
item.selected = true;
}
this.input.value = this.currentItems.map((item) => item.label).join(",");
this._styleItem(item);
} else {
this.currentItems = [item];
item.selected = true;
this.input.value = item.label;
this._styleItem(item);
if (!silent) this._resolveValue();
}
this._focusItem(item);
}
_resolveValue(blur) {
var output, initialValue;
if (this.popup) this.popup.hide(true);
if (this.params.multiselect) output = this.currentItems.map((item) => item.value);
else if (blur && this.params.autocomplete && this.typing) if (this.params.freetext || this.params.allowEmpty && this.input.value === "") output = this.input.value;
else {
this.actions.cancel();
return;
}
else if (this.currentItems[0]) output = this.currentItems[0].value;
else {
initialValue = Array.isArray(this.initialValues) ? this.initialValues[0] : this.initialValues;
if (initialValue === null || typeof initialValue === "undefined" || initialValue === "") output = initialValue;
else output = this.params.emptyValue;
}
if (output === "") output = this.params.emptyValue;
this.actions.success(output);
if (this.isFilter) {
this.initialValues = output && !Array.isArray(output) ? [output] : output;
this.currentItems = [];
}
}
};
function list(cell, onRendered, success, cancel, editorParams) {
return new Edit$1(this, cell, onRendered, success, cancel, editorParams).input;
}
function star$1(cell, onRendered, success, cancel, editorParams) {
var self = this, element = cell.getElement(), value = cell.getValue(), maxStars = element.getElementsByTagName("svg").length || 5, size = element.getElementsByTagName("svg")[0] ? element.getElementsByTagName("svg")[0].getAttribute("width") : 14, stars = [], starsHolder = document.createElement("div"), star = document.createElementNS("http://www.w3.org/2000/svg", "svg");
function starChange(val) {
stars.forEach(function(star, i) {
if (i < val) {
if (self.table.browser == "ie") star.setAttribute("class", "tabulator-star-active");
else star.classList.replace("tabulator-star-inactive", "tabulator-star-active");
star.innerHTML = "<polygon fill=\"#488CE9\" stroke=\"#014AAE\" stroke-width=\"37.6152\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-miterlimit=\"10\" points=\"259.216,29.942 330.27,173.919 489.16,197.007 374.185,309.08 401.33,467.31 259.216,392.612 117.104,467.31 144.25,309.08 29.274,197.007 188.165,173.919 \"/>";
} else {
if (self.table.browser == "ie") star.setAttribute("class", "tabulator-star-inactive");
else star.classList.replace("tabulator-star-active", "tabulator-star-inactive");
star.innerHTML = "<polygon fill=\"#010155\" stroke=\"#686868\" stroke-width=\"37.6152\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-miterlimit=\"10\" points=\"259.216,29.942 330.27,173.919 489.16,197.007 374.185,309.08 401.33,467.31 259.216,392.612 117.104,467.31 144.25,309.08 29.274,197.007 188.165,173.919 \"/>";
}
});
}
function buildStar(i) {
var starHolder = document.createElement("span");
var nextStar = star.cloneNode(true);
stars.push(nextStar);
starHolder.addEventListener("mouseenter", function(e) {
e.stopPropagation();
e.stopImmediatePropagation();
starChange(i);
});
starHolder.addEventListener("mousemove", function(e) {
e.stopPropagation();
e.stopImmediatePropagation();
});
starHolder.addEventListener("click", function(e) {
e.stopPropagation();
e.stopImmediatePropagation();
success(i);
element.blur();
});
starHolder.appendChild(nextStar);
starsHolder.appendChild(starHolder);
}
function changeValue(val) {
value = val;
starChange(val);
}
element.style.whiteSpace = "nowrap";
element.style.overflow = "hidden";
element.style.textOverflow = "ellipsis";
starsHolder.style.verticalAlign = "middle";
starsHolder.style.display = "inline-block";
starsHolder.style.padding = "4px";
star.setAttribute("width", size);
star.setAttribute("height", size);
star.setAttribute("viewBox", "0 0 512 512");
star.setAttribute("xml:space", "preserve");
star.style.padding = "0 1px";
if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
key = key.slice(1);
starsHolder.setAttribute(key, starsHolder.getAttribute(key) + editorParams.elementAttributes["+" + key]);
} else starsHolder.setAttribute(key, editorParams.elementAttributes[key]);
for (var i = 1; i <= maxStars; i++) buildStar(i);
value = Math.min(parseInt(value), maxStars);
starChange(value);
starsHolder.addEventListener("mousemove", function(e) {
starChange(0);
});
starsHolder.addEventListener("click", function(e) {
success(0);
});
element.addEventListener("blur", function(e) {
cancel();
});
element.addEventListener("keydown", function(e) {
switch (e.keyCode) {
case 39:
changeValue(value + 1);
break;
case 37:
changeValue(value - 1);
break;
case 13:
success(value);
break;
case 27:
cancel();
break;
}
});
return starsHolder;
}
function progress$1(cell, onRendered, success, cancel, editorParams) {
var element = cell.getElement(), max = typeof editorParams.max === "undefined" ? element.getElementsByTagName("div")[0] && element.getElementsByTagName("div")[0].getAttribute("max") || 100 : editorParams.max, min = typeof editorParams.min === "undefined" ? element.getElementsByTagName("div")[0] && element.getElementsByTagName("div")[0].getAttribute("min") || 0 : editorParams.min, percent = (max - min) / 100, value = cell.getValue() || 0, handle = document.createElement("div"), bar = document.createElement("div"), mouseDrag, mouseDragWidth;
function updateValue() {
var style = window.getComputedStyle(element, null);
var calcVal = percent * Math.round(bar.offsetWidth / ((element.clientWidth - parseInt(style.getPropertyValue("padding-left")) - parseInt(style.getPropertyValue("padding-right"))) / 100)) + min;
success(calcVal);
element.setAttribute("aria-valuenow", calcVal);
element.setAttribute("aria-label", value);
}
handle.style.position = "absolute";
handle.style.right = "0";
handle.style.top = "0";
handle.style.bottom = "0";
handle.style.width = "5px";
handle.classList.add("tabulator-progress-handle");
bar.style.display = "inline-block";
bar.style.position = "relative";
bar.style.height = "100%";
bar.style.backgroundColor = "#488CE9";
bar.style.maxWidth = "100%";
bar.style.minWidth = "0%";
if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
key = key.slice(1);
bar.setAttribute(key, bar.getAttribute(key) + editorParams.elementAttributes["+" + key]);
} else bar.setAttribute(key, editorParams.elementAttributes[key]);
element.style.padding = "4px 4px";
value = Math.min(parseFloat(value), max);
value = Math.max(parseFloat(value), min);
value = Math.round((value - min) / percent);
bar.style.width = value + "%";
element.setAttribute("aria-valuemin", min);
element.setAttribute("aria-valuemax", max);
bar.appendChild(handle);
handle.addEventListener("mousedown", function(e) {
mouseDrag = e.screenX;
mouseDragWidth = bar.offsetWidth;
});
handle.addEventListener("mouseover", function() {
handle.style.cursor = "ew-resize";
});
element.addEventListener("mousemove", function(e) {
if (mouseDrag) bar.style.width = mouseDragWidth + e.screenX - mouseDrag + "px";
});
element.addEventListener("mouseup", function(e) {
if (mouseDrag) {
e.stopPropagation();
e.stopImmediatePropagation();
mouseDrag = false;
mouseDragWidth = false;
updateValue();
}
});
element.addEventListener("keydown", function(e) {
switch (e.keyCode) {
case 39:
e.preventDefault();
bar.style.width = bar.clientWidth + element.clientWidth / 100 + "px";
break;
case 37:
e.preventDefault();
bar.style.width = bar.clientWidth - element.clientWidth / 100 + "px";
break;
case 9:
case 13:
updateValue();
break;
case 27:
cancel();
break;
}
});
element.addEventListener("blur", function() {
cancel();
});
return bar;
}
function tickCross$1(cell, onRendered, success, cancel, editorParams) {
var value = cell.getValue(), input = document.createElement("input"), tristate = editorParams.tristate, indetermValue = typeof editorParams.indeterminateValue === "undefined" ? null : editorParams.indeterminateValue, indetermState = false, trueValueSet = Object.keys(editorParams).includes("trueValue"), falseValueSet = Object.keys(editorParams).includes("falseValue");
input.setAttribute("type", "checkbox");
input.style.marginTop = "5px";
input.style.boxSizing = "border-box";
if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
key = key.slice(1);
input.setAttribute(key, input.getAttribute(key) + editorParams.elementAttributes["+" + key]);
} else input.setAttribute(key, editorParams.elementAttributes[key]);
input.value = value;
if (tristate && (typeof value === "undefined" || value === indetermValue || value === "")) {
indetermState = true;
input.indeterminate = true;
}
if (this.table.browser != "firefox" && this.table.browser != "safari") onRendered(function() {
if (cell.getType() === "cell") input.focus({ preventScroll: true });
});
input.checked = trueValueSet ? value === editorParams.trueValue : value === true || value === "true" || value === "True" || value === 1;
function setValue(blur) {
var checkedValue = input.checked;
if (trueValueSet && checkedValue) checkedValue = editorParams.trueValue;
else if (falseValueSet && !checkedValue) checkedValue = editorParams.falseValue;
if (tristate) if (!blur) if (input.checked && !indetermState) {
input.checked = false;
input.indeterminate = true;
indetermState = true;
return indetermValue;
} else {
indetermState = false;
return checkedValue;
}
else if (indetermState) return indetermValue;
else return checkedValue;
else return checkedValue;
}
input.addEventListener("change", function(e) {
success(setValue());
});
input.addEventListener("blur", function(e) {
success(setValue(true));
});
input.addEventListener("keydown", function(e) {
if (e.keyCode == 13) success(setValue());
if (e.keyCode == 27) cancel();
});
return input;
}
function adaptable$1(cell, onRendered, success, cancel, params) {
var column = cell._getSelf().column, lookup, editorFunc, editorParams;
function defaultLookup(cell) {
var value = cell.getValue(), editor = "input";
switch (typeof value) {
case "number":
editor = "number";
break;
case "boolean":
editor = "tickCross";
break;
case "string":
if (value.includes("\n")) editor = "textarea";
break;
}
return editor;
}
lookup = params.editorLookup ? params.editorLookup(cell) : defaultLookup(cell);
if (params.paramsLookup) editorParams = typeof params.paramsLookup === "function" ? params.paramsLookup(lookup, cell) : params.paramsLookup[lookup];
editorFunc = this.table.modules.edit.lookupEditor(lookup, column);
return editorFunc.call(this, cell, onRendered, success, cancel, editorParams || {});
}
var defaultEditors = {
input,
textarea: textarea$1,
number: number$1,
range,
date: date$1,
time: time$1,
datetime: datetime$2,
list,
star: star$1,
progress: progress$1,
tickCross: tickCross$1,
adaptable: adaptable$1
};
var Edit = class Edit extends Module {
static moduleName = "edit";
static editors = defaultEditors;
constructor(table) {
super(table);
this.currentCell = false;
this.mouseClick = false;
this.recursionBlock = false;
this.invalidEdit = false;
this.editedCells = [];
this.convertEmptyValues = false;
this.editors = Edit.editors;
this.registerTableOption("editTriggerEvent", "focus");
this.registerTableOption("editorEmptyValue");
this.registerTableOption("editorEmptyValueFunc", this.emptyValueCheck.bind(this));
this.registerColumnOption("editable");
this.registerColumnOption("editor");
this.registerColumnOption("editorParams");
this.registerColumnOption("editorEmptyValue");
this.registerColumnOption("editorEmptyValueFunc");
this.registerColumnOption("cellEditing");
this.registerColumnOption("cellEdited");
this.registerColumnOption("cellEditCancelled");
this.registerTableFunction("getEditedCells", this.getEditedCells.bind(this));
this.registerTableFunction("clearCellEdited", this.clearCellEdited.bind(this));
this.registerTableFunction("navigatePrev", this.navigatePrev.bind(this));
this.registerTableFunction("navigateNext", this.navigateNext.bind(this));
this.registerTableFunction("navigateLeft", this.navigateLeft.bind(this));
this.registerTableFunction("navigateRight", this.navigateRight.bind(this));
this.registerTableFunction("navigateUp", this.navigateUp.bind(this));
this.registerTableFunction("navigateDown", this.navigateDown.bind(this));
this.registerComponentFunction("cell", "isEdited", this.cellIsEdited.bind(this));
this.registerComponentFunction("cell", "clearEdited", this.clearEdited.bind(this));
this.registerComponentFunction("cell", "edit", this.editCell.bind(this));
this.registerComponentFunction("cell", "cancelEdit", this.cellCancelEdit.bind(this));
this.registerComponentFunction("cell", "navigatePrev", this.navigatePrev.bind(this));
this.registerComponentFunction("cell", "navigateNext", this.navigateNext.bind(this));
this.registerComponentFunction("cell", "navigateLeft", this.navigateLeft.bind(this));
this.registerComponentFunction("cell", "navigateRight", this.navigateRight.bind(this));
this.registerComponentFunction("cell", "navigateUp", this.navigateUp.bind(this));
this.registerComponentFunction("cell", "navigateDown", this.navigateDown.bind(this));
}
initialize() {
this.subscribe("cell-init", this.bindEditor.bind(this));
this.subscribe("cell-delete", this.clearEdited.bind(this));
this.subscribe("cell-value-changed", this.updateCellClass.bind(this));
this.subscribe("column-layout", this.initializeColumnCheck.bind(this));
this.subscribe("column-delete", this.columnDeleteCheck.bind(this));
this.subscribe("row-deleting", this.rowDeleteCheck.bind(this));
this.subscribe("row-layout", this.rowEditableCheck.bind(this));
this.subscribe("data-refreshing", this.cancelEdit.bind(this));
this.subscribe("clipboard-paste", this.pasteBlocker.bind(this));
this.subscribe("keybinding-nav-prev", this.navigatePrev.bind(this, void 0));
this.subscribe("keybinding-nav-next", this.keybindingNavigateNext.bind(this));
this.subscribe("keybinding-nav-up", this.navigateUp.bind(this, void 0));
this.subscribe("keybinding-nav-down", this.navigateDown.bind(this, void 0));
if (Object.keys(this.table.options).includes("editorEmptyValue")) this.convertEmptyValues = true;
}
pasteBlocker(e) {
if (this.currentCell) return true;
}
keybindingNavigateNext(e) {
var cell = this.currentCell, newRow = this.options("tabEndNewRow");
if (cell) {
if (!this.navigateNext(cell, e)) {
if (newRow) {
cell.getElement().firstChild.blur();
if (!this.invalidEdit) {
if (newRow === true) newRow = this.table.addRow({});
else if (typeof newRow == "function") newRow = this.table.addRow(newRow(cell.row.getComponent()));
else newRow = this.table.addRow(Object.assign({}, newRow));
newRow.then(() => {
setTimeout(() => {
cell.getComponent().navigateNext();
});
});
}
}
}
}
}
cellIsEdited(cell) {
return !!cell.modules.edit && cell.modules.edit.edited;
}
cellCancelEdit(cell) {
if (cell === this.currentCell) this.table.modules.edit.cancelEdit();
else console.warn("Cancel Editor Error - This cell is not currently being edited ");
}
updateCellClass(cell) {
if (this.allowEdit(cell)) cell.getElement().classList.add("tabulator-editable");
else cell.getElement().classList.remove("tabulator-editable");
}
clearCellEdited(cells) {
if (!cells) cells = this.table.modules.edit.getEditedCells();
if (!Array.isArray(cells)) cells = [cells];
cells.forEach((cell) => {
this.table.modules.edit.clearEdited(cell._getSelf());
});
}
navigatePrev(cell = this.currentCell, e) {
var nextCell, prevRow;
if (cell) {
if (e) e.preventDefault();
nextCell = this.navigateLeft();
if (nextCell) return true;
else {
prevRow = this.table.rowManager.prevDisplayRow(cell.row, true);
if (prevRow) {
nextCell = this.findPrevEditableCell(prevRow, prevRow.cells.length);
if (nextCell) {
nextCell.getComponent().edit();
return true;
}
}
}
}
return false;
}
navigateNext(cell = this.currentCell, e) {
var nextCell, nextRow;
if (cell) {
if (e) e.preventDefault();
nextCell = this.navigateRight();
if (nextCell) return true;
else {
nextRow = this.table.rowManager.nextDisplayRow(cell.row, true);
if (nextRow) {
nextCell = this.findNextEditableCell(nextRow, -1);
if (nextCell) {
nextCell.getComponent().edit();
return true;
}
}
}
}
return false;
}
navigateLeft(cell = this.currentCell, e) {
var index, nextCell;
if (cell) {
if (e) e.preventDefault();
index = cell.getIndex();
nextCell = this.findPrevEditableCell(cell.row, index);
if (nextCell) {
nextCell.getComponent().edit();
return true;
}
}
return false;
}
navigateRight(cell = this.currentCell, e) {
var index, nextCell;
if (cell) {
if (e) e.preventDefault();
index = cell.getIndex();
nextCell = this.findNextEditableCell(cell.row, index);
if (nextCell) {
nextCell.getComponent().edit();
return true;
}
}
return false;
}
navigateUp(cell = this.currentCell, e) {
var index, nextRow;
if (cell) {
if (e) e.preventDefault();
index = cell.getIndex();
nextRow = this.table.rowManager.prevDisplayRow(cell.row, true);
if (nextRow) {
nextRow.cells[index].getComponent().edit();
return true;
}
}
return false;
}
navigateDown(cell = this.currentCell, e) {
var index, nextRow;
if (cell) {
if (e) e.preventDefault();
index = cell.getIndex();
nextRow = this.table.rowManager.nextDisplayRow(cell.row, true);
if (nextRow) {
nextRow.cells[index].getComponent().edit();
return true;
}
}
return false;
}
findNextEditableCell(row, index) {
var nextCell = false;
if (index < row.cells.length - 1) for (var i = index + 1; i < row.cells.length; i++) {
let cell = row.cells[i];
if (cell.column.modules.edit && Helpers.elVisible(cell.getElement())) {
if (this.allowEdit(cell)) {
nextCell = cell;
break;
}
}
}
return nextCell;
}
findPrevEditableCell(row, index) {
var prevCell = false;
if (index > 0) for (var i = index - 1; i >= 0; i--) {
let cell = row.cells[i];
if (cell.column.modules.edit && Helpers.elVisible(cell.getElement())) {
if (this.allowEdit(cell)) {
prevCell = cell;
break;
}
}
}
return prevCell;
}
initializeColumnCheck(column) {
if (typeof column.definition.editor !== "undefined") this.initializeColumn(column);
}
columnDeleteCheck(column) {
if (this.currentCell && this.currentCell.column === column) this.cancelEdit();
}
rowDeleteCheck(row) {
if (this.currentCell && this.currentCell.row === row) this.cancelEdit();
}
rowEditableCheck(row) {
row.getCells().forEach((cell) => {
if (cell.column.modules.edit && typeof cell.column.modules.edit.check === "function") this.updateCellClass(cell);
});
}
initializeColumn(column) {
var convertEmpty = Object.keys(column.definition).includes("editorEmptyValue");
var config = {
editor: false,
blocked: false,
check: column.definition.editable,
params: column.definition.editorParams || {},
convertEmptyValues: convertEmpty,
editorEmptyValue: column.definition.editorEmptyValue,
editorEmptyValueFunc: column.definition.editorEmptyValueFunc
};
config.editor = this.lookupEditor(column.definition.editor, column);
if (config.editor) column.modules.edit = config;
}
lookupEditor(editor, column) {
var editorFunc;
switch (typeof editor) {
case "string":
if (this.editors[editor]) editorFunc = this.editors[editor];
else console.warn("Editor Error - No such editor found: ", editor);
break;
case "function":
editorFunc = editor;
break;
case "boolean":
if (editor === true) if (typeof column.definition.formatter !== "function") if (this.editors[column.definition.formatter]) editorFunc = this.editors[column.definition.formatter];
else editorFunc = this.editors["input"];
else console.warn("Editor Error - Cannot auto lookup editor for a custom formatter: ", column.definition.formatter);
break;
}
return editorFunc;
}
getCurrentCell() {
return this.currentCell ? this.currentCell.getComponent() : false;
}
clearEditor(cancel) {
var cell = this.currentCell, cellEl;
this.invalidEdit = false;
if (cell) {
this.currentCell = false;
cellEl = cell.getElement();
this.dispatch("edit-editor-clear", cell, cancel);
cellEl.classList.remove("tabulator-editing");
while (cellEl.firstChild) cellEl.removeChild(cellEl.firstChild);
cell.row.getElement().classList.remove("tabulator-editing");
cell.table.element.classList.remove("tabulator-editing");
}
}
cancelEdit() {
if (this.currentCell) {
var cell = this.currentCell;
var component = this.currentCell.getComponent();
this.clearEditor(true);
cell.setValueActual(cell.getValue());
cell.cellRendered();
if (cell.column.definition.editor == "textarea" || cell.column.definition.variableHeight) cell.row.normalizeHeight(true);
if (cell.column.definition.cellEditCancelled) cell.column.definition.cellEditCancelled.call(this.table, component);
this.dispatch("edit-cancelled", cell);
this.dispatchExternal("cellEditCancelled", component);
}
}
bindEditor(cell) {
if (cell.column.modules.edit) {
var self = this, element = cell.getElement(true);
this.updateCellClass(cell);
element.setAttribute("tabindex", 0);
element.addEventListener("mousedown", function(e) {
if (e.button === 2) e.preventDefault();
else self.mouseClick = true;
});
if (this.options("editTriggerEvent") === "dblclick") element.addEventListener("dblclick", function(e) {
if (!element.classList.contains("tabulator-editing")) {
element.focus({ preventScroll: true });
self.edit(cell, e, false);
}
});
if (this.options("editTriggerEvent") === "focus" || this.options("editTriggerEvent") === "click") element.addEventListener("click", function(e) {
if (!element.classList.contains("tabulator-editing")) {
element.focus({ preventScroll: true });
self.edit(cell, e, false);
}
});
if (this.options("editTriggerEvent") === "focus") element.addEventListener("focus", function(e) {
if (!self.recursionBlock) self.edit(cell, e, false);
});
}
}
focusCellNoEvent(cell, block) {
this.recursionBlock = true;
if (!(block && this.table.browser === "ie")) cell.getElement().focus({ preventScroll: true });
this.recursionBlock = false;
}
editCell(cell, forceEdit) {
this.focusCellNoEvent(cell);
this.edit(cell, false, forceEdit);
}
focusScrollAdjust(cell) {
if (this.table.rowManager.getRenderMode() == "virtual") {
var topEdge = this.table.rowManager.element.scrollTop, bottomEdge = this.table.rowManager.element.clientHeight + this.table.rowManager.element.scrollTop, rowEl = cell.row.getElement();
if (rowEl.offsetTop < topEdge) this.table.rowManager.element.scrollTop -= topEdge - rowEl.offsetTop;
else if (rowEl.offsetTop + rowEl.offsetHeight > bottomEdge) this.table.rowManager.element.scrollTop += rowEl.offsetTop + rowEl.offsetHeight - bottomEdge;
var leftEdge = this.table.rowManager.element.scrollLeft, rightEdge = this.table.rowManager.element.clientWidth + this.table.rowManager.element.scrollLeft, cellEl = cell.getElement();
if (this.table.modExists("frozenColumns")) {
leftEdge += parseInt(this.table.modules.frozenColumns.leftMargin || 0);
rightEdge -= parseInt(this.table.modules.frozenColumns.rightMargin || 0);
}
if (this.table.options.renderHorizontal === "virtual") {
leftEdge -= parseInt(this.table.columnManager.renderer.vDomPadLeft);
rightEdge -= parseInt(this.table.columnManager.renderer.vDomPadLeft);
}
if (cellEl.offsetLeft < leftEdge) this.table.rowManager.element.scrollLeft -= leftEdge - cellEl.offsetLeft;
else if (cellEl.offsetLeft + cellEl.offsetWidth > rightEdge) this.table.rowManager.element.scrollLeft += cellEl.offsetLeft + cellEl.offsetWidth - rightEdge;
}
}
allowEdit(cell) {
var check = cell.column.modules.edit ? true : false;
if (cell.column.modules.edit) switch (typeof cell.column.modules.edit.check) {
case "function":
if (cell.row.initialized) check = cell.column.modules.edit.check(cell.getComponent());
break;
case "string":
check = !!cell.row.data[cell.column.modules.edit.check];
break;
case "boolean":
check = cell.column.modules.edit.check;
break;
}
return check;
}
edit(cell, e, forceEdit) {
var self = this, allowEdit = true, rendered = function() {}, element = cell.getElement(), editFinished = false, cellEditor, component, params;
if (this.currentCell) {
if (!this.invalidEdit && this.currentCell !== cell) this.cancelEdit();
return;
}
function success(value) {
if (self.currentCell === cell && !editFinished) {
var valid = self.chain("edit-success", [cell, value], true, true);
if (valid === true || self.table.options.validationMode === "highlight") {
editFinished = true;
self.clearEditor();
if (!cell.modules.edit) cell.modules.edit = {};
cell.modules.edit.edited = true;
if (self.editedCells.indexOf(cell) == -1) self.editedCells.push(cell);
value = self.transformEmptyValues(value, cell);
cell.setValue(value, true);
return valid === true;
} else {
editFinished = true;
self.invalidEdit = true;
self.focusCellNoEvent(cell, true);
rendered();
setTimeout(() => {
editFinished = false;
}, 10);
return false;
}
}
}
function cancel() {
if (self.currentCell === cell && !editFinished) self.cancelEdit();
}
function onRendered(callback) {
rendered = callback;
}
if (!cell.column.modules.edit.blocked) {
if (e) e.stopPropagation();
allowEdit = this.allowEdit(cell);
if (allowEdit || forceEdit) {
self.cancelEdit();
self.currentCell = cell;
this.focusScrollAdjust(cell);
component = cell.getComponent();
if (this.mouseClick) {
this.mouseClick = false;
if (cell.column.definition.cellClick) cell.column.definition.cellClick.call(this.table, e, component);
}
if (cell.column.definition.cellEditing) cell.column.definition.cellEditing.call(this.table, component);
this.dispatch("cell-editing", cell);
this.dispatchExternal("cellEditing", component);
params = typeof cell.column.modules.edit.params === "function" ? cell.column.modules.edit.params(component) : cell.column.modules.edit.params;
cellEditor = cell.column.modules.edit.editor.call(self, component, onRendered, success, cancel, params);
if (this.currentCell && cellEditor !== false) if (cellEditor instanceof Node) {
element.classList.add("tabulator-editing");
cell.row.getElement().classList.add("tabulator-editing");
cell.table.element.classList.add("tabulator-editing");
while (element.firstChild) element.removeChild(element.firstChild);
element.appendChild(cellEditor);
rendered();
var children = element.children;
for (var i = 0; i < children.length; i++) children[i].addEventListener("click", function(e) {
e.stopPropagation();
});
} else {
console.warn("Edit Error - Editor should return an instance of Node, the editor returned:", cellEditor);
this.blur(element);
return false;
}
else {
this.blur(element);
return false;
}
return true;
} else {
this.mouseClick = false;
this.blur(element);
return false;
}
} else {
this.mouseClick = false;
this.blur(element);
return false;
}
}
emptyValueCheck(value) {
return value === "" || value === null || typeof value === "undefined";
}
transformEmptyValues(value, cell) {
var mod = cell.column.modules.edit, convert = mod.convertEmptyValues || this.convertEmptyValues, checkFunc;
if (convert) {
checkFunc = mod.editorEmptyValueFunc || this.options("editorEmptyValueFunc");
if (checkFunc && checkFunc(value)) value = mod.convertEmptyValues ? mod.editorEmptyValue : this.options("editorEmptyValue");
}
return value;
}
blur(element) {
if (!this.confirm("edit-blur", [element])) element.blur();
}
getEditedCells() {
var output = [];
this.editedCells.forEach((cell) => {
output.push(cell.getComponent());
});
return output;
}
clearEdited(cell) {
var editIndex;
if (cell.modules.edit && cell.modules.edit.edited) {
cell.modules.edit.edited = false;
this.dispatch("edit-edited-clear", cell);
}
editIndex = this.editedCells.indexOf(cell);
if (editIndex > -1) this.editedCells.splice(editIndex, 1);
}
};
var ExportRow = class {
constructor(type, columns, component, indent) {
this.type = type;
this.columns = columns;
this.component = component || false;
this.indent = indent || 0;
}
};
var ExportColumn = class {
constructor(value, component, width, height, depth) {
this.value = value;
this.component = component || false;
this.width = width;
this.height = height;
this.depth = depth;
}
};
var columnLookups$1 = {};
var rowLookups$1 = {
visible: function() {
return this.rowManager.getVisibleRows(false, true);
},
all: function() {
return this.rowManager.rows;
},
selected: function() {
return this.modules.selectRow.selectedRows;
},
active: function() {
if (this.options.pagination) return this.rowManager.getDisplayRows(this.rowManager.displayRows.length - 2);
else return this.rowManager.getDisplayRows();
}
};
var Export = class Export extends Module {
static moduleName = "export";
static columnLookups = columnLookups$1;
static rowLookups = rowLookups$1;
constructor(table) {
super(table);
this.config = {};
this.cloneTableStyle = true;
this.colVisProp = "";
this.colVisPropAttach = "";
this.registerTableOption("htmlOutputConfig", false);
this.registerColumnOption("htmlOutput");
this.registerColumnOption("titleHtmlOutput");
}
initialize() {
this.registerTableFunction("getHtml", this.getHtml.bind(this));
}
generateExportList(config, style, range, colVisProp) {
var headers, body, columns, colLookup;
this.cloneTableStyle = style;
this.config = config || {};
this.colVisProp = colVisProp;
this.colVisPropAttach = this.colVisProp.charAt(0).toUpperCase() + this.colVisProp.slice(1);
colLookup = Export.columnLookups[range];
if (colLookup) {
columns = colLookup.call(this.table);
columns = columns.filter((col) => this.columnVisCheck(col));
}
headers = this.config.columnHeaders !== false ? this.headersToExportRows(this.generateColumnGroupHeaders(columns)) : [];
if (columns) columns = columns.map((col) => col.getComponent());
body = this.bodyToExportRows(this.rowLookup(range), columns);
return headers.concat(body);
}
generateTable(config, style, range, colVisProp) {
var list = this.generateExportList(config, style, range, colVisProp);
return this.generateTableElement(list);
}
rowLookup(range) {
var rows = [], rowLookup;
if (typeof range == "function") range.call(this.table).forEach((row) => {
row = this.table.rowManager.findRow(row);
if (row) rows.push(row);
});
else {
rowLookup = Export.rowLookups[range] || Export.rowLookups["active"];
rows = rowLookup.call(this.table);
}
return Object.assign([], rows);
}
generateColumnGroupHeaders(columns) {
var output = [];
if (!columns) columns = this.config.columnGroups !== false ? this.table.columnManager.columns : this.table.columnManager.columnsByIndex;
columns.forEach((column) => {
var colData = this.processColumnGroup(column);
if (colData) output.push(colData);
});
return output;
}
processColumnGroup(column) {
var subGroups = column.columns, maxDepth = 0;
var groupData = {
title: column.definition["title" + this.colVisPropAttach] || column.definition.title,
column,
depth: 1
};
if (subGroups.length) {
groupData.subGroups = [];
groupData.width = 0;
subGroups.forEach((subGroup) => {
var subGroupData = this.processColumnGroup(subGroup);
if (subGroupData) {
groupData.width += subGroupData.width;
groupData.subGroups.push(subGroupData);
if (subGroupData.depth > maxDepth) maxDepth = subGroupData.depth;
}
});
groupData.depth += maxDepth;
if (!groupData.width) return false;
} else if (this.columnVisCheck(column)) groupData.width = 1;
else return false;
return groupData;
}
columnVisCheck(column) {
var visProp = column.definition[this.colVisProp];
if (this.config.rowHeaders === false && column.isRowHeader) return false;
if (typeof visProp === "function") visProp = visProp.call(this.table, column.getComponent());
if (visProp === false || visProp === true) return visProp;
return column.visible && column.field;
}
headersToExportRows(columns) {
var headers = [], headerDepth = 0, exportRows = [];
function parseColumnGroup(column, level) {
var depth = headerDepth - level;
if (typeof headers[level] === "undefined") headers[level] = [];
column.height = column.subGroups ? 1 : depth - column.depth + 1;
headers[level].push(column);
if (column.height > 1) for (let i = 1; i < column.height; i++) {
if (typeof headers[level + i] === "undefined") headers[level + i] = [];
headers[level + i].push(false);
}
if (column.width > 1) for (let i = 1; i < column.width; i++) headers[level].push(false);
if (column.subGroups) column.subGroups.forEach(function(subGroup) {
parseColumnGroup(subGroup, level + 1);
});
}
columns.forEach(function(column) {
if (column.depth > headerDepth) headerDepth = column.depth;
});
columns.forEach(function(column) {
parseColumnGroup(column, 0);
});
headers.forEach((header) => {
var columns = [];
header.forEach((col) => {
if (col) {
let title = typeof col.title === "undefined" ? "" : col.title;
columns.push(new ExportColumn(title, col.column.getComponent(), col.width, col.height, col.depth));
} else columns.push(null);
});
exportRows.push(new ExportRow("header", columns));
});
return exportRows;
}
bodyToExportRows(rows, columns = []) {
var exportRows = [];
if (columns.length === 0) this.table.columnManager.columnsByIndex.forEach((column) => {
if (this.columnVisCheck(column)) columns.push(column.getComponent());
});
if (this.config.columnCalcs !== false && this.table.modExists("columnCalcs")) {
if (this.table.modules.columnCalcs.topInitialized) rows.unshift(this.table.modules.columnCalcs.topRow);
if (this.table.modules.columnCalcs.botInitialized) rows.push(this.table.modules.columnCalcs.botRow);
}
rows = rows.filter((row) => {
switch (row.type) {
case "group": return this.config.rowGroups !== false;
case "calc": return this.config.columnCalcs !== false;
case "row": return !(this.table.options.dataTree && this.config.dataTree === false && row.modules.dataTree.parent);
}
return true;
});
rows.forEach((row, i) => {
var rowData = row.getData(this.colVisProp);
var exportCols = [];
var indent = 0;
switch (row.type) {
case "group":
indent = row.level;
exportCols.push(new ExportColumn(row.key, row.getComponent(), columns.length, 1));
break;
case "calc":
case "row":
columns.forEach((col) => {
exportCols.push(new ExportColumn(col._column.getFieldValue(rowData), col, 1, 1));
});
if (this.table.options.dataTree && this.config.dataTree !== false) indent = row.modules.dataTree.index;
break;
}
exportRows.push(new ExportRow(row.type, exportCols, row.getComponent(), indent));
});
return exportRows;
}
generateTableElement(list) {
var table = document.createElement("table"), headerEl = document.createElement("thead"), bodyEl = document.createElement("tbody"), styles = this.lookupTableStyles(), rowFormatter = this.table.options["rowFormatter" + this.colVisPropAttach], setup = {};
setup.rowFormatter = rowFormatter !== null ? rowFormatter : this.table.options.rowFormatter;
if (this.table.options.dataTree && this.config.dataTree !== false && this.table.modExists("columnCalcs")) setup.treeElementField = this.table.modules.dataTree.elementField;
setup.groupHeader = this.table.options["groupHeader" + this.colVisPropAttach];
if (setup.groupHeader && !Array.isArray(setup.groupHeader)) setup.groupHeader = [setup.groupHeader];
table.classList.add("tabulator-print-table");
this.mapElementStyles(this.table.columnManager.getHeadersElement(), headerEl, [
"border-top",
"border-left",
"border-right",
"border-bottom",
"background-color",
"color",
"font-weight",
"font-family",
"font-size"
]);
if (list.length > 1e3) console.warn("It may take a long time to render an HTML table with more than 1000 rows");
list.forEach((row, i) => {
let rowEl;
switch (row.type) {
case "header":
headerEl.appendChild(this.generateHeaderElement(row, setup, styles));
break;
case "group":
bodyEl.appendChild(this.generateGroupElement(row, setup, styles));
break;
case "calc":
bodyEl.appendChild(this.generateCalcElement(row, setup, styles));
break;
case "row":
rowEl = this.generateRowElement(row, setup, styles);
this.mapElementStyles(i % 2 && styles.evenRow ? styles.evenRow : styles.oddRow, rowEl, [
"border-top",
"border-left",
"border-right",
"border-bottom",
"color",
"font-weight",
"font-family",
"font-size",
"background-color"
]);
bodyEl.appendChild(rowEl);
break;
}
});
if (headerEl.innerHTML) table.appendChild(headerEl);
table.appendChild(bodyEl);
this.mapElementStyles(this.table.element, table, [
"border-top",
"border-left",
"border-right",
"border-bottom"
]);
return table;
}
lookupTableStyles() {
var styles = {};
if (this.cloneTableStyle && window.getComputedStyle) {
styles.oddRow = this.table.element.querySelector(".tabulator-row-odd:not(.tabulator-group):not(.tabulator-calcs)");
styles.evenRow = this.table.element.querySelector(".tabulator-row-even:not(.tabulator-group):not(.tabulator-calcs)");
styles.calcRow = this.table.element.querySelector(".tabulator-row.tabulator-calcs");
styles.firstRow = this.table.element.querySelector(".tabulator-row:not(.tabulator-group):not(.tabulator-calcs)");
styles.firstGroup = this.table.element.getElementsByClassName("tabulator-group")[0];
if (styles.firstRow) {
styles.styleCells = styles.firstRow.getElementsByClassName("tabulator-cell");
styles.styleRowHeader = styles.firstRow.getElementsByClassName("tabulator-row-header")[0];
styles.firstCell = styles.styleCells[0];
styles.lastCell = styles.styleCells[styles.styleCells.length - 1];
}
}
return styles;
}
generateHeaderElement(row, setup, styles) {
var rowEl = document.createElement("tr");
row.columns.forEach((column) => {
if (column) {
var cellEl = document.createElement("th");
var classNames = column.component._column.definition.cssClass ? column.component._column.definition.cssClass.split(" ") : [];
cellEl.colSpan = column.width;
cellEl.rowSpan = column.height;
cellEl.innerHTML = column.value;
if (this.cloneTableStyle) cellEl.style.boxSizing = "border-box";
classNames.forEach(function(className) {
cellEl.classList.add(className);
});
this.mapElementStyles(column.component.getElement(), cellEl, [
"text-align",
"border-left",
"border-right",
"background-color",
"color",
"font-weight",
"font-family",
"font-size"
]);
this.mapElementStyles(column.component._column.contentElement, cellEl, [
"padding-top",
"padding-left",
"padding-right",
"padding-bottom"
]);
if (column.component._column.visible) this.mapElementStyles(column.component.getElement(), cellEl, ["width"]);
else if (column.component._column.definition.width) cellEl.style.width = column.component._column.definition.width + "px";
if (column.component._column.parent && column.component._column.parent.isGroup) this.mapElementStyles(column.component._column.parent.groupElement, cellEl, ["border-top"]);
else this.mapElementStyles(column.component.getElement(), cellEl, ["border-top"]);
if (column.component._column.isGroup) this.mapElementStyles(column.component.getElement(), cellEl, ["border-bottom"]);
else this.mapElementStyles(this.table.columnManager.getElement(), cellEl, ["border-bottom"]);
rowEl.appendChild(cellEl);
}
});
return rowEl;
}
generateGroupElement(row, setup, styles) {
var rowEl = document.createElement("tr"), cellEl = document.createElement("td"), group = row.columns[0];
rowEl.classList.add("tabulator-print-table-row");
if (setup.groupHeader && setup.groupHeader[row.indent]) group.value = setup.groupHeader[row.indent](group.value, row.component._group.getRowCount(), row.component._group.getData(), row.component);
else if (setup.groupHeader !== false) group.value = row.component._group.generator(group.value, row.component._group.getRowCount(), row.component._group.getData(), row.component);
cellEl.colSpan = group.width;
cellEl.innerHTML = group.value;
rowEl.classList.add("tabulator-print-table-group");
rowEl.classList.add("tabulator-group-level-" + row.indent);
if (group.component.isVisible()) rowEl.classList.add("tabulator-group-visible");
this.mapElementStyles(styles.firstGroup, rowEl, [
"border-top",
"border-left",
"border-right",
"border-bottom",
"color",
"font-weight",
"font-family",
"font-size",
"background-color"
]);
this.mapElementStyles(styles.firstGroup, cellEl, [
"padding-top",
"padding-left",
"padding-right",
"padding-bottom"
]);
rowEl.appendChild(cellEl);
return rowEl;
}
generateCalcElement(row, setup, styles) {
var rowEl = this.generateRowElement(row, setup, styles);
rowEl.classList.add("tabulator-print-table-calcs");
this.mapElementStyles(styles.calcRow, rowEl, [
"border-top",
"border-left",
"border-right",
"border-bottom",
"color",
"font-weight",
"font-family",
"font-size",
"background-color"
]);
return rowEl;
}
generateRowElement(row, setup, styles) {
var rowEl = document.createElement("tr");
rowEl.classList.add("tabulator-print-table-row");
row.columns.forEach((col, i) => {
if (col) {
var cellEl = document.createElement("td"), column = col.component._column, table = this.table, index = table.columnManager.findColumnIndex(column), value = col.value, cellStyle, styleProps;
var cellWrapper = {
modules: {},
getValue: function() {
return value;
},
getField: function() {
return column.definition.field;
},
getElement: function() {
return cellEl;
},
getType: function() {
return "cell";
},
getColumn: function() {
return column.getComponent();
},
getData: function() {
return row.component.getData();
},
getRow: function() {
return row.component;
},
getTable: function() {
return table;
},
getComponent: function() {
return cellWrapper;
},
column
};
(column.definition.cssClass ? column.definition.cssClass.split(" ") : []).forEach(function(className) {
cellEl.classList.add(className);
});
if (this.table.modExists("format") && this.config.formatCells !== false) value = this.table.modules.format.formatExportValue(cellWrapper, this.colVisProp);
else switch (typeof value) {
case "object":
value = value !== null ? JSON.stringify(value) : "";
break;
case "undefined":
value = "";
break;
}
if (value instanceof Node) cellEl.appendChild(value);
else cellEl.innerHTML = value;
styleProps = [
"padding-top",
"padding-left",
"padding-right",
"padding-bottom",
"border-top",
"border-left",
"border-right",
"border-bottom",
"color",
"font-weight",
"font-family",
"font-size",
"text-align"
];
if (column.isRowHeader) {
cellStyle = styles.styleRowHeader;
styleProps.push("background-color");
} else cellStyle = styles.styleCells && styles.styleCells[index] ? styles.styleCells[index] : styles.firstCell;
if (cellStyle) {
this.mapElementStyles(cellStyle, cellEl, styleProps);
if (column.definition.align) cellEl.style.textAlign = column.definition.align;
}
if (this.table.options.dataTree && this.config.dataTree !== false) {
if (setup.treeElementField && setup.treeElementField == column.field || !setup.treeElementField && i == 0) {
if (row.component._row.modules.dataTree.controlEl) cellEl.insertBefore(row.component._row.modules.dataTree.controlEl.cloneNode(true), cellEl.firstChild);
if (row.component._row.modules.dataTree.branchEl) cellEl.insertBefore(row.component._row.modules.dataTree.branchEl.cloneNode(true), cellEl.firstChild);
}
}
rowEl.appendChild(cellEl);
if (cellWrapper.modules.format && cellWrapper.modules.format.renderedCallback) cellWrapper.modules.format.renderedCallback();
}
});
if (setup.rowFormatter && row.type === "row" && this.config.formatCells !== false) {
let formatComponent = Object.assign(row.component);
formatComponent.getElement = function() {
return rowEl;
};
setup.rowFormatter(row.component);
}
return rowEl;
}
generateHTMLTable(list) {
var holder = document.createElement("div");
holder.appendChild(this.generateTableElement(list));
return holder.innerHTML;
}
getHtml(visible, style, config, colVisProp) {
var list = this.generateExportList(config || this.table.options.htmlOutputConfig, style, visible, colVisProp || "htmlOutput");
return this.generateHTMLTable(list);
}
mapElementStyles(from, to, props) {
if (this.cloneTableStyle && from && to) {
var lookup = {
"background-color": "backgroundColor",
"color": "fontColor",
"width": "width",
"font-weight": "fontWeight",
"font-family": "fontFamily",
"font-size": "fontSize",
"text-align": "textAlign",
"border-top": "borderTop",
"border-left": "borderLeft",
"border-right": "borderRight",
"border-bottom": "borderBottom",
"padding-top": "paddingTop",
"padding-left": "paddingLeft",
"padding-right": "paddingRight",
"padding-bottom": "paddingBottom"
};
if (window.getComputedStyle) {
var fromStyle = window.getComputedStyle(from);
props.forEach(function(prop) {
if (!to.style[lookup[prop]]) to.style[lookup[prop]] = fromStyle.getPropertyValue(prop);
});
}
}
}
};
var defaultFilters = {
"=": function(filterVal, rowVal, rowData, filterParams) {
return rowVal == filterVal ? true : false;
},
"<": function(filterVal, rowVal, rowData, filterParams) {
return rowVal < filterVal ? true : false;
},
"<=": function(filterVal, rowVal, rowData, filterParams) {
return rowVal <= filterVal ? true : false;
},
">": function(filterVal, rowVal, rowData, filterParams) {
return rowVal > filterVal ? true : false;
},
">=": function(filterVal, rowVal, rowData, filterParams) {
return rowVal >= filterVal ? true : false;
},
"!=": function(filterVal, rowVal, rowData, filterParams) {
return rowVal != filterVal ? true : false;
},
"regex": function(filterVal, rowVal, rowData, filterParams) {
if (typeof filterVal == "string") filterVal = new RegExp(filterVal);
return filterVal.test(rowVal);
},
"like": function(filterVal, rowVal, rowData, filterParams) {
if (filterVal === null || typeof filterVal === "undefined") return rowVal === filterVal ? true : false;
else if (typeof rowVal !== "undefined" && rowVal !== null) return String(rowVal).toLowerCase().indexOf(filterVal.toLowerCase()) > -1;
else return false;
},
"keywords": function(filterVal, rowVal, rowData, filterParams) {
var keywords = filterVal.toLowerCase().split(typeof filterParams.separator === "undefined" ? " " : filterParams.separator), value = String(rowVal === null || typeof rowVal === "undefined" ? "" : rowVal).toLowerCase(), matches = [];
keywords.forEach((keyword) => {
if (value.includes(keyword)) matches.push(true);
});
return filterParams.matchAll ? matches.length === keywords.length : !!matches.length;
},
"starts": function(filterVal, rowVal, rowData, filterParams) {
if (filterVal === null || typeof filterVal === "undefined") return rowVal === filterVal ? true : false;
else if (typeof rowVal !== "undefined" && rowVal !== null) return String(rowVal).toLowerCase().startsWith(filterVal.toLowerCase());
else return false;
},
"ends": function(filterVal, rowVal, rowData, filterParams) {
if (filterVal === null || typeof filterVal === "undefined") return rowVal === filterVal ? true : false;
else if (typeof rowVal !== "undefined" && rowVal !== null) return String(rowVal).toLowerCase().endsWith(filterVal.toLowerCase());
else return false;
},
"in": function(filterVal, rowVal, rowData, filterParams) {
if (Array.isArray(filterVal)) return filterVal.length ? filterVal.indexOf(rowVal) > -1 : true;
else {
console.warn("Filter Error - filter value is not an array:", filterVal);
return false;
}
}
};
var Filter = class Filter extends Module {
static moduleName = "filter";
static filters = defaultFilters;
constructor(table) {
super(table);
this.filterList = [];
this.headerFilters = {};
this.headerFilterColumns = [];
this.prevHeaderFilterChangeCheck = "";
this.prevHeaderFilterChangeCheck = "{}";
this.changed = false;
this.tableInitialized = false;
this.registerTableOption("filterMode", "local");
this.registerTableOption("initialFilter", false);
this.registerTableOption("initialHeaderFilter", false);
this.registerTableOption("headerFilterLiveFilterDelay", 300);
this.registerTableOption("placeholderHeaderFilter", false);
this.registerColumnOption("headerFilter");
this.registerColumnOption("headerFilterPlaceholder");
this.registerColumnOption("headerFilterParams");
this.registerColumnOption("headerFilterEmptyCheck");
this.registerColumnOption("headerFilterFunc");
this.registerColumnOption("headerFilterFuncParams");
this.registerColumnOption("headerFilterLiveFilter");
this.registerTableFunction("searchRows", this.searchRows.bind(this));
this.registerTableFunction("searchData", this.searchData.bind(this));
this.registerTableFunction("setFilter", this.userSetFilter.bind(this));
this.registerTableFunction("refreshFilter", this.userRefreshFilter.bind(this));
this.registerTableFunction("addFilter", this.userAddFilter.bind(this));
this.registerTableFunction("getFilters", this.getFilters.bind(this));
this.registerTableFunction("setHeaderFilterFocus", this.userSetHeaderFilterFocus.bind(this));
this.registerTableFunction("getHeaderFilterValue", this.userGetHeaderFilterValue.bind(this));
this.registerTableFunction("setHeaderFilterValue", this.userSetHeaderFilterValue.bind(this));
this.registerTableFunction("getHeaderFilters", this.getHeaderFilters.bind(this));
this.registerTableFunction("removeFilter", this.userRemoveFilter.bind(this));
this.registerTableFunction("clearFilter", this.userClearFilter.bind(this));
this.registerTableFunction("clearHeaderFilter", this.userClearHeaderFilter.bind(this));
this.registerComponentFunction("column", "headerFilterFocus", this.setHeaderFilterFocus.bind(this));
this.registerComponentFunction("column", "reloadHeaderFilter", this.reloadHeaderFilter.bind(this));
this.registerComponentFunction("column", "getHeaderFilterValue", this.getHeaderFilterValue.bind(this));
this.registerComponentFunction("column", "setHeaderFilterValue", this.setHeaderFilterValue.bind(this));
}
initialize() {
this.subscribe("column-init", this.initializeColumnHeaderFilter.bind(this));
this.subscribe("column-width-fit-before", this.hideHeaderFilterElements.bind(this));
this.subscribe("column-width-fit-after", this.showHeaderFilterElements.bind(this));
this.subscribe("table-built", this.tableBuilt.bind(this));
this.subscribe("placeholder", this.generatePlaceholder.bind(this));
if (this.table.options.filterMode === "remote") this.subscribe("data-params", this.remoteFilterParams.bind(this));
this.registerDataHandler(this.filter.bind(this), 10);
}
tableBuilt() {
if (this.table.options.initialFilter) this.setFilter(this.table.options.initialFilter);
if (this.table.options.initialHeaderFilter) this.table.options.initialHeaderFilter.forEach((item) => {
var column = this.table.columnManager.findColumn(item.field);
if (column) this.setHeaderFilterValue(column, item.value);
else {
console.warn("Column Filter Error - No matching column found:", item.field);
return false;
}
});
this.tableInitialized = true;
}
remoteFilterParams(data, config, silent, params) {
params.filter = this.getFilters(true, true);
return params;
}
generatePlaceholder(text) {
if (this.table.options.placeholderHeaderFilter && Object.keys(this.headerFilters).length) return this.table.options.placeholderHeaderFilter;
}
userSetFilter(field, type, value, params) {
this.setFilter(field, type, value, params);
this.refreshFilter();
}
userRefreshFilter() {
this.refreshFilter();
}
userAddFilter(field, type, value, params) {
this.addFilter(field, type, value, params);
this.refreshFilter();
}
userSetHeaderFilterFocus(field) {
var column = this.table.columnManager.findColumn(field);
if (column) this.setHeaderFilterFocus(column);
else {
console.warn("Column Filter Focus Error - No matching column found:", field);
return false;
}
}
userGetHeaderFilterValue(field) {
var column = this.table.columnManager.findColumn(field);
if (column) return this.getHeaderFilterValue(column);
else console.warn("Column Filter Error - No matching column found:", field);
}
userSetHeaderFilterValue(field, value) {
var column = this.table.columnManager.findColumn(field);
if (column) this.setHeaderFilterValue(column, value);
else {
console.warn("Column Filter Error - No matching column found:", field);
return false;
}
}
userRemoveFilter(field, type, value) {
this.removeFilter(field, type, value);
this.refreshFilter();
}
userClearFilter(all) {
this.clearFilter(all);
this.refreshFilter();
}
userClearHeaderFilter() {
this.clearHeaderFilter();
this.refreshFilter();
}
searchRows(field, type, value) {
return this.search("rows", field, type, value);
}
searchData(field, type, value) {
return this.search("data", field, type, value);
}
initializeColumnHeaderFilter(column) {
if (column.definition.headerFilter) this.initializeColumn(column);
}
initializeColumn(column, value) {
var self = this, field = column.getField();
function success(value) {
var filterType = column.modules.filter.tagType == "input" && column.modules.filter.attrType == "text" || column.modules.filter.tagType == "textarea" ? "partial" : "match", type = "", filterChangeCheck = "", filterFunc;
if (typeof column.modules.filter.prevSuccess === "undefined" || column.modules.filter.prevSuccess !== value) {
column.modules.filter.prevSuccess = value;
if (!column.modules.filter.emptyFunc(value)) {
column.modules.filter.value = value;
switch (typeof column.definition.headerFilterFunc) {
case "string":
if (Filter.filters[column.definition.headerFilterFunc]) {
type = column.definition.headerFilterFunc;
filterFunc = function(data) {
var params = column.definition.headerFilterFuncParams || {};
var fieldVal = column.getFieldValue(data);
params = typeof params === "function" ? params(value, fieldVal, data) : params;
return Filter.filters[column.definition.headerFilterFunc](value, fieldVal, data, params);
};
} else console.warn("Header Filter Error - Matching filter function not found: ", column.definition.headerFilterFunc);
break;
case "function":
filterFunc = function(data) {
var params = column.definition.headerFilterFuncParams || {};
var fieldVal = column.getFieldValue(data);
params = typeof params === "function" ? params(value, fieldVal, data) : params;
return column.definition.headerFilterFunc(value, fieldVal, data, params);
};
type = filterFunc;
break;
}
if (!filterFunc) switch (filterType) {
case "partial":
filterFunc = function(data) {
var colVal = column.getFieldValue(data);
if (typeof colVal !== "undefined" && colVal !== null) return String(colVal).toLowerCase().indexOf(String(value).toLowerCase()) > -1;
else return false;
};
type = "like";
break;
default:
filterFunc = function(data) {
return column.getFieldValue(data) == value;
};
type = "=";
}
self.headerFilters[field] = {
value,
func: filterFunc,
type
};
} else delete self.headerFilters[field];
column.modules.filter.value = value;
filterChangeCheck = JSON.stringify(self.headerFilters);
if (self.prevHeaderFilterChangeCheck !== filterChangeCheck) {
self.prevHeaderFilterChangeCheck = filterChangeCheck;
self.trackChanges();
self.refreshFilter();
}
}
return true;
}
column.modules.filter = {
success,
attrType: false,
tagType: false,
emptyFunc: false
};
this.generateHeaderFilterElement(column);
}
generateHeaderFilterElement(column, initialValue, reinitialize) {
var self = this, success = column.modules.filter.success, field = column.getField(), filterElement, editor, editorElement, cellWrapper, typingTimer, searchTrigger, params, onRenderedCallback;
column.modules.filter.value = initialValue;
function cancel() {}
function onRendered(callback) {
onRenderedCallback = callback;
}
if (column.modules.filter.headerElement && column.modules.filter.headerElement.parentNode) column.contentElement.removeChild(column.modules.filter.headerElement.parentNode);
if (field) {
column.modules.filter.emptyFunc = column.definition.headerFilterEmptyCheck || function(value) {
return !value && value !== 0;
};
filterElement = document.createElement("div");
filterElement.classList.add("tabulator-header-filter");
switch (typeof column.definition.headerFilter) {
case "string":
if (self.table.modules.edit.editors[column.definition.headerFilter]) {
editor = self.table.modules.edit.editors[column.definition.headerFilter];
if ((column.definition.headerFilter === "tick" || column.definition.headerFilter === "tickCross") && !column.definition.headerFilterEmptyCheck) column.modules.filter.emptyFunc = function(value) {
return value !== true && value !== false;
};
} else console.warn("Filter Error - Cannot build header filter, No such editor found: ", column.definition.editor);
break;
case "function":
editor = column.definition.headerFilter;
break;
case "boolean":
if (column.modules.edit && column.modules.edit.editor) editor = column.modules.edit.editor;
else if (column.definition.formatter && self.table.modules.edit.editors[column.definition.formatter]) {
editor = self.table.modules.edit.editors[column.definition.formatter];
if ((column.definition.formatter === "tick" || column.definition.formatter === "tickCross") && !column.definition.headerFilterEmptyCheck) column.modules.filter.emptyFunc = function(value) {
return value !== true && value !== false;
};
} else editor = self.table.modules.edit.editors["input"];
break;
}
if (editor) {
cellWrapper = {
getValue: function() {
return typeof initialValue !== "undefined" ? initialValue : "";
},
getField: function() {
return column.definition.field;
},
getElement: function() {
return filterElement;
},
getColumn: function() {
return column.getComponent();
},
getTable: () => {
return this.table;
},
getType: () => {
return "header";
},
getRow: function() {
return { normalizeHeight: function() {} };
}
};
params = column.definition.headerFilterParams || {};
params = typeof params === "function" ? params.call(self.table, cellWrapper) : params;
editorElement = editor.call(this.table.modules.edit, cellWrapper, onRendered, success, cancel, params);
if (!editorElement) {
console.warn("Filter Error - Cannot add filter to " + field + " column, editor returned a value of false");
return;
}
if (!(editorElement instanceof Node)) {
console.warn("Filter Error - Cannot add filter to " + field + " column, editor should return an instance of Node, the editor returned:", editorElement);
return;
}
self.langBind("headerFilters|columns|" + column.definition.field, function(value) {
editorElement.setAttribute("placeholder", typeof value !== "undefined" && value ? value : column.definition.headerFilterPlaceholder || self.langText("headerFilters|default"));
});
editorElement.addEventListener("click", function(e) {
e.stopPropagation();
editorElement.focus();
});
editorElement.addEventListener("focus", (e) => {
var left = this.table.columnManager.contentsElement.scrollLeft;
if (left !== this.table.rowManager.element.scrollLeft) {
this.table.rowManager.scrollHorizontal(left);
this.table.columnManager.scrollHorizontal(left);
}
});
typingTimer = false;
searchTrigger = function(e) {
if (typingTimer) clearTimeout(typingTimer);
typingTimer = setTimeout(function() {
success(editorElement.value);
}, self.table.options.headerFilterLiveFilterDelay);
};
column.modules.filter.headerElement = editorElement;
column.modules.filter.attrType = editorElement.hasAttribute("type") ? editorElement.getAttribute("type").toLowerCase() : "";
column.modules.filter.tagType = editorElement.tagName.toLowerCase();
if (column.definition.headerFilterLiveFilter !== false) {
if (!(column.definition.headerFilter === "autocomplete" || column.definition.headerFilter === "tickCross" || (column.definition.editor === "autocomplete" || column.definition.editor === "tickCross") && column.definition.headerFilter === true)) {
editorElement.addEventListener("keyup", searchTrigger);
editorElement.addEventListener("search", searchTrigger);
if (column.modules.filter.attrType == "number") editorElement.addEventListener("change", function(e) {
success(editorElement.value);
});
if (column.modules.filter.attrType == "text" && this.table.browser !== "ie") editorElement.setAttribute("type", "search");
}
if (column.modules.filter.tagType == "input" || column.modules.filter.tagType == "select" || column.modules.filter.tagType == "textarea") editorElement.addEventListener("mousedown", function(e) {
e.stopPropagation();
});
}
filterElement.appendChild(editorElement);
column.contentElement.appendChild(filterElement);
if (!reinitialize) self.headerFilterColumns.push(column);
if (onRenderedCallback) onRenderedCallback();
}
} else console.warn("Filter Error - Cannot add header filter, column has no field set:", column.definition.title);
}
hideHeaderFilterElements() {
this.headerFilterColumns.forEach(function(column) {
if (column.modules.filter && column.modules.filter.headerElement) column.modules.filter.headerElement.style.display = "none";
});
}
showHeaderFilterElements() {
this.headerFilterColumns.forEach(function(column) {
if (column.modules.filter && column.modules.filter.headerElement) column.modules.filter.headerElement.style.display = "";
});
}
setHeaderFilterFocus(column) {
if (column.modules.filter && column.modules.filter.headerElement) column.modules.filter.headerElement.focus();
else console.warn("Column Filter Focus Error - No header filter set on column:", column.getField());
}
getHeaderFilterValue(column) {
if (column.modules.filter && column.modules.filter.headerElement) return column.modules.filter.value;
else console.warn("Column Filter Error - No header filter set on column:", column.getField());
}
setHeaderFilterValue(column, value) {
if (column) if (column.modules.filter && column.modules.filter.headerElement) {
this.generateHeaderFilterElement(column, value, true);
column.modules.filter.success(value);
} else console.warn("Column Filter Error - No header filter set on column:", column.getField());
}
reloadHeaderFilter(column) {
if (column) if (column.modules.filter && column.modules.filter.headerElement) this.generateHeaderFilterElement(column, column.modules.filter.value, true);
else console.warn("Column Filter Error - No header filter set on column:", column.getField());
}
refreshFilter() {
if (this.tableInitialized) if (this.table.options.filterMode === "remote") this.reloadData(null, false, false);
else this.refreshData(true);
}
trackChanges() {
this.changed = true;
this.dispatch("filter-changed");
}
hasChanged() {
var changed = this.changed;
this.changed = false;
return changed;
}
setFilter(field, type, value, params) {
this.filterList = [];
if (!Array.isArray(field)) field = [{
field,
type,
value,
params
}];
this.addFilter(field);
}
addFilter(field, type, value, params) {
var changed = false;
if (!Array.isArray(field)) field = [{
field,
type,
value,
params
}];
field.forEach((filter) => {
filter = this.findFilter(filter);
if (filter) {
this.filterList.push(filter);
changed = true;
}
});
if (changed) this.trackChanges();
}
findFilter(filter) {
var column;
if (Array.isArray(filter)) return this.findSubFilters(filter);
var filterFunc = false;
if (typeof filter.field == "function") filterFunc = function(data) {
return filter.field(data, filter.type || {});
};
else if (Filter.filters[filter.type]) {
column = this.table.columnManager.getColumnByField(filter.field);
if (column) filterFunc = function(data) {
return Filter.filters[filter.type](filter.value, column.getFieldValue(data), data, filter.params || {});
};
else filterFunc = function(data) {
return Filter.filters[filter.type](filter.value, data[filter.field], data, filter.params || {});
};
} else console.warn("Filter Error - No such filter type found, ignoring: ", filter.type);
filter.func = filterFunc;
return filter.func ? filter : false;
}
findSubFilters(filters) {
var output = [];
filters.forEach((filter) => {
filter = this.findFilter(filter);
if (filter) output.push(filter);
});
return output.length ? output : false;
}
getFilters(all, ajax) {
var output = [];
if (all) output = this.getHeaderFilters();
if (ajax) output.forEach(function(item) {
if (typeof item.type == "function") item.type = "function";
});
output = output.concat(this.filtersToArray(this.filterList, ajax));
return output;
}
filtersToArray(filterList, ajax) {
var output = [];
filterList.forEach((filter) => {
var item;
if (Array.isArray(filter)) output.push(this.filtersToArray(filter, ajax));
else {
item = {
field: filter.field,
type: filter.type,
value: filter.value
};
if (ajax) {
if (typeof item.type == "function") item.type = "function";
}
output.push(item);
}
});
return output;
}
getHeaderFilters() {
var output = [];
for (var key in this.headerFilters) output.push({
field: key,
type: this.headerFilters[key].type,
value: this.headerFilters[key].value
});
return output;
}
removeFilter(field, type, value) {
if (!Array.isArray(field)) field = [{
field,
type,
value
}];
field.forEach((filter) => {
var index = -1;
if (typeof filter.field == "object") index = this.filterList.findIndex((element) => {
return filter === element;
});
else index = this.filterList.findIndex((element) => {
return filter.field === element.field && filter.type === element.type && filter.value === element.value;
});
if (index > -1) this.filterList.splice(index, 1);
else console.warn("Filter Error - No matching filter type found, ignoring: ", filter.type);
});
this.trackChanges();
}
clearFilter(all) {
this.filterList = [];
if (all) this.clearHeaderFilter();
this.trackChanges();
}
clearHeaderFilter() {
this.headerFilters = {};
this.prevHeaderFilterChangeCheck = "{}";
this.headerFilterColumns.forEach((column) => {
if (typeof column.modules.filter.value !== "undefined") delete column.modules.filter.value;
column.modules.filter.prevSuccess = void 0;
this.reloadHeaderFilter(column);
});
this.trackChanges();
}
search(searchType, field, type, value) {
var activeRows = [], filterList = [];
if (!Array.isArray(field)) field = [{
field,
type,
value
}];
field.forEach((filter) => {
filter = this.findFilter(filter);
if (filter) filterList.push(filter);
});
this.table.rowManager.rows.forEach((row) => {
var match = true;
filterList.forEach((filter) => {
if (!this.filterRecurse(filter, row.getData())) match = false;
});
if (match) activeRows.push(searchType === "data" ? row.getData("data") : row.getComponent());
});
return activeRows;
}
filter(rowList, filters) {
var activeRows = [], activeRowComponents = [];
if (this.subscribedExternal("dataFiltering")) this.dispatchExternal("dataFiltering", this.getFilters(true));
if (this.table.options.filterMode !== "remote" && (this.filterList.length || Object.keys(this.headerFilters).length)) rowList.forEach((row) => {
if (this.filterRow(row)) activeRows.push(row);
});
else activeRows = rowList.slice(0);
if (this.subscribedExternal("dataFiltered")) {
activeRows.forEach((row) => {
activeRowComponents.push(row.getComponent());
});
this.dispatchExternal("dataFiltered", this.getFilters(true), activeRowComponents);
}
return activeRows;
}
filterRow(row, filters) {
var match = true, data = row.getData();
this.filterList.forEach((filter) => {
if (!this.filterRecurse(filter, data)) match = false;
});
for (var field in this.headerFilters) if (!this.headerFilters[field].func(data)) match = false;
return match;
}
filterRecurse(filter, data) {
var match = false;
if (Array.isArray(filter)) filter.forEach((subFilter) => {
if (this.filterRecurse(subFilter, data)) match = true;
});
else match = filter.func(data);
return match;
}
};
function plaintext(cell, formatterParams, onRendered) {
return this.emptyToSpace(this.sanitizeHTML(cell.getValue()));
}
function html(cell, formatterParams, onRendered) {
return cell.getValue();
}
function textarea(cell, formatterParams, onRendered) {
cell.getElement().style.whiteSpace = "pre-wrap";
return this.emptyToSpace(this.sanitizeHTML(cell.getValue()));
}
function money(cell, formatterParams, onRendered) {
var floatVal = parseFloat(cell.getValue()), sign = "", number, integer, decimal, rgx, value;
var decimalSym = formatterParams.decimal || ".";
var thousandSym = formatterParams.thousand || ",";
var negativeSign = formatterParams.negativeSign || "-";
var symbol = formatterParams.symbol || "";
var after = !!formatterParams.symbolAfter;
var precision = typeof formatterParams.precision !== "undefined" ? formatterParams.precision : 2;
if (isNaN(floatVal)) return this.emptyToSpace(this.sanitizeHTML(cell.getValue()));
if (floatVal < 0) {
floatVal = Math.abs(floatVal);
sign = negativeSign;
}
number = precision !== false ? floatVal.toFixed(precision) : floatVal;
number = String(number).split(".");
integer = number[0];
decimal = number.length > 1 ? decimalSym + number[1] : "";
if (formatterParams.thousand !== false) {
rgx = /(\d+)(\d{3})/;
while (rgx.test(integer)) integer = integer.replace(rgx, "$1" + thousandSym + "$2");
}
value = integer + decimal;
if (sign === true) {
value = "(" + value + ")";
return after ? value + symbol : symbol + value;
} else return after ? sign + value + symbol : sign + symbol + value;
}
function link(cell, formatterParams, onRendered) {
var value = cell.getValue(), urlPrefix = formatterParams.urlPrefix || "", download = formatterParams.download, label = value, el = document.createElement("a"), data;
function labelTraverse(path, data) {
var value = data[path.shift()];
if (path.length && typeof value === "object") return labelTraverse(path, value);
return value;
}
if (formatterParams.labelField) {
data = cell.getData();
label = labelTraverse(formatterParams.labelField.split(this.table.options.nestedFieldSeparator), data);
}
if (formatterParams.label) switch (typeof formatterParams.label) {
case "string":
label = formatterParams.label;
break;
case "function":
label = formatterParams.label(cell);
break;
}
if (label) {
if (formatterParams.urlField) {
data = cell.getData();
value = Helpers.retrieveNestedData(this.table.options.nestedFieldSeparator, formatterParams.urlField, data);
}
if (formatterParams.url) switch (typeof formatterParams.url) {
case "string":
value = formatterParams.url;
break;
case "function":
value = formatterParams.url(cell);
break;
}
el.setAttribute("href", urlPrefix + value);
if (formatterParams.target) el.setAttribute("target", formatterParams.target);
if (formatterParams.download) {
if (typeof download == "function") download = download(cell);
else download = download === true ? "" : download;
el.setAttribute("download", download);
}
el.innerHTML = this.emptyToSpace(this.sanitizeHTML(label));
return el;
} else return " ";
}
function image(cell, formatterParams, onRendered) {
var el = document.createElement("img"), src = cell.getValue();
if (formatterParams.urlPrefix) src = formatterParams.urlPrefix + cell.getValue();
if (formatterParams.urlSuffix) src = src + formatterParams.urlSuffix;
el.setAttribute("src", src);
switch (typeof formatterParams.height) {
case "number":
el.style.height = formatterParams.height + "px";
break;
case "string":
el.style.height = formatterParams.height;
break;
}
switch (typeof formatterParams.width) {
case "number":
el.style.width = formatterParams.width + "px";
break;
case "string":
el.style.width = formatterParams.width;
break;
}
el.addEventListener("load", function() {
cell.getRow().normalizeHeight();
});
return el;
}
function tickCross(cell, formatterParams, onRendered) {
var value = cell.getValue(), element = cell.getElement(), empty = formatterParams.allowEmpty, truthy = formatterParams.allowTruthy, trueValueSet = Object.keys(formatterParams).includes("trueValue"), tick = typeof formatterParams.tickElement !== "undefined" ? formatterParams.tickElement : "<svg enable-background=\"new 0 0 24 24\" height=\"14\" width=\"14\" viewBox=\"0 0 24 24\" xml:space=\"preserve\" ><path fill=\"#2DC214\" clip-rule=\"evenodd\" d=\"M21.652,3.211c-0.293-0.295-0.77-0.295-1.061,0L9.41,14.34 c-0.293,0.297-0.771,0.297-1.062,0L3.449,9.351C3.304,9.203,3.114,9.13,2.923,9.129C2.73,9.128,2.534,9.201,2.387,9.351 l-2.165,1.946C0.078,11.445,0,11.63,0,11.823c0,0.194,0.078,0.397,0.223,0.544l4.94,5.184c0.292,0.296,0.771,0.776,1.062,1.07 l2.124,2.141c0.292,0.293,0.769,0.293,1.062,0l14.366-14.34c0.293-0.294,0.293-0.777,0-1.071L21.652,3.211z\" fill-rule=\"evenodd\"/></svg>", cross = typeof formatterParams.crossElement !== "undefined" ? formatterParams.crossElement : "<svg enable-background=\"new 0 0 24 24\" height=\"14\" width=\"14\" viewBox=\"0 0 24 24\" xml:space=\"preserve\" ><path fill=\"#CE1515\" d=\"M22.245,4.015c0.313,0.313,0.313,0.826,0,1.139l-6.276,6.27c-0.313,0.312-0.313,0.826,0,1.14l6.273,6.272 c0.313,0.313,0.313,0.826,0,1.14l-2.285,2.277c-0.314,0.312-0.828,0.312-1.142,0l-6.271-6.271c-0.313-0.313-0.828-0.313-1.141,0 l-6.276,6.267c-0.313,0.313-0.828,0.313-1.141,0l-2.282-2.28c-0.313-0.313-0.313-0.826,0-1.14l6.278-6.269 c0.313-0.312,0.313-0.826,0-1.14L1.709,5.147c-0.314-0.313-0.314-0.827,0-1.14l2.284-2.278C4.308,1.417,4.821,1.417,5.135,1.73 L11.405,8c0.314,0.314,0.828,0.314,1.141,0.001l6.276-6.267c0.312-0.312,0.826-0.312,1.141,0L22.245,4.015z\"/></svg>";
if (trueValueSet && value === formatterParams.trueValue || !trueValueSet && (truthy && value || value === true || value === "true" || value === "True" || value === 1 || value === "1")) {
element.setAttribute("aria-checked", true);
return tick || "";
} else if (empty && (value === "null" || value === "" || value === null || typeof value === "undefined")) {
element.setAttribute("aria-checked", "mixed");
return "";
} else {
element.setAttribute("aria-checked", false);
return cross || "";
}
}
function datetime$1(cell, formatterParams, onRendered) {
var DT = this.table.dependencyRegistry.lookup(["luxon", "DateTime"], "DateTime");
var inputFormat = formatterParams.inputFormat || "yyyy-MM-dd HH:mm:ss";
var outputFormat = formatterParams.outputFormat || "dd/MM/yyyy HH:mm:ss";
var invalid = typeof formatterParams.invalidPlaceholder !== "undefined" ? formatterParams.invalidPlaceholder : "";
var value = cell.getValue();
if (typeof DT != "undefined") {
var newDatetime;
if (DT.isDateTime(value)) newDatetime = value;
else if (inputFormat === "iso") newDatetime = DT.fromISO(String(value));
else newDatetime = DT.fromFormat(String(value), inputFormat);
if (newDatetime.isValid) {
if (formatterParams.timezone) newDatetime = newDatetime.setZone(formatterParams.timezone);
return newDatetime.toFormat(outputFormat);
} else if (invalid === true || !value) return value;
else if (typeof invalid === "function") return invalid(value);
else return invalid;
} else console.error("Format Error - 'datetime' formatter is dependant on luxon.js");
}
function datetimediff(cell, formatterParams, onRendered) {
var DT = this.table.dependencyRegistry.lookup(["luxon", "DateTime"], "DateTime");
var inputFormat = formatterParams.inputFormat || "yyyy-MM-dd HH:mm:ss";
var invalid = typeof formatterParams.invalidPlaceholder !== "undefined" ? formatterParams.invalidPlaceholder : "";
var suffix = typeof formatterParams.suffix !== "undefined" ? formatterParams.suffix : false;
var unit = typeof formatterParams.unit !== "undefined" ? formatterParams.unit : "days";
var humanize = typeof formatterParams.humanize !== "undefined" ? formatterParams.humanize : false;
var date = typeof formatterParams.date !== "undefined" ? formatterParams.date : DT.now();
var value = cell.getValue();
if (typeof DT != "undefined") {
var newDatetime;
if (DT.isDateTime(value)) newDatetime = value;
else if (inputFormat === "iso") newDatetime = DT.fromISO(String(value));
else newDatetime = DT.fromFormat(String(value), inputFormat);
if (newDatetime.isValid) if (humanize) return newDatetime.diff(date, unit).toHuman() + (suffix ? " " + suffix : "");
else return parseInt(newDatetime.diff(date, unit)[unit]) + (suffix ? " " + suffix : "");
else if (invalid === true) return value;
else if (typeof invalid === "function") return invalid(value);
else return invalid;
} else console.error("Format Error - 'datetimediff' formatter is dependant on luxon.js");
}
function lookup(cell, formatterParams, onRendered) {
var value = cell.getValue();
if (typeof formatterParams[value] === "undefined") {
console.warn("Missing display value for " + value);
return value;
}
return formatterParams[value];
}
function star(cell, formatterParams, onRendered) {
var value = cell.getValue(), element = cell.getElement(), maxStars = formatterParams && formatterParams.stars ? formatterParams.stars : 5, stars = document.createElement("span"), star = document.createElementNS("http://www.w3.org/2000/svg", "svg"), starActive = "<polygon fill=\"#FFEA00\" stroke=\"#C1AB60\" stroke-width=\"37.6152\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-miterlimit=\"10\" points=\"259.216,29.942 330.27,173.919 489.16,197.007 374.185,309.08 401.33,467.31 259.216,392.612 117.104,467.31 144.25,309.08 29.274,197.007 188.165,173.919 \"/>", starInactive = "<polygon fill=\"#D2D2D2\" stroke=\"#686868\" stroke-width=\"37.6152\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-miterlimit=\"10\" points=\"259.216,29.942 330.27,173.919 489.16,197.007 374.185,309.08 401.33,467.31 259.216,392.612 117.104,467.31 144.25,309.08 29.274,197.007 188.165,173.919 \"/>";
stars.style.verticalAlign = "middle";
star.setAttribute("width", "14");
star.setAttribute("height", "14");
star.setAttribute("viewBox", "0 0 512 512");
star.setAttribute("xml:space", "preserve");
star.style.padding = "0 1px";
value = value && !isNaN(value) ? parseInt(value) : 0;
value = Math.max(0, Math.min(value, maxStars));
for (var i = 1; i <= maxStars; i++) {
var nextStar = star.cloneNode(true);
nextStar.innerHTML = i <= value ? starActive : starInactive;
stars.appendChild(nextStar);
}
element.style.whiteSpace = "nowrap";
element.style.overflow = "hidden";
element.style.textOverflow = "ellipsis";
element.setAttribute("aria-label", value);
return stars;
}
function traffic(cell, formatterParams, onRendered) {
var value = this.sanitizeHTML(cell.getValue()) || 0, el = document.createElement("span"), max = formatterParams && formatterParams.max ? formatterParams.max : 100, min = formatterParams && formatterParams.min ? formatterParams.min : 0, colors = formatterParams && typeof formatterParams.color !== "undefined" ? formatterParams.color : [
"red",
"orange",
"green"
], color = "#666666", percent, percentValue;
if (isNaN(value) || typeof cell.getValue() === "undefined") return;
el.classList.add("tabulator-traffic-light");
percentValue = parseFloat(value) <= max ? parseFloat(value) : max;
percentValue = parseFloat(percentValue) >= min ? parseFloat(percentValue) : min;
percent = (max - min) / 100;
percentValue = Math.round((percentValue - min) / percent);
switch (typeof colors) {
case "string":
color = colors;
break;
case "function":
color = colors(value);
break;
case "object": if (Array.isArray(colors)) {
var unit = 100 / colors.length;
var index = Math.floor(percentValue / unit);
index = Math.min(index, colors.length - 1);
index = Math.max(index, 0);
color = colors[index];
break;
}
}
el.style.backgroundColor = color;
return el;
}
function progress(cell, formatterParams = {}, onRendered) {
var value = this.sanitizeHTML(cell.getValue()) || 0, element = cell.getElement(), max = formatterParams.max ? formatterParams.max : 100, min = formatterParams.min ? formatterParams.min : 0, legendAlign = formatterParams.legendAlign ? formatterParams.legendAlign : "center", percent, percentValue = parseFloat(value) <= max ? parseFloat(value) : max, color, legend, legendColor;
percentValue = parseFloat(percentValue) >= min ? parseFloat(percentValue) : min;
percent = (max - min) / 100;
percentValue = Math.round((percentValue - min) / percent);
switch (typeof formatterParams.color) {
case "string":
color = formatterParams.color;
break;
case "function":
color = formatterParams.color(value);
break;
case "object": if (Array.isArray(formatterParams.color)) {
let unit = 100 / formatterParams.color.length;
let index = Math.floor(percentValue / unit);
index = Math.min(index, formatterParams.color.length - 1);
index = Math.max(index, 0);
color = formatterParams.color[index];
break;
}
default: color = "#2DC214";
}
switch (typeof formatterParams.legend) {
case "string":
legend = formatterParams.legend;
break;
case "function":
legend = formatterParams.legend(value);
break;
case "boolean":
legend = value;
break;
default: legend = false;
}
switch (typeof formatterParams.legendColor) {
case "string":
legendColor = formatterParams.legendColor;
break;
case "function":
legendColor = formatterParams.legendColor(value);
break;
case "object":
if (Array.isArray(formatterParams.legendColor)) {
let unit = 100 / formatterParams.legendColor.length;
let index = Math.floor(percentValue / unit);
index = Math.min(index, formatterParams.legendColor.length - 1);
index = Math.max(index, 0);
legendColor = formatterParams.legendColor[index];
}
break;
default: legendColor = "#000";
}
element.style.minWidth = "30px";
element.style.position = "relative";
element.setAttribute("aria-label", percentValue);
var barEl = document.createElement("div");
barEl.style.display = "inline-block";
barEl.style.width = percentValue + "%";
barEl.style.backgroundColor = color;
barEl.style.height = "100%";
barEl.setAttribute("data-max", max);
barEl.setAttribute("data-min", min);
var barContainer = document.createElement("div");
barContainer.style.position = "relative";
barContainer.style.width = "100%";
barContainer.style.height = "100%";
if (legend) {
var legendEl = document.createElement("div");
legendEl.style.position = "absolute";
legendEl.style.top = 0;
legendEl.style.left = 0;
legendEl.style.textAlign = legendAlign;
legendEl.style.width = "100%";
legendEl.style.color = legendColor;
legendEl.innerHTML = legend;
}
onRendered(function() {
if (!(cell instanceof CellComponent)) {
var holderEl = document.createElement("div");
holderEl.style.position = "absolute";
holderEl.style.top = "4px";
holderEl.style.bottom = "4px";
holderEl.style.left = "4px";
holderEl.style.right = "4px";
element.appendChild(holderEl);
element = holderEl;
}
element.appendChild(barContainer);
barContainer.appendChild(barEl);
if (legend) barContainer.appendChild(legendEl);
});
return "";
}
function color(cell, formatterParams, onRendered) {
cell.getElement().style.backgroundColor = this.sanitizeHTML(cell.getValue());
return "";
}
function buttonTick(cell, formatterParams, onRendered) {
return "<svg enable-background=\"new 0 0 24 24\" height=\"14\" width=\"14\" viewBox=\"0 0 24 24\" xml:space=\"preserve\" ><path fill=\"#2DC214\" clip-rule=\"evenodd\" d=\"M21.652,3.211c-0.293-0.295-0.77-0.295-1.061,0L9.41,14.34 c-0.293,0.297-0.771,0.297-1.062,0L3.449,9.351C3.304,9.203,3.114,9.13,2.923,9.129C2.73,9.128,2.534,9.201,2.387,9.351 l-2.165,1.946C0.078,11.445,0,11.63,0,11.823c0,0.194,0.078,0.397,0.223,0.544l4.94,5.184c0.292,0.296,0.771,0.776,1.062,1.07 l2.124,2.141c0.292,0.293,0.769,0.293,1.062,0l14.366-14.34c0.293-0.294,0.293-0.777,0-1.071L21.652,3.211z\" fill-rule=\"evenodd\"/></svg>";
}
function buttonCross(cell, formatterParams, onRendered) {
return "<svg enable-background=\"new 0 0 24 24\" height=\"14\" width=\"14\" viewBox=\"0 0 24 24\" xml:space=\"preserve\" ><path fill=\"#CE1515\" d=\"M22.245,4.015c0.313,0.313,0.313,0.826,0,1.139l-6.276,6.27c-0.313,0.312-0.313,0.826,0,1.14l6.273,6.272 c0.313,0.313,0.313,0.826,0,1.14l-2.285,2.277c-0.314,0.312-0.828,0.312-1.142,0l-6.271-6.271c-0.313-0.313-0.828-0.313-1.141,0 l-6.276,6.267c-0.313,0.313-0.828,0.313-1.141,0l-2.282-2.28c-0.313-0.313-0.313-0.826,0-1.14l6.278-6.269 c0.313-0.312,0.313-0.826,0-1.14L1.709,5.147c-0.314-0.313-0.314-0.827,0-1.14l2.284-2.278C4.308,1.417,4.821,1.417,5.135,1.73 L11.405,8c0.314,0.314,0.828,0.314,1.141,0.001l6.276-6.267c0.312-0.312,0.826-0.312,1.141,0L22.245,4.015z\"/></svg>";
}
function toggle(cell, formatterParams, onRendered) {
var value = cell.getValue(), size = formatterParams.size || 15, sizePx = size + "px", containEl, switchEl, onValue = formatterParams.hasOwnProperty("onValue") ? formatterParams.onValue : true, offValue = formatterParams.hasOwnProperty("offValue") ? formatterParams.offValue : false, state = formatterParams.onTruthy ? value : value === onValue;
containEl = document.createElement("div");
containEl.classList.add("tabulator-toggle");
if (state) {
containEl.classList.add("tabulator-toggle-on");
containEl.style.flexDirection = "row-reverse";
if (formatterParams.onColor) containEl.style.background = formatterParams.onColor;
} else if (formatterParams.offColor) containEl.style.background = formatterParams.offColor;
containEl.style.width = 2.5 * size + "px";
containEl.style.borderRadius = sizePx;
if (formatterParams.clickable) containEl.addEventListener("click", (e) => {
cell.setValue(state ? offValue : onValue);
});
switchEl = document.createElement("div");
switchEl.classList.add("tabulator-toggle-switch");
switchEl.style.height = sizePx;
switchEl.style.width = sizePx;
switchEl.style.borderRadius = sizePx;
containEl.appendChild(switchEl);
return containEl;
}
function rownum(cell, formatterParams, onRendered) {
var content = document.createElement("span");
var row = cell.getRow();
var table = cell.getTable();
row.watchPosition((position) => {
if (formatterParams.relativeToPage) position += table.modules.page.getPageSize() * (table.modules.page.getPage() - 1);
content.innerText = position;
});
return content;
}
function handle(cell, formatterParams, onRendered) {
cell.getElement().classList.add("tabulator-row-handle");
return "<div class='tabulator-row-handle-box'><div class='tabulator-row-handle-bar'></div><div class='tabulator-row-handle-bar'></div><div class='tabulator-row-handle-bar'></div></div>";
}
function adaptable(cell, params, onRendered) {
var lookup, formatterFunc, formatterParams;
function defaultLookup(cell) {
var value = cell.getValue(), formatter = "plaintext";
switch (typeof value) {
case "boolean":
formatter = "tickCross";
break;
case "string":
if (value.includes("\n")) formatter = "textarea";
break;
}
return formatter;
}
lookup = params.formatterLookup ? params.formatterLookup(cell) : defaultLookup(cell);
if (params.paramsLookup) formatterParams = typeof params.paramsLookup === "function" ? params.paramsLookup(lookup, cell) : params.paramsLookup[lookup];
formatterFunc = this.table.modules.format.lookupFormatter(lookup);
return formatterFunc.call(this, cell, formatterParams || {}, onRendered);
}
function array$2(cell, formatterParams, onRendered) {
var delimiter = formatterParams.delimiter || ",", value = cell.getValue(), table = this.table, valueMap;
if (formatterParams.valueMap) if (typeof formatterParams.valueMap === "string") valueMap = function(value) {
return value.map((item) => {
return Helpers.retrieveNestedData(table.options.nestedFieldSeparator, formatterParams.valueMap, item);
});
};
else valueMap = formatterParams.valueMap;
if (Array.isArray(value)) {
if (valueMap) value = valueMap(value);
return value.join(delimiter);
} else return value;
}
function json$1(cell, formatterParams, onRendered) {
var indent = formatterParams.indent || " ", multiline = typeof formatterParams.multiline === "undefined" ? true : formatterParams.multiline, replacer = formatterParams.replacer || null, value = cell.getValue();
if (multiline) cell.getElement().style.whiteSpace = "pre-wrap";
return JSON.stringify(value, replacer, indent);
}
var defaultFormatters = {
plaintext,
html,
textarea,
money,
link,
image,
tickCross,
datetime: datetime$1,
datetimediff,
lookup,
star,
traffic,
progress,
color,
buttonTick,
buttonCross,
toggle,
rownum,
handle,
adaptable,
array: array$2,
json: json$1
};
var Format = class Format extends Module {
static moduleName = "format";
static formatters = defaultFormatters;
constructor(table) {
super(table);
this.registerColumnOption("formatter");
this.registerColumnOption("formatterParams");
this.registerColumnOption("formatterPrint");
this.registerColumnOption("formatterPrintParams");
this.registerColumnOption("formatterClipboard");
this.registerColumnOption("formatterClipboardParams");
this.registerColumnOption("formatterHtmlOutput");
this.registerColumnOption("formatterHtmlOutputParams");
this.registerColumnOption("titleFormatter");
this.registerColumnOption("titleFormatterParams");
}
initialize() {
this.subscribe("cell-format", this.formatValue.bind(this));
this.subscribe("cell-rendered", this.cellRendered.bind(this));
this.subscribe("column-layout", this.initializeColumn.bind(this));
this.subscribe("column-format", this.formatHeader.bind(this));
}
initializeColumn(column) {
column.modules.format = this.lookupTypeFormatter(column, "");
if (typeof column.definition.formatterPrint !== "undefined") column.modules.format.print = this.lookupTypeFormatter(column, "Print");
if (typeof column.definition.formatterClipboard !== "undefined") column.modules.format.clipboard = this.lookupTypeFormatter(column, "Clipboard");
if (typeof column.definition.formatterHtmlOutput !== "undefined") column.modules.format.htmlOutput = this.lookupTypeFormatter(column, "HtmlOutput");
}
lookupTypeFormatter(column, type) {
var config = { params: column.definition["formatter" + type + "Params"] || {} }, formatter = column.definition["formatter" + type];
config.formatter = this.lookupFormatter(formatter);
return config;
}
lookupFormatter(formatter) {
var formatterFunc;
switch (typeof formatter) {
case "string":
if (Format.formatters[formatter]) formatterFunc = Format.formatters[formatter];
else {
console.warn("Formatter Error - No such formatter found: ", formatter);
formatterFunc = Format.formatters.plaintext;
}
break;
case "function":
formatterFunc = formatter;
break;
default:
formatterFunc = Format.formatters.plaintext;
break;
}
return formatterFunc;
}
cellRendered(cell) {
if (cell.modules.format && cell.modules.format.renderedCallback && !cell.modules.format.rendered) {
cell.modules.format.renderedCallback();
cell.modules.format.rendered = true;
}
}
formatHeader(column, title, el) {
var formatter, params, onRendered, mockCell;
if (column.definition.titleFormatter) {
formatter = this.lookupFormatter(column.definition.titleFormatter);
onRendered = (callback) => {
column.titleFormatterRendered = callback;
};
mockCell = {
getValue: function() {
return title;
},
getElement: function() {
return el;
},
getType: function() {
return "header";
},
getColumn: function() {
return column.getComponent();
},
getTable: () => {
return this.table;
}
};
params = column.definition.titleFormatterParams || {};
params = typeof params === "function" ? params() : params;
return formatter.call(this, mockCell, params, onRendered);
} else return title;
}
formatValue(cell) {
var component = cell.getComponent(), params = typeof cell.column.modules.format.params === "function" ? cell.column.modules.format.params(component) : cell.column.modules.format.params;
function onRendered(callback) {
if (!cell.modules.format) cell.modules.format = {};
cell.modules.format.renderedCallback = callback;
cell.modules.format.rendered = false;
}
return cell.column.modules.format.formatter.call(this, component, params, onRendered);
}
formatExportValue(cell, type) {
var formatter = cell.column.modules.format[type], params;
if (formatter) {
params = typeof formatter.params === "function" ? formatter.params(cell.getComponent()) : formatter.params;
function onRendered(callback) {
if (!cell.modules.format) cell.modules.format = {};
cell.modules.format.renderedCallback = callback;
cell.modules.format.rendered = false;
}
return formatter.formatter.call(this, cell.getComponent(), params, onRendered);
} else return this.formatValue(cell);
}
sanitizeHTML(value) {
if (value) {
var entityMap = {
"&": "&",
"<": "<",
">": ">",
"\"": """,
"'": "'",
"/": "/",
"`": "`",
"=": "="
};
return String(value).replace(/[&<>"'`=/]/g, function(s) {
return entityMap[s];
});
} else return value;
}
emptyToSpace(value) {
return value === null || typeof value === "undefined" || value === "" ? " " : value;
}
};
var FrozenColumns = class extends Module {
static moduleName = "frozenColumns";
constructor(table) {
super(table);
this.leftColumns = [];
this.rightColumns = [];
this.initializationMode = "left";
this.active = false;
this.blocked = true;
this.registerColumnOption("frozen");
}
reset() {
this.initializationMode = "left";
this.leftColumns = [];
this.rightColumns = [];
this.active = false;
}
initialize() {
this.subscribe("cell-layout", this.layoutCell.bind(this));
this.subscribe("column-init", this.initializeColumn.bind(this));
this.subscribe("column-width", this.layout.bind(this));
this.subscribe("row-layout-after", this.layoutRow.bind(this));
this.subscribe("table-layout", this.layout.bind(this));
this.subscribe("columns-loading", this.reset.bind(this));
this.subscribe("column-add", this.reinitializeColumns.bind(this));
this.subscribe("column-deleted", this.reinitializeColumns.bind(this));
this.subscribe("column-hide", this.reinitializeColumns.bind(this));
this.subscribe("column-show", this.reinitializeColumns.bind(this));
this.subscribe("columns-loaded", this.reinitializeColumns.bind(this));
this.subscribe("table-redraw", this.layout.bind(this));
this.subscribe("layout-refreshing", this.blockLayout.bind(this));
this.subscribe("layout-refreshed", this.unblockLayout.bind(this));
this.subscribe("scrollbar-vertical", this.adjustForScrollbar.bind(this));
}
blockLayout() {
this.blocked = true;
}
unblockLayout() {
this.blocked = false;
}
layoutCell(cell) {
this.layoutElement(cell.element, cell.column);
}
reinitializeColumns() {
this.reset();
this.table.columnManager.columnsByIndex.forEach((column) => {
this.initializeColumn(column);
});
this.layout();
}
initializeColumn(column) {
var config = {
margin: 0,
edge: false
};
if (!column.isGroup) if (this.frozenCheck(column)) {
config.position = this.initializationMode;
if (this.initializationMode == "left") this.leftColumns.push(column);
else this.rightColumns.unshift(column);
this.active = true;
column.modules.frozen = config;
} else this.initializationMode = "right";
}
frozenCheck(column) {
if (column.parent.isGroup && column.definition.frozen) console.warn("Frozen Column Error - Parent column group must be frozen, not individual columns or sub column groups");
if (column.parent.isGroup) return this.frozenCheck(column.parent);
else return column.definition.frozen;
}
layoutCalcRows() {
if (this.table.modExists("columnCalcs")) {
if (this.table.modules.columnCalcs.topInitialized && this.table.modules.columnCalcs.topRow) this.layoutRow(this.table.modules.columnCalcs.topRow);
if (this.table.modules.columnCalcs.botInitialized && this.table.modules.columnCalcs.botRow) this.layoutRow(this.table.modules.columnCalcs.botRow);
if (this.table.modExists("groupRows")) this.layoutGroupCalcs(this.table.modules.groupRows.getGroups());
}
}
layoutGroupCalcs(groups) {
groups.forEach((group) => {
if (group.calcs.top) this.layoutRow(group.calcs.top);
if (group.calcs.bottom) this.layoutRow(group.calcs.bottom);
if (group.groupList && group.groupList.length) this.layoutGroupCalcs(group.groupList);
});
}
layoutColumnPosition(allCells) {
var leftParents = [];
var leftMargin = 0;
var rightMargin = 0;
this.leftColumns.forEach((column, i) => {
column.modules.frozen.marginValue = leftMargin;
column.modules.frozen.margin = column.modules.frozen.marginValue + "px";
if (column.visible) leftMargin += column.getWidth();
if (i == this.leftColumns.length - 1) column.modules.frozen.edge = true;
else column.modules.frozen.edge = false;
if (column.parent.isGroup) {
var parentEl = this.getColGroupParentElement(column);
if (!leftParents.includes(parentEl)) {
this.layoutElement(parentEl, column);
leftParents.push(parentEl);
}
parentEl.classList.toggle("tabulator-frozen-left", column.modules.frozen.edge && column.modules.frozen.position === "left");
parentEl.classList.toggle("tabulator-frozen-right", column.modules.frozen.edge && column.modules.frozen.position === "right");
} else this.layoutElement(column.getElement(), column);
if (allCells) column.cells.forEach((cell) => {
this.layoutElement(cell.getElement(true), column);
});
});
this.rightColumns.forEach((column, i) => {
column.modules.frozen.marginValue = rightMargin;
column.modules.frozen.margin = column.modules.frozen.marginValue + "px";
if (column.visible) rightMargin += column.getWidth();
if (i == this.rightColumns.length - 1) column.modules.frozen.edge = true;
else column.modules.frozen.edge = false;
if (column.parent.isGroup) this.layoutElement(this.getColGroupParentElement(column), column);
else this.layoutElement(column.getElement(), column);
if (allCells) column.cells.forEach((cell) => {
this.layoutElement(cell.getElement(true), column);
});
});
}
getColGroupParentElement(column) {
return column.parent.isGroup ? this.getColGroupParentElement(column.parent) : column.getElement();
}
layout() {
if (this.active && !this.blocked) {
this.layoutColumnPosition();
this.reinitializeRows();
this.layoutCalcRows();
}
}
reinitializeRows() {
var visibleRows = this.table.rowManager.getVisibleRows(true);
this.table.rowManager.getRows().filter((row) => !visibleRows.includes(row)).forEach((row) => {
row.deinitialize();
});
visibleRows.forEach((row) => {
if (row.type === "row") this.layoutRow(row);
});
}
layoutRow(row) {
if (this.table.options.layout === "fitDataFill" && this.rightColumns.length) this.table.rowManager.getTableElement().style.minWidth = "calc(100% - " + this.rightMargin + ")";
this.leftColumns.forEach((column) => {
var cell = row.getCell(column);
if (cell) this.layoutElement(cell.getElement(true), column);
});
this.rightColumns.forEach((column) => {
var cell = row.getCell(column);
if (cell) this.layoutElement(cell.getElement(true), column);
});
}
layoutElement(element, column) {
var position;
if (column.modules.frozen && element) {
element.style.position = "sticky";
if (this.table.rtl) position = column.modules.frozen.position === "left" ? "right" : "left";
else position = column.modules.frozen.position;
element.style[position] = column.modules.frozen.margin;
element.classList.add("tabulator-frozen");
element.classList.toggle("tabulator-frozen-left", column.modules.frozen.edge && column.modules.frozen.position === "left");
element.classList.toggle("tabulator-frozen-right", column.modules.frozen.edge && column.modules.frozen.position === "right");
}
}
adjustForScrollbar(width) {
if (this.rightColumns.length) this.table.columnManager.getContentsElement().style.width = "calc(100% - " + width + "px)";
}
getFrozenColumns() {
return this.leftColumns.concat(this.rightColumns);
}
_calcSpace(columns, index) {
var width = 0;
for (let i = 0; i < index; i++) if (columns[i].visible) width += columns[i].getWidth();
return width;
}
};
var FrozenRows = class extends Module {
static moduleName = "frozenRows";
constructor(table) {
super(table);
this.topElement = document.createElement("div");
this.rows = [];
this.registerComponentFunction("row", "freeze", this.freezeRow.bind(this));
this.registerComponentFunction("row", "unfreeze", this.unfreezeRow.bind(this));
this.registerComponentFunction("row", "isFrozen", this.isRowFrozen.bind(this));
this.registerTableOption("frozenRowsField", "id");
this.registerTableOption("frozenRows", false);
}
initialize() {
var fragment = document.createDocumentFragment();
this.rows = [];
this.topElement.classList.add("tabulator-frozen-rows-holder");
fragment.appendChild(document.createElement("br"));
fragment.appendChild(this.topElement);
this.table.columnManager.getContentsElement().insertBefore(fragment, this.table.columnManager.headersElement.nextSibling);
this.subscribe("row-deleting", this.detachRow.bind(this));
this.subscribe("rows-visible", this.visibleRows.bind(this));
this.registerDisplayHandler(this.getRows.bind(this), 10);
if (this.table.options.frozenRows) {
this.subscribe("data-processed", this.initializeRows.bind(this));
this.subscribe("row-added", this.initializeRow.bind(this));
this.subscribe("table-redrawing", this.resizeHolderWidth.bind(this));
this.subscribe("column-resized", this.resizeHolderWidth.bind(this));
this.subscribe("column-show", this.resizeHolderWidth.bind(this));
this.subscribe("column-hide", this.resizeHolderWidth.bind(this));
}
this.resizeHolderWidth();
}
resizeHolderWidth() {
this.topElement.style.minWidth = this.table.columnManager.headersElement.offsetWidth + "px";
}
initializeRows() {
this.table.rowManager.getRows().forEach((row) => {
this.initializeRow(row);
});
}
initializeRow(row) {
var frozenRows = this.table.options.frozenRows, rowType = typeof frozenRows;
if (rowType === "number") {
if (row.getPosition() && row.getPosition() + this.rows.length <= frozenRows) this.freezeRow(row);
} else if (rowType === "function") {
if (frozenRows.call(this.table, row.getComponent())) this.freezeRow(row);
} else if (Array.isArray(frozenRows)) {
if (frozenRows.includes(row.data[this.options("frozenRowsField")])) this.freezeRow(row);
}
}
isRowFrozen(row) {
return this.rows.indexOf(row) > -1;
}
isFrozen() {
return !!this.rows.length;
}
visibleRows(viewable, rows) {
this.rows.forEach((row) => {
rows.push(row);
});
return rows;
}
getRows(rows) {
var output = rows.slice(0);
this.rows.forEach(function(row) {
var index = output.indexOf(row);
if (index > -1) output.splice(index, 1);
});
return output;
}
freezeRow(row) {
if (!row.modules.frozen) {
row.modules.frozen = true;
this.topElement.appendChild(row.getElement());
row.initialize();
row.normalizeHeight();
this.rows.push(row);
this.refreshData(false, "display");
this.table.rowManager.adjustTableSize();
this.styleRows();
} else console.warn("Freeze Error - Row is already frozen");
}
unfreezeRow(row) {
if (row.modules.frozen) {
row.modules.frozen = false;
this.detachRow(row);
this.table.rowManager.adjustTableSize();
this.refreshData(false, "display");
if (this.rows.length) this.styleRows();
} else console.warn("Freeze Error - Row is already unfrozen");
}
detachRow(row) {
var index = this.rows.indexOf(row);
if (index > -1) {
var rowEl = row.getElement();
if (rowEl.parentNode) rowEl.parentNode.removeChild(rowEl);
this.rows.splice(index, 1);
}
}
styleRows(row) {
this.rows.forEach((row, i) => {
this.table.rowManager.styleRow(row, i);
});
}
};
var GroupComponent = class {
constructor(group) {
this._group = group;
this.type = "GroupComponent";
return new Proxy(this, { get: function(target, name, receiver) {
if (typeof target[name] !== "undefined") return target[name];
else return target._group.groupManager.table.componentFunctionBinder.handle("group", target._group, name);
} });
}
getKey() {
return this._group.key;
}
getField() {
return this._group.field;
}
getElement() {
return this._group.element;
}
getRows() {
return this._group.getRows(true);
}
getSubGroups() {
return this._group.getSubGroups(true);
}
getParentGroup() {
return this._group.parent ? this._group.parent.getComponent() : false;
}
isVisible() {
return this._group.visible;
}
show() {
this._group.show();
}
hide() {
this._group.hide();
}
toggle() {
this._group.toggleVisibility();
}
scrollTo(position, ifVisible) {
return this._group.groupManager.table.rowManager.scrollToRow(this._group, position, ifVisible);
}
_getSelf() {
return this._group;
}
getTable() {
return this._group.groupManager.table;
}
};
var Group = class Group {
constructor(groupManager, parent, level, key, field, generator, oldGroup) {
this.groupManager = groupManager;
this.parent = parent;
this.key = key;
this.level = level;
this.field = field;
this.hasSubGroups = level < groupManager.groupIDLookups.length - 1;
this.addRow = this.hasSubGroups ? this._addRowToGroup : this._addRow;
this.type = "group";
this.old = oldGroup;
this.rows = [];
this.groups = [];
this.groupList = [];
this.generator = generator;
this.element = false;
this.elementContents = false;
this.height = 0;
this.outerHeight = 0;
this.initialized = false;
this.calcs = {};
this.initialized = false;
this.modules = {};
this.arrowElement = false;
this.visible = oldGroup ? oldGroup.visible : typeof groupManager.startOpen[level] !== "undefined" ? groupManager.startOpen[level] : groupManager.startOpen[0];
this.component = null;
this.createElements();
this.addBindings();
this.createValueGroups();
}
wipe(elementsOnly) {
if (!elementsOnly) if (this.groupList.length) this.groupList.forEach(function(group) {
group.wipe();
});
else this.rows.forEach((row) => {
if (row.modules) delete row.modules.group;
});
this.element = false;
this.arrowElement = false;
this.elementContents = false;
}
createElements() {
var arrow = document.createElement("div");
arrow.classList.add("tabulator-arrow");
this.element = document.createElement("div");
this.element.classList.add("tabulator-row");
this.element.classList.add("tabulator-group");
this.element.classList.add("tabulator-group-level-" + this.level);
this.element.setAttribute("role", "rowgroup");
this.arrowElement = document.createElement("div");
this.arrowElement.classList.add("tabulator-group-toggle");
this.arrowElement.appendChild(arrow);
if (this.groupManager.table.options.movableRows !== false && this.groupManager.table.modExists("moveRow")) this.groupManager.table.modules.moveRow.initializeGroupHeader(this);
}
createValueGroups() {
var level = this.level + 1;
if (this.groupManager.allowedValues && this.groupManager.allowedValues[level]) this.groupManager.allowedValues[level].forEach((value) => {
this._createGroup(value, level);
});
}
addBindings() {
var toggleElement;
if (this.groupManager.table.options.groupToggleElement) {
toggleElement = this.groupManager.table.options.groupToggleElement == "arrow" ? this.arrowElement : this.element;
toggleElement.addEventListener("click", (e) => {
if (this.groupManager.table.options.groupToggleElement === "arrow") {
e.stopPropagation();
e.stopImmediatePropagation();
}
setTimeout(() => {
this.toggleVisibility();
});
});
}
}
_createGroup(groupID, level) {
var groupKey = level + "_" + groupID;
var group = new Group(this.groupManager, this, level, groupID, this.groupManager.groupIDLookups[level].field, this.groupManager.headerGenerator[level] || this.groupManager.headerGenerator[0], this.old ? this.old.groups[groupKey] : false);
this.groups[groupKey] = group;
this.groupList.push(group);
}
_addRowToGroup(row) {
var level = this.level + 1;
if (this.hasSubGroups) {
var groupID = this.groupManager.groupIDLookups[level].func(row.getData()), groupKey = level + "_" + groupID;
if (this.groupManager.allowedValues && this.groupManager.allowedValues[level]) {
if (this.groups[groupKey]) this.groups[groupKey].addRow(row);
} else {
if (!this.groups[groupKey]) this._createGroup(groupID, level);
this.groups[groupKey].addRow(row);
}
}
}
_addRow(row) {
this.rows.push(row);
row.modules.group = this;
}
insertRow(row, to, after) {
var data = this.conformRowData({});
row.updateData(data);
var toIndex = this.rows.indexOf(to);
if (toIndex > -1) if (after) this.rows.splice(toIndex + 1, 0, row);
else this.rows.splice(toIndex, 0, row);
else if (after) this.rows.push(row);
else this.rows.unshift(row);
row.modules.group = this;
if (this.groupManager.table.modExists("columnCalcs") && this.groupManager.table.options.columnCalcs != "table") this.groupManager.table.modules.columnCalcs.recalcGroup(this);
this.groupManager.updateGroupRows(true);
}
scrollHeader(left) {
if (this.arrowElement) {
this.arrowElement.style.marginLeft = left;
this.groupList.forEach(function(child) {
child.scrollHeader(left);
});
}
}
getRowIndex(row) {}
conformRowData(data) {
if (this.field) data[this.field] = this.key;
else console.warn("Data Conforming Error - Cannot conform row data to match new group as groupBy is a function");
if (this.parent) data = this.parent.conformRowData(data);
return data;
}
removeRow(row) {
var index = this.rows.indexOf(row);
var el = row.getElement();
if (index > -1) this.rows.splice(index, 1);
if (!this.groupManager.table.options.groupValues && !this.rows.length) {
if (this.parent) this.parent.removeGroup(this);
else this.groupManager.removeGroup(this);
this.groupManager.updateGroupRows(true);
} else {
if (el.parentNode) el.parentNode.removeChild(el);
if (!this.groupManager.blockRedraw) {
this.generateGroupHeaderContents();
if (this.groupManager.table.modExists("columnCalcs") && this.groupManager.table.options.columnCalcs != "table") this.groupManager.table.modules.columnCalcs.recalcGroup(this);
}
}
}
removeGroup(group) {
var groupKey = group.level + "_" + group.key, index;
if (this.groups[groupKey]) {
delete this.groups[groupKey];
index = this.groupList.indexOf(group);
if (index > -1) this.groupList.splice(index, 1);
if (!this.groupList.length) if (this.parent) this.parent.removeGroup(this);
else this.groupManager.removeGroup(this);
}
}
getHeadersAndRows() {
var output = [];
output.push(this);
this._visSet();
if (this.calcs.top) {
this.calcs.top.detachElement();
this.calcs.top.deleteCells();
}
if (this.calcs.bottom) {
this.calcs.bottom.detachElement();
this.calcs.bottom.deleteCells();
}
if (this.visible) if (this.groupList.length) this.groupList.forEach(function(group) {
output = output.concat(group.getHeadersAndRows());
});
else {
if (this.groupManager.table.options.columnCalcs != "table" && this.groupManager.table.modExists("columnCalcs") && this.groupManager.table.modules.columnCalcs.hasTopCalcs()) {
this.calcs.top = this.groupManager.table.modules.columnCalcs.generateTopRow(this.rows);
output.push(this.calcs.top);
}
output = output.concat(this.rows);
if (this.groupManager.table.options.columnCalcs != "table" && this.groupManager.table.modExists("columnCalcs") && this.groupManager.table.modules.columnCalcs.hasBottomCalcs()) {
this.calcs.bottom = this.groupManager.table.modules.columnCalcs.generateBottomRow(this.rows);
output.push(this.calcs.bottom);
}
}
else if (!this.groupList.length && this.groupManager.table.options.columnCalcs != "table") {
if (this.groupManager.table.modExists("columnCalcs")) {
if (this.groupManager.table.modules.columnCalcs.hasTopCalcs()) {
if (this.groupManager.table.options.groupClosedShowCalcs) {
this.calcs.top = this.groupManager.table.modules.columnCalcs.generateTopRow(this.rows);
output.push(this.calcs.top);
}
}
if (this.groupManager.table.modules.columnCalcs.hasBottomCalcs()) {
if (this.groupManager.table.options.groupClosedShowCalcs) {
this.calcs.bottom = this.groupManager.table.modules.columnCalcs.generateBottomRow(this.rows);
output.push(this.calcs.bottom);
}
}
}
}
return output;
}
getData(visible, transform) {
var output = [];
this._visSet();
if (!visible || visible && this.visible) this.rows.forEach((row) => {
output.push(row.getData(transform || "data"));
});
return output;
}
getRowCount() {
var count = 0;
if (this.groupList.length) this.groupList.forEach((group) => {
count += group.getRowCount();
});
else count = this.rows.length;
return count;
}
toggleVisibility() {
if (this.visible) this.hide();
else this.show();
}
hide() {
this.visible = false;
if (this.groupManager.table.rowManager.getRenderMode() == "basic" && !this.groupManager.table.options.pagination) {
this.element.classList.remove("tabulator-group-visible");
if (this.groupList.length) this.groupList.forEach((group) => {
group.getHeadersAndRows().forEach((row) => {
row.detachElement();
});
});
else this.rows.forEach((row) => {
var rowEl = row.getElement();
rowEl.parentNode.removeChild(rowEl);
});
this.groupManager.updateGroupRows(true);
} else this.groupManager.updateGroupRows(true);
this.groupManager.table.externalEvents.dispatch("groupVisibilityChanged", this.getComponent(), false);
}
show() {
this.visible = true;
if (this.groupManager.table.rowManager.getRenderMode() == "basic" && !this.groupManager.table.options.pagination) {
this.element.classList.add("tabulator-group-visible");
var prev = this.generateElement();
if (this.groupList.length) this.groupList.forEach((group) => {
group.getHeadersAndRows().forEach((row) => {
var rowEl = row.getElement();
prev.parentNode.insertBefore(rowEl, prev.nextSibling);
row.initialize();
prev = rowEl;
});
});
else this.rows.forEach((row) => {
var rowEl = row.getElement();
prev.parentNode.insertBefore(rowEl, prev.nextSibling);
row.initialize();
prev = rowEl;
});
this.groupManager.updateGroupRows(true);
} else this.groupManager.updateGroupRows(true);
this.groupManager.table.externalEvents.dispatch("groupVisibilityChanged", this.getComponent(), true);
}
_visSet() {
var data = [];
if (typeof this.visible == "function") {
this.rows.forEach(function(row) {
data.push(row.getData());
});
this.visible = this.visible(this.key, this.getRowCount(), data, this.getComponent());
}
}
getRowGroup(row) {
var match = false;
if (this.groupList.length) this.groupList.forEach(function(group) {
var result = group.getRowGroup(row);
if (result) match = result;
});
else if (this.rows.find(function(item) {
return item === row;
})) match = this;
return match;
}
getSubGroups(component) {
var output = [];
this.groupList.forEach(function(child) {
output.push(component ? child.getComponent() : child);
});
return output;
}
getRows(component, includeChildren) {
var output = [];
if (includeChildren && this.groupList.length) this.groupList.forEach((group) => {
output = output.concat(group.getRows(component, includeChildren));
});
else this.rows.forEach(function(row) {
output.push(component ? row.getComponent() : row);
});
return output;
}
generateGroupHeaderContents() {
var data = [];
this.getRows(false, true).forEach(function(row) {
data.push(row.getData());
});
this.elementContents = this.generator(this.key, this.getRowCount(), data, this.getComponent());
while (this.element.firstChild) this.element.removeChild(this.element.firstChild);
if (typeof this.elementContents === "string") this.element.innerHTML = this.elementContents;
else this.element.appendChild(this.elementContents);
this.element.insertBefore(this.arrowElement, this.element.firstChild);
}
getPath(path = []) {
path.unshift(this.key);
if (this.parent) this.parent.getPath(path);
return path;
}
getElement() {
return this.elementContents ? this.element : this.generateElement();
}
generateElement() {
this.addBindings = false;
this._visSet();
if (this.visible) this.element.classList.add("tabulator-group-visible");
else this.element.classList.remove("tabulator-group-visible");
for (var i = 0; i < this.element.childNodes.length; ++i) this.element.childNodes[i].parentNode.removeChild(this.element.childNodes[i]);
this.generateGroupHeaderContents();
return this.element;
}
detachElement() {
if (this.element && this.element.parentNode) this.element.parentNode.removeChild(this.element);
}
normalizeHeight() {
this.setHeight(this.element.clientHeight);
}
initialize(force) {
if (!this.initialized || force) {
this.normalizeHeight();
this.initialized = true;
}
}
reinitialize() {
this.initialized = false;
this.height = 0;
if (Helpers.elVisible(this.element)) this.initialize(true);
}
setHeight(height) {
if (this.height != height) {
this.height = height;
this.outerHeight = this.element.offsetHeight;
}
}
getHeight() {
return this.outerHeight;
}
getGroup() {
return this;
}
reinitializeHeight() {}
calcHeight() {}
setCellHeight() {}
clearCellHeight() {}
deinitializeHeight() {}
rendered() {}
getComponent() {
if (!this.component) this.component = new GroupComponent(this);
return this.component;
}
};
var GroupRows = class extends Module {
static moduleName = "groupRows";
constructor(table) {
super(table);
this.groupIDLookups = false;
this.startOpen = [function() {
return false;
}];
this.headerGenerator = [function() {
return "";
}];
this.groupList = [];
this.allowedValues = false;
this.groups = {};
this.displayHandler = this.getRows.bind(this);
this.blockRedraw = false;
this.registerTableOption("groupBy", false);
this.registerTableOption("groupStartOpen", true);
this.registerTableOption("groupValues", false);
this.registerTableOption("groupUpdateOnCellEdit", false);
this.registerTableOption("groupHeader", false);
this.registerTableOption("groupHeaderPrint", null);
this.registerTableOption("groupHeaderClipboard", null);
this.registerTableOption("groupHeaderHtmlOutput", null);
this.registerTableOption("groupHeaderDownload", null);
this.registerTableOption("groupToggleElement", "arrow");
this.registerTableOption("groupClosedShowCalcs", false);
this.registerTableFunction("setGroupBy", this.setGroupBy.bind(this));
this.registerTableFunction("setGroupValues", this.setGroupValues.bind(this));
this.registerTableFunction("setGroupStartOpen", this.setGroupStartOpen.bind(this));
this.registerTableFunction("setGroupHeader", this.setGroupHeader.bind(this));
this.registerTableFunction("getGroups", this.userGetGroups.bind(this));
this.registerTableFunction("getGroupedData", this.userGetGroupedData.bind(this));
this.registerComponentFunction("row", "getGroup", this.rowGetGroup.bind(this));
}
initialize() {
this.subscribe("table-destroy", this._blockRedrawing.bind(this));
this.subscribe("rows-wipe", this._blockRedrawing.bind(this));
this.subscribe("rows-wiped", this._restore_redrawing.bind(this));
if (this.table.options.groupBy) {
if (this.table.options.groupUpdateOnCellEdit) {
this.subscribe("cell-value-updated", this.cellUpdated.bind(this));
this.subscribe("row-data-changed", this.reassignRowToGroup.bind(this), 0);
}
this.subscribe("table-built", this.configureGroupSetup.bind(this));
this.subscribe("row-deleting", this.rowDeleting.bind(this));
this.subscribe("row-deleted", this.rowsUpdated.bind(this));
this.subscribe("scroll-horizontal", this.scrollHeaders.bind(this));
this.subscribe("rows-wipe", this.wipe.bind(this));
this.subscribe("rows-added", this.rowsUpdated.bind(this));
this.subscribe("row-moving", this.rowMoving.bind(this));
this.subscribe("row-adding-index", this.rowAddingIndex.bind(this));
this.subscribe("rows-sample", this.rowSample.bind(this));
this.subscribe("render-virtual-fill", this.virtualRenderFill.bind(this));
this.registerDisplayHandler(this.displayHandler, 20);
this.initialized = true;
}
}
_blockRedrawing() {
this.blockRedraw = true;
}
_restore_redrawing() {
this.blockRedraw = false;
}
configureGroupSetup() {
if (this.table.options.groupBy) {
var groupBy = this.table.options.groupBy, startOpen = this.table.options.groupStartOpen, groupHeader = this.table.options.groupHeader;
this.allowedValues = this.table.options.groupValues;
if (Array.isArray(groupBy) && Array.isArray(groupHeader) && groupBy.length > groupHeader.length) console.warn("Error creating group headers, groupHeader array is shorter than groupBy array");
this.headerGenerator = [function() {
return "";
}];
this.startOpen = [function() {
return false;
}];
this.langBind("groups|item", (langValue, lang) => {
this.headerGenerator[0] = (value, count, data) => {
return (typeof value === "undefined" ? "" : value) + "<span>(" + count + " " + (count === 1 ? langValue : lang.groups.items) + ")</span>";
};
});
this.groupIDLookups = [];
if (groupBy) {
if (this.table.modExists("columnCalcs") && this.table.options.columnCalcs != "table" && this.table.options.columnCalcs != "both") this.table.modules.columnCalcs.removeCalcs();
} else if (this.table.modExists("columnCalcs") && this.table.options.columnCalcs != "group") this.table.columnManager.getRealColumns().forEach((col) => {
if (col.definition.topCalc) this.table.modules.columnCalcs.initializeTopRow();
if (col.definition.bottomCalc) this.table.modules.columnCalcs.initializeBottomRow();
});
if (!Array.isArray(groupBy)) groupBy = [groupBy];
groupBy.forEach((group, i) => {
var lookupFunc, column;
if (typeof group == "function") lookupFunc = group;
else {
column = this.table.columnManager.getColumnByField(group);
if (column) lookupFunc = function(data) {
return column.getFieldValue(data);
};
else lookupFunc = function(data) {
return data[group];
};
}
this.groupIDLookups.push({
field: typeof group === "function" ? false : group,
func: lookupFunc,
values: this.allowedValues ? this.allowedValues[i] : false
});
});
if (startOpen) {
if (!Array.isArray(startOpen)) startOpen = [startOpen];
startOpen.forEach((level) => {});
this.startOpen = startOpen;
}
if (groupHeader) this.headerGenerator = Array.isArray(groupHeader) ? groupHeader : [groupHeader];
} else {
this.groupList = [];
this.groups = {};
}
}
rowSample(rows, prevValue) {
if (this.table.options.groupBy) {
var group = this.getGroups(false)[0];
prevValue.push(group.getRows(false)[0]);
}
return prevValue;
}
virtualRenderFill() {
var el = this.table.rowManager.tableElement;
var rows = this.table.rowManager.getVisibleRows();
if (this.table.options.groupBy) {
rows = rows.filter((row) => {
return row.type !== "group";
});
el.style.minWidth = !rows.length ? this.table.columnManager.getWidth() + "px" : "";
} else return rows;
}
rowAddingIndex(row, index, top) {
if (this.table.options.groupBy) {
this.assignRowToGroup(row);
var groupRows = row.modules.group.rows;
if (groupRows.length > 1) if (!index || index && groupRows.indexOf(index) == -1) {
if (top) {
if (groupRows[0] !== row) {
index = groupRows[0];
this.table.rowManager.moveRowInArray(row.modules.group.rows, row, index, !top);
}
} else if (groupRows[groupRows.length - 1] !== row) {
index = groupRows[groupRows.length - 1];
this.table.rowManager.moveRowInArray(row.modules.group.rows, row, index, !top);
}
} else this.table.rowManager.moveRowInArray(row.modules.group.rows, row, index, !top);
return index;
}
}
trackChanges() {
this.dispatch("group-changed");
}
setGroupBy(groups) {
this.table.options.groupBy = groups;
if (!this.initialized) this.initialize();
this.configureGroupSetup();
if (!groups && this.table.modExists("columnCalcs") && this.table.options.columnCalcs === true) this.table.modules.columnCalcs.reinitializeCalcs();
this.refreshData();
this.trackChanges();
}
setGroupValues(groupValues) {
this.table.options.groupValues = groupValues;
this.configureGroupSetup();
this.refreshData();
this.trackChanges();
}
setGroupStartOpen(values) {
this.table.options.groupStartOpen = values;
this.configureGroupSetup();
if (this.table.options.groupBy) {
this.refreshData();
this.trackChanges();
} else console.warn("Grouping Update - cant refresh view, no groups have been set");
}
setGroupHeader(values) {
this.table.options.groupHeader = values;
this.configureGroupSetup();
if (this.table.options.groupBy) {
this.refreshData();
this.trackChanges();
} else console.warn("Grouping Update - cant refresh view, no groups have been set");
}
userGetGroups(values) {
return this.getGroups(true);
}
userGetGroupedData() {
return this.table.options.groupBy ? this.getGroupedData() : this.getData();
}
rowGetGroup(row) {
return row.modules.group ? row.modules.group.getComponent() : false;
}
rowMoving(from, to, after) {
if (this.table.options.groupBy) {
if (!after && to instanceof Group) to = this.table.rowManager.prevDisplayRow(from) || to;
var toGroup = to instanceof Group ? to : to.modules.group;
var fromGroup = from instanceof Group ? from : from.modules.group;
if (toGroup === fromGroup) this.table.rowManager.moveRowInArray(toGroup.rows, from, to, after);
else {
if (fromGroup) fromGroup.removeRow(from);
toGroup.insertRow(from, to, after);
}
}
}
rowDeleting(row) {
if (this.table.options.groupBy && row.modules.group) row.modules.group.removeRow(row);
}
rowsUpdated(row) {
if (this.table.options.groupBy) this.updateGroupRows(true);
}
cellUpdated(cell) {
if (this.table.options.groupBy) this.reassignRowToGroup(cell.row);
}
getRows(rows) {
if (this.table.options.groupBy && this.groupIDLookups.length) {
this.dispatchExternal("dataGrouping");
this.generateGroups(rows);
if (this.subscribedExternal("dataGrouped")) this.dispatchExternal("dataGrouped", this.getGroups(true));
return this.updateGroupRows();
} else return rows.slice(0);
}
getGroups(component) {
var groupComponents = [];
this.groupList.forEach(function(group) {
groupComponents.push(component ? group.getComponent() : group);
});
return groupComponents;
}
getChildGroups(group) {
var groupComponents = [];
if (!group) group = this;
group.groupList.forEach((child) => {
if (child.groupList.length) groupComponents = groupComponents.concat(this.getChildGroups(child));
else groupComponents.push(child);
});
return groupComponents;
}
wipe() {
if (this.table.options.groupBy) {
this.groupList.forEach(function(group) {
group.wipe();
});
this.groupList = [];
this.groups = {};
}
}
pullGroupListData(groupList) {
var groupListData = [];
groupList.forEach((group) => {
var groupHeader = {};
groupHeader.level = 0;
groupHeader.rowCount = 0;
groupHeader.headerContent = "";
var childData = [];
if (group.hasSubGroups) {
childData = this.pullGroupListData(group.groupList);
groupHeader.level = group.level;
groupHeader.rowCount = childData.length - group.groupList.length;
groupHeader.headerContent = group.generator(group.key, groupHeader.rowCount, group.rows, group);
groupListData.push(groupHeader);
groupListData = groupListData.concat(childData);
} else {
groupHeader.level = group.level;
groupHeader.headerContent = group.generator(group.key, group.rows.length, group.rows, group);
groupHeader.rowCount = group.getRows().length;
groupListData.push(groupHeader);
group.getRows().forEach((row) => {
groupListData.push(row.getData("data"));
});
}
});
return groupListData;
}
getGroupedData() {
return this.pullGroupListData(this.groupList);
}
getRowGroup(row) {
var match = false;
if (this.options("dataTree")) row = this.table.modules.dataTree.getTreeParentRoot(row);
this.groupList.forEach((group) => {
var result = group.getRowGroup(row);
if (result) match = result;
});
return match;
}
countGroups() {
return this.groupList.length;
}
generateGroups(rows) {
var oldGroups = this.groups;
this.groups = {};
this.groupList = [];
if (this.allowedValues && this.allowedValues[0]) {
this.allowedValues[0].forEach((value) => {
this.createGroup(value, 0, oldGroups);
});
rows.forEach((row) => {
this.assignRowToExistingGroup(row, oldGroups);
});
} else rows.forEach((row) => {
this.assignRowToGroup(row, oldGroups);
});
Object.values(oldGroups).forEach((group) => {
group.wipe(true);
});
}
createGroup(groupID, level, oldGroups) {
var groupKey = level + "_" + groupID, group;
oldGroups = oldGroups || [];
group = new Group(this, false, level, groupID, this.groupIDLookups[0].field, this.headerGenerator[0], oldGroups[groupKey]);
this.groups[groupKey] = group;
this.groupList.push(group);
}
assignRowToExistingGroup(row, oldGroups) {
var groupKey = "0_" + this.groupIDLookups[0].func(row.getData());
if (this.groups[groupKey]) this.groups[groupKey].addRow(row);
}
assignRowToGroup(row, oldGroups) {
var groupID = this.groupIDLookups[0].func(row.getData()), newGroupNeeded = !this.groups["0_" + groupID];
if (newGroupNeeded) this.createGroup(groupID, 0, oldGroups);
this.groups["0_" + groupID].addRow(row);
return !newGroupNeeded;
}
reassignRowToGroup(row) {
if (row.type === "row") {
var oldRowGroup = row.modules.group, oldGroupPath = oldRowGroup.getPath(), newGroupPath = this.getExpectedPath(row);
if (!(oldGroupPath.length == newGroupPath.length && oldGroupPath.every((element, index) => {
return element === newGroupPath[index];
}))) {
oldRowGroup.removeRow(row);
this.assignRowToGroup(row, this.groups);
this.refreshData(true);
}
}
}
getExpectedPath(row) {
var groupPath = [], rowData = row.getData();
this.groupIDLookups.forEach((groupId) => {
groupPath.push(groupId.func(rowData));
});
return groupPath;
}
updateGroupRows(force) {
var output = [];
if (!this.blockRedraw) {
this.groupList.forEach((group) => {
output = output.concat(group.getHeadersAndRows());
});
if (force) this.refreshData(true);
}
return output;
}
scrollHeaders(left) {
if (this.table.options.groupBy) {
if (this.table.options.renderHorizontal === "virtual") left -= this.table.columnManager.renderer.vDomPadLeft;
left = left + "px";
this.groupList.forEach((group) => {
group.scrollHeader(left);
});
}
}
removeGroup(group) {
var groupKey = group.level + "_" + group.key, index;
if (this.groups[groupKey]) {
delete this.groups[groupKey];
index = this.groupList.indexOf(group);
if (index > -1) this.groupList.splice(index, 1);
}
}
checkBasicModeGroupHeaderWidth() {
var element = this.table.rowManager.tableElement, onlyGroupHeaders = true;
this.table.rowManager.getDisplayRows().forEach((row, index) => {
this.table.rowManager.styleRow(row, index);
element.appendChild(row.getElement());
row.initialize(true);
if (row.type !== "group") onlyGroupHeaders = false;
});
if (onlyGroupHeaders) element.style.minWidth = this.table.columnManager.getWidth() + "px";
else element.style.minWidth = "";
}
};
var defaultUndoers = {
cellEdit: function(action) {
action.component.setValueProcessData(action.data.oldValue);
action.component.cellRendered();
},
rowAdd: function(action) {
action.component.deleteActual();
this.table.rowManager.checkPlaceholder();
},
rowDelete: function(action) {
var newRow = this.table.rowManager.addRowActual(action.data.data, action.data.pos, action.data.index);
if (this.table.options.groupBy && this.table.modExists("groupRows")) this.table.modules.groupRows.updateGroupRows(true);
this._rebindRow(action.component, newRow);
this.table.rowManager.checkPlaceholder();
},
rowMove: function(action) {
var after = action.data.posFrom - action.data.posTo > 0;
this.table.rowManager.moveRowActual(action.component, this.table.rowManager.getRowFromPosition(action.data.posFrom), after);
this.table.rowManager.regenerateRowPositions();
this.table.rowManager.reRenderInPosition();
}
};
var defaultRedoers = {
cellEdit: function(action) {
action.component.setValueProcessData(action.data.newValue);
action.component.cellRendered();
},
rowAdd: function(action) {
var newRow = this.table.rowManager.addRowActual(action.data.data, action.data.pos, action.data.index);
if (this.table.options.groupBy && this.table.modExists("groupRows")) this.table.modules.groupRows.updateGroupRows(true);
this._rebindRow(action.component, newRow);
this.table.rowManager.checkPlaceholder();
},
rowDelete: function(action) {
action.component.deleteActual();
this.table.rowManager.checkPlaceholder();
},
rowMove: function(action) {
this.table.rowManager.moveRowActual(action.component, this.table.rowManager.getRowFromPosition(action.data.posTo), action.data.after);
this.table.rowManager.regenerateRowPositions();
this.table.rowManager.reRenderInPosition();
}
};
var extensions$3 = { keybindings: {
bindings: {
undo: ["ctrl + 90", "meta + 90"],
redo: ["ctrl + 89", "meta + 89"]
},
actions: {
undo: function(e) {
var cell = false;
if (this.table.options.history && this.table.modExists("history") && this.table.modExists("edit")) {
cell = this.table.modules.edit.currentCell;
if (!cell) {
e.preventDefault();
this.table.modules.history.undo();
}
}
},
redo: function(e) {
var cell = false;
if (this.table.options.history && this.table.modExists("history") && this.table.modExists("edit")) {
cell = this.table.modules.edit.currentCell;
if (!cell) {
e.preventDefault();
this.table.modules.history.redo();
}
}
}
}
} };
var History = class History extends Module {
static moduleName = "history";
static moduleExtensions = extensions$3;
static undoers = defaultUndoers;
static redoers = defaultRedoers;
constructor(table) {
super(table);
this.history = [];
this.index = -1;
this.registerTableOption("history", false);
}
initialize() {
if (this.table.options.history) {
this.subscribe("cell-value-updated", this.cellUpdated.bind(this));
this.subscribe("cell-delete", this.clearComponentHistory.bind(this));
this.subscribe("row-delete", this.rowDeleted.bind(this));
this.subscribe("rows-wipe", this.clear.bind(this));
this.subscribe("row-added", this.rowAdded.bind(this));
this.subscribe("row-move", this.rowMoved.bind(this));
}
this.registerTableFunction("undo", this.undo.bind(this));
this.registerTableFunction("redo", this.redo.bind(this));
this.registerTableFunction("getHistoryUndoSize", this.getHistoryUndoSize.bind(this));
this.registerTableFunction("getHistoryRedoSize", this.getHistoryRedoSize.bind(this));
this.registerTableFunction("clearHistory", this.clear.bind(this));
}
rowMoved(from, to, after) {
this.action("rowMove", from, {
posFrom: from.getPosition(),
posTo: to.getPosition(),
to,
after
});
}
rowAdded(row, data, pos, index) {
this.action("rowAdd", row, {
data,
pos,
index
});
}
rowDeleted(row) {
var index, rows;
if (this.table.options.groupBy) {
rows = row.getComponent().getGroup()._getSelf().rows;
index = rows.indexOf(row);
if (index) index = rows[index - 1];
} else {
index = row.table.rowManager.getRowIndex(row);
if (index) index = row.table.rowManager.rows[index - 1];
}
this.action("rowDelete", row, {
data: row.getData(),
pos: !index,
index
});
}
cellUpdated(cell) {
this.action("cellEdit", cell, {
oldValue: cell.oldValue,
newValue: cell.value
});
}
clear() {
this.history = [];
this.index = -1;
}
action(type, component, data) {
this.history = this.history.slice(0, this.index + 1);
this.history.push({
type,
component,
data
});
this.index++;
}
getHistoryUndoSize() {
return this.index + 1;
}
getHistoryRedoSize() {
return this.history.length - (this.index + 1);
}
clearComponentHistory(component) {
var index = this.history.findIndex(function(item) {
return item.component === component;
});
if (index > -1) {
this.history.splice(index, 1);
if (index <= this.index) this.index--;
this.clearComponentHistory(component);
}
}
undo() {
if (this.index > -1) {
let action = this.history[this.index];
History.undoers[action.type].call(this, action);
this.index--;
this.dispatchExternal("historyUndo", action.type, action.component.getComponent(), action.data);
return true;
} else {
console.warn(this.options("history") ? "History Undo Error - No more history to undo" : "History module not enabled");
return false;
}
}
redo() {
if (this.history.length - 1 > this.index) {
this.index++;
let action = this.history[this.index];
History.redoers[action.type].call(this, action);
this.dispatchExternal("historyRedo", action.type, action.component.getComponent(), action.data);
return true;
} else {
console.warn(this.options("history") ? "History Redo Error - No more history to redo" : "History module not enabled");
return false;
}
}
_rebindRow(oldRow, newRow) {
this.history.forEach(function(action) {
if (action.component instanceof Row) {
if (action.component === oldRow) action.component = newRow;
} else if (action.component instanceof Cell) {
if (action.component.row === oldRow) {
var field = action.component.column.getField();
if (field) action.component = newRow.getCell(field);
}
}
});
}
};
var HtmlTableImport = class extends Module {
static moduleName = "htmlTableImport";
constructor(table) {
super(table);
this.fieldIndex = [];
this.hasIndex = false;
}
initialize() {
this.tableElementCheck();
}
tableElementCheck() {
if (this.table.originalElement && this.table.originalElement.tagName === "TABLE") if (this.table.originalElement.childNodes.length) this.parseTable();
else console.warn("Unable to parse data from empty table tag, Tabulator should be initialized on a div tag unless importing data from a table element.");
}
parseTable() {
var element = this.table.originalElement, options = this.table.options, headers = element.getElementsByTagName("th"), rows = element.getElementsByTagName("tbody")[0], data = [];
this.hasIndex = false;
this.dispatchExternal("htmlImporting");
rows = rows ? rows.getElementsByTagName("tr") : [];
this._extractOptions(element, options);
if (headers.length) this._extractHeaders(headers, rows);
else this._generateBlankHeaders(headers, rows);
for (var index = 0; index < rows.length; index++) {
var cells = rows[index].getElementsByTagName("td"), item = {};
if (!this.hasIndex) item[options.index] = index;
for (var i = 0; i < cells.length; i++) {
var cell = cells[i];
if (typeof this.fieldIndex[i] !== "undefined") item[this.fieldIndex[i]] = cell.innerHTML;
}
data.push(item);
}
options.data = data;
this.dispatchExternal("htmlImported");
}
_extractOptions(element, options, defaultOptions) {
var attributes = element.attributes;
var optionsArr = defaultOptions ? Object.keys(defaultOptions) : Object.keys(options);
var optionsList = {};
optionsArr.forEach((item) => {
optionsList[item.toLowerCase()] = item;
});
for (var index in attributes) {
var attrib = attributes[index];
var name;
if (attrib && typeof attrib == "object" && attrib.name && attrib.name.indexOf("tabulator-") === 0) {
name = attrib.name.replace("tabulator-", "");
if (typeof optionsList[name] !== "undefined") options[optionsList[name]] = this._attribValue(attrib.value);
}
}
}
_attribValue(value) {
if (value === "true") return true;
if (value === "false") return false;
return value;
}
_findCol(title) {
return this.table.options.columns.find((column) => {
return column.title === title;
}) || false;
}
_extractHeaders(headers, rows) {
for (var index = 0; index < headers.length; index++) {
var header = headers[index], exists = false, col = this._findCol(header.textContent), width;
if (col) exists = true;
else col = { title: header.textContent.trim() };
if (!col.field) col.field = header.textContent.trim().toLowerCase().replaceAll(" ", "_");
width = header.getAttribute("width");
if (width && !col.width) col.width = width;
this._extractOptions(header, col, this.table.columnManager.optionsList.registeredDefaults);
this.fieldIndex[index] = col.field;
if (col.field == this.table.options.index) this.hasIndex = true;
if (!exists) this.table.options.columns.push(col);
}
}
_generateBlankHeaders(headers, rows) {
for (var index = 0; index < headers.length; index++) {
var header = headers[index], col = {
title: "",
field: "col" + index
};
this.fieldIndex[index] = col.field;
var width = header.getAttribute("width");
if (width) col.width = width;
this.table.options.columns.push(col);
}
}
};
function csv(input) {
var data = [], row = 0, col = 0, inQuote = false;
for (let index = 0; index < input.length; index++) {
let char = input[index], nextChar = input[index + 1];
if (!data[row]) data[row] = [];
if (!data[row][col]) data[row][col] = "";
if (char == "\"" && inQuote && nextChar == "\"") {
data[row][col] += char;
index++;
continue;
}
if (char == "\"") {
inQuote = !inQuote;
continue;
}
if (char == "," && !inQuote) {
col++;
continue;
}
if (char == "\r" && nextChar == "\n" && !inQuote) {
col = 0;
row++;
index++;
continue;
}
if ((char == "\r" || char == "\n") && !inQuote) {
col = 0;
row++;
continue;
}
data[row][col] += char;
}
return data;
}
function json(input) {
try {
return JSON.parse(input);
} catch (e) {
console.warn("JSON Import Error - File contents is invalid JSON", e);
return Promise.reject();
}
}
function array$1(input) {
return input;
}
function xlsx(input) {
var XLSXLib = this.dependencyRegistry.lookup("XLSX"), workbook2 = XLSXLib.read(input), sheet = workbook2.Sheets[workbook2.SheetNames[0]];
return XLSXLib.utils.sheet_to_json(sheet, { header: 1 });
}
var defaultImporters = {
csv,
json,
array: array$1,
xlsx
};
var Import = class Import extends Module {
static moduleName = "import";
static importers = defaultImporters;
constructor(table) {
super(table);
this.registerTableOption("importFormat");
this.registerTableOption("importReader", "text");
this.registerTableOption("importHeaderTransform");
this.registerTableOption("importValueTransform");
this.registerTableOption("importDataValidator");
this.registerTableOption("importFileValidator");
}
initialize() {
this.registerTableFunction("import", this.importFromFile.bind(this));
if (this.table.options.importFormat) {
this.subscribe("data-loading", this.loadDataCheck.bind(this), 10);
this.subscribe("data-load", this.loadData.bind(this), 10);
}
}
loadDataCheck(data) {
return this.table.options.importFormat && (typeof data === "string" || Array.isArray(data) && data.length && Array.isArray(data));
}
loadData(data, params, config, silent, previousData) {
return this.importData(this.lookupImporter(), data).then(this.structureData.bind(this)).catch((err) => {
console.error("Import Error:", err || "Unable to import data");
return Promise.reject(err);
});
}
lookupImporter(importFormat) {
var importer;
if (!importFormat) importFormat = this.table.options.importFormat;
if (typeof importFormat === "string") importer = Import.importers[importFormat];
else importer = importFormat;
if (!importer) console.error("Import Error - Importer not found:", importFormat);
return importer;
}
importFromFile(importFormat, extension, importReader) {
var importer = this.lookupImporter(importFormat);
if (importer) return this.pickFile(extension, importReader).then(this.importData.bind(this, importer)).then(this.structureData.bind(this)).then(this.mutateData.bind(this)).then(this.validateData.bind(this)).then(this.setData.bind(this)).catch((err) => {
this.dispatch("import-error", err);
this.dispatchExternal("importError", err);
console.error("Import Error:", err || "Unable to import file");
this.table.dataLoader.alertError();
setTimeout(() => {
this.table.dataLoader.clearAlert();
}, 3e3);
return Promise.reject(err);
});
}
pickFile(extensions, importReader) {
return new Promise((resolve, reject) => {
var input = document.createElement("input");
input.type = "file";
input.accept = extensions;
input.addEventListener("change", (e) => {
var file = input.files[0], reader = new FileReader(), valid = this.validateFile(file);
if (valid === true) {
this.dispatch("import-importing", input.files);
this.dispatchExternal("importImporting", input.files);
switch (importReader || this.table.options.importReader) {
case "buffer":
reader.readAsArrayBuffer(file);
break;
case "binary":
reader.readAsBinaryString(file);
break;
case "url":
reader.readAsDataURL(file);
break;
default: reader.readAsText(file);
}
reader.onload = (e) => {
resolve(reader.result);
};
reader.onerror = (e) => {
console.warn("File Load Error - Unable to read file");
reject(e);
};
} else reject(valid);
});
this.dispatch("import-choose");
this.dispatchExternal("importChoose");
input.click();
});
}
importData(importer, fileContents) {
var data;
this.table.dataLoader.alertLoader();
return new Promise((resolve, reject) => {
setTimeout(() => {
data = importer.call(this.table, fileContents);
if (data instanceof Promise) resolve(data);
else data ? resolve(data) : reject();
}, 10);
});
}
structureData(parsedData) {
var data = [];
if (Array.isArray(parsedData) && parsedData.length && Array.isArray(parsedData[0])) {
if (this.table.options.autoColumns) data = this.structureArrayToObject(parsedData);
else data = this.structureArrayToColumns(parsedData);
return data;
} else return parsedData;
}
mutateData(data) {
var output = [];
if (Array.isArray(data)) data.forEach((row) => {
output.push(this.table.modules.mutator.transformRow(row, "import"));
});
else output = data;
return output;
}
transformHeader(headers) {
var output = [];
if (this.table.options.importHeaderTransform) headers.forEach((item) => {
output.push(this.table.options.importHeaderTransform.call(this.table, item, headers));
});
else return headers;
return output;
}
transformData(row) {
var output = [];
if (this.table.options.importValueTransform) row.forEach((item) => {
output.push(this.table.options.importValueTransform.call(this.table, item, row));
});
else return row;
return output;
}
structureArrayToObject(parsedData) {
var columns = this.transformHeader(parsedData.shift());
return parsedData.map((values) => {
var row = {};
values = this.transformData(values);
columns.forEach((key, i) => {
row[key] = values[i];
});
return row;
});
}
structureArrayToColumns(parsedData) {
var data = [], firstRow = this.transformHeader(parsedData[0]), columns = this.table.getColumns();
if (columns[0] && firstRow[0]) {
if (columns[0].getDefinition().title === firstRow[0]) parsedData.shift();
}
parsedData.forEach((rowData) => {
var row = {};
rowData = this.transformData(rowData);
rowData.forEach((value, index) => {
var column = columns[index];
if (column) row[column.getField()] = value;
});
data.push(row);
});
return data;
}
validateFile(file) {
if (this.table.options.importFileValidator) return this.table.options.importFileValidator.call(this.table, file);
return true;
}
validateData(data) {
var result;
if (this.table.options.importDataValidator) {
result = this.table.options.importDataValidator.call(this.table, data);
if (result === true) return data;
else return Promise.reject(result);
}
return data;
}
setData(data) {
this.dispatch("import-imported", data);
this.dispatchExternal("importImported", data);
this.table.dataLoader.clearAlert();
return this.table.setData(data);
}
};
var Interaction = class extends Module {
static moduleName = "interaction";
constructor(table) {
super(table);
this.eventMap = {
rowClick: "row-click",
rowDblClick: "row-dblclick",
rowContext: "row-contextmenu",
rowMouseEnter: "row-mouseenter",
rowMouseLeave: "row-mouseleave",
rowMouseOver: "row-mouseover",
rowMouseOut: "row-mouseout",
rowMouseMove: "row-mousemove",
rowMouseDown: "row-mousedown",
rowMouseUp: "row-mouseup",
rowTap: "row",
rowDblTap: "row",
rowTapHold: "row",
cellClick: "cell-click",
cellDblClick: "cell-dblclick",
cellContext: "cell-contextmenu",
cellMouseEnter: "cell-mouseenter",
cellMouseLeave: "cell-mouseleave",
cellMouseOver: "cell-mouseover",
cellMouseOut: "cell-mouseout",
cellMouseMove: "cell-mousemove",
cellMouseDown: "cell-mousedown",
cellMouseUp: "cell-mouseup",
cellTap: "cell",
cellDblTap: "cell",
cellTapHold: "cell",
headerClick: "column-click",
headerDblClick: "column-dblclick",
headerContext: "column-contextmenu",
headerMouseEnter: "column-mouseenter",
headerMouseLeave: "column-mouseleave",
headerMouseOver: "column-mouseover",
headerMouseOut: "column-mouseout",
headerMouseMove: "column-mousemove",
headerMouseDown: "column-mousedown",
headerMouseUp: "column-mouseup",
headerTap: "column",
headerDblTap: "column",
headerTapHold: "column",
groupClick: "group-click",
groupDblClick: "group-dblclick",
groupContext: "group-contextmenu",
groupMouseEnter: "group-mouseenter",
groupMouseLeave: "group-mouseleave",
groupMouseOver: "group-mouseover",
groupMouseOut: "group-mouseout",
groupMouseMove: "group-mousemove",
groupMouseDown: "group-mousedown",
groupMouseUp: "group-mouseup",
groupTap: "group",
groupDblTap: "group",
groupTapHold: "group"
};
this.subscribers = {};
this.touchSubscribers = {};
this.columnSubscribers = {};
this.touchWatchers = {
row: {
tap: null,
tapDbl: null,
tapHold: null
},
cell: {
tap: null,
tapDbl: null,
tapHold: null
},
column: {
tap: null,
tapDbl: null,
tapHold: null
},
group: {
tap: null,
tapDbl: null,
tapHold: null
}
};
this.registerColumnOption("headerClick");
this.registerColumnOption("headerDblClick");
this.registerColumnOption("headerContext");
this.registerColumnOption("headerMouseEnter");
this.registerColumnOption("headerMouseLeave");
this.registerColumnOption("headerMouseOver");
this.registerColumnOption("headerMouseOut");
this.registerColumnOption("headerMouseMove");
this.registerColumnOption("headerMouseDown");
this.registerColumnOption("headerMouseUp");
this.registerColumnOption("headerTap");
this.registerColumnOption("headerDblTap");
this.registerColumnOption("headerTapHold");
this.registerColumnOption("cellClick");
this.registerColumnOption("cellDblClick");
this.registerColumnOption("cellContext");
this.registerColumnOption("cellMouseEnter");
this.registerColumnOption("cellMouseLeave");
this.registerColumnOption("cellMouseOver");
this.registerColumnOption("cellMouseOut");
this.registerColumnOption("cellMouseMove");
this.registerColumnOption("cellMouseDown");
this.registerColumnOption("cellMouseUp");
this.registerColumnOption("cellTap");
this.registerColumnOption("cellDblTap");
this.registerColumnOption("cellTapHold");
}
initialize() {
this.initializeExternalEvents();
this.subscribe("column-init", this.initializeColumn.bind(this));
this.subscribe("cell-dblclick", this.cellContentsSelectionFixer.bind(this));
this.subscribe("scroll-horizontal", this.clearTouchWatchers.bind(this));
this.subscribe("scroll-vertical", this.clearTouchWatchers.bind(this));
}
clearTouchWatchers() {
Object.values(this.touchWatchers).forEach((type) => {
for (let key in type) type[key] = null;
});
}
cellContentsSelectionFixer(e, cell) {
var range;
if (this.table.modExists("edit")) {
if (this.table.modules.edit.currentCell === cell) return;
}
e.preventDefault();
try {
if (document.selection) {
range = document.body.createTextRange();
range.moveToElementText(cell.getElement());
range.select();
} else if (window.getSelection) {
range = document.createRange();
range.selectNode(cell.getElement());
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
}
} catch (e) {}
}
initializeExternalEvents() {
for (let key in this.eventMap) this.subscriptionChangeExternal(key, this.subscriptionChanged.bind(this, key));
}
subscriptionChanged(key, added) {
if (added) {
if (!this.subscribers[key]) if (this.eventMap[key].includes("-")) {
this.subscribers[key] = this.handle.bind(this, key);
this.subscribe(this.eventMap[key], this.subscribers[key]);
} else this.subscribeTouchEvents(key);
} else if (this.eventMap[key].includes("-")) {
if (this.subscribers[key] && !this.columnSubscribers[key] && !this.subscribedExternal(key)) {
this.unsubscribe(this.eventMap[key], this.subscribers[key]);
delete this.subscribers[key];
}
} else this.unsubscribeTouchEvents(key);
}
subscribeTouchEvents(key) {
var type = this.eventMap[key];
if (!this.touchSubscribers[type + "-touchstart"]) {
this.touchSubscribers[type + "-touchstart"] = this.handleTouch.bind(this, type, "start");
this.touchSubscribers[type + "-touchend"] = this.handleTouch.bind(this, type, "end");
this.subscribe(type + "-touchstart", this.touchSubscribers[type + "-touchstart"]);
this.subscribe(type + "-touchend", this.touchSubscribers[type + "-touchend"]);
}
this.subscribers[key] = true;
}
unsubscribeTouchEvents(key) {
var noTouch = true, type = this.eventMap[key];
if (this.subscribers[key] && !this.subscribedExternal(key)) {
delete this.subscribers[key];
for (let i in this.eventMap) if (this.eventMap[i] === type) {
if (this.subscribers[i]) noTouch = false;
}
if (noTouch) {
this.unsubscribe(type + "-touchstart", this.touchSubscribers[type + "-touchstart"]);
this.unsubscribe(type + "-touchend", this.touchSubscribers[type + "-touchend"]);
delete this.touchSubscribers[type + "-touchstart"];
delete this.touchSubscribers[type + "-touchend"];
}
}
}
initializeColumn(column) {
var def = column.definition;
for (let key in this.eventMap) if (def[key]) {
this.subscriptionChanged(key, true);
if (!this.columnSubscribers[key]) this.columnSubscribers[key] = [];
this.columnSubscribers[key].push(column);
}
}
handle(action, e, component) {
this.dispatchEvent(action, e, component);
}
handleTouch(type, action, e, component) {
var watchers = this.touchWatchers[type];
if (type === "column") type = "header";
switch (action) {
case "start":
watchers.tap = true;
clearTimeout(watchers.tapHold);
watchers.tapHold = setTimeout(() => {
clearTimeout(watchers.tapHold);
watchers.tapHold = null;
watchers.tap = null;
clearTimeout(watchers.tapDbl);
watchers.tapDbl = null;
this.dispatchEvent(type + "TapHold", e, component);
}, 1e3);
break;
case "end":
if (watchers.tap) {
watchers.tap = null;
this.dispatchEvent(type + "Tap", e, component);
}
if (watchers.tapDbl) {
clearTimeout(watchers.tapDbl);
watchers.tapDbl = null;
this.dispatchEvent(type + "DblTap", e, component);
} else watchers.tapDbl = setTimeout(() => {
clearTimeout(watchers.tapDbl);
watchers.tapDbl = null;
}, 300);
clearTimeout(watchers.tapHold);
watchers.tapHold = null;
break;
}
}
dispatchEvent(action, e, component) {
var componentObj = component.getComponent(), callback;
if (this.columnSubscribers[action]) {
if (component instanceof Cell) callback = component.column.definition[action];
else if (component instanceof Column) callback = component.definition[action];
if (callback) callback(e, componentObj);
}
this.dispatchExternal(action, e, componentObj);
}
};
var defaultBindings = {
navPrev: "shift + 9",
navNext: 9,
navUp: 38,
navDown: 40,
navLeft: 37,
navRight: 39,
scrollPageUp: 33,
scrollPageDown: 34,
scrollToStart: 36,
scrollToEnd: 35
};
var defaultActions = {
keyBlock: function(e) {
e.stopPropagation();
e.preventDefault();
},
scrollPageUp: function(e) {
var rowManager = this.table.rowManager, newPos = rowManager.scrollTop - rowManager.element.clientHeight;
e.preventDefault();
if (rowManager.displayRowsCount) if (newPos >= 0) rowManager.element.scrollTop = newPos;
else rowManager.scrollToRow(rowManager.getDisplayRows()[0]);
this.table.element.focus();
},
scrollPageDown: function(e) {
var rowManager = this.table.rowManager, newPos = rowManager.scrollTop + rowManager.element.clientHeight, scrollMax = rowManager.element.scrollHeight;
e.preventDefault();
if (rowManager.displayRowsCount) if (newPos <= scrollMax) rowManager.element.scrollTop = newPos;
else rowManager.scrollToRow(rowManager.getDisplayRows()[rowManager.displayRowsCount - 1]);
this.table.element.focus();
},
scrollToStart: function(e) {
var rowManager = this.table.rowManager;
e.preventDefault();
if (rowManager.displayRowsCount) rowManager.scrollToRow(rowManager.getDisplayRows()[0]);
this.table.element.focus();
},
scrollToEnd: function(e) {
var rowManager = this.table.rowManager;
e.preventDefault();
if (rowManager.displayRowsCount) rowManager.scrollToRow(rowManager.getDisplayRows()[rowManager.displayRowsCount - 1]);
this.table.element.focus();
},
navPrev: function(e) {
this.dispatch("keybinding-nav-prev", e);
},
navNext: function(e) {
this.dispatch("keybinding-nav-next", e);
},
navLeft: function(e) {
this.dispatch("keybinding-nav-left", e);
},
navRight: function(e) {
this.dispatch("keybinding-nav-right", e);
},
navUp: function(e) {
this.dispatch("keybinding-nav-up", e);
},
navDown: function(e) {
this.dispatch("keybinding-nav-down", e);
}
};
var Keybindings = class Keybindings extends Module {
static moduleName = "keybindings";
static bindings = defaultBindings;
static actions = defaultActions;
constructor(table) {
super(table);
this.watchKeys = null;
this.pressedKeys = null;
this.keyupBinding = false;
this.keydownBinding = false;
this.registerTableOption("keybindings", {});
this.registerTableOption("tabEndNewRow", false);
}
initialize() {
var bindings = this.table.options.keybindings, mergedBindings = {};
this.watchKeys = {};
this.pressedKeys = [];
if (bindings !== false) {
Object.assign(mergedBindings, Keybindings.bindings);
Object.assign(mergedBindings, bindings);
this.mapBindings(mergedBindings);
this.bindEvents();
}
this.subscribe("table-destroy", this.clearBindings.bind(this));
}
mapBindings(bindings) {
for (let key in bindings) if (Keybindings.actions[key]) {
if (bindings[key]) {
if (typeof bindings[key] !== "object") bindings[key] = [bindings[key]];
bindings[key].forEach((binding) => {
(Array.isArray(binding) ? binding : [binding]).forEach((item) => {
this.mapBinding(key, item);
});
});
}
} else console.warn("Key Binding Error - no such action:", key);
}
mapBinding(action, symbolsList) {
var binding = {
action: Keybindings.actions[action],
keys: [],
ctrl: false,
shift: false,
meta: false
};
symbolsList.toString().toLowerCase().split(" ").join("").split("+").forEach((symbol) => {
switch (symbol) {
case "ctrl":
binding.ctrl = true;
break;
case "shift":
binding.shift = true;
break;
case "meta":
binding.meta = true;
break;
default:
symbol = isNaN(symbol) ? symbol.toUpperCase().charCodeAt(0) : parseInt(symbol);
binding.keys.push(symbol);
if (!this.watchKeys[symbol]) this.watchKeys[symbol] = [];
this.watchKeys[symbol].push(binding);
}
});
}
bindEvents() {
var self = this;
this.keyupBinding = function(e) {
var code = e.keyCode;
var bindings = self.watchKeys[code];
if (bindings) {
self.pressedKeys.push(code);
bindings.forEach(function(binding) {
self.checkBinding(e, binding);
});
}
};
this.keydownBinding = function(e) {
var code = e.keyCode;
if (self.watchKeys[code]) {
var index = self.pressedKeys.indexOf(code);
if (index > -1) self.pressedKeys.splice(index, 1);
}
};
this.table.element.addEventListener("keydown", this.keyupBinding);
this.table.element.addEventListener("keyup", this.keydownBinding);
}
clearBindings() {
if (this.keyupBinding) this.table.element.removeEventListener("keydown", this.keyupBinding);
if (this.keydownBinding) this.table.element.removeEventListener("keyup", this.keydownBinding);
}
checkBinding(e, binding) {
var match = true;
if (e.ctrlKey == binding.ctrl && e.shiftKey == binding.shift && e.metaKey == binding.meta) {
binding.keys.forEach((key) => {
if (this.pressedKeys.indexOf(key) == -1) match = false;
});
if (match) binding.action.call(this, e);
return true;
}
return false;
}
};
var Menu = class extends Module {
static moduleName = "menu";
constructor(table) {
super(table);
this.menuContainer = null;
this.nestedMenuBlock = false;
this.currentComponent = null;
this.rootPopup = null;
this.columnSubscribers = {};
this.registerTableOption("rowContextMenu", false);
this.registerTableOption("rowClickMenu", false);
this.registerTableOption("rowDblClickMenu", false);
this.registerTableOption("groupContextMenu", false);
this.registerTableOption("groupClickMenu", false);
this.registerTableOption("groupDblClickMenu", false);
this.registerColumnOption("headerContextMenu");
this.registerColumnOption("headerClickMenu");
this.registerColumnOption("headerDblClickMenu");
this.registerColumnOption("headerMenu");
this.registerColumnOption("headerMenuIcon");
this.registerColumnOption("contextMenu");
this.registerColumnOption("clickMenu");
this.registerColumnOption("dblClickMenu");
}
initialize() {
this.deprecatedOptionsCheck();
this.initializeRowWatchers();
this.initializeGroupWatchers();
this.subscribe("column-init", this.initializeColumn.bind(this));
}
deprecatedOptionsCheck() {}
initializeRowWatchers() {
if (this.table.options.rowContextMenu) {
this.subscribe("row-contextmenu", this.loadMenuEvent.bind(this, this.table.options.rowContextMenu));
this.table.on("rowTapHold", this.loadMenuEvent.bind(this, this.table.options.rowContextMenu));
}
if (this.table.options.rowClickMenu) this.subscribe("row-click", this.loadMenuEvent.bind(this, this.table.options.rowClickMenu));
if (this.table.options.rowDblClickMenu) this.subscribe("row-dblclick", this.loadMenuEvent.bind(this, this.table.options.rowDblClickMenu));
}
initializeGroupWatchers() {
if (this.table.options.groupContextMenu) {
this.subscribe("group-contextmenu", this.loadMenuEvent.bind(this, this.table.options.groupContextMenu));
this.table.on("groupTapHold", this.loadMenuEvent.bind(this, this.table.options.groupContextMenu));
}
if (this.table.options.groupClickMenu) this.subscribe("group-click", this.loadMenuEvent.bind(this, this.table.options.groupClickMenu));
if (this.table.options.groupDblClickMenu) this.subscribe("group-dblclick", this.loadMenuEvent.bind(this, this.table.options.groupDblClickMenu));
}
initializeColumn(column) {
var def = column.definition;
if (def.headerContextMenu && !this.columnSubscribers.headerContextMenu) {
this.columnSubscribers.headerContextMenu = this.loadMenuTableColumnEvent.bind(this, "headerContextMenu");
this.subscribe("column-contextmenu", this.columnSubscribers.headerContextMenu);
this.table.on("headerTapHold", this.loadMenuTableColumnEvent.bind(this, "headerContextMenu"));
}
if (def.headerClickMenu && !this.columnSubscribers.headerClickMenu) {
this.columnSubscribers.headerClickMenu = this.loadMenuTableColumnEvent.bind(this, "headerClickMenu");
this.subscribe("column-click", this.columnSubscribers.headerClickMenu);
}
if (def.headerDblClickMenu && !this.columnSubscribers.headerDblClickMenu) {
this.columnSubscribers.headerDblClickMenu = this.loadMenuTableColumnEvent.bind(this, "headerDblClickMenu");
this.subscribe("column-dblclick", this.columnSubscribers.headerDblClickMenu);
}
if (def.headerMenu) this.initializeColumnHeaderMenu(column);
if (def.contextMenu && !this.columnSubscribers.contextMenu) {
this.columnSubscribers.contextMenu = this.loadMenuTableCellEvent.bind(this, "contextMenu");
this.subscribe("cell-contextmenu", this.columnSubscribers.contextMenu);
this.table.on("cellTapHold", this.loadMenuTableCellEvent.bind(this, "contextMenu"));
}
if (def.clickMenu && !this.columnSubscribers.clickMenu) {
this.columnSubscribers.clickMenu = this.loadMenuTableCellEvent.bind(this, "clickMenu");
this.subscribe("cell-click", this.columnSubscribers.clickMenu);
}
if (def.dblClickMenu && !this.columnSubscribers.dblClickMenu) {
this.columnSubscribers.dblClickMenu = this.loadMenuTableCellEvent.bind(this, "dblClickMenu");
this.subscribe("cell-dblclick", this.columnSubscribers.dblClickMenu);
}
}
initializeColumnHeaderMenu(column) {
var icon = column.definition.headerMenuIcon, headerMenuEl = document.createElement("span");
headerMenuEl.classList.add("tabulator-header-popup-button");
if (icon) {
if (typeof icon === "function") icon = icon(column.getComponent());
if (icon instanceof HTMLElement) headerMenuEl.appendChild(icon);
else headerMenuEl.innerHTML = icon;
} else headerMenuEl.innerHTML = "⋮";
headerMenuEl.addEventListener("click", (e) => {
e.stopPropagation();
e.preventDefault();
this.loadMenuEvent(column.definition.headerMenu, e, column);
});
column.titleElement.insertBefore(headerMenuEl, column.titleElement.firstChild);
}
loadMenuTableCellEvent(option, e, cell) {
if (cell._cell) cell = cell._cell;
if (cell.column.definition[option]) this.loadMenuEvent(cell.column.definition[option], e, cell);
}
loadMenuTableColumnEvent(option, e, column) {
if (column._column) column = column._column;
if (column.definition[option]) this.loadMenuEvent(column.definition[option], e, column);
}
loadMenuEvent(menu, e, component) {
if (component._group) component = component._group;
else if (component._row) component = component._row;
menu = typeof menu == "function" ? menu.call(this.table, e, component.getComponent()) : menu;
this.loadMenu(e, component, menu);
}
loadMenu(e, component, menu, parentEl, parentPopup) {
var touch = !(e instanceof MouseEvent), menuEl = document.createElement("div"), popup;
menuEl.classList.add("tabulator-menu");
if (!touch) e.preventDefault();
if (!menu || !menu.length) return;
if (!parentEl) {
if (this.nestedMenuBlock) {
if (this.rootPopup) return;
} else this.nestedMenuBlock = setTimeout(() => {
this.nestedMenuBlock = false;
}, 100);
if (this.rootPopup) this.rootPopup.hide();
this.rootPopup = popup = this.popup(menuEl);
} else popup = parentPopup.child(menuEl);
menu.forEach((item) => {
var itemEl = document.createElement("div"), label = item.label, disabled = item.disabled;
if (item.separator) itemEl.classList.add("tabulator-menu-separator");
else {
itemEl.classList.add("tabulator-menu-item");
if (typeof label == "function") label = label.call(this.table, component.getComponent());
if (label instanceof Node) itemEl.appendChild(label);
else itemEl.innerHTML = label;
if (typeof disabled == "function") disabled = disabled.call(this.table, component.getComponent());
if (disabled) {
itemEl.classList.add("tabulator-menu-item-disabled");
itemEl.addEventListener("click", (e) => {
e.stopPropagation();
});
} else if (item.menu && item.menu.length) itemEl.addEventListener("click", (e) => {
e.stopPropagation();
this.loadMenu(e, component, item.menu, itemEl, popup);
});
else if (item.action) itemEl.addEventListener("click", (e) => {
item.action(e, component.getComponent());
});
if (item.menu && item.menu.length) itemEl.classList.add("tabulator-menu-item-submenu");
}
menuEl.appendChild(itemEl);
});
menuEl.addEventListener("click", (e) => {
if (this.rootPopup) this.rootPopup.hide();
});
popup.show(parentEl || e);
if (popup === this.rootPopup) {
this.rootPopup.hideOnBlur(() => {
this.rootPopup = null;
if (this.currentComponent) {
this.dispatch("menu-closed", menu, popup);
this.dispatchExternal("menuClosed", this.currentComponent.getComponent());
this.currentComponent = null;
}
});
this.currentComponent = component;
this.dispatch("menu-opened", menu, popup);
this.dispatchExternal("menuOpened", component.getComponent());
}
}
};
var MoveColumns = class extends Module {
static moduleName = "moveColumn";
constructor(table) {
super(table);
this.placeholderElement = this.createPlaceholderElement();
this.hoverElement = false;
this.checkTimeout = false;
this.checkPeriod = 250;
this.moving = false;
this.toCol = false;
this.toColAfter = false;
this.startX = 0;
this.autoScrollMargin = 40;
this.autoScrollStep = 5;
this.autoScrollTimeout = false;
this.touchMove = false;
this.moveHover = this.moveHover.bind(this);
this.endMove = this.endMove.bind(this);
this.registerTableOption("movableColumns", false);
}
createPlaceholderElement() {
var el = document.createElement("div");
el.classList.add("tabulator-col");
el.classList.add("tabulator-col-placeholder");
return el;
}
initialize() {
if (this.table.options.movableColumns) {
this.subscribe("column-init", this.initializeColumn.bind(this));
this.subscribe("alert-show", this.abortMove.bind(this));
}
}
abortMove() {
clearTimeout(this.checkTimeout);
}
initializeColumn(column) {
var self = this, config = {}, colEl;
if (!column.modules.frozen && !column.isGroup && !column.isRowHeader) {
colEl = column.getElement();
config.mousemove = function(e) {
if (column.parent === self.moving.parent) {
if ((self.touchMove ? e.touches[0].pageX : e.pageX) - Helpers.elOffset(colEl).left + self.table.columnManager.contentsElement.scrollLeft > column.getWidth() / 2) {
if (self.toCol !== column || !self.toColAfter) {
colEl.parentNode.insertBefore(self.placeholderElement, colEl.nextSibling);
self.moveColumn(column, true);
}
} else if (self.toCol !== column || self.toColAfter) {
colEl.parentNode.insertBefore(self.placeholderElement, colEl);
self.moveColumn(column, false);
}
}
}.bind(self);
colEl.addEventListener("mousedown", function(e) {
self.touchMove = false;
if (e.which === 1) self.checkTimeout = setTimeout(function() {
self.startMove(e, column);
}, self.checkPeriod);
});
colEl.addEventListener("mouseup", function(e) {
if (e.which === 1) {
if (self.checkTimeout) clearTimeout(self.checkTimeout);
}
});
self.bindTouchEvents(column);
}
column.modules.moveColumn = config;
}
bindTouchEvents(column) {
var colEl = column.getElement(), startXMove = false, nextCol, prevCol, nextColWidth, prevColWidth, nextColWidthLast, prevColWidthLast;
colEl.addEventListener("touchstart", (e) => {
this.checkTimeout = setTimeout(() => {
this.touchMove = true;
nextCol = column.nextColumn();
nextColWidth = nextCol ? nextCol.getWidth() / 2 : 0;
prevCol = column.prevColumn();
prevColWidth = prevCol ? prevCol.getWidth() / 2 : 0;
nextColWidthLast = 0;
prevColWidthLast = 0;
startXMove = false;
this.startMove(e, column);
}, this.checkPeriod);
}, { passive: true });
colEl.addEventListener("touchmove", (e) => {
var diff, moveToCol;
if (this.moving) {
this.moveHover(e);
if (!startXMove) startXMove = e.touches[0].pageX;
diff = e.touches[0].pageX - startXMove;
if (diff > 0) {
if (nextCol && diff - nextColWidthLast > nextColWidth) {
moveToCol = nextCol;
if (moveToCol !== column) {
startXMove = e.touches[0].pageX;
moveToCol.getElement().parentNode.insertBefore(this.placeholderElement, moveToCol.getElement().nextSibling);
this.moveColumn(moveToCol, true);
}
}
} else if (prevCol && -diff - prevColWidthLast > prevColWidth) {
moveToCol = prevCol;
if (moveToCol !== column) {
startXMove = e.touches[0].pageX;
moveToCol.getElement().parentNode.insertBefore(this.placeholderElement, moveToCol.getElement());
this.moveColumn(moveToCol, false);
}
}
if (moveToCol) {
nextCol = moveToCol.nextColumn();
nextColWidthLast = nextColWidth;
nextColWidth = nextCol ? nextCol.getWidth() / 2 : 0;
prevCol = moveToCol.prevColumn();
prevColWidthLast = prevColWidth;
prevColWidth = prevCol ? prevCol.getWidth() / 2 : 0;
}
}
}, { passive: true });
colEl.addEventListener("touchend", (e) => {
if (this.checkTimeout) clearTimeout(this.checkTimeout);
if (this.moving) this.endMove(e);
});
}
startMove(e, column) {
var element = column.getElement(), headerElement = this.table.columnManager.getContentsElement(), headersElement = this.table.columnManager.getHeadersElement();
if (this.table.modules.selectRange && this.table.modules.selectRange.columnSelection) {
if (this.table.modules.selectRange.mousedown && this.table.modules.selectRange.selecting === "column") return;
}
this.moving = column;
this.startX = (this.touchMove ? e.touches[0].pageX : e.pageX) - Helpers.elOffset(element).left;
this.table.element.classList.add("tabulator-block-select");
this.placeholderElement.style.width = column.getWidth() + "px";
this.placeholderElement.style.height = column.getHeight() + "px";
element.parentNode.insertBefore(this.placeholderElement, element);
element.parentNode.removeChild(element);
this.hoverElement = element.cloneNode(true);
this.hoverElement.classList.add("tabulator-moving");
headerElement.appendChild(this.hoverElement);
this.hoverElement.style.left = "0";
this.hoverElement.style.bottom = headerElement.clientHeight - headersElement.offsetHeight + "px";
if (!this.touchMove) {
this._bindMouseMove();
document.body.addEventListener("mousemove", this.moveHover);
document.body.addEventListener("mouseup", this.endMove);
}
this.moveHover(e);
this.dispatch("column-moving", e, this.moving);
}
_bindMouseMove() {
this.table.columnManager.columnsByIndex.forEach(function(column) {
if (column.modules.moveColumn.mousemove) column.getElement().addEventListener("mousemove", column.modules.moveColumn.mousemove);
});
}
_unbindMouseMove() {
this.table.columnManager.columnsByIndex.forEach(function(column) {
if (column.modules.moveColumn.mousemove) column.getElement().removeEventListener("mousemove", column.modules.moveColumn.mousemove);
});
}
moveColumn(column, after) {
var movingCells = this.moving.getCells();
this.toCol = column;
this.toColAfter = after;
if (after) column.getCells().forEach(function(cell, i) {
var cellEl = cell.getElement(true);
if (cellEl.parentNode && movingCells[i]) cellEl.parentNode.insertBefore(movingCells[i].getElement(), cellEl.nextSibling);
});
else column.getCells().forEach(function(cell, i) {
var cellEl = cell.getElement(true);
if (cellEl.parentNode && movingCells[i]) cellEl.parentNode.insertBefore(movingCells[i].getElement(), cellEl);
});
}
endMove(e) {
if (e.which === 1 || this.touchMove) {
this._unbindMouseMove();
this.placeholderElement.parentNode.insertBefore(this.moving.getElement(), this.placeholderElement.nextSibling);
this.placeholderElement.parentNode.removeChild(this.placeholderElement);
this.hoverElement.parentNode.removeChild(this.hoverElement);
this.table.element.classList.remove("tabulator-block-select");
if (this.toCol) this.table.columnManager.moveColumnActual(this.moving, this.toCol, this.toColAfter);
this.moving = false;
this.toCol = false;
this.toColAfter = false;
if (!this.touchMove) {
document.body.removeEventListener("mousemove", this.moveHover);
document.body.removeEventListener("mouseup", this.endMove);
}
}
}
moveHover(e) {
var columnHolder = this.table.columnManager.getContentsElement(), scrollLeft = columnHolder.scrollLeft, xPos = (this.touchMove ? e.touches[0].pageX : e.pageX) - Helpers.elOffset(columnHolder).left + scrollLeft, scrollPos;
this.hoverElement.style.left = xPos - this.startX + "px";
if (xPos - scrollLeft < this.autoScrollMargin) {
if (!this.autoScrollTimeout) this.autoScrollTimeout = setTimeout(() => {
scrollPos = Math.max(0, scrollLeft - 5);
this.table.rowManager.getElement().scrollLeft = scrollPos;
this.autoScrollTimeout = false;
}, 1);
}
if (scrollLeft + columnHolder.clientWidth - xPos < this.autoScrollMargin) {
if (!this.autoScrollTimeout) this.autoScrollTimeout = setTimeout(() => {
scrollPos = Math.min(columnHolder.clientWidth, scrollLeft + 5);
this.table.rowManager.getElement().scrollLeft = scrollPos;
this.autoScrollTimeout = false;
}, 1);
}
}
};
var defaultSenders = { delete: function(fromRow, toRow, toTable) {
fromRow.delete();
} };
var defaultReceivers = {
insert: function(fromRow, toRow, fromTable) {
this.table.addRow(fromRow.getData(), void 0, toRow);
return true;
},
add: function(fromRow, toRow, fromTable) {
this.table.addRow(fromRow.getData());
return true;
},
update: function(fromRow, toRow, fromTable) {
if (toRow) {
toRow.update(fromRow.getData());
return true;
}
return false;
},
replace: function(fromRow, toRow, fromTable) {
if (toRow) {
this.table.addRow(fromRow.getData(), void 0, toRow);
toRow.delete();
return true;
}
return false;
}
};
var MoveRows = class MoveRows extends Module {
static moduleName = "moveRow";
static senders = defaultSenders;
static receivers = defaultReceivers;
constructor(table) {
super(table);
this.placeholderElement = this.createPlaceholderElement();
this.hoverElement = false;
this.checkTimeout = false;
this.checkPeriod = 150;
this.moving = false;
this.toRow = false;
this.toRowAfter = false;
this.hasHandle = false;
this.startY = 0;
this.startX = 0;
this.moveHover = this.moveHover.bind(this);
this.endMove = this.endMove.bind(this);
this.tableRowDropEvent = false;
this.touchMove = false;
this.connection = false;
this.connectionSelectorsTables = false;
this.connectionSelectorsElements = false;
this.connectionElements = [];
this.connections = [];
this.connectedTable = false;
this.connectedRow = false;
this.registerTableOption("movableRows", false);
this.registerTableOption("movableRowsConnectedTables", false);
this.registerTableOption("movableRowsConnectedElements", false);
this.registerTableOption("movableRowsSender", false);
this.registerTableOption("movableRowsReceiver", "insert");
this.registerColumnOption("rowHandle");
}
createPlaceholderElement() {
var el = document.createElement("div");
el.classList.add("tabulator-row");
el.classList.add("tabulator-row-placeholder");
return el;
}
initialize() {
if (this.table.options.movableRows) {
this.connectionSelectorsTables = this.table.options.movableRowsConnectedTables;
this.connectionSelectorsElements = this.table.options.movableRowsConnectedElements;
this.connection = this.connectionSelectorsTables || this.connectionSelectorsElements;
this.subscribe("cell-init", this.initializeCell.bind(this));
this.subscribe("column-init", this.initializeColumn.bind(this));
this.subscribe("row-init", this.initializeRow.bind(this));
}
}
initializeGroupHeader(group) {
var self = this, config = {};
config.mouseup = function(e) {
self.tableRowDrop(e, group);
}.bind(self);
config.mousemove = function(e) {
var rowEl;
if (e.pageY - Helpers.elOffset(group.element).top + self.table.rowManager.element.scrollTop > group.getHeight() / 2) {
if (self.toRow !== group || !self.toRowAfter) {
rowEl = group.getElement();
rowEl.parentNode.insertBefore(self.placeholderElement, rowEl.nextSibling);
self.moveRow(group, true);
}
} else if (self.toRow !== group || self.toRowAfter) {
rowEl = group.getElement();
if (rowEl.previousSibling) {
rowEl.parentNode.insertBefore(self.placeholderElement, rowEl);
self.moveRow(group, false);
}
}
}.bind(self);
group.modules.moveRow = config;
}
initializeRow(row) {
var self = this, config = {}, rowEl;
config.mouseup = function(e) {
self.tableRowDrop(e, row);
}.bind(self);
config.mousemove = function(e) {
var rowEl = row.getElement();
if (e.pageY - Helpers.elOffset(rowEl).top + self.table.rowManager.element.scrollTop > row.getHeight() / 2) {
if (self.toRow !== row || !self.toRowAfter) {
rowEl.parentNode.insertBefore(self.placeholderElement, rowEl.nextSibling);
self.moveRow(row, true);
}
} else if (self.toRow !== row || self.toRowAfter) {
rowEl.parentNode.insertBefore(self.placeholderElement, rowEl);
self.moveRow(row, false);
}
}.bind(self);
if (!this.hasHandle) {
rowEl = row.getElement();
rowEl.addEventListener("mousedown", function(e) {
if (e.which === 1) self.checkTimeout = setTimeout(function() {
self.startMove(e, row);
}, self.checkPeriod);
});
rowEl.addEventListener("mouseup", function(e) {
if (e.which === 1) {
if (self.checkTimeout) clearTimeout(self.checkTimeout);
}
});
this.bindTouchEvents(row, row.getElement());
}
row.modules.moveRow = config;
}
initializeColumn(column) {
if (column.definition.rowHandle && this.table.options.movableRows !== false) this.hasHandle = true;
}
initializeCell(cell) {
if (cell.column.definition.rowHandle && this.table.options.movableRows !== false) {
var self = this, cellEl = cell.getElement(true);
cellEl.addEventListener("mousedown", function(e) {
if (e.which === 1) self.checkTimeout = setTimeout(function() {
self.startMove(e, cell.row);
}, self.checkPeriod);
});
cellEl.addEventListener("mouseup", function(e) {
if (e.which === 1) {
if (self.checkTimeout) clearTimeout(self.checkTimeout);
}
});
this.bindTouchEvents(cell.row, cellEl);
}
}
bindTouchEvents(row, element) {
var startYMove = false, nextRow, prevRow, nextRowHeight, prevRowHeight, nextRowHeightLast, prevRowHeightLast;
element.addEventListener("touchstart", (e) => {
this.checkTimeout = setTimeout(() => {
this.touchMove = true;
nextRow = row.nextRow();
nextRowHeight = nextRow ? nextRow.getHeight() / 2 : 0;
prevRow = row.prevRow();
prevRowHeight = prevRow ? prevRow.getHeight() / 2 : 0;
nextRowHeightLast = 0;
prevRowHeightLast = 0;
startYMove = false;
this.startMove(e, row);
}, this.checkPeriod);
}, { passive: true });
this.moving, this.toRow, this.toRowAfter;
element.addEventListener("touchmove", (e) => {
var diff, moveToRow;
if (this.moving) {
e.preventDefault();
this.moveHover(e);
if (!startYMove) startYMove = e.touches[0].pageY;
diff = e.touches[0].pageY - startYMove;
if (diff > 0) {
if (nextRow && diff - nextRowHeightLast > nextRowHeight) {
moveToRow = nextRow;
if (moveToRow !== row) {
startYMove = e.touches[0].pageY;
moveToRow.getElement().parentNode.insertBefore(this.placeholderElement, moveToRow.getElement().nextSibling);
this.moveRow(moveToRow, true);
}
}
} else if (prevRow && -diff - prevRowHeightLast > prevRowHeight) {
moveToRow = prevRow;
if (moveToRow !== row) {
startYMove = e.touches[0].pageY;
moveToRow.getElement().parentNode.insertBefore(this.placeholderElement, moveToRow.getElement());
this.moveRow(moveToRow, false);
}
}
if (moveToRow) {
nextRow = moveToRow.nextRow();
nextRowHeightLast = nextRowHeight;
nextRowHeight = nextRow ? nextRow.getHeight() / 2 : 0;
prevRow = moveToRow.prevRow();
prevRowHeightLast = prevRowHeight;
prevRowHeight = prevRow ? prevRow.getHeight() / 2 : 0;
}
}
});
element.addEventListener("touchend", (e) => {
if (this.checkTimeout) clearTimeout(this.checkTimeout);
if (this.moving) {
this.endMove(e);
this.touchMove = false;
}
});
}
_bindMouseMove() {
this.table.rowManager.getDisplayRows().forEach((row) => {
if ((row.type === "row" || row.type === "group") && row.modules.moveRow && row.modules.moveRow.mousemove) row.getElement().addEventListener("mousemove", row.modules.moveRow.mousemove);
});
}
_unbindMouseMove() {
this.table.rowManager.getDisplayRows().forEach((row) => {
if ((row.type === "row" || row.type === "group") && row.modules.moveRow && row.modules.moveRow.mousemove) row.getElement().removeEventListener("mousemove", row.modules.moveRow.mousemove);
});
}
startMove(e, row) {
var element = row.getElement();
this.setStartPosition(e, row);
this.moving = row;
this.table.element.classList.add("tabulator-block-select");
this.placeholderElement.style.width = row.getWidth() + "px";
this.placeholderElement.style.height = row.getHeight() + "px";
if (!this.connection) {
element.parentNode.insertBefore(this.placeholderElement, element);
element.parentNode.removeChild(element);
} else {
this.table.element.classList.add("tabulator-movingrow-sending");
this.connectToTables(row);
}
this.hoverElement = element.cloneNode(true);
this.hoverElement.classList.add("tabulator-moving");
if (this.connection) {
document.body.appendChild(this.hoverElement);
this.hoverElement.style.left = "0";
this.hoverElement.style.top = "0";
this.hoverElement.style.width = this.table.element.clientWidth + "px";
this.hoverElement.style.whiteSpace = "nowrap";
this.hoverElement.style.overflow = "hidden";
this.hoverElement.style.pointerEvents = "none";
} else {
this.table.rowManager.getTableElement().appendChild(this.hoverElement);
this.hoverElement.style.left = "0";
this.hoverElement.style.top = "0";
this._bindMouseMove();
}
document.body.addEventListener("mousemove", this.moveHover);
document.body.addEventListener("mouseup", this.endMove);
this.dispatchExternal("rowMoving", row.getComponent());
this.moveHover(e);
}
setStartPosition(e, row) {
var pageX = this.touchMove ? e.touches[0].pageX : e.pageX, pageY = this.touchMove ? e.touches[0].pageY : e.pageY, element = row.getElement(), position;
if (this.connection) {
position = element.getBoundingClientRect();
this.startX = position.left - pageX + window.pageXOffset;
this.startY = position.top - pageY + window.pageYOffset;
} else this.startY = pageY - element.getBoundingClientRect().top;
}
endMove(e) {
if (!e || e.which === 1 || this.touchMove) {
this._unbindMouseMove();
if (!this.connection) {
this.placeholderElement.parentNode.insertBefore(this.moving.getElement(), this.placeholderElement.nextSibling);
this.placeholderElement.parentNode.removeChild(this.placeholderElement);
}
this.hoverElement.parentNode.removeChild(this.hoverElement);
this.table.element.classList.remove("tabulator-block-select");
if (this.toRow) this.table.rowManager.moveRow(this.moving, this.toRow, this.toRowAfter);
else this.dispatchExternal("rowMoveCancelled", this.moving.getComponent());
this.moving = false;
this.toRow = false;
this.toRowAfter = false;
document.body.removeEventListener("mousemove", this.moveHover);
document.body.removeEventListener("mouseup", this.endMove);
if (this.connection) {
this.table.element.classList.remove("tabulator-movingrow-sending");
this.disconnectFromTables();
}
}
}
moveRow(row, after) {
this.toRow = row;
this.toRowAfter = after;
}
moveHover(e) {
if (this.connection) this.moveHoverConnections.call(this, e);
else this.moveHoverTable.call(this, e);
}
moveHoverTable(e) {
var rowHolder = this.table.rowManager.getElement(), scrollTop = rowHolder.scrollTop, yPos = (this.touchMove ? e.touches[0].pageY : e.pageY) - rowHolder.getBoundingClientRect().top + scrollTop;
this.hoverElement.style.top = Math.min(yPos - this.startY, this.table.rowManager.element.scrollHeight - this.hoverElement.offsetHeight) + "px";
}
moveHoverConnections(e) {
this.hoverElement.style.left = this.startX + (this.touchMove ? e.touches[0].pageX : e.pageX) + "px";
this.hoverElement.style.top = this.startY + (this.touchMove ? e.touches[0].pageY : e.pageY) + "px";
}
elementRowDrop(e, element, row) {
this.dispatchExternal("movableRowsElementDrop", e, element, row ? row.getComponent() : false);
}
connectToTables(row) {
var connectionTables;
if (this.connectionSelectorsTables) {
connectionTables = this.commsConnections(this.connectionSelectorsTables);
this.dispatchExternal("movableRowsSendingStart", connectionTables);
this.commsSend(this.connectionSelectorsTables, "moveRow", "connect", { row });
}
if (this.connectionSelectorsElements) {
this.connectionElements = [];
if (!Array.isArray(this.connectionSelectorsElements)) this.connectionSelectorsElements = [this.connectionSelectorsElements];
this.connectionSelectorsElements.forEach((query) => {
if (typeof query === "string") this.connectionElements = this.connectionElements.concat(Array.prototype.slice.call(document.querySelectorAll(query)));
else this.connectionElements.push(query);
});
this.connectionElements.forEach((element) => {
var dropEvent = (e) => {
this.elementRowDrop(e, element, this.moving);
};
element.addEventListener("mouseup", dropEvent);
element.tabulatorElementDropEvent = dropEvent;
element.classList.add("tabulator-movingrow-receiving");
});
}
}
disconnectFromTables() {
var connectionTables;
if (this.connectionSelectorsTables) {
connectionTables = this.commsConnections(this.connectionSelectorsTables);
this.dispatchExternal("movableRowsSendingStop", connectionTables);
this.commsSend(this.connectionSelectorsTables, "moveRow", "disconnect");
}
this.connectionElements.forEach((element) => {
element.classList.remove("tabulator-movingrow-receiving");
element.removeEventListener("mouseup", element.tabulatorElementDropEvent);
delete element.tabulatorElementDropEvent;
});
}
connect(table, row) {
if (!this.connectedTable) {
this.connectedTable = table;
this.connectedRow = row;
this.table.element.classList.add("tabulator-movingrow-receiving");
this.table.rowManager.getDisplayRows().forEach((row) => {
if (row.type === "row" && row.modules.moveRow && row.modules.moveRow.mouseup) row.getElement().addEventListener("mouseup", row.modules.moveRow.mouseup);
});
this.tableRowDropEvent = this.tableRowDrop.bind(this);
this.table.element.addEventListener("mouseup", this.tableRowDropEvent);
this.dispatchExternal("movableRowsReceivingStart", row, table);
return true;
} else {
console.warn("Move Row Error - Table cannot accept connection, already connected to table:", this.connectedTable);
return false;
}
}
disconnect(table) {
if (table === this.connectedTable) {
this.connectedTable = false;
this.connectedRow = false;
this.table.element.classList.remove("tabulator-movingrow-receiving");
this.table.rowManager.getDisplayRows().forEach((row) => {
if (row.type === "row" && row.modules.moveRow && row.modules.moveRow.mouseup) row.getElement().removeEventListener("mouseup", row.modules.moveRow.mouseup);
});
this.table.element.removeEventListener("mouseup", this.tableRowDropEvent);
this.dispatchExternal("movableRowsReceivingStop", table);
} else console.warn("Move Row Error - trying to disconnect from non connected table");
}
dropComplete(table, row, success) {
var sender = false;
if (success) {
switch (typeof this.table.options.movableRowsSender) {
case "string":
sender = MoveRows.senders[this.table.options.movableRowsSender];
break;
case "function":
sender = this.table.options.movableRowsSender;
break;
}
if (sender) sender.call(this, this.moving ? this.moving.getComponent() : void 0, row ? row.getComponent() : void 0, table);
else if (this.table.options.movableRowsSender) console.warn("Mover Row Error - no matching sender found:", this.table.options.movableRowsSender);
this.dispatchExternal("movableRowsSent", this.moving.getComponent(), row ? row.getComponent() : void 0, table);
} else this.dispatchExternal("movableRowsSentFailed", this.moving.getComponent(), row ? row.getComponent() : void 0, table);
this.endMove();
}
tableRowDrop(e, row) {
var receiver = false, success = false;
e.stopImmediatePropagation();
switch (typeof this.table.options.movableRowsReceiver) {
case "string":
receiver = MoveRows.receivers[this.table.options.movableRowsReceiver];
break;
case "function":
receiver = this.table.options.movableRowsReceiver;
break;
}
if (receiver) success = receiver.call(this, this.connectedRow.getComponent(), row ? row.getComponent() : void 0, this.connectedTable);
else console.warn("Mover Row Error - no matching receiver found:", this.table.options.movableRowsReceiver);
if (success) this.dispatchExternal("movableRowsReceived", this.connectedRow.getComponent(), row ? row.getComponent() : void 0, this.connectedTable);
else this.dispatchExternal("movableRowsReceivedFailed", this.connectedRow.getComponent(), row ? row.getComponent() : void 0, this.connectedTable);
this.commsSend(this.connectedTable, "moveRow", "dropcomplete", {
row,
success
});
}
commsReceived(table, action, data) {
switch (action) {
case "connect": return this.connect(table, data.row);
case "disconnect": return this.disconnect(table);
case "dropcomplete": return this.dropComplete(table, data.row, data.success);
}
}
};
var defaultMutators = {};
var Mutator = class Mutator extends Module {
static moduleName = "mutator";
static mutators = defaultMutators;
constructor(table) {
super(table);
this.allowedTypes = [
"",
"data",
"edit",
"clipboard",
"import"
];
this.enabled = true;
this.registerColumnOption("mutator");
this.registerColumnOption("mutatorParams");
this.registerColumnOption("mutatorData");
this.registerColumnOption("mutatorDataParams");
this.registerColumnOption("mutatorEdit");
this.registerColumnOption("mutatorEditParams");
this.registerColumnOption("mutatorClipboard");
this.registerColumnOption("mutatorClipboardParams");
this.registerColumnOption("mutatorImport");
this.registerColumnOption("mutatorImportParams");
this.registerColumnOption("mutateLink");
}
initialize() {
this.subscribe("cell-value-changing", this.transformCell.bind(this));
this.subscribe("cell-value-changed", this.mutateLink.bind(this));
this.subscribe("column-layout", this.initializeColumn.bind(this));
this.subscribe("row-data-init-before", this.rowDataChanged.bind(this));
this.subscribe("row-data-changing", this.rowDataChanged.bind(this));
}
rowDataChanged(row, tempData, updatedData) {
return this.transformRow(tempData, "data", updatedData);
}
initializeColumn(column) {
var match = false, config = {};
this.allowedTypes.forEach((type) => {
var key = "mutator" + (type.charAt(0).toUpperCase() + type.slice(1)), mutator;
if (column.definition[key]) {
mutator = this.lookupMutator(column.definition[key]);
if (mutator) {
match = true;
config[key] = {
mutator,
params: column.definition[key + "Params"] || {}
};
}
}
});
if (match) column.modules.mutate = config;
}
lookupMutator(value) {
var mutator = false;
switch (typeof value) {
case "string":
if (Mutator.mutators[value]) mutator = Mutator.mutators[value];
else console.warn("Mutator Error - No such mutator found, ignoring: ", value);
break;
case "function":
mutator = value;
break;
}
return mutator;
}
transformRow(data, type, updatedData) {
var key = "mutator" + (type.charAt(0).toUpperCase() + type.slice(1)), value;
if (this.enabled) this.table.columnManager.traverse((column) => {
var mutator, params, component;
if (column.modules.mutate) {
mutator = column.modules.mutate[key] || column.modules.mutate.mutator || false;
if (mutator) {
value = column.getFieldValue(typeof updatedData !== "undefined" ? updatedData : data);
if (type == "data" && !updatedData || typeof value !== "undefined") {
component = column.getComponent();
params = typeof mutator.params === "function" ? mutator.params(value, data, type, component) : mutator.params;
column.setFieldValue(data, mutator.mutator(value, data, type, params, component));
}
}
}
});
return data;
}
transformCell(cell, value) {
if (cell.column.modules.mutate) {
var mutator = cell.column.modules.mutate.mutatorEdit || cell.column.modules.mutate.mutator || false, tempData = {};
if (mutator) {
tempData = Object.assign(tempData, cell.row.getData());
cell.column.setFieldValue(tempData, value);
return mutator.mutator(value, tempData, "edit", mutator.params, cell.getComponent());
}
}
return value;
}
mutateLink(cell) {
var links = cell.column.definition.mutateLink;
if (links) {
if (!Array.isArray(links)) links = [links];
links.forEach((link) => {
var linkCell = cell.row.getCell(link);
if (linkCell) linkCell.setValue(linkCell.getValue(), true, true);
});
}
}
enable() {
this.enabled = true;
}
disable() {
this.enabled = false;
}
};
function rows(pageSize, currentRow, currentPage, totalRows, totalPages) {
var el = document.createElement("span"), showingEl = document.createElement("span"), valueEl = document.createElement("span"), ofEl = document.createElement("span"), totalEl = document.createElement("span"), rowsEl = document.createElement("span");
this.table.modules.localize.langBind("pagination|counter|showing", (value) => {
showingEl.innerHTML = value;
});
this.table.modules.localize.langBind("pagination|counter|of", (value) => {
ofEl.innerHTML = value;
});
this.table.modules.localize.langBind("pagination|counter|rows", (value) => {
rowsEl.innerHTML = value;
});
if (totalRows) {
valueEl.innerHTML = " " + currentRow + "-" + Math.min(currentRow + pageSize - 1, totalRows) + " ";
totalEl.innerHTML = " " + totalRows + " ";
el.appendChild(showingEl);
el.appendChild(valueEl);
el.appendChild(ofEl);
el.appendChild(totalEl);
el.appendChild(rowsEl);
} else {
valueEl.innerHTML = " 0 ";
el.appendChild(showingEl);
el.appendChild(valueEl);
el.appendChild(rowsEl);
}
return el;
}
function pages(pageSize, currentRow, currentPage, totalRows, totalPages) {
var el = document.createElement("span"), showingEl = document.createElement("span"), valueEl = document.createElement("span"), ofEl = document.createElement("span"), totalEl = document.createElement("span"), rowsEl = document.createElement("span");
this.table.modules.localize.langBind("pagination|counter|showing", (value) => {
showingEl.innerHTML = value;
});
valueEl.innerHTML = " " + currentPage + " ";
this.table.modules.localize.langBind("pagination|counter|of", (value) => {
ofEl.innerHTML = value;
});
totalEl.innerHTML = " " + totalPages + " ";
this.table.modules.localize.langBind("pagination|counter|pages", (value) => {
rowsEl.innerHTML = value;
});
el.appendChild(showingEl);
el.appendChild(valueEl);
el.appendChild(ofEl);
el.appendChild(totalEl);
el.appendChild(rowsEl);
return el;
}
var defaultPageCounters = {
rows,
pages
};
var Page = class Page extends Module {
static moduleName = "page";
static pageCounters = defaultPageCounters;
constructor(table) {
super(table);
this.mode = "local";
this.progressiveLoad = false;
this.element = null;
this.pageCounterElement = null;
this.pageCounter = null;
this.size = 0;
this.page = 1;
this.count = 5;
this.max = 1;
this.remoteRowCountEstimate = null;
this.initialLoad = true;
this.dataChanging = false;
this.pageSizes = [];
this.registerTableOption("pagination", false);
this.registerTableOption("paginationMode", "local");
this.registerTableOption("paginationSize", false);
this.registerTableOption("paginationInitialPage", 1);
this.registerTableOption("paginationCounter", false);
this.registerTableOption("paginationCounterElement", false);
this.registerTableOption("paginationButtonCount", 5);
this.registerTableOption("paginationSizeSelector", false);
this.registerTableOption("paginationElement", false);
this.registerTableOption("paginationAddRow", "page");
this.registerTableOption("paginationOutOfRange", false);
this.registerTableOption("progressiveLoad", false);
this.registerTableOption("progressiveLoadDelay", 0);
this.registerTableOption("progressiveLoadScrollMargin", 0);
this.registerTableFunction("setMaxPage", this.setMaxPage.bind(this));
this.registerTableFunction("setPage", this.setPage.bind(this));
this.registerTableFunction("setPageToRow", this.userSetPageToRow.bind(this));
this.registerTableFunction("setPageSize", this.userSetPageSize.bind(this));
this.registerTableFunction("getPageSize", this.getPageSize.bind(this));
this.registerTableFunction("previousPage", this.previousPage.bind(this));
this.registerTableFunction("nextPage", this.nextPage.bind(this));
this.registerTableFunction("getPage", this.getPage.bind(this));
this.registerTableFunction("getPageMax", this.getPageMax.bind(this));
this.registerComponentFunction("row", "pageTo", this.setPageToRow.bind(this));
}
initialize() {
if (this.table.options.pagination) {
this.subscribe("row-deleted", this.rowsUpdated.bind(this));
this.subscribe("row-added", this.rowsUpdated.bind(this));
this.subscribe("data-processed", this.initialLoadComplete.bind(this));
this.subscribe("table-built", this.calculatePageSizes.bind(this));
this.subscribe("footer-redraw", this.footerRedraw.bind(this));
if (this.table.options.paginationAddRow == "page") this.subscribe("row-adding-position", this.rowAddingPosition.bind(this));
if (this.table.options.paginationMode === "remote") {
this.subscribe("data-params", this.remotePageParams.bind(this));
this.subscribe("data-loaded", this._parseRemoteData.bind(this));
}
if (this.table.options.progressiveLoad) console.error("Progressive Load Error - Pagination and progressive load cannot be used at the same time");
this.registerDisplayHandler(this.restOnRenderBefore.bind(this), 40);
this.registerDisplayHandler(this.getRows.bind(this), 50);
this.createElements();
this.initializePageCounter();
this.initializePaginator();
} else if (this.table.options.progressiveLoad) {
this.subscribe("data-params", this.remotePageParams.bind(this));
this.subscribe("data-loaded", this._parseRemoteData.bind(this));
this.subscribe("table-built", this.calculatePageSizes.bind(this));
this.subscribe("data-processed", this.initialLoadComplete.bind(this));
this.initializeProgressive(this.table.options.progressiveLoad);
if (this.table.options.progressiveLoad === "scroll") this.subscribe("scroll-vertical", this.scrollVertical.bind(this));
}
}
rowAddingPosition(row, top) {
var rowManager = this.table.rowManager, displayRows = rowManager.getDisplayRows(), index;
if (top) {
if (displayRows.length) index = displayRows[0];
else if (rowManager.activeRows.length) {
index = rowManager.activeRows[rowManager.activeRows.length - 1];
top = false;
}
} else if (displayRows.length) {
index = displayRows[displayRows.length - 1];
top = displayRows.length < this.size ? false : true;
}
return {
index,
top
};
}
calculatePageSizes() {
var testElRow, testElCell;
if (this.table.options.paginationSize) this.size = this.table.options.paginationSize;
else {
testElRow = document.createElement("div");
testElRow.classList.add("tabulator-row");
testElRow.style.visibility = "hidden";
testElCell = document.createElement("div");
testElCell.classList.add("tabulator-cell");
testElCell.innerHTML = "Page Row Test";
testElRow.appendChild(testElCell);
this.table.rowManager.getTableElement().appendChild(testElRow);
this.size = Math.floor(this.table.rowManager.getElement().clientHeight / testElRow.offsetHeight);
this.table.rowManager.getTableElement().removeChild(testElRow);
}
this.dispatchExternal("pageSizeChanged", this.size);
this.generatePageSizeSelectList();
}
initialLoadComplete() {
this.initialLoad = false;
}
remotePageParams(data, config, silent, params) {
if (!this.initialLoad) {
if (this.progressiveLoad && !silent || !this.progressiveLoad && !this.dataChanging) this.reset(true);
}
params.page = this.page;
if (this.size) params.size = this.size;
return params;
}
userSetPageToRow(row) {
if (this.table.options.pagination) {
row = this.table.rowManager.findRow(row);
if (row) return this.setPageToRow(row);
}
return Promise.reject();
}
userSetPageSize(size) {
if (this.table.options.pagination) {
this.setPageSize(size);
return this.setPage(1);
} else return false;
}
scrollVertical(top, dir) {
var element, diff, margin;
if (!dir && !this.table.dataLoader.loading) {
element = this.table.rowManager.getElement();
diff = element.scrollHeight - element.clientHeight - top;
margin = this.table.options.progressiveLoadScrollMargin || element.clientHeight * 2;
if (diff < margin) this.nextPage().catch(() => {});
}
}
restOnRenderBefore(rows, renderInPosition) {
if (!renderInPosition) {
if (this.mode === "local") this.reset();
}
return rows;
}
rowsUpdated() {
this.refreshData(true, "all");
}
createElements() {
var button;
this.element = document.createElement("span");
this.element.classList.add("tabulator-paginator");
this.pagesElement = document.createElement("span");
this.pagesElement.classList.add("tabulator-pages");
button = document.createElement("button");
button.classList.add("tabulator-page");
button.setAttribute("type", "button");
button.setAttribute("role", "button");
button.setAttribute("aria-label", "");
button.setAttribute("title", "");
this.firstBut = button.cloneNode(true);
this.firstBut.setAttribute("data-page", "first");
this.prevBut = button.cloneNode(true);
this.prevBut.setAttribute("data-page", "prev");
this.nextBut = button.cloneNode(true);
this.nextBut.setAttribute("data-page", "next");
this.lastBut = button.cloneNode(true);
this.lastBut.setAttribute("data-page", "last");
if (this.table.options.paginationSizeSelector) {
this.pageSizeSelect = document.createElement("select");
this.pageSizeSelect.classList.add("tabulator-page-size");
}
}
generatePageSizeSelectList() {
var pageSizes = [];
if (this.pageSizeSelect) {
if (Array.isArray(this.table.options.paginationSizeSelector)) {
pageSizes = this.table.options.paginationSizeSelector;
this.pageSizes = pageSizes;
if (this.pageSizes.indexOf(this.size) == -1) pageSizes.unshift(this.size);
} else if (this.pageSizes.indexOf(this.size) == -1) {
pageSizes = [];
for (let i = 1; i < 5; i++) pageSizes.push(this.size * i);
this.pageSizes = pageSizes;
} else pageSizes = this.pageSizes;
while (this.pageSizeSelect.firstChild) this.pageSizeSelect.removeChild(this.pageSizeSelect.firstChild);
pageSizes.forEach((item) => {
var itemEl = document.createElement("option");
itemEl.value = item;
if (item === true) this.langBind("pagination|all", function(value) {
itemEl.innerHTML = value;
});
else itemEl.innerHTML = item;
this.pageSizeSelect.appendChild(itemEl);
});
this.pageSizeSelect.value = this.size;
}
}
initializePageCounter() {
var counter = this.table.options.paginationCounter, pageCounter = null;
if (counter) {
if (typeof counter === "function") pageCounter = counter;
else pageCounter = Page.pageCounters[counter];
if (pageCounter) {
this.pageCounter = pageCounter;
this.pageCounterElement = document.createElement("span");
this.pageCounterElement.classList.add("tabulator-page-counter");
} else console.warn("Pagination Error - No such page counter found: ", counter);
}
}
initializePaginator(hidden) {
var pageSelectLabel, paginationCounterHolder;
if (!hidden) {
this.langBind("pagination|first", (value) => {
this.firstBut.innerHTML = value;
});
this.langBind("pagination|first_title", (value) => {
this.firstBut.setAttribute("aria-label", value);
this.firstBut.setAttribute("title", value);
});
this.langBind("pagination|prev", (value) => {
this.prevBut.innerHTML = value;
});
this.langBind("pagination|prev_title", (value) => {
this.prevBut.setAttribute("aria-label", value);
this.prevBut.setAttribute("title", value);
});
this.langBind("pagination|next", (value) => {
this.nextBut.innerHTML = value;
});
this.langBind("pagination|next_title", (value) => {
this.nextBut.setAttribute("aria-label", value);
this.nextBut.setAttribute("title", value);
});
this.langBind("pagination|last", (value) => {
this.lastBut.innerHTML = value;
});
this.langBind("pagination|last_title", (value) => {
this.lastBut.setAttribute("aria-label", value);
this.lastBut.setAttribute("title", value);
});
this.firstBut.addEventListener("click", () => {
this.setPage(1);
});
this.prevBut.addEventListener("click", () => {
this.previousPage();
});
this.nextBut.addEventListener("click", () => {
this.nextPage();
});
this.lastBut.addEventListener("click", () => {
this.setPage(this.max);
});
if (this.table.options.paginationElement) this.element = this.table.options.paginationElement;
if (this.pageSizeSelect) {
pageSelectLabel = document.createElement("label");
this.langBind("pagination|page_size", (value) => {
this.pageSizeSelect.setAttribute("aria-label", value);
this.pageSizeSelect.setAttribute("title", value);
pageSelectLabel.innerHTML = value;
});
this.element.appendChild(pageSelectLabel);
this.element.appendChild(this.pageSizeSelect);
this.pageSizeSelect.addEventListener("change", (e) => {
this.setPageSize(this.pageSizeSelect.value == "true" ? true : this.pageSizeSelect.value);
this.setPage(1);
});
}
this.element.appendChild(this.firstBut);
this.element.appendChild(this.prevBut);
this.element.appendChild(this.pagesElement);
this.element.appendChild(this.nextBut);
this.element.appendChild(this.lastBut);
if (!this.table.options.paginationElement) {
if (this.table.options.paginationCounter) if (this.table.options.paginationCounterElement) {
if (this.table.options.paginationCounterElement instanceof HTMLElement) this.table.options.paginationCounterElement.appendChild(this.pageCounterElement);
else if (typeof this.table.options.paginationCounterElement === "string") {
paginationCounterHolder = document.querySelector(this.table.options.paginationCounterElement);
if (paginationCounterHolder) paginationCounterHolder.appendChild(this.pageCounterElement);
else console.warn("Pagination Error - Unable to find element matching paginationCounterElement selector:", this.table.options.paginationCounterElement);
}
} else this.footerAppend(this.pageCounterElement);
this.footerAppend(this.element);
}
this.page = this.table.options.paginationInitialPage;
this.count = this.table.options.paginationButtonCount;
}
this.mode = this.table.options.paginationMode;
}
initializeProgressive(mode) {
this.initializePaginator(true);
this.mode = "progressive_" + mode;
this.progressiveLoad = true;
}
trackChanges() {
this.dispatch("page-changed");
}
setMaxRows(rowCount) {
if (!rowCount) this.max = 1;
else this.max = this.size === true ? 1 : Math.ceil(rowCount / this.size);
if (this.page > this.max) this.page = this.max;
}
reset(force) {
if (!this.initialLoad) {
if (this.mode == "local" || force) {
this.page = 1;
this.trackChanges();
}
}
}
setMaxPage(max) {
max = parseInt(max);
this.max = max || 1;
if (this.page > this.max) {
this.page = this.max;
this.trigger();
}
}
setPage(page) {
switch (page) {
case "first": return this.setPage(1);
case "prev": return this.previousPage();
case "next": return this.nextPage();
case "last": return this.setPage(this.max);
}
page = parseInt(page);
if (page > 0 && page <= this.max || this.mode !== "local") {
this.page = page;
this.trackChanges();
return this.trigger();
} else {
console.warn("Pagination Error - Requested page is out of range of 1 - " + this.max + ":", page);
return Promise.reject();
}
}
setPageToRow(row) {
var index = this.displayRows(-1).indexOf(row);
if (index > -1) {
var page = this.size === true ? 1 : Math.ceil((index + 1) / this.size);
return this.setPage(page);
} else {
console.warn("Pagination Error - Requested row is not visible");
return Promise.reject();
}
}
setPageSize(size) {
if (size !== true) size = parseInt(size);
if (size > 0) {
this.size = size;
this.dispatchExternal("pageSizeChanged", size);
}
if (this.pageSizeSelect) this.generatePageSizeSelectList();
this.trackChanges();
}
_setPageCounter(totalRows, size, currentRow) {
var content;
if (this.pageCounter) {
if (this.mode === "remote") {
size = this.size;
currentRow = (this.page - 1) * this.size + 1;
totalRows = this.remoteRowCountEstimate;
}
content = this.pageCounter.call(this, size, currentRow, this.page, totalRows, this.max);
switch (typeof content) {
case "object":
if (content instanceof Node) {
while (this.pageCounterElement.firstChild) this.pageCounterElement.removeChild(this.pageCounterElement.firstChild);
this.pageCounterElement.appendChild(content);
} else {
this.pageCounterElement.innerHTML = "";
if (content != null) console.warn("Page Counter Error - Page Counter has returned a type of object, the only valid page counter object return is an instance of Node, the page counter returned:", content);
}
break;
case "undefined":
this.pageCounterElement.innerHTML = "";
break;
default: this.pageCounterElement.innerHTML = content;
}
}
}
_setPageButtons() {
let leftSize = Math.floor((this.count - 1) / 2);
let rightSize = Math.ceil((this.count - 1) / 2);
let min = this.max - this.page + leftSize + 1 < this.count ? this.max - this.count + 1 : Math.max(this.page - leftSize, 1);
let max = this.page <= rightSize ? Math.min(this.count, this.max) : Math.min(this.page + rightSize, this.max);
while (this.pagesElement.firstChild) this.pagesElement.removeChild(this.pagesElement.firstChild);
if (this.page == 1) {
this.firstBut.disabled = true;
this.prevBut.disabled = true;
} else {
this.firstBut.disabled = false;
this.prevBut.disabled = false;
}
if (this.page == this.max) {
this.lastBut.disabled = true;
this.nextBut.disabled = true;
} else {
this.lastBut.disabled = false;
this.nextBut.disabled = false;
}
for (let i = min; i <= max; i++) if (i > 0 && i <= this.max) this.pagesElement.appendChild(this._generatePageButton(i));
this.footerRedraw();
}
_generatePageButton(page) {
var button = document.createElement("button");
button.classList.add("tabulator-page");
if (page == this.page) button.classList.add("active");
button.setAttribute("type", "button");
button.setAttribute("role", "button");
this.langBind("pagination|page_title", (value) => {
button.setAttribute("aria-label", value + " " + page);
button.setAttribute("title", value + " " + page);
});
button.setAttribute("data-page", page);
button.textContent = page;
button.addEventListener("click", (e) => {
this.setPage(page);
});
return button;
}
previousPage() {
if (this.page > 1) {
this.page--;
this.trackChanges();
return this.trigger();
} else {
console.warn("Pagination Error - Previous page would be less than page 1:", 0);
return Promise.reject();
}
}
nextPage() {
if (this.page < this.max) {
this.page++;
this.trackChanges();
return this.trigger();
} else {
if (!this.progressiveLoad) console.warn("Pagination Error - Next page would be greater than maximum page of " + this.max + ":", this.max + 1);
return Promise.reject();
}
}
getPage() {
return this.page;
}
getPageMax() {
return this.max;
}
getPageSize(size) {
return this.size;
}
getMode() {
return this.mode;
}
getRows(data) {
var actualRowPageSize = 0, output, start, end, actualStartRow;
var actualRows = data.filter((row) => {
return row.type === "row";
});
if (this.mode == "local") {
output = [];
this.setMaxRows(data.length);
if (this.size === true) {
start = 0;
end = data.length;
} else {
start = this.size * (this.page - 1);
end = start + parseInt(this.size);
}
this._setPageButtons();
for (let i = start; i < end; i++) {
let row = data[i];
if (row) {
output.push(row);
if (row.type === "row") {
if (!actualStartRow) actualStartRow = row;
actualRowPageSize++;
}
}
}
this._setPageCounter(actualRows.length, actualRowPageSize, actualStartRow ? actualRows.indexOf(actualStartRow) + 1 : 0);
return output;
} else {
this._setPageButtons();
this._setPageCounter(actualRows.length);
return data.slice(0);
}
}
trigger() {
var left;
switch (this.mode) {
case "local":
left = this.table.rowManager.scrollLeft;
this.refreshData();
this.table.rowManager.scrollHorizontal(left);
this.dispatchExternal("pageLoaded", this.getPage());
return Promise.resolve();
case "remote":
this.dataChanging = true;
return this.reloadData(null).finally(() => {
this.dataChanging = false;
});
case "progressive_load":
case "progressive_scroll": return this.reloadData(null, true);
default:
console.warn("Pagination Error - no such pagination mode:", this.mode);
return Promise.reject();
}
}
_parseRemoteData(data) {
var margin, paginationOutOfRange;
if (typeof data.last_page === "undefined") console.warn("Remote Pagination Error - Server response missing '" + (this.options("dataReceiveParams").last_page || "last_page") + "' property");
if (data.data) {
this.max = parseInt(data.last_page) || 1;
this.remoteRowCountEstimate = typeof data.last_row !== "undefined" ? data.last_row : data.last_page * this.size - (this.page == data.last_page ? this.size - data.data.length : 0);
if (this.progressiveLoad) {
switch (this.mode) {
case "progressive_load":
if (this.page == 1) this.table.rowManager.setData(data.data, false, this.page == 1);
else this.table.rowManager.addRows(data.data);
if (this.page < this.max) setTimeout(() => {
this.nextPage();
}, this.table.options.progressiveLoadDelay);
break;
case "progressive_scroll":
data = this.page === 1 ? data.data : this.table.rowManager.getData().concat(data.data);
this.table.rowManager.setData(data, this.page !== 1, this.page == 1);
margin = this.table.options.progressiveLoadScrollMargin || this.table.rowManager.element.clientHeight * 2;
if (this.table.rowManager.element.scrollHeight <= this.table.rowManager.element.clientHeight + margin) {
if (this.page < this.max) setTimeout(() => {
this.nextPage();
});
}
break;
}
return false;
} else {
if (this.page > this.max) {
console.warn("Remote Pagination Error - Server returned last page value lower than the current page");
paginationOutOfRange = this.options("paginationOutOfRange");
if (paginationOutOfRange) return this.setPage(typeof paginationOutOfRange === "function" ? paginationOutOfRange.call(this, this.page, this.max) : paginationOutOfRange);
}
this.dispatchExternal("pageLoaded", this.getPage());
}
} else console.warn("Remote Pagination Error - Server response missing '" + (this.options("dataReceiveParams").data || "data") + "' property");
return data.data;
}
footerRedraw() {
var footer = this.table.footerManager.containerElement;
if (Math.ceil(footer.clientWidth) - footer.scrollWidth < 0) this.pagesElement.style.display = "none";
else {
this.pagesElement.style.display = "";
if (Math.ceil(footer.clientWidth) - footer.scrollWidth < 0) this.pagesElement.style.display = "none";
}
}
};
var defaultReaders = {
local: function(id, type) {
var data = localStorage.getItem(id + "-" + type);
return data ? JSON.parse(data) : false;
},
cookie: function(id, type) {
var cookie = document.cookie, key = id + "-" + type, cookiePos = cookie.indexOf(key + "="), end, data;
if (cookiePos > -1) {
cookie = cookie.slice(cookiePos);
end = cookie.indexOf(";");
if (end > -1) cookie = cookie.slice(0, end);
data = cookie.replace(key + "=", "");
}
return data ? JSON.parse(data) : false;
}
};
var defaultWriters = {
local: function(id, type, data) {
localStorage.setItem(id + "-" + type, JSON.stringify(data));
},
cookie: function(id, type, data) {
var expireDate = new Date();
expireDate.setDate(expireDate.getDate() + 1e4);
document.cookie = id + "-" + type + "=" + JSON.stringify(data) + "; expires=" + expireDate.toUTCString();
}
};
var Persistence = class Persistence extends Module {
static moduleName = "persistence";
static moduleInitOrder = -10;
static readers = defaultReaders;
static writers = defaultWriters;
constructor(table) {
super(table);
this.mode = "";
this.id = "";
this.defWatcherBlock = false;
this.config = {};
this.readFunc = false;
this.writeFunc = false;
this.registerTableOption("persistence", false);
this.registerTableOption("persistenceID", "");
this.registerTableOption("persistenceMode", true);
this.registerTableOption("persistenceReaderFunc", false);
this.registerTableOption("persistenceWriterFunc", false);
}
localStorageTest() {
var testKey = "_tabulator_test";
try {
window.localStorage.setItem(testKey, testKey);
window.localStorage.removeItem(testKey);
return true;
} catch (e) {
return false;
}
}
initialize() {
if (this.table.options.persistence) {
var mode = this.table.options.persistenceMode, id = this.table.options.persistenceID, retrievedData;
this.mode = mode !== true ? mode : this.localStorageTest() ? "local" : "cookie";
if (this.table.options.persistenceReaderFunc) if (typeof this.table.options.persistenceReaderFunc === "function") this.readFunc = this.table.options.persistenceReaderFunc;
else if (Persistence.readers[this.table.options.persistenceReaderFunc]) this.readFunc = Persistence.readers[this.table.options.persistenceReaderFunc];
else console.warn("Persistence Read Error - invalid reader set", this.table.options.persistenceReaderFunc);
else if (Persistence.readers[this.mode]) this.readFunc = Persistence.readers[this.mode];
else console.warn("Persistence Read Error - invalid reader set", this.mode);
if (this.table.options.persistenceWriterFunc) if (typeof this.table.options.persistenceWriterFunc === "function") this.writeFunc = this.table.options.persistenceWriterFunc;
else if (Persistence.writers[this.table.options.persistenceWriterFunc]) this.writeFunc = Persistence.writers[this.table.options.persistenceWriterFunc];
else console.warn("Persistence Write Error - invalid reader set", this.table.options.persistenceWriterFunc);
else if (Persistence.writers[this.mode]) this.writeFunc = Persistence.writers[this.mode];
else console.warn("Persistence Write Error - invalid writer set", this.mode);
this.id = "tabulator-" + (id || this.table.element.getAttribute("id") || "");
this.config = {
sort: this.table.options.persistence === true || this.table.options.persistence.sort,
filter: this.table.options.persistence === true || this.table.options.persistence.filter,
headerFilter: this.table.options.persistence === true || this.table.options.persistence.headerFilter,
group: this.table.options.persistence === true || this.table.options.persistence.group,
page: this.table.options.persistence === true || this.table.options.persistence.page,
columns: this.table.options.persistence === true ? [
"title",
"width",
"visible"
] : this.table.options.persistence.columns
};
if (this.config.page) {
retrievedData = this.retrieveData("page");
if (retrievedData) {
if (typeof retrievedData.paginationSize !== "undefined" && (this.config.page === true || this.config.page.size)) this.table.options.paginationSize = retrievedData.paginationSize;
if (typeof retrievedData.paginationInitialPage !== "undefined" && (this.config.page === true || this.config.page.page)) this.table.options.paginationInitialPage = retrievedData.paginationInitialPage;
}
}
if (this.config.group) {
retrievedData = this.retrieveData("group");
if (retrievedData) {
if (typeof retrievedData.groupBy !== "undefined" && (this.config.group === true || this.config.group.groupBy)) this.table.options.groupBy = retrievedData.groupBy;
if (typeof retrievedData.groupStartOpen !== "undefined" && (this.config.group === true || this.config.group.groupStartOpen)) this.table.options.groupStartOpen = retrievedData.groupStartOpen;
if (typeof retrievedData.groupHeader !== "undefined" && (this.config.group === true || this.config.group.groupHeader)) this.table.options.groupHeader = retrievedData.groupHeader;
}
}
if (this.config.columns) {
this.table.options.columns = this.load("columns", this.table.options.columns);
this.subscribe("column-init", this.initializeColumn.bind(this));
this.subscribe("column-show", this.save.bind(this, "columns"));
this.subscribe("column-hide", this.save.bind(this, "columns"));
this.subscribe("column-moved", this.save.bind(this, "columns"));
}
this.subscribe("table-built", this.tableBuilt.bind(this), 0);
this.subscribe("table-redraw", this.tableRedraw.bind(this));
this.subscribe("filter-changed", this.eventSave.bind(this, "filter"));
this.subscribe("filter-changed", this.eventSave.bind(this, "headerFilter"));
this.subscribe("sort-changed", this.eventSave.bind(this, "sort"));
this.subscribe("group-changed", this.eventSave.bind(this, "group"));
this.subscribe("page-changed", this.eventSave.bind(this, "page"));
this.subscribe("column-resized", this.eventSave.bind(this, "columns"));
this.subscribe("column-width", this.eventSave.bind(this, "columns"));
this.subscribe("layout-refreshed", this.eventSave.bind(this, "columns"));
}
this.registerTableFunction("getColumnLayout", this.getColumnLayout.bind(this));
this.registerTableFunction("setColumnLayout", this.setColumnLayout.bind(this));
}
eventSave(type) {
if (this.config[type]) this.save(type);
}
tableBuilt() {
var sorters, filters, headerFilters;
if (this.config.sort) {
sorters = this.load("sort");
if (!sorters === false) this.table.options.initialSort = sorters;
}
if (this.config.filter) {
filters = this.load("filter");
if (!filters === false) this.table.options.initialFilter = filters;
}
if (this.config.headerFilter) {
headerFilters = this.load("headerFilter");
if (!headerFilters === false) this.table.options.initialHeaderFilter = headerFilters;
}
}
tableRedraw(force) {
if (force && this.config.columns) this.save("columns");
}
getColumnLayout() {
return this.parseColumns(this.table.columnManager.getColumns());
}
setColumnLayout(layout) {
this.table.columnManager.setColumns(this.mergeDefinition(this.table.options.columns, layout, true));
return true;
}
initializeColumn(column) {
var def, keys;
if (this.config.columns) {
this.defWatcherBlock = true;
def = column.getDefinition();
keys = this.config.columns === true ? Object.keys(def) : this.config.columns;
keys.forEach((key) => {
var props = Object.getOwnPropertyDescriptor(def, key);
var value = def[key];
if (props) Object.defineProperty(def, key, {
set: (newValue) => {
value = newValue;
if (!this.defWatcherBlock) this.save("columns");
if (props.set) props.set(newValue);
},
get: () => {
if (props.get) props.get();
return value;
}
});
});
this.defWatcherBlock = false;
}
}
load(type, current) {
var data = this.retrieveData(type);
if (current) data = data ? this.mergeDefinition(current, data) : current;
return data;
}
retrieveData(type) {
return this.readFunc ? this.readFunc(this.id, type) : false;
}
mergeDefinition(oldCols, newCols, mergeAllNew) {
var output = [];
newCols = newCols || [];
newCols.forEach((column, to) => {
var from = this._findColumn(oldCols, column), keys;
if (from) {
if (mergeAllNew) keys = Object.keys(column);
else if (this.config.columns === true || this.config.columns == void 0) {
keys = Object.keys(from);
keys.push("width");
} else keys = this.config.columns;
keys.forEach((key) => {
if (key !== "columns" && typeof column[key] !== "undefined") from[key] = column[key];
});
if (from.columns) from.columns = this.mergeDefinition(from.columns, column.columns);
output.push(from);
}
});
oldCols.forEach((column, i) => {
if (!this._findColumn(newCols, column)) if (output.length > i) output.splice(i, 0, column);
else output.push(column);
});
return output;
}
_findColumn(columns, subject) {
var type = subject.columns ? "group" : subject.field ? "field" : "object";
return columns.find(function(col) {
switch (type) {
case "group": return col.title === subject.title && col.columns.length === subject.columns.length;
case "field": return col.field === subject.field;
case "object": return col === subject;
}
});
}
save(type) {
var data = {};
switch (type) {
case "columns":
data = this.parseColumns(this.table.columnManager.getColumns());
break;
case "filter":
data = this.table.modules.filter.getFilters();
break;
case "headerFilter":
data = this.table.modules.filter.getHeaderFilters();
break;
case "sort":
data = this.validateSorters(this.table.modules.sort.getSort());
break;
case "group":
data = this.getGroupConfig();
break;
case "page":
data = this.getPageConfig();
break;
}
if (this.writeFunc) this.writeFunc(this.id, type, data);
}
validateSorters(data) {
data.forEach(function(item) {
item.column = item.field;
delete item.field;
});
return data;
}
getGroupConfig() {
var data = {};
if (this.config.group) {
if (this.config.group === true || this.config.group.groupBy) data.groupBy = this.table.options.groupBy;
if (this.config.group === true || this.config.group.groupStartOpen) data.groupStartOpen = this.table.options.groupStartOpen;
if (this.config.group === true || this.config.group.groupHeader) data.groupHeader = this.table.options.groupHeader;
}
return data;
}
getPageConfig() {
var data = {};
if (this.config.page) {
if (this.config.page === true || this.config.page.size) data.paginationSize = this.table.modules.page.getPageSize();
if (this.config.page === true || this.config.page.page) data.paginationInitialPage = this.table.modules.page.getPage();
}
return data;
}
parseColumns(columns) {
var definitions = [], excludedKeys = [
"headerContextMenu",
"headerMenu",
"contextMenu",
"clickMenu"
];
columns.forEach((column) => {
var defStore = {}, colDef = column.getDefinition(), keys;
if (column.isGroup) {
defStore.title = colDef.title;
defStore.columns = this.parseColumns(column.getColumns());
} else {
defStore.field = column.getField();
if (this.config.columns === true || this.config.columns == void 0) {
keys = Object.keys(colDef);
keys.push("width");
keys.push("visible");
} else keys = this.config.columns;
keys.forEach((key) => {
switch (key) {
case "width":
defStore.width = column.getWidth();
break;
case "visible":
defStore.visible = column.visible;
break;
default: if (typeof colDef[key] !== "function" && excludedKeys.indexOf(key) === -1) defStore[key] = colDef[key];
}
});
}
definitions.push(defStore);
});
return definitions;
}
};
var Popup = class extends Module {
static moduleName = "popup";
constructor(table) {
super(table);
this.columnSubscribers = {};
this.registerTableOption("rowContextPopup", false);
this.registerTableOption("rowClickPopup", false);
this.registerTableOption("rowDblClickPopup", false);
this.registerTableOption("groupContextPopup", false);
this.registerTableOption("groupClickPopup", false);
this.registerTableOption("groupDblClickPopup", false);
this.registerColumnOption("headerContextPopup");
this.registerColumnOption("headerClickPopup");
this.registerColumnOption("headerDblClickPopup");
this.registerColumnOption("headerPopup");
this.registerColumnOption("headerPopupIcon");
this.registerColumnOption("contextPopup");
this.registerColumnOption("clickPopup");
this.registerColumnOption("dblClickPopup");
this.registerComponentFunction("cell", "popup", this._componentPopupCall.bind(this));
this.registerComponentFunction("column", "popup", this._componentPopupCall.bind(this));
this.registerComponentFunction("row", "popup", this._componentPopupCall.bind(this));
this.registerComponentFunction("group", "popup", this._componentPopupCall.bind(this));
}
initialize() {
this.initializeRowWatchers();
this.initializeGroupWatchers();
this.subscribe("column-init", this.initializeColumn.bind(this));
}
_componentPopupCall(component, contents, position) {
this.loadPopupEvent(contents, null, component, position);
}
initializeRowWatchers() {
if (this.table.options.rowContextPopup) {
this.subscribe("row-contextmenu", this.loadPopupEvent.bind(this, this.table.options.rowContextPopup));
this.table.on("rowTapHold", this.loadPopupEvent.bind(this, this.table.options.rowContextPopup));
}
if (this.table.options.rowClickPopup) this.subscribe("row-click", this.loadPopupEvent.bind(this, this.table.options.rowClickPopup));
if (this.table.options.rowDblClickPopup) this.subscribe("row-dblclick", this.loadPopupEvent.bind(this, this.table.options.rowDblClickPopup));
}
initializeGroupWatchers() {
if (this.table.options.groupContextPopup) {
this.subscribe("group-contextmenu", this.loadPopupEvent.bind(this, this.table.options.groupContextPopup));
this.table.on("groupTapHold", this.loadPopupEvent.bind(this, this.table.options.groupContextPopup));
}
if (this.table.options.groupClickPopup) this.subscribe("group-click", this.loadPopupEvent.bind(this, this.table.options.groupClickPopup));
if (this.table.options.groupDblClickPopup) this.subscribe("group-dblclick", this.loadPopupEvent.bind(this, this.table.options.groupDblClickPopup));
}
initializeColumn(column) {
var def = column.definition;
if (def.headerContextPopup && !this.columnSubscribers.headerContextPopup) {
this.columnSubscribers.headerContextPopup = this.loadPopupTableColumnEvent.bind(this, "headerContextPopup");
this.subscribe("column-contextmenu", this.columnSubscribers.headerContextPopup);
this.table.on("headerTapHold", this.loadPopupTableColumnEvent.bind(this, "headerContextPopup"));
}
if (def.headerClickPopup && !this.columnSubscribers.headerClickPopup) {
this.columnSubscribers.headerClickPopup = this.loadPopupTableColumnEvent.bind(this, "headerClickPopup");
this.subscribe("column-click", this.columnSubscribers.headerClickPopup);
}
if (def.headerDblClickPopup && !this.columnSubscribers.headerDblClickPopup) {
this.columnSubscribers.headerDblClickPopup = this.loadPopupTableColumnEvent.bind(this, "headerDblClickPopup");
this.subscribe("column-dblclick", this.columnSubscribers.headerDblClickPopup);
}
if (def.headerPopup) this.initializeColumnHeaderPopup(column);
if (def.contextPopup && !this.columnSubscribers.contextPopup) {
this.columnSubscribers.contextPopup = this.loadPopupTableCellEvent.bind(this, "contextPopup");
this.subscribe("cell-contextmenu", this.columnSubscribers.contextPopup);
this.table.on("cellTapHold", this.loadPopupTableCellEvent.bind(this, "contextPopup"));
}
if (def.clickPopup && !this.columnSubscribers.clickPopup) {
this.columnSubscribers.clickPopup = this.loadPopupTableCellEvent.bind(this, "clickPopup");
this.subscribe("cell-click", this.columnSubscribers.clickPopup);
}
if (def.dblClickPopup && !this.columnSubscribers.dblClickPopup) {
this.columnSubscribers.dblClickPopup = this.loadPopupTableCellEvent.bind(this, "dblClickPopup");
this.subscribe("cell-click", this.columnSubscribers.dblClickPopup);
}
}
initializeColumnHeaderPopup(column) {
var icon = column.definition.headerPopupIcon, headerPopupEl = document.createElement("span");
headerPopupEl.classList.add("tabulator-header-popup-button");
if (icon) {
if (typeof icon === "function") icon = icon(column.getComponent());
if (icon instanceof HTMLElement) headerPopupEl.appendChild(icon);
else headerPopupEl.innerHTML = icon;
} else headerPopupEl.innerHTML = "⋮";
headerPopupEl.addEventListener("click", (e) => {
e.stopPropagation();
e.preventDefault();
this.loadPopupEvent(column.definition.headerPopup, e, column);
});
column.titleElement.insertBefore(headerPopupEl, column.titleElement.firstChild);
}
loadPopupTableCellEvent(option, e, cell) {
if (cell._cell) cell = cell._cell;
if (cell.column.definition[option]) this.loadPopupEvent(cell.column.definition[option], e, cell);
}
loadPopupTableColumnEvent(option, e, column) {
if (column._column) column = column._column;
if (column.definition[option]) this.loadPopupEvent(column.definition[option], e, column);
}
loadPopupEvent(contents, e, component, position) {
var renderedCallback;
function onRendered(callback) {
renderedCallback = callback;
}
if (component._group) component = component._group;
else if (component._row) component = component._row;
contents = typeof contents == "function" ? contents.call(this.table, e, component.getComponent(), onRendered) : contents;
this.loadPopup(e, component, contents, renderedCallback, position);
}
loadPopup(e, component, contents, renderedCallback, position) {
var touch = !(e instanceof MouseEvent), contentsEl, popup;
if (contents instanceof HTMLElement) contentsEl = contents;
else {
contentsEl = document.createElement("div");
contentsEl.innerHTML = contents;
}
contentsEl.classList.add("tabulator-popup");
contentsEl.addEventListener("click", (e) => {
e.stopPropagation();
});
if (!touch) e.preventDefault();
popup = this.popup(contentsEl);
if (typeof renderedCallback === "function") popup.renderCallback(renderedCallback);
if (e) popup.show(e);
else popup.show(component.getElement(), position || "center");
popup.hideOnBlur(() => {
this.dispatchExternal("popupClosed", component.getComponent());
});
this.dispatchExternal("popupOpened", component.getComponent());
}
};
var Print = class extends Module {
static moduleName = "print";
constructor(table) {
super(table);
this.element = false;
this.manualBlock = false;
this.beforeprintEventHandler = null;
this.afterprintEventHandler = null;
this.registerTableOption("printAsHtml", false);
this.registerTableOption("printFormatter", false);
this.registerTableOption("printHeader", false);
this.registerTableOption("printFooter", false);
this.registerTableOption("printStyled", true);
this.registerTableOption("printRowRange", "visible");
this.registerTableOption("printConfig", {});
this.registerColumnOption("print");
this.registerColumnOption("titlePrint");
}
initialize() {
if (this.table.options.printAsHtml) {
this.beforeprintEventHandler = this.replaceTable.bind(this);
this.afterprintEventHandler = this.cleanup.bind(this);
window.addEventListener("beforeprint", this.beforeprintEventHandler);
window.addEventListener("afterprint", this.afterprintEventHandler);
this.subscribe("table-destroy", this.destroy.bind(this));
}
this.registerTableFunction("print", this.printFullscreen.bind(this));
}
destroy() {
if (this.table.options.printAsHtml) {
window.removeEventListener("beforeprint", this.beforeprintEventHandler);
window.removeEventListener("afterprint", this.afterprintEventHandler);
}
}
replaceTable() {
if (!this.manualBlock) {
this.element = document.createElement("div");
this.element.classList.add("tabulator-print-table");
this.element.appendChild(this.table.modules.export.generateTable(this.table.options.printConfig, this.table.options.printStyled, this.table.options.printRowRange, "print"));
this.table.element.style.display = "none";
this.table.element.parentNode.insertBefore(this.element, this.table.element);
}
}
cleanup() {
document.body.classList.remove("tabulator-print-fullscreen-hide");
if (this.element && this.element.parentNode) {
this.element.parentNode.removeChild(this.element);
this.table.element.style.display = "";
}
}
printFullscreen(visible, style, config) {
var scrollX = window.scrollX, scrollY = window.scrollY, headerEl = document.createElement("div"), footerEl = document.createElement("div"), tableEl = this.table.modules.export.generateTable(typeof config != "undefined" ? config : this.table.options.printConfig, typeof style != "undefined" ? style : this.table.options.printStyled, visible || this.table.options.printRowRange, "print"), headerContent, footerContent;
this.manualBlock = true;
this.element = document.createElement("div");
this.element.classList.add("tabulator-print-fullscreen");
if (this.table.options.printHeader) {
headerEl.classList.add("tabulator-print-header");
headerContent = typeof this.table.options.printHeader == "function" ? this.table.options.printHeader.call(this.table) : this.table.options.printHeader;
if (typeof headerContent == "string") headerEl.innerHTML = headerContent;
else headerEl.appendChild(headerContent);
this.element.appendChild(headerEl);
}
this.element.appendChild(tableEl);
if (this.table.options.printFooter) {
footerEl.classList.add("tabulator-print-footer");
footerContent = typeof this.table.options.printFooter == "function" ? this.table.options.printFooter.call(this.table) : this.table.options.printFooter;
if (typeof footerContent == "string") footerEl.innerHTML = footerContent;
else footerEl.appendChild(footerContent);
this.element.appendChild(footerEl);
}
document.body.classList.add("tabulator-print-fullscreen-hide");
document.body.appendChild(this.element);
if (this.table.options.printFormatter) this.table.options.printFormatter(this.element, tableEl);
window.print();
this.cleanup();
window.scrollTo(scrollX, scrollY);
this.manualBlock = false;
}
};
var ReactiveData = class extends Module {
static moduleName = "reactiveData";
constructor(table) {
super(table);
this.data = false;
this.blocked = false;
this.origFuncs = {};
this.currentVersion = 0;
this.registerTableOption("reactiveData", false);
}
initialize() {
if (this.table.options.reactiveData) {
this.subscribe("cell-value-save-before", this.block.bind(this, "cellsave"));
this.subscribe("cell-value-save-after", this.unblock.bind(this, "cellsave"));
this.subscribe("row-data-save-before", this.block.bind(this, "rowsave"));
this.subscribe("row-data-save-after", this.unblock.bind(this, "rowsave"));
this.subscribe("row-data-init-after", this.watchRow.bind(this));
this.subscribe("data-processing", this.watchData.bind(this));
this.subscribe("table-destroy", this.unwatchData.bind(this));
}
}
watchData(data) {
var self = this, version;
this.currentVersion++;
version = this.currentVersion;
this.unwatchData();
this.data = data;
this.origFuncs.push = data.push;
Object.defineProperty(this.data, "push", {
enumerable: false,
configurable: true,
value: function() {
var args = Array.from(arguments), result;
if (!self.blocked && version === self.currentVersion) {
self.block("data-push");
args.forEach((arg) => {
self.table.rowManager.addRowActual(arg, false);
});
result = self.origFuncs.push.apply(data, arguments);
self.unblock("data-push");
}
return result;
}
});
this.origFuncs.unshift = data.unshift;
Object.defineProperty(this.data, "unshift", {
enumerable: false,
configurable: true,
value: function() {
var args = Array.from(arguments), result;
if (!self.blocked && version === self.currentVersion) {
self.block("data-unshift");
args.forEach((arg) => {
self.table.rowManager.addRowActual(arg, true);
});
result = self.origFuncs.unshift.apply(data, arguments);
self.unblock("data-unshift");
}
return result;
}
});
this.origFuncs.shift = data.shift;
Object.defineProperty(this.data, "shift", {
enumerable: false,
configurable: true,
value: function() {
var row, result;
if (!self.blocked && version === self.currentVersion) {
self.block("data-shift");
if (self.data.length) {
row = self.table.rowManager.getRowFromDataObject(self.data[0]);
if (row) row.deleteActual();
}
result = self.origFuncs.shift.call(data);
self.unblock("data-shift");
}
return result;
}
});
this.origFuncs.pop = data.pop;
Object.defineProperty(this.data, "pop", {
enumerable: false,
configurable: true,
value: function() {
var row, result;
if (!self.blocked && version === self.currentVersion) {
self.block("data-pop");
if (self.data.length) {
row = self.table.rowManager.getRowFromDataObject(self.data[self.data.length - 1]);
if (row) row.deleteActual();
}
result = self.origFuncs.pop.call(data);
self.unblock("data-pop");
}
return result;
}
});
this.origFuncs.splice = data.splice;
Object.defineProperty(this.data, "splice", {
enumerable: false,
configurable: true,
value: function() {
var args = Array.from(arguments), start = args[0] < 0 ? data.length + args[0] : args[0], end = args[1], newRows = args[2] ? args.slice(2) : false, startRow, result;
if (!self.blocked && version === self.currentVersion) {
self.block("data-splice");
if (newRows) {
startRow = data[start] ? self.table.rowManager.getRowFromDataObject(data[start]) : false;
if (startRow) newRows.forEach((rowData) => {
self.table.rowManager.addRowActual(rowData, true, startRow, true);
});
else {
newRows = newRows.slice().reverse();
newRows.forEach((rowData) => {
self.table.rowManager.addRowActual(rowData, true, false, true);
});
}
}
if (end !== 0) {
var oldRows = data.slice(start, typeof args[1] === "undefined" ? args[1] : start + end);
oldRows.forEach((rowData, i) => {
var row = self.table.rowManager.getRowFromDataObject(rowData);
if (row) row.deleteActual(i !== oldRows.length - 1);
});
}
if (newRows || end !== 0) self.table.rowManager.reRenderInPosition();
result = self.origFuncs.splice.apply(data, arguments);
self.unblock("data-splice");
}
return result;
}
});
}
unwatchData() {
if (this.data !== false) for (var key in this.origFuncs) Object.defineProperty(this.data, key, {
enumerable: true,
configurable: true,
writable: true,
value: this.origFuncs.key
});
}
watchRow(row) {
var data = row.getData();
for (var key in data) this.watchKey(row, data, key);
if (this.table.options.dataTree) this.watchTreeChildren(row);
}
watchTreeChildren(row) {
var self = this, childField = row.getData()[this.table.options.dataTreeChildField], origFuncs = {};
if (childField) {
origFuncs.push = childField.push;
Object.defineProperty(childField, "push", {
enumerable: false,
configurable: true,
value: () => {
if (!self.blocked) {
self.block("tree-push");
var result = origFuncs.push.apply(childField, arguments);
this.rebuildTree(row);
self.unblock("tree-push");
}
return result;
}
});
origFuncs.unshift = childField.unshift;
Object.defineProperty(childField, "unshift", {
enumerable: false,
configurable: true,
value: () => {
if (!self.blocked) {
self.block("tree-unshift");
var result = origFuncs.unshift.apply(childField, arguments);
this.rebuildTree(row);
self.unblock("tree-unshift");
}
return result;
}
});
origFuncs.shift = childField.shift;
Object.defineProperty(childField, "shift", {
enumerable: false,
configurable: true,
value: () => {
if (!self.blocked) {
self.block("tree-shift");
var result = origFuncs.shift.call(childField);
this.rebuildTree(row);
self.unblock("tree-shift");
}
return result;
}
});
origFuncs.pop = childField.pop;
Object.defineProperty(childField, "pop", {
enumerable: false,
configurable: true,
value: () => {
if (!self.blocked) {
self.block("tree-pop");
var result = origFuncs.pop.call(childField);
this.rebuildTree(row);
self.unblock("tree-pop");
}
return result;
}
});
origFuncs.splice = childField.splice;
Object.defineProperty(childField, "splice", {
enumerable: false,
configurable: true,
value: () => {
if (!self.blocked) {
self.block("tree-splice");
var result = origFuncs.splice.apply(childField, arguments);
this.rebuildTree(row);
self.unblock("tree-splice");
}
return result;
}
});
}
}
rebuildTree(row) {
this.table.modules.dataTree.initializeRow(row);
this.table.modules.dataTree.layoutRow(row);
this.table.rowManager.refreshActiveData("tree", false, true);
}
watchKey(row, data, key) {
var self = this, props = Object.getOwnPropertyDescriptor(data, key), value = data[key], version = this.currentVersion;
Object.defineProperty(data, key, {
set: (newValue) => {
value = newValue;
if (!self.blocked && version === self.currentVersion) {
self.block("key");
var update = {};
update[key] = newValue;
row.updateData(update);
self.unblock("key");
}
if (props.set) props.set(newValue);
},
get: () => {
if (props.get) props.get();
return value;
}
});
}
unwatchRow(row) {
var data = row.getData();
for (var key in data) Object.defineProperty(data, key, { value: data[key] });
}
block(key) {
if (!this.blocked) this.blocked = key;
}
unblock(key) {
if (this.blocked === key) this.blocked = false;
}
};
var ResizeColumns = class extends Module {
static moduleName = "resizeColumns";
constructor(table) {
super(table);
this.startColumn = false;
this.startX = false;
this.startWidth = false;
this.latestX = false;
this.handle = null;
this.initialNextColumn = null;
this.nextColumn = null;
this.initialized = false;
this.registerColumnOption("resizable", true);
this.registerTableOption("resizableColumnFit", false);
this.registerTableOption("resizableColumnGuide", false);
}
initialize() {
this.subscribe("column-rendered", this.layoutColumnHeader.bind(this));
}
initializeEventWatchers() {
if (!this.initialized) {
this.subscribe("cell-rendered", this.layoutCellHandles.bind(this));
this.subscribe("cell-delete", this.deInitializeComponent.bind(this));
this.subscribe("cell-height", this.resizeHandle.bind(this));
this.subscribe("column-moved", this.columnLayoutUpdated.bind(this));
this.subscribe("column-hide", this.deInitializeColumn.bind(this));
this.subscribe("column-show", this.columnLayoutUpdated.bind(this));
this.subscribe("column-width", this.columnWidthUpdated.bind(this));
this.subscribe("column-delete", this.deInitializeComponent.bind(this));
this.subscribe("column-height", this.resizeHandle.bind(this));
this.initialized = true;
}
}
layoutCellHandles(cell) {
if (cell.row.type === "row") {
this.deInitializeComponent(cell);
this.initializeColumn("cell", cell, cell.column, cell.element);
}
}
layoutColumnHeader(column) {
if (column.definition.resizable) {
this.initializeEventWatchers();
this.deInitializeComponent(column);
this.initializeColumn("header", column, column, column.element);
}
}
columnLayoutUpdated(column) {
var prev = column.prevColumn();
this.reinitializeColumn(column);
if (prev) this.reinitializeColumn(prev);
}
columnWidthUpdated(column) {
if (column.modules.frozen) {
if (this.table.modules.frozenColumns.leftColumns.includes(column)) this.table.modules.frozenColumns.leftColumns.forEach((col) => {
this.reinitializeColumn(col);
});
else if (this.table.modules.frozenColumns.rightColumns.includes(column)) this.table.modules.frozenColumns.rightColumns.forEach((col) => {
this.reinitializeColumn(col);
});
}
}
frozenColumnOffset(column) {
var offset = false;
if (column.modules.frozen) {
offset = column.modules.frozen.marginValue;
if (column.modules.frozen.position === "left") offset += column.getWidth() - 3;
else if (offset) offset -= 3;
}
return offset !== false ? offset + "px" : false;
}
reinitializeColumn(column) {
var frozenOffset = this.frozenColumnOffset(column);
column.cells.forEach((cell) => {
if (cell.modules.resize && cell.modules.resize.handleEl) {
if (frozenOffset) {
cell.modules.resize.handleEl.style[column.modules.frozen.position] = frozenOffset;
cell.modules.resize.handleEl.style["z-index"] = 11;
}
cell.element.after(cell.modules.resize.handleEl);
}
});
if (column.modules.resize && column.modules.resize.handleEl) {
if (frozenOffset) column.modules.resize.handleEl.style[column.modules.frozen.position] = frozenOffset;
column.element.after(column.modules.resize.handleEl);
}
}
initializeColumn(type, component, column, element) {
var self = this, variableHeight = false, mode = column.definition.resizable, config = {}, nearestColumn = column.getLastColumn();
if (type === "header") {
variableHeight = column.definition.formatter == "textarea" || column.definition.variableHeight;
config = { variableHeight };
}
if ((mode === true || mode == type) && this._checkResizability(nearestColumn)) {
var handle = document.createElement("span");
handle.className = "tabulator-col-resize-handle";
handle.addEventListener("click", function(e) {
e.stopPropagation();
});
var handleDown = function(e) {
self.startColumn = column;
self.initialNextColumn = self.nextColumn = nearestColumn.nextColumn();
self._mouseDown(e, nearestColumn, handle);
};
handle.addEventListener("mousedown", handleDown);
handle.addEventListener("touchstart", handleDown, { passive: true });
handle.addEventListener("dblclick", (e) => {
var oldWidth = nearestColumn.getWidth();
e.stopPropagation();
nearestColumn.reinitializeWidth(true);
if (oldWidth !== nearestColumn.getWidth()) {
self.dispatch("column-resized", nearestColumn);
self.dispatchExternal("columnResized", nearestColumn.getComponent());
}
});
if (column.modules.frozen) {
handle.style.position = "sticky";
handle.style[column.modules.frozen.position] = this.frozenColumnOffset(column);
}
config.handleEl = handle;
if (element.parentNode && column.visible) element.after(handle);
}
component.modules.resize = config;
}
deInitializeColumn(column) {
this.deInitializeComponent(column);
column.cells.forEach((cell) => {
this.deInitializeComponent(cell);
});
}
deInitializeComponent(component) {
var handleEl;
if (component.modules.resize) {
handleEl = component.modules.resize.handleEl;
if (handleEl && handleEl.parentElement) handleEl.parentElement.removeChild(handleEl);
}
}
resizeHandle(component, height) {
if (component.modules.resize && component.modules.resize.handleEl) component.modules.resize.handleEl.style.height = height;
}
resize(e, column) {
var x = typeof e.clientX === "undefined" ? e.touches[0].clientX : e.clientX, startDiff = x - this.startX, moveDiff = x - this.latestX, blockedBefore, blockedAfter;
this.latestX = x;
if (this.table.rtl) {
startDiff = -startDiff;
moveDiff = -moveDiff;
}
blockedBefore = column.width == column.minWidth || column.width == column.maxWidth;
column.setWidth(this.startWidth + startDiff);
blockedAfter = column.width == column.minWidth || column.width == column.maxWidth;
if (moveDiff < 0) this.nextColumn = this.initialNextColumn;
if (this.table.options.resizableColumnFit && this.nextColumn && !(blockedBefore && blockedAfter)) {
let colWidth = this.nextColumn.getWidth();
if (moveDiff > 0) {
if (colWidth <= this.nextColumn.minWidth) this.nextColumn = this.nextColumn.nextColumn();
}
if (this.nextColumn) this.nextColumn.setWidth(this.nextColumn.getWidth() - moveDiff);
}
this.table.columnManager.rerenderColumns(true);
if (!this.table.browserSlow && column.modules.resize && column.modules.resize.variableHeight) column.checkCellHeights();
}
calcGuidePosition(e, column, handle) {
var mouseX = typeof e.clientX === "undefined" ? e.touches[0].clientX : e.clientX, handleX = handle.getBoundingClientRect().x - this.table.element.getBoundingClientRect().x, tableX = this.table.element.getBoundingClientRect().x, columnX = column.element.getBoundingClientRect().left - tableX, mouseDiff = mouseX - this.startX, pos = Math.max(handleX + mouseDiff, columnX + column.minWidth);
if (column.maxWidth) pos = Math.min(pos, columnX + column.maxWidth);
return pos;
}
_checkResizability(column) {
return column.definition.resizable;
}
_mouseDown(e, column, handle) {
var self = this, guideEl;
this.dispatchExternal("columnResizing", column.getComponent());
if (self.table.options.resizableColumnGuide) {
guideEl = document.createElement("span");
guideEl.classList.add("tabulator-col-resize-guide");
self.table.element.appendChild(guideEl);
setTimeout(() => {
guideEl.style.left = self.calcGuidePosition(e, column, handle) + "px";
});
}
self.table.element.classList.add("tabulator-block-select");
function mouseMove(e) {
if (self.table.options.resizableColumnGuide) guideEl.style.left = self.calcGuidePosition(e, column, handle) + "px";
else self.resize(e, column);
}
function mouseUp(e) {
if (self.table.options.resizableColumnGuide) {
self.resize(e, column);
guideEl.remove();
}
if (self.startColumn.modules.edit) self.startColumn.modules.edit.blocked = false;
if (self.table.browserSlow && column.modules.resize && column.modules.resize.variableHeight) column.checkCellHeights();
document.body.removeEventListener("mouseup", mouseUp);
document.body.removeEventListener("mousemove", mouseMove);
handle.removeEventListener("touchmove", mouseMove);
handle.removeEventListener("touchend", mouseUp);
self.table.element.classList.remove("tabulator-block-select");
if (self.startWidth !== column.getWidth()) {
self.table.columnManager.verticalAlignHeaders();
self.dispatch("column-resized", column);
self.dispatchExternal("columnResized", column.getComponent());
}
}
e.stopPropagation();
if (self.startColumn.modules.edit) self.startColumn.modules.edit.blocked = true;
self.startX = typeof e.clientX === "undefined" ? e.touches[0].clientX : e.clientX;
self.latestX = self.startX;
self.startWidth = column.getWidth();
document.body.addEventListener("mousemove", mouseMove);
document.body.addEventListener("mouseup", mouseUp);
handle.addEventListener("touchmove", mouseMove, { passive: true });
handle.addEventListener("touchend", mouseUp);
}
};
var ResizeRows = class extends Module {
static moduleName = "resizeRows";
constructor(table) {
super(table);
this.startColumn = false;
this.startY = false;
this.startHeight = false;
this.handle = null;
this.prevHandle = null;
this.registerTableOption("resizableRows", false);
this.registerTableOption("resizableRowGuide", false);
}
initialize() {
if (this.table.options.resizableRows) this.subscribe("row-layout-after", this.initializeRow.bind(this));
}
initializeRow(row) {
var self = this, rowEl = row.getElement();
var handle = document.createElement("div");
handle.className = "tabulator-row-resize-handle";
var prevHandle = document.createElement("div");
prevHandle.className = "tabulator-row-resize-handle prev";
handle.addEventListener("click", function(e) {
e.stopPropagation();
});
var handleDown = function(e) {
self.startRow = row;
self._mouseDown(e, row, handle);
};
handle.addEventListener("mousedown", handleDown);
handle.addEventListener("touchstart", handleDown, { passive: true });
prevHandle.addEventListener("click", function(e) {
e.stopPropagation();
});
var prevHandleDown = function(e) {
var prevRow = self.table.rowManager.prevDisplayRow(row);
if (prevRow) {
self.startRow = prevRow;
self._mouseDown(e, prevRow, prevHandle);
}
};
prevHandle.addEventListener("mousedown", prevHandleDown);
prevHandle.addEventListener("touchstart", prevHandleDown, { passive: true });
rowEl.appendChild(handle);
rowEl.appendChild(prevHandle);
}
resize(e, row) {
row.setHeight(this.startHeight + ((typeof e.screenY === "undefined" ? e.touches[0].screenY : e.screenY) - this.startY));
}
calcGuidePosition(e, row, handle) {
var mouseY = typeof e.screenY === "undefined" ? e.touches[0].screenY : e.screenY, handleY = handle.getBoundingClientRect().y - this.table.element.getBoundingClientRect().y, tableY = this.table.element.getBoundingClientRect().y, rowY = row.element.getBoundingClientRect().top - tableY, mouseDiff = mouseY - this.startY;
return Math.max(handleY + mouseDiff, rowY);
}
_mouseDown(e, row, handle) {
var self = this, guideEl;
self.dispatchExternal("rowResizing", row.getComponent());
if (self.table.options.resizableRowGuide) {
guideEl = document.createElement("span");
guideEl.classList.add("tabulator-row-resize-guide");
self.table.element.appendChild(guideEl);
setTimeout(() => {
guideEl.style.top = self.calcGuidePosition(e, row, handle) + "px";
});
}
self.table.element.classList.add("tabulator-block-select");
function mouseMove(e) {
if (self.table.options.resizableRowGuide) guideEl.style.top = self.calcGuidePosition(e, row, handle) + "px";
else self.resize(e, row);
}
function mouseUp(e) {
if (self.table.options.resizableRowGuide) {
self.resize(e, row);
guideEl.remove();
}
document.body.removeEventListener("mouseup", mouseMove);
document.body.removeEventListener("mousemove", mouseMove);
handle.removeEventListener("touchmove", mouseMove);
handle.removeEventListener("touchend", mouseUp);
self.table.element.classList.remove("tabulator-block-select");
self.dispatchExternal("rowResized", row.getComponent());
}
e.stopPropagation();
self.startY = typeof e.screenY === "undefined" ? e.touches[0].screenY : e.screenY;
self.startHeight = row.getHeight();
document.body.addEventListener("mousemove", mouseMove);
document.body.addEventListener("mouseup", mouseUp);
handle.addEventListener("touchmove", mouseMove, { passive: true });
handle.addEventListener("touchend", mouseUp);
}
};
var ResizeTable = class extends Module {
static moduleName = "resizeTable";
constructor(table) {
super(table);
this.binding = false;
this.visibilityObserver = false;
this.resizeObserver = false;
this.containerObserver = false;
this.tableHeight = 0;
this.tableWidth = 0;
this.containerHeight = 0;
this.containerWidth = 0;
this.autoResize = false;
this.visible = false;
this.initialized = false;
this.initialRedraw = false;
this.registerTableOption("autoResize", true);
}
initialize() {
if (this.table.options.autoResize) {
var table = this.table, tableStyle;
this.tableHeight = table.element.clientHeight;
this.tableWidth = table.element.clientWidth;
if (table.element.parentNode) {
this.containerHeight = table.element.parentNode.clientHeight;
this.containerWidth = table.element.parentNode.clientWidth;
}
if (typeof IntersectionObserver !== "undefined" && typeof ResizeObserver !== "undefined" && table.rowManager.getRenderMode() === "virtual") {
this.initializeVisibilityObserver();
this.autoResize = true;
this.resizeObserver = new ResizeObserver((entry) => {
if (!table.browserMobile || table.browserMobile && (!table.modules.edit || table.modules.edit && !table.modules.edit.currentCell)) {
var nodeHeight = Math.floor(entry[0].contentRect.height);
var nodeWidth = Math.floor(entry[0].contentRect.width);
if (this.tableHeight != nodeHeight || this.tableWidth != nodeWidth) {
this.tableHeight = nodeHeight;
this.tableWidth = nodeWidth;
if (table.element.parentNode) {
this.containerHeight = table.element.parentNode.clientHeight;
this.containerWidth = table.element.parentNode.clientWidth;
}
this.redrawTable();
}
}
});
this.resizeObserver.observe(table.element);
tableStyle = window.getComputedStyle(table.element);
if (this.table.element.parentNode && !this.table.rowManager.fixedHeight && (tableStyle.getPropertyValue("max-height") || tableStyle.getPropertyValue("min-height"))) {
this.containerObserver = new ResizeObserver((entry) => {
if (!table.browserMobile || table.browserMobile && (!table.modules.edit || table.modules.edit && !table.modules.edit.currentCell)) {
var nodeHeight = Math.floor(entry[0].contentRect.height);
var nodeWidth = Math.floor(entry[0].contentRect.width);
if (this.containerHeight != nodeHeight || this.containerWidth != nodeWidth) {
this.containerHeight = nodeHeight;
this.containerWidth = nodeWidth;
this.tableHeight = table.element.clientHeight;
this.tableWidth = table.element.clientWidth;
}
this.redrawTable();
}
});
this.containerObserver.observe(this.table.element.parentNode);
}
this.subscribe("table-resize", this.tableResized.bind(this));
} else {
this.binding = function() {
if (!table.browserMobile || table.browserMobile && (!table.modules.edit || table.modules.edit && !table.modules.edit.currentCell)) {
table.columnManager.rerenderColumns(true);
table.redraw();
}
};
window.addEventListener("resize", this.binding);
}
this.subscribe("table-destroy", this.clearBindings.bind(this));
}
}
initializeVisibilityObserver() {
this.visibilityObserver = new IntersectionObserver((entries) => {
this.visible = entries[0].isIntersecting;
if (!this.initialized) {
this.initialized = true;
this.initialRedraw = !this.visible;
} else if (this.visible) {
this.redrawTable(this.initialRedraw);
this.initialRedraw = false;
}
});
this.visibilityObserver.observe(this.table.element);
}
redrawTable(force) {
if (this.initialized && this.visible) {
this.table.columnManager.rerenderColumns(true);
this.table.redraw(force);
}
}
tableResized() {
this.table.rowManager.redraw();
}
clearBindings() {
if (this.binding) window.removeEventListener("resize", this.binding);
if (this.resizeObserver) this.resizeObserver.unobserve(this.table.element);
if (this.visibilityObserver) this.visibilityObserver.unobserve(this.table.element);
if (this.containerObserver) this.containerObserver.unobserve(this.table.element.parentNode);
}
};
function responsiveCollapse(cell, formatterParams, onRendered) {
var el = document.createElement("div"), config = cell.getRow()._row.modules.responsiveLayout;
el.classList.add("tabulator-responsive-collapse-toggle");
el.innerHTML = `<svg class='tabulator-responsive-collapse-toggle-open' viewbox="0 0 24 24">
<line x1="7" y1="12" x2="17" y2="12" fill="none" stroke-width="3" stroke-linecap="round" />
<line y1="7" x1="12" y2="17" x2="12" fill="none" stroke-width="3" stroke-linecap="round" />
</svg>
<svg class='tabulator-responsive-collapse-toggle-close' viewbox="0 0 24 24">
<line x1="7" y1="12" x2="17" y2="12" fill="none" stroke-width="3" stroke-linecap="round" />
</svg>`;
cell.getElement().classList.add("tabulator-row-handle");
function toggleList(isOpen) {
var collapseEl = config.element;
config.open = isOpen;
if (collapseEl) if (config.open) {
el.classList.add("open");
collapseEl.style.display = "";
} else {
el.classList.remove("open");
collapseEl.style.display = "none";
}
}
el.addEventListener("click", function(e) {
e.stopImmediatePropagation();
toggleList(!config.open);
cell.getTable().rowManager.adjustTableSize();
});
toggleList(config.open);
return el;
}
var extensions$2 = { format: { formatters: { responsiveCollapse } } };
var ResponsiveLayout = class extends Module {
static moduleName = "responsiveLayout";
static moduleExtensions = extensions$2;
constructor(table) {
super(table);
this.columns = [];
this.hiddenColumns = [];
this.mode = "";
this.index = 0;
this.collapseFormatter = [];
this.collapseStartOpen = true;
this.collapseHandleColumn = false;
this.registerTableOption("responsiveLayout", false);
this.registerTableOption("responsiveLayoutCollapseStartOpen", true);
this.registerTableOption("responsiveLayoutCollapseUseFormatters", true);
this.registerTableOption("responsiveLayoutCollapseFormatter", false);
this.registerColumnOption("responsive");
}
initialize() {
if (this.table.options.responsiveLayout) {
this.subscribe("column-layout", this.initializeColumn.bind(this));
this.subscribe("column-show", this.updateColumnVisibility.bind(this));
this.subscribe("column-hide", this.updateColumnVisibility.bind(this));
this.subscribe("columns-loaded", this.initializeResponsivity.bind(this));
this.subscribe("column-moved", this.initializeResponsivity.bind(this));
this.subscribe("column-add", this.initializeResponsivity.bind(this));
this.subscribe("column-delete", this.initializeResponsivity.bind(this));
this.subscribe("table-redrawing", this.tableRedraw.bind(this));
if (this.table.options.responsiveLayout === "collapse") {
this.subscribe("row-data-changed", this.generateCollapsedRowContent.bind(this));
this.subscribe("row-init", this.initializeRow.bind(this));
this.subscribe("row-layout", this.layoutRow.bind(this));
}
}
}
tableRedraw(force) {
if (["fitColumns", "fitDataStretch"].indexOf(this.layoutMode()) === -1) {
if (!force) this.update();
}
}
initializeResponsivity() {
var columns = [];
this.mode = this.table.options.responsiveLayout;
this.collapseFormatter = this.table.options.responsiveLayoutCollapseFormatter || this.formatCollapsedData;
this.collapseStartOpen = this.table.options.responsiveLayoutCollapseStartOpen;
this.hiddenColumns = [];
if (this.collapseFormatter) this.collapseFormatter = this.collapseFormatter.bind(this.table);
this.table.columnManager.columnsByIndex.forEach((column, i) => {
if (column.modules.responsive) {
if (column.modules.responsive.order && column.modules.responsive.visible) {
column.modules.responsive.index = i;
columns.push(column);
if (!column.visible && this.mode === "collapse") this.hiddenColumns.push(column);
}
}
});
columns = columns.reverse();
columns = columns.sort((a, b) => {
return b.modules.responsive.order - a.modules.responsive.order || b.modules.responsive.index - a.modules.responsive.index;
});
this.columns = columns;
if (this.mode === "collapse") this.generateCollapsedContent();
for (let col of this.table.columnManager.columnsByIndex) if (col.definition.formatter == "responsiveCollapse") {
this.collapseHandleColumn = col;
break;
}
if (this.collapseHandleColumn) if (this.hiddenColumns.length) this.collapseHandleColumn.show();
else this.collapseHandleColumn.hide();
}
initializeColumn(column) {
var def = column.getDefinition();
column.modules.responsive = {
order: typeof def.responsive === "undefined" ? 1 : def.responsive,
visible: def.visible === false ? false : true
};
}
initializeRow(row) {
var el;
if (row.type !== "calc") {
el = document.createElement("div");
el.classList.add("tabulator-responsive-collapse");
row.modules.responsiveLayout = {
element: el,
open: this.collapseStartOpen
};
if (!this.collapseStartOpen) el.style.display = "none";
}
}
layoutRow(row) {
var rowEl = row.getElement();
if (row.modules.responsiveLayout) {
rowEl.appendChild(row.modules.responsiveLayout.element);
this.generateCollapsedRowContent(row);
}
}
updateColumnVisibility(column, responsiveToggle) {
if (!responsiveToggle && column.modules.responsive) {
column.modules.responsive.visible = column.visible;
this.initializeResponsivity();
}
}
hideColumn(column) {
var colCount = this.hiddenColumns.length;
column.hide(false, true);
if (this.mode === "collapse") {
this.hiddenColumns.unshift(column);
this.generateCollapsedContent();
if (this.collapseHandleColumn && !colCount) this.collapseHandleColumn.show();
}
}
showColumn(column) {
var index;
column.show(false, true);
column.setWidth(column.getWidth());
if (this.mode === "collapse") {
index = this.hiddenColumns.indexOf(column);
if (index > -1) this.hiddenColumns.splice(index, 1);
this.generateCollapsedContent();
if (this.collapseHandleColumn && !this.hiddenColumns.length) this.collapseHandleColumn.hide();
}
}
update() {
var working = true;
while (working) {
let width = this.table.modules.layout.getMode() == "fitColumns" ? this.table.columnManager.getFlexBaseWidth() : this.table.columnManager.getWidth();
let diff = (this.table.options.headerVisible ? this.table.columnManager.element.clientWidth : this.table.element.clientWidth) - width;
if (diff < 0) {
let column = this.columns[this.index];
if (column) {
this.hideColumn(column);
this.index++;
} else working = false;
} else {
let column = this.columns[this.index - 1];
if (column) if (diff > 0) if (diff >= column.getWidth()) {
this.showColumn(column);
this.index--;
} else working = false;
else working = false;
else working = false;
}
if (!this.table.rowManager.activeRowsCount) this.table.rowManager.renderEmptyScroll();
}
}
generateCollapsedContent() {
this.table.rowManager.getDisplayRows().forEach((row) => {
this.generateCollapsedRowContent(row);
});
}
generateCollapsedRowContent(row) {
var el, contents;
if (row.modules.responsiveLayout) {
el = row.modules.responsiveLayout.element;
while (el.firstChild) el.removeChild(el.firstChild);
contents = this.collapseFormatter(this.generateCollapsedRowData(row));
if (contents) el.appendChild(contents);
row.calcHeight(true);
}
}
generateCollapsedRowData(row) {
var data = row.getData(), output = [], mockCellComponent;
this.hiddenColumns.forEach((column) => {
var value = column.getFieldValue(data);
if (column.definition.title && column.field) if (column.modules.format && this.table.options.responsiveLayoutCollapseUseFormatters) {
mockCellComponent = {
value: false,
data: {},
getValue: function() {
return value;
},
getData: function() {
return data;
},
getType: function() {
return "cell";
},
getElement: function() {
return document.createElement("div");
},
getRow: function() {
return row.getComponent();
},
getColumn: function() {
return column.getComponent();
},
getTable: () => {
return this.table;
}
};
function onRendered(callback) {
callback();
}
output.push({
field: column.field,
title: column.definition.title,
value: column.modules.format.formatter.call(this.table.modules.format, mockCellComponent, column.modules.format.params, onRendered)
});
} else output.push({
field: column.field,
title: column.definition.title,
value
});
});
return output;
}
formatCollapsedData(data) {
var list = document.createElement("table");
data.forEach((item) => {
var row = document.createElement("tr");
var titleData = document.createElement("td");
var valueData = document.createElement("td");
var node_content;
var titleHighlight = document.createElement("strong");
titleData.appendChild(titleHighlight);
this.modules.localize.bind("columns|" + item.field, function(text) {
titleHighlight.innerHTML = text || item.title;
});
if (item.value instanceof Node) {
node_content = document.createElement("div");
node_content.appendChild(item.value);
valueData.appendChild(node_content);
} else valueData.innerHTML = item.value;
row.appendChild(titleData);
row.appendChild(valueData);
list.appendChild(row);
});
return Object.keys(data).length ? list : "";
}
};
function rowSelection(cell, formatterParams, onRendered) {
var checkbox = document.createElement("input");
var blocked = false;
checkbox.type = "checkbox";
checkbox.setAttribute("aria-label", "Select Row");
if (this.table.modExists("selectRow", true)) {
checkbox.addEventListener("click", (e) => {
e.stopPropagation();
});
if (typeof cell.getRow == "function") {
var row = cell.getRow();
if (row instanceof RowComponent) {
checkbox.addEventListener("change", (e) => {
if (this.table.options.selectableRowsRangeMode === "click") if (!blocked) row.toggleSelect();
else blocked = false;
else row.toggleSelect();
});
if (this.table.options.selectableRowsRangeMode === "click") checkbox.addEventListener("click", (e) => {
blocked = true;
this.table.modules.selectRow.handleComplexRowClick(row._row, e);
});
checkbox.checked = row.isSelected && row.isSelected();
this.table.modules.selectRow.registerRowSelectCheckbox(row, checkbox);
} else checkbox = "";
} else {
checkbox.addEventListener("change", (e) => {
if (this.table.modules.selectRow.selectedRows.length) this.table.deselectRow();
else this.table.selectRow(formatterParams.rowRange);
});
this.table.modules.selectRow.registerHeaderSelectCheckbox(checkbox);
}
}
return checkbox;
}
var extensions$1 = { format: { formatters: { rowSelection } } };
var SelectRow = class extends Module {
static moduleName = "selectRow";
static moduleExtensions = extensions$1;
constructor(table) {
super(table);
this.selecting = false;
this.lastClickedRow = false;
this.selectPrev = [];
this.selectedRows = [];
this.headerCheckboxElement = null;
this.registerTableOption("selectableRows", "highlight");
this.registerTableOption("selectableRowsRangeMode", "drag");
this.registerTableOption("selectableRowsRollingSelection", true);
this.registerTableOption("selectableRowsPersistence", true);
this.registerTableOption("selectableRowsCheck", function(data, row) {
return true;
});
this.registerTableFunction("selectRow", this.selectRows.bind(this));
this.registerTableFunction("deselectRow", this.deselectRows.bind(this));
this.registerTableFunction("toggleSelectRow", this.toggleRow.bind(this));
this.registerTableFunction("getSelectedRows", this.getSelectedRows.bind(this));
this.registerTableFunction("getSelectedData", this.getSelectedData.bind(this));
this.registerComponentFunction("row", "select", this.selectRows.bind(this));
this.registerComponentFunction("row", "deselect", this.deselectRows.bind(this));
this.registerComponentFunction("row", "toggleSelect", this.toggleRow.bind(this));
this.registerComponentFunction("row", "isSelected", this.isRowSelected.bind(this));
}
initialize() {
this.deprecatedOptionsCheck();
if (this.table.options.selectableRows === "highlight" && this.table.options.selectableRange) this.table.options.selectableRows = false;
if (this.table.options.selectableRows !== false) {
this.subscribe("row-init", this.initializeRow.bind(this));
this.subscribe("row-deleting", this.rowDeleted.bind(this));
this.subscribe("rows-wipe", this.clearSelectionData.bind(this));
this.subscribe("rows-retrieve", this.rowRetrieve.bind(this));
if (this.table.options.selectableRows && !this.table.options.selectableRowsPersistence) this.subscribe("data-refreshing", this.deselectRows.bind(this));
}
}
deprecatedOptionsCheck() {}
rowRetrieve(type, prevValue) {
return type === "selected" ? this.selectedRows : prevValue;
}
rowDeleted(row) {
this._deselectRow(row, true);
}
clearSelectionData(silent) {
var prevSelected = this.selectedRows.length;
this.selecting = false;
this.lastClickedRow = false;
this.selectPrev = [];
this.selectedRows = [];
if (prevSelected && silent !== true) this._rowSelectionChanged();
}
initializeRow(row) {
var self = this, selectable = self.checkRowSelectability(row), element = row.getElement();
var endSelect = function() {
setTimeout(function() {
self.selecting = false;
}, 50);
document.body.removeEventListener("mouseup", endSelect);
};
row.modules.select = { selected: false };
element.classList.toggle("tabulator-selectable", selectable);
element.classList.toggle("tabulator-unselectable", !selectable);
if (self.checkRowSelectability(row)) {
if (self.table.options.selectableRows && self.table.options.selectableRows != "highlight") if (self.table.options.selectableRowsRangeMode === "click") element.addEventListener("click", this.handleComplexRowClick.bind(this, row));
else {
element.addEventListener("click", function(e) {
if (!self.table.modExists("edit") || !self.table.modules.edit.getCurrentCell()) self.table._clearSelection();
if (!self.selecting) self.toggleRow(row);
});
element.addEventListener("mousedown", function(e) {
if (e.shiftKey) {
self.table._clearSelection();
self.selecting = true;
self.selectPrev = [];
document.body.addEventListener("mouseup", endSelect);
document.body.addEventListener("keyup", endSelect);
self.toggleRow(row);
return false;
}
});
element.addEventListener("mouseenter", function(e) {
if (self.selecting) {
self.table._clearSelection();
self.toggleRow(row);
if (self.selectPrev[1] == row) self.toggleRow(self.selectPrev[0]);
}
});
element.addEventListener("mouseout", function(e) {
if (self.selecting) {
self.table._clearSelection();
self.selectPrev.unshift(row);
}
});
}
}
}
handleComplexRowClick(row, e) {
if (e.shiftKey) {
this.table._clearSelection();
this.lastClickedRow = this.lastClickedRow || row;
var lastClickedRowIdx = this.table.rowManager.getDisplayRowIndex(this.lastClickedRow);
var rowIdx = this.table.rowManager.getDisplayRowIndex(row);
var fromRowIdx = lastClickedRowIdx <= rowIdx ? lastClickedRowIdx : rowIdx;
var toRowIdx = lastClickedRowIdx >= rowIdx ? lastClickedRowIdx : rowIdx;
var toggledRows = this.table.rowManager.getDisplayRows().slice(0).splice(fromRowIdx, toRowIdx - fromRowIdx + 1);
if (e.ctrlKey || e.metaKey) {
toggledRows.forEach((toggledRow) => {
if (toggledRow !== this.lastClickedRow) if (this.table.options.selectableRows !== true && !this.isRowSelected(row)) {
if (this.selectedRows.length < this.table.options.selectableRows) this.toggleRow(toggledRow);
} else this.toggleRow(toggledRow);
});
this.lastClickedRow = row;
} else {
this.deselectRows(void 0, true);
if (this.table.options.selectableRows !== true) {
if (toggledRows.length > this.table.options.selectableRows) toggledRows = toggledRows.slice(0, this.table.options.selectableRows);
}
this.selectRows(toggledRows);
}
this.table._clearSelection();
} else if (e.ctrlKey || e.metaKey) {
this.toggleRow(row);
this.lastClickedRow = row;
} else {
this.deselectRows(void 0, true);
this.selectRows(row);
this.lastClickedRow = row;
}
}
checkRowSelectability(row) {
if (row && row.type === "row") return this.table.options.selectableRowsCheck.call(this.table, row.getComponent());
return false;
}
toggleRow(row) {
if (this.checkRowSelectability(row)) if (row.modules.select && row.modules.select.selected) this._deselectRow(row);
else this._selectRow(row);
}
selectRows(rows) {
var changes = [], rowMatch, change;
switch (typeof rows) {
case "undefined":
rowMatch = this.table.rowManager.rows;
break;
case "number":
rowMatch = this.table.rowManager.findRow(rows);
break;
case "string":
rowMatch = this.table.rowManager.findRow(rows);
if (!rowMatch) rowMatch = this.table.rowManager.getRows(rows);
break;
default:
rowMatch = rows;
break;
}
if (Array.isArray(rowMatch)) {
if (rowMatch.length) {
rowMatch.forEach((row) => {
change = this._selectRow(row, true, true);
if (change) changes.push(change);
});
this._rowSelectionChanged(false, changes);
}
} else if (rowMatch) this._selectRow(rowMatch, false, true);
}
_selectRow(rowInfo, silent, force) {
if (!isNaN(this.table.options.selectableRows) && this.table.options.selectableRows !== true && !force) {
if (this.selectedRows.length >= this.table.options.selectableRows) if (this.table.options.selectableRowsRollingSelection) this._deselectRow(this.selectedRows[0]);
else return false;
}
var row = this.table.rowManager.findRow(rowInfo);
if (row) {
if (this.selectedRows.indexOf(row) == -1) {
row.getElement().classList.add("tabulator-selected");
if (!row.modules.select) row.modules.select = {};
row.modules.select.selected = true;
if (row.modules.select.checkboxEl) row.modules.select.checkboxEl.checked = true;
this.selectedRows.push(row);
if (this.table.options.dataTreeSelectPropagate) this.childRowSelection(row, true);
this.dispatchExternal("rowSelected", row.getComponent());
this._rowSelectionChanged(silent, row);
return row;
}
} else if (!silent) console.warn("Selection Error - No such row found, ignoring selection:" + rowInfo);
}
isRowSelected(row) {
return this.selectedRows.indexOf(row) !== -1;
}
deselectRows(rows, silent) {
var changes = [], rowMatch, change;
switch (typeof rows) {
case "undefined":
rowMatch = Object.assign([], this.selectedRows);
break;
case "number":
rowMatch = this.table.rowManager.findRow(rows);
break;
case "string":
rowMatch = this.table.rowManager.findRow(rows);
if (!rowMatch) rowMatch = this.table.rowManager.getRows(rows);
break;
default:
rowMatch = rows;
break;
}
if (Array.isArray(rowMatch)) {
if (rowMatch.length) {
rowMatch.forEach((row) => {
change = this._deselectRow(row, true, true);
if (change) changes.push(change);
});
this._rowSelectionChanged(silent, [], changes);
}
} else if (rowMatch) this._deselectRow(rowMatch, silent, true);
}
_deselectRow(rowInfo, silent) {
var self = this, row = self.table.rowManager.findRow(rowInfo), index, element;
if (row) {
index = self.selectedRows.findIndex(function(selectedRow) {
return selectedRow == row;
});
if (index > -1) {
element = row.getElement();
if (element) element.classList.remove("tabulator-selected");
if (!row.modules.select) row.modules.select = {};
row.modules.select.selected = false;
if (row.modules.select.checkboxEl) row.modules.select.checkboxEl.checked = false;
self.selectedRows.splice(index, 1);
if (this.table.options.dataTreeSelectPropagate) this.childRowSelection(row, false);
this.dispatchExternal("rowDeselected", row.getComponent());
self._rowSelectionChanged(silent, void 0, row);
return row;
}
} else if (!silent) console.warn("Deselection Error - No such row found, ignoring selection:" + rowInfo);
}
getSelectedData() {
var data = [];
this.selectedRows.forEach(function(row) {
data.push(row.getData());
});
return data;
}
getSelectedRows() {
var rows = [];
this.selectedRows.forEach(function(row) {
rows.push(row.getComponent());
});
return rows;
}
_rowSelectionChanged(silent, selected = [], deselected = []) {
if (this.headerCheckboxElement) if (this.selectedRows.length === 0) {
this.headerCheckboxElement.checked = false;
this.headerCheckboxElement.indeterminate = false;
} else if (this.table.rowManager.rows.length === this.selectedRows.length) {
this.headerCheckboxElement.checked = true;
this.headerCheckboxElement.indeterminate = false;
} else {
this.headerCheckboxElement.indeterminate = true;
this.headerCheckboxElement.checked = false;
}
if (!silent) {
if (!Array.isArray(selected)) selected = [selected];
selected = selected.map((row) => row.getComponent());
if (!Array.isArray(deselected)) deselected = [deselected];
deselected = deselected.map((row) => row.getComponent());
this.dispatchExternal("rowSelectionChanged", this.getSelectedData(), this.getSelectedRows(), selected, deselected);
}
}
registerRowSelectCheckbox(row, element) {
if (!row._row.modules.select) row._row.modules.select = {};
row._row.modules.select.checkboxEl = element;
}
registerHeaderSelectCheckbox(element) {
this.headerCheckboxElement = element;
}
childRowSelection(row, select) {
var children = this.table.modules.dataTree.getChildren(row, true, true);
if (select) for (let child of children) this._selectRow(child, true);
else for (let child of children) this._deselectRow(child, true);
}
};
var RangeComponent = class {
constructor(range) {
this._range = range;
return new Proxy(this, { get: function(target, name, receiver) {
if (typeof target[name] !== "undefined") return target[name];
else return target._range.table.componentFunctionBinder.handle("range", target._range, name);
} });
}
getElement() {
return this._range.element;
}
getData() {
return this._range.getData();
}
getCells() {
return this._range.getCells(true, true);
}
getStructuredCells() {
return this._range.getStructuredCells();
}
getRows() {
return this._range.getRows().map((row) => row.getComponent());
}
getColumns() {
return this._range.getColumns().map((column) => column.getComponent());
}
getBounds() {
return this._range.getBounds();
}
getTopEdge() {
return this._range.top;
}
getBottomEdge() {
return this._range.bottom;
}
getLeftEdge() {
return this._range.left;
}
getRightEdge() {
return this._range.right;
}
setBounds(start, end) {
if (this._range.destroyedGuard("setBounds")) this._range.setBounds(start ? start._cell : start, end ? end._cell : end);
}
setStartBound(start) {
if (this._range.destroyedGuard("setStartBound")) {
this._range.setEndBound(start ? start._cell : start);
this._range.rangeManager.layoutElement();
}
}
setEndBound(end) {
if (this._range.destroyedGuard("setEndBound")) {
this._range.setEndBound(end ? end._cell : end);
this._range.rangeManager.layoutElement();
}
}
clearValues() {
if (this._range.destroyedGuard("clearValues")) this._range.clearValues();
}
remove() {
if (this._range.destroyedGuard("remove")) this._range.destroy(true);
}
};
var Range = class extends CoreFeature {
constructor(table, rangeManager, start, end) {
super(table);
this.rangeManager = rangeManager;
this.element = null;
this.initialized = false;
this.initializing = {
start: false,
end: false
};
this.destroyed = false;
this.top = 0;
this.bottom = 0;
this.left = 0;
this.right = 0;
this.table = table;
this.start = {
row: 0,
col: 0
};
this.end = {
row: 0,
col: 0
};
if (this.rangeManager.rowHeader) {
this.left = 1;
this.right = 1;
this.start.col = 1;
this.end.col = 1;
}
this.initElement();
setTimeout(() => {
this.initBounds(start, end);
});
}
initElement() {
this.element = document.createElement("div");
this.element.classList.add("tabulator-range");
}
initBounds(start, end) {
this._updateMinMax();
if (start) this.setBounds(start, end || start);
}
setStart(row, col) {
if (this.start.row !== row || this.start.col !== col) {
this.start.row = row;
this.start.col = col;
this.initializing.start = true;
this._updateMinMax();
}
}
setEnd(row, col) {
if (this.end.row !== row || this.end.col !== col) {
this.end.row = row;
this.end.col = col;
this.initializing.end = true;
this._updateMinMax();
}
}
setBounds(start, end, visibleRows) {
if (start) this.setStartBound(start);
this.setEndBound(end || start);
this.rangeManager.layoutElement(visibleRows);
}
setStartBound(element) {
var row, col;
if (element.type === "column") {
if (this.rangeManager.columnSelection) this.setStart(0, element.getPosition() - 1);
} else {
row = element.row.position - 1;
col = element.column.getPosition() - 1;
if (element.column === this.rangeManager.rowHeader) this.setStart(row, 1);
else this.setStart(row, col);
}
}
setEndBound(element) {
var rowsCount = this._getTableRows().length, row, col, isRowHeader;
if (element.type === "column") {
if (this.rangeManager.columnSelection) {
if (this.rangeManager.selecting === "column") this.setEnd(rowsCount - 1, element.getPosition() - 1);
else if (this.rangeManager.selecting === "cell") this.setEnd(0, element.getPosition() - 1);
}
} else {
row = element.row.position - 1;
col = element.column.getPosition() - 1;
isRowHeader = element.column === this.rangeManager.rowHeader;
if (this.rangeManager.selecting === "row") this.setEnd(row, this._getTableColumns().length - 1);
else if (this.rangeManager.selecting !== "row" && isRowHeader) this.setEnd(row, 0);
else if (this.rangeManager.selecting === "column") this.setEnd(rowsCount - 1, col);
else this.setEnd(row, col);
}
}
_updateMinMax() {
this.top = Math.min(this.start.row, this.end.row);
this.bottom = Math.max(this.start.row, this.end.row);
this.left = Math.min(this.start.col, this.end.col);
this.right = Math.max(this.start.col, this.end.col);
if (this.initialized) this.dispatchExternal("rangeChanged", this.getComponent());
else if (this.initializing.start && this.initializing.end) {
this.initialized = true;
this.dispatchExternal("rangeAdded", this.getComponent());
}
}
_getTableColumns() {
return this.table.columnManager.getVisibleColumnsByIndex();
}
_getTableRows() {
return this.table.rowManager.getDisplayRows().filter((row) => row.type === "row");
}
layout() {
var _vDomTop = this.table.rowManager.renderer.vDomTop, _vDomBottom = this.table.rowManager.renderer.vDomBottom, _vDomLeft = this.table.columnManager.renderer.leftCol, _vDomRight = this.table.columnManager.renderer.rightCol, top, bottom, left, right, topLeftCell, bottomRightCell, topLeftCellEl, bottomRightCellEl, topLeftRowEl, bottomRightRowEl;
if (this.table.options.renderHorizontal === "virtual" && this.rangeManager.rowHeader) _vDomRight += 1;
if (_vDomTop == null) _vDomTop = 0;
if (_vDomBottom == null) _vDomBottom = Infinity;
if (_vDomLeft == null) _vDomLeft = 0;
if (_vDomRight == null) _vDomRight = Infinity;
if (this.overlaps(_vDomLeft, _vDomTop, _vDomRight, _vDomBottom)) {
top = Math.max(this.top, _vDomTop);
bottom = Math.min(this.bottom, _vDomBottom);
left = Math.max(this.left, _vDomLeft);
right = Math.min(this.right, _vDomRight);
topLeftCell = this.rangeManager.getCell(top, left);
bottomRightCell = this.rangeManager.getCell(bottom, right);
topLeftCellEl = topLeftCell.getElement();
bottomRightCellEl = bottomRightCell.getElement();
topLeftRowEl = topLeftCell.row.getElement();
bottomRightRowEl = bottomRightCell.row.getElement();
this.element.classList.add("tabulator-range-active");
if (this.table.rtl) {
this.element.style.right = topLeftRowEl.offsetWidth - topLeftCellEl.offsetLeft - topLeftCellEl.offsetWidth + "px";
this.element.style.width = topLeftCellEl.offsetLeft + topLeftCellEl.offsetWidth - bottomRightCellEl.offsetLeft + "px";
} else {
this.element.style.left = topLeftRowEl.offsetLeft + topLeftCellEl.offsetLeft + "px";
this.element.style.width = bottomRightCellEl.offsetLeft + bottomRightCellEl.offsetWidth - topLeftCellEl.offsetLeft + "px";
}
this.element.style.top = topLeftRowEl.offsetTop + "px";
this.element.style.height = bottomRightRowEl.offsetTop + bottomRightRowEl.offsetHeight - topLeftRowEl.offsetTop + "px";
}
}
atTopLeft(cell) {
return cell.row.position - 1 === this.top && cell.column.getPosition() - 1 === this.left;
}
atBottomRight(cell) {
return cell.row.position - 1 === this.bottom && cell.column.getPosition() - 1 === this.right;
}
occupies(cell) {
return this.occupiesRow(cell.row) && this.occupiesColumn(cell.column);
}
occupiesRow(row) {
return this.top <= row.position - 1 && row.position - 1 <= this.bottom;
}
occupiesColumn(col) {
return this.left <= col.getPosition() - 1 && col.getPosition() - 1 <= this.right;
}
overlaps(left, top, right, bottom) {
if (this.left > right || left > this.right || this.top > bottom || top > this.bottom) return false;
return true;
}
getData() {
var data = [], rows = this.getRows(), columns = this.getColumns();
rows.forEach((row) => {
var rowData = row.getData(), result = {};
columns.forEach((column) => {
result[column.field] = rowData[column.field];
});
data.push(result);
});
return data;
}
getCells(structured, component) {
var cells = [], rows = this.getRows(), columns = this.getColumns();
if (structured) cells = rows.map((row) => {
var arr = [];
row.getCells().forEach((cell) => {
if (columns.includes(cell.column)) arr.push(component ? cell.getComponent() : cell);
});
return arr;
});
else rows.forEach((row) => {
row.getCells().forEach((cell) => {
if (columns.includes(cell.column)) cells.push(component ? cell.getComponent() : cell);
});
});
return cells;
}
getStructuredCells() {
return this.getCells(true, true);
}
getRows() {
return this._getTableRows().slice(this.top, this.bottom + 1);
}
getColumns() {
return this._getTableColumns().slice(this.left, this.right + 1);
}
clearValues() {
var cells = this.getCells();
var clearValue = this.table.options.selectableRangeClearCellsValue;
this.table.blockRedraw();
cells.forEach((cell) => {
cell.setValue(clearValue);
});
this.table.restoreRedraw();
}
getBounds(component) {
var cells = this.getCells(false, component), output = {
start: null,
end: null
};
if (cells.length) {
output.start = cells[0];
output.end = cells[cells.length - 1];
} else console.warn("No bounds defined on range");
return output;
}
getComponent() {
if (!this.component) this.component = new RangeComponent(this);
return this.component;
}
destroy(notify) {
this.destroyed = true;
this.element.remove();
if (notify) this.rangeManager.rangeRemoved(this);
if (this.initialized) this.dispatchExternal("rangeRemoved", this.getComponent());
}
destroyedGuard(func) {
if (this.destroyed) console.warn("You cannot call the " + func + " function on a destroyed range");
return !this.destroyed;
}
};
var extensions = {
keybindings: {
bindings: {
rangeJumpUp: ["ctrl + 38", "meta + 38"],
rangeJumpDown: ["ctrl + 40", "meta + 40"],
rangeJumpLeft: ["ctrl + 37", "meta + 37"],
rangeJumpRight: ["ctrl + 39", "meta + 39"],
rangeExpandUp: "shift + 38",
rangeExpandDown: "shift + 40",
rangeExpandLeft: "shift + 37",
rangeExpandRight: "shift + 39",
rangeExpandJumpUp: ["ctrl + shift + 38", "meta + shift + 38"],
rangeExpandJumpDown: ["ctrl + shift + 40", "meta + shift + 40"],
rangeExpandJumpLeft: ["ctrl + shift + 37", "meta + shift + 37"],
rangeExpandJumpRight: ["ctrl + shift + 39", "meta + shift + 39"]
},
actions: {
rangeJumpLeft: function(e) {
this.dispatch("keybinding-nav-range", e, "left", true, false);
},
rangeJumpRight: function(e) {
this.dispatch("keybinding-nav-range", e, "right", true, false);
},
rangeJumpUp: function(e) {
this.dispatch("keybinding-nav-range", e, "up", true, false);
},
rangeJumpDown: function(e) {
this.dispatch("keybinding-nav-range", e, "down", true, false);
},
rangeExpandLeft: function(e) {
this.dispatch("keybinding-nav-range", e, "left", false, true);
},
rangeExpandRight: function(e) {
this.dispatch("keybinding-nav-range", e, "right", false, true);
},
rangeExpandUp: function(e) {
this.dispatch("keybinding-nav-range", e, "up", false, true);
},
rangeExpandDown: function(e) {
this.dispatch("keybinding-nav-range", e, "down", false, true);
},
rangeExpandJumpLeft: function(e) {
this.dispatch("keybinding-nav-range", e, "left", true, true);
},
rangeExpandJumpRight: function(e) {
this.dispatch("keybinding-nav-range", e, "right", true, true);
},
rangeExpandJumpUp: function(e) {
this.dispatch("keybinding-nav-range", e, "up", true, true);
},
rangeExpandJumpDown: function(e) {
this.dispatch("keybinding-nav-range", e, "down", true, true);
}
}
},
clipboard: {
pasteActions: { range: function(data) {
var rows = [], range = this.table.modules.selectRange.activeRange, singleCell = false, bounds, startCell, startRow, rowWidth, dataLength = data.length;
if (range) {
bounds = range.getBounds();
startCell = bounds.start;
if (bounds.start === bounds.end) singleCell = true;
if (startCell) {
rows = this.table.rowManager.activeRows.slice();
startRow = rows.indexOf(startCell.row);
if (singleCell) rowWidth = data.length;
else rowWidth = rows.indexOf(bounds.end.row) - startRow + 1;
if (startRow > -1) {
this.table.blockRedraw();
rows = rows.slice(startRow, startRow + rowWidth);
rows.forEach((row, i) => {
row.updateData(data[i % dataLength]);
});
this.table.restoreRedraw();
}
}
}
return rows;
} },
pasteParsers: { range: function(clipboard) {
var data = [], rows = [], range = this.table.modules.selectRange.activeRange, singleCell = false, bounds, startCell, colWidth, columnMap, startCol;
if (range) {
bounds = range.getBounds();
startCell = bounds.start;
if (bounds.start === bounds.end) singleCell = true;
if (startCell) {
clipboard = clipboard.split("\n");
clipboard.forEach(function(row) {
data.push(row.split(" "));
});
if (data.length) {
columnMap = this.table.columnManager.getVisibleColumnsByIndex();
startCol = columnMap.indexOf(startCell.column);
if (startCol > -1) {
if (singleCell) colWidth = data[0].length;
else colWidth = columnMap.indexOf(bounds.end.column) - startCol + 1;
columnMap = columnMap.slice(startCol, startCol + colWidth);
data.forEach((item) => {
var row = {};
var itemLength = item.length;
columnMap.forEach(function(col, i) {
row[col.field] = item[i % itemLength];
});
rows.push(row);
});
return rows;
}
}
}
}
return false;
} }
},
export: {
columnLookups: { range: function() {
var columns = this.modules.selectRange.selectedColumns();
if (this.columnManager.rowHeader) columns.unshift(this.columnManager.rowHeader);
return columns;
} },
rowLookups: { range: function() {
return this.modules.selectRange.selectedRows();
} }
}
};
var SelectRange = class extends Module {
static moduleName = "selectRange";
static moduleInitOrder = 1;
static moduleExtensions = extensions;
constructor(table) {
super(table);
this.selecting = "cell";
this.mousedown = false;
this.ranges = [];
this.overlay = null;
this.rowHeader = null;
this.layoutChangeTimeout = null;
this.columnSelection = false;
this.rowSelection = false;
this.maxRanges = 0;
this.activeRange = false;
this.blockKeydown = false;
this.keyDownEvent = this._handleKeyDown.bind(this);
this.mouseUpEvent = this._handleMouseUp.bind(this);
this.registerTableOption("selectableRange", false);
this.registerTableOption("selectableRangeColumns", false);
this.registerTableOption("selectableRangeRows", false);
this.registerTableOption("selectableRangeClearCells", false);
this.registerTableOption("selectableRangeClearCellsValue", void 0);
this.registerTableOption("selectableRangeAutoFocus", true);
this.registerTableFunction("getRangesData", this.getRangesData.bind(this));
this.registerTableFunction("getRanges", this.getRanges.bind(this));
this.registerTableFunction("addRange", this.addRangeFromComponent.bind(this));
this.registerComponentFunction("cell", "getRanges", this.cellGetRanges.bind(this));
this.registerComponentFunction("row", "getRanges", this.rowGetRanges.bind(this));
this.registerComponentFunction("column", "getRanges", this.colGetRanges.bind(this));
}
initialize() {
if (this.options("selectableRange")) {
if (!this.options("selectableRows")) {
this.maxRanges = this.options("selectableRange");
this.initializeTable();
this.initializeWatchers();
} else console.warn("SelectRange functionality cannot be used in conjunction with row selection");
if (this.options("columns").findIndex((column) => column.frozen) > 0) console.warn("Having frozen column in arbitrary position with selectRange option may result in unpredictable behavior.");
if (this.options("columns").filter((column) => column.frozen) > 1) console.warn("Having multiple frozen columns with selectRange option may result in unpredictable behavior.");
}
}
initializeTable() {
this.overlay = document.createElement("div");
this.overlay.classList.add("tabulator-range-overlay");
this.rangeContainer = document.createElement("div");
this.rangeContainer.classList.add("tabulator-range-container");
this.activeRangeCellElement = document.createElement("div");
this.activeRangeCellElement.classList.add("tabulator-range-cell-active");
this.overlay.appendChild(this.rangeContainer);
this.overlay.appendChild(this.activeRangeCellElement);
this.table.rowManager.element.addEventListener("keydown", this.keyDownEvent);
this.resetRanges();
this.table.rowManager.element.appendChild(this.overlay);
this.table.columnManager.element.setAttribute("tabindex", 0);
this.table.element.classList.add("tabulator-ranges");
}
initializeWatchers() {
this.columnSelection = this.options("selectableRangeColumns");
this.rowSelection = this.options("selectableRangeRows");
this.subscribe("column-init", this.initializeColumn.bind(this));
this.subscribe("column-mousedown", this.handleColumnMouseDown.bind(this));
this.subscribe("column-mousemove", this.handleColumnMouseMove.bind(this));
this.subscribe("column-resized", this.handleColumnResized.bind(this));
this.subscribe("column-moving", this.handleColumnMoving.bind(this));
this.subscribe("column-moved", this.handleColumnMoved.bind(this));
this.subscribe("column-width", this.layoutChange.bind(this));
this.subscribe("column-height", this.layoutChange.bind(this));
this.subscribe("column-resized", this.layoutChange.bind(this));
this.subscribe("columns-loaded", this.updateHeaderColumn.bind(this));
this.subscribe("cell-height", this.layoutChange.bind(this));
this.subscribe("cell-rendered", this.renderCell.bind(this));
this.subscribe("cell-mousedown", this.handleCellMouseDown.bind(this));
this.subscribe("cell-mousemove", this.handleCellMouseMove.bind(this));
this.subscribe("cell-click", this.handleCellClick.bind(this));
this.subscribe("cell-editing", this.handleEditingCell.bind(this));
this.subscribe("page-changed", this.redraw.bind(this));
this.subscribe("scroll-vertical", this.layoutChange.bind(this));
this.subscribe("scroll-horizontal", this.layoutChange.bind(this));
this.subscribe("data-destroy", this.tableDestroyed.bind(this));
this.subscribe("data-processed", this.resetRanges.bind(this));
this.subscribe("table-layout", this.layoutElement.bind(this));
this.subscribe("table-redraw", this.redraw.bind(this));
this.subscribe("table-destroy", this.tableDestroyed.bind(this));
this.subscribe("edit-editor-clear", this.finishEditingCell.bind(this));
this.subscribe("edit-blur", this.restoreFocus.bind(this));
this.subscribe("keybinding-nav-prev", this.keyNavigate.bind(this, "left"));
this.subscribe("keybinding-nav-next", this.keyNavigate.bind(this, "right"));
this.subscribe("keybinding-nav-left", this.keyNavigate.bind(this, "left"));
this.subscribe("keybinding-nav-right", this.keyNavigate.bind(this, "right"));
this.subscribe("keybinding-nav-up", this.keyNavigate.bind(this, "up"));
this.subscribe("keybinding-nav-down", this.keyNavigate.bind(this, "down"));
this.subscribe("keybinding-nav-range", this.keyNavigateRange.bind(this));
}
initializeColumn(column) {
if (this.columnSelection && column.definition.headerSort && this.options("headerSortClickElement") !== "icon") console.warn("Using column headerSort with selectableRangeColumns option may result in unpredictable behavior. Consider using headerSortClickElement: 'icon'.");
if (column.modules.edit);
}
updateHeaderColumn() {
var frozenCols;
if (this.rowSelection) {
this.rowHeader = this.table.columnManager.getVisibleColumnsByIndex()[0];
if (this.rowHeader) {
this.rowHeader.definition.cssClass = this.rowHeader.definition.cssClass + " tabulator-range-row-header";
if (this.rowHeader.definition.headerSort) console.warn("Using column headerSort with selectableRangeRows option may result in unpredictable behavior");
if (this.rowHeader.definition.editor) console.warn("Using column editor with selectableRangeRows option may result in unpredictable behavior");
}
}
if (this.table.modules.frozenColumns && this.table.modules.frozenColumns.active) {
frozenCols = this.table.modules.frozenColumns.getFrozenColumns();
if (frozenCols.length > 1 || frozenCols.length === 1 && frozenCols[0] !== this.rowHeader) console.warn("Using frozen columns that are not the range header in combination with the selectRange option may result in unpredictable behavior");
}
}
getRanges() {
return this.ranges.map((range) => range.getComponent());
}
getRangesData() {
return this.ranges.map((range) => range.getData());
}
addRangeFromComponent(start, end) {
start = start ? start._cell : null;
end = end ? end._cell : null;
return this.addRange(start, end);
}
cellGetRanges(cell) {
var ranges = [];
if (cell.column === this.rowHeader) ranges = this.ranges.filter((range) => range.occupiesRow(cell.row));
else ranges = this.ranges.filter((range) => range.occupies(cell));
return ranges.map((range) => range.getComponent());
}
rowGetRanges(row) {
return this.ranges.filter((range) => range.occupiesRow(row)).map((range) => range.getComponent());
}
colGetRanges(col) {
return this.ranges.filter((range) => range.occupiesColumn(col)).map((range) => range.getComponent());
}
_handleMouseUp(e) {
this.mousedown = false;
document.removeEventListener("mouseup", this.mouseUpEvent);
}
_handleKeyDown(e) {
if (!this.blockKeydown && (!this.table.modules.edit || this.table.modules.edit && !this.table.modules.edit.currentCell)) {
if (e.key === "Enter") {
if (this.table.modules.edit && this.table.modules.edit.currentCell) return;
this.table.modules.edit.editCell(this.getActiveCell());
e.preventDefault();
}
if ((e.key === "Backspace" || e.key === "Delete") && this.options("selectableRangeClearCells")) {
if (this.activeRange) this.activeRange.clearValues();
}
}
}
initializeFocus(cell) {
var range;
this.restoreFocus();
try {
if (document.selection) {
range = document.body.createTextRange();
range.moveToElementText(cell.getElement());
range.select();
} else if (window.getSelection) {
range = document.createRange();
range.selectNode(cell.getElement());
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
}
} catch (e) {}
}
restoreFocus(element) {
this.table.rowManager.element.focus();
return true;
}
handleColumnResized(column) {
var selected;
if (this.selecting !== "column" && this.selecting !== "all") return;
selected = this.ranges.some((range) => range.occupiesColumn(column));
if (!selected) return;
this.ranges.forEach((range) => {
range.getColumns(true).forEach((selectedColumn) => {
if (selectedColumn !== column) selectedColumn.setWidth(column.width);
});
});
}
handleColumnMoving(_event, column) {
this.resetRanges().setBounds(column);
this.overlay.style.visibility = "hidden";
}
handleColumnMoved(from, _to, _after) {
this.activeRange.setBounds(from);
this.layoutElement();
}
handleColumnMouseDown(event, column) {
if (event.button === 2 && (this.selecting === "column" || this.selecting === "all") && this.activeRange.occupiesColumn(column)) return;
if (this.table.options.movableColumns && this.selecting === "column" && this.activeRange.occupiesColumn(column)) return;
this.mousedown = true;
document.addEventListener("mouseup", this.mouseUpEvent);
this.newSelection(event, column);
}
handleColumnMouseMove(e, column) {
if (column === this.rowHeader || !this.mousedown || this.selecting === "all") return;
this.activeRange.setBounds(false, column, true);
}
renderCell(cell) {
var el = cell.getElement(), rangeIdx = this.ranges.findIndex((range) => range.occupies(cell));
el.classList.toggle("tabulator-range-selected", rangeIdx !== -1);
el.classList.toggle("tabulator-range-only-cell-selected", this.ranges.length === 1 && this.ranges[0].atTopLeft(cell) && this.ranges[0].atBottomRight(cell));
el.dataset.range = rangeIdx;
}
handleCellMouseDown(event, cell) {
if (event.button === 2 && (this.activeRange.occupies(cell) || (this.selecting === "row" || this.selecting === "all") && this.activeRange.occupiesRow(cell.row))) return;
this.mousedown = true;
document.addEventListener("mouseup", this.mouseUpEvent);
this.newSelection(event, cell);
}
handleCellMouseMove(e, cell) {
if (!this.mousedown || this.selecting === "all") return;
this.activeRange.setBounds(false, cell, true);
}
handleCellClick(e, cell) {
this.initializeFocus(cell);
}
handleEditingCell(cell) {
if (this.activeRange) this.activeRange.setBounds(cell);
}
finishEditingCell() {
this.blockKeydown = true;
this.table.rowManager.element.focus();
setTimeout(() => {
this.blockKeydown = false;
}, 10);
}
keyNavigate(dir, e) {
if (this.navigate(false, false, dir));
e.preventDefault();
}
keyNavigateRange(e, dir, jump, expand) {
if (this.navigate(jump, expand, dir));
e.preventDefault();
}
navigate(jump, expand, dir) {
var moved = false, range, rangeEdge, prevRect, nextRow, nextCol, row, column, rowRect, rowManagerRect, columnRect, columnManagerRect;
if (this.table.modules.edit && this.table.modules.edit.currentCell) return false;
if (this.ranges.length > 1) this.ranges = this.ranges.filter((range) => {
if (range === this.activeRange) {
range.setEnd(range.start.row, range.start.col);
return true;
}
range.destroy();
return false;
});
range = this.activeRange;
prevRect = {
top: range.top,
bottom: range.bottom,
left: range.left,
right: range.right
};
rangeEdge = expand ? range.end : range.start;
nextRow = rangeEdge.row;
nextCol = rangeEdge.col;
if (jump) switch (dir) {
case "left":
nextCol = this.findJumpCellLeft(range.start.row, rangeEdge.col);
break;
case "right":
nextCol = this.findJumpCellRight(range.start.row, rangeEdge.col);
break;
case "up":
nextRow = this.findJumpCellUp(rangeEdge.row, range.start.col);
break;
case "down":
nextRow = this.findJumpCellDown(rangeEdge.row, range.start.col);
break;
}
else {
if (expand) {
if (this.selecting === "row" && (dir === "left" || dir === "right") || this.selecting === "column" && (dir === "up" || dir === "down")) return;
}
switch (dir) {
case "left":
nextCol = Math.max(nextCol - 1, 0);
break;
case "right":
nextCol = Math.min(nextCol + 1, this.getTableColumns().length - 1);
break;
case "up":
nextRow = Math.max(nextRow - 1, 0);
break;
case "down":
nextRow = Math.min(nextRow + 1, this.getTableRows().length - 1);
break;
}
}
if (this.rowHeader && nextCol === 0) nextCol = 1;
if (!expand) range.setStart(nextRow, nextCol);
range.setEnd(nextRow, nextCol);
if (!expand) this.selecting = "cell";
moved = prevRect.top !== range.top || prevRect.bottom !== range.bottom || prevRect.left !== range.left || prevRect.right !== range.right;
if (moved) {
row = this.getRowByRangePos(range.end.row);
column = this.getColumnByRangePos(range.end.col);
rowRect = row.getElement().getBoundingClientRect();
columnRect = column.getElement().getBoundingClientRect();
rowManagerRect = this.table.rowManager.getElement().getBoundingClientRect();
columnManagerRect = this.table.columnManager.getElement().getBoundingClientRect();
if (!(rowRect.top >= rowManagerRect.top && rowRect.bottom <= rowManagerRect.bottom)) if (row.getElement().parentNode && column.getElement().parentNode) this.autoScroll(range, row.getElement(), column.getElement());
else row.getComponent().scrollTo(void 0, false);
if (!(columnRect.left >= columnManagerRect.left + this.getRowHeaderWidth() && columnRect.right <= columnManagerRect.right)) if (row.getElement().parentNode && column.getElement().parentNode) this.autoScroll(range, row.getElement(), column.getElement());
else column.getComponent().scrollTo(void 0, false);
this.layoutElement();
return true;
}
}
rangeRemoved(removed) {
this.ranges = this.ranges.filter((range) => range !== removed);
if (this.activeRange === removed) if (this.ranges.length) this.activeRange = this.ranges[this.ranges.length - 1];
else this.addRange();
this.layoutElement();
}
findJumpRow(column, rows, reverse, emptyStart, emptySide) {
if (reverse) rows = rows.reverse();
return this.findJumpItem(emptyStart, emptySide, rows, function(row) {
return row.getData()[column.getField()];
});
}
findJumpCol(row, columns, reverse, emptyStart, emptySide) {
if (reverse) columns = columns.reverse();
return this.findJumpItem(emptyStart, emptySide, columns, function(column) {
return row.getData()[column.getField()];
});
}
findJumpItem(emptyStart, emptySide, items, valueResolver) {
var nextItem;
for (let currentItem of items) {
let currentValue = valueResolver(currentItem);
if (emptyStart) {
nextItem = currentItem;
if (currentValue) break;
} else if (emptySide) {
nextItem = currentItem;
if (currentValue) break;
} else if (currentValue) nextItem = currentItem;
else break;
}
return nextItem;
}
findJumpCellLeft(rowPos, colPos) {
var row = this.getRowByRangePos(rowPos), columns = this.getTableColumns(), isStartingCellEmpty = this.isEmpty(row.getData()[columns[colPos].getField()]), isLeftOfStartingCellEmpty = columns[colPos - 1] ? this.isEmpty(row.getData()[columns[colPos - 1].getField()]) : false, targetCols = this.rowHeader ? columns.slice(1, colPos) : columns.slice(0, colPos), jumpCol = this.findJumpCol(row, targetCols, true, isStartingCellEmpty, isLeftOfStartingCellEmpty);
if (jumpCol) return jumpCol.getPosition() - 1;
return colPos;
}
findJumpCellRight(rowPos, colPos) {
var row = this.getRowByRangePos(rowPos), columns = this.getTableColumns(), isStartingCellEmpty = this.isEmpty(row.getData()[columns[colPos].getField()]), isRightOfStartingCellEmpty = columns[colPos + 1] ? this.isEmpty(row.getData()[columns[colPos + 1].getField()]) : false, jumpCol = this.findJumpCol(row, columns.slice(colPos + 1, columns.length), false, isStartingCellEmpty, isRightOfStartingCellEmpty);
if (jumpCol) return jumpCol.getPosition() - 1;
return colPos;
}
findJumpCellUp(rowPos, colPos) {
var column = this.getColumnByRangePos(colPos), rows = this.getTableRows(), isStartingCellEmpty = this.isEmpty(rows[rowPos].getData()[column.getField()]), isTopOfStartingCellEmpty = rows[rowPos - 1] ? this.isEmpty(rows[rowPos - 1].getData()[column.getField()]) : false, jumpRow = this.findJumpRow(column, rows.slice(0, rowPos), true, isStartingCellEmpty, isTopOfStartingCellEmpty);
if (jumpRow) return jumpRow.position - 1;
return rowPos;
}
findJumpCellDown(rowPos, colPos) {
var column = this.getColumnByRangePos(colPos), rows = this.getTableRows(), isStartingCellEmpty = this.isEmpty(rows[rowPos].getData()[column.getField()]), isBottomOfStartingCellEmpty = rows[rowPos + 1] ? this.isEmpty(rows[rowPos + 1].getData()[column.getField()]) : false, jumpRow = this.findJumpRow(column, rows.slice(rowPos + 1, rows.length), false, isStartingCellEmpty, isBottomOfStartingCellEmpty);
if (jumpRow) return jumpRow.position - 1;
return rowPos;
}
newSelection(event, element) {
var range;
if (element.type === "column") {
if (!this.columnSelection) return;
if (element === this.rowHeader) {
range = this.resetRanges();
this.selecting = "all";
var topLeftCell, bottomRightCell = this.getCell(-1, -1);
if (this.rowHeader) topLeftCell = this.getCell(0, 1);
else topLeftCell = this.getCell(0, 0);
range.setBounds(topLeftCell, bottomRightCell);
return;
} else this.selecting = "column";
} else if (element.column === this.rowHeader) this.selecting = "row";
else this.selecting = "cell";
if (event.shiftKey) this.activeRange.setBounds(false, element);
else if (event.ctrlKey) this.addRange().setBounds(element);
else this.resetRanges().setBounds(element);
}
autoScroll(range, row, column) {
var tableHolder = this.table.rowManager.element, rect, view, withinHorizontalView, withinVerticalView;
if (typeof row === "undefined") row = this.getRowByRangePos(range.end.row).getElement();
if (typeof column === "undefined") column = this.getColumnByRangePos(range.end.col).getElement();
rect = {
left: column.offsetLeft,
right: column.offsetLeft + column.offsetWidth,
top: row.offsetTop,
bottom: row.offsetTop + row.offsetHeight
};
view = {
left: tableHolder.scrollLeft + this.getRowHeaderWidth(),
right: Math.ceil(tableHolder.scrollLeft + tableHolder.clientWidth),
top: tableHolder.scrollTop,
bottom: tableHolder.scrollTop + tableHolder.offsetHeight - this.table.rowManager.scrollbarWidth
};
withinHorizontalView = view.left < rect.left && rect.left < view.right && view.left < rect.right && rect.right < view.right;
withinVerticalView = view.top < rect.top && rect.top < view.bottom && view.top < rect.bottom && rect.bottom < view.bottom;
if (!withinHorizontalView) {
if (rect.left < view.left) tableHolder.scrollLeft = rect.left - this.getRowHeaderWidth();
else if (rect.right > view.right) tableHolder.scrollLeft = Math.min(rect.right - tableHolder.clientWidth, rect.left - this.getRowHeaderWidth());
}
if (!withinVerticalView) {
if (rect.top < view.top) tableHolder.scrollTop = rect.top;
else if (rect.bottom > view.bottom) tableHolder.scrollTop = rect.bottom - tableHolder.clientHeight;
}
}
layoutChange() {
this.overlay.style.visibility = "hidden";
clearTimeout(this.layoutChangeTimeout);
this.layoutChangeTimeout = setTimeout(this.layoutRanges.bind(this), 200);
}
redraw(force) {
if (force) {
this.selecting = "cell";
this.resetRanges();
this.layoutElement();
}
}
layoutElement(visibleRows) {
var rows;
if (visibleRows) rows = this.table.rowManager.getVisibleRows(true);
else rows = this.table.rowManager.getRows();
rows.forEach((row) => {
if (row.type === "row") {
this.layoutRow(row);
row.cells.forEach((cell) => this.renderCell(cell));
}
});
this.getTableColumns().forEach((column) => {
this.layoutColumn(column);
});
this.layoutRanges();
}
layoutRow(row) {
var el = row.getElement(), selected = false, occupied = this.ranges.some((range) => range.occupiesRow(row));
if (this.selecting === "row") selected = occupied;
else if (this.selecting === "all") selected = true;
el.classList.toggle("tabulator-range-selected", selected);
el.classList.toggle("tabulator-range-highlight", occupied);
}
layoutColumn(column) {
var el = column.getElement(), selected = false, occupied = this.ranges.some((range) => range.occupiesColumn(column));
if (this.selecting === "column") selected = occupied;
else if (this.selecting === "all") selected = true;
el.classList.toggle("tabulator-range-selected", selected);
el.classList.toggle("tabulator-range-highlight", occupied);
}
layoutRanges() {
var activeCell, activeCellEl, activeRowEl;
if (!this.table.initialized) return;
activeCell = this.getActiveCell();
if (!activeCell) return;
activeCellEl = activeCell.getElement();
activeRowEl = activeCell.row.getElement();
if (this.table.rtl) this.activeRangeCellElement.style.right = activeRowEl.offsetWidth - activeCellEl.offsetLeft - activeCellEl.offsetWidth + "px";
else this.activeRangeCellElement.style.left = activeRowEl.offsetLeft + activeCellEl.offsetLeft + "px";
this.activeRangeCellElement.style.top = activeRowEl.offsetTop + "px";
this.activeRangeCellElement.style.width = activeCellEl.offsetWidth + "px";
this.activeRangeCellElement.style.height = activeRowEl.offsetHeight + "px";
this.ranges.forEach((range) => range.layout());
this.overlay.style.visibility = "visible";
}
getCell(rowIdx, colIdx) {
var row;
if (colIdx < 0) {
colIdx = this.getTableColumns().length + colIdx;
if (colIdx < 0) return null;
}
if (rowIdx < 0) rowIdx = this.getTableRows().length + rowIdx;
row = this.table.rowManager.getRowFromPosition(rowIdx + 1);
return row ? row.getCells(false, true).filter((cell) => cell.column.visible)[colIdx] : null;
}
getActiveCell() {
return this.getCell(this.activeRange.start.row, this.activeRange.start.col);
}
getRowByRangePos(pos) {
return this.getTableRows()[pos];
}
getColumnByRangePos(pos) {
return this.getTableColumns()[pos];
}
getTableRows() {
return this.table.rowManager.getDisplayRows().filter((row) => row.type === "row");
}
getTableColumns() {
return this.table.columnManager.getVisibleColumnsByIndex();
}
addRange(start, end) {
var range;
if (this.maxRanges !== true && this.ranges.length >= this.maxRanges) this.ranges.shift().destroy();
range = new Range(this.table, this, start, end);
this.activeRange = range;
this.ranges.push(range);
this.rangeContainer.appendChild(range.element);
return range;
}
resetRanges() {
var range, cell, visibleCells;
this.ranges.forEach((range) => range.destroy());
this.ranges = [];
range = this.addRange();
if (this.table.rowManager.activeRows.length) {
visibleCells = this.table.rowManager.activeRows[0].cells.filter((cell) => cell.column.visible);
cell = visibleCells[this.rowHeader ? 1 : 0];
if (cell) {
range.setBounds(cell);
if (this.options("selectableRangeAutoFocus")) this.initializeFocus(cell);
}
}
return range;
}
tableDestroyed() {
document.removeEventListener("mouseup", this.mouseUpEvent);
this.table.rowManager.element.removeEventListener("keydown", this.keyDownEvent);
}
selectedRows(component) {
return component ? this.activeRange.getRows().map((row) => row.getComponent()) : this.activeRange.getRows();
}
selectedColumns(component) {
return component ? this.activeRange.getColumns().map((col) => col.getComponent()) : this.activeRange.getColumns();
}
getRowHeaderWidth() {
if (!this.rowHeader) return 0;
return this.rowHeader.getElement().offsetWidth;
}
isEmpty(value) {
return value === null || value === void 0 || value === "";
}
};
function number(a, b, aRow, bRow, column, dir, params) {
var alignEmptyValues = params.alignEmptyValues;
var decimal = params.decimalSeparator;
var thousand = params.thousandSeparator;
var emptyAlign = 0;
a = String(a);
b = String(b);
if (thousand) {
a = a.split(thousand).join("");
b = b.split(thousand).join("");
}
if (decimal) {
a = a.split(decimal).join(".");
b = b.split(decimal).join(".");
}
a = parseFloat(a);
b = parseFloat(b);
if (isNaN(a)) emptyAlign = isNaN(b) ? 0 : -1;
else if (isNaN(b)) emptyAlign = 1;
else return a - b;
if (alignEmptyValues === "top" && dir === "desc" || alignEmptyValues === "bottom" && dir === "asc") emptyAlign *= -1;
return emptyAlign;
}
function string(a, b, aRow, bRow, column, dir, params) {
var alignEmptyValues = params.alignEmptyValues;
var emptyAlign = 0;
var locale;
if (!a) emptyAlign = !b ? 0 : -1;
else if (!b) emptyAlign = 1;
else {
switch (typeof params.locale) {
case "boolean":
if (params.locale) locale = this.langLocale();
break;
case "string":
locale = params.locale;
break;
}
return String(a).toLowerCase().localeCompare(String(b).toLowerCase(), locale);
}
if (alignEmptyValues === "top" && dir === "desc" || alignEmptyValues === "bottom" && dir === "asc") emptyAlign *= -1;
return emptyAlign;
}
function datetime(a, b, aRow, bRow, column, dir, params) {
var DT = this.table.dependencyRegistry.lookup(["luxon", "DateTime"], "DateTime");
var format = params.format || "dd/MM/yyyy HH:mm:ss", alignEmptyValues = params.alignEmptyValues, emptyAlign = 0;
if (typeof DT != "undefined") {
if (!DT.isDateTime(a)) if (format === "iso") a = DT.fromISO(String(a));
else a = DT.fromFormat(String(a), format);
if (!DT.isDateTime(b)) if (format === "iso") b = DT.fromISO(String(b));
else b = DT.fromFormat(String(b), format);
if (!a.isValid) emptyAlign = !b.isValid ? 0 : -1;
else if (!b.isValid) emptyAlign = 1;
else return a - b;
if (alignEmptyValues === "top" && dir === "desc" || alignEmptyValues === "bottom" && dir === "asc") emptyAlign *= -1;
return emptyAlign;
} else console.error("Sort Error - 'datetime' sorter is dependant on luxon.js");
}
function date(a, b, aRow, bRow, column, dir, params) {
if (!params.format) params.format = "dd/MM/yyyy";
return datetime.call(this, a, b, aRow, bRow, column, dir, params);
}
function time(a, b, aRow, bRow, column, dir, params) {
if (!params.format) params.format = "HH:mm";
return datetime.call(this, a, b, aRow, bRow, column, dir, params);
}
function boolean(a, b, aRow, bRow, column, dir, params) {
return (a === true || a === "true" || a === "True" || a === 1 ? 1 : 0) - (b === true || b === "true" || b === "True" || b === 1 ? 1 : 0);
}
function array(a, b, aRow, bRow, column, dir, params) {
var type = params.type || "length", alignEmptyValues = params.alignEmptyValues, emptyAlign = 0, table = this.table, valueMap;
if (params.valueMap) if (typeof params.valueMap === "string") valueMap = function(value) {
return value.map((item) => {
return Helpers.retrieveNestedData(table.options.nestedFieldSeparator, params.valueMap, item);
});
};
else valueMap = params.valueMap;
function calc(value) {
var result;
if (valueMap) value = valueMap(value);
switch (type) {
case "length":
result = value.length;
break;
case "sum":
result = value.reduce(function(c, d) {
return c + d;
});
break;
case "max":
result = Math.max.apply(null, value);
break;
case "min":
result = Math.min.apply(null, value);
break;
case "avg":
result = value.reduce(function(c, d) {
return c + d;
}) / value.length;
break;
case "string":
result = value.join("");
break;
}
return result;
}
if (!Array.isArray(a)) emptyAlign = !Array.isArray(b) ? 0 : -1;
else if (!Array.isArray(b)) emptyAlign = 1;
else if (type === "string") return String(calc(a)).toLowerCase().localeCompare(String(calc(b)).toLowerCase());
else return calc(b) - calc(a);
if (alignEmptyValues === "top" && dir === "desc" || alignEmptyValues === "bottom" && dir === "asc") emptyAlign *= -1;
return emptyAlign;
}
function exists(a, b, aRow, bRow, column, dir, params) {
return (typeof a == "undefined" ? 0 : 1) - (typeof b == "undefined" ? 0 : 1);
}
function alphanum(as, bs, aRow, bRow, column, dir, params) {
var a, b, a1, b1, i = 0, L, rx = /(\d+)|(\D+)/g, rd = /\d/;
var alignEmptyValues = params.alignEmptyValues;
var emptyAlign = 0;
if (!as && as !== 0) emptyAlign = !bs && bs !== 0 ? 0 : -1;
else if (!bs && bs !== 0) emptyAlign = 1;
else {
if (isFinite(as) && isFinite(bs)) return as - bs;
a = String(as).toLowerCase();
b = String(bs).toLowerCase();
if (a === b) return 0;
if (!(rd.test(a) && rd.test(b))) return a > b ? 1 : -1;
a = a.match(rx);
b = b.match(rx);
L = a.length > b.length ? b.length : a.length;
while (i < L) {
a1 = a[i];
b1 = b[i++];
if (a1 !== b1) if (isFinite(a1) && isFinite(b1)) {
if (a1.charAt(0) === "0") a1 = "." + a1;
if (b1.charAt(0) === "0") b1 = "." + b1;
return a1 - b1;
} else return a1 > b1 ? 1 : -1;
}
return a.length > b.length;
}
if (alignEmptyValues === "top" && dir === "desc" || alignEmptyValues === "bottom" && dir === "asc") emptyAlign *= -1;
return emptyAlign;
}
var defaultSorters = {
number,
string,
date,
time,
datetime,
boolean,
array,
exists,
alphanum
};
var Sort = class Sort extends Module {
static moduleName = "sort";
static sorters = defaultSorters;
constructor(table) {
super(table);
this.sortList = [];
this.changed = false;
this.registerTableOption("sortMode", "local");
this.registerTableOption("initialSort", false);
this.registerTableOption("columnHeaderSortMulti", true);
this.registerTableOption("sortOrderReverse", false);
this.registerTableOption("headerSortElement", "<div class='tabulator-arrow'></div>");
this.registerTableOption("headerSortClickElement", "header");
this.registerColumnOption("sorter");
this.registerColumnOption("sorterParams");
this.registerColumnOption("headerSort", true);
this.registerColumnOption("headerSortStartingDir");
this.registerColumnOption("headerSortTristate");
}
initialize() {
this.subscribe("column-layout", this.initializeColumn.bind(this));
this.subscribe("table-built", this.tableBuilt.bind(this));
this.registerDataHandler(this.sort.bind(this), 20);
this.registerTableFunction("setSort", this.userSetSort.bind(this));
this.registerTableFunction("getSorters", this.getSort.bind(this));
this.registerTableFunction("clearSort", this.clearSort.bind(this));
if (this.table.options.sortMode === "remote") this.subscribe("data-params", this.remoteSortParams.bind(this));
}
tableBuilt() {
if (this.table.options.initialSort) this.setSort(this.table.options.initialSort);
}
remoteSortParams(data, config, silent, params) {
var sorters = this.getSort();
sorters.forEach((item) => {
delete item.column;
});
params.sort = sorters;
return params;
}
userSetSort(sortList, dir) {
this.setSort(sortList, dir);
this.refreshSort();
}
clearSort() {
this.clear();
this.refreshSort();
}
initializeColumn(column) {
var sorter = false, colEl, arrowEl;
switch (typeof column.definition.sorter) {
case "string":
if (Sort.sorters[column.definition.sorter]) sorter = Sort.sorters[column.definition.sorter];
else console.warn("Sort Error - No such sorter found: ", column.definition.sorter);
break;
case "function":
sorter = column.definition.sorter;
break;
}
column.modules.sort = {
sorter,
dir: "none",
params: column.definition.sorterParams || {},
startingDir: column.definition.headerSortStartingDir || "asc",
tristate: column.definition.headerSortTristate
};
if (column.definition.headerSort !== false) {
colEl = column.getElement();
colEl.classList.add("tabulator-sortable");
arrowEl = document.createElement("div");
arrowEl.classList.add("tabulator-col-sorter");
switch (this.table.options.headerSortClickElement) {
case "icon":
arrowEl.classList.add("tabulator-col-sorter-element");
break;
case "header":
colEl.classList.add("tabulator-col-sorter-element");
break;
default:
colEl.classList.add("tabulator-col-sorter-element");
break;
}
switch (this.table.options.headerSortElement) {
case "function": break;
case "object":
arrowEl.appendChild(this.table.options.headerSortElement);
break;
default: arrowEl.innerHTML = this.table.options.headerSortElement;
}
column.titleHolderElement.appendChild(arrowEl);
column.modules.sort.element = arrowEl;
this.setColumnHeaderSortIcon(column, "none");
if (this.table.options.headerSortClickElement === "icon") arrowEl.addEventListener("mousedown", (e) => {
e.stopPropagation();
});
(this.table.options.headerSortClickElement === "icon" ? arrowEl : colEl).addEventListener("click", (e) => {
var dir = "", sorters = [], match = false;
if (column.modules.sort) {
if (column.modules.sort.tristate) if (column.modules.sort.dir == "none") dir = column.modules.sort.startingDir;
else if (column.modules.sort.dir == column.modules.sort.startingDir) dir = column.modules.sort.dir == "asc" ? "desc" : "asc";
else dir = "none";
else switch (column.modules.sort.dir) {
case "asc":
dir = "desc";
break;
case "desc":
dir = "asc";
break;
default: dir = column.modules.sort.startingDir;
}
if (this.table.options.columnHeaderSortMulti && (e.shiftKey || e.ctrlKey)) {
sorters = this.getSort();
match = sorters.findIndex((sorter) => {
return sorter.field === column.getField();
});
if (match > -1) {
sorters[match].dir = dir;
match = sorters.splice(match, 1)[0];
if (dir != "none") sorters.push(match);
} else if (dir != "none") sorters.push({
column,
dir
});
this.setSort(sorters);
} else if (dir == "none") this.clear();
else this.setSort(column, dir);
this.refreshSort();
}
});
}
}
refreshSort() {
if (this.table.options.sortMode === "remote") this.reloadData(null, false, false);
else this.refreshData(true);
}
hasChanged() {
var changed = this.changed;
this.changed = false;
return changed;
}
getSort() {
var self = this, sorters = [];
self.sortList.forEach(function(item) {
if (item.column) sorters.push({
column: item.column.getComponent(),
field: item.column.getField(),
dir: item.dir
});
});
return sorters;
}
setSort(sortList, dir) {
var self = this, newSortList = [];
if (!Array.isArray(sortList)) sortList = [{
column: sortList,
dir
}];
sortList.forEach(function(item) {
var column = self.table.columnManager.findColumn(item.column);
if (column) {
item.column = column;
newSortList.push(item);
self.changed = true;
} else console.warn("Sort Warning - Sort field does not exist and is being ignored: ", item.column);
});
self.sortList = newSortList;
this.dispatch("sort-changed");
}
clear() {
this.setSort([]);
}
findSorter(column) {
var row = this.table.rowManager.activeRows[0], sorter = "string", field, value;
if (row) {
row = row.getData();
field = column.getField();
if (field) {
value = column.getFieldValue(row);
switch (typeof value) {
case "undefined":
sorter = "string";
break;
case "boolean":
sorter = "boolean";
break;
default:
if (!isNaN(value) && value !== "") sorter = "number";
else if (value.match(/((^[0-9]+[a-z]+)|(^[a-z]+[0-9]+))+$/i)) sorter = "alphanum";
break;
}
}
}
return Sort.sorters[sorter];
}
sort(data, sortOnly) {
var self = this, sortList = this.table.options.sortOrderReverse ? self.sortList.slice().reverse() : self.sortList, sortListActual = [], rowComponents = [];
if (this.subscribedExternal("dataSorting")) this.dispatchExternal("dataSorting", self.getSort());
if (!sortOnly) self.clearColumnHeaders();
if (this.table.options.sortMode !== "remote") {
sortList.forEach(function(item, i) {
var sortObj;
if (item.column) {
sortObj = item.column.modules.sort;
if (sortObj) {
if (!sortObj.sorter) sortObj.sorter = self.findSorter(item.column);
item.params = typeof sortObj.params === "function" ? sortObj.params(item.column.getComponent(), item.dir) : sortObj.params;
sortListActual.push(item);
}
if (!sortOnly) self.setColumnHeader(item.column, item.dir);
}
});
if (sortListActual.length) self._sortItems(data, sortListActual);
} else if (!sortOnly) sortList.forEach(function(item, i) {
self.setColumnHeader(item.column, item.dir);
});
if (this.subscribedExternal("dataSorted")) {
data.forEach((row) => {
rowComponents.push(row.getComponent());
});
this.dispatchExternal("dataSorted", self.getSort(), rowComponents);
}
return data;
}
clearColumnHeaders() {
this.table.columnManager.getRealColumns().forEach((column) => {
if (column.modules.sort) {
column.modules.sort.dir = "none";
column.getElement().setAttribute("aria-sort", "none");
this.setColumnHeaderSortIcon(column, "none");
}
});
}
setColumnHeader(column, dir) {
column.modules.sort.dir = dir;
column.getElement().setAttribute("aria-sort", dir === "asc" ? "ascending" : "descending");
this.setColumnHeaderSortIcon(column, dir);
}
setColumnHeaderSortIcon(column, dir) {
var sortEl = column.modules.sort.element, arrowEl;
if (column.definition.headerSort && typeof this.table.options.headerSortElement === "function") {
while (sortEl.firstChild) sortEl.removeChild(sortEl.firstChild);
arrowEl = this.table.options.headerSortElement.call(this.table, column.getComponent(), dir);
if (typeof arrowEl === "object") sortEl.appendChild(arrowEl);
else sortEl.innerHTML = arrowEl;
}
}
_sortItems(data, sortList) {
var sorterCount = sortList.length - 1;
data.sort((a, b) => {
var result;
for (var i = sorterCount; i >= 0; i--) {
let sortItem = sortList[i];
result = this._sortRow(a, b, sortItem.column, sortItem.dir, sortItem.params);
if (result !== 0) break;
}
return result;
});
}
_sortRow(a, b, column, dir, params) {
var el1Comp, el2Comp;
var el1 = dir == "asc" ? a : b;
var el2 = dir == "asc" ? b : a;
a = column.getFieldValue(el1.getData());
b = column.getFieldValue(el2.getData());
a = typeof a !== "undefined" ? a : "";
b = typeof b !== "undefined" ? b : "";
el1Comp = el1.getComponent();
el2Comp = el2.getComponent();
return column.modules.sort.sorter.call(this, a, b, el1Comp, el2Comp, column.getComponent(), dir, params);
}
};
var GridCalculator = class {
constructor(columns, rows) {
this.columnCount = columns;
this.rowCount = rows;
this.columnString = [];
this.columns = [];
this.rows = [];
}
genColumns(data) {
var colCount = Math.max(this.columnCount, Math.max(...data.map((item) => item.length)));
this.columnString = [];
this.columns = [];
for (let i = 1; i <= colCount; i++) {
this.incrementChar(this.columnString.length - 1);
this.columns.push(this.columnString.join(""));
}
return this.columns;
}
genRows(data) {
var rowCount = Math.max(this.rowCount, data.length);
this.rows = [];
for (let i = 1; i <= rowCount; i++) this.rows.push(i);
return this.rows;
}
incrementChar(i) {
let char = this.columnString[i];
if (char) if (char !== "Z") this.columnString[i] = String.fromCharCode(this.columnString[i].charCodeAt(0) + 1);
else {
this.columnString[i] = "A";
if (i) this.incrementChar(i - 1);
else this.columnString.push("A");
}
else this.columnString.push("A");
}
setRowCount(count) {
this.rowCount = count;
}
setColumnCount(count) {
this.columnCount = count;
}
};
var SheetComponent = class {
constructor(sheet) {
this._sheet = sheet;
return new Proxy(this, { get: function(target, name, receiver) {
if (typeof target[name] !== "undefined") return target[name];
else return target._sheet.table.componentFunctionBinder.handle("sheet", target._sheet, name);
} });
}
getTitle() {
return this._sheet.title;
}
getKey() {
return this._sheet.key;
}
getDefinition() {
return this._sheet.getDefinition();
}
getData() {
return this._sheet.getData();
}
setData(data) {
return this._sheet.setData(data);
}
clear() {
return this._sheet.clear();
}
remove() {
return this._sheet.remove();
}
active() {
return this._sheet.active();
}
setTitle(title) {
return this._sheet.setTitle(title);
}
setRows(rows) {
return this._sheet.setRows(rows);
}
setColumns(columns) {
return this._sheet.setColumns(columns);
}
};
var Sheet = class extends CoreFeature {
constructor(spreadsheetManager, definition) {
super(spreadsheetManager.table);
this.spreadsheetManager = spreadsheetManager;
this.definition = definition;
this.title = this.definition.title || "";
this.key = this.definition.key || this.definition.title;
this.rowCount = this.definition.rows;
this.columnCount = this.definition.columns;
this.data = this.definition.data || [];
this.element = null;
this.isActive = false;
this.grid = new GridCalculator(this.columnCount, this.rowCount);
this.defaultColumnDefinition = {
width: 100,
headerHozAlign: "center",
headerSort: false
};
this.columnDefinition = Object.assign(this.defaultColumnDefinition, this.options("spreadsheetColumnDefinition"));
this.columnDefs = [];
this.rowDefs = [];
this.columnFields = [];
this.columns = [];
this.rows = [];
this.scrollTop = null;
this.scrollLeft = null;
this.initialize();
this.dispatchExternal("sheetAdded", this.getComponent());
}
initialize() {
this.initializeElement();
this.initializeColumns();
this.initializeRows();
}
reinitialize() {
this.initializeColumns();
this.initializeRows();
}
initializeElement() {
this.element = document.createElement("div");
this.element.classList.add("tabulator-spreadsheet-tab");
this.element.innerText = this.title;
this.element.addEventListener("click", () => {
this.spreadsheetManager.loadSheet(this);
});
}
initializeColumns() {
this.grid.setColumnCount(this.columnCount);
this.columnFields = this.grid.genColumns(this.data);
this.columnDefs = [];
this.columnFields.forEach((ref) => {
var def = Object.assign({}, this.columnDefinition);
def.field = ref;
def.title = ref;
this.columnDefs.push(def);
});
}
initializeRows() {
var refs;
this.grid.setRowCount(this.rowCount);
refs = this.grid.genRows(this.data);
this.rowDefs = [];
refs.forEach((ref, i) => {
var def = { "_id": ref };
var data = this.data[i];
if (data) data.forEach((val, j) => {
var field = this.columnFields[j];
if (field) def[field] = val;
});
this.rowDefs.push(def);
});
}
unload() {
this.isActive = false;
this.scrollTop = this.table.rowManager.scrollTop;
this.scrollLeft = this.table.rowManager.scrollLeft;
this.data = this.getData(true);
this.element.classList.remove("tabulator-spreadsheet-tab-active");
}
load() {
var wasInactive = !this.isActive;
this.isActive = true;
this.table.blockRedraw();
this.table.setData([]);
this.table.setColumns(this.columnDefs);
this.table.setData(this.rowDefs);
this.table.restoreRedraw();
if (wasInactive && this.scrollTop !== null) {
this.table.rowManager.element.scrollLeft = this.scrollLeft;
this.table.rowManager.element.scrollTop = this.scrollTop;
}
this.element.classList.add("tabulator-spreadsheet-tab-active");
this.dispatchExternal("sheetLoaded", this.getComponent());
}
getComponent() {
return new SheetComponent(this);
}
getDefinition() {
return {
title: this.title,
key: this.key,
rows: this.rowCount,
columns: this.columnCount,
data: this.getData()
};
}
getData(full) {
var output = [], rowWidths, outputWidth, outputHeight;
this.rowDefs.forEach((rowData) => {
var row = [];
this.columnFields.forEach((field) => {
row.push(rowData[field]);
});
output.push(row);
});
if (!full && !this.options("spreadsheetOutputFull")) {
rowWidths = output.map((row) => row.findLastIndex((val) => typeof val !== "undefined") + 1);
outputWidth = Math.max(...rowWidths);
outputHeight = rowWidths.findLastIndex((width) => width > 0) + 1;
output = output.slice(0, outputHeight);
output = output.map((row) => row.slice(0, outputWidth));
}
return output;
}
setData(data) {
this.data = data;
this.reinitialize();
this.dispatchExternal("sheetUpdated", this.getComponent());
if (this.isActive) this.load();
}
clear() {
this.setData([]);
}
setTitle(title) {
this.title = title;
this.element.innerText = title;
this.dispatchExternal("sheetUpdated", this.getComponent());
}
setRows(rows) {
this.rowCount = rows;
this.initializeRows();
this.dispatchExternal("sheetUpdated", this.getComponent());
if (this.isActive) this.load();
}
setColumns(columns) {
this.columnCount = columns;
this.reinitialize();
this.dispatchExternal("sheetUpdated", this.getComponent());
if (this.isActive) this.load();
}
remove() {
this.spreadsheetManager.removeSheet(this);
}
destroy() {
if (this.element.parentNode) this.element.parentNode.removeChild(this.element);
this.dispatchExternal("sheetRemoved", this.getComponent());
}
active() {
this.spreadsheetManager.loadSheet(this);
}
};
var Spreadsheet = class extends Module {
static moduleName = "spreadsheet";
constructor(table) {
super(table);
this.sheets = [];
this.element = null;
this.registerTableOption("spreadsheet", false);
this.registerTableOption("spreadsheetRows", 50);
this.registerTableOption("spreadsheetColumns", 50);
this.registerTableOption("spreadsheetColumnDefinition", {});
this.registerTableOption("spreadsheetOutputFull", false);
this.registerTableOption("spreadsheetData", false);
this.registerTableOption("spreadsheetSheets", false);
this.registerTableOption("spreadsheetSheetTabs", false);
this.registerTableOption("spreadsheetSheetTabsElement", false);
this.registerTableFunction("setSheets", this.setSheets.bind(this));
this.registerTableFunction("addSheet", this.addSheet.bind(this));
this.registerTableFunction("getSheets", this.getSheets.bind(this));
this.registerTableFunction("getSheetDefinitions", this.getSheetDefinitions.bind(this));
this.registerTableFunction("setSheetData", this.setSheetData.bind(this));
this.registerTableFunction("getSheet", this.getSheet.bind(this));
this.registerTableFunction("getSheetData", this.getSheetData.bind(this));
this.registerTableFunction("clearSheet", this.clearSheet.bind(this));
this.registerTableFunction("removeSheet", this.removeSheetFunc.bind(this));
this.registerTableFunction("activeSheet", this.activeSheetFunc.bind(this));
}
initialize() {
if (this.options("spreadsheet")) {
this.subscribe("table-initialized", this.tableInitialized.bind(this));
this.subscribe("data-loaded", this.loadRemoteData.bind(this));
this.table.options.index = "_id";
if (this.options("spreadsheetData") && this.options("spreadsheetSheets")) {
console.warn("You cannot use spreadsheetData and spreadsheetSheets at the same time, ignoring spreadsheetData");
this.table.options.spreadsheetData = false;
}
this.compatibilityCheck();
if (this.options("spreadsheetSheetTabs")) this.initializeTabset();
}
}
compatibilityCheck() {
if (this.options("data")) console.warn("Do not use the data option when working with spreadsheets, use either spreadsheetData or spreadsheetSheets to pass data into the table");
if (this.options("pagination")) console.warn("The spreadsheet module is not compatible with the pagination module");
if (this.options("groupBy")) console.warn("The spreadsheet module is not compatible with the row grouping module");
if (this.options("responsiveCollapse")) console.warn("The spreadsheet module is not compatible with the responsive collapse module");
}
initializeTabset() {
this.element = document.createElement("div");
this.element.classList.add("tabulator-spreadsheet-tabs");
var altContainer = this.options("spreadsheetSheetTabsElement");
if (altContainer && !(altContainer instanceof HTMLElement)) {
altContainer = document.querySelector(altContainer);
if (!altContainer) console.warn("Unable to find element matching spreadsheetSheetTabsElement selector:", this.options("spreadsheetSheetTabsElement"));
}
if (altContainer) altContainer.appendChild(this.element);
else this.footerAppend(this.element);
}
tableInitialized() {
if (this.sheets.length) this.loadSheet(this.sheets[0]);
else if (this.options("spreadsheetSheets")) this.loadSheets(this.options("spreadsheetSheets"));
else if (this.options("spreadsheetData")) this.loadData(this.options("spreadsheetData"));
}
loadRemoteData(data, data1, data2) {
console.log("data", data, data1, data2);
if (Array.isArray(data)) {
this.table.dataLoader.clearAlert();
this.dispatchExternal("dataLoaded", data);
if (!data.length || Array.isArray(data[0])) this.loadData(data);
else this.loadSheets(data);
} else console.error("Spreadsheet Loading Error - Unable to process remote data due to invalid data type \nExpecting: array \nReceived: ", typeof data, "\nData: ", data);
return false;
}
loadData(data) {
var def = { data };
this.loadSheet(this.newSheet(def));
}
destroySheets() {
this.sheets.forEach((sheet) => {
sheet.destroy();
});
this.sheets = [];
this.activeSheet = null;
}
loadSheets(sheets) {
if (!Array.isArray(sheets)) sheets = [];
this.destroySheets();
sheets.forEach((def) => {
this.newSheet(def);
});
this.loadSheet(this.sheets[0]);
}
loadSheet(sheet) {
if (this.activeSheet !== sheet) {
if (this.activeSheet) this.activeSheet.unload();
this.activeSheet = sheet;
sheet.load();
}
}
newSheet(definition = {}) {
var sheet;
if (!definition.rows) definition.rows = this.options("spreadsheetRows");
if (!definition.columns) definition.columns = this.options("spreadsheetColumns");
sheet = new Sheet(this, definition);
this.sheets.push(sheet);
if (this.element) this.element.appendChild(sheet.element);
return sheet;
}
removeSheet(sheet) {
var index = this.sheets.indexOf(sheet), prevSheet;
if (this.sheets.length > 1) {
if (index > -1) {
this.sheets.splice(index, 1);
sheet.destroy();
if (this.activeSheet === sheet) {
prevSheet = this.sheets[index - 1] || this.sheets[0];
if (prevSheet) this.loadSheet(prevSheet);
else this.activeSheet = null;
}
}
} else console.warn("Unable to remove sheet, at least one sheet must be active");
}
lookupSheet(key) {
if (!key) return this.activeSheet;
else if (key instanceof Sheet) return key;
else if (key instanceof SheetComponent) return key._sheet;
else return this.sheets.find((sheet) => sheet.key === key) || false;
}
setSheets(sheets) {
this.loadSheets(sheets);
return this.getSheets();
}
addSheet(sheet) {
return this.newSheet(sheet).getComponent();
}
getSheetDefinitions() {
return this.sheets.map((sheet) => sheet.getDefinition());
}
getSheets() {
return this.sheets.map((sheet) => sheet.getComponent());
}
getSheet(key) {
var sheet = this.lookupSheet(key);
return sheet ? sheet.getComponent() : false;
}
setSheetData(key, data) {
if (key && !data) {
data = key;
key = false;
}
var sheet = this.lookupSheet(key);
return sheet ? sheet.setData(data) : false;
}
getSheetData(key) {
var sheet = this.lookupSheet(key);
return sheet ? sheet.getData() : false;
}
clearSheet(key) {
var sheet = this.lookupSheet(key);
return sheet ? sheet.clear() : false;
}
removeSheetFunc(key) {
var sheet = this.lookupSheet(key);
if (sheet) this.removeSheet(sheet);
}
activeSheetFunc(key) {
var sheet = this.lookupSheet(key);
return sheet ? this.loadSheet(sheet) : false;
}
};
var Tooltip = class extends Module {
static moduleName = "tooltip";
constructor(table) {
super(table);
this.tooltipSubscriber = null, this.headerSubscriber = null, this.timeout = null;
this.popupInstance = null;
this.registerTableOption("tooltipDelay", 300);
this.registerColumnOption("tooltip");
this.registerColumnOption("headerTooltip");
}
initialize() {
this.deprecatedOptionsCheck();
this.subscribe("column-init", this.initializeColumn.bind(this));
}
deprecatedOptionsCheck() {}
initializeColumn(column) {
if (column.definition.headerTooltip && !this.headerSubscriber) {
this.headerSubscriber = true;
this.subscribe("column-mousemove", this.mousemoveCheck.bind(this, "headerTooltip"));
this.subscribe("column-mouseout", this.mouseoutCheck.bind(this, "headerTooltip"));
}
if (column.definition.tooltip && !this.tooltipSubscriber) {
this.tooltipSubscriber = true;
this.subscribe("cell-mousemove", this.mousemoveCheck.bind(this, "tooltip"));
this.subscribe("cell-mouseout", this.mouseoutCheck.bind(this, "tooltip"));
}
}
mousemoveCheck(action, e, component) {
var tooltip = action === "tooltip" ? component.column.definition.tooltip : component.definition.headerTooltip;
if (tooltip) {
this.clearPopup();
this.timeout = setTimeout(this.loadTooltip.bind(this, e, component, tooltip), this.table.options.tooltipDelay);
}
}
mouseoutCheck(action, e, component) {
if (!this.popupInstance) this.clearPopup();
}
clearPopup(action, e, component) {
clearTimeout(this.timeout);
this.timeout = null;
if (this.popupInstance) this.popupInstance.hide();
}
loadTooltip(e, component, tooltip) {
var contentsEl, renderedCallback, coords;
function onRendered(callback) {
renderedCallback = callback;
}
if (typeof tooltip === "function") tooltip = tooltip(e, component.getComponent(), onRendered);
if (tooltip instanceof HTMLElement) contentsEl = tooltip;
else {
contentsEl = document.createElement("div");
if (tooltip === true) if (component instanceof Cell) tooltip = component.value;
else if (component.definition.field) this.langBind("columns|" + component.definition.field, (value) => {
contentsEl.innerHTML = tooltip = value || component.definition.title;
});
else tooltip = component.definition.title;
contentsEl.innerHTML = tooltip;
}
if (tooltip || tooltip === 0 || tooltip === false) {
contentsEl.classList.add("tabulator-tooltip");
contentsEl.addEventListener("mousemove", (e) => e.preventDefault());
this.popupInstance = this.popup(contentsEl);
if (typeof renderedCallback === "function") this.popupInstance.renderCallback(renderedCallback);
coords = this.popupInstance.containerEventCoords(e);
this.popupInstance.show(coords.x + 15, coords.y + 15).hideOnBlur(() => {
this.dispatchExternal("TooltipClosed", component.getComponent());
this.popupInstance = null;
});
this.dispatchExternal("TooltipOpened", component.getComponent());
}
}
};
var defaultValidators = {
integer: function(cell, value, parameters) {
if (value === "" || value === null || typeof value === "undefined") return true;
value = Number(value);
return !isNaN(value) && isFinite(value) && Math.floor(value) === value;
},
float: function(cell, value, parameters) {
if (value === "" || value === null || typeof value === "undefined") return true;
value = Number(value);
return !isNaN(value) && isFinite(value) && value % 1 !== 0;
},
numeric: function(cell, value, parameters) {
if (value === "" || value === null || typeof value === "undefined") return true;
return !isNaN(value);
},
string: function(cell, value, parameters) {
if (value === "" || value === null || typeof value === "undefined") return true;
return isNaN(value);
},
alphanumeric: function(cell, value, parameters) {
if (value === "" || value === null || typeof value === "undefined") return true;
return new RegExp(/^[a-z0-9]+$/i).test(value);
},
max: function(cell, value, parameters) {
if (value === "" || value === null || typeof value === "undefined") return true;
return parseFloat(value) <= parameters;
},
min: function(cell, value, parameters) {
if (value === "" || value === null || typeof value === "undefined") return true;
return parseFloat(value) >= parameters;
},
starts: function(cell, value, parameters) {
if (value === "" || value === null || typeof value === "undefined") return true;
return String(value).toLowerCase().startsWith(String(parameters).toLowerCase());
},
ends: function(cell, value, parameters) {
if (value === "" || value === null || typeof value === "undefined") return true;
return String(value).toLowerCase().endsWith(String(parameters).toLowerCase());
},
minLength: function(cell, value, parameters) {
if (value === "" || value === null || typeof value === "undefined") return true;
return String(value).length >= parameters;
},
maxLength: function(cell, value, parameters) {
if (value === "" || value === null || typeof value === "undefined") return true;
return String(value).length <= parameters;
},
in: function(cell, value, parameters) {
if (value === "" || value === null || typeof value === "undefined") return true;
if (typeof parameters == "string") parameters = parameters.split("|");
return parameters.indexOf(value) > -1;
},
regex: function(cell, value, parameters) {
if (value === "" || value === null || typeof value === "undefined") return true;
return new RegExp(parameters).test(value);
},
unique: function(cell, value, parameters) {
if (value === "" || value === null || typeof value === "undefined") return true;
var unique = true;
var cellData = cell.getData();
var column = cell.getColumn()._getSelf();
this.table.rowManager.rows.forEach(function(row) {
var data = row.getData();
if (data !== cellData) {
if (value == column.getFieldValue(data)) unique = false;
}
});
return unique;
},
required: function(cell, value, parameters) {
return value !== "" && value !== null && typeof value !== "undefined";
}
};
var allModules = Object.freeze({
__proto__: null,
AccessorModule: Accessor,
AjaxModule: Ajax,
ClipboardModule: Clipboard,
ColumnCalcsModule: ColumnCalcs,
DataTreeModule: DataTree,
DownloadModule: Download,
EditModule: Edit,
ExportModule: Export,
FilterModule: Filter,
FormatModule: Format,
FrozenColumnsModule: FrozenColumns,
FrozenRowsModule: FrozenRows,
GroupRowsModule: GroupRows,
HistoryModule: History,
HtmlTableImportModule: HtmlTableImport,
ImportModule: Import,
InteractionModule: Interaction,
KeybindingsModule: Keybindings,
MenuModule: Menu,
MoveColumnsModule: MoveColumns,
MoveRowsModule: MoveRows,
MutatorModule: Mutator,
PageModule: Page,
PersistenceModule: Persistence,
PopupModule: Popup,
PrintModule: Print,
ReactiveDataModule: ReactiveData,
ResizeColumnsModule: ResizeColumns,
ResizeRowsModule: ResizeRows,
ResizeTableModule: ResizeTable,
ResponsiveLayoutModule: ResponsiveLayout,
SelectRangeModule: SelectRange,
SelectRowModule: SelectRow,
SortModule: Sort,
SpreadsheetModule: Spreadsheet,
TooltipModule: Tooltip,
ValidateModule: class Validate extends Module {
static moduleName = "validate";
static validators = defaultValidators;
constructor(table) {
super(table);
this.invalidCells = [];
this.registerTableOption("validationMode", "blocking");
this.registerColumnOption("validator");
this.registerTableFunction("getInvalidCells", this.getInvalidCells.bind(this));
this.registerTableFunction("clearCellValidation", this.userClearCellValidation.bind(this));
this.registerTableFunction("validate", this.userValidate.bind(this));
this.registerComponentFunction("cell", "isValid", this.cellIsValid.bind(this));
this.registerComponentFunction("cell", "clearValidation", this.clearValidation.bind(this));
this.registerComponentFunction("cell", "validate", this.cellValidate.bind(this));
this.registerComponentFunction("column", "validate", this.columnValidate.bind(this));
this.registerComponentFunction("row", "validate", this.rowValidate.bind(this));
}
initialize() {
this.subscribe("cell-delete", this.clearValidation.bind(this));
this.subscribe("column-layout", this.initializeColumnCheck.bind(this));
this.subscribe("edit-success", this.editValidate.bind(this));
this.subscribe("edit-editor-clear", this.editorClear.bind(this));
this.subscribe("edit-edited-clear", this.editedClear.bind(this));
}
editValidate(cell, value, previousValue) {
var valid = this.table.options.validationMode !== "manual" ? this.validate(cell.column.modules.validate, cell, value) : true;
if (valid !== true) setTimeout(() => {
cell.getElement().classList.add("tabulator-validation-fail");
this.dispatchExternal("validationFailed", cell.getComponent(), value, valid);
});
return valid;
}
editorClear(cell, cancelled) {
if (cancelled) {
if (cell.column.modules.validate) this.cellValidate(cell);
}
cell.getElement().classList.remove("tabulator-validation-fail");
}
editedClear(cell) {
if (cell.modules.validate) cell.modules.validate.invalid = false;
}
cellIsValid(cell) {
return cell.modules.validate ? cell.modules.validate.invalid || true : true;
}
cellValidate(cell) {
return this.validate(cell.column.modules.validate, cell, cell.getValue());
}
columnValidate(column) {
var invalid = [];
column.cells.forEach((cell) => {
if (this.cellValidate(cell) !== true) invalid.push(cell.getComponent());
});
return invalid.length ? invalid : true;
}
rowValidate(row) {
var invalid = [];
row.cells.forEach((cell) => {
if (this.cellValidate(cell) !== true) invalid.push(cell.getComponent());
});
return invalid.length ? invalid : true;
}
userClearCellValidation(cells) {
if (!cells) cells = this.getInvalidCells();
if (!Array.isArray(cells)) cells = [cells];
cells.forEach((cell) => {
this.clearValidation(cell._getSelf());
});
}
userValidate(cells) {
var output = [];
this.table.rowManager.rows.forEach((row) => {
row = row.getComponent();
var valid = row.validate();
if (valid !== true) output = output.concat(valid);
});
return output.length ? output : true;
}
initializeColumnCheck(column) {
if (typeof column.definition.validator !== "undefined") this.initializeColumn(column);
}
initializeColumn(column) {
var self = this, config = [], validator;
if (column.definition.validator) {
if (Array.isArray(column.definition.validator)) column.definition.validator.forEach((item) => {
validator = self._extractValidator(item);
if (validator) config.push(validator);
});
else {
validator = this._extractValidator(column.definition.validator);
if (validator) config.push(validator);
}
column.modules.validate = config.length ? config : false;
}
}
_extractValidator(value) {
var type, params, pos;
switch (typeof value) {
case "string":
pos = value.indexOf(":");
if (pos > -1) {
type = value.substring(0, pos);
params = value.substring(pos + 1);
} else type = value;
return this._buildValidator(type, params);
case "function": return this._buildValidator(value);
case "object": return this._buildValidator(value.type, value.parameters);
}
}
_buildValidator(type, params) {
var func = typeof type == "function" ? type : Validate.validators[type];
if (!func) {
console.warn("Validator Setup Error - No matching validator found:", type);
return false;
} else return {
type: typeof type == "function" ? "function" : type,
func,
params
};
}
validate(validators, cell, value) {
var self = this, failedValidators = [], invalidIndex = this.invalidCells.indexOf(cell);
if (validators) validators.forEach((item) => {
if (!item.func.call(self, cell.getComponent(), value, item.params)) failedValidators.push({
type: item.type,
parameters: item.params
});
});
if (!cell.modules.validate) cell.modules.validate = {};
if (!failedValidators.length) {
cell.modules.validate.invalid = false;
cell.getElement().classList.remove("tabulator-validation-fail");
if (invalidIndex > -1) this.invalidCells.splice(invalidIndex, 1);
} else {
cell.modules.validate.invalid = failedValidators;
if (this.table.options.validationMode !== "manual") cell.getElement().classList.add("tabulator-validation-fail");
if (invalidIndex == -1) this.invalidCells.push(cell);
}
return failedValidators.length ? failedValidators : true;
}
getInvalidCells() {
var output = [];
this.invalidCells.forEach((cell) => {
output.push(cell.getComponent());
});
return output;
}
clearValidation(cell) {
var invalidIndex;
if (cell.modules.validate && cell.modules.validate.invalid) {
cell.getElement().classList.remove("tabulator-validation-fail");
cell.modules.validate.invalid = false;
invalidIndex = this.invalidCells.indexOf(cell);
if (invalidIndex > -1) this.invalidCells.splice(invalidIndex, 1);
}
}
}
});
var defaultOptions = {
debugEventsExternal: false,
debugEventsInternal: false,
debugInvalidOptions: true,
debugInvalidComponentFuncs: true,
debugInitialization: true,
debugDeprecation: true,
height: false,
minHeight: false,
maxHeight: false,
columnHeaderVertAlign: "top",
popupContainer: false,
columns: [],
columnDefaults: {},
rowHeader: false,
data: false,
autoColumns: false,
autoColumnsDefinitions: false,
nestedFieldSeparator: ".",
footerElement: false,
index: "id",
textDirection: "auto",
addRowPos: "bottom",
headerVisible: true,
renderVertical: "virtual",
renderHorizontal: "basic",
renderVerticalBuffer: 0,
scrollToRowPosition: "top",
scrollToRowIfVisible: true,
scrollToColumnPosition: "left",
scrollToColumnIfVisible: true,
rowFormatter: false,
rowFormatterPrint: null,
rowFormatterClipboard: null,
rowFormatterHtmlOutput: null,
rowHeight: null,
placeholder: false,
dataLoader: true,
dataLoaderLoading: false,
dataLoaderError: false,
dataLoaderErrorTimeout: 3e3,
dataSendParams: {},
dataReceiveParams: {},
dependencies: {}
};
var OptionsList = class {
constructor(table, msgType, defaults = {}) {
this.table = table;
this.msgType = msgType;
this.registeredDefaults = Object.assign({}, defaults);
}
register(option, value) {
this.registeredDefaults[option] = value;
}
generate(defaultOptions, userOptions = {}) {
var output = Object.assign({}, this.registeredDefaults), warn = this.table.options.debugInvalidOptions || userOptions.debugInvalidOptions === true;
Object.assign(output, defaultOptions);
for (let key in userOptions) if (!output.hasOwnProperty(key)) {
if (warn) console.warn("Invalid " + this.msgType + " option:", key);
output[key] = userOptions.key;
}
for (let key in output) if (key in userOptions) output[key] = userOptions[key];
else if (Array.isArray(output[key])) output[key] = Object.assign([], output[key]);
else if (typeof output[key] === "object" && output[key] !== null) output[key] = Object.assign({}, output[key]);
else if (typeof output[key] === "undefined") delete output[key];
return output;
}
};
var Renderer = class extends CoreFeature {
constructor(table) {
super(table);
this.elementVertical = table.rowManager.element;
this.elementHorizontal = table.columnManager.element;
this.tableElement = table.rowManager.tableElement;
this.verticalFillMode = "fit";
}
initialize() {}
clearRows() {}
clearColumns() {}
reinitializeColumnWidths(columns) {}
renderRows() {}
renderColumns() {}
rerenderRows(callback) {
if (callback) callback();
}
rerenderColumns(update, blockRedraw) {}
renderRowCells(row) {}
rerenderRowCells(row, force) {}
scrollColumns(left, dir) {}
scrollRows(top, dir) {}
resize() {}
scrollToRow(row) {}
scrollToRowNearestTop(row) {}
visibleRows(includingBuffer) {
return [];
}
rows() {
return this.table.rowManager.getDisplayRows();
}
styleRow(row, index) {
var rowEl = row.getElement();
if (index % 2) {
rowEl.classList.add("tabulator-row-even");
rowEl.classList.remove("tabulator-row-odd");
} else {
rowEl.classList.add("tabulator-row-odd");
rowEl.classList.remove("tabulator-row-even");
}
}
clear() {
this.clearRows();
this.clearColumns();
}
render() {
this.renderRows();
this.renderColumns();
}
rerender(callback) {
this.rerenderRows();
this.rerenderColumns();
}
scrollToRowPosition(row, position, ifVisible) {
var rowIndex = this.rows().indexOf(row), rowEl = row.getElement(), offset = 0;
return new Promise((resolve, reject) => {
if (rowIndex > -1) {
if (typeof ifVisible === "undefined") ifVisible = this.table.options.scrollToRowIfVisible;
if (!ifVisible) {
if (Helpers.elVisible(rowEl)) {
offset = Helpers.elOffset(rowEl).top - Helpers.elOffset(this.elementVertical).top;
if (offset > 0 && offset < this.elementVertical.clientHeight - rowEl.offsetHeight) {
resolve();
return false;
}
}
}
if (typeof position === "undefined") position = this.table.options.scrollToRowPosition;
if (position === "nearest") position = this.scrollToRowNearestTop(row) ? "top" : "bottom";
this.scrollToRow(row);
switch (position) {
case "middle":
case "center":
if (this.elementVertical.scrollHeight - this.elementVertical.scrollTop == this.elementVertical.clientHeight) this.elementVertical.scrollTop = this.elementVertical.scrollTop + (rowEl.offsetTop - this.elementVertical.scrollTop) - (this.elementVertical.scrollHeight - rowEl.offsetTop) / 2;
else this.elementVertical.scrollTop = this.elementVertical.scrollTop - this.elementVertical.clientHeight / 2;
break;
case "bottom":
if (this.elementVertical.scrollHeight - this.elementVertical.scrollTop == this.elementVertical.clientHeight) this.elementVertical.scrollTop = this.elementVertical.scrollTop - (this.elementVertical.scrollHeight - rowEl.offsetTop) + rowEl.offsetHeight;
else this.elementVertical.scrollTop = this.elementVertical.scrollTop - this.elementVertical.clientHeight + rowEl.offsetHeight;
break;
case "top":
this.elementVertical.scrollTop = rowEl.offsetTop;
break;
}
resolve();
} else {
console.warn("Scroll Error - Row not visible");
reject("Scroll Error - Row not visible");
}
});
}
};
var BasicHorizontal = class extends Renderer {
constructor(table) {
super(table);
}
renderRowCells(row, inFragment) {
const rowFrag = document.createDocumentFragment();
row.cells.forEach((cell) => {
rowFrag.appendChild(cell.getElement());
});
row.element.appendChild(rowFrag);
if (!inFragment) row.cells.forEach((cell) => {
cell.cellRendered();
});
}
reinitializeColumnWidths(columns) {
columns.forEach(function(column) {
column.reinitializeWidth();
});
}
};
var VirtualDomHorizontal = class extends Renderer {
constructor(table) {
super(table);
this.leftCol = 0;
this.rightCol = 0;
this.scrollLeft = 0;
this.vDomScrollPosLeft = 0;
this.vDomScrollPosRight = 0;
this.vDomPadLeft = 0;
this.vDomPadRight = 0;
this.fitDataColAvg = 0;
this.windowBuffer = 200;
this.visibleRows = null;
this.initialized = false;
this.isFitData = false;
this.columns = [];
}
initialize() {
this.compatibilityCheck();
this.layoutCheck();
this.vertScrollListen();
}
compatibilityCheck() {
if (this.options("layout") == "fitDataTable") console.warn("Horizontal Virtual DOM is not compatible with fitDataTable layout mode");
if (this.options("responsiveLayout")) console.warn("Horizontal Virtual DOM is not compatible with responsive columns");
if (this.options("rtl")) console.warn("Horizontal Virtual DOM is not currently compatible with RTL text direction");
}
layoutCheck() {
this.isFitData = this.options("layout").startsWith("fitData");
}
vertScrollListen() {
this.subscribe("scroll-vertical", this.clearVisRowCache.bind(this));
this.subscribe("data-refreshed", this.clearVisRowCache.bind(this));
}
clearVisRowCache() {
this.visibleRows = null;
}
renderColumns(row, force) {
this.dataChange();
}
scrollColumns(left, dir) {
if (this.scrollLeft != left) {
this.scrollLeft = left;
this.scroll(left - (this.vDomScrollPosLeft + this.windowBuffer));
}
}
calcWindowBuffer() {
var buffer = this.elementVertical.clientWidth;
this.table.columnManager.columnsByIndex.forEach((column) => {
if (column.visible) {
var width = column.getWidth();
if (width > buffer) buffer = width;
}
});
this.windowBuffer = buffer * 2;
}
rerenderColumns(update, blockRedraw) {
var old = {
cols: this.columns,
leftCol: this.leftCol,
rightCol: this.rightCol
}, colPos = 0;
if (update && !this.initialized) return;
this.clear();
this.calcWindowBuffer();
this.scrollLeft = this.elementVertical.scrollLeft;
this.vDomScrollPosLeft = this.scrollLeft - this.windowBuffer;
this.vDomScrollPosRight = this.scrollLeft + this.elementVertical.clientWidth + this.windowBuffer;
this.table.columnManager.columnsByIndex.forEach((column) => {
var config = {}, width;
if (column.visible) {
if (!column.modules.frozen) {
width = column.getWidth();
config.leftPos = colPos;
config.rightPos = colPos + width;
config.width = width;
if (this.isFitData) config.fitDataCheck = column.modules.vdomHoz ? column.modules.vdomHoz.fitDataCheck : true;
if (colPos + width > this.vDomScrollPosLeft && colPos < this.vDomScrollPosRight) {
if (this.leftCol == -1) {
this.leftCol = this.columns.length;
this.vDomPadLeft = colPos;
}
this.rightCol = this.columns.length;
} else if (this.leftCol !== -1) this.vDomPadRight += width;
this.columns.push(column);
column.modules.vdomHoz = config;
colPos += width;
}
}
});
this.tableElement.style.paddingLeft = this.vDomPadLeft + "px";
this.tableElement.style.paddingRight = this.vDomPadRight + "px";
this.initialized = true;
if (!blockRedraw) {
if (!update || this.reinitChanged(old)) this.reinitializeRows();
}
this.elementVertical.scrollLeft = this.scrollLeft;
}
renderRowCells(row) {
if (this.initialized) this.initializeRow(row);
else {
const rowFrag = document.createDocumentFragment();
row.cells.forEach((cell) => {
rowFrag.appendChild(cell.getElement());
});
row.element.appendChild(rowFrag);
row.cells.forEach((cell) => {
cell.cellRendered();
});
}
}
rerenderRowCells(row, force) {
this.reinitializeRow(row, force);
}
reinitializeColumnWidths(columns) {
for (let i = this.leftCol; i <= this.rightCol; i++) {
let col = this.columns[i];
if (col) col.reinitializeWidth();
}
}
deinitialize() {
this.initialized = false;
}
clear() {
this.columns = [];
this.leftCol = -1;
this.rightCol = 0;
this.vDomScrollPosLeft = 0;
this.vDomScrollPosRight = 0;
this.vDomPadLeft = 0;
this.vDomPadRight = 0;
}
dataChange() {
var change = false, row, rowEl;
if (this.isFitData) {
this.table.columnManager.columnsByIndex.forEach((column) => {
if (!column.definition.width && column.visible) change = true;
});
if (change && this.table.rowManager.getDisplayRows().length) {
this.vDomScrollPosRight = this.scrollLeft + this.elementVertical.clientWidth + this.windowBuffer;
row = this.chain("rows-sample", [1], [], () => {
return this.table.rowManager.getDisplayRows();
})[0];
if (row) {
rowEl = row.getElement();
row.generateCells();
this.tableElement.appendChild(rowEl);
for (let colEnd = 0; colEnd < row.cells.length; colEnd++) {
let cell = row.cells[colEnd];
rowEl.appendChild(cell.getElement());
cell.column.reinitializeWidth();
}
rowEl.parentNode.removeChild(rowEl);
this.rerenderColumns(false, true);
}
}
} else if (this.options("layout") === "fitColumns") {
this.layoutRefresh();
this.rerenderColumns(false, true);
}
}
reinitChanged(old) {
var match = true;
if (old.cols.length !== this.columns.length || old.leftCol !== this.leftCol || old.rightCol !== this.rightCol) return true;
old.cols.forEach((col, i) => {
if (col !== this.columns[i]) match = false;
});
return !match;
}
reinitializeRows() {
var visibleRows = this.getVisibleRows(), otherRows = this.table.rowManager.getRows().filter((row) => !visibleRows.includes(row));
visibleRows.forEach((row) => {
this.reinitializeRow(row, true);
});
otherRows.forEach((row) => {
row.deinitialize();
});
}
getVisibleRows() {
if (!this.visibleRows) this.visibleRows = this.table.rowManager.getVisibleRows();
return this.visibleRows;
}
scroll(diff) {
this.vDomScrollPosLeft += diff;
this.vDomScrollPosRight += diff;
if (Math.abs(diff) > this.windowBuffer / 2) this.rerenderColumns();
else if (diff > 0) {
this.addColRight();
this.removeColLeft();
} else {
this.addColLeft();
this.removeColRight();
}
}
colPositionAdjust(start, end, diff) {
for (let i = start; i < end; i++) {
let column = this.columns[i];
column.modules.vdomHoz.leftPos += diff;
column.modules.vdomHoz.rightPos += diff;
}
}
addColRight() {
var changes = false, working = true;
while (working) {
let column = this.columns[this.rightCol + 1];
if (column) if (column.modules.vdomHoz.leftPos <= this.vDomScrollPosRight) {
changes = true;
this.getVisibleRows().forEach((row) => {
if (row.type !== "group") {
var cell = row.getCell(column);
row.getElement().insertBefore(cell.getElement(), row.getCell(this.columns[this.rightCol]).getElement().nextSibling);
cell.cellRendered();
}
});
this.fitDataColActualWidthCheck(column);
this.rightCol++;
this.getVisibleRows().forEach((row) => {
if (row.type !== "group") row.modules.vdomHoz.rightCol = this.rightCol;
});
if (this.rightCol >= this.columns.length - 1) this.vDomPadRight = 0;
else this.vDomPadRight -= column.getWidth();
} else working = false;
else working = false;
}
if (changes) this.tableElement.style.paddingRight = this.vDomPadRight + "px";
}
addColLeft() {
var changes = false, working = true;
while (working) {
let column = this.columns[this.leftCol - 1];
if (column) if (column.modules.vdomHoz.rightPos >= this.vDomScrollPosLeft) {
changes = true;
this.getVisibleRows().forEach((row) => {
if (row.type !== "group") {
var cell = row.getCell(column);
row.getElement().insertBefore(cell.getElement(), row.getCell(this.columns[this.leftCol]).getElement());
cell.cellRendered();
}
});
this.leftCol--;
this.getVisibleRows().forEach((row) => {
if (row.type !== "group") row.modules.vdomHoz.leftCol = this.leftCol;
});
if (this.leftCol <= 0) this.vDomPadLeft = 0;
else this.vDomPadLeft -= column.getWidth();
let diff = this.fitDataColActualWidthCheck(column);
if (diff) {
this.scrollLeft = this.elementVertical.scrollLeft = this.elementVertical.scrollLeft + diff;
this.vDomPadRight -= diff;
}
} else working = false;
else working = false;
}
if (changes) this.tableElement.style.paddingLeft = this.vDomPadLeft + "px";
}
removeColRight() {
var changes = false, working = true;
while (working) {
let column = this.columns[this.rightCol];
if (column) if (column.modules.vdomHoz.leftPos > this.vDomScrollPosRight) {
changes = true;
this.getVisibleRows().forEach((row) => {
if (row.type !== "group") {
var cell = row.getCell(column);
try {
row.getElement().removeChild(cell.getElement());
} catch (ex) {
console.warn("Could not removeColRight", ex.message);
}
}
});
this.vDomPadRight += column.getWidth();
this.rightCol--;
this.getVisibleRows().forEach((row) => {
if (row.type !== "group") row.modules.vdomHoz.rightCol = this.rightCol;
});
} else working = false;
else working = false;
}
if (changes) this.tableElement.style.paddingRight = this.vDomPadRight + "px";
}
removeColLeft() {
var changes = false, working = true;
while (working) {
let column = this.columns[this.leftCol];
if (column) if (column.modules.vdomHoz.rightPos < this.vDomScrollPosLeft) {
changes = true;
this.getVisibleRows().forEach((row) => {
if (row.type !== "group") {
var cell = row.getCell(column);
try {
row.getElement().removeChild(cell.getElement());
} catch (ex) {
console.warn("Could not removeColLeft", ex.message);
}
}
});
this.vDomPadLeft += column.getWidth();
this.leftCol++;
this.getVisibleRows().forEach((row) => {
if (row.type !== "group") row.modules.vdomHoz.leftCol = this.leftCol;
});
} else working = false;
else working = false;
}
if (changes) this.tableElement.style.paddingLeft = this.vDomPadLeft + "px";
}
fitDataColActualWidthCheck(column) {
var newWidth, widthDiff;
if (column.modules.vdomHoz.fitDataCheck) {
column.reinitializeWidth();
newWidth = column.getWidth();
widthDiff = newWidth - column.modules.vdomHoz.width;
if (widthDiff) {
column.modules.vdomHoz.rightPos += widthDiff;
column.modules.vdomHoz.width = newWidth;
this.colPositionAdjust(this.columns.indexOf(column) + 1, this.columns.length, widthDiff);
}
column.modules.vdomHoz.fitDataCheck = false;
}
return widthDiff;
}
initializeRow(row) {
if (row.type !== "group") {
row.modules.vdomHoz = {
leftCol: this.leftCol,
rightCol: this.rightCol
};
if (this.table.modules.frozenColumns) this.table.modules.frozenColumns.leftColumns.forEach((column) => {
this.appendCell(row, column);
});
for (let i = this.leftCol; i <= this.rightCol; i++) this.appendCell(row, this.columns[i]);
if (this.table.modules.frozenColumns) this.table.modules.frozenColumns.rightColumns.forEach((column) => {
this.appendCell(row, column);
});
}
}
appendCell(row, column) {
if (column && column.visible) {
let cell = row.getCell(column);
row.getElement().appendChild(cell.getElement());
cell.cellRendered();
}
}
reinitializeRow(row, force) {
if (row.type !== "group") {
if (force || !row.modules.vdomHoz || row.modules.vdomHoz.leftCol !== this.leftCol || row.modules.vdomHoz.rightCol !== this.rightCol) {
var rowEl = row.getElement();
while (rowEl.firstChild) rowEl.removeChild(rowEl.firstChild);
this.initializeRow(row);
}
}
}
};
var ColumnManager = class extends CoreFeature {
constructor(table) {
super(table);
this.blockHozScrollEvent = false;
this.headersElement = null;
this.contentsElement = null;
this.rowHeader = null;
this.element = null;
this.columns = [];
this.columnsByIndex = [];
this.columnsByField = {};
this.scrollLeft = 0;
this.optionsList = new OptionsList(this.table, "column definition", defaultColumnOptions);
this.redrawBlock = false;
this.redrawBlockUpdate = null;
this.renderer = null;
}
initialize() {
this.initializeRenderer();
this.headersElement = this.createHeadersElement();
this.contentsElement = this.createHeaderContentsElement();
this.element = this.createHeaderElement();
this.contentsElement.insertBefore(this.headersElement, this.contentsElement.firstChild);
this.element.insertBefore(this.contentsElement, this.element.firstChild);
this.initializeScrollWheelWatcher();
this.subscribe("scroll-horizontal", this.scrollHorizontal.bind(this));
this.subscribe("scrollbar-vertical", this.padVerticalScrollbar.bind(this));
}
padVerticalScrollbar(width) {
if (this.table.rtl) this.headersElement.style.marginLeft = width + "px";
else this.headersElement.style.marginRight = width + "px";
}
initializeRenderer() {
var renderClass;
var renderers = {
"virtual": VirtualDomHorizontal,
"basic": BasicHorizontal
};
if (typeof this.table.options.renderHorizontal === "string") renderClass = renderers[this.table.options.renderHorizontal];
else renderClass = this.table.options.renderHorizontal;
if (renderClass) {
this.renderer = new renderClass(this.table, this.element, this.tableElement);
this.renderer.initialize();
} else console.error("Unable to find matching renderer:", this.table.options.renderHorizontal);
}
createHeadersElement() {
var el = document.createElement("div");
el.classList.add("tabulator-headers");
el.setAttribute("role", "row");
return el;
}
createHeaderContentsElement() {
var el = document.createElement("div");
el.classList.add("tabulator-header-contents");
el.setAttribute("role", "rowgroup");
return el;
}
createHeaderElement() {
var el = document.createElement("div");
el.classList.add("tabulator-header");
el.setAttribute("role", "rowgroup");
if (!this.table.options.headerVisible) el.classList.add("tabulator-header-hidden");
return el;
}
getElement() {
return this.element;
}
getContentsElement() {
return this.contentsElement;
}
getHeadersElement() {
return this.headersElement;
}
scrollHorizontal(left) {
this.contentsElement.scrollLeft = left;
this.scrollLeft = left;
this.renderer.scrollColumns(left);
}
initializeScrollWheelWatcher() {
this.contentsElement.addEventListener("wheel", (e) => {
var left;
if (e.deltaX) {
left = this.contentsElement.scrollLeft + e.deltaX;
this.table.rowManager.scrollHorizontal(left);
this.table.columnManager.scrollHorizontal(left);
}
});
}
generateColumnsFromRowData(data) {
var cols = [], collProgress = {}, rowSample = this.table.options.autoColumns === "full" ? data : [data[0]], definitions = this.table.options.autoColumnsDefinitions;
if (data && data.length) {
rowSample.forEach((row) => {
Object.keys(row).forEach((key, index) => {
let value = row[key], col;
if (!collProgress[key]) {
col = {
field: key,
title: key,
sorter: this.calculateSorterFromValue(value)
};
cols.splice(index, 0, col);
collProgress[key] = typeof value === "undefined" ? col : true;
} else if (collProgress[key] !== true) {
if (typeof value !== "undefined") {
collProgress[key].sorter = this.calculateSorterFromValue(value);
collProgress[key] = true;
}
}
});
});
if (definitions) switch (typeof definitions) {
case "function":
this.table.options.columns = definitions.call(this.table, cols);
break;
case "object":
if (Array.isArray(definitions)) cols.forEach((col) => {
var match = definitions.find((def) => {
return def.field === col.field;
});
if (match) Object.assign(col, match);
});
else cols.forEach((col) => {
if (definitions[col.field]) Object.assign(col, definitions[col.field]);
});
this.table.options.columns = cols;
break;
}
else this.table.options.columns = cols;
this.setColumns(this.table.options.columns);
}
}
calculateSorterFromValue(value) {
var sorter;
switch (typeof value) {
case "undefined":
sorter = "string";
break;
case "boolean":
sorter = "boolean";
break;
case "number":
sorter = "number";
break;
case "object":
if (Array.isArray(value)) sorter = "array";
else sorter = "string";
break;
default:
if (!isNaN(value) && value !== "") sorter = "number";
else if (value.match(/((^[0-9]+[a-z]+)|(^[a-z]+[0-9]+))+$/i)) sorter = "alphanum";
else sorter = "string";
break;
}
return sorter;
}
setColumns(cols, row) {
while (this.headersElement.firstChild) this.headersElement.removeChild(this.headersElement.firstChild);
this.columns = [];
this.columnsByIndex = [];
this.columnsByField = {};
this.dispatch("columns-loading");
this.dispatchExternal("columnsLoading");
if (this.table.options.rowHeader) {
this.rowHeader = new Column(this.table.options.rowHeader === true ? {} : this.table.options.rowHeader, this, true);
this.columns.push(this.rowHeader);
this.headersElement.appendChild(this.rowHeader.getElement());
this.rowHeader.columnRendered();
}
cols.forEach((def, i) => {
this._addColumn(def);
});
this._reIndexColumns();
this.dispatch("columns-loaded");
if (this.subscribedExternal("columnsLoaded")) this.dispatchExternal("columnsLoaded", this.getComponents());
this.rerenderColumns(false, true);
this.redraw(true);
}
_addColumn(definition, before, nextToColumn) {
var column = new Column(definition, this), colEl = column.getElement(), index = nextToColumn ? this.findColumnIndex(nextToColumn) : nextToColumn;
if (before && this.rowHeader && (!nextToColumn || nextToColumn === this.rowHeader)) {
before = false;
nextToColumn = this.rowHeader;
index = 0;
}
if (nextToColumn && index > -1) {
var topColumn = nextToColumn.getTopColumn();
var parentIndex = this.columns.indexOf(topColumn);
var nextEl = topColumn.getElement();
if (before) {
this.columns.splice(parentIndex, 0, column);
nextEl.parentNode.insertBefore(colEl, nextEl);
} else {
this.columns.splice(parentIndex + 1, 0, column);
nextEl.parentNode.insertBefore(colEl, nextEl.nextSibling);
}
} else if (before) {
this.columns.unshift(column);
this.headersElement.insertBefore(column.getElement(), this.headersElement.firstChild);
} else {
this.columns.push(column);
this.headersElement.appendChild(column.getElement());
}
column.columnRendered();
return column;
}
registerColumnField(col) {
if (col.definition.field) this.columnsByField[col.definition.field] = col;
}
registerColumnPosition(col) {
this.columnsByIndex.push(col);
}
_reIndexColumns() {
this.columnsByIndex = [];
this.columns.forEach(function(column) {
column.reRegisterPosition();
});
}
verticalAlignHeaders() {
var minHeight = 0;
if (!this.redrawBlock) {
this.headersElement.style.height = "";
this.columns.forEach((column) => {
column.clearVerticalAlign();
});
this.columns.forEach((column) => {
var height = column.getHeight();
if (height > minHeight) minHeight = height;
});
this.headersElement.style.height = minHeight + "px";
this.columns.forEach((column) => {
column.verticalAlign(this.table.options.columnHeaderVertAlign, minHeight);
});
this.table.rowManager.adjustTableSize();
}
}
findColumn(subject) {
var columns;
if (typeof subject == "object") {
if (subject instanceof Column) return subject;
else if (subject instanceof ColumnComponent) return subject._getSelf() || false;
else if (typeof HTMLElement !== "undefined" && subject instanceof HTMLElement) {
columns = [];
this.columns.forEach((column) => {
columns.push(column);
columns = columns.concat(column.getColumns(true));
});
return columns.find((column) => {
return column.element === subject;
}) || false;
}
} else return this.columnsByField[subject] || false;
return false;
}
getColumnByField(field) {
return this.columnsByField[field];
}
getColumnsByFieldRoot(root) {
var matches = [];
Object.keys(this.columnsByField).forEach((field) => {
if ((this.table.options.nestedFieldSeparator ? field.split(this.table.options.nestedFieldSeparator)[0] : field) === root) matches.push(this.columnsByField[field]);
});
return matches;
}
getColumnByIndex(index) {
return this.columnsByIndex[index];
}
getFirstVisibleColumn() {
var index = this.columnsByIndex.findIndex((col) => {
return col.visible;
});
return index > -1 ? this.columnsByIndex[index] : false;
}
getVisibleColumnsByIndex() {
return this.columnsByIndex.filter((col) => col.visible);
}
getColumns() {
return this.columns;
}
findColumnIndex(column) {
return this.columnsByIndex.findIndex((col) => {
return column === col;
});
}
getRealColumns() {
return this.columnsByIndex;
}
traverse(callback) {
this.columnsByIndex.forEach((column, i) => {
callback(column, i);
});
}
getDefinitions(active) {
var output = [];
this.columnsByIndex.forEach((column) => {
if (!active || active && column.visible) output.push(column.getDefinition());
});
return output;
}
getDefinitionTree() {
var output = [];
this.columns.forEach((column) => {
output.push(column.getDefinition(true));
});
return output;
}
getComponents(structured) {
var output = [];
(structured ? this.columns : this.columnsByIndex).forEach((column) => {
output.push(column.getComponent());
});
return output;
}
getWidth() {
var width = 0;
this.columnsByIndex.forEach((column) => {
if (column.visible) width += column.getWidth();
});
return width;
}
moveColumn(from, to, after) {
to.element.parentNode.insertBefore(from.element, to.element);
if (after) to.element.parentNode.insertBefore(to.element, from.element);
this.moveColumnActual(from, to, after);
this.verticalAlignHeaders();
this.table.rowManager.reinitialize();
}
moveColumnActual(from, to, after) {
if (from.parent.isGroup) this._moveColumnInArray(from.parent.columns, from, to, after);
else this._moveColumnInArray(this.columns, from, to, after);
this._moveColumnInArray(this.columnsByIndex, from, to, after, true);
this.rerenderColumns(true);
this.dispatch("column-moved", from, to, after);
if (this.subscribedExternal("columnMoved")) this.dispatchExternal("columnMoved", from.getComponent(), this.table.columnManager.getComponents());
}
_moveColumnInArray(columns, from, to, after, updateRows) {
var fromIndex = columns.indexOf(from), toIndex, rows = [];
if (fromIndex > -1) {
columns.splice(fromIndex, 1);
toIndex = columns.indexOf(to);
if (toIndex > -1) {
if (after) toIndex = toIndex + 1;
} else toIndex = fromIndex;
columns.splice(toIndex, 0, from);
if (updateRows) {
rows = this.chain("column-moving-rows", [
from,
to,
after
], null, []) || [];
rows = rows.concat(this.table.rowManager.rows);
rows.forEach(function(row) {
if (row.cells.length) {
var cell = row.cells.splice(fromIndex, 1)[0];
row.cells.splice(toIndex, 0, cell);
}
});
}
}
}
scrollToColumn(column, position, ifVisible) {
var left = 0, offset = column.getLeftOffset(), adjust = 0, colEl = column.getElement();
return new Promise((resolve, reject) => {
if (typeof position === "undefined") position = this.table.options.scrollToColumnPosition;
if (typeof ifVisible === "undefined") ifVisible = this.table.options.scrollToColumnIfVisible;
if (column.visible) {
switch (position) {
case "middle":
case "center":
adjust = -this.element.clientWidth / 2;
break;
case "right":
adjust = colEl.clientWidth - this.headersElement.clientWidth;
break;
}
if (!ifVisible) {
if (offset > 0 && offset + colEl.offsetWidth < this.element.clientWidth) return false;
}
left = offset + adjust;
left = Math.max(Math.min(left, this.table.rowManager.element.scrollWidth - this.table.rowManager.element.clientWidth), 0);
this.table.rowManager.scrollHorizontal(left);
this.scrollHorizontal(left);
resolve();
} else {
console.warn("Scroll Error - Column not visible");
reject("Scroll Error - Column not visible");
}
});
}
generateCells(row) {
var cells = [];
this.columnsByIndex.forEach((column) => {
cells.push(column.generateCell(row));
});
return cells;
}
getFlexBaseWidth() {
var totalWidth = this.table.element.clientWidth, fixedWidth = 0;
if (this.table.rowManager.element.scrollHeight > this.table.rowManager.element.clientHeight) totalWidth -= this.table.rowManager.element.offsetWidth - this.table.rowManager.element.clientWidth;
this.columnsByIndex.forEach(function(column) {
var width, minWidth, colWidth;
if (column.visible) {
width = column.definition.width || 0;
minWidth = parseInt(column.minWidth);
if (typeof width == "string") if (width.indexOf("%") > -1) colWidth = totalWidth / 100 * parseInt(width);
else colWidth = parseInt(width);
else colWidth = width;
fixedWidth += colWidth > minWidth ? colWidth : minWidth;
}
});
return fixedWidth;
}
addColumn(definition, before, nextToColumn) {
return new Promise((resolve, reject) => {
var column = this._addColumn(definition, before, nextToColumn);
this._reIndexColumns();
this.dispatch("column-add", definition, before, nextToColumn);
if (this.layoutMode() != "fitColumns") column.reinitializeWidth();
this.redraw(true);
this.table.rowManager.reinitialize();
this.rerenderColumns();
resolve(column);
});
}
deregisterColumn(column) {
var field = column.getField(), index;
if (field) delete this.columnsByField[field];
index = this.columnsByIndex.indexOf(column);
if (index > -1) this.columnsByIndex.splice(index, 1);
index = this.columns.indexOf(column);
if (index > -1) this.columns.splice(index, 1);
this.verticalAlignHeaders();
this.redraw();
}
rerenderColumns(update, silent) {
if (!this.redrawBlock) this.renderer.rerenderColumns(update, silent);
else if (update === false || update === true && this.redrawBlockUpdate === null) this.redrawBlockUpdate = update;
}
blockRedraw() {
this.redrawBlock = true;
this.redrawBlockUpdate = null;
}
restoreRedraw() {
this.redrawBlock = false;
this.verticalAlignHeaders();
this.renderer.rerenderColumns(this.redrawBlockUpdate);
}
redraw(force) {
if (Helpers.elVisible(this.element)) this.verticalAlignHeaders();
if (force) {
this.table.rowManager.resetScroll();
this.table.rowManager.reinitialize();
}
if (!this.confirm("table-redrawing", force)) this.layoutRefresh(force);
this.dispatch("table-redraw", force);
this.table.footerManager.redraw();
}
};
var BasicVertical = class extends Renderer {
constructor(table) {
super(table);
this.verticalFillMode = "fill";
this.scrollTop = 0;
this.scrollLeft = 0;
this.scrollTop = 0;
this.scrollLeft = 0;
}
clearRows() {
var element = this.tableElement;
while (element.firstChild) element.removeChild(element.firstChild);
element.scrollTop = 0;
element.scrollLeft = 0;
element.style.minWidth = "";
element.style.minHeight = "";
element.style.display = "";
element.style.visibility = "";
}
renderRows() {
var element = this.tableElement, onlyGroupHeaders = true, tableFrag = document.createDocumentFragment(), rows = this.rows();
rows.forEach((row, index) => {
this.styleRow(row, index);
row.initialize(false, true);
if (row.type !== "group") onlyGroupHeaders = false;
tableFrag.appendChild(row.getElement());
});
element.appendChild(tableFrag);
rows.forEach((row) => {
row.rendered();
if (!row.heightInitialized) row.calcHeight(true);
});
rows.forEach((row) => {
if (!row.heightInitialized) row.setCellHeight();
});
if (onlyGroupHeaders) element.style.minWidth = this.table.columnManager.getWidth() + "px";
else element.style.minWidth = "";
}
rerenderRows(callback) {
this.clearRows();
if (callback) callback();
this.renderRows();
if (!this.rows().length) this.table.rowManager.tableEmpty();
}
scrollToRowNearestTop(row) {
var rowTop = Helpers.elOffset(row.getElement()).top;
return !(Math.abs(this.elementVertical.scrollTop - rowTop) > Math.abs(this.elementVertical.scrollTop + this.elementVertical.clientHeight - rowTop));
}
scrollToRow(row) {
var rowEl = row.getElement();
this.elementVertical.scrollTop = Helpers.elOffset(rowEl).top - Helpers.elOffset(this.elementVertical).top + this.elementVertical.scrollTop;
}
visibleRows(includingBuffer) {
return this.rows();
}
};
var VirtualDomVertical = class extends Renderer {
constructor(table) {
super(table);
this.verticalFillMode = "fill";
this.scrollTop = 0;
this.scrollLeft = 0;
this.vDomRowHeight = 20;
this.vDomTop = 0;
this.vDomBottom = 0;
this.vDomScrollPosTop = 0;
this.vDomScrollPosBottom = 0;
this.vDomTopPad = 0;
this.vDomBottomPad = 0;
this.vDomMaxRenderChain = 90;
this.vDomWindowBuffer = 0;
this.vDomWindowMinTotalRows = 20;
this.vDomWindowMinMarginRows = 5;
this.vDomTopNewRows = [];
this.vDomBottomNewRows = [];
}
clearRows() {
var element = this.tableElement;
while (element.firstChild) element.removeChild(element.firstChild);
element.style.paddingTop = "";
element.style.paddingBottom = "";
element.style.minHeight = "";
element.style.display = "";
element.style.visibility = "";
this.elementVertical.scrollTop = 0;
this.elementVertical.scrollLeft = 0;
this.scrollTop = 0;
this.scrollLeft = 0;
this.vDomTop = 0;
this.vDomBottom = 0;
this.vDomTopPad = 0;
this.vDomBottomPad = 0;
this.vDomScrollPosTop = 0;
this.vDomScrollPosBottom = 0;
}
renderRows() {
this._virtualRenderFill();
}
rerenderRows(callback) {
var scrollTop = this.elementVertical.scrollTop;
var topRow = false;
var topOffset = false;
var left = this.table.rowManager.scrollLeft;
var rows = this.rows();
for (var i = this.vDomTop; i <= this.vDomBottom; i++) if (rows[i]) {
var diff = scrollTop - rows[i].getElement().offsetTop;
if (topOffset === false || Math.abs(diff) < topOffset) {
topOffset = diff;
topRow = i;
} else break;
}
rows.forEach((row) => {
row.deinitializeHeight();
});
if (callback) callback();
if (this.rows().length) this._virtualRenderFill(topRow === false ? this.rows.length - 1 : topRow, true, topOffset || 0);
else {
this.clear();
this.table.rowManager.tableEmpty();
}
this.scrollColumns(left);
}
scrollColumns(left) {
this.table.rowManager.scrollHorizontal(left);
}
scrollRows(top, dir) {
var topDiff = top - this.vDomScrollPosTop;
var bottomDiff = top - this.vDomScrollPosBottom;
var margin = this.vDomWindowBuffer * 2;
var rows = this.rows();
this.scrollTop = top;
if (-topDiff > margin || bottomDiff > margin) {
var left = this.table.rowManager.scrollLeft;
this._virtualRenderFill(Math.floor(this.elementVertical.scrollTop / this.elementVertical.scrollHeight * rows.length));
this.scrollColumns(left);
} else if (dir) {
if (topDiff < 0) this._addTopRow(rows, -topDiff);
if (bottomDiff < 0) if (this.vDomScrollHeight - this.scrollTop > this.vDomWindowBuffer) this._removeBottomRow(rows, -bottomDiff);
else this.vDomScrollPosBottom = this.scrollTop;
} else {
if (bottomDiff >= 0) this._addBottomRow(rows, bottomDiff);
if (topDiff >= 0) if (this.scrollTop > this.vDomWindowBuffer) this._removeTopRow(rows, topDiff);
else this.vDomScrollPosTop = this.scrollTop;
}
}
resize() {
this.vDomWindowBuffer = this.table.options.renderVerticalBuffer || this.elementVertical.clientHeight;
}
scrollToRowNearestTop(row) {
var rowIndex = this.rows().indexOf(row);
return !(Math.abs(this.vDomTop - rowIndex) > Math.abs(this.vDomBottom - rowIndex));
}
scrollToRow(row) {
var index = this.rows().indexOf(row);
if (index > -1) this._virtualRenderFill(index, true);
}
visibleRows(includingBuffer) {
var topEdge = this.elementVertical.scrollTop, bottomEdge = this.elementVertical.clientHeight + topEdge, topFound = false, topRow = 0, bottomRow = 0, rows = this.rows();
if (includingBuffer) {
topRow = this.vDomTop;
bottomRow = this.vDomBottom;
} else for (var i = this.vDomTop; i <= this.vDomBottom; i++) if (rows[i]) if (!topFound) if (topEdge - rows[i].getElement().offsetTop >= 0) topRow = i;
else {
topFound = true;
if (bottomEdge - rows[i].getElement().offsetTop >= 0) bottomRow = i;
else break;
}
else if (bottomEdge - rows[i].getElement().offsetTop >= 0) bottomRow = i;
else break;
return rows.slice(topRow, bottomRow + 1);
}
_virtualRenderFill(position, forceMove, offset) {
var element = this.tableElement, holder = this.elementVertical, topPad = 0, rowsHeight = 0, rowHeight = 0, heightOccupied = 0, topPadHeight = 0, i = 0, rows = this.rows(), rowsCount = rows.length, index = 0, row, rowFragment, renderedRows = [], totalRowsRendered = 0, rowsToRender = 0, fixedHeight = this.table.rowManager.fixedHeight, containerHeight = this.elementVertical.clientHeight, avgRowHeight = this.table.options.rowHeight, resized = true;
position = position || 0;
offset = offset || 0;
if (!position) this.clear();
else {
while (element.firstChild) element.removeChild(element.firstChild);
heightOccupied = (rowsCount - position + 1) * this.vDomRowHeight;
if (heightOccupied < containerHeight) {
position -= Math.ceil((containerHeight - heightOccupied) / this.vDomRowHeight);
if (position < 0) position = 0;
}
topPad = Math.min(Math.max(Math.floor(this.vDomWindowBuffer / this.vDomRowHeight), this.vDomWindowMinMarginRows), position);
position -= topPad;
}
if (rowsCount && Helpers.elVisible(this.elementVertical)) {
this.vDomTop = position;
this.vDomBottom = position - 1;
if (fixedHeight || this.table.options.maxHeight) {
if (avgRowHeight) rowsToRender = containerHeight / avgRowHeight + this.vDomWindowBuffer / avgRowHeight;
rowsToRender = Math.max(this.vDomWindowMinTotalRows, Math.ceil(rowsToRender));
} else rowsToRender = rowsCount;
while ((rowsToRender == rowsCount || rowsHeight <= containerHeight + this.vDomWindowBuffer || totalRowsRendered < this.vDomWindowMinTotalRows) && this.vDomBottom < rowsCount - 1) {
renderedRows = [];
rowFragment = document.createDocumentFragment();
i = 0;
while (i < rowsToRender && this.vDomBottom < rowsCount - 1) {
index = this.vDomBottom + 1, row = rows[index];
this.styleRow(row, index);
row.initialize(false, true);
if (!row.heightInitialized && !this.table.options.rowHeight) row.clearCellHeight();
rowFragment.appendChild(row.getElement());
renderedRows.push(row);
this.vDomBottom++;
i++;
}
if (!renderedRows.length) break;
element.appendChild(rowFragment);
renderedRows.forEach((row) => {
row.rendered();
if (!row.heightInitialized) row.calcHeight(true);
});
renderedRows.forEach((row) => {
if (!row.heightInitialized) row.setCellHeight();
});
renderedRows.forEach((row) => {
rowHeight = row.getHeight();
if (totalRowsRendered < topPad) topPadHeight += rowHeight;
else rowsHeight += rowHeight;
if (rowHeight > this.vDomWindowBuffer) this.vDomWindowBuffer = rowHeight * 2;
totalRowsRendered++;
});
resized = this.table.rowManager.adjustTableSize();
containerHeight = this.elementVertical.clientHeight;
if (resized && (fixedHeight || this.table.options.maxHeight)) {
avgRowHeight = rowsHeight / totalRowsRendered;
rowsToRender = Math.max(this.vDomWindowMinTotalRows, Math.ceil(containerHeight / avgRowHeight + this.vDomWindowBuffer / avgRowHeight));
}
}
if (!position) {
this.vDomTopPad = 0;
this.vDomRowHeight = Math.floor((rowsHeight + topPadHeight) / totalRowsRendered);
this.vDomBottomPad = this.vDomRowHeight * (rowsCount - this.vDomBottom - 1);
this.vDomScrollHeight = topPadHeight + rowsHeight + this.vDomBottomPad - containerHeight;
} else {
this.vDomTopPad = !forceMove ? this.scrollTop - topPadHeight : this.vDomRowHeight * this.vDomTop + offset;
this.vDomBottomPad = this.vDomBottom == rowsCount - 1 ? 0 : Math.max(this.vDomScrollHeight - this.vDomTopPad - rowsHeight - topPadHeight, 0);
}
element.style.paddingTop = this.vDomTopPad + "px";
element.style.paddingBottom = this.vDomBottomPad + "px";
if (forceMove) this.scrollTop = this.vDomTopPad + topPadHeight + offset - (this.elementVertical.scrollWidth > this.elementVertical.clientWidth ? this.elementVertical.offsetHeight - containerHeight : 0);
this.scrollTop = Math.min(this.scrollTop, this.elementVertical.scrollHeight - containerHeight);
if (this.elementVertical.scrollWidth > this.elementVertical.clientWidth && forceMove) this.scrollTop += this.elementVertical.offsetHeight - containerHeight;
this.vDomScrollPosTop = this.scrollTop;
this.vDomScrollPosBottom = this.scrollTop;
holder.scrollTop = this.scrollTop;
this.dispatch("render-virtual-fill");
}
}
_addTopRow(rows, fillableSpace) {
var table = this.tableElement, addedRows = [], paddingAdjust = 0, index = this.vDomTop - 1, i = 0, working = true;
while (working) if (this.vDomTop) {
let row = rows[index], rowHeight, initialized;
if (row && i < this.vDomMaxRenderChain) {
rowHeight = row.getHeight() || this.vDomRowHeight;
initialized = row.initialized;
if (fillableSpace >= rowHeight) {
this.styleRow(row, index);
table.insertBefore(row.getElement(), table.firstChild);
if (!row.initialized || !row.heightInitialized) addedRows.push(row);
row.initialize();
if (!initialized) {
rowHeight = row.getElement().offsetHeight;
if (rowHeight > this.vDomWindowBuffer) this.vDomWindowBuffer = rowHeight * 2;
}
fillableSpace -= rowHeight;
paddingAdjust += rowHeight;
this.vDomTop--;
index--;
i++;
} else working = false;
} else working = false;
} else working = false;
for (let row of addedRows) row.clearCellHeight();
this._quickNormalizeRowHeight(addedRows);
if (paddingAdjust) {
this.vDomTopPad -= paddingAdjust;
if (this.vDomTopPad < 0) this.vDomTopPad = index * this.vDomRowHeight;
if (index < 1) this.vDomTopPad = 0;
table.style.paddingTop = this.vDomTopPad + "px";
this.vDomScrollPosTop -= paddingAdjust;
}
}
_removeTopRow(rows, fillableSpace) {
var removableRows = [], paddingAdjust = 0, i = 0, working = true;
while (working) {
let row = rows[this.vDomTop], rowHeight;
if (row && i < this.vDomMaxRenderChain) {
rowHeight = row.getHeight() || this.vDomRowHeight;
if (fillableSpace >= rowHeight) {
this.vDomTop++;
fillableSpace -= rowHeight;
paddingAdjust += rowHeight;
removableRows.push(row);
i++;
} else working = false;
} else working = false;
}
for (let row of removableRows) {
let rowEl = row.getElement();
if (rowEl.parentNode) rowEl.parentNode.removeChild(rowEl);
}
if (paddingAdjust) {
this.vDomTopPad += paddingAdjust;
this.tableElement.style.paddingTop = this.vDomTopPad + "px";
this.vDomScrollPosTop += this.vDomTop ? paddingAdjust : paddingAdjust + this.vDomWindowBuffer;
}
}
_addBottomRow(rows, fillableSpace) {
var table = this.tableElement, addedRows = [], paddingAdjust = 0, index = this.vDomBottom + 1, i = 0, working = true;
while (working) {
let row = rows[index], rowHeight, initialized;
if (row && i < this.vDomMaxRenderChain) {
rowHeight = row.getHeight() || this.vDomRowHeight;
initialized = row.initialized;
if (fillableSpace >= rowHeight) {
this.styleRow(row, index);
table.appendChild(row.getElement());
if (!row.initialized || !row.heightInitialized) addedRows.push(row);
row.initialize();
if (!initialized) {
rowHeight = row.getElement().offsetHeight;
if (rowHeight > this.vDomWindowBuffer) this.vDomWindowBuffer = rowHeight * 2;
}
fillableSpace -= rowHeight;
paddingAdjust += rowHeight;
this.vDomBottom++;
index++;
i++;
} else working = false;
} else working = false;
}
for (let row of addedRows) row.clearCellHeight();
this._quickNormalizeRowHeight(addedRows);
if (paddingAdjust) {
this.vDomBottomPad -= paddingAdjust;
if (this.vDomBottomPad < 0 || index == rows.length - 1) this.vDomBottomPad = 0;
table.style.paddingBottom = this.vDomBottomPad + "px";
this.vDomScrollPosBottom += paddingAdjust;
}
}
_removeBottomRow(rows, fillableSpace) {
var removableRows = [], paddingAdjust = 0, i = 0, working = true;
while (working) {
let row = rows[this.vDomBottom], rowHeight;
if (row && i < this.vDomMaxRenderChain) {
rowHeight = row.getHeight() || this.vDomRowHeight;
if (fillableSpace >= rowHeight) {
this.vDomBottom--;
fillableSpace -= rowHeight;
paddingAdjust += rowHeight;
removableRows.push(row);
i++;
} else working = false;
} else working = false;
}
for (let row of removableRows) {
let rowEl = row.getElement();
if (rowEl.parentNode) rowEl.parentNode.removeChild(rowEl);
}
if (paddingAdjust) {
this.vDomBottomPad += paddingAdjust;
if (this.vDomBottomPad < 0) this.vDomBottomPad = 0;
this.tableElement.style.paddingBottom = this.vDomBottomPad + "px";
this.vDomScrollPosBottom -= paddingAdjust;
}
}
_quickNormalizeRowHeight(rows) {
for (let row of rows) row.calcHeight();
for (let row of rows) row.setCellHeight();
}
};
var RowManager = class extends CoreFeature {
constructor(table) {
super(table);
this.element = this.createHolderElement();
this.tableElement = this.createTableElement();
this.heightFixer = this.createTableElement();
this.placeholder = null;
this.placeholderContents = null;
this.firstRender = false;
this.renderMode = "virtual";
this.fixedHeight = false;
this.rows = [];
this.activeRowsPipeline = [];
this.activeRows = [];
this.activeRowsCount = 0;
this.displayRows = [];
this.displayRowsCount = 0;
this.scrollTop = 0;
this.scrollLeft = 0;
this.redrawBlock = false;
this.redrawBlockRestoreConfig = false;
this.redrawBlockRenderInPosition = false;
this.dataPipeline = [];
this.displayPipeline = [];
this.scrollbarWidth = 0;
this.renderer = null;
}
createHolderElement() {
var el = document.createElement("div");
el.classList.add("tabulator-tableholder");
el.setAttribute("tabindex", 0);
return el;
}
createTableElement() {
var el = document.createElement("div");
el.classList.add("tabulator-table");
el.setAttribute("role", "rowgroup");
return el;
}
initializePlaceholder() {
var placeholder = this.table.options.placeholder;
if (typeof placeholder === "function") placeholder = placeholder.call(this.table);
placeholder = this.chain("placeholder", [placeholder], placeholder, placeholder) || placeholder;
if (placeholder) {
let el = document.createElement("div");
el.classList.add("tabulator-placeholder");
if (typeof placeholder == "string") {
let contents = document.createElement("div");
contents.classList.add("tabulator-placeholder-contents");
contents.innerHTML = placeholder;
el.appendChild(contents);
this.placeholderContents = contents;
} else if (typeof HTMLElement !== "undefined" && placeholder instanceof HTMLElement) {
el.appendChild(placeholder);
this.placeholderContents = placeholder;
} else {
console.warn("Invalid placeholder provided, must be string or HTML Element", placeholder);
this.el = null;
}
this.placeholder = el;
}
}
getElement() {
return this.element;
}
getTableElement() {
return this.tableElement;
}
initialize() {
this.initializePlaceholder();
this.initializeRenderer();
this.element.appendChild(this.tableElement);
this.firstRender = true;
this.element.addEventListener("scroll", () => {
var left = this.element.scrollLeft, leftDir = this.scrollLeft > left, top = this.element.scrollTop, topDir = this.scrollTop > top;
if (this.scrollLeft != left) {
this.scrollLeft = left;
this.dispatch("scroll-horizontal", left, leftDir);
this.dispatchExternal("scrollHorizontal", left, leftDir);
this._positionPlaceholder();
}
if (this.scrollTop != top) {
this.scrollTop = top;
this.renderer.scrollRows(top, topDir);
this.dispatch("scroll-vertical", top, topDir);
this.dispatchExternal("scrollVertical", top, topDir);
}
});
}
findRow(subject) {
if (typeof subject == "object") {
if (subject instanceof Row) return subject;
else if (subject instanceof RowComponent) return subject._getSelf() || false;
else if (typeof HTMLElement !== "undefined" && subject instanceof HTMLElement) return this.rows.find((row) => {
return row.getElement() === subject;
}) || false;
else if (subject === null) return false;
} else if (typeof subject == "undefined") return false;
else return this.rows.find((row) => {
return row.data[this.table.options.index] == subject;
}) || false;
return false;
}
getRowFromDataObject(data) {
return this.rows.find((row) => {
return row.data === data;
}) || false;
}
getRowFromPosition(position) {
return this.getDisplayRows().find((row) => {
return row.type === "row" && row.getPosition() === position && row.isDisplayed();
});
}
scrollToRow(row, position, ifVisible) {
return this.renderer.scrollToRowPosition(row, position, ifVisible);
}
setData(data, renderInPosition, columnsChanged) {
return new Promise((resolve, reject) => {
if (renderInPosition && this.getDisplayRows().length) if (this.table.options.pagination) this._setDataActual(data, true);
else this.reRenderInPosition(() => {
this._setDataActual(data);
});
else {
if (this.table.options.autoColumns && columnsChanged && this.table.initialized) this.table.columnManager.generateColumnsFromRowData(data);
this.resetScroll();
this._setDataActual(data);
}
resolve();
});
}
_setDataActual(data, renderInPosition) {
this.dispatchExternal("dataProcessing", data);
this._wipeElements();
if (Array.isArray(data)) {
this.dispatch("data-processing", data);
data.forEach((def, i) => {
if (def && typeof def === "object") {
var row = new Row(def, this);
this.rows.push(row);
} else console.warn("Data Loading Warning - Invalid row data detected and ignored, expecting object but received:", def);
});
this.refreshActiveData(false, false, renderInPosition);
this.dispatch("data-processed", data);
this.dispatchExternal("dataProcessed", data);
} else console.error("Data Loading Error - Unable to process data due to invalid data type \nExpecting: array \nReceived: ", typeof data, "\nData: ", data);
}
_wipeElements() {
this.dispatch("rows-wipe");
this.destroy();
this.adjustTableSize();
this.dispatch("rows-wiped");
}
destroy() {
this.rows.forEach((row) => {
row.wipe();
});
this.rows = [];
this.activeRows = [];
this.activeRowsPipeline = [];
this.activeRowsCount = 0;
this.displayRows = [];
this.displayRowsCount = 0;
}
deleteRow(row, blockRedraw) {
var allIndex = this.rows.indexOf(row), activeIndex = this.activeRows.indexOf(row);
if (activeIndex > -1) this.activeRows.splice(activeIndex, 1);
if (allIndex > -1) this.rows.splice(allIndex, 1);
this.setActiveRows(this.activeRows);
this.displayRowIterator((rows) => {
var displayIndex = rows.indexOf(row);
if (displayIndex > -1) rows.splice(displayIndex, 1);
});
if (!blockRedraw) this.reRenderInPosition();
this.regenerateRowPositions();
this.dispatchExternal("rowDeleted", row.getComponent());
if (!this.displayRowsCount) this.tableEmpty();
if (this.subscribedExternal("dataChanged")) this.dispatchExternal("dataChanged", this.getData());
}
addRow(data, pos, index, blockRedraw) {
return this.addRowActual(data, pos, index, blockRedraw);
}
addRows(data, pos, index, refreshDisplayOnly) {
var rows = [];
return new Promise((resolve, reject) => {
pos = this.findAddRowPos(pos);
if (!Array.isArray(data)) data = [data];
if (typeof index == "undefined" && pos || typeof index !== "undefined" && !pos) data.reverse();
data.forEach((item, i) => {
var row = this.addRow(item, pos, index, true);
rows.push(row);
this.dispatch("row-added", row, item, pos, index);
});
this.refreshActiveData(refreshDisplayOnly ? "displayPipeline" : false, false, true);
this.regenerateRowPositions();
if (this.displayRowsCount) this._clearPlaceholder();
resolve(rows);
});
}
findAddRowPos(pos) {
if (typeof pos === "undefined") pos = this.table.options.addRowPos;
if (pos === "pos") pos = true;
if (pos === "bottom") pos = false;
return pos;
}
addRowActual(data, pos, index, blockRedraw) {
var row = data instanceof Row ? data : new Row(data || {}, this), top = this.findAddRowPos(pos), allIndex = -1, activeIndex, chainResult;
if (!index) {
chainResult = this.chain("row-adding-position", [row, top], null, {
index,
top
});
index = chainResult.index;
top = chainResult.top;
}
if (typeof index !== "undefined") index = this.findRow(index);
index = this.chain("row-adding-index", [
row,
index,
top
], null, index);
if (index) allIndex = this.rows.indexOf(index);
if (index && allIndex > -1) {
activeIndex = this.activeRows.indexOf(index);
this.displayRowIterator(function(rows) {
var displayIndex = rows.indexOf(index);
if (displayIndex > -1) rows.splice(top ? displayIndex : displayIndex + 1, 0, row);
});
if (activeIndex > -1) this.activeRows.splice(top ? activeIndex : activeIndex + 1, 0, row);
this.rows.splice(top ? allIndex : allIndex + 1, 0, row);
} else if (top) {
this.displayRowIterator(function(rows) {
rows.unshift(row);
});
this.activeRows.unshift(row);
this.rows.unshift(row);
} else {
this.displayRowIterator(function(rows) {
rows.push(row);
});
this.activeRows.push(row);
this.rows.push(row);
}
this.setActiveRows(this.activeRows);
this.dispatchExternal("rowAdded", row.getComponent());
if (this.subscribedExternal("dataChanged")) this.dispatchExternal("dataChanged", this.table.rowManager.getData());
if (!blockRedraw) this.reRenderInPosition();
return row;
}
moveRow(from, to, after) {
this.dispatch("row-move", from, to, after);
this.moveRowActual(from, to, after);
this.regenerateRowPositions();
this.dispatch("row-moved", from, to, after);
this.dispatchExternal("rowMoved", from.getComponent());
}
moveRowActual(from, to, after) {
this.moveRowInArray(this.rows, from, to, after);
this.moveRowInArray(this.activeRows, from, to, after);
this.displayRowIterator((rows) => {
this.moveRowInArray(rows, from, to, after);
});
this.dispatch("row-moving", from, to, after);
}
moveRowInArray(rows, from, to, after) {
var fromIndex, toIndex, start, end;
if (from !== to) {
fromIndex = rows.indexOf(from);
if (fromIndex > -1) {
rows.splice(fromIndex, 1);
toIndex = rows.indexOf(to);
if (toIndex > -1) if (after) rows.splice(toIndex + 1, 0, from);
else rows.splice(toIndex, 0, from);
else rows.splice(fromIndex, 0, from);
}
if (rows === this.getDisplayRows()) {
start = fromIndex < toIndex ? fromIndex : toIndex;
end = toIndex > fromIndex ? toIndex : fromIndex + 1;
for (let i = start; i <= end; i++) if (rows[i]) this.styleRow(rows[i], i);
}
}
}
clearData() {
this.setData([]);
}
getRowIndex(row) {
return this.findRowIndex(row, this.rows);
}
getDisplayRowIndex(row) {
var index = this.getDisplayRows().indexOf(row);
return index > -1 ? index : false;
}
nextDisplayRow(row, rowOnly) {
var index = this.getDisplayRowIndex(row), nextRow = false;
if (index !== false && index < this.displayRowsCount - 1) nextRow = this.getDisplayRows()[index + 1];
if (nextRow && (!(nextRow instanceof Row) || nextRow.type != "row")) return this.nextDisplayRow(nextRow, rowOnly);
return nextRow;
}
prevDisplayRow(row, rowOnly) {
var index = this.getDisplayRowIndex(row), prevRow = false;
if (index) prevRow = this.getDisplayRows()[index - 1];
if (rowOnly && prevRow && (!(prevRow instanceof Row) || prevRow.type != "row")) return this.prevDisplayRow(prevRow, rowOnly);
return prevRow;
}
findRowIndex(row, list) {
var rowIndex;
row = this.findRow(row);
if (row) {
rowIndex = list.indexOf(row);
if (rowIndex > -1) return rowIndex;
}
return false;
}
getData(active, transform) {
var output = [];
this.getRows(active).forEach(function(row) {
if (row.type == "row") output.push(row.getData(transform || "data"));
});
return output;
}
getComponents(active) {
var output = [];
this.getRows(active).forEach(function(row) {
output.push(row.getComponent());
});
return output;
}
getDataCount(active) {
return this.getRows(active).length;
}
scrollHorizontal(left) {
this.scrollLeft = left;
this.element.scrollLeft = left;
this.dispatch("scroll-horizontal", left);
}
registerDataPipelineHandler(handler, priority) {
if (typeof priority !== "undefined") {
this.dataPipeline.push({
handler,
priority
});
this.dataPipeline.sort((a, b) => {
return a.priority - b.priority;
});
} else console.error("Data pipeline handlers must have a priority in order to be registered");
}
registerDisplayPipelineHandler(handler, priority) {
if (typeof priority !== "undefined") {
this.displayPipeline.push({
handler,
priority
});
this.displayPipeline.sort((a, b) => {
return a.priority - b.priority;
});
} else console.error("Display pipeline handlers must have a priority in order to be registered");
}
refreshActiveData(handler, skipStage, renderInPosition) {
var table = this.table, stage = "", index = 0, cascadeOrder = [
"all",
"dataPipeline",
"display",
"displayPipeline",
"end"
];
if (!this.table.destroyed) {
if (typeof handler === "function") {
index = this.dataPipeline.findIndex((item) => {
return item.handler === handler;
});
if (index > -1) {
stage = "dataPipeline";
if (skipStage) if (index == this.dataPipeline.length - 1) stage = "display";
else index++;
} else {
index = this.displayPipeline.findIndex((item) => {
return item.handler === handler;
});
if (index > -1) {
stage = "displayPipeline";
if (skipStage) if (index == this.displayPipeline.length - 1) stage = "end";
else index++;
} else {
console.error("Unable to refresh data, invalid handler provided", handler);
return;
}
}
} else {
stage = handler || "all";
index = 0;
}
if (this.redrawBlock) {
if (!this.redrawBlockRestoreConfig || this.redrawBlockRestoreConfig && (this.redrawBlockRestoreConfig.stage === stage && index < this.redrawBlockRestoreConfig.index || cascadeOrder.indexOf(stage) < cascadeOrder.indexOf(this.redrawBlockRestoreConfig.stage))) this.redrawBlockRestoreConfig = {
handler,
skipStage,
renderInPosition,
stage,
index
};
return;
} else {
if (Helpers.elVisible(this.element)) if (renderInPosition) this.reRenderInPosition(this.refreshPipelines.bind(this, handler, stage, index, renderInPosition));
else {
this.refreshPipelines(handler, stage, index, renderInPosition);
if (!handler) this.table.columnManager.renderer.renderColumns();
this.renderTable();
if (table.options.layoutColumnsOnNewData) this.table.columnManager.redraw(true);
}
else this.refreshPipelines(handler, stage, index, renderInPosition);
this.dispatch("data-refreshed");
}
}
}
refreshPipelines(handler, stage, index, renderInPosition) {
this.dispatch("data-refreshing");
if (!handler || !this.activeRowsPipeline[0]) this.activeRowsPipeline[0] = this.rows.slice(0);
switch (stage) {
case "all":
case "dataPipeline":
for (let i = index; i < this.dataPipeline.length; i++) {
let result = this.dataPipeline[i].handler(this.activeRowsPipeline[i].slice(0));
this.activeRowsPipeline[i + 1] = result || this.activeRowsPipeline[i].slice(0);
}
this.setActiveRows(this.activeRowsPipeline[this.dataPipeline.length]);
case "display":
index = 0;
this.resetDisplayRows();
case "displayPipeline": for (let i = index; i < this.displayPipeline.length; i++) {
let result = this.displayPipeline[i].handler((i ? this.getDisplayRows(i - 1) : this.activeRows).slice(0), renderInPosition);
this.setDisplayRows(result || this.getDisplayRows(i - 1).slice(0), i);
}
case "end": this.regenerateRowPositions();
}
if (this.getDisplayRows().length) this._clearPlaceholder();
}
regenerateRowPositions() {
var rows = this.getDisplayRows();
var index = 1;
rows.forEach((row) => {
if (row.type === "row") {
row.setPosition(index);
index++;
}
});
}
setActiveRows(activeRows) {
this.activeRows = this.activeRows = Object.assign([], activeRows);
this.activeRowsCount = this.activeRows.length;
}
resetDisplayRows() {
this.displayRows = [];
this.displayRows.push(this.activeRows.slice(0));
this.displayRowsCount = this.displayRows[0].length;
}
setDisplayRows(displayRows, index) {
this.displayRows[index] = displayRows;
if (index == this.displayRows.length - 1) this.displayRowsCount = this.displayRows[this.displayRows.length - 1].length;
}
getDisplayRows(index) {
if (typeof index == "undefined") return this.displayRows.length ? this.displayRows[this.displayRows.length - 1] : [];
else return this.displayRows[index] || [];
}
getVisibleRows(chain, viewable) {
var rows = Object.assign([], this.renderer.visibleRows(!viewable));
if (chain) rows = this.chain("rows-visible", [viewable], rows, rows);
return rows;
}
displayRowIterator(callback) {
this.activeRowsPipeline.forEach(callback);
this.displayRows.forEach(callback);
this.displayRowsCount = this.displayRows[this.displayRows.length - 1].length;
}
getRows(type) {
var rows = [];
switch (type) {
case "active":
rows = this.activeRows;
break;
case "display":
rows = this.table.rowManager.getDisplayRows();
break;
case "visible":
rows = this.getVisibleRows(false, true);
break;
default: rows = this.chain("rows-retrieve", type, null, this.rows) || this.rows;
}
return rows;
}
reRenderInPosition(callback) {
if (this.redrawBlock) if (callback) callback();
else this.redrawBlockRenderInPosition = true;
else {
this.dispatchExternal("renderStarted");
this.renderer.rerenderRows(callback);
if (!this.fixedHeight) this.adjustTableSize();
this.scrollBarCheck();
this.dispatchExternal("renderComplete");
}
}
scrollBarCheck() {
var scrollbarWidth = 0;
if (this.element.scrollHeight > this.element.clientHeight) scrollbarWidth = this.element.offsetWidth - this.element.clientWidth;
if (scrollbarWidth !== this.scrollbarWidth) {
this.scrollbarWidth = scrollbarWidth;
this.dispatch("scrollbar-vertical", scrollbarWidth);
}
}
initializeRenderer() {
var renderClass;
var renderers = {
"virtual": VirtualDomVertical,
"basic": BasicVertical
};
if (typeof this.table.options.renderVertical === "string") renderClass = renderers[this.table.options.renderVertical];
else renderClass = this.table.options.renderVertical;
if (renderClass) {
this.renderMode = this.table.options.renderVertical;
this.renderer = new renderClass(this.table, this.element, this.tableElement);
this.renderer.initialize();
if ((this.table.element.clientHeight || this.table.options.height) && !(this.table.options.minHeight && this.table.options.maxHeight)) this.fixedHeight = true;
else this.fixedHeight = false;
} else console.error("Unable to find matching renderer:", this.table.options.renderVertical);
}
getRenderMode() {
return this.renderMode;
}
renderTable() {
this.dispatchExternal("renderStarted");
this.element.scrollTop = 0;
this._clearTable();
if (this.displayRowsCount) {
this.renderer.renderRows();
if (this.firstRender) {
this.firstRender = false;
if (!this.fixedHeight) this.adjustTableSize();
this.layoutRefresh(true);
}
} else this.renderEmptyScroll();
if (!this.fixedHeight) this.adjustTableSize();
this.dispatch("table-layout");
if (!this.displayRowsCount) this._showPlaceholder();
this.scrollBarCheck();
this.dispatchExternal("renderComplete");
}
renderEmptyScroll() {
if (this.placeholder) this.tableElement.style.display = "none";
else this.tableElement.style.minWidth = this.table.columnManager.getWidth() + "px";
}
_clearTable() {
this._clearPlaceholder();
this.scrollTop = 0;
this.scrollLeft = 0;
this.renderer.clearRows();
}
tableEmpty() {
this.renderEmptyScroll();
this._showPlaceholder();
}
checkPlaceholder() {
if (this.displayRowsCount) this._clearPlaceholder();
else this.tableEmpty();
}
_showPlaceholder() {
if (this.placeholder) {
if (this.placeholder && this.placeholder.parentNode) this.placeholder.parentNode.removeChild(this.placeholder);
this.initializePlaceholder();
this.placeholder.setAttribute("tabulator-render-mode", this.renderMode);
this.getElement().appendChild(this.placeholder);
this._positionPlaceholder();
this.adjustTableSize();
}
}
_clearPlaceholder() {
if (this.placeholder && this.placeholder.parentNode) this.placeholder.parentNode.removeChild(this.placeholder);
this.tableElement.style.minWidth = "";
this.tableElement.style.display = "";
}
_positionPlaceholder() {
if (this.placeholder && this.placeholder.parentNode) {
this.placeholder.style.width = this.table.columnManager.getWidth() + "px";
this.placeholderContents.style.width = this.table.rowManager.element.clientWidth + "px";
this.placeholderContents.style.marginLeft = this.scrollLeft + "px";
}
}
styleRow(row, index) {
var rowEl = row.getElement();
if (index % 2) {
rowEl.classList.add("tabulator-row-even");
rowEl.classList.remove("tabulator-row-odd");
} else {
rowEl.classList.add("tabulator-row-odd");
rowEl.classList.remove("tabulator-row-even");
}
}
normalizeHeight(force) {
this.activeRows.forEach(function(row) {
row.normalizeHeight(force);
});
}
adjustTableSize() {
let initialHeight = this.element.clientHeight, minHeight;
let resized = false;
if (this.renderer.verticalFillMode === "fill") {
let otherHeight = Math.floor(this.table.columnManager.getElement().getBoundingClientRect().height + (this.table.footerManager && this.table.footerManager.active && !this.table.footerManager.external ? this.table.footerManager.getElement().getBoundingClientRect().height : 0));
if (this.fixedHeight) {
minHeight = isNaN(this.table.options.minHeight) ? this.table.options.minHeight : this.table.options.minHeight + "px";
const height = "calc(100% - " + otherHeight + "px)";
this.element.style.minHeight = minHeight || "calc(100% - " + otherHeight + "px)";
this.element.style.height = height;
this.element.style.maxHeight = height;
} else {
this.element.style.height = "";
this.element.style.height = this.table.element.clientHeight - otherHeight + "px";
this.element.scrollTop = this.scrollTop;
}
this.renderer.resize();
if (!this.fixedHeight && initialHeight != this.element.clientHeight) {
resized = true;
if (this.subscribed("table-resize")) this.dispatch("table-resize");
else this.redraw();
}
this.scrollBarCheck();
}
this._positionPlaceholder();
return resized;
}
reinitialize() {
this.rows.forEach(function(row) {
row.reinitialize(true);
});
}
blockRedraw() {
this.redrawBlock = true;
this.redrawBlockRestoreConfig = false;
}
restoreRedraw() {
this.redrawBlock = false;
if (this.redrawBlockRestoreConfig) {
this.refreshActiveData(this.redrawBlockRestoreConfig.handler, this.redrawBlockRestoreConfig.skipStage, this.redrawBlockRestoreConfig.renderInPosition);
this.redrawBlockRestoreConfig = false;
} else if (this.redrawBlockRenderInPosition) this.reRenderInPosition();
this.redrawBlockRenderInPosition = false;
}
redraw(force) {
this.adjustTableSize();
this.table.tableWidth = this.table.element.clientWidth;
if (!force) {
this.reRenderInPosition();
this.scrollHorizontal(this.scrollLeft);
} else this.renderTable();
}
resetScroll() {
this.element.scrollLeft = 0;
this.element.scrollTop = 0;
if (this.table.browser === "ie") {
var event = document.createEvent("Event");
event.initEvent("scroll", false, true);
this.element.dispatchEvent(event);
} else this.element.dispatchEvent(new Event("scroll"));
}
};
var FooterManager = class extends CoreFeature {
constructor(table) {
super(table);
this.active = false;
this.element = this.createElement();
this.containerElement = this.createContainerElement();
this.external = false;
}
initialize() {
this.initializeElement();
}
createElement() {
var el = document.createElement("div");
el.classList.add("tabulator-footer");
return el;
}
createContainerElement() {
var el = document.createElement("div");
el.classList.add("tabulator-footer-contents");
this.element.appendChild(el);
return el;
}
initializeElement() {
if (this.table.options.footerElement) switch (typeof this.table.options.footerElement) {
case "string":
if (this.table.options.footerElement[0] === "<") this.containerElement.innerHTML = this.table.options.footerElement;
else {
this.external = true;
this.containerElement = document.querySelector(this.table.options.footerElement);
}
break;
default:
this.element = this.table.options.footerElement;
break;
}
}
getElement() {
return this.element;
}
append(element) {
this.activate();
this.containerElement.appendChild(element);
this.table.rowManager.adjustTableSize();
}
prepend(element) {
this.activate();
this.element.insertBefore(element, this.element.firstChild);
this.table.rowManager.adjustTableSize();
}
remove(element) {
element.parentNode.removeChild(element);
this.deactivate();
}
deactivate(force) {
if (!this.element.firstChild || force) {
if (!this.external) this.element.parentNode.removeChild(this.element);
this.active = false;
}
}
activate() {
if (!this.active) {
this.active = true;
if (!this.external) {
this.table.element.appendChild(this.getElement());
this.table.element.style.display = "";
}
}
}
redraw() {
this.dispatch("footer-redraw");
}
};
var InteractionManager = class extends CoreFeature {
constructor(table) {
super(table);
this.el = null;
this.abortClasses = ["tabulator-headers", "tabulator-table"];
this.previousTargets = {};
this.listeners = [
"click",
"dblclick",
"contextmenu",
"mouseenter",
"mouseleave",
"mouseover",
"mouseout",
"mousemove",
"mouseup",
"mousedown",
"touchstart",
"touchend"
];
this.componentMap = {
"tabulator-cell": "cell",
"tabulator-row": "row",
"tabulator-group": "group",
"tabulator-col": "column"
};
this.pseudoTrackers = {
"row": {
subscriber: null,
target: null
},
"cell": {
subscriber: null,
target: null
},
"group": {
subscriber: null,
target: null
},
"column": {
subscriber: null,
target: null
}
};
this.pseudoTracking = false;
}
initialize() {
this.el = this.table.element;
this.buildListenerMap();
this.bindSubscriptionWatchers();
}
buildListenerMap() {
var listenerMap = {};
this.listeners.forEach((listener) => {
listenerMap[listener] = {
handler: null,
components: []
};
});
this.listeners = listenerMap;
}
bindPseudoEvents() {
Object.keys(this.pseudoTrackers).forEach((key) => {
this.pseudoTrackers[key].subscriber = this.pseudoMouseEnter.bind(this, key);
this.subscribe(key + "-mouseover", this.pseudoTrackers[key].subscriber);
});
this.pseudoTracking = true;
}
pseudoMouseEnter(key, e, target) {
if (this.pseudoTrackers[key].target !== target) {
if (this.pseudoTrackers[key].target) this.dispatch(key + "-mouseleave", e, this.pseudoTrackers[key].target);
this.pseudoMouseLeave(key, e);
this.pseudoTrackers[key].target = target;
this.dispatch(key + "-mouseenter", e, target);
}
}
pseudoMouseLeave(key, e) {
var leaveList = Object.keys(this.pseudoTrackers), linkedKeys = {
"row": ["cell"],
"cell": ["row"]
};
leaveList = leaveList.filter((item) => {
var links = linkedKeys[key];
return item !== key && (!links || links && !links.includes(item));
});
leaveList.forEach((key) => {
var target = this.pseudoTrackers[key].target;
if (this.pseudoTrackers[key].target) {
this.dispatch(key + "-mouseleave", e, target);
this.pseudoTrackers[key].target = null;
}
});
}
bindSubscriptionWatchers() {
var listeners = Object.keys(this.listeners), components = Object.values(this.componentMap);
for (let comp of components) for (let listener of listeners) {
let key = comp + "-" + listener;
this.subscriptionChange(key, this.subscriptionChanged.bind(this, comp, listener));
}
this.subscribe("table-destroy", this.clearWatchers.bind(this));
}
subscriptionChanged(component, key, added) {
var listener = this.listeners[key].components, index = listener.indexOf(component), changed = false;
if (added) {
if (index === -1) {
listener.push(component);
changed = true;
}
} else if (!this.subscribed(component + "-" + key)) {
if (index > -1) {
listener.splice(index, 1);
changed = true;
}
}
if ((key === "mouseenter" || key === "mouseleave") && !this.pseudoTracking) this.bindPseudoEvents();
if (changed) this.updateEventListeners();
}
updateEventListeners() {
for (let key in this.listeners) {
let listener = this.listeners[key];
if (listener.components.length) {
if (!listener.handler) {
listener.handler = this.track.bind(this, key);
this.el.addEventListener(key, listener.handler);
}
} else if (listener.handler) {
this.el.removeEventListener(key, listener.handler);
listener.handler = null;
}
}
}
track(type, e) {
var path = e.composedPath && e.composedPath() || e.path;
var targets = this.findTargets(path);
targets = this.bindComponents(type, targets);
this.triggerEvents(type, e, targets);
if (this.pseudoTracking && (type == "mouseover" || type == "mouseleave") && !Object.keys(targets).length) this.pseudoMouseLeave("none", e);
}
findTargets(path) {
var targets = {};
let componentMap = Object.keys(this.componentMap);
for (let el of path) {
let classList = el.classList ? [...el.classList] : [];
if (classList.filter((item) => {
return this.abortClasses.includes(item);
}).length) break;
let elTargets = classList.filter((item) => {
return componentMap.includes(item);
});
for (let target of elTargets) if (!targets[this.componentMap[target]]) targets[this.componentMap[target]] = el;
}
if (targets.group && targets.group === targets.row) delete targets.row;
return targets;
}
bindComponents(type, targets) {
var keys = Object.keys(targets).reverse(), listener = this.listeners[type], matches = {}, output = {}, targetMatches = {};
for (let key of keys) {
let component, target = targets[key], previousTarget = this.previousTargets[key];
if (previousTarget && previousTarget.target === target) component = previousTarget.component;
else switch (key) {
case "row":
case "group":
if (listener.components.includes("row") || listener.components.includes("cell") || listener.components.includes("group")) {
component = this.table.rowManager.getVisibleRows(true).find((row) => {
return row.getElement() === target;
});
if (targets["row"] && targets["row"].parentNode && targets["row"].parentNode.closest(".tabulator-row")) targets[key] = false;
}
break;
case "column":
if (listener.components.includes("column")) component = this.table.columnManager.findColumn(target);
break;
case "cell":
if (listener.components.includes("cell")) {
if (matches["row"] instanceof Row) component = matches["row"].findCell(target);
else if (targets["row"]) console.warn("Event Target Lookup Error - The row this cell is attached to cannot be found, has the table been reinitialized without being destroyed first?");
}
break;
}
if (component) {
matches[key] = component;
targetMatches[key] = {
target,
component
};
}
}
this.previousTargets = targetMatches;
Object.keys(targets).forEach((key) => {
output[key] = matches[key];
});
return output;
}
triggerEvents(type, e, targets) {
var listener = this.listeners[type];
for (let key in targets) if (targets[key] && listener.components.includes(key)) this.dispatch(key + "-" + type, e, targets[key]);
}
clearWatchers() {
for (let key in this.listeners) {
let listener = this.listeners[key];
if (listener.handler) {
this.el.removeEventListener(key, listener.handler);
listener.handler = null;
}
}
}
};
var ComponentFunctionBinder = class {
constructor(table) {
this.table = table;
this.bindings = {};
}
bind(type, funcName, handler) {
if (!this.bindings[type]) this.bindings[type] = {};
if (this.bindings[type][funcName]) console.warn("Unable to bind component handler, a matching function name is already bound", type, funcName, handler);
else this.bindings[type][funcName] = handler;
}
handle(type, component, name) {
if (this.bindings[type] && this.bindings[type][name] && typeof this.bindings[type][name].bind === "function") return this.bindings[type][name].bind(null, component);
else if (name !== "then" && typeof name === "string" && !name.startsWith("_")) {
if (this.table.options.debugInvalidComponentFuncs) console.error("The " + type + " component does not have a " + name + " function, have you checked that you have the correct Tabulator module installed?");
}
}
};
var DataLoader = class extends CoreFeature {
constructor(table) {
super(table);
this.requestOrder = 0;
this.loading = false;
}
initialize() {}
load(data, params, config, replace, silent, columnsChanged) {
var requestNo = ++this.requestOrder;
if (this.table.destroyed) return Promise.resolve();
this.dispatchExternal("dataLoading", data);
if (data && (data.indexOf("{") == 0 || data.indexOf("[") == 0)) data = JSON.parse(data);
if (this.confirm("data-loading", [
data,
params,
config,
silent
])) {
this.loading = true;
if (!silent) this.alertLoader();
params = this.chain("data-params", [
data,
config,
silent
], params || {}, params || {});
params = this.mapParams(params, this.table.options.dataSendParams);
return this.chain("data-load", [
data,
params,
config,
silent
], false, Promise.resolve([])).then((response) => {
if (!this.table.destroyed) {
if (!Array.isArray(response) && typeof response == "object") response = this.mapParams(response, this.objectInvert(this.table.options.dataReceiveParams));
var rowData = this.chain("data-loaded", [response], null, response);
if (requestNo == this.requestOrder) {
this.clearAlert();
if (rowData !== false) {
this.dispatchExternal("dataLoaded", rowData);
this.table.rowManager.setData(rowData, replace, typeof columnsChanged === "undefined" ? !replace : columnsChanged);
}
} else console.warn("Data Load Response Blocked - An active data load request was blocked by an attempt to change table data while the request was being made");
} else console.warn("Data Load Response Blocked - Table has been destroyed");
}).catch((error) => {
console.error("Data Load Error: ", error);
this.dispatchExternal("dataLoadError", error);
if (!silent) this.alertError();
setTimeout(() => {
this.clearAlert();
}, this.table.options.dataLoaderErrorTimeout);
}).finally(() => {
this.loading = false;
});
} else {
this.dispatchExternal("dataLoaded", data);
if (!data) data = [];
this.table.rowManager.setData(data, replace, typeof columnsChanged === "undefined" ? !replace : columnsChanged);
return Promise.resolve();
}
}
mapParams(params, map) {
var output = {};
for (let key in params) output[map.hasOwnProperty(key) ? map[key] : key] = params[key];
return output;
}
objectInvert(obj) {
var output = {};
for (let key in obj) output[obj[key]] = key;
return output;
}
blockActiveLoad() {
this.requestOrder++;
}
alertLoader() {
if (typeof this.table.options.dataLoader === "function" ? this.table.options.dataLoader() : this.table.options.dataLoader) this.table.alertManager.alert(this.table.options.dataLoaderLoading || this.langText("data|loading"));
}
alertError() {
this.table.alertManager.alert(this.table.options.dataLoaderError || this.langText("data|error"), "error");
}
clearAlert() {
this.table.alertManager.clear();
}
};
var ExternalEventBus = class {
constructor(table, optionsList, debug) {
this.table = table;
this.events = {};
this.optionsList = optionsList || {};
this.subscriptionNotifiers = {};
this.dispatch = debug ? this._debugDispatch.bind(this) : this._dispatch.bind(this);
this.debug = debug;
}
subscriptionChange(key, callback) {
if (!this.subscriptionNotifiers[key]) this.subscriptionNotifiers[key] = [];
this.subscriptionNotifiers[key].push(callback);
if (this.subscribed(key)) this._notifySubscriptionChange(key, true);
}
subscribe(key, callback) {
if (!this.events[key]) this.events[key] = [];
this.events[key].push(callback);
this._notifySubscriptionChange(key, true);
}
unsubscribe(key, callback) {
var index;
if (this.events[key]) if (callback) {
index = this.events[key].findIndex((item) => {
return item === callback;
});
if (index > -1) this.events[key].splice(index, 1);
else {
console.warn("Cannot remove event, no matching event found:", key, callback);
return;
}
} else delete this.events[key];
else {
console.warn("Cannot remove event, no events set on:", key);
return;
}
this._notifySubscriptionChange(key, false);
}
subscribed(key) {
return this.events[key] && this.events[key].length;
}
_notifySubscriptionChange(key, subscribed) {
var notifiers = this.subscriptionNotifiers[key];
if (notifiers) notifiers.forEach((callback) => {
callback(subscribed);
});
}
_dispatch() {
var args = Array.from(arguments), key = args.shift(), result;
if (this.events[key]) this.events[key].forEach((callback, i) => {
let callResult = callback.apply(this.table, args);
if (!i) result = callResult;
});
return result;
}
_debugDispatch() {
var args = Array.from(arguments), key = args[0];
args[0] = "ExternalEvent:" + args[0];
if (this.debug === true || this.debug.includes(key)) console.log(...args);
return this._dispatch(...arguments);
}
};
var InternalEventBus = class {
constructor(debug) {
this.events = {};
this.subscriptionNotifiers = {};
this.dispatch = debug ? this._debugDispatch.bind(this) : this._dispatch.bind(this);
this.chain = debug ? this._debugChain.bind(this) : this._chain.bind(this);
this.confirm = debug ? this._debugConfirm.bind(this) : this._confirm.bind(this);
this.debug = debug;
}
subscriptionChange(key, callback) {
if (!this.subscriptionNotifiers[key]) this.subscriptionNotifiers[key] = [];
this.subscriptionNotifiers[key].push(callback);
if (this.subscribed(key)) this._notifySubscriptionChange(key, true);
}
subscribe(key, callback, priority = 1e4) {
if (!this.events[key]) this.events[key] = [];
this.events[key].push({
callback,
priority
});
this.events[key].sort((a, b) => {
return a.priority - b.priority;
});
this._notifySubscriptionChange(key, true);
}
unsubscribe(key, callback) {
var index;
if (this.events[key]) {
if (callback) {
index = this.events[key].findIndex((item) => {
return item.callback === callback;
});
if (index > -1) this.events[key].splice(index, 1);
else {
console.warn("Cannot remove event, no matching event found:", key, callback);
return;
}
}
} else {
console.warn("Cannot remove event, no events set on:", key);
return;
}
this._notifySubscriptionChange(key, false);
}
subscribed(key) {
return this.events[key] && this.events[key].length;
}
_chain(key, args, initialValue, fallback) {
var value = initialValue;
if (!Array.isArray(args)) args = [args];
if (this.subscribed(key)) {
this.events[key].forEach((subscriber, i) => {
value = subscriber.callback.apply(this, args.concat([value]));
});
return value;
} else return typeof fallback === "function" ? fallback() : fallback;
}
_confirm(key, args) {
var confirmed = false;
if (!Array.isArray(args)) args = [args];
if (this.subscribed(key)) this.events[key].forEach((subscriber, i) => {
if (subscriber.callback.apply(this, args)) confirmed = true;
});
return confirmed;
}
_notifySubscriptionChange(key, subscribed) {
var notifiers = this.subscriptionNotifiers[key];
if (notifiers) notifiers.forEach((callback) => {
callback(subscribed);
});
}
_dispatch() {
var args = Array.from(arguments), key = args.shift();
if (this.events[key]) this.events[key].forEach((subscriber) => {
subscriber.callback.apply(this, args);
});
}
_debugDispatch() {
var args = Array.from(arguments), key = args[0];
args[0] = "InternalEvent:" + key;
if (this.debug === true || this.debug.includes(key)) console.log(...args);
return this._dispatch(...arguments);
}
_debugChain() {
var args = Array.from(arguments), key = args[0];
args[0] = "InternalEvent:" + key;
if (this.debug === true || this.debug.includes(key)) console.log(...args);
return this._chain(...arguments);
}
_debugConfirm() {
var args = Array.from(arguments), key = args[0];
args[0] = "InternalEvent:" + key;
if (this.debug === true || this.debug.includes(key)) console.log(...args);
return this._confirm(...arguments);
}
};
var DeprecationAdvisor = class extends CoreFeature {
constructor(table) {
super(table);
}
_warnUser() {
if (this.options("debugDeprecation")) console.warn(...arguments);
}
check(oldOption, newOption, convert) {
var msg = "";
if (typeof this.options(oldOption) !== "undefined") {
msg = "Deprecated Setup Option - Use of the %c" + oldOption + "%c option is now deprecated";
if (newOption) {
msg = msg + ", Please use the %c" + newOption + "%c option instead";
this._warnUser(msg, "font-weight: bold;", "font-weight: normal;", "font-weight: bold;", "font-weight: normal;");
if (convert) this.table.options[newOption] = this.table.options[oldOption];
} else this._warnUser(msg, "font-weight: bold;", "font-weight: normal;");
return false;
} else return true;
}
checkMsg(oldOption, msg) {
if (typeof this.options(oldOption) !== "undefined") {
this._warnUser("%cDeprecated Setup Option - Use of the %c" + oldOption + " %c option is now deprecated, " + msg, "font-weight: normal;", "font-weight: bold;", "font-weight: normal;");
return false;
} else return true;
}
msg(msg) {
this._warnUser(msg);
}
};
var DependencyRegistry = class extends CoreFeature {
constructor(table) {
super(table);
this.deps = {};
this.props = {};
}
initialize() {
this.deps = Object.assign({}, this.options("dependencies"));
}
lookup(key, prop, silent) {
if (Array.isArray(key)) {
for (const item of key) {
var match = this.lookup(item, prop, true);
if (match) break;
}
if (match) return match;
else this.error(key);
} else if (prop) return this.lookupProp(key, prop, silent);
else return this.lookupKey(key, silent);
}
lookupProp(key, prop, silent) {
var dependency;
if (this.props[key] && this.props[key][prop]) return this.props[key][prop];
else {
dependency = this.lookupKey(key, silent);
if (dependency) {
if (!this.props[key]) this.props[key] = {};
this.props[key][prop] = dependency[prop] || dependency;
return this.props[key][prop];
}
}
}
lookupKey(key, silent) {
var dependency;
if (this.deps[key]) dependency = this.deps[key];
else if (window[key]) {
this.deps[key] = window[key];
dependency = this.deps[key];
} else if (!silent) this.error(key);
return dependency;
}
error(key) {
console.error("Unable to find dependency", key, "Please check documentation and ensure you have imported the required library into your project");
}
};
function fitData(columns, forced) {
if (forced) this.table.columnManager.renderer.reinitializeColumnWidths(columns);
if (this.table.options.responsiveLayout && this.table.modExists("responsiveLayout", true)) this.table.modules.responsiveLayout.update();
}
function fitDataGeneral(columns, forced) {
columns.forEach(function(column) {
column.reinitializeWidth();
});
if (this.table.options.responsiveLayout && this.table.modExists("responsiveLayout", true)) this.table.modules.responsiveLayout.update();
}
function fitDataStretch(columns, forced) {
var colsWidth = 0, tableWidth = this.table.rowManager.element.clientWidth, gap = 0, lastCol = false;
columns.forEach((column, i) => {
if (!column.widthFixed) column.reinitializeWidth();
if (this.table.options.responsiveLayout ? column.modules.responsive.visible : column.visible) lastCol = column;
if (column.visible) colsWidth += column.getWidth();
});
if (lastCol) {
gap = tableWidth - colsWidth + lastCol.getWidth();
if (this.table.options.responsiveLayout && this.table.modExists("responsiveLayout", true)) {
lastCol.setWidth(0);
this.table.modules.responsiveLayout.update();
}
if (gap > 0) lastCol.setWidth(gap);
else lastCol.reinitializeWidth();
} else if (this.table.options.responsiveLayout && this.table.modExists("responsiveLayout", true)) this.table.modules.responsiveLayout.update();
}
function fitColumns(columns, forced) {
var totalWidth = this.table.rowManager.element.getBoundingClientRect().width;
var fixedWidth = 0;
var flexWidth = 0;
var flexGrowUnits = 0;
var flexColWidth = 0;
var flexColumns = [];
var fixedShrinkColumns = [];
var flexShrinkUnits = 0;
var overflowWidth = 0;
var gapFill = 0;
function calcWidth(width) {
var colWidth;
if (typeof width == "string") if (width.indexOf("%") > -1) colWidth = totalWidth / 100 * parseInt(width);
else colWidth = parseInt(width);
else colWidth = width;
return colWidth;
}
function scaleColumns(columns, freeSpace, colWidth, shrinkCols) {
var oversizeCols = [], oversizeSpace = 0, remainingSpace = 0, nextColWidth = 0, remainingFlexGrowUnits = flexGrowUnits, gap = 0, changeUnits = 0, undersizeCols = [];
function calcGrow(col) {
return colWidth * (col.column.definition.widthGrow || 1);
}
function calcShrink(col) {
return calcWidth(col.width) - colWidth * (col.column.definition.widthShrink || 0);
}
columns.forEach(function(col, i) {
var width = shrinkCols ? calcShrink(col) : calcGrow(col);
if (col.column.minWidth >= width) oversizeCols.push(col);
else if (col.column.maxWidth && col.column.maxWidth < width) {
col.width = col.column.maxWidth;
freeSpace -= col.column.maxWidth;
remainingFlexGrowUnits -= shrinkCols ? col.column.definition.widthShrink || 1 : col.column.definition.widthGrow || 1;
if (remainingFlexGrowUnits) colWidth = Math.floor(freeSpace / remainingFlexGrowUnits);
} else {
undersizeCols.push(col);
changeUnits += shrinkCols ? col.column.definition.widthShrink || 1 : col.column.definition.widthGrow || 1;
}
});
if (oversizeCols.length) {
oversizeCols.forEach(function(col) {
oversizeSpace += shrinkCols ? col.width - col.column.minWidth : col.column.minWidth;
col.width = col.column.minWidth;
});
remainingSpace = freeSpace - oversizeSpace;
nextColWidth = changeUnits ? Math.floor(remainingSpace / changeUnits) : remainingSpace;
gap = scaleColumns(undersizeCols, remainingSpace, nextColWidth, shrinkCols);
} else {
gap = changeUnits ? freeSpace - Math.floor(freeSpace / changeUnits) * changeUnits : freeSpace;
undersizeCols.forEach(function(column) {
column.width = shrinkCols ? calcShrink(column) : calcGrow(column);
});
}
return gap;
}
if (this.table.options.responsiveLayout && this.table.modExists("responsiveLayout", true)) this.table.modules.responsiveLayout.update();
if (this.table.rowManager.element.scrollHeight > this.table.rowManager.element.clientHeight) totalWidth -= this.table.rowManager.element.offsetWidth - this.table.rowManager.element.clientWidth;
columns.forEach(function(column) {
var width, minWidth, colWidth;
if (column.visible) {
width = column.definition.width;
minWidth = parseInt(column.minWidth);
if (width) {
colWidth = calcWidth(width);
fixedWidth += colWidth > minWidth ? colWidth : minWidth;
if (column.definition.widthShrink) {
fixedShrinkColumns.push({
column,
width: colWidth > minWidth ? colWidth : minWidth
});
flexShrinkUnits += column.definition.widthShrink;
}
} else {
flexColumns.push({
column,
width: 0
});
flexGrowUnits += column.definition.widthGrow || 1;
}
}
});
flexWidth = totalWidth - fixedWidth;
flexColWidth = Math.floor(flexWidth / flexGrowUnits);
gapFill = scaleColumns(flexColumns, flexWidth, flexColWidth, false);
if (flexColumns.length && gapFill > 0) flexColumns[flexColumns.length - 1].width += gapFill;
flexColumns.forEach(function(col) {
flexWidth -= col.width;
});
overflowWidth = Math.abs(gapFill) + flexWidth;
if (overflowWidth > 0 && flexShrinkUnits) gapFill = scaleColumns(fixedShrinkColumns, overflowWidth, Math.floor(overflowWidth / flexShrinkUnits), true);
if (gapFill && fixedShrinkColumns.length) fixedShrinkColumns[fixedShrinkColumns.length - 1].width -= gapFill;
flexColumns.forEach(function(col) {
col.column.setWidth(col.width);
});
fixedShrinkColumns.forEach(function(col) {
col.column.setWidth(col.width);
});
}
var defaultModes = {
fitData,
fitDataFill: fitDataGeneral,
fitDataTable: fitDataGeneral,
fitDataStretch,
fitColumns
};
var Layout = class Layout extends Module {
static moduleName = "layout";
static modes = defaultModes;
constructor(table) {
super(table, "layout");
this.mode = null;
this.registerTableOption("layout", "fitData");
this.registerTableOption("layoutColumnsOnNewData", false);
this.registerColumnOption("widthGrow");
this.registerColumnOption("widthShrink");
}
initialize() {
var layout = this.table.options.layout;
if (Layout.modes[layout]) this.mode = layout;
else {
console.warn("Layout Error - invalid mode set, defaulting to 'fitData' : " + layout);
this.mode = "fitData";
}
this.table.element.setAttribute("tabulator-layout", this.mode);
this.subscribe("column-init", this.initializeColumn.bind(this));
}
initializeColumn(column) {
if (column.definition.widthGrow) column.definition.widthGrow = Number(column.definition.widthGrow);
if (column.definition.widthShrink) column.definition.widthShrink = Number(column.definition.widthShrink);
}
getMode() {
return this.mode;
}
layout(dataChanged) {
var variableHeight = this.table.columnManager.columnsByIndex.find((column) => column.definition.variableHeight || column.definition.formatter === "textarea");
this.dispatch("layout-refreshing");
Layout.modes[this.mode].call(this, this.table.columnManager.columnsByIndex, dataChanged);
if (variableHeight) this.table.rowManager.normalizeHeight(true);
this.dispatch("layout-refreshed");
}
};
var defaultLangs = { "default": {
"groups": {
"item": "item",
"items": "items"
},
"columns": {},
"data": {
"loading": "Loading",
"error": "Error"
},
"pagination": {
"page_size": "Page Size",
"page_title": "Show Page",
"first": "First",
"first_title": "First Page",
"last": "Last",
"last_title": "Last Page",
"prev": "Prev",
"prev_title": "Prev Page",
"next": "Next",
"next_title": "Next Page",
"all": "All",
"counter": {
"showing": "Showing",
"of": "of",
"rows": "rows",
"pages": "pages"
}
},
"headerFilters": {
"default": "filter column...",
"columns": {}
}
} };
var Localize = class Localize extends Module {
static moduleName = "localize";
static langs = defaultLangs;
constructor(table) {
super(table);
this.locale = "default";
this.lang = false;
this.bindings = {};
this.langList = {};
this.registerTableOption("locale", false);
this.registerTableOption("langs", {});
}
initialize() {
this.langList = Helpers.deepClone(Localize.langs);
if (this.table.options.columnDefaults.headerFilterPlaceholder !== false) this.setHeaderFilterPlaceholder(this.table.options.columnDefaults.headerFilterPlaceholder);
for (let locale in this.table.options.langs) this.installLang(locale, this.table.options.langs[locale]);
this.setLocale(this.table.options.locale);
this.registerTableFunction("setLocale", this.setLocale.bind(this));
this.registerTableFunction("getLocale", this.getLocale.bind(this));
this.registerTableFunction("getLang", this.getLang.bind(this));
}
setHeaderFilterPlaceholder(placeholder) {
this.langList.default.headerFilters.default = placeholder;
}
installLang(locale, lang) {
if (this.langList[locale]) this._setLangProp(this.langList[locale], lang);
else this.langList[locale] = lang;
}
_setLangProp(lang, values) {
for (let key in values) if (lang[key] && typeof lang[key] == "object") this._setLangProp(lang[key], values[key]);
else lang[key] = values[key];
}
setLocale(desiredLocale) {
desiredLocale = desiredLocale || "default";
function traverseLang(trans, path) {
for (var prop in trans) if (typeof trans[prop] == "object") {
if (!path[prop]) path[prop] = {};
traverseLang(trans[prop], path[prop]);
} else path[prop] = trans[prop];
}
if (desiredLocale === true && navigator.language) desiredLocale = navigator.language.toLowerCase();
if (desiredLocale) {
if (!this.langList[desiredLocale]) {
let prefix = desiredLocale.split("-")[0];
if (this.langList[prefix]) {
console.warn("Localization Error - Exact matching locale not found, using closest match: ", desiredLocale, prefix);
desiredLocale = prefix;
} else {
console.warn("Localization Error - Matching locale not found, using default: ", desiredLocale);
desiredLocale = "default";
}
}
}
this.locale = desiredLocale;
this.lang = Helpers.deepClone(this.langList.default || {});
if (desiredLocale != "default") traverseLang(this.langList[desiredLocale], this.lang);
this.dispatchExternal("localized", this.locale, this.lang);
this._executeBindings();
}
getLocale(locale) {
return this.locale;
}
getLang(locale) {
return locale ? this.langList[locale] : this.lang;
}
getText(path, value) {
var pathArray = (value ? path + "|" + value : path).split("|");
return this._getLangElement(pathArray, this.locale) || "";
}
_getLangElement(path, locale) {
var root = this.lang;
path.forEach(function(level) {
var rootPath;
if (root) {
rootPath = root[level];
if (typeof rootPath != "undefined") root = rootPath;
else root = false;
}
});
return root;
}
bind(path, callback) {
if (!this.bindings[path]) this.bindings[path] = [];
this.bindings[path].push(callback);
callback(this.getText(path), this.lang);
}
_executeBindings() {
for (let path in this.bindings) this.bindings[path].forEach((binding) => {
binding(this.getText(path), this.lang);
});
}
};
var Comms = class extends Module {
static moduleName = "comms";
constructor(table) {
super(table);
}
initialize() {
this.registerTableFunction("tableComms", this.receive.bind(this));
}
getConnections(selectors) {
var connections = [];
this.table.constructor.registry.lookupTable(selectors).forEach((con) => {
if (this.table !== con) connections.push(con);
});
return connections;
}
send(selectors, module, action, data) {
var connections = this.getConnections(selectors);
connections.forEach((connection) => {
connection.tableComms(this.table.element, module, action, data);
});
if (!connections.length && selectors) console.warn("Table Connection Error - No tables matching selector found", selectors);
}
receive(table, module, action, data) {
if (this.table.modExists(module)) return this.table.modules[module].commsReceived(table, action, data);
else console.warn("Inter-table Comms Error - no such module:", module);
}
};
var coreModules = Object.freeze({
__proto__: null,
CommsModule: Comms,
LayoutModule: Layout,
LocalizeModule: Localize
});
var TableRegistry = class TableRegistry {
static registry = {
tables: [],
register(table) {
TableRegistry.registry.tables.push(table);
},
deregister(table) {
var index = TableRegistry.registry.tables.indexOf(table);
if (index > -1) TableRegistry.registry.tables.splice(index, 1);
},
lookupTable(query, silent) {
var results = [], matches, match;
if (typeof query === "string") {
matches = document.querySelectorAll(query);
if (matches.length) for (var i = 0; i < matches.length; i++) {
match = TableRegistry.registry.matchElement(matches[i]);
if (match) results.push(match);
}
} else if (typeof HTMLElement !== "undefined" && query instanceof HTMLElement || query instanceof TableRegistry) {
match = TableRegistry.registry.matchElement(query);
if (match) results.push(match);
} else if (Array.isArray(query)) query.forEach(function(item) {
results = results.concat(TableRegistry.registry.lookupTable(item));
});
else if (!silent) console.warn("Table Connection Error - Invalid Selector", query);
return results;
},
matchElement(element) {
return TableRegistry.registry.tables.find(function(table) {
return element instanceof TableRegistry ? table === element : table.element === element;
});
}
};
static findTable(query) {
var results = TableRegistry.registry.lookupTable(query, true);
return Array.isArray(results) && !results.length ? false : results;
}
};
var ModuleBinder = class ModuleBinder extends TableRegistry {
static moduleBindings = {};
static moduleExtensions = {};
static modulesRegistered = false;
static defaultModules = false;
constructor() {
super();
}
static initializeModuleBinder(defaultModules) {
if (!ModuleBinder.modulesRegistered) {
ModuleBinder.modulesRegistered = true;
ModuleBinder._registerModules(coreModules, true);
if (defaultModules) ModuleBinder._registerModules(defaultModules);
}
}
static _extendModule(name, property, values) {
if (ModuleBinder.moduleBindings[name]) {
var source = ModuleBinder.moduleBindings[name][property];
if (source) if (typeof values == "object") for (let key in values) source[key] = values[key];
else console.warn("Module Error - Invalid value type, it must be an object");
else console.warn("Module Error - property does not exist:", property);
} else console.warn("Module Error - module does not exist:", name);
}
static _registerModules(modules, core) {
var mods = Object.values(modules);
if (core) mods.forEach((mod) => {
mod.prototype.moduleCore = true;
});
ModuleBinder._registerModule(mods);
}
static _registerModule(modules) {
if (!Array.isArray(modules)) modules = [modules];
modules.forEach((mod) => {
ModuleBinder._registerModuleBinding(mod);
ModuleBinder._registerModuleExtensions(mod);
});
}
static _registerModuleBinding(mod) {
if (mod.moduleName) ModuleBinder.moduleBindings[mod.moduleName] = mod;
else console.error("Unable to bind module, no moduleName defined", mod.moduleName);
}
static _registerModuleExtensions(mod) {
var extensions = mod.moduleExtensions;
if (mod.moduleExtensions) for (let modKey in extensions) {
let ext = extensions[modKey];
if (ModuleBinder.moduleBindings[modKey]) for (let propKey in ext) ModuleBinder._extendModule(modKey, propKey, ext[propKey]);
else {
if (!ModuleBinder.moduleExtensions[modKey]) ModuleBinder.moduleExtensions[modKey] = {};
for (let propKey in ext) {
if (!ModuleBinder.moduleExtensions[modKey][propKey]) ModuleBinder.moduleExtensions[modKey][propKey] = {};
Object.assign(ModuleBinder.moduleExtensions[modKey][propKey], ext[propKey]);
}
}
}
ModuleBinder._extendModuleFromQueue(mod);
}
static _extendModuleFromQueue(mod) {
var extensions = ModuleBinder.moduleExtensions[mod.moduleName];
if (extensions) for (let propKey in extensions) ModuleBinder._extendModule(mod.moduleName, propKey, extensions[propKey]);
}
_bindModules() {
var orderedStartMods = [], orderedEndMods = [], unOrderedMods = [];
this.modules = {};
for (var name in ModuleBinder.moduleBindings) {
let mod = ModuleBinder.moduleBindings[name];
let module = new mod(this);
this.modules[name] = module;
if (mod.prototype.moduleCore) this.modulesCore.push(module);
else if (mod.moduleInitOrder) if (mod.moduleInitOrder < 0) orderedStartMods.push(module);
else orderedEndMods.push(module);
else unOrderedMods.push(module);
}
orderedStartMods.sort((a, b) => a.moduleInitOrder > b.moduleInitOrder ? 1 : -1);
orderedEndMods.sort((a, b) => a.moduleInitOrder > b.moduleInitOrder ? 1 : -1);
this.modulesRegular = orderedStartMods.concat(unOrderedMods.concat(orderedEndMods));
}
};
var Alert = class extends CoreFeature {
constructor(table) {
super(table);
this.element = this._createAlertElement();
this.msgElement = this._createMsgElement();
this.type = null;
this.element.appendChild(this.msgElement);
}
_createAlertElement() {
var el = document.createElement("div");
el.classList.add("tabulator-alert");
return el;
}
_createMsgElement() {
var el = document.createElement("div");
el.classList.add("tabulator-alert-msg");
el.setAttribute("role", "alert");
return el;
}
_typeClass() {
return "tabulator-alert-state-" + this.type;
}
alert(content, type = "msg") {
if (content) {
this.clear();
this.dispatch("alert-show", type);
this.type = type;
while (this.msgElement.firstChild) this.msgElement.removeChild(this.msgElement.firstChild);
this.msgElement.classList.add(this._typeClass());
if (typeof content === "function") content = content();
if (content instanceof HTMLElement) this.msgElement.appendChild(content);
else this.msgElement.innerHTML = content;
this.table.element.appendChild(this.element);
}
}
clear() {
this.dispatch("alert-hide", this.type);
if (this.element.parentNode) this.element.parentNode.removeChild(this.element);
this.msgElement.classList.remove(this._typeClass());
}
};
var Tabulator$1$1 = class Tabulator$1 extends ModuleBinder {
static defaultOptions = defaultOptions;
static extendModule() {
Tabulator$1.initializeModuleBinder();
Tabulator$1._extendModule(...arguments);
}
static registerModule() {
Tabulator$1.initializeModuleBinder();
Tabulator$1._registerModule(...arguments);
}
constructor(element, options, modules) {
super();
Tabulator$1.initializeModuleBinder(modules);
this.options = {};
this.columnManager = null;
this.rowManager = null;
this.footerManager = null;
this.alertManager = null;
this.vdomHoz = null;
this.externalEvents = null;
this.eventBus = null;
this.interactionMonitor = false;
this.browser = "";
this.browserSlow = false;
this.browserMobile = false;
this.rtl = false;
this.originalElement = null;
this.componentFunctionBinder = new ComponentFunctionBinder(this);
this.dataLoader = false;
this.modules = {};
this.modulesCore = [];
this.modulesRegular = [];
this.deprecationAdvisor = new DeprecationAdvisor(this);
this.optionsList = new OptionsList(this, "table constructor");
this.dependencyRegistry = new DependencyRegistry(this);
this.initialized = false;
this.destroyed = false;
if (this.initializeElement(element)) {
this.initializeCoreSystems(options);
setTimeout(() => {
this._create();
});
}
this.constructor.registry.register(this);
}
initializeElement(element) {
if (typeof HTMLElement !== "undefined" && element instanceof HTMLElement) {
this.element = element;
return true;
} else if (typeof element === "string") {
this.element = document.querySelector(element);
if (this.element) return true;
else {
console.error("Tabulator Creation Error - no element found matching selector: ", element);
return false;
}
} else {
console.error("Tabulator Creation Error - Invalid element provided:", element);
return false;
}
}
initializeCoreSystems(options) {
this.columnManager = new ColumnManager(this);
this.rowManager = new RowManager(this);
this.footerManager = new FooterManager(this);
this.dataLoader = new DataLoader(this);
this.alertManager = new Alert(this);
this._bindModules();
this.options = this.optionsList.generate(Tabulator$1.defaultOptions, options);
this._clearObjectPointers();
this._mapDeprecatedFunctionality();
this.externalEvents = new ExternalEventBus(this, this.options, this.options.debugEventsExternal);
this.eventBus = new InternalEventBus(this.options.debugEventsInternal);
this.interactionMonitor = new InteractionManager(this);
this.dataLoader.initialize();
this.footerManager.initialize();
this.dependencyRegistry.initialize();
}
_mapDeprecatedFunctionality() {}
_clearSelection() {
this.element.classList.add("tabulator-block-select");
if (window.getSelection) {
if (window.getSelection().empty) window.getSelection().empty();
else if (window.getSelection().removeAllRanges) window.getSelection().removeAllRanges();
} else if (document.selection) document.selection.empty();
this.element.classList.remove("tabulator-block-select");
}
_create() {
this.externalEvents.dispatch("tableBuilding");
this.eventBus.dispatch("table-building");
this._rtlCheck();
this._buildElement();
this._initializeTable();
this.initialized = true;
this._loadInitialData().finally(() => {
this.eventBus.dispatch("table-initialized");
this.externalEvents.dispatch("tableBuilt");
});
}
_rtlCheck() {
var style = window.getComputedStyle(this.element);
switch (this.options.textDirection) {
case "auto": if (style.direction !== "rtl") break;
case "rtl":
this.element.classList.add("tabulator-rtl");
this.rtl = true;
break;
case "ltr": this.element.classList.add("tabulator-ltr");
default: this.rtl = false;
}
}
_clearObjectPointers() {
this.options.columns = this.options.columns.slice(0);
if (Array.isArray(this.options.data) && !this.options.reactiveData) this.options.data = this.options.data.slice(0);
}
_buildElement() {
var element = this.element, options = this.options, newElement;
if (element.tagName === "TABLE") {
this.originalElement = this.element;
newElement = document.createElement("div");
var attributes = element.attributes;
for (var i in attributes) if (typeof attributes[i] == "object") newElement.setAttribute(attributes[i].name, attributes[i].value);
element.parentNode.replaceChild(newElement, element);
this.element = element = newElement;
}
element.classList.add("tabulator");
element.setAttribute("role", "grid");
while (element.firstChild) element.removeChild(element.firstChild);
if (options.height) {
options.height = isNaN(options.height) ? options.height : options.height + "px";
element.style.height = options.height;
}
if (options.minHeight !== false) {
options.minHeight = isNaN(options.minHeight) ? options.minHeight : options.minHeight + "px";
element.style.minHeight = options.minHeight;
}
if (options.maxHeight !== false) {
options.maxHeight = isNaN(options.maxHeight) ? options.maxHeight : options.maxHeight + "px";
element.style.maxHeight = options.maxHeight;
}
}
_initializeTable() {
var element = this.element, options = this.options;
this.interactionMonitor.initialize();
this.columnManager.initialize();
this.rowManager.initialize();
this._detectBrowser();
this.modulesCore.forEach((mod) => {
mod.initialize();
});
element.appendChild(this.columnManager.getElement());
element.appendChild(this.rowManager.getElement());
if (options.footerElement) this.footerManager.activate();
if (options.autoColumns && options.data) this.columnManager.generateColumnsFromRowData(this.options.data);
this.modulesRegular.forEach((mod) => {
mod.initialize();
});
this.columnManager.setColumns(options.columns);
this.eventBus.dispatch("table-built");
}
_loadInitialData() {
return this.dataLoader.load(this.options.data).finally(() => {
this.columnManager.verticalAlignHeaders();
});
}
destroy() {
var element = this.element;
this.destroyed = true;
this.constructor.registry.deregister(this);
this.eventBus.dispatch("table-destroy");
this.rowManager.destroy();
while (element.firstChild) element.removeChild(element.firstChild);
element.classList.remove("tabulator");
this.externalEvents.dispatch("tableDestroyed");
}
_detectBrowser() {
var ua = navigator.userAgent || navigator.vendor || window.opera;
if (ua.indexOf("Trident") > -1) {
this.browser = "ie";
this.browserSlow = true;
} else if (ua.indexOf("Edge") > -1) {
this.browser = "edge";
this.browserSlow = true;
} else if (ua.indexOf("Firefox") > -1) {
this.browser = "firefox";
this.browserSlow = false;
} else if (ua.indexOf("Mac OS") > -1) {
this.browser = "safari";
this.browserSlow = false;
} else {
this.browser = "other";
this.browserSlow = false;
}
this.browserMobile = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(ua) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55\/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk\/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i.test(ua.slice(0, 4));
}
initGuard(func, msg) {
var stack, line;
if (this.options.debugInitialization && !this.initialized) {
if (!func) {
stack = new Error().stack.split("\n");
line = stack[0] == "Error" ? stack[2] : stack[1];
if (line[0] == " ") func = line.trim().split(" ")[1].split(".")[1];
else func = line.trim().split("@")[0];
}
console.warn("Table Not Initialized - Calling the " + func + " function before the table is initialized may result in inconsistent behavior, Please wait for the `tableBuilt` event before calling this function." + (msg ? " " + msg : ""));
}
return this.initialized;
}
blockRedraw() {
this.initGuard();
this.eventBus.dispatch("redraw-blocking");
this.rowManager.blockRedraw();
this.columnManager.blockRedraw();
this.eventBus.dispatch("redraw-blocked");
}
restoreRedraw() {
this.initGuard();
this.eventBus.dispatch("redraw-restoring");
this.rowManager.restoreRedraw();
this.columnManager.restoreRedraw();
this.eventBus.dispatch("redraw-restored");
}
setData(data, params, config) {
this.initGuard(false, "To set initial data please use the 'data' property in the table constructor.");
return this.dataLoader.load(data, params, config, false);
}
clearData() {
this.initGuard();
this.dataLoader.blockActiveLoad();
this.rowManager.clearData();
}
getData(active) {
return this.rowManager.getData(active);
}
getDataCount(active) {
return this.rowManager.getDataCount(active);
}
replaceData(data, params, config) {
this.initGuard();
return this.dataLoader.load(data, params, config, true, true);
}
updateData(data) {
var responses = 0;
this.initGuard();
return new Promise((resolve, reject) => {
this.dataLoader.blockActiveLoad();
if (typeof data === "string") data = JSON.parse(data);
if (data && data.length > 0) data.forEach((item) => {
var row = this.rowManager.findRow(item[this.options.index]);
if (row) {
responses++;
row.updateData(item).then(() => {
responses--;
if (!responses) resolve();
}).catch((e) => {
reject("Update Error - Unable to update row", item, e);
});
} else reject("Update Error - Unable to find row", item);
});
else {
console.warn("Update Error - No data provided");
reject("Update Error - No data provided");
}
});
}
addData(data, pos, index) {
this.initGuard();
return new Promise((resolve, reject) => {
this.dataLoader.blockActiveLoad();
if (typeof data === "string") data = JSON.parse(data);
if (data) this.rowManager.addRows(data, pos, index).then((rows) => {
var output = [];
rows.forEach(function(row) {
output.push(row.getComponent());
});
resolve(output);
});
else {
console.warn("Update Error - No data provided");
reject("Update Error - No data provided");
}
});
}
updateOrAddData(data) {
var rows = [], responses = 0;
this.initGuard();
return new Promise((resolve, reject) => {
this.dataLoader.blockActiveLoad();
if (typeof data === "string") data = JSON.parse(data);
if (data && data.length > 0) data.forEach((item) => {
var row = this.rowManager.findRow(item[this.options.index]);
responses++;
if (row) row.updateData(item).then(() => {
responses--;
rows.push(row.getComponent());
if (!responses) resolve(rows);
});
else this.rowManager.addRows(item).then((newRows) => {
responses--;
rows.push(newRows[0].getComponent());
if (!responses) resolve(rows);
});
});
else {
console.warn("Update Error - No data provided");
reject("Update Error - No data provided");
}
});
}
getRow(index) {
var row = this.rowManager.findRow(index);
if (row) return row.getComponent();
else {
console.warn("Find Error - No matching row found:", index);
return false;
}
}
getRowFromPosition(position) {
var row = this.rowManager.getRowFromPosition(position);
if (row) return row.getComponent();
else {
console.warn("Find Error - No matching row found:", position);
return false;
}
}
deleteRow(index) {
var foundRows = [];
this.initGuard();
if (!Array.isArray(index)) index = [index];
for (let item of index) {
let row = this.rowManager.findRow(item, true);
if (row) foundRows.push(row);
else {
console.error("Delete Error - No matching row found:", item);
return Promise.reject("Delete Error - No matching row found");
}
}
foundRows.sort((a, b) => {
return this.rowManager.rows.indexOf(a) > this.rowManager.rows.indexOf(b) ? 1 : -1;
});
foundRows.forEach((row) => {
row.delete();
});
this.rowManager.reRenderInPosition();
return Promise.resolve();
}
addRow(data, pos, index) {
this.initGuard();
if (typeof data === "string") data = JSON.parse(data);
return this.rowManager.addRows(data, pos, index, true).then((rows) => {
return rows[0].getComponent();
});
}
updateOrAddRow(index, data) {
var row = this.rowManager.findRow(index);
this.initGuard();
if (typeof data === "string") data = JSON.parse(data);
if (row) return row.updateData(data).then(() => {
return row.getComponent();
});
else return this.rowManager.addRows(data).then((rows) => {
return rows[0].getComponent();
});
}
updateRow(index, data) {
var row = this.rowManager.findRow(index);
this.initGuard();
if (typeof data === "string") data = JSON.parse(data);
if (row) return row.updateData(data).then(() => {
return Promise.resolve(row.getComponent());
});
else {
console.warn("Update Error - No matching row found:", index);
return Promise.reject("Update Error - No matching row found");
}
}
scrollToRow(index, position, ifVisible) {
var row = this.rowManager.findRow(index);
if (row) return this.rowManager.scrollToRow(row, position, ifVisible);
else {
console.warn("Scroll Error - No matching row found:", index);
return Promise.reject("Scroll Error - No matching row found");
}
}
moveRow(from, to, after) {
var fromRow = this.rowManager.findRow(from);
this.initGuard();
if (fromRow) fromRow.moveToRow(to, after);
else console.warn("Move Error - No matching row found:", from);
}
getRows(active) {
return this.rowManager.getComponents(active);
}
getRowPosition(index) {
var row = this.rowManager.findRow(index);
if (row) return row.getPosition();
else {
console.warn("Position Error - No matching row found:", index);
return false;
}
}
setColumns(definition) {
this.initGuard(false, "To set initial columns please use the 'columns' property in the table constructor");
this.columnManager.setColumns(definition);
}
getColumns(structured) {
return this.columnManager.getComponents(structured);
}
getColumn(field) {
var column = this.columnManager.findColumn(field);
if (column) return column.getComponent();
else {
console.warn("Find Error - No matching column found:", field);
return false;
}
}
getColumnDefinitions() {
return this.columnManager.getDefinitionTree();
}
showColumn(field) {
var column = this.columnManager.findColumn(field);
this.initGuard();
if (column) column.show();
else {
console.warn("Column Show Error - No matching column found:", field);
return false;
}
}
hideColumn(field) {
var column = this.columnManager.findColumn(field);
this.initGuard();
if (column) column.hide();
else {
console.warn("Column Hide Error - No matching column found:", field);
return false;
}
}
toggleColumn(field) {
var column = this.columnManager.findColumn(field);
this.initGuard();
if (column) if (column.visible) column.hide();
else column.show();
else {
console.warn("Column Visibility Toggle Error - No matching column found:", field);
return false;
}
}
addColumn(definition, before, field) {
var column = this.columnManager.findColumn(field);
this.initGuard();
return this.columnManager.addColumn(definition, before, column).then((column) => {
return column.getComponent();
});
}
deleteColumn(field) {
var column = this.columnManager.findColumn(field);
this.initGuard();
if (column) return column.delete();
else {
console.warn("Column Delete Error - No matching column found:", field);
return Promise.reject();
}
}
updateColumnDefinition(field, definition) {
var column = this.columnManager.findColumn(field);
this.initGuard();
if (column) return column.updateDefinition(definition);
else {
console.warn("Column Update Error - No matching column found:", field);
return Promise.reject();
}
}
moveColumn(from, to, after) {
var fromColumn = this.columnManager.findColumn(from), toColumn = this.columnManager.findColumn(to);
this.initGuard();
if (fromColumn) if (toColumn) this.columnManager.moveColumn(fromColumn, toColumn, after);
else console.warn("Move Error - No matching column found:", toColumn);
else console.warn("Move Error - No matching column found:", from);
}
scrollToColumn(field, position, ifVisible) {
return new Promise((resolve, reject) => {
var column = this.columnManager.findColumn(field);
if (column) return this.columnManager.scrollToColumn(column, position, ifVisible);
else {
console.warn("Scroll Error - No matching column found:", field);
return Promise.reject("Scroll Error - No matching column found");
}
});
}
redraw(force) {
this.initGuard();
this.columnManager.redraw(force);
this.rowManager.redraw(force);
}
setHeight(height) {
this.options.height = isNaN(height) ? height : height + "px";
this.element.style.height = this.options.height;
this.rowManager.initializeRenderer();
this.rowManager.redraw(true);
}
on(key, callback) {
this.externalEvents.subscribe(key, callback);
}
off(key, callback) {
this.externalEvents.unsubscribe(key, callback);
}
dispatchEvent() {
Array.from(arguments).shift();
this.externalEvents.dispatch(...arguments);
}
alert(contents, type) {
this.initGuard();
this.alertManager.alert(contents, type);
}
clearAlert() {
this.initGuard();
this.alertManager.clear();
}
modExists(plugin, required) {
if (this.modules[plugin]) return true;
else {
if (required) console.error("Tabulator Module Not Installed: " + plugin);
return false;
}
}
module(key) {
var mod = this.modules[key];
if (!mod) console.error("Tabulator module not installed: " + key);
return mod;
}
};
var TabulatorFull = class extends Tabulator$1$1 {
static extendModule() {
Tabulator$1$1.initializeModuleBinder(allModules);
Tabulator$1$1._extendModule(...arguments);
}
static registerModule() {
Tabulator$1$1.initializeModuleBinder(allModules);
Tabulator$1$1._registerModule(...arguments);
}
constructor(element, options, modules) {
super(element, options, allModules);
}
};
var TabulatorFull$1 = TabulatorFull;
var require_toastify = __commonJSMin(((exports, module) => {
(function(root, factory) {
if (typeof module === "object" && module.exports) module.exports = factory();
else root.Toastify = factory();
})(exports, function(global) {
var Toastify = function(options) {
return new Toastify.lib.init(options);
}, version = "1.12.0";
Toastify.defaults = {
oldestFirst: true,
text: "Toastify is awesome!",
node: void 0,
duration: 3e3,
selector: void 0,
callback: function() {},
destination: void 0,
newWindow: false,
close: false,
gravity: "toastify-top",
positionLeft: false,
position: "",
backgroundColor: "",
avatar: "",
className: "",
stopOnFocus: true,
onClick: function() {},
offset: {
x: 0,
y: 0
},
escapeMarkup: true,
ariaLive: "polite",
style: { background: "" }
};
Toastify.lib = Toastify.prototype = {
toastify: version,
constructor: Toastify,
init: function(options) {
if (!options) options = {};
this.options = {};
this.toastElement = null;
this.options.text = options.text || Toastify.defaults.text;
this.options.node = options.node || Toastify.defaults.node;
this.options.duration = options.duration === 0 ? 0 : options.duration || Toastify.defaults.duration;
this.options.selector = options.selector || Toastify.defaults.selector;
this.options.callback = options.callback || Toastify.defaults.callback;
this.options.destination = options.destination || Toastify.defaults.destination;
this.options.newWindow = options.newWindow || Toastify.defaults.newWindow;
this.options.close = options.close || Toastify.defaults.close;
this.options.gravity = options.gravity === "bottom" ? "toastify-bottom" : Toastify.defaults.gravity;
this.options.positionLeft = options.positionLeft || Toastify.defaults.positionLeft;
this.options.position = options.position || Toastify.defaults.position;
this.options.backgroundColor = options.backgroundColor || Toastify.defaults.backgroundColor;
this.options.avatar = options.avatar || Toastify.defaults.avatar;
this.options.className = options.className || Toastify.defaults.className;
this.options.stopOnFocus = options.stopOnFocus === void 0 ? Toastify.defaults.stopOnFocus : options.stopOnFocus;
this.options.onClick = options.onClick || Toastify.defaults.onClick;
this.options.offset = options.offset || Toastify.defaults.offset;
this.options.escapeMarkup = options.escapeMarkup !== void 0 ? options.escapeMarkup : Toastify.defaults.escapeMarkup;
this.options.ariaLive = options.ariaLive || Toastify.defaults.ariaLive;
this.options.style = options.style || Toastify.defaults.style;
if (options.backgroundColor) this.options.style.background = options.backgroundColor;
return this;
},
buildToast: function() {
if (!this.options) throw "Toastify is not initialized";
var divElement = document.createElement("div");
divElement.className = "toastify on " + this.options.className;
if (!!this.options.position) divElement.className += " toastify-" + this.options.position;
else if (this.options.positionLeft === true) {
divElement.className += " toastify-left";
console.warn("Property `positionLeft` will be depreciated in further versions. Please use `position` instead.");
} else divElement.className += " toastify-right";
divElement.className += " " + this.options.gravity;
if (this.options.backgroundColor) console.warn("DEPRECATION NOTICE: \"backgroundColor\" is being deprecated. Please use the \"style.background\" property.");
for (var property in this.options.style) divElement.style[property] = this.options.style[property];
if (this.options.ariaLive) divElement.setAttribute("aria-live", this.options.ariaLive);
if (this.options.node && this.options.node.nodeType === Node.ELEMENT_NODE) divElement.appendChild(this.options.node);
else {
if (this.options.escapeMarkup) divElement.innerText = this.options.text;
else divElement.innerHTML = this.options.text;
if (this.options.avatar !== "") {
var avatarElement = document.createElement("img");
avatarElement.src = this.options.avatar;
avatarElement.className = "toastify-avatar";
if (this.options.position == "left" || this.options.positionLeft === true) divElement.appendChild(avatarElement);
else divElement.insertAdjacentElement("afterbegin", avatarElement);
}
}
if (this.options.close === true) {
var closeElement = document.createElement("button");
closeElement.type = "button";
closeElement.setAttribute("aria-label", "Close");
closeElement.className = "toast-close";
closeElement.innerHTML = "✖";
closeElement.addEventListener("click", function(event) {
event.stopPropagation();
this.removeElement(this.toastElement);
window.clearTimeout(this.toastElement.timeOutValue);
}.bind(this));
var width = window.innerWidth > 0 ? window.innerWidth : screen.width;
if ((this.options.position == "left" || this.options.positionLeft === true) && width > 360) divElement.insertAdjacentElement("afterbegin", closeElement);
else divElement.appendChild(closeElement);
}
if (this.options.stopOnFocus && this.options.duration > 0) {
var self = this;
divElement.addEventListener("mouseover", function(event) {
window.clearTimeout(divElement.timeOutValue);
});
divElement.addEventListener("mouseleave", function() {
divElement.timeOutValue = window.setTimeout(function() {
self.removeElement(divElement);
}, self.options.duration);
});
}
if (typeof this.options.destination !== "undefined") divElement.addEventListener("click", function(event) {
event.stopPropagation();
if (this.options.newWindow === true) window.open(this.options.destination, "_blank");
else window.location = this.options.destination;
}.bind(this));
if (typeof this.options.onClick === "function" && typeof this.options.destination === "undefined") divElement.addEventListener("click", function(event) {
event.stopPropagation();
this.options.onClick();
}.bind(this));
if (typeof this.options.offset === "object") {
var x = getAxisOffsetAValue("x", this.options);
var y = getAxisOffsetAValue("y", this.options);
var xOffset = this.options.position == "left" ? x : "-" + x;
var yOffset = this.options.gravity == "toastify-top" ? y : "-" + y;
divElement.style.transform = "translate(" + xOffset + "," + yOffset + ")";
}
return divElement;
},
showToast: function() {
this.toastElement = this.buildToast();
var rootElement;
if (typeof this.options.selector === "string") rootElement = document.getElementById(this.options.selector);
else if (this.options.selector instanceof HTMLElement || typeof ShadowRoot !== "undefined" && this.options.selector instanceof ShadowRoot) rootElement = this.options.selector;
else rootElement = document.body;
if (!rootElement) throw "Root element is not defined";
var elementToInsert = Toastify.defaults.oldestFirst ? rootElement.firstChild : rootElement.lastChild;
rootElement.insertBefore(this.toastElement, elementToInsert);
Toastify.reposition();
if (this.options.duration > 0) this.toastElement.timeOutValue = window.setTimeout(function() {
this.removeElement(this.toastElement);
}.bind(this), this.options.duration);
return this;
},
hideToast: function() {
if (this.toastElement.timeOutValue) clearTimeout(this.toastElement.timeOutValue);
this.removeElement(this.toastElement);
},
removeElement: function(toastElement) {
toastElement.className = toastElement.className.replace(" on", "");
window.setTimeout(function() {
if (this.options.node && this.options.node.parentNode) this.options.node.parentNode.removeChild(this.options.node);
if (toastElement.parentNode) toastElement.parentNode.removeChild(toastElement);
this.options.callback.call(toastElement);
Toastify.reposition();
}.bind(this), 400);
}
};
Toastify.reposition = function() {
var topLeftOffsetSize = {
top: 15,
bottom: 15
};
var topRightOffsetSize = {
top: 15,
bottom: 15
};
var offsetSize = {
top: 15,
bottom: 15
};
var allToasts = document.getElementsByClassName("toastify");
var classUsed;
for (var i = 0; i < allToasts.length; i++) {
if (containsClass(allToasts[i], "toastify-top") === true) classUsed = "toastify-top";
else classUsed = "toastify-bottom";
var height = allToasts[i].offsetHeight;
classUsed = classUsed.substr(9, classUsed.length - 1);
var offset = 15;
if ((window.innerWidth > 0 ? window.innerWidth : screen.width) <= 360) {
allToasts[i].style[classUsed] = offsetSize[classUsed] + "px";
offsetSize[classUsed] += height + offset;
} else if (containsClass(allToasts[i], "toastify-left") === true) {
allToasts[i].style[classUsed] = topLeftOffsetSize[classUsed] + "px";
topLeftOffsetSize[classUsed] += height + offset;
} else {
allToasts[i].style[classUsed] = topRightOffsetSize[classUsed] + "px";
topRightOffsetSize[classUsed] += height + offset;
}
}
return this;
};
function getAxisOffsetAValue(axis, options) {
if (options.offset[axis]) if (isNaN(options.offset[axis])) return options.offset[axis];
else return options.offset[axis] + "px";
return "0px";
}
function containsClass(elem, yourClass) {
if (!elem || typeof yourClass !== "string") return false;
else if (elem.className && elem.className.trim().split(/\s+/gi).indexOf(yourClass) > -1) return true;
else return false;
}
Toastify.lib.init.prototype = Toastify.lib;
return Toastify;
});
}));
var require_localforage = __commonJSMin(((exports, module) => {
(function(f) {
if (typeof exports === "object" && typeof module !== "undefined") module.exports = f();
else if (typeof define === "function" && define.amd) define([], f);
else {
var g;
if (typeof window !== "undefined") g = window;
else if (typeof global !== "undefined") g = global;
else if (typeof self !== "undefined") g = self;
else g = this;
g.localforage = f();
}
})(function() {
return (function e(t, n, r) {
function s(o, u) {
if (!n[o]) {
if (!t[o]) {
var a = typeof __require == "function" && __require;
if (!u && a) return a(o, !0);
if (i) return i(o, !0);
var f = new Error("Cannot find module '" + o + "'");
throw f.code = "MODULE_NOT_FOUND", f;
}
var l = n[o] = { exports: {} };
t[o][0].call(l.exports, function(e) {
var n = t[o][1][e];
return s(n ? n : e);
}, l, l.exports, e, t, n, r);
}
return n[o].exports;
}
var i = typeof __require == "function" && __require;
for (var o = 0; o < r.length; o++) s(r[o]);
return s;
})({
1: [function(_dereq_, module$1, exports$1) {
(function(global) {
"use strict";
var Mutation = global.MutationObserver || global.WebKitMutationObserver;
var scheduleDrain;
if (Mutation) {
var called = 0;
var observer = new Mutation(nextTick);
var element = global.document.createTextNode("");
observer.observe(element, { characterData: true });
scheduleDrain = function() {
element.data = called = ++called % 2;
};
} else if (!global.setImmediate && typeof global.MessageChannel !== "undefined") {
var channel = new global.MessageChannel();
channel.port1.onmessage = nextTick;
scheduleDrain = function() {
channel.port2.postMessage(0);
};
} else if ("document" in global && "onreadystatechange" in global.document.createElement("script")) scheduleDrain = function() {
var scriptEl = global.document.createElement("script");
scriptEl.onreadystatechange = function() {
nextTick();
scriptEl.onreadystatechange = null;
scriptEl.parentNode.removeChild(scriptEl);
scriptEl = null;
};
global.document.documentElement.appendChild(scriptEl);
};
else scheduleDrain = function() {
setTimeout(nextTick, 0);
};
var draining;
var queue = [];
function nextTick() {
draining = true;
var i, oldQueue;
var len = queue.length;
while (len) {
oldQueue = queue;
queue = [];
i = -1;
while (++i < len) oldQueue[i]();
len = queue.length;
}
draining = false;
}
module$1.exports = immediate;
function immediate(task) {
if (queue.push(task) === 1 && !draining) scheduleDrain();
}
}).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
}, {}],
2: [function(_dereq_, module$2, exports$2) {
"use strict";
var immediate = _dereq_(1);
function INTERNAL() {}
var handlers = {};
var REJECTED = ["REJECTED"];
var FULFILLED = ["FULFILLED"];
var PENDING = ["PENDING"];
module$2.exports = Promise;
function Promise(resolver) {
if (typeof resolver !== "function") throw new TypeError("resolver must be a function");
this.state = PENDING;
this.queue = [];
this.outcome = void 0;
if (resolver !== INTERNAL) safelyResolveThenable(this, resolver);
}
Promise.prototype["catch"] = function(onRejected) {
return this.then(null, onRejected);
};
Promise.prototype.then = function(onFulfilled, onRejected) {
if (typeof onFulfilled !== "function" && this.state === FULFILLED || typeof onRejected !== "function" && this.state === REJECTED) return this;
var promise = new this.constructor(INTERNAL);
if (this.state !== PENDING) unwrap(promise, this.state === FULFILLED ? onFulfilled : onRejected, this.outcome);
else this.queue.push(new QueueItem(promise, onFulfilled, onRejected));
return promise;
};
function QueueItem(promise, onFulfilled, onRejected) {
this.promise = promise;
if (typeof onFulfilled === "function") {
this.onFulfilled = onFulfilled;
this.callFulfilled = this.otherCallFulfilled;
}
if (typeof onRejected === "function") {
this.onRejected = onRejected;
this.callRejected = this.otherCallRejected;
}
}
QueueItem.prototype.callFulfilled = function(value) {
handlers.resolve(this.promise, value);
};
QueueItem.prototype.otherCallFulfilled = function(value) {
unwrap(this.promise, this.onFulfilled, value);
};
QueueItem.prototype.callRejected = function(value) {
handlers.reject(this.promise, value);
};
QueueItem.prototype.otherCallRejected = function(value) {
unwrap(this.promise, this.onRejected, value);
};
function unwrap(promise, func, value) {
immediate(function() {
var returnValue;
try {
returnValue = func(value);
} catch (e) {
return handlers.reject(promise, e);
}
if (returnValue === promise) handlers.reject(promise, new TypeError("Cannot resolve promise with itself"));
else handlers.resolve(promise, returnValue);
});
}
handlers.resolve = function(self, value) {
var result = tryCatch(getThen, value);
if (result.status === "error") return handlers.reject(self, result.value);
var thenable = result.value;
if (thenable) safelyResolveThenable(self, thenable);
else {
self.state = FULFILLED;
self.outcome = value;
var i = -1;
var len = self.queue.length;
while (++i < len) self.queue[i].callFulfilled(value);
}
return self;
};
handlers.reject = function(self, error) {
self.state = REJECTED;
self.outcome = error;
var i = -1;
var len = self.queue.length;
while (++i < len) self.queue[i].callRejected(error);
return self;
};
function getThen(obj) {
var then = obj && obj.then;
if (obj && (typeof obj === "object" || typeof obj === "function") && typeof then === "function") return function appyThen() {
then.apply(obj, arguments);
};
}
function safelyResolveThenable(self, thenable) {
var called = false;
function onError(value) {
if (called) return;
called = true;
handlers.reject(self, value);
}
function onSuccess(value) {
if (called) return;
called = true;
handlers.resolve(self, value);
}
function tryToUnwrap() {
thenable(onSuccess, onError);
}
var result = tryCatch(tryToUnwrap);
if (result.status === "error") onError(result.value);
}
function tryCatch(func, value) {
var out = {};
try {
out.value = func(value);
out.status = "success";
} catch (e) {
out.status = "error";
out.value = e;
}
return out;
}
Promise.resolve = resolve;
function resolve(value) {
if (value instanceof this) return value;
return handlers.resolve(new this(INTERNAL), value);
}
Promise.reject = reject;
function reject(reason) {
var promise = new this(INTERNAL);
return handlers.reject(promise, reason);
}
Promise.all = all;
function all(iterable) {
var self = this;
if (Object.prototype.toString.call(iterable) !== "[object Array]") return this.reject(new TypeError("must be an array"));
var len = iterable.length;
var called = false;
if (!len) return this.resolve([]);
var values = new Array(len);
var resolved = 0;
var i = -1;
var promise = new this(INTERNAL);
while (++i < len) allResolver(iterable[i], i);
return promise;
function allResolver(value, i) {
self.resolve(value).then(resolveFromAll, function(error) {
if (!called) {
called = true;
handlers.reject(promise, error);
}
});
function resolveFromAll(outValue) {
values[i] = outValue;
if (++resolved === len && !called) {
called = true;
handlers.resolve(promise, values);
}
}
}
}
Promise.race = race;
function race(iterable) {
var self = this;
if (Object.prototype.toString.call(iterable) !== "[object Array]") return this.reject(new TypeError("must be an array"));
var len = iterable.length;
var called = false;
if (!len) return this.resolve([]);
var i = -1;
var promise = new this(INTERNAL);
while (++i < len) resolver(iterable[i]);
return promise;
function resolver(value) {
self.resolve(value).then(function(response) {
if (!called) {
called = true;
handlers.resolve(promise, response);
}
}, function(error) {
if (!called) {
called = true;
handlers.reject(promise, error);
}
});
}
}
}, { "1": 1 }],
3: [function(_dereq_, module$3, exports$3) {
(function(global) {
"use strict";
if (typeof global.Promise !== "function") global.Promise = _dereq_(2);
}).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
}, { "2": 2 }],
4: [function(_dereq_, module$4, exports$4) {
"use strict";
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function(obj) {
return typeof obj;
} : function(obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function");
}
function getIDB() {
try {
if (typeof indexedDB !== "undefined") return indexedDB;
if (typeof webkitIndexedDB !== "undefined") return webkitIndexedDB;
if (typeof mozIndexedDB !== "undefined") return mozIndexedDB;
if (typeof OIndexedDB !== "undefined") return OIndexedDB;
if (typeof msIndexedDB !== "undefined") return msIndexedDB;
} catch (e) {
return;
}
}
var idb = getIDB();
function isIndexedDBValid() {
try {
if (!idb || !idb.open) return false;
var isSafari = typeof openDatabase !== "undefined" && /(Safari|iPhone|iPad|iPod)/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent) && !/BlackBerry/.test(navigator.platform);
var hasFetch = typeof fetch === "function" && fetch.toString().indexOf("[native code") !== -1;
return (!isSafari || hasFetch) && typeof indexedDB !== "undefined" && typeof IDBKeyRange !== "undefined";
} catch (e) {
return false;
}
}
function createBlob(parts, properties) {
parts = parts || [];
properties = properties || {};
try {
return new Blob(parts, properties);
} catch (e) {
if (e.name !== "TypeError") throw e;
var builder = new (typeof BlobBuilder !== "undefined" ? BlobBuilder : typeof MSBlobBuilder !== "undefined" ? MSBlobBuilder : typeof MozBlobBuilder !== "undefined" ? MozBlobBuilder : WebKitBlobBuilder)();
for (var i = 0; i < parts.length; i += 1) builder.append(parts[i]);
return builder.getBlob(properties.type);
}
}
if (typeof Promise === "undefined") _dereq_(3);
var Promise$1 = Promise;
function executeCallback(promise, callback) {
if (callback) promise.then(function(result) {
callback(null, result);
}, function(error) {
callback(error);
});
}
function executeTwoCallbacks(promise, callback, errorCallback) {
if (typeof callback === "function") promise.then(callback);
if (typeof errorCallback === "function") promise["catch"](errorCallback);
}
function normalizeKey(key) {
if (typeof key !== "string") {
console.warn(key + " used as a key, but it is not a string.");
key = String(key);
}
return key;
}
function getCallback() {
if (arguments.length && typeof arguments[arguments.length - 1] === "function") return arguments[arguments.length - 1];
}
var DETECT_BLOB_SUPPORT_STORE = "local-forage-detect-blob-support";
var supportsBlobs = void 0;
var dbContexts = {};
var toString = Object.prototype.toString;
var READ_ONLY = "readonly";
var READ_WRITE = "readwrite";
function _binStringToArrayBuffer(bin) {
var length = bin.length;
var buf = new ArrayBuffer(length);
var arr = new Uint8Array(buf);
for (var i = 0; i < length; i++) arr[i] = bin.charCodeAt(i);
return buf;
}
function _checkBlobSupportWithoutCaching(idb) {
return new Promise$1(function(resolve) {
var txn = idb.transaction(DETECT_BLOB_SUPPORT_STORE, READ_WRITE);
var blob = createBlob([""]);
txn.objectStore(DETECT_BLOB_SUPPORT_STORE).put(blob, "key");
txn.onabort = function(e) {
e.preventDefault();
e.stopPropagation();
resolve(false);
};
txn.oncomplete = function() {
var matchedChrome = navigator.userAgent.match(/Chrome\/(\d+)/);
resolve(navigator.userAgent.match(/Edge\//) || !matchedChrome || parseInt(matchedChrome[1], 10) >= 43);
};
})["catch"](function() {
return false;
});
}
function _checkBlobSupport(idb) {
if (typeof supportsBlobs === "boolean") return Promise$1.resolve(supportsBlobs);
return _checkBlobSupportWithoutCaching(idb).then(function(value) {
supportsBlobs = value;
return supportsBlobs;
});
}
function _deferReadiness(dbInfo) {
var dbContext = dbContexts[dbInfo.name];
var deferredOperation = {};
deferredOperation.promise = new Promise$1(function(resolve, reject) {
deferredOperation.resolve = resolve;
deferredOperation.reject = reject;
});
dbContext.deferredOperations.push(deferredOperation);
if (!dbContext.dbReady) dbContext.dbReady = deferredOperation.promise;
else dbContext.dbReady = dbContext.dbReady.then(function() {
return deferredOperation.promise;
});
}
function _advanceReadiness(dbInfo) {
var deferredOperation = dbContexts[dbInfo.name].deferredOperations.pop();
if (deferredOperation) {
deferredOperation.resolve();
return deferredOperation.promise;
}
}
function _rejectReadiness(dbInfo, err) {
var deferredOperation = dbContexts[dbInfo.name].deferredOperations.pop();
if (deferredOperation) {
deferredOperation.reject(err);
return deferredOperation.promise;
}
}
function _getConnection(dbInfo, upgradeNeeded) {
return new Promise$1(function(resolve, reject) {
dbContexts[dbInfo.name] = dbContexts[dbInfo.name] || createDbContext();
if (dbInfo.db) if (upgradeNeeded) {
_deferReadiness(dbInfo);
dbInfo.db.close();
} else return resolve(dbInfo.db);
var dbArgs = [dbInfo.name];
if (upgradeNeeded) dbArgs.push(dbInfo.version);
var openreq = idb.open.apply(idb, dbArgs);
if (upgradeNeeded) openreq.onupgradeneeded = function(e) {
var db = openreq.result;
try {
db.createObjectStore(dbInfo.storeName);
if (e.oldVersion <= 1) db.createObjectStore(DETECT_BLOB_SUPPORT_STORE);
} catch (ex) {
if (ex.name === "ConstraintError") console.warn("The database \"" + dbInfo.name + "\" has been upgraded from version " + e.oldVersion + " to version " + e.newVersion + ", but the storage \"" + dbInfo.storeName + "\" already exists.");
else throw ex;
}
};
openreq.onerror = function(e) {
e.preventDefault();
reject(openreq.error);
};
openreq.onsuccess = function() {
var db = openreq.result;
db.onversionchange = function(e) {
e.target.close();
};
resolve(db);
_advanceReadiness(dbInfo);
};
});
}
function _getOriginalConnection(dbInfo) {
return _getConnection(dbInfo, false);
}
function _getUpgradedConnection(dbInfo) {
return _getConnection(dbInfo, true);
}
function _isUpgradeNeeded(dbInfo, defaultVersion) {
if (!dbInfo.db) return true;
var isNewStore = !dbInfo.db.objectStoreNames.contains(dbInfo.storeName);
var isDowngrade = dbInfo.version < dbInfo.db.version;
var isUpgrade = dbInfo.version > dbInfo.db.version;
if (isDowngrade) {
if (dbInfo.version !== defaultVersion) console.warn("The database \"" + dbInfo.name + "\" can't be downgraded from version " + dbInfo.db.version + " to version " + dbInfo.version + ".");
dbInfo.version = dbInfo.db.version;
}
if (isUpgrade || isNewStore) {
if (isNewStore) {
var incVersion = dbInfo.db.version + 1;
if (incVersion > dbInfo.version) dbInfo.version = incVersion;
}
return true;
}
return false;
}
function _encodeBlob(blob) {
return new Promise$1(function(resolve, reject) {
var reader = new FileReader();
reader.onerror = reject;
reader.onloadend = function(e) {
resolve({
__local_forage_encoded_blob: true,
data: btoa(e.target.result || ""),
type: blob.type
});
};
reader.readAsBinaryString(blob);
});
}
function _decodeBlob(encodedBlob) {
return createBlob([_binStringToArrayBuffer(atob(encodedBlob.data))], { type: encodedBlob.type });
}
function _isEncodedBlob(value) {
return value && value.__local_forage_encoded_blob;
}
function _fullyReady(callback) {
var self = this;
var promise = self._initReady().then(function() {
var dbContext = dbContexts[self._dbInfo.name];
if (dbContext && dbContext.dbReady) return dbContext.dbReady;
});
executeTwoCallbacks(promise, callback, callback);
return promise;
}
function _tryReconnect(dbInfo) {
_deferReadiness(dbInfo);
var dbContext = dbContexts[dbInfo.name];
var forages = dbContext.forages;
for (var i = 0; i < forages.length; i++) {
var forage = forages[i];
if (forage._dbInfo.db) {
forage._dbInfo.db.close();
forage._dbInfo.db = null;
}
}
dbInfo.db = null;
return _getOriginalConnection(dbInfo).then(function(db) {
dbInfo.db = db;
if (_isUpgradeNeeded(dbInfo)) return _getUpgradedConnection(dbInfo);
return db;
}).then(function(db) {
dbInfo.db = dbContext.db = db;
for (var i = 0; i < forages.length; i++) forages[i]._dbInfo.db = db;
})["catch"](function(err) {
_rejectReadiness(dbInfo, err);
throw err;
});
}
function createTransaction(dbInfo, mode, callback, retries) {
if (retries === void 0) retries = 1;
try {
callback(null, dbInfo.db.transaction(dbInfo.storeName, mode));
} catch (err) {
if (retries > 0 && (!dbInfo.db || err.name === "InvalidStateError" || err.name === "NotFoundError")) return Promise$1.resolve().then(function() {
if (!dbInfo.db || err.name === "NotFoundError" && !dbInfo.db.objectStoreNames.contains(dbInfo.storeName) && dbInfo.version <= dbInfo.db.version) {
if (dbInfo.db) dbInfo.version = dbInfo.db.version + 1;
return _getUpgradedConnection(dbInfo);
}
}).then(function() {
return _tryReconnect(dbInfo).then(function() {
createTransaction(dbInfo, mode, callback, retries - 1);
});
})["catch"](callback);
callback(err);
}
}
function createDbContext() {
return {
forages: [],
db: null,
dbReady: null,
deferredOperations: []
};
}
function _initStorage(options) {
var self = this;
var dbInfo = { db: null };
if (options) for (var i in options) dbInfo[i] = options[i];
var dbContext = dbContexts[dbInfo.name];
if (!dbContext) {
dbContext = createDbContext();
dbContexts[dbInfo.name] = dbContext;
}
dbContext.forages.push(self);
if (!self._initReady) {
self._initReady = self.ready;
self.ready = _fullyReady;
}
var initPromises = [];
function ignoreErrors() {
return Promise$1.resolve();
}
for (var j = 0; j < dbContext.forages.length; j++) {
var forage = dbContext.forages[j];
if (forage !== self) initPromises.push(forage._initReady()["catch"](ignoreErrors));
}
var forages = dbContext.forages.slice(0);
return Promise$1.all(initPromises).then(function() {
dbInfo.db = dbContext.db;
return _getOriginalConnection(dbInfo);
}).then(function(db) {
dbInfo.db = db;
if (_isUpgradeNeeded(dbInfo, self._defaultConfig.version)) return _getUpgradedConnection(dbInfo);
return db;
}).then(function(db) {
dbInfo.db = dbContext.db = db;
self._dbInfo = dbInfo;
for (var k = 0; k < forages.length; k++) {
var forage = forages[k];
if (forage !== self) {
forage._dbInfo.db = dbInfo.db;
forage._dbInfo.version = dbInfo.version;
}
}
});
}
function getItem(key, callback) {
var self = this;
key = normalizeKey(key);
var promise = new Promise$1(function(resolve, reject) {
self.ready().then(function() {
createTransaction(self._dbInfo, READ_ONLY, function(err, transaction) {
if (err) return reject(err);
try {
var req = transaction.objectStore(self._dbInfo.storeName).get(key);
req.onsuccess = function() {
var value = req.result;
if (value === void 0) value = null;
if (_isEncodedBlob(value)) value = _decodeBlob(value);
resolve(value);
};
req.onerror = function() {
reject(req.error);
};
} catch (e) {
reject(e);
}
});
})["catch"](reject);
});
executeCallback(promise, callback);
return promise;
}
function iterate(iterator, callback) {
var self = this;
var promise = new Promise$1(function(resolve, reject) {
self.ready().then(function() {
createTransaction(self._dbInfo, READ_ONLY, function(err, transaction) {
if (err) return reject(err);
try {
var req = transaction.objectStore(self._dbInfo.storeName).openCursor();
var iterationNumber = 1;
req.onsuccess = function() {
var cursor = req.result;
if (cursor) {
var value = cursor.value;
if (_isEncodedBlob(value)) value = _decodeBlob(value);
var result = iterator(value, cursor.key, iterationNumber++);
if (result !== void 0) resolve(result);
else cursor["continue"]();
} else resolve();
};
req.onerror = function() {
reject(req.error);
};
} catch (e) {
reject(e);
}
});
})["catch"](reject);
});
executeCallback(promise, callback);
return promise;
}
function setItem(key, value, callback) {
var self = this;
key = normalizeKey(key);
var promise = new Promise$1(function(resolve, reject) {
var dbInfo;
self.ready().then(function() {
dbInfo = self._dbInfo;
if (toString.call(value) === "[object Blob]") return _checkBlobSupport(dbInfo.db).then(function(blobSupport) {
if (blobSupport) return value;
return _encodeBlob(value);
});
return value;
}).then(function(value) {
createTransaction(self._dbInfo, READ_WRITE, function(err, transaction) {
if (err) return reject(err);
try {
var store = transaction.objectStore(self._dbInfo.storeName);
if (value === null) value = void 0;
var req = store.put(value, key);
transaction.oncomplete = function() {
if (value === void 0) value = null;
resolve(value);
};
transaction.onabort = transaction.onerror = function() {
reject(req.error ? req.error : req.transaction.error);
};
} catch (e) {
reject(e);
}
});
})["catch"](reject);
});
executeCallback(promise, callback);
return promise;
}
function removeItem(key, callback) {
var self = this;
key = normalizeKey(key);
var promise = new Promise$1(function(resolve, reject) {
self.ready().then(function() {
createTransaction(self._dbInfo, READ_WRITE, function(err, transaction) {
if (err) return reject(err);
try {
var req = transaction.objectStore(self._dbInfo.storeName)["delete"](key);
transaction.oncomplete = function() {
resolve();
};
transaction.onerror = function() {
reject(req.error);
};
transaction.onabort = function() {
reject(req.error ? req.error : req.transaction.error);
};
} catch (e) {
reject(e);
}
});
})["catch"](reject);
});
executeCallback(promise, callback);
return promise;
}
function clear(callback) {
var self = this;
var promise = new Promise$1(function(resolve, reject) {
self.ready().then(function() {
createTransaction(self._dbInfo, READ_WRITE, function(err, transaction) {
if (err) return reject(err);
try {
var req = transaction.objectStore(self._dbInfo.storeName).clear();
transaction.oncomplete = function() {
resolve();
};
transaction.onabort = transaction.onerror = function() {
reject(req.error ? req.error : req.transaction.error);
};
} catch (e) {
reject(e);
}
});
})["catch"](reject);
});
executeCallback(promise, callback);
return promise;
}
function length(callback) {
var self = this;
var promise = new Promise$1(function(resolve, reject) {
self.ready().then(function() {
createTransaction(self._dbInfo, READ_ONLY, function(err, transaction) {
if (err) return reject(err);
try {
var req = transaction.objectStore(self._dbInfo.storeName).count();
req.onsuccess = function() {
resolve(req.result);
};
req.onerror = function() {
reject(req.error);
};
} catch (e) {
reject(e);
}
});
})["catch"](reject);
});
executeCallback(promise, callback);
return promise;
}
function key(n, callback) {
var self = this;
var promise = new Promise$1(function(resolve, reject) {
if (n < 0) {
resolve(null);
return;
}
self.ready().then(function() {
createTransaction(self._dbInfo, READ_ONLY, function(err, transaction) {
if (err) return reject(err);
try {
var store = transaction.objectStore(self._dbInfo.storeName);
var advanced = false;
var req = store.openKeyCursor();
req.onsuccess = function() {
var cursor = req.result;
if (!cursor) {
resolve(null);
return;
}
if (n === 0) resolve(cursor.key);
else if (!advanced) {
advanced = true;
cursor.advance(n);
} else resolve(cursor.key);
};
req.onerror = function() {
reject(req.error);
};
} catch (e) {
reject(e);
}
});
})["catch"](reject);
});
executeCallback(promise, callback);
return promise;
}
function keys(callback) {
var self = this;
var promise = new Promise$1(function(resolve, reject) {
self.ready().then(function() {
createTransaction(self._dbInfo, READ_ONLY, function(err, transaction) {
if (err) return reject(err);
try {
var req = transaction.objectStore(self._dbInfo.storeName).openKeyCursor();
var keys = [];
req.onsuccess = function() {
var cursor = req.result;
if (!cursor) {
resolve(keys);
return;
}
keys.push(cursor.key);
cursor["continue"]();
};
req.onerror = function() {
reject(req.error);
};
} catch (e) {
reject(e);
}
});
})["catch"](reject);
});
executeCallback(promise, callback);
return promise;
}
function dropInstance(options, callback) {
callback = getCallback.apply(this, arguments);
var currentConfig = this.config();
options = typeof options !== "function" && options || {};
if (!options.name) {
options.name = options.name || currentConfig.name;
options.storeName = options.storeName || currentConfig.storeName;
}
var self = this;
var promise;
if (!options.name) promise = Promise$1.reject("Invalid arguments");
else {
var dbPromise = options.name === currentConfig.name && self._dbInfo.db ? Promise$1.resolve(self._dbInfo.db) : _getOriginalConnection(options).then(function(db) {
var dbContext = dbContexts[options.name];
var forages = dbContext.forages;
dbContext.db = db;
for (var i = 0; i < forages.length; i++) forages[i]._dbInfo.db = db;
return db;
});
if (!options.storeName) promise = dbPromise.then(function(db) {
_deferReadiness(options);
var dbContext = dbContexts[options.name];
var forages = dbContext.forages;
db.close();
for (var i = 0; i < forages.length; i++) {
var forage = forages[i];
forage._dbInfo.db = null;
}
return new Promise$1(function(resolve, reject) {
var req = idb.deleteDatabase(options.name);
req.onerror = function() {
var db = req.result;
if (db) db.close();
reject(req.error);
};
req.onblocked = function() {
console.warn("dropInstance blocked for database \"" + options.name + "\" until all open connections are closed");
};
req.onsuccess = function() {
var db = req.result;
if (db) db.close();
resolve(db);
};
}).then(function(db) {
dbContext.db = db;
for (var i = 0; i < forages.length; i++) {
var _forage = forages[i];
_advanceReadiness(_forage._dbInfo);
}
})["catch"](function(err) {
(_rejectReadiness(options, err) || Promise$1.resolve())["catch"](function() {});
throw err;
});
});
else promise = dbPromise.then(function(db) {
if (!db.objectStoreNames.contains(options.storeName)) return;
var newVersion = db.version + 1;
_deferReadiness(options);
var dbContext = dbContexts[options.name];
var forages = dbContext.forages;
db.close();
for (var i = 0; i < forages.length; i++) {
var forage = forages[i];
forage._dbInfo.db = null;
forage._dbInfo.version = newVersion;
}
return new Promise$1(function(resolve, reject) {
var req = idb.open(options.name, newVersion);
req.onerror = function(err) {
req.result.close();
reject(err);
};
req.onupgradeneeded = function() {
req.result.deleteObjectStore(options.storeName);
};
req.onsuccess = function() {
var db = req.result;
db.close();
resolve(db);
};
}).then(function(db) {
dbContext.db = db;
for (var j = 0; j < forages.length; j++) {
var _forage2 = forages[j];
_forage2._dbInfo.db = db;
_advanceReadiness(_forage2._dbInfo);
}
})["catch"](function(err) {
(_rejectReadiness(options, err) || Promise$1.resolve())["catch"](function() {});
throw err;
});
});
}
executeCallback(promise, callback);
return promise;
}
var asyncStorage = {
_driver: "asyncStorage",
_initStorage,
_support: isIndexedDBValid(),
iterate,
getItem,
setItem,
removeItem,
clear,
length,
key,
keys,
dropInstance
};
function isWebSQLValid() {
return typeof openDatabase === "function";
}
var BASE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var BLOB_TYPE_PREFIX = "~~local_forage_type~";
var BLOB_TYPE_PREFIX_REGEX = /^~~local_forage_type~([^~]+)~/;
var SERIALIZED_MARKER = "__lfsc__:";
var SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER.length;
var TYPE_ARRAYBUFFER = "arbf";
var TYPE_BLOB = "blob";
var TYPE_INT8ARRAY = "si08";
var TYPE_UINT8ARRAY = "ui08";
var TYPE_UINT8CLAMPEDARRAY = "uic8";
var TYPE_INT16ARRAY = "si16";
var TYPE_INT32ARRAY = "si32";
var TYPE_UINT16ARRAY = "ur16";
var TYPE_UINT32ARRAY = "ui32";
var TYPE_FLOAT32ARRAY = "fl32";
var TYPE_FLOAT64ARRAY = "fl64";
var TYPE_SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER_LENGTH + TYPE_ARRAYBUFFER.length;
var toString$1 = Object.prototype.toString;
function stringToBuffer(serializedString) {
var bufferLength = serializedString.length * .75;
var len = serializedString.length;
var i;
var p = 0;
var encoded1, encoded2, encoded3, encoded4;
if (serializedString[serializedString.length - 1] === "=") {
bufferLength--;
if (serializedString[serializedString.length - 2] === "=") bufferLength--;
}
var buffer = new ArrayBuffer(bufferLength);
var bytes = new Uint8Array(buffer);
for (i = 0; i < len; i += 4) {
encoded1 = BASE_CHARS.indexOf(serializedString[i]);
encoded2 = BASE_CHARS.indexOf(serializedString[i + 1]);
encoded3 = BASE_CHARS.indexOf(serializedString[i + 2]);
encoded4 = BASE_CHARS.indexOf(serializedString[i + 3]);
bytes[p++] = encoded1 << 2 | encoded2 >> 4;
bytes[p++] = (encoded2 & 15) << 4 | encoded3 >> 2;
bytes[p++] = (encoded3 & 3) << 6 | encoded4 & 63;
}
return buffer;
}
function bufferToString(buffer) {
var bytes = new Uint8Array(buffer);
var base64String = "";
var i;
for (i = 0; i < bytes.length; i += 3) {
base64String += BASE_CHARS[bytes[i] >> 2];
base64String += BASE_CHARS[(bytes[i] & 3) << 4 | bytes[i + 1] >> 4];
base64String += BASE_CHARS[(bytes[i + 1] & 15) << 2 | bytes[i + 2] >> 6];
base64String += BASE_CHARS[bytes[i + 2] & 63];
}
if (bytes.length % 3 === 2) base64String = base64String.substring(0, base64String.length - 1) + "=";
else if (bytes.length % 3 === 1) base64String = base64String.substring(0, base64String.length - 2) + "==";
return base64String;
}
function serialize(value, callback) {
var valueType = "";
if (value) valueType = toString$1.call(value);
if (value && (valueType === "[object ArrayBuffer]" || value.buffer && toString$1.call(value.buffer) === "[object ArrayBuffer]")) {
var buffer;
var marker = SERIALIZED_MARKER;
if (value instanceof ArrayBuffer) {
buffer = value;
marker += TYPE_ARRAYBUFFER;
} else {
buffer = value.buffer;
if (valueType === "[object Int8Array]") marker += TYPE_INT8ARRAY;
else if (valueType === "[object Uint8Array]") marker += TYPE_UINT8ARRAY;
else if (valueType === "[object Uint8ClampedArray]") marker += TYPE_UINT8CLAMPEDARRAY;
else if (valueType === "[object Int16Array]") marker += TYPE_INT16ARRAY;
else if (valueType === "[object Uint16Array]") marker += TYPE_UINT16ARRAY;
else if (valueType === "[object Int32Array]") marker += TYPE_INT32ARRAY;
else if (valueType === "[object Uint32Array]") marker += TYPE_UINT32ARRAY;
else if (valueType === "[object Float32Array]") marker += TYPE_FLOAT32ARRAY;
else if (valueType === "[object Float64Array]") marker += TYPE_FLOAT64ARRAY;
else callback(new Error("Failed to get type for BinaryArray"));
}
callback(marker + bufferToString(buffer));
} else if (valueType === "[object Blob]") {
var fileReader = new FileReader();
fileReader.onload = function() {
var str = BLOB_TYPE_PREFIX + value.type + "~" + bufferToString(this.result);
callback(SERIALIZED_MARKER + TYPE_BLOB + str);
};
fileReader.readAsArrayBuffer(value);
} else try {
callback(JSON.stringify(value));
} catch (e) {
console.error("Couldn't convert value into a JSON string: ", value);
callback(null, e);
}
}
function deserialize(value) {
if (value.substring(0, SERIALIZED_MARKER_LENGTH) !== SERIALIZED_MARKER) return JSON.parse(value);
var serializedString = value.substring(TYPE_SERIALIZED_MARKER_LENGTH);
var type = value.substring(SERIALIZED_MARKER_LENGTH, TYPE_SERIALIZED_MARKER_LENGTH);
var blobType;
if (type === TYPE_BLOB && BLOB_TYPE_PREFIX_REGEX.test(serializedString)) {
var matcher = serializedString.match(BLOB_TYPE_PREFIX_REGEX);
blobType = matcher[1];
serializedString = serializedString.substring(matcher[0].length);
}
var buffer = stringToBuffer(serializedString);
switch (type) {
case TYPE_ARRAYBUFFER: return buffer;
case TYPE_BLOB: return createBlob([buffer], { type: blobType });
case TYPE_INT8ARRAY: return new Int8Array(buffer);
case TYPE_UINT8ARRAY: return new Uint8Array(buffer);
case TYPE_UINT8CLAMPEDARRAY: return new Uint8ClampedArray(buffer);
case TYPE_INT16ARRAY: return new Int16Array(buffer);
case TYPE_UINT16ARRAY: return new Uint16Array(buffer);
case TYPE_INT32ARRAY: return new Int32Array(buffer);
case TYPE_UINT32ARRAY: return new Uint32Array(buffer);
case TYPE_FLOAT32ARRAY: return new Float32Array(buffer);
case TYPE_FLOAT64ARRAY: return new Float64Array(buffer);
default: throw new Error("Unkown type: " + type);
}
}
var localforageSerializer = {
serialize,
deserialize,
stringToBuffer,
bufferToString
};
function createDbTable(t, dbInfo, callback, errorCallback) {
t.executeSql("CREATE TABLE IF NOT EXISTS " + dbInfo.storeName + " (id INTEGER PRIMARY KEY, key unique, value)", [], callback, errorCallback);
}
function _initStorage$1(options) {
var self = this;
var dbInfo = { db: null };
if (options) for (var i in options) dbInfo[i] = typeof options[i] !== "string" ? options[i].toString() : options[i];
var dbInfoPromise = new Promise$1(function(resolve, reject) {
try {
dbInfo.db = openDatabase(dbInfo.name, String(dbInfo.version), dbInfo.description, dbInfo.size);
} catch (e) {
return reject(e);
}
dbInfo.db.transaction(function(t) {
createDbTable(t, dbInfo, function() {
self._dbInfo = dbInfo;
resolve();
}, function(t, error) {
reject(error);
});
}, reject);
});
dbInfo.serializer = localforageSerializer;
return dbInfoPromise;
}
function tryExecuteSql(t, dbInfo, sqlStatement, args, callback, errorCallback) {
t.executeSql(sqlStatement, args, callback, function(t, error) {
if (error.code === error.SYNTAX_ERR) t.executeSql("SELECT name FROM sqlite_master WHERE type='table' AND name = ?", [dbInfo.storeName], function(t, results) {
if (!results.rows.length) createDbTable(t, dbInfo, function() {
t.executeSql(sqlStatement, args, callback, errorCallback);
}, errorCallback);
else errorCallback(t, error);
}, errorCallback);
else errorCallback(t, error);
}, errorCallback);
}
function getItem$1(key, callback) {
var self = this;
key = normalizeKey(key);
var promise = new Promise$1(function(resolve, reject) {
self.ready().then(function() {
var dbInfo = self._dbInfo;
dbInfo.db.transaction(function(t) {
tryExecuteSql(t, dbInfo, "SELECT * FROM " + dbInfo.storeName + " WHERE key = ? LIMIT 1", [key], function(t, results) {
var result = results.rows.length ? results.rows.item(0).value : null;
if (result) result = dbInfo.serializer.deserialize(result);
resolve(result);
}, function(t, error) {
reject(error);
});
});
})["catch"](reject);
});
executeCallback(promise, callback);
return promise;
}
function iterate$1(iterator, callback) {
var self = this;
var promise = new Promise$1(function(resolve, reject) {
self.ready().then(function() {
var dbInfo = self._dbInfo;
dbInfo.db.transaction(function(t) {
tryExecuteSql(t, dbInfo, "SELECT * FROM " + dbInfo.storeName, [], function(t, results) {
var rows = results.rows;
var length = rows.length;
for (var i = 0; i < length; i++) {
var item = rows.item(i);
var result = item.value;
if (result) result = dbInfo.serializer.deserialize(result);
result = iterator(result, item.key, i + 1);
if (result !== void 0) {
resolve(result);
return;
}
}
resolve();
}, function(t, error) {
reject(error);
});
});
})["catch"](reject);
});
executeCallback(promise, callback);
return promise;
}
function _setItem(key, value, callback, retriesLeft) {
var self = this;
key = normalizeKey(key);
var promise = new Promise$1(function(resolve, reject) {
self.ready().then(function() {
if (value === void 0) value = null;
var originalValue = value;
var dbInfo = self._dbInfo;
dbInfo.serializer.serialize(value, function(value, error) {
if (error) reject(error);
else dbInfo.db.transaction(function(t) {
tryExecuteSql(t, dbInfo, "INSERT OR REPLACE INTO " + dbInfo.storeName + " (key, value) VALUES (?, ?)", [key, value], function() {
resolve(originalValue);
}, function(t, error) {
reject(error);
});
}, function(sqlError) {
if (sqlError.code === sqlError.QUOTA_ERR) {
if (retriesLeft > 0) {
resolve(_setItem.apply(self, [
key,
originalValue,
callback,
retriesLeft - 1
]));
return;
}
reject(sqlError);
}
});
});
})["catch"](reject);
});
executeCallback(promise, callback);
return promise;
}
function setItem$1(key, value, callback) {
return _setItem.apply(this, [
key,
value,
callback,
1
]);
}
function removeItem$1(key, callback) {
var self = this;
key = normalizeKey(key);
var promise = new Promise$1(function(resolve, reject) {
self.ready().then(function() {
var dbInfo = self._dbInfo;
dbInfo.db.transaction(function(t) {
tryExecuteSql(t, dbInfo, "DELETE FROM " + dbInfo.storeName + " WHERE key = ?", [key], function() {
resolve();
}, function(t, error) {
reject(error);
});
});
})["catch"](reject);
});
executeCallback(promise, callback);
return promise;
}
function clear$1(callback) {
var self = this;
var promise = new Promise$1(function(resolve, reject) {
self.ready().then(function() {
var dbInfo = self._dbInfo;
dbInfo.db.transaction(function(t) {
tryExecuteSql(t, dbInfo, "DELETE FROM " + dbInfo.storeName, [], function() {
resolve();
}, function(t, error) {
reject(error);
});
});
})["catch"](reject);
});
executeCallback(promise, callback);
return promise;
}
function length$1(callback) {
var self = this;
var promise = new Promise$1(function(resolve, reject) {
self.ready().then(function() {
var dbInfo = self._dbInfo;
dbInfo.db.transaction(function(t) {
tryExecuteSql(t, dbInfo, "SELECT COUNT(key) as c FROM " + dbInfo.storeName, [], function(t, results) {
var result = results.rows.item(0).c;
resolve(result);
}, function(t, error) {
reject(error);
});
});
})["catch"](reject);
});
executeCallback(promise, callback);
return promise;
}
function key$1(n, callback) {
var self = this;
var promise = new Promise$1(function(resolve, reject) {
self.ready().then(function() {
var dbInfo = self._dbInfo;
dbInfo.db.transaction(function(t) {
tryExecuteSql(t, dbInfo, "SELECT key FROM " + dbInfo.storeName + " WHERE id = ? LIMIT 1", [n + 1], function(t, results) {
resolve(results.rows.length ? results.rows.item(0).key : null);
}, function(t, error) {
reject(error);
});
});
})["catch"](reject);
});
executeCallback(promise, callback);
return promise;
}
function keys$1(callback) {
var self = this;
var promise = new Promise$1(function(resolve, reject) {
self.ready().then(function() {
var dbInfo = self._dbInfo;
dbInfo.db.transaction(function(t) {
tryExecuteSql(t, dbInfo, "SELECT key FROM " + dbInfo.storeName, [], function(t, results) {
var keys = [];
for (var i = 0; i < results.rows.length; i++) keys.push(results.rows.item(i).key);
resolve(keys);
}, function(t, error) {
reject(error);
});
});
})["catch"](reject);
});
executeCallback(promise, callback);
return promise;
}
function getAllStoreNames(db) {
return new Promise$1(function(resolve, reject) {
db.transaction(function(t) {
t.executeSql("SELECT name FROM sqlite_master WHERE type='table' AND name <> '__WebKitDatabaseInfoTable__'", [], function(t, results) {
var storeNames = [];
for (var i = 0; i < results.rows.length; i++) storeNames.push(results.rows.item(i).name);
resolve({
db,
storeNames
});
}, function(t, error) {
reject(error);
});
}, function(sqlError) {
reject(sqlError);
});
});
}
function dropInstance$1(options, callback) {
callback = getCallback.apply(this, arguments);
var currentConfig = this.config();
options = typeof options !== "function" && options || {};
if (!options.name) {
options.name = options.name || currentConfig.name;
options.storeName = options.storeName || currentConfig.storeName;
}
var self = this;
var promise;
if (!options.name) promise = Promise$1.reject("Invalid arguments");
else promise = new Promise$1(function(resolve) {
var db;
if (options.name === currentConfig.name) db = self._dbInfo.db;
else db = openDatabase(options.name, "", "", 0);
if (!options.storeName) resolve(getAllStoreNames(db));
else resolve({
db,
storeNames: [options.storeName]
});
}).then(function(operationInfo) {
return new Promise$1(function(resolve, reject) {
operationInfo.db.transaction(function(t) {
function dropTable(storeName) {
return new Promise$1(function(resolve, reject) {
t.executeSql("DROP TABLE IF EXISTS " + storeName, [], function() {
resolve();
}, function(t, error) {
reject(error);
});
});
}
var operations = [];
for (var i = 0, len = operationInfo.storeNames.length; i < len; i++) operations.push(dropTable(operationInfo.storeNames[i]));
Promise$1.all(operations).then(function() {
resolve();
})["catch"](function(e) {
reject(e);
});
}, function(sqlError) {
reject(sqlError);
});
});
});
executeCallback(promise, callback);
return promise;
}
var webSQLStorage = {
_driver: "webSQLStorage",
_initStorage: _initStorage$1,
_support: isWebSQLValid(),
iterate: iterate$1,
getItem: getItem$1,
setItem: setItem$1,
removeItem: removeItem$1,
clear: clear$1,
length: length$1,
key: key$1,
keys: keys$1,
dropInstance: dropInstance$1
};
function isLocalStorageValid() {
try {
return typeof localStorage !== "undefined" && "setItem" in localStorage && !!localStorage.setItem;
} catch (e) {
return false;
}
}
function _getKeyPrefix(options, defaultConfig) {
var keyPrefix = options.name + "/";
if (options.storeName !== defaultConfig.storeName) keyPrefix += options.storeName + "/";
return keyPrefix;
}
function checkIfLocalStorageThrows() {
var localStorageTestKey = "_localforage_support_test";
try {
localStorage.setItem(localStorageTestKey, true);
localStorage.removeItem(localStorageTestKey);
return false;
} catch (e) {
return true;
}
}
function _isLocalStorageUsable() {
return !checkIfLocalStorageThrows() || localStorage.length > 0;
}
function _initStorage$2(options) {
var self = this;
var dbInfo = {};
if (options) for (var i in options) dbInfo[i] = options[i];
dbInfo.keyPrefix = _getKeyPrefix(options, self._defaultConfig);
if (!_isLocalStorageUsable()) return Promise$1.reject();
self._dbInfo = dbInfo;
dbInfo.serializer = localforageSerializer;
return Promise$1.resolve();
}
function clear$2(callback) {
var self = this;
var promise = self.ready().then(function() {
var keyPrefix = self._dbInfo.keyPrefix;
for (var i = localStorage.length - 1; i >= 0; i--) {
var key = localStorage.key(i);
if (key.indexOf(keyPrefix) === 0) localStorage.removeItem(key);
}
});
executeCallback(promise, callback);
return promise;
}
function getItem$2(key, callback) {
var self = this;
key = normalizeKey(key);
var promise = self.ready().then(function() {
var dbInfo = self._dbInfo;
var result = localStorage.getItem(dbInfo.keyPrefix + key);
if (result) result = dbInfo.serializer.deserialize(result);
return result;
});
executeCallback(promise, callback);
return promise;
}
function iterate$2(iterator, callback) {
var self = this;
var promise = self.ready().then(function() {
var dbInfo = self._dbInfo;
var keyPrefix = dbInfo.keyPrefix;
var keyPrefixLength = keyPrefix.length;
var length = localStorage.length;
var iterationNumber = 1;
for (var i = 0; i < length; i++) {
var key = localStorage.key(i);
if (key.indexOf(keyPrefix) !== 0) continue;
var value = localStorage.getItem(key);
if (value) value = dbInfo.serializer.deserialize(value);
value = iterator(value, key.substring(keyPrefixLength), iterationNumber++);
if (value !== void 0) return value;
}
});
executeCallback(promise, callback);
return promise;
}
function key$2(n, callback) {
var self = this;
var promise = self.ready().then(function() {
var dbInfo = self._dbInfo;
var result;
try {
result = localStorage.key(n);
} catch (error) {
result = null;
}
if (result) result = result.substring(dbInfo.keyPrefix.length);
return result;
});
executeCallback(promise, callback);
return promise;
}
function keys$2(callback) {
var self = this;
var promise = self.ready().then(function() {
var dbInfo = self._dbInfo;
var length = localStorage.length;
var keys = [];
for (var i = 0; i < length; i++) {
var itemKey = localStorage.key(i);
if (itemKey.indexOf(dbInfo.keyPrefix) === 0) keys.push(itemKey.substring(dbInfo.keyPrefix.length));
}
return keys;
});
executeCallback(promise, callback);
return promise;
}
function length$2(callback) {
var promise = this.keys().then(function(keys) {
return keys.length;
});
executeCallback(promise, callback);
return promise;
}
function removeItem$2(key, callback) {
var self = this;
key = normalizeKey(key);
var promise = self.ready().then(function() {
var dbInfo = self._dbInfo;
localStorage.removeItem(dbInfo.keyPrefix + key);
});
executeCallback(promise, callback);
return promise;
}
function setItem$2(key, value, callback) {
var self = this;
key = normalizeKey(key);
var promise = self.ready().then(function() {
if (value === void 0) value = null;
var originalValue = value;
return new Promise$1(function(resolve, reject) {
var dbInfo = self._dbInfo;
dbInfo.serializer.serialize(value, function(value, error) {
if (error) reject(error);
else try {
localStorage.setItem(dbInfo.keyPrefix + key, value);
resolve(originalValue);
} catch (e) {
if (e.name === "QuotaExceededError" || e.name === "NS_ERROR_DOM_QUOTA_REACHED") reject(e);
reject(e);
}
});
});
});
executeCallback(promise, callback);
return promise;
}
function dropInstance$2(options, callback) {
callback = getCallback.apply(this, arguments);
options = typeof options !== "function" && options || {};
if (!options.name) {
var currentConfig = this.config();
options.name = options.name || currentConfig.name;
options.storeName = options.storeName || currentConfig.storeName;
}
var self = this;
var promise;
if (!options.name) promise = Promise$1.reject("Invalid arguments");
else promise = new Promise$1(function(resolve) {
if (!options.storeName) resolve(options.name + "/");
else resolve(_getKeyPrefix(options, self._defaultConfig));
}).then(function(keyPrefix) {
for (var i = localStorage.length - 1; i >= 0; i--) {
var key = localStorage.key(i);
if (key.indexOf(keyPrefix) === 0) localStorage.removeItem(key);
}
});
executeCallback(promise, callback);
return promise;
}
var localStorageWrapper = {
_driver: "localStorageWrapper",
_initStorage: _initStorage$2,
_support: isLocalStorageValid(),
iterate: iterate$2,
getItem: getItem$2,
setItem: setItem$2,
removeItem: removeItem$2,
clear: clear$2,
length: length$2,
key: key$2,
keys: keys$2,
dropInstance: dropInstance$2
};
var sameValue = function sameValue(x, y) {
return x === y || typeof x === "number" && typeof y === "number" && isNaN(x) && isNaN(y);
};
var includes = function includes(array, searchElement) {
var len = array.length;
var i = 0;
while (i < len) {
if (sameValue(array[i], searchElement)) return true;
i++;
}
return false;
};
var isArray = Array.isArray || function(arg) {
return Object.prototype.toString.call(arg) === "[object Array]";
};
var DefinedDrivers = {};
var DriverSupport = {};
var DefaultDrivers = {
INDEXEDDB: asyncStorage,
WEBSQL: webSQLStorage,
LOCALSTORAGE: localStorageWrapper
};
var DefaultDriverOrder = [
DefaultDrivers.INDEXEDDB._driver,
DefaultDrivers.WEBSQL._driver,
DefaultDrivers.LOCALSTORAGE._driver
];
var OptionalDriverMethods = ["dropInstance"];
var LibraryMethods = [
"clear",
"getItem",
"iterate",
"key",
"keys",
"length",
"removeItem",
"setItem"
].concat(OptionalDriverMethods);
var DefaultConfig = {
description: "",
driver: DefaultDriverOrder.slice(),
name: "localforage",
size: 4980736,
storeName: "keyvaluepairs",
version: 1
};
function callWhenReady(localForageInstance, libraryMethod) {
localForageInstance[libraryMethod] = function() {
var _args = arguments;
return localForageInstance.ready().then(function() {
return localForageInstance[libraryMethod].apply(localForageInstance, _args);
});
};
}
function extend() {
for (var i = 1; i < arguments.length; i++) {
var arg = arguments[i];
if (arg) {
for (var _key in arg) if (arg.hasOwnProperty(_key)) if (isArray(arg[_key])) arguments[0][_key] = arg[_key].slice();
else arguments[0][_key] = arg[_key];
}
}
return arguments[0];
}
module$4.exports = new (function() {
function LocalForage(options) {
_classCallCheck(this, LocalForage);
for (var driverTypeKey in DefaultDrivers) if (DefaultDrivers.hasOwnProperty(driverTypeKey)) {
var driver = DefaultDrivers[driverTypeKey];
var driverName = driver._driver;
this[driverTypeKey] = driverName;
if (!DefinedDrivers[driverName]) this.defineDriver(driver);
}
this._defaultConfig = extend({}, DefaultConfig);
this._config = extend({}, this._defaultConfig, options);
this._driverSet = null;
this._initDriver = null;
this._ready = false;
this._dbInfo = null;
this._wrapLibraryMethodsWithReady();
this.setDriver(this._config.driver)["catch"](function() {});
}
LocalForage.prototype.config = function config(options) {
if ((typeof options === "undefined" ? "undefined" : _typeof(options)) === "object") {
if (this._ready) return new Error("Can't call config() after localforage has been used.");
for (var i in options) {
if (i === "storeName") options[i] = options[i].replace(/\W/g, "_");
if (i === "version" && typeof options[i] !== "number") return new Error("Database version must be a number.");
this._config[i] = options[i];
}
if ("driver" in options && options.driver) return this.setDriver(this._config.driver);
return true;
} else if (typeof options === "string") return this._config[options];
else return this._config;
};
LocalForage.prototype.defineDriver = function defineDriver(driverObject, callback, errorCallback) {
var promise = new Promise$1(function(resolve, reject) {
try {
var driverName = driverObject._driver;
var complianceError = new Error("Custom driver not compliant; see https://mozilla.github.io/localForage/#definedriver");
if (!driverObject._driver) {
reject(complianceError);
return;
}
var driverMethods = LibraryMethods.concat("_initStorage");
for (var i = 0, len = driverMethods.length; i < len; i++) {
var driverMethodName = driverMethods[i];
if ((!includes(OptionalDriverMethods, driverMethodName) || driverObject[driverMethodName]) && typeof driverObject[driverMethodName] !== "function") {
reject(complianceError);
return;
}
}
(function configureMissingMethods() {
var methodNotImplementedFactory = function methodNotImplementedFactory(methodName) {
return function() {
var error = new Error("Method " + methodName + " is not implemented by the current driver");
var promise = Promise$1.reject(error);
executeCallback(promise, arguments[arguments.length - 1]);
return promise;
};
};
for (var _i = 0, _len = OptionalDriverMethods.length; _i < _len; _i++) {
var optionalDriverMethod = OptionalDriverMethods[_i];
if (!driverObject[optionalDriverMethod]) driverObject[optionalDriverMethod] = methodNotImplementedFactory(optionalDriverMethod);
}
})();
var setDriverSupport = function setDriverSupport(support) {
if (DefinedDrivers[driverName]) console.info("Redefining LocalForage driver: " + driverName);
DefinedDrivers[driverName] = driverObject;
DriverSupport[driverName] = support;
resolve();
};
if ("_support" in driverObject) if (driverObject._support && typeof driverObject._support === "function") driverObject._support().then(setDriverSupport, reject);
else setDriverSupport(!!driverObject._support);
else setDriverSupport(true);
} catch (e) {
reject(e);
}
});
executeTwoCallbacks(promise, callback, errorCallback);
return promise;
};
LocalForage.prototype.driver = function driver() {
return this._driver || null;
};
LocalForage.prototype.getDriver = function getDriver(driverName, callback, errorCallback) {
var getDriverPromise = DefinedDrivers[driverName] ? Promise$1.resolve(DefinedDrivers[driverName]) : Promise$1.reject(new Error("Driver not found."));
executeTwoCallbacks(getDriverPromise, callback, errorCallback);
return getDriverPromise;
};
LocalForage.prototype.getSerializer = function getSerializer(callback) {
var serializerPromise = Promise$1.resolve(localforageSerializer);
executeTwoCallbacks(serializerPromise, callback);
return serializerPromise;
};
LocalForage.prototype.ready = function ready(callback) {
var self = this;
var promise = self._driverSet.then(function() {
if (self._ready === null) self._ready = self._initDriver();
return self._ready;
});
executeTwoCallbacks(promise, callback, callback);
return promise;
};
LocalForage.prototype.setDriver = function setDriver(drivers, callback, errorCallback) {
var self = this;
if (!isArray(drivers)) drivers = [drivers];
var supportedDrivers = this._getSupportedDrivers(drivers);
function setDriverToConfig() {
self._config.driver = self.driver();
}
function extendSelfWithDriver(driver) {
self._extend(driver);
setDriverToConfig();
self._ready = self._initStorage(self._config);
return self._ready;
}
function initDriver(supportedDrivers) {
return function() {
var currentDriverIndex = 0;
function driverPromiseLoop() {
while (currentDriverIndex < supportedDrivers.length) {
var driverName = supportedDrivers[currentDriverIndex];
currentDriverIndex++;
self._dbInfo = null;
self._ready = null;
return self.getDriver(driverName).then(extendSelfWithDriver)["catch"](driverPromiseLoop);
}
setDriverToConfig();
var error = new Error("No available storage method found.");
self._driverSet = Promise$1.reject(error);
return self._driverSet;
}
return driverPromiseLoop();
};
}
var oldDriverSetDone = this._driverSet !== null ? this._driverSet["catch"](function() {
return Promise$1.resolve();
}) : Promise$1.resolve();
this._driverSet = oldDriverSetDone.then(function() {
var driverName = supportedDrivers[0];
self._dbInfo = null;
self._ready = null;
return self.getDriver(driverName).then(function(driver) {
self._driver = driver._driver;
setDriverToConfig();
self._wrapLibraryMethodsWithReady();
self._initDriver = initDriver(supportedDrivers);
});
})["catch"](function() {
setDriverToConfig();
var error = new Error("No available storage method found.");
self._driverSet = Promise$1.reject(error);
return self._driverSet;
});
executeTwoCallbacks(this._driverSet, callback, errorCallback);
return this._driverSet;
};
LocalForage.prototype.supports = function supports(driverName) {
return !!DriverSupport[driverName];
};
LocalForage.prototype._extend = function _extend(libraryMethodsAndProperties) {
extend(this, libraryMethodsAndProperties);
};
LocalForage.prototype._getSupportedDrivers = function _getSupportedDrivers(drivers) {
var supportedDrivers = [];
for (var i = 0, len = drivers.length; i < len; i++) {
var driverName = drivers[i];
if (this.supports(driverName)) supportedDrivers.push(driverName);
}
return supportedDrivers;
};
LocalForage.prototype._wrapLibraryMethodsWithReady = function _wrapLibraryMethodsWithReady() {
for (var i = 0, len = LibraryMethods.length; i < len; i++) callWhenReady(this, LibraryMethods[i]);
};
LocalForage.prototype.createInstance = function createInstance(options) {
return new LocalForage(options);
};
return LocalForage;
}())();
}, { "3": 3 }]
}, {}, [4])(4);
});
}));
var require_viewer = __commonJSMin(((exports, module) => {
(function(global, factory) {
typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define(factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, global.Viewer = factory());
})(exports, (function() {
"use strict";
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
enumerableOnly && (symbols = symbols.filter(function(sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
})), keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread2(target) {
for (var i = 1; i < arguments.length; i++) {
var source = null != arguments[i] ? arguments[i] : {};
i % 2 ? ownKeys(Object(source), !0).forEach(function(key) {
_defineProperty(target, key, source[key]);
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function(key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
return target;
}
function _typeof(obj) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(obj) {
return typeof obj;
} : function(obj) {
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
}, _typeof(obj);
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function");
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
Object.defineProperty(Constructor, "prototype", { writable: false });
return Constructor;
}
function _defineProperty(obj, key, value) {
if (key in obj) Object.defineProperty(obj, key, {
value,
enumerable: true,
configurable: true,
writable: true
});
else obj[key] = value;
return obj;
}
var DEFAULTS = {
backdrop: true,
button: true,
navbar: true,
title: true,
toolbar: true,
className: "",
container: "body",
filter: null,
fullscreen: true,
inheritedAttributes: [
"crossOrigin",
"decoding",
"isMap",
"loading",
"referrerPolicy",
"sizes",
"srcset",
"useMap"
],
initialCoverage: .9,
initialViewIndex: 0,
inline: false,
interval: 5e3,
keyboard: true,
focus: true,
loading: true,
loop: true,
minWidth: 200,
minHeight: 100,
movable: true,
rotatable: true,
scalable: true,
zoomable: true,
zoomOnTouch: true,
zoomOnWheel: true,
slideOnTouch: true,
toggleOnDblclick: true,
tooltip: true,
transition: true,
zIndex: 2015,
zIndexInline: 0,
zoomRatio: .1,
minZoomRatio: .01,
maxZoomRatio: 100,
url: "src",
ready: null,
show: null,
shown: null,
hide: null,
hidden: null,
view: null,
viewed: null,
move: null,
moved: null,
rotate: null,
rotated: null,
scale: null,
scaled: null,
zoom: null,
zoomed: null,
play: null,
stop: null
};
var TEMPLATE = "<div class=\"viewer-container\" tabindex=\"-1\" touch-action=\"none\"><div class=\"viewer-canvas\"></div><div class=\"viewer-footer\"><div class=\"viewer-title\"></div><div class=\"viewer-toolbar\"></div><div class=\"viewer-navbar\"><ul class=\"viewer-list\" role=\"navigation\"></ul></div></div><div class=\"viewer-tooltip\" role=\"alert\" aria-hidden=\"true\"></div><div class=\"viewer-button\" data-viewer-action=\"mix\" role=\"button\"></div><div class=\"viewer-player\"></div></div>";
var IS_BROWSER = typeof window !== "undefined" && typeof window.document !== "undefined";
var WINDOW = IS_BROWSER ? window : {};
var IS_TOUCH_DEVICE = IS_BROWSER && WINDOW.document.documentElement ? "ontouchstart" in WINDOW.document.documentElement : false;
var HAS_POINTER_EVENT = IS_BROWSER ? "PointerEvent" in WINDOW : false;
var NAMESPACE = "viewer";
var ACTION_MOVE = "move";
var ACTION_SWITCH = "switch";
var ACTION_ZOOM = "zoom";
var CLASS_ACTIVE = "".concat(NAMESPACE, "-active");
var CLASS_CLOSE = "".concat(NAMESPACE, "-close");
var CLASS_FADE = "".concat(NAMESPACE, "-fade");
var CLASS_FIXED = "".concat(NAMESPACE, "-fixed");
var CLASS_FULLSCREEN = "".concat(NAMESPACE, "-fullscreen");
var CLASS_FULLSCREEN_EXIT = "".concat(NAMESPACE, "-fullscreen-exit");
var CLASS_HIDE = "".concat(NAMESPACE, "-hide");
var CLASS_HIDE_MD_DOWN = "".concat(NAMESPACE, "-hide-md-down");
var CLASS_HIDE_SM_DOWN = "".concat(NAMESPACE, "-hide-sm-down");
var CLASS_HIDE_XS_DOWN = "".concat(NAMESPACE, "-hide-xs-down");
var CLASS_IN = "".concat(NAMESPACE, "-in");
var CLASS_INVISIBLE = "".concat(NAMESPACE, "-invisible");
var CLASS_LOADING = "".concat(NAMESPACE, "-loading");
var CLASS_MOVE = "".concat(NAMESPACE, "-move");
var CLASS_OPEN = "".concat(NAMESPACE, "-open");
var CLASS_SHOW = "".concat(NAMESPACE, "-show");
var CLASS_TRANSITION = "".concat(NAMESPACE, "-transition");
var EVENT_CLICK = "click";
var EVENT_DBLCLICK = "dblclick";
var EVENT_DRAG_START = "dragstart";
var EVENT_FOCUSIN = "focusin";
var EVENT_KEY_DOWN = "keydown";
var EVENT_LOAD = "load";
var EVENT_ERROR = "error";
var EVENT_TOUCH_END = IS_TOUCH_DEVICE ? "touchend touchcancel" : "mouseup";
var EVENT_TOUCH_MOVE = IS_TOUCH_DEVICE ? "touchmove" : "mousemove";
var EVENT_POINTER_DOWN = HAS_POINTER_EVENT ? "pointerdown" : IS_TOUCH_DEVICE ? "touchstart" : "mousedown";
var EVENT_POINTER_MOVE = HAS_POINTER_EVENT ? "pointermove" : EVENT_TOUCH_MOVE;
var EVENT_POINTER_UP = HAS_POINTER_EVENT ? "pointerup pointercancel" : EVENT_TOUCH_END;
var EVENT_RESIZE = "resize";
var EVENT_TRANSITION_END = "transitionend";
var EVENT_WHEEL = "wheel";
var EVENT_READY = "ready";
var EVENT_SHOW = "show";
var EVENT_SHOWN = "shown";
var EVENT_HIDE = "hide";
var EVENT_HIDDEN = "hidden";
var EVENT_VIEW = "view";
var EVENT_VIEWED = "viewed";
var EVENT_MOVE = "move";
var EVENT_MOVED = "moved";
var EVENT_ROTATE = "rotate";
var EVENT_ROTATED = "rotated";
var EVENT_SCALE = "scale";
var EVENT_SCALED = "scaled";
var EVENT_ZOOM = "zoom";
var EVENT_ZOOMED = "zoomed";
var EVENT_PLAY = "play";
var EVENT_STOP = "stop";
var DATA_ACTION = "".concat(NAMESPACE, "Action");
var REGEXP_SPACES = /\s\s*/;
var BUTTONS = [
"zoom-in",
"zoom-out",
"one-to-one",
"reset",
"prev",
"play",
"next",
"rotate-left",
"rotate-right",
"flip-horizontal",
"flip-vertical"
];
function isString(value) {
return typeof value === "string";
}
var isNaN = Number.isNaN || WINDOW.isNaN;
function isNumber(value) {
return typeof value === "number" && !isNaN(value);
}
function isUndefined(value) {
return typeof value === "undefined";
}
function isObject(value) {
return _typeof(value) === "object" && value !== null;
}
var hasOwnProperty = Object.prototype.hasOwnProperty;
function isPlainObject(value) {
if (!isObject(value)) return false;
try {
var _constructor = value.constructor;
var prototype = _constructor.prototype;
return _constructor && prototype && hasOwnProperty.call(prototype, "isPrototypeOf");
} catch (error) {
return false;
}
}
function isFunction(value) {
return typeof value === "function";
}
function forEach(data, callback) {
if (data && isFunction(callback)) {
if (Array.isArray(data) || isNumber(data.length)) {
var length = data.length;
var i;
for (i = 0; i < length; i += 1) if (callback.call(data, data[i], i, data) === false) break;
} else if (isObject(data)) Object.keys(data).forEach(function(key) {
callback.call(data, data[key], key, data);
});
}
return data;
}
var assign = Object.assign || function assign(obj) {
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) args[_key - 1] = arguments[_key];
if (isObject(obj) && args.length > 0) args.forEach(function(arg) {
if (isObject(arg)) Object.keys(arg).forEach(function(key) {
obj[key] = arg[key];
});
});
return obj;
};
var REGEXP_SUFFIX = /^(?:width|height|left|top|marginLeft|marginTop)$/;
function setStyle(element, styles) {
var style = element.style;
forEach(styles, function(value, property) {
if (REGEXP_SUFFIX.test(property) && isNumber(value)) value += "px";
style[property] = value;
});
}
function escapeHTMLEntities(value) {
return isString(value) ? value.replace(/&(?!amp;|quot;|#39;|lt;|gt;)/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">") : value;
}
function hasClass(element, value) {
if (!element || !value) return false;
return element.classList ? element.classList.contains(value) : element.className.indexOf(value) > -1;
}
function addClass(element, value) {
if (!element || !value) return;
if (isNumber(element.length)) {
forEach(element, function(elem) {
addClass(elem, value);
});
return;
}
if (element.classList) {
element.classList.add(value);
return;
}
var className = element.className.trim();
if (!className) element.className = value;
else if (className.indexOf(value) < 0) element.className = "".concat(className, " ").concat(value);
}
function removeClass(element, value) {
if (!element || !value) return;
if (isNumber(element.length)) {
forEach(element, function(elem) {
removeClass(elem, value);
});
return;
}
if (element.classList) {
element.classList.remove(value);
return;
}
if (element.className.indexOf(value) >= 0) element.className = element.className.replace(value, "");
}
function toggleClass(element, value, added) {
if (!value) return;
if (isNumber(element.length)) {
forEach(element, function(elem) {
toggleClass(elem, value, added);
});
return;
}
if (added) addClass(element, value);
else removeClass(element, value);
}
var REGEXP_HYPHENATE = /([a-z\d])([A-Z])/g;
function hyphenate(value) {
return value.replace(REGEXP_HYPHENATE, "$1-$2").toLowerCase();
}
function getData(element, name) {
if (isObject(element[name])) return element[name];
if (element.dataset) return element.dataset[name];
return element.getAttribute("data-".concat(hyphenate(name)));
}
function setData(element, name, data) {
if (isObject(data)) element[name] = data;
else if (element.dataset) element.dataset[name] = data;
else element.setAttribute("data-".concat(hyphenate(name)), data);
}
var onceSupported = function() {
var supported = false;
if (IS_BROWSER) {
var once = false;
var listener = function listener() {};
var options = Object.defineProperty({}, "once", {
get: function get() {
supported = true;
return once;
},
set: function set(value) {
once = value;
}
});
WINDOW.addEventListener("test", listener, options);
WINDOW.removeEventListener("test", listener, options);
}
return supported;
}();
function removeListener(element, type, listener) {
var options = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : {};
var handler = listener;
type.trim().split(REGEXP_SPACES).forEach(function(event) {
if (!onceSupported) {
var listeners = element.listeners;
if (listeners && listeners[event] && listeners[event][listener]) {
handler = listeners[event][listener];
delete listeners[event][listener];
if (Object.keys(listeners[event]).length === 0) delete listeners[event];
if (Object.keys(listeners).length === 0) delete element.listeners;
}
}
element.removeEventListener(event, handler, options);
});
}
function addListener(element, type, listener) {
var options = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : {};
var _handler = listener;
type.trim().split(REGEXP_SPACES).forEach(function(event) {
if (options.once && !onceSupported) {
var _element$listeners = element.listeners, listeners = _element$listeners === void 0 ? {} : _element$listeners;
_handler = function handler() {
delete listeners[event][listener];
element.removeEventListener(event, _handler, options);
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) args[_key2] = arguments[_key2];
listener.apply(element, args);
};
if (!listeners[event]) listeners[event] = {};
if (listeners[event][listener]) element.removeEventListener(event, listeners[event][listener], options);
listeners[event][listener] = _handler;
element.listeners = listeners;
}
element.addEventListener(event, _handler, options);
});
}
function dispatchEvent(element, type, data, options) {
var event;
if (isFunction(Event) && isFunction(CustomEvent)) event = new CustomEvent(type, _objectSpread2({
bubbles: true,
cancelable: true,
detail: data
}, options));
else {
event = document.createEvent("CustomEvent");
event.initCustomEvent(type, true, true, data);
}
return element.dispatchEvent(event);
}
function getOffset(element) {
var box = element.getBoundingClientRect();
return {
left: box.left + (window.pageXOffset - document.documentElement.clientLeft),
top: box.top + (window.pageYOffset - document.documentElement.clientTop)
};
}
function getTransforms(_ref) {
var rotate = _ref.rotate, scaleX = _ref.scaleX, scaleY = _ref.scaleY, translateX = _ref.translateX, translateY = _ref.translateY;
var values = [];
if (isNumber(translateX) && translateX !== 0) values.push("translateX(".concat(translateX, "px)"));
if (isNumber(translateY) && translateY !== 0) values.push("translateY(".concat(translateY, "px)"));
if (isNumber(rotate) && rotate !== 0) values.push("rotate(".concat(rotate, "deg)"));
if (isNumber(scaleX) && scaleX !== 1) values.push("scaleX(".concat(scaleX, ")"));
if (isNumber(scaleY) && scaleY !== 1) values.push("scaleY(".concat(scaleY, ")"));
var transform = values.length ? values.join(" ") : "none";
return {
WebkitTransform: transform,
msTransform: transform,
transform
};
}
function getImageNameFromURL(url) {
return isString(url) ? decodeURIComponent(url.replace(/^.*\//, "").replace(/[?&#].*$/, "")) : "";
}
var IS_SAFARI = WINDOW.navigator && /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i.test(WINDOW.navigator.userAgent);
function getImageNaturalSizes(image, options, callback) {
var newImage = document.createElement("img");
if (image.naturalWidth && !IS_SAFARI) {
callback(image.naturalWidth, image.naturalHeight);
return newImage;
}
var body = document.body || document.documentElement;
newImage.onload = function() {
callback(newImage.width, newImage.height);
if (!IS_SAFARI) body.removeChild(newImage);
};
forEach(options.inheritedAttributes, function(name) {
var value = image.getAttribute(name);
if (value !== null) newImage.setAttribute(name, value);
});
newImage.src = image.src;
if (!IS_SAFARI) {
newImage.style.cssText = "left:0;max-height:none!important;max-width:none!important;min-height:0!important;min-width:0!important;opacity:0;position:absolute;top:0;z-index:-1;";
body.appendChild(newImage);
}
return newImage;
}
function getResponsiveClass(type) {
switch (type) {
case 2: return CLASS_HIDE_XS_DOWN;
case 3: return CLASS_HIDE_SM_DOWN;
case 4: return CLASS_HIDE_MD_DOWN;
default: return "";
}
}
function getMaxZoomRatio(pointers) {
var pointers2 = _objectSpread2({}, pointers);
var ratios = [];
forEach(pointers, function(pointer, pointerId) {
delete pointers2[pointerId];
forEach(pointers2, function(pointer2) {
var x1 = Math.abs(pointer.startX - pointer2.startX);
var y1 = Math.abs(pointer.startY - pointer2.startY);
var x2 = Math.abs(pointer.endX - pointer2.endX);
var y2 = Math.abs(pointer.endY - pointer2.endY);
var z1 = Math.sqrt(x1 * x1 + y1 * y1);
var ratio = (Math.sqrt(x2 * x2 + y2 * y2) - z1) / z1;
ratios.push(ratio);
});
});
ratios.sort(function(a, b) {
return Math.abs(a) < Math.abs(b);
});
return ratios[0];
}
function getPointer(_ref2, endOnly) {
var pageX = _ref2.pageX, pageY = _ref2.pageY;
var end = {
endX: pageX,
endY: pageY
};
return endOnly ? end : _objectSpread2({
timeStamp: Date.now(),
startX: pageX,
startY: pageY
}, end);
}
function getPointersCenter(pointers) {
var pageX = 0;
var pageY = 0;
var count = 0;
forEach(pointers, function(_ref3) {
var startX = _ref3.startX, startY = _ref3.startY;
pageX += startX;
pageY += startY;
count += 1;
});
pageX /= count;
pageY /= count;
return {
pageX,
pageY
};
}
var render = {
render: function render() {
this.initContainer();
this.initViewer();
this.initList();
this.renderViewer();
},
initBody: function initBody() {
var ownerDocument = this.element.ownerDocument;
var body = ownerDocument.body || ownerDocument.documentElement;
this.body = body;
this.scrollbarWidth = window.innerWidth - ownerDocument.documentElement.clientWidth;
this.initialBodyPaddingRight = body.style.paddingRight;
this.initialBodyComputedPaddingRight = window.getComputedStyle(body).paddingRight;
},
initContainer: function initContainer() {
this.containerData = {
width: window.innerWidth,
height: window.innerHeight
};
},
initViewer: function initViewer() {
var options = this.options, parent = this.parent;
var viewerData;
if (options.inline) {
viewerData = {
width: Math.max(parent.offsetWidth, options.minWidth),
height: Math.max(parent.offsetHeight, options.minHeight)
};
this.parentData = viewerData;
}
if (this.fulled || !viewerData) viewerData = this.containerData;
this.viewerData = assign({}, viewerData);
},
renderViewer: function renderViewer() {
if (this.options.inline && !this.fulled) setStyle(this.viewer, this.viewerData);
},
initList: function initList() {
var _this = this;
var element = this.element, options = this.options, list = this.list;
var items = [];
list.innerHTML = "";
forEach(this.images, function(image, index) {
var src = image.src;
var alt = image.alt || getImageNameFromURL(src);
var url = _this.getImageURL(image);
if (src || url) {
var item = document.createElement("li");
var img = document.createElement("img");
forEach(options.inheritedAttributes, function(name) {
var value = image.getAttribute(name);
if (value !== null) img.setAttribute(name, value);
});
if (options.navbar) img.src = src || url;
img.alt = alt;
img.setAttribute("data-original-url", url || src);
item.setAttribute("data-index", index);
item.setAttribute("data-viewer-action", "view");
item.setAttribute("role", "button");
if (options.keyboard) item.setAttribute("tabindex", 0);
item.appendChild(img);
list.appendChild(item);
items.push(item);
}
});
this.items = items;
forEach(items, function(item) {
var image = item.firstElementChild;
var onLoad;
var onError;
setData(image, "filled", true);
if (options.loading) addClass(item, CLASS_LOADING);
addListener(image, EVENT_LOAD, onLoad = function onLoad(event) {
removeListener(image, EVENT_ERROR, onError);
if (options.loading) removeClass(item, CLASS_LOADING);
_this.loadImage(event);
}, { once: true });
addListener(image, EVENT_ERROR, onError = function onError() {
removeListener(image, EVENT_LOAD, onLoad);
if (options.loading) removeClass(item, CLASS_LOADING);
}, { once: true });
});
if (options.transition) addListener(element, EVENT_VIEWED, function() {
addClass(list, CLASS_TRANSITION);
}, { once: true });
},
renderList: function renderList() {
var index = this.index;
var item = this.items[index];
if (!item) return;
var next = item.nextElementSibling;
var gutter = parseInt(window.getComputedStyle(next || item).marginLeft, 10);
var offsetWidth = item.offsetWidth;
var outerWidth = offsetWidth + gutter;
setStyle(this.list, assign({ width: outerWidth * this.length - gutter }, getTransforms({ translateX: (this.viewerData.width - offsetWidth) / 2 - outerWidth * index })));
},
resetList: function resetList() {
var list = this.list;
list.innerHTML = "";
removeClass(list, CLASS_TRANSITION);
setStyle(list, getTransforms({ translateX: 0 }));
},
initImage: function initImage(done) {
var _this2 = this;
var options = this.options, image = this.image, viewerData = this.viewerData;
var footerHeight = this.footer.offsetHeight;
var viewerWidth = viewerData.width;
var viewerHeight = Math.max(viewerData.height - footerHeight, footerHeight);
var oldImageData = this.imageData || {};
var sizingImage;
this.imageInitializing = { abort: function abort() {
sizingImage.onload = null;
} };
sizingImage = getImageNaturalSizes(image, options, function(naturalWidth, naturalHeight) {
var aspectRatio = naturalWidth / naturalHeight;
var initialCoverage = Math.max(0, Math.min(1, options.initialCoverage));
var width = viewerWidth;
var height = viewerHeight;
_this2.imageInitializing = false;
if (viewerHeight * aspectRatio > viewerWidth) height = viewerWidth / aspectRatio;
else width = viewerHeight * aspectRatio;
initialCoverage = isNumber(initialCoverage) ? initialCoverage : .9;
width = Math.min(width * initialCoverage, naturalWidth);
height = Math.min(height * initialCoverage, naturalHeight);
var left = (viewerWidth - width) / 2;
var top = (viewerHeight - height) / 2;
var imageData = {
left,
top,
x: left,
y: top,
width,
height,
oldRatio: 1,
ratio: width / naturalWidth,
aspectRatio,
naturalWidth,
naturalHeight
};
var initialImageData = assign({}, imageData);
if (options.rotatable) {
imageData.rotate = oldImageData.rotate || 0;
initialImageData.rotate = 0;
}
if (options.scalable) {
imageData.scaleX = oldImageData.scaleX || 1;
imageData.scaleY = oldImageData.scaleY || 1;
initialImageData.scaleX = 1;
initialImageData.scaleY = 1;
}
_this2.imageData = imageData;
_this2.initialImageData = initialImageData;
if (done) done();
});
},
renderImage: function renderImage(done) {
var _this3 = this;
var image = this.image, imageData = this.imageData;
setStyle(image, assign({
width: imageData.width,
height: imageData.height,
marginLeft: imageData.x,
marginTop: imageData.y
}, getTransforms(imageData)));
if (done) if ((this.viewing || this.moving || this.rotating || this.scaling || this.zooming) && this.options.transition && hasClass(image, CLASS_TRANSITION)) {
var onTransitionEnd = function onTransitionEnd() {
_this3.imageRendering = false;
done();
};
this.imageRendering = { abort: function abort() {
removeListener(image, EVENT_TRANSITION_END, onTransitionEnd);
} };
addListener(image, EVENT_TRANSITION_END, onTransitionEnd, { once: true });
} else done();
},
resetImage: function resetImage() {
if (this.viewing || this.viewed) {
var image = this.image;
if (this.viewing) this.viewing.abort();
image.parentNode.removeChild(image);
this.image = null;
}
}
};
var events = {
bind: function bind() {
var options = this.options, viewer = this.viewer, canvas = this.canvas;
var document = this.element.ownerDocument;
addListener(viewer, EVENT_CLICK, this.onClick = this.click.bind(this));
addListener(viewer, EVENT_DRAG_START, this.onDragStart = this.dragstart.bind(this));
addListener(canvas, EVENT_POINTER_DOWN, this.onPointerDown = this.pointerdown.bind(this));
addListener(document, EVENT_POINTER_MOVE, this.onPointerMove = this.pointermove.bind(this));
addListener(document, EVENT_POINTER_UP, this.onPointerUp = this.pointerup.bind(this));
addListener(document, EVENT_KEY_DOWN, this.onKeyDown = this.keydown.bind(this));
addListener(window, EVENT_RESIZE, this.onResize = this.resize.bind(this));
if (options.zoomable && options.zoomOnWheel) addListener(viewer, EVENT_WHEEL, this.onWheel = this.wheel.bind(this), {
passive: false,
capture: true
});
if (options.toggleOnDblclick) addListener(canvas, EVENT_DBLCLICK, this.onDblclick = this.dblclick.bind(this));
},
unbind: function unbind() {
var options = this.options, viewer = this.viewer, canvas = this.canvas;
var document = this.element.ownerDocument;
removeListener(viewer, EVENT_CLICK, this.onClick);
removeListener(viewer, EVENT_DRAG_START, this.onDragStart);
removeListener(canvas, EVENT_POINTER_DOWN, this.onPointerDown);
removeListener(document, EVENT_POINTER_MOVE, this.onPointerMove);
removeListener(document, EVENT_POINTER_UP, this.onPointerUp);
removeListener(document, EVENT_KEY_DOWN, this.onKeyDown);
removeListener(window, EVENT_RESIZE, this.onResize);
if (options.zoomable && options.zoomOnWheel) removeListener(viewer, EVENT_WHEEL, this.onWheel, {
passive: false,
capture: true
});
if (options.toggleOnDblclick) removeListener(canvas, EVENT_DBLCLICK, this.onDblclick);
}
};
var handlers = {
click: function click(event) {
var options = this.options, imageData = this.imageData;
var target = event.target;
var action = getData(target, DATA_ACTION);
if (!action && target.localName === "img" && target.parentElement.localName === "li") {
target = target.parentElement;
action = getData(target, DATA_ACTION);
}
if (IS_TOUCH_DEVICE && event.isTrusted && target === this.canvas) clearTimeout(this.clickCanvasTimeout);
switch (action) {
case "mix":
if (this.played) this.stop();
else if (options.inline) if (this.fulled) this.exit();
else this.full();
else this.hide();
break;
case "hide":
this.hide();
break;
case "view":
this.view(getData(target, "index"));
break;
case "zoom-in":
this.zoom(.1, true);
break;
case "zoom-out":
this.zoom(-.1, true);
break;
case "one-to-one":
this.toggle();
break;
case "reset":
this.reset();
break;
case "prev":
this.prev(options.loop);
break;
case "play":
this.play(options.fullscreen);
break;
case "next":
this.next(options.loop);
break;
case "rotate-left":
this.rotate(-90);
break;
case "rotate-right":
this.rotate(90);
break;
case "flip-horizontal":
this.scaleX(-imageData.scaleX || -1);
break;
case "flip-vertical":
this.scaleY(-imageData.scaleY || -1);
break;
default: if (this.played) this.stop();
}
},
dblclick: function dblclick(event) {
event.preventDefault();
if (this.viewed && event.target === this.image) {
if (IS_TOUCH_DEVICE && event.isTrusted) clearTimeout(this.doubleClickImageTimeout);
this.toggle(event.isTrusted ? event : event.detail && event.detail.originalEvent);
}
},
load: function load() {
var _this = this;
if (this.timeout) {
clearTimeout(this.timeout);
this.timeout = false;
}
var element = this.element, options = this.options, image = this.image, index = this.index, viewerData = this.viewerData;
removeClass(image, CLASS_INVISIBLE);
if (options.loading) removeClass(this.canvas, CLASS_LOADING);
image.style.cssText = "height:0;" + "margin-left:".concat(viewerData.width / 2, "px;") + "margin-top:".concat(viewerData.height / 2, "px;") + "max-width:none!important;position:relative;width:0;";
this.initImage(function() {
toggleClass(image, CLASS_MOVE, options.movable);
toggleClass(image, CLASS_TRANSITION, options.transition);
_this.renderImage(function() {
_this.viewed = true;
_this.viewing = false;
if (isFunction(options.viewed)) addListener(element, EVENT_VIEWED, options.viewed, { once: true });
dispatchEvent(element, EVENT_VIEWED, {
originalImage: _this.images[index],
index,
image
}, { cancelable: false });
});
});
},
loadImage: function loadImage(event) {
var image = event.target;
var parent = image.parentNode;
var parentWidth = parent.offsetWidth || 30;
var parentHeight = parent.offsetHeight || 50;
var filled = !!getData(image, "filled");
getImageNaturalSizes(image, this.options, function(naturalWidth, naturalHeight) {
var aspectRatio = naturalWidth / naturalHeight;
var width = parentWidth;
var height = parentHeight;
if (parentHeight * aspectRatio > parentWidth) if (filled) width = parentHeight * aspectRatio;
else height = parentWidth / aspectRatio;
else if (filled) height = parentWidth / aspectRatio;
else width = parentHeight * aspectRatio;
setStyle(image, assign({
width,
height
}, getTransforms({
translateX: (parentWidth - width) / 2,
translateY: (parentHeight - height) / 2
})));
});
},
keydown: function keydown(event) {
var options = this.options;
if (!options.keyboard) return;
var keyCode = event.keyCode || event.which || event.charCode;
switch (keyCode) {
case 13:
if (this.viewer.contains(event.target)) this.click(event);
break;
}
if (!this.fulled) return;
switch (keyCode) {
case 27:
if (this.played) this.stop();
else if (options.inline) {
if (this.fulled) this.exit();
} else this.hide();
break;
case 32:
if (this.played) this.stop();
break;
case 37:
if (this.played && this.playing) this.playing.prev();
else this.prev(options.loop);
break;
case 38:
event.preventDefault();
this.zoom(options.zoomRatio, true);
break;
case 39:
if (this.played && this.playing) this.playing.next();
else this.next(options.loop);
break;
case 40:
event.preventDefault();
this.zoom(-options.zoomRatio, true);
break;
case 48:
case 49:
if (event.ctrlKey) {
event.preventDefault();
this.toggle();
}
break;
}
},
dragstart: function dragstart(event) {
if (event.target.localName === "img") event.preventDefault();
},
pointerdown: function pointerdown(event) {
var options = this.options, pointers = this.pointers;
var buttons = event.buttons, button = event.button;
if (!this.viewed || this.showing || this.viewing || this.hiding || (event.type === "mousedown" || event.type === "pointerdown" && event.pointerType === "mouse") && (isNumber(buttons) && buttons !== 1 || isNumber(button) && button !== 0 || event.ctrlKey)) return;
event.preventDefault();
if (event.changedTouches) forEach(event.changedTouches, function(touch) {
pointers[touch.identifier] = getPointer(touch);
});
else pointers[event.pointerId || 0] = getPointer(event);
var action = options.movable ? ACTION_MOVE : false;
if (options.zoomOnTouch && options.zoomable && Object.keys(pointers).length > 1) action = ACTION_ZOOM;
else if (options.slideOnTouch && (event.pointerType === "touch" || event.type === "touchstart") && this.isSwitchable()) action = ACTION_SWITCH;
if (options.transition && (action === ACTION_MOVE || action === ACTION_ZOOM)) removeClass(this.image, CLASS_TRANSITION);
this.action = action;
},
pointermove: function pointermove(event) {
var pointers = this.pointers, action = this.action;
if (!this.viewed || !action) return;
event.preventDefault();
if (event.changedTouches) forEach(event.changedTouches, function(touch) {
assign(pointers[touch.identifier] || {}, getPointer(touch, true));
});
else assign(pointers[event.pointerId || 0] || {}, getPointer(event, true));
this.change(event);
},
pointerup: function pointerup(event) {
var _this2 = this;
var options = this.options, action = this.action, pointers = this.pointers;
var pointer;
if (event.changedTouches) forEach(event.changedTouches, function(touch) {
pointer = pointers[touch.identifier];
delete pointers[touch.identifier];
});
else {
pointer = pointers[event.pointerId || 0];
delete pointers[event.pointerId || 0];
}
if (!action) return;
event.preventDefault();
if (options.transition && (action === ACTION_MOVE || action === ACTION_ZOOM)) addClass(this.image, CLASS_TRANSITION);
this.action = false;
if (IS_TOUCH_DEVICE && action !== ACTION_ZOOM && pointer && Date.now() - pointer.timeStamp < 500) {
clearTimeout(this.clickCanvasTimeout);
clearTimeout(this.doubleClickImageTimeout);
if (options.toggleOnDblclick && this.viewed && event.target === this.image) if (this.imageClicked) {
this.imageClicked = false;
this.doubleClickImageTimeout = setTimeout(function() {
dispatchEvent(_this2.image, EVENT_DBLCLICK, { originalEvent: event });
}, 50);
} else {
this.imageClicked = true;
this.doubleClickImageTimeout = setTimeout(function() {
_this2.imageClicked = false;
}, 500);
}
else {
this.imageClicked = false;
if (options.backdrop && options.backdrop !== "static" && event.target === this.canvas) this.clickCanvasTimeout = setTimeout(function() {
dispatchEvent(_this2.canvas, EVENT_CLICK, { originalEvent: event });
}, 50);
}
}
},
resize: function resize() {
var _this3 = this;
if (!this.isShown || this.hiding) return;
if (this.fulled) {
this.close();
this.initBody();
this.open();
}
this.initContainer();
this.initViewer();
this.renderViewer();
this.renderList();
if (this.viewed) this.initImage(function() {
_this3.renderImage();
});
if (this.played) {
if (this.options.fullscreen && this.fulled && !(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement)) {
this.stop();
return;
}
forEach(this.player.getElementsByTagName("img"), function(image) {
addListener(image, EVENT_LOAD, _this3.loadImage.bind(_this3), { once: true });
dispatchEvent(image, EVENT_LOAD);
});
}
},
wheel: function wheel(event) {
var _this4 = this;
if (!this.viewed) return;
event.preventDefault();
if (this.wheeling) return;
this.wheeling = true;
setTimeout(function() {
_this4.wheeling = false;
}, 50);
var ratio = Number(this.options.zoomRatio) || .1;
var delta = 1;
if (event.deltaY) delta = event.deltaY > 0 ? 1 : -1;
else if (event.wheelDelta) delta = -event.wheelDelta / 120;
else if (event.detail) delta = event.detail > 0 ? 1 : -1;
this.zoom(-delta * ratio, true, null, event);
}
};
var methods = {
show: function show() {
var immediate = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : false;
var element = this.element, options = this.options;
if (options.inline || this.showing || this.isShown || this.showing) return this;
if (!this.ready) {
this.build();
if (this.ready) this.show(immediate);
return this;
}
if (isFunction(options.show)) addListener(element, EVENT_SHOW, options.show, { once: true });
if (dispatchEvent(element, EVENT_SHOW) === false || !this.ready) return this;
if (this.hiding) this.transitioning.abort();
this.showing = true;
this.open();
var viewer = this.viewer;
removeClass(viewer, CLASS_HIDE);
viewer.setAttribute("role", "dialog");
viewer.setAttribute("aria-labelledby", this.title.id);
viewer.setAttribute("aria-modal", true);
viewer.removeAttribute("aria-hidden");
if (options.transition && !immediate) {
var shown = this.shown.bind(this);
this.transitioning = { abort: function abort() {
removeListener(viewer, EVENT_TRANSITION_END, shown);
removeClass(viewer, CLASS_IN);
} };
addClass(viewer, CLASS_TRANSITION);
viewer.initialOffsetWidth = viewer.offsetWidth;
addListener(viewer, EVENT_TRANSITION_END, shown, { once: true });
addClass(viewer, CLASS_IN);
} else {
addClass(viewer, CLASS_IN);
this.shown();
}
return this;
},
hide: function hide() {
var _this = this;
var immediate = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : false;
var element = this.element, options = this.options;
if (options.inline || this.hiding || !(this.isShown || this.showing)) return this;
if (isFunction(options.hide)) addListener(element, EVENT_HIDE, options.hide, { once: true });
if (dispatchEvent(element, EVENT_HIDE) === false) return this;
if (this.showing) this.transitioning.abort();
this.hiding = true;
if (this.played) this.stop();
else if (this.viewing) this.viewing.abort();
var viewer = this.viewer, image = this.image;
var hideImmediately = function hideImmediately() {
removeClass(viewer, CLASS_IN);
_this.hidden();
};
if (options.transition && !immediate) {
var onViewerTransitionEnd = function onViewerTransitionEnd(event) {
if (event && event.target === viewer) {
removeListener(viewer, EVENT_TRANSITION_END, onViewerTransitionEnd);
_this.hidden();
}
};
var onImageTransitionEnd = function onImageTransitionEnd() {
if (hasClass(viewer, CLASS_TRANSITION)) {
addListener(viewer, EVENT_TRANSITION_END, onViewerTransitionEnd);
removeClass(viewer, CLASS_IN);
} else hideImmediately();
};
this.transitioning = { abort: function abort() {
if (_this.viewed && hasClass(image, CLASS_TRANSITION)) removeListener(image, EVENT_TRANSITION_END, onImageTransitionEnd);
else if (hasClass(viewer, CLASS_TRANSITION)) removeListener(viewer, EVENT_TRANSITION_END, onViewerTransitionEnd);
} };
if (this.viewed && hasClass(image, CLASS_TRANSITION)) {
addListener(image, EVENT_TRANSITION_END, onImageTransitionEnd, { once: true });
this.zoomTo(0, false, null, null, true);
} else onImageTransitionEnd();
} else hideImmediately();
return this;
},
view: function view() {
var _this2 = this;
var index = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : this.options.initialViewIndex;
index = Number(index) || 0;
if (this.hiding || this.played || index < 0 || index >= this.length || this.viewed && index === this.index) return this;
if (!this.isShown) {
this.index = index;
return this.show();
}
if (this.viewing) this.viewing.abort();
var element = this.element, options = this.options, title = this.title, canvas = this.canvas;
var item = this.items[index];
var img = item.querySelector("img");
var url = getData(img, "originalUrl");
var alt = img.getAttribute("alt");
var image = document.createElement("img");
forEach(options.inheritedAttributes, function(name) {
var value = img.getAttribute(name);
if (value !== null) image.setAttribute(name, value);
});
image.src = url;
image.alt = alt;
if (isFunction(options.view)) addListener(element, EVENT_VIEW, options.view, { once: true });
if (dispatchEvent(element, EVENT_VIEW, {
originalImage: this.images[index],
index,
image
}) === false || !this.isShown || this.hiding || this.played) return this;
var activeItem = this.items[this.index];
if (activeItem) {
removeClass(activeItem, CLASS_ACTIVE);
activeItem.removeAttribute("aria-selected");
}
addClass(item, CLASS_ACTIVE);
item.setAttribute("aria-selected", true);
if (options.focus) item.focus();
this.image = image;
this.viewed = false;
this.index = index;
this.imageData = {};
addClass(image, CLASS_INVISIBLE);
if (options.loading) addClass(canvas, CLASS_LOADING);
canvas.innerHTML = "";
canvas.appendChild(image);
this.renderList();
title.innerHTML = "";
var onViewed = function onViewed() {
var imageData = _this2.imageData;
var render = Array.isArray(options.title) ? options.title[1] : options.title;
title.innerHTML = escapeHTMLEntities(isFunction(render) ? render.call(_this2, image, imageData) : "".concat(alt, " (").concat(imageData.naturalWidth, " × ").concat(imageData.naturalHeight, ")"));
};
var onLoad;
var onError;
addListener(element, EVENT_VIEWED, onViewed, { once: true });
this.viewing = { abort: function abort() {
removeListener(element, EVENT_VIEWED, onViewed);
if (image.complete) {
if (_this2.imageRendering) _this2.imageRendering.abort();
else if (_this2.imageInitializing) _this2.imageInitializing.abort();
} else {
image.src = "";
removeListener(image, EVENT_LOAD, onLoad);
if (_this2.timeout) clearTimeout(_this2.timeout);
}
} };
if (image.complete) this.load();
else {
addListener(image, EVENT_LOAD, onLoad = function onLoad() {
removeListener(image, EVENT_ERROR, onError);
_this2.load();
}, { once: true });
addListener(image, EVENT_ERROR, onError = function onError() {
removeListener(image, EVENT_LOAD, onLoad);
if (_this2.timeout) {
clearTimeout(_this2.timeout);
_this2.timeout = false;
}
removeClass(image, CLASS_INVISIBLE);
if (options.loading) removeClass(_this2.canvas, CLASS_LOADING);
}, { once: true });
if (this.timeout) clearTimeout(this.timeout);
this.timeout = setTimeout(function() {
removeClass(image, CLASS_INVISIBLE);
_this2.timeout = false;
}, 1e3);
}
return this;
},
prev: function prev() {
var loop = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : false;
var index = this.index - 1;
if (index < 0) index = loop ? this.length - 1 : 0;
this.view(index);
return this;
},
next: function next() {
var loop = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : false;
var maxIndex = this.length - 1;
var index = this.index + 1;
if (index > maxIndex) index = loop ? 0 : maxIndex;
this.view(index);
return this;
},
move: function move(x) {
var y = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : x;
var imageData = this.imageData;
this.moveTo(isUndefined(x) ? x : imageData.x + Number(x), isUndefined(y) ? y : imageData.y + Number(y));
return this;
},
moveTo: function moveTo(x) {
var _this3 = this;
var y = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : x;
var _originalEvent = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : null;
var element = this.element, options = this.options, imageData = this.imageData;
x = Number(x);
y = Number(y);
if (this.viewed && !this.played && options.movable) {
var oldX = imageData.x;
var oldY = imageData.y;
var changed = false;
if (isNumber(x)) changed = true;
else x = oldX;
if (isNumber(y)) changed = true;
else y = oldY;
if (changed) {
if (isFunction(options.move)) addListener(element, EVENT_MOVE, options.move, { once: true });
if (dispatchEvent(element, EVENT_MOVE, {
x,
y,
oldX,
oldY,
originalEvent: _originalEvent
}) === false) return this;
imageData.x = x;
imageData.y = y;
imageData.left = x;
imageData.top = y;
this.moving = true;
this.renderImage(function() {
_this3.moving = false;
if (isFunction(options.moved)) addListener(element, EVENT_MOVED, options.moved, { once: true });
dispatchEvent(element, EVENT_MOVED, {
x,
y,
oldX,
oldY,
originalEvent: _originalEvent
}, { cancelable: false });
});
}
}
return this;
},
rotate: function rotate(degree) {
this.rotateTo((this.imageData.rotate || 0) + Number(degree));
return this;
},
rotateTo: function rotateTo(degree) {
var _this4 = this;
var element = this.element, options = this.options, imageData = this.imageData;
degree = Number(degree);
if (isNumber(degree) && this.viewed && !this.played && options.rotatable) {
var oldDegree = imageData.rotate;
if (isFunction(options.rotate)) addListener(element, EVENT_ROTATE, options.rotate, { once: true });
if (dispatchEvent(element, EVENT_ROTATE, {
degree,
oldDegree
}) === false) return this;
imageData.rotate = degree;
this.rotating = true;
this.renderImage(function() {
_this4.rotating = false;
if (isFunction(options.rotated)) addListener(element, EVENT_ROTATED, options.rotated, { once: true });
dispatchEvent(element, EVENT_ROTATED, {
degree,
oldDegree
}, { cancelable: false });
});
}
return this;
},
scaleX: function scaleX(_scaleX) {
this.scale(_scaleX, this.imageData.scaleY);
return this;
},
scaleY: function scaleY(_scaleY) {
this.scale(this.imageData.scaleX, _scaleY);
return this;
},
scale: function scale(scaleX) {
var _this5 = this;
var scaleY = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : scaleX;
var element = this.element, options = this.options, imageData = this.imageData;
scaleX = Number(scaleX);
scaleY = Number(scaleY);
if (this.viewed && !this.played && options.scalable) {
var oldScaleX = imageData.scaleX;
var oldScaleY = imageData.scaleY;
var changed = false;
if (isNumber(scaleX)) changed = true;
else scaleX = oldScaleX;
if (isNumber(scaleY)) changed = true;
else scaleY = oldScaleY;
if (changed) {
if (isFunction(options.scale)) addListener(element, EVENT_SCALE, options.scale, { once: true });
if (dispatchEvent(element, EVENT_SCALE, {
scaleX,
scaleY,
oldScaleX,
oldScaleY
}) === false) return this;
imageData.scaleX = scaleX;
imageData.scaleY = scaleY;
this.scaling = true;
this.renderImage(function() {
_this5.scaling = false;
if (isFunction(options.scaled)) addListener(element, EVENT_SCALED, options.scaled, { once: true });
dispatchEvent(element, EVENT_SCALED, {
scaleX,
scaleY,
oldScaleX,
oldScaleY
}, { cancelable: false });
});
}
}
return this;
},
zoom: function zoom(ratio) {
var showTooltip = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : false;
var pivot = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : null;
var _originalEvent = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : null;
var imageData = this.imageData;
ratio = Number(ratio);
if (ratio < 0) ratio = 1 / (1 - ratio);
else ratio = 1 + ratio;
this.zoomTo(imageData.width * ratio / imageData.naturalWidth, showTooltip, pivot, _originalEvent);
return this;
},
zoomTo: function zoomTo(ratio) {
var _this6 = this;
var showTooltip = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : false;
var pivot = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : null;
var _originalEvent = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : null;
var _zoomable = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : false;
var element = this.element, options = this.options, pointers = this.pointers, imageData = this.imageData;
var x = imageData.x, y = imageData.y, width = imageData.width, height = imageData.height, naturalWidth = imageData.naturalWidth, naturalHeight = imageData.naturalHeight;
ratio = Math.max(0, ratio);
if (isNumber(ratio) && this.viewed && !this.played && (_zoomable || options.zoomable)) {
if (!_zoomable) {
var minZoomRatio = Math.max(.01, options.minZoomRatio);
var maxZoomRatio = Math.min(100, options.maxZoomRatio);
ratio = Math.min(Math.max(ratio, minZoomRatio), maxZoomRatio);
}
if (_originalEvent) switch (_originalEvent.type) {
case "wheel":
if (options.zoomRatio >= .055 && ratio > .95 && ratio < 1.05) ratio = 1;
break;
case "pointermove":
case "touchmove":
case "mousemove":
if (ratio > .99 && ratio < 1.01) ratio = 1;
break;
}
var newWidth = naturalWidth * ratio;
var newHeight = naturalHeight * ratio;
var offsetWidth = newWidth - width;
var offsetHeight = newHeight - height;
var oldRatio = imageData.ratio;
if (isFunction(options.zoom)) addListener(element, EVENT_ZOOM, options.zoom, { once: true });
if (dispatchEvent(element, EVENT_ZOOM, {
ratio,
oldRatio,
originalEvent: _originalEvent
}) === false) return this;
this.zooming = true;
if (_originalEvent) {
var offset = getOffset(this.viewer);
var center = pointers && Object.keys(pointers).length > 0 ? getPointersCenter(pointers) : {
pageX: _originalEvent.pageX,
pageY: _originalEvent.pageY
};
imageData.x -= offsetWidth * ((center.pageX - offset.left - x) / width);
imageData.y -= offsetHeight * ((center.pageY - offset.top - y) / height);
} else if (isPlainObject(pivot) && isNumber(pivot.x) && isNumber(pivot.y)) {
imageData.x -= offsetWidth * ((pivot.x - x) / width);
imageData.y -= offsetHeight * ((pivot.y - y) / height);
} else {
imageData.x -= offsetWidth / 2;
imageData.y -= offsetHeight / 2;
}
imageData.left = imageData.x;
imageData.top = imageData.y;
imageData.width = newWidth;
imageData.height = newHeight;
imageData.oldRatio = oldRatio;
imageData.ratio = ratio;
this.renderImage(function() {
_this6.zooming = false;
if (isFunction(options.zoomed)) addListener(element, EVENT_ZOOMED, options.zoomed, { once: true });
dispatchEvent(element, EVENT_ZOOMED, {
ratio,
oldRatio,
originalEvent: _originalEvent
}, { cancelable: false });
});
if (showTooltip) this.tooltip();
}
return this;
},
play: function play() {
var _this7 = this;
var fullscreen = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : false;
if (!this.isShown || this.played) return this;
var element = this.element, options = this.options;
if (isFunction(options.play)) addListener(element, EVENT_PLAY, options.play, { once: true });
if (dispatchEvent(element, EVENT_PLAY) === false) return this;
var player = this.player;
var onLoad = this.loadImage.bind(this);
var list = [];
var total = 0;
var index = 0;
this.played = true;
this.onLoadWhenPlay = onLoad;
if (fullscreen) this.requestFullscreen(fullscreen);
addClass(player, CLASS_SHOW);
forEach(this.items, function(item, i) {
var img = item.querySelector("img");
var image = document.createElement("img");
image.src = getData(img, "originalUrl");
image.alt = img.getAttribute("alt");
image.referrerPolicy = img.referrerPolicy;
total += 1;
addClass(image, CLASS_FADE);
toggleClass(image, CLASS_TRANSITION, options.transition);
if (hasClass(item, CLASS_ACTIVE)) {
addClass(image, CLASS_IN);
index = i;
}
list.push(image);
addListener(image, EVENT_LOAD, onLoad, { once: true });
player.appendChild(image);
});
if (isNumber(options.interval) && options.interval > 0) {
var prev = function prev() {
clearTimeout(_this7.playing.timeout);
removeClass(list[index], CLASS_IN);
index -= 1;
index = index >= 0 ? index : total - 1;
addClass(list[index], CLASS_IN);
_this7.playing.timeout = setTimeout(prev, options.interval);
};
var next = function next() {
clearTimeout(_this7.playing.timeout);
removeClass(list[index], CLASS_IN);
index += 1;
index = index < total ? index : 0;
addClass(list[index], CLASS_IN);
_this7.playing.timeout = setTimeout(next, options.interval);
};
if (total > 1) this.playing = {
prev,
next,
timeout: setTimeout(next, options.interval)
};
}
return this;
},
stop: function stop() {
var _this8 = this;
if (!this.played) return this;
var element = this.element, options = this.options;
if (isFunction(options.stop)) addListener(element, EVENT_STOP, options.stop, { once: true });
if (dispatchEvent(element, EVENT_STOP) === false) return this;
var player = this.player;
clearTimeout(this.playing.timeout);
this.playing = false;
this.played = false;
forEach(player.getElementsByTagName("img"), function(image) {
removeListener(image, EVENT_LOAD, _this8.onLoadWhenPlay);
});
removeClass(player, CLASS_SHOW);
player.innerHTML = "";
this.exitFullscreen();
return this;
},
full: function full() {
var _this9 = this;
var options = this.options, viewer = this.viewer, image = this.image, list = this.list;
if (!this.isShown || this.played || this.fulled || !options.inline) return this;
this.fulled = true;
this.open();
addClass(this.button, CLASS_FULLSCREEN_EXIT);
if (options.transition) {
removeClass(list, CLASS_TRANSITION);
if (this.viewed) removeClass(image, CLASS_TRANSITION);
}
addClass(viewer, CLASS_FIXED);
viewer.setAttribute("role", "dialog");
viewer.setAttribute("aria-labelledby", this.title.id);
viewer.setAttribute("aria-modal", true);
viewer.removeAttribute("style");
setStyle(viewer, { zIndex: options.zIndex });
if (options.focus) this.enforceFocus();
this.initContainer();
this.viewerData = assign({}, this.containerData);
this.renderList();
if (this.viewed) this.initImage(function() {
_this9.renderImage(function() {
if (options.transition) setTimeout(function() {
addClass(image, CLASS_TRANSITION);
addClass(list, CLASS_TRANSITION);
}, 0);
});
});
return this;
},
exit: function exit() {
var _this10 = this;
var options = this.options, viewer = this.viewer, image = this.image, list = this.list;
if (!this.isShown || this.played || !this.fulled || !options.inline) return this;
this.fulled = false;
this.close();
removeClass(this.button, CLASS_FULLSCREEN_EXIT);
if (options.transition) {
removeClass(list, CLASS_TRANSITION);
if (this.viewed) removeClass(image, CLASS_TRANSITION);
}
if (options.focus) this.clearEnforceFocus();
viewer.removeAttribute("role");
viewer.removeAttribute("aria-labelledby");
viewer.removeAttribute("aria-modal");
removeClass(viewer, CLASS_FIXED);
setStyle(viewer, { zIndex: options.zIndexInline });
this.viewerData = assign({}, this.parentData);
this.renderViewer();
this.renderList();
if (this.viewed) this.initImage(function() {
_this10.renderImage(function() {
if (options.transition) setTimeout(function() {
addClass(image, CLASS_TRANSITION);
addClass(list, CLASS_TRANSITION);
}, 0);
});
});
return this;
},
tooltip: function tooltip() {
var _this11 = this;
var options = this.options, tooltipBox = this.tooltipBox, imageData = this.imageData;
if (!this.viewed || this.played || !options.tooltip) return this;
tooltipBox.textContent = "".concat(Math.round(imageData.ratio * 100), "%");
if (!this.tooltipping) if (options.transition) {
if (this.fading) dispatchEvent(tooltipBox, EVENT_TRANSITION_END);
addClass(tooltipBox, CLASS_SHOW);
addClass(tooltipBox, CLASS_FADE);
addClass(tooltipBox, CLASS_TRANSITION);
tooltipBox.removeAttribute("aria-hidden");
tooltipBox.initialOffsetWidth = tooltipBox.offsetWidth;
addClass(tooltipBox, CLASS_IN);
} else {
addClass(tooltipBox, CLASS_SHOW);
tooltipBox.removeAttribute("aria-hidden");
}
else clearTimeout(this.tooltipping);
this.tooltipping = setTimeout(function() {
if (options.transition) {
addListener(tooltipBox, EVENT_TRANSITION_END, function() {
removeClass(tooltipBox, CLASS_SHOW);
removeClass(tooltipBox, CLASS_FADE);
removeClass(tooltipBox, CLASS_TRANSITION);
tooltipBox.setAttribute("aria-hidden", true);
_this11.fading = false;
}, { once: true });
removeClass(tooltipBox, CLASS_IN);
_this11.fading = true;
} else {
removeClass(tooltipBox, CLASS_SHOW);
tooltipBox.setAttribute("aria-hidden", true);
}
_this11.tooltipping = false;
}, 1e3);
return this;
},
toggle: function toggle() {
var _originalEvent = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : null;
if (this.imageData.ratio === 1) this.zoomTo(this.imageData.oldRatio, true, null, _originalEvent);
else this.zoomTo(1, true, null, _originalEvent);
return this;
},
reset: function reset() {
if (this.viewed && !this.played) {
this.imageData = assign({}, this.initialImageData);
this.renderImage();
}
return this;
},
update: function update() {
var _this12 = this;
var element = this.element, options = this.options, isImg = this.isImg;
if (isImg && !element.parentNode) return this.destroy();
var images = [];
forEach(isImg ? [element] : element.querySelectorAll("img"), function(image) {
if (isFunction(options.filter)) {
if (options.filter.call(_this12, image)) images.push(image);
} else if (_this12.getImageURL(image)) images.push(image);
});
if (!images.length) return this;
this.images = images;
this.length = images.length;
if (this.ready) {
var changedIndexes = [];
forEach(this.items, function(item, i) {
var img = item.querySelector("img");
var image = images[i];
if (image && img) {
if (image.src !== img.src || image.alt !== img.alt) changedIndexes.push(i);
} else changedIndexes.push(i);
});
setStyle(this.list, { width: "auto" });
this.initList();
if (this.isShown) if (this.length) {
if (this.viewed) {
var changedIndex = changedIndexes.indexOf(this.index);
if (changedIndex >= 0) {
this.viewed = false;
this.view(Math.max(Math.min(this.index - changedIndex, this.length - 1), 0));
} else {
var activeItem = this.items[this.index];
addClass(activeItem, CLASS_ACTIVE);
activeItem.setAttribute("aria-selected", true);
}
}
} else {
this.image = null;
this.viewed = false;
this.index = 0;
this.imageData = {};
this.canvas.innerHTML = "";
this.title.innerHTML = "";
}
} else this.build();
return this;
},
destroy: function destroy() {
var element = this.element, options = this.options;
if (!element[NAMESPACE]) return this;
this.destroyed = true;
if (this.ready) {
if (this.played) this.stop();
if (options.inline) {
if (this.fulled) this.exit();
this.unbind();
} else if (this.isShown) {
if (this.viewing) {
if (this.imageRendering) this.imageRendering.abort();
else if (this.imageInitializing) this.imageInitializing.abort();
}
if (this.hiding) this.transitioning.abort();
this.hidden();
} else if (this.showing) {
this.transitioning.abort();
this.hidden();
}
this.ready = false;
this.viewer.parentNode.removeChild(this.viewer);
} else if (options.inline) {
if (this.delaying) this.delaying.abort();
else if (this.initializing) this.initializing.abort();
}
if (!options.inline) removeListener(element, EVENT_CLICK, this.onStart);
element[NAMESPACE] = void 0;
return this;
}
};
var others = {
getImageURL: function getImageURL(image) {
var url = this.options.url;
if (isString(url)) url = image.getAttribute(url);
else if (isFunction(url)) url = url.call(this, image);
else url = "";
return url;
},
enforceFocus: function enforceFocus() {
var _this = this;
this.clearEnforceFocus();
addListener(document, EVENT_FOCUSIN, this.onFocusin = function(event) {
var viewer = _this.viewer;
var target = event.target;
if (target === document || target === viewer || viewer.contains(target)) return;
while (target) {
if (target.getAttribute("tabindex") !== null || target.getAttribute("aria-modal") === "true") return;
target = target.parentElement;
}
viewer.focus();
});
},
clearEnforceFocus: function clearEnforceFocus() {
if (this.onFocusin) {
removeListener(document, EVENT_FOCUSIN, this.onFocusin);
this.onFocusin = null;
}
},
open: function open() {
var body = this.body;
addClass(body, CLASS_OPEN);
if (this.scrollbarWidth > 0) body.style.paddingRight = "".concat(this.scrollbarWidth + (parseFloat(this.initialBodyComputedPaddingRight) || 0), "px");
},
close: function close() {
var body = this.body;
removeClass(body, CLASS_OPEN);
if (this.scrollbarWidth > 0) body.style.paddingRight = this.initialBodyPaddingRight;
},
shown: function shown() {
var element = this.element, options = this.options, viewer = this.viewer;
this.fulled = true;
this.isShown = true;
this.render();
this.bind();
this.showing = false;
if (options.focus) {
viewer.focus();
this.enforceFocus();
}
if (isFunction(options.shown)) addListener(element, EVENT_SHOWN, options.shown, { once: true });
if (dispatchEvent(element, EVENT_SHOWN) === false) return;
if (this.ready && this.isShown && !this.hiding) this.view(this.index);
},
hidden: function hidden() {
var element = this.element, options = this.options, viewer = this.viewer;
if (options.fucus) this.clearEnforceFocus();
this.fulled = false;
this.viewed = false;
this.isShown = false;
this.close();
this.unbind();
addClass(viewer, CLASS_HIDE);
viewer.removeAttribute("role");
viewer.removeAttribute("aria-labelledby");
viewer.removeAttribute("aria-modal");
viewer.setAttribute("aria-hidden", true);
this.resetList();
this.resetImage();
this.hiding = false;
if (!this.destroyed) {
if (isFunction(options.hidden)) addListener(element, EVENT_HIDDEN, options.hidden, { once: true });
dispatchEvent(element, EVENT_HIDDEN, null, { cancelable: false });
}
},
requestFullscreen: function requestFullscreen(options) {
var document = this.element.ownerDocument;
if (this.fulled && !(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement)) {
var documentElement = document.documentElement;
if (documentElement.requestFullscreen) if (isPlainObject(options)) documentElement.requestFullscreen(options);
else documentElement.requestFullscreen();
else if (documentElement.webkitRequestFullscreen) documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
else if (documentElement.mozRequestFullScreen) documentElement.mozRequestFullScreen();
else if (documentElement.msRequestFullscreen) documentElement.msRequestFullscreen();
}
},
exitFullscreen: function exitFullscreen() {
var document = this.element.ownerDocument;
if (this.fulled && (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement)) {
if (document.exitFullscreen) document.exitFullscreen();
else if (document.webkitExitFullscreen) document.webkitExitFullscreen();
else if (document.mozCancelFullScreen) document.mozCancelFullScreen();
else if (document.msExitFullscreen) document.msExitFullscreen();
}
},
change: function change(event) {
var options = this.options, pointers = this.pointers;
var pointer = pointers[Object.keys(pointers)[0]];
if (!pointer) return;
var offsetX = pointer.endX - pointer.startX;
var offsetY = pointer.endY - pointer.startY;
switch (this.action) {
case ACTION_MOVE:
this.move(offsetX, offsetY, event);
break;
case ACTION_ZOOM:
this.zoom(getMaxZoomRatio(pointers), false, null, event);
break;
case ACTION_SWITCH:
this.action = "switched";
var absoluteOffsetX = Math.abs(offsetX);
if (absoluteOffsetX > 1 && absoluteOffsetX > Math.abs(offsetY)) {
this.pointers = {};
if (offsetX > 1) this.prev(options.loop);
else if (offsetX < -1) this.next(options.loop);
}
break;
}
forEach(pointers, function(p) {
p.startX = p.endX;
p.startY = p.endY;
});
},
isSwitchable: function isSwitchable() {
var imageData = this.imageData, viewerData = this.viewerData;
return this.length > 1 && imageData.x >= 0 && imageData.y >= 0 && imageData.width <= viewerData.width && imageData.height <= viewerData.height;
}
};
var AnotherViewer = WINDOW.Viewer;
var getUniqueID = function(id) {
return function() {
id += 1;
return id;
};
}(-1);
var Viewer = function() {
function Viewer(element) {
var options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
_classCallCheck(this, Viewer);
if (!element || element.nodeType !== 1) throw new Error("The first argument is required and must be an element.");
this.element = element;
this.options = assign({}, DEFAULTS, isPlainObject(options) && options);
this.action = false;
this.fading = false;
this.fulled = false;
this.hiding = false;
this.imageClicked = false;
this.imageData = {};
this.index = this.options.initialViewIndex;
this.isImg = false;
this.isShown = false;
this.length = 0;
this.moving = false;
this.played = false;
this.playing = false;
this.pointers = {};
this.ready = false;
this.rotating = false;
this.scaling = false;
this.showing = false;
this.timeout = false;
this.tooltipping = false;
this.viewed = false;
this.viewing = false;
this.wheeling = false;
this.zooming = false;
this.id = getUniqueID();
this.init();
}
_createClass(Viewer, [{
key: "init",
value: function init() {
var _this = this;
var element = this.element, options = this.options;
if (element[NAMESPACE]) return;
element[NAMESPACE] = this;
if (options.focus && !options.keyboard) options.focus = false;
var isImg = element.localName === "img";
var images = [];
forEach(isImg ? [element] : element.querySelectorAll("img"), function(image) {
if (isFunction(options.filter)) {
if (options.filter.call(_this, image)) images.push(image);
} else if (_this.getImageURL(image)) images.push(image);
});
this.isImg = isImg;
this.length = images.length;
this.images = images;
this.initBody();
if (isUndefined(document.createElement(NAMESPACE).style.transition)) options.transition = false;
if (options.inline) {
var count = 0;
var progress = function progress() {
count += 1;
if (count === _this.length) {
var timeout;
_this.initializing = false;
_this.delaying = { abort: function abort() {
clearTimeout(timeout);
} };
timeout = setTimeout(function() {
_this.delaying = false;
_this.build();
}, 0);
}
};
this.initializing = { abort: function abort() {
forEach(images, function(image) {
if (!image.complete) {
removeListener(image, EVENT_LOAD, progress);
removeListener(image, EVENT_ERROR, progress);
}
});
} };
forEach(images, function(image) {
if (image.complete) progress();
else {
var onLoad;
var onError;
addListener(image, EVENT_LOAD, onLoad = function onLoad() {
removeListener(image, EVENT_ERROR, onError);
progress();
}, { once: true });
addListener(image, EVENT_ERROR, onError = function onError() {
removeListener(image, EVENT_LOAD, onLoad);
progress();
}, { once: true });
}
});
} else addListener(element, EVENT_CLICK, this.onStart = function(_ref) {
var target = _ref.target;
if (target.localName === "img" && (!isFunction(options.filter) || options.filter.call(_this, target))) _this.view(_this.images.indexOf(target));
});
}
}, {
key: "build",
value: function build() {
if (this.ready) return;
var element = this.element, options = this.options;
var parent = element.parentNode;
var template = document.createElement("div");
template.innerHTML = TEMPLATE;
var viewer = template.querySelector(".".concat(NAMESPACE, "-container"));
var title = viewer.querySelector(".".concat(NAMESPACE, "-title"));
var toolbar = viewer.querySelector(".".concat(NAMESPACE, "-toolbar"));
var navbar = viewer.querySelector(".".concat(NAMESPACE, "-navbar"));
var button = viewer.querySelector(".".concat(NAMESPACE, "-button"));
var canvas = viewer.querySelector(".".concat(NAMESPACE, "-canvas"));
this.parent = parent;
this.viewer = viewer;
this.title = title;
this.toolbar = toolbar;
this.navbar = navbar;
this.button = button;
this.canvas = canvas;
this.footer = viewer.querySelector(".".concat(NAMESPACE, "-footer"));
this.tooltipBox = viewer.querySelector(".".concat(NAMESPACE, "-tooltip"));
this.player = viewer.querySelector(".".concat(NAMESPACE, "-player"));
this.list = viewer.querySelector(".".concat(NAMESPACE, "-list"));
viewer.id = "".concat(NAMESPACE).concat(this.id);
title.id = "".concat(NAMESPACE, "Title").concat(this.id);
addClass(title, !options.title ? CLASS_HIDE : getResponsiveClass(Array.isArray(options.title) ? options.title[0] : options.title));
addClass(navbar, !options.navbar ? CLASS_HIDE : getResponsiveClass(options.navbar));
toggleClass(button, CLASS_HIDE, !options.button);
if (options.keyboard) button.setAttribute("tabindex", 0);
if (options.backdrop) {
addClass(viewer, "".concat(NAMESPACE, "-backdrop"));
if (!options.inline && options.backdrop !== "static") setData(canvas, DATA_ACTION, "hide");
}
if (isString(options.className) && options.className) options.className.split(REGEXP_SPACES).forEach(function(className) {
addClass(viewer, className);
});
if (options.toolbar) {
var list = document.createElement("ul");
var custom = isPlainObject(options.toolbar);
var zoomButtons = BUTTONS.slice(0, 3);
var rotateButtons = BUTTONS.slice(7, 9);
var scaleButtons = BUTTONS.slice(9);
if (!custom) addClass(toolbar, getResponsiveClass(options.toolbar));
forEach(custom ? options.toolbar : BUTTONS, function(value, index) {
var deep = custom && isPlainObject(value);
var name = custom ? hyphenate(index) : value;
var show = deep && !isUndefined(value.show) ? value.show : value;
if (!show || !options.zoomable && zoomButtons.indexOf(name) !== -1 || !options.rotatable && rotateButtons.indexOf(name) !== -1 || !options.scalable && scaleButtons.indexOf(name) !== -1) return;
var size = deep && !isUndefined(value.size) ? value.size : value;
var click = deep && !isUndefined(value.click) ? value.click : value;
var item = document.createElement("li");
if (options.keyboard) item.setAttribute("tabindex", 0);
item.setAttribute("role", "button");
addClass(item, "".concat(NAMESPACE, "-").concat(name));
if (!isFunction(click)) setData(item, DATA_ACTION, name);
if (isNumber(show)) addClass(item, getResponsiveClass(show));
if (["small", "large"].indexOf(size) !== -1) addClass(item, "".concat(NAMESPACE, "-").concat(size));
else if (name === "play") addClass(item, "".concat(NAMESPACE, "-large"));
if (isFunction(click)) addListener(item, EVENT_CLICK, click);
list.appendChild(item);
});
toolbar.appendChild(list);
} else addClass(toolbar, CLASS_HIDE);
if (!options.rotatable) {
var rotates = toolbar.querySelectorAll("li[class*=\"rotate\"]");
addClass(rotates, CLASS_INVISIBLE);
forEach(rotates, function(rotate) {
toolbar.appendChild(rotate);
});
}
if (options.inline) {
addClass(button, CLASS_FULLSCREEN);
setStyle(viewer, { zIndex: options.zIndexInline });
if (window.getComputedStyle(parent).position === "static") setStyle(parent, { position: "relative" });
parent.insertBefore(viewer, element.nextSibling);
} else {
addClass(button, CLASS_CLOSE);
addClass(viewer, CLASS_FIXED);
addClass(viewer, CLASS_FADE);
addClass(viewer, CLASS_HIDE);
setStyle(viewer, { zIndex: options.zIndex });
var container = options.container;
if (isString(container)) container = element.ownerDocument.querySelector(container);
if (!container) container = this.body;
container.appendChild(viewer);
}
if (options.inline) {
this.render();
this.bind();
this.isShown = true;
}
this.ready = true;
if (isFunction(options.ready)) addListener(element, EVENT_READY, options.ready, { once: true });
if (dispatchEvent(element, EVENT_READY) === false) {
this.ready = false;
return;
}
if (this.ready && options.inline) this.view(this.index);
}
}], [{
key: "noConflict",
value: function noConflict() {
window.Viewer = AnotherViewer;
return Viewer;
}
}, {
key: "setDefaults",
value: function setDefaults(options) {
assign(DEFAULTS, isPlainObject(options) && options);
}
}]);
return Viewer;
}();
assign(Viewer.prototype, render, events, handlers, methods, others);
return Viewer;
}));
}));
var require_md5 = __commonJSMin(((exports, module) => {
(function($) {
"use strict";
function safeAdd(x, y) {
var lsw = (x & 65535) + (y & 65535);
return (x >> 16) + (y >> 16) + (lsw >> 16) << 16 | lsw & 65535;
}
function bitRotateLeft(num, cnt) {
return num << cnt | num >>> 32 - cnt;
}
function md5cmn(q, a, b, x, s, t) {
return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b);
}
function md5ff(a, b, c, d, x, s, t) {
return md5cmn(b & c | ~b & d, a, b, x, s, t);
}
function md5gg(a, b, c, d, x, s, t) {
return md5cmn(b & d | c & ~d, a, b, x, s, t);
}
function md5hh(a, b, c, d, x, s, t) {
return md5cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5ii(a, b, c, d, x, s, t) {
return md5cmn(c ^ (b | ~d), a, b, x, s, t);
}
function binlMD5(x, len) {
x[len >> 5] |= 128 << len % 32;
x[(len + 64 >>> 9 << 4) + 14] = len;
var i;
var olda;
var oldb;
var oldc;
var oldd;
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
for (i = 0; i < x.length; i += 16) {
olda = a;
oldb = b;
oldc = c;
oldd = d;
a = md5ff(a, b, c, d, x[i], 7, -680876936);
d = md5ff(d, a, b, c, x[i + 1], 12, -389564586);
c = md5ff(c, d, a, b, x[i + 2], 17, 606105819);
b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330);
a = md5ff(a, b, c, d, x[i + 4], 7, -176418897);
d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426);
c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341);
b = md5ff(b, c, d, a, x[i + 7], 22, -45705983);
a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416);
d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417);
c = md5ff(c, d, a, b, x[i + 10], 17, -42063);
b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162);
a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682);
d = md5ff(d, a, b, c, x[i + 13], 12, -40341101);
c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290);
b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329);
a = md5gg(a, b, c, d, x[i + 1], 5, -165796510);
d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632);
c = md5gg(c, d, a, b, x[i + 11], 14, 643717713);
b = md5gg(b, c, d, a, x[i], 20, -373897302);
a = md5gg(a, b, c, d, x[i + 5], 5, -701558691);
d = md5gg(d, a, b, c, x[i + 10], 9, 38016083);
c = md5gg(c, d, a, b, x[i + 15], 14, -660478335);
b = md5gg(b, c, d, a, x[i + 4], 20, -405537848);
a = md5gg(a, b, c, d, x[i + 9], 5, 568446438);
d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690);
c = md5gg(c, d, a, b, x[i + 3], 14, -187363961);
b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501);
a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467);
d = md5gg(d, a, b, c, x[i + 2], 9, -51403784);
c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473);
b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734);
a = md5hh(a, b, c, d, x[i + 5], 4, -378558);
d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463);
c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562);
b = md5hh(b, c, d, a, x[i + 14], 23, -35309556);
a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060);
d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353);
c = md5hh(c, d, a, b, x[i + 7], 16, -155497632);
b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640);
a = md5hh(a, b, c, d, x[i + 13], 4, 681279174);
d = md5hh(d, a, b, c, x[i], 11, -358537222);
c = md5hh(c, d, a, b, x[i + 3], 16, -722521979);
b = md5hh(b, c, d, a, x[i + 6], 23, 76029189);
a = md5hh(a, b, c, d, x[i + 9], 4, -640364487);
d = md5hh(d, a, b, c, x[i + 12], 11, -421815835);
c = md5hh(c, d, a, b, x[i + 15], 16, 530742520);
b = md5hh(b, c, d, a, x[i + 2], 23, -995338651);
a = md5ii(a, b, c, d, x[i], 6, -198630844);
d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415);
c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905);
b = md5ii(b, c, d, a, x[i + 5], 21, -57434055);
a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571);
d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606);
c = md5ii(c, d, a, b, x[i + 10], 15, -1051523);
b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799);
a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359);
d = md5ii(d, a, b, c, x[i + 15], 10, -30611744);
c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380);
b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649);
a = md5ii(a, b, c, d, x[i + 4], 6, -145523070);
d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379);
c = md5ii(c, d, a, b, x[i + 2], 15, 718787259);
b = md5ii(b, c, d, a, x[i + 9], 21, -343485551);
a = safeAdd(a, olda);
b = safeAdd(b, oldb);
c = safeAdd(c, oldc);
d = safeAdd(d, oldd);
}
return [
a,
b,
c,
d
];
}
function binl2rstr(input) {
var i;
var output = "";
var length32 = input.length * 32;
for (i = 0; i < length32; i += 8) output += String.fromCharCode(input[i >> 5] >>> i % 32 & 255);
return output;
}
function rstr2binl(input) {
var i;
var output = [];
output[(input.length >> 2) - 1] = void 0;
for (i = 0; i < output.length; i += 1) output[i] = 0;
var length8 = input.length * 8;
for (i = 0; i < length8; i += 8) output[i >> 5] |= (input.charCodeAt(i / 8) & 255) << i % 32;
return output;
}
function rstrMD5(s) {
return binl2rstr(binlMD5(rstr2binl(s), s.length * 8));
}
function rstrHMACMD5(key, data) {
var i;
var bkey = rstr2binl(key);
var ipad = [];
var opad = [];
var hash;
ipad[15] = opad[15] = void 0;
if (bkey.length > 16) bkey = binlMD5(bkey, key.length * 8);
for (i = 0; i < 16; i += 1) {
ipad[i] = bkey[i] ^ 909522486;
opad[i] = bkey[i] ^ 1549556828;
}
hash = binlMD5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
return binl2rstr(binlMD5(opad.concat(hash), 640));
}
function rstr2hex(input) {
var hexTab = "0123456789abcdef";
var output = "";
var x;
var i;
for (i = 0; i < input.length; i += 1) {
x = input.charCodeAt(i);
output += hexTab.charAt(x >>> 4 & 15) + hexTab.charAt(x & 15);
}
return output;
}
function str2rstrUTF8(input) {
return unescape(encodeURIComponent(input));
}
function rawMD5(s) {
return rstrMD5(str2rstrUTF8(s));
}
function hexMD5(s) {
return rstr2hex(rawMD5(s));
}
function rawHMACMD5(k, d) {
return rstrHMACMD5(str2rstrUTF8(k), str2rstrUTF8(d));
}
function hexHMACMD5(k, d) {
return rstr2hex(rawHMACMD5(k, d));
}
function md5(string, key, raw) {
if (!key) {
if (!raw) return hexMD5(string);
return rawMD5(string);
}
if (!raw) return hexHMACMD5(key, string);
return rawHMACMD5(key, string);
}
if (typeof define === "function" && define.amd) define(function() {
return md5;
});
else if (typeof module === "object" && module.exports) module.exports = md5;
else $.md5 = md5;
})(exports);
}));
var import_toastify = __toESM(require_toastify(), 1);
var import_localforage = __toESM(require_localforage(), 1);
var import_viewer = __toESM(require_viewer(), 1);
var import_md5 = __toESM(require_md5(), 1);
_css("/*!\n * Toastify js 1.12.0\n * https://github.com/apvarun/toastify-js\n * @license MIT licensed\n *\n * Copyright (C) 2018 Varun A P\n */\n.toastify{color:#fff;opacity:0;cursor:pointer;z-index:2147483647;background:linear-gradient(135deg,#73a5ff,#5477f5);border-radius:2px;max-width:calc(50% - 20px);padding:12px 20px;text-decoration:none;transition:all .4s cubic-bezier(.215,.61,.355,1);display:inline-block;position:fixed;box-shadow:0 3px 6px -1px #0000001f,0 10px 36px -4px #4d60e84d}.toastify.on{opacity:1}.toast-close{color:#fff;cursor:pointer;opacity:.4;background:0 0;border:0;padding:0 5px;font-family:inherit;font-size:1em}.toastify-right{right:15px}.toastify-left{left:15px}.toastify-top{top:-150px}.toastify-bottom{bottom:-150px}.toastify-rounded{border-radius:25px}.toastify-avatar{border-radius:2px;width:1.5em;height:1.5em;margin:-7px 5px}.toastify-center{max-width:-moz-fit-content;margin-left:auto;margin-right:auto;left:0;right:0}@media only screen and (width<=360px){.toastify-right,.toastify-left{max-width:fit-content;margin-left:auto;margin-right:auto;left:0;right:0}}");
_css("/*!\n * Viewer.js v1.11.1\n * https://fengyuanchen.github.io/viewerjs\n *\n * Copyright 2015-present Chen Fengyuan\n * Released under the MIT license\n *\n * Date: 2022-11-06T05:18:17.414Z\n */\n.viewer-close:before,.viewer-flip-horizontal:before,.viewer-flip-vertical:before,.viewer-fullscreen-exit:before,.viewer-fullscreen:before,.viewer-next:before,.viewer-one-to-one:before,.viewer-play:before,.viewer-prev:before,.viewer-reset:before,.viewer-rotate-left:before,.viewer-rotate-right:before,.viewer-zoom-in:before,.viewer-zoom-out:before{color:#0000;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARgAAAAUCAYAAABWOyJDAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAQPSURBVHic7Zs/iFxVFMa/0U2UaJGksUgnIVhYxVhpjDbZCBmLdAYECxsRFBTUamcXUiSNncgKQbSxsxH8gzAP3FU2jY0kKKJNiiiIghFlccnP4p3nPCdv3p9778vsLOcHB2bfveeb7955c3jvvNkBIMdxnD64a94GHMfZu3iBcRynN7zAOI7TG15gHCeeNUkr8zaxG2lbYDYsdgMbktBsP03jdQwljSXdtBhLOmtjowC9Mg9L+knSlcD8TNKpSA9lBpK2JF2VdDSR5n5J64m0qli399hNFMUlpshQii5jbXTbHGviB0nLNeNDSd9VO4A2UdB2fp+x0eCnaXxWXGA2X0au/3HgN9P4LFCjIANOJdrLr0zzZ+BEpNYDwKbpnQMeAw4m8HjQtM6Z9qa917zPQwFr3M5KgA6J5rTJCdFZJj9/lyvGhsDvwFNVuV2MhhjrK6b9bFiE+j1r87eBl4HDwCF7/U/k+ofAX5b/EXBv5JoLMuILzf3Ap6Z3EzgdqHMCuF7hcQf4HDgeoHnccncqdK/TvSDWffFXI/exICY/xZyqc6XLWF1UFZna4gJ7q8BsRvgd2/xXpo6P+D9dfT7PpECtA3cnWPM0GXGFZh/wgWltA+cDNC7X+AP4GzjZQe+k5dRxuYPeiuXU7e1qwLpDz7dFjXKRaSwuMLvAlG8zZlG+YmiK1HoFqT7wP2z+4Q45TfEGcMt01xLoNZEBTwRqD4BLpnMLeC1A41UmVxsXgXeBayV/Wx20rpTyrpnWRft7p6O/FdqzGrDukPNtkaMoMo3FBdBSQMOnYBCReyf05s126fU9ytfX98+mY54Kxnp7S9K3kj6U9KYdG0h6UdLbkh7poFXMfUnSOyVvL0h6VtIXHbS6nOP+s/Zm9mvyXW1uuC9ohZ72E9uDmXWLJOB1GxsH+DxPftsB8B6wlGDN02TAkxG6+4D3TWsbeC5CS8CDFce+AW500LhhOW2020TRjK3b21HEmgti9m0RonxbdMZeVzV+/4tF3cBpP7E9mKHNL5q8h5g0eYsCMQz0epq8gQrwMXAgcs0FGXGFRcB9wCemF9PkbYqM/Bas7fxLwNeJPdTdpo4itQti8lPMqTpXuozVRVXPpbHI3KkNTB1NfkL81j2mvhDp91HgV9MKuRIqrykj3WPq4rHyL+axj8/qGPmTqi6F9YDlHOvJU6oYcTsh/TYSzWmTE6JT19CtLTJt32D6CmHe0eQn1O8z5AXgT4sx4Vcu0/EQecMydB8z0hUWkTd2t4CrwNEePqMBcAR4mrBbwyXLPWJa8zrXmmLEhNBmfpkuY2102xxrih+pb+ieAb6vGhuA97UcJ5KR8gZ77K+99xxeYBzH6Q3/Z0fHcXrDC4zjOL3hBcZxnN74F+zlvXFWXF9PAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:280px;width:20px;height:20px;font-size:0;line-height:0;display:block}.viewer-zoom-in:before{content:\"Zoom In\";background-position:0 0}.viewer-zoom-out:before{content:\"Zoom Out\";background-position:-20px 0}.viewer-one-to-one:before{content:\"One to One\";background-position:-40px 0}.viewer-reset:before{content:\"Reset\";background-position:-60px 0}.viewer-prev:before{content:\"Previous\";background-position:-80px 0}.viewer-play:before{content:\"Play\";background-position:-100px 0}.viewer-next:before{content:\"Next\";background-position:-120px 0}.viewer-rotate-left:before{content:\"Rotate Left\";background-position:-140px 0}.viewer-rotate-right:before{content:\"Rotate Right\";background-position:-160px 0}.viewer-flip-horizontal:before{content:\"Flip Horizontal\";background-position:-180px 0}.viewer-flip-vertical:before{content:\"Flip Vertical\";background-position:-200px 0}.viewer-fullscreen:before{content:\"Enter Full Screen\";background-position:-220px 0}.viewer-fullscreen-exit:before{content:\"Exit Full Screen\";background-position:-240px 0}.viewer-close:before{content:\"Close\";background-position:-260px 0}.viewer-container{-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;user-select:none;direction:ltr;font-size:0;line-height:0;position:absolute;inset:0;overflow:hidden}.viewer-container ::-moz-selection{background-color:#0000}.viewer-container::-moz-selection{background-color:#0000}.viewer-container ::selection{background-color:#0000}.viewer-container::selection{background-color:#0000}.viewer-container:focus{outline:0}.viewer-container img{width:100%;height:auto;display:block;min-width:0!important;max-width:none!important;min-height:0!important;max-height:none!important}.viewer-canvas{position:absolute;inset:0;overflow:hidden}.viewer-canvas>img{width:auto;height:auto;margin:15px auto;max-width:90%!important}.viewer-footer{text-align:center;position:absolute;bottom:0;left:0;right:0;overflow:hidden}.viewer-navbar{background-color:#00000080;overflow:hidden}.viewer-list{box-sizing:content-box;height:50px;margin:0;padding:1px 0;overflow:hidden}.viewer-list>li{color:#0000;cursor:pointer;float:left;opacity:.5;width:30px;height:50px;font-size:0;line-height:0;transition:opacity .15s;overflow:hidden}.viewer-list>li:focus,.viewer-list>li:hover{opacity:.75}.viewer-list>li:focus{outline:0}.viewer-list>li+li{margin-left:1px}.viewer-list>.viewer-loading{position:relative}.viewer-list>.viewer-loading:after{border-width:2px;width:20px;height:20px;margin-top:-10px;margin-left:-10px}.viewer-list>.viewer-active,.viewer-list>.viewer-active:focus,.viewer-list>.viewer-active:hover{opacity:1}.viewer-player{cursor:none;z-index:1;background-color:#000;display:none;bottom:0;right:0}.viewer-player,.viewer-player>img{position:absolute;top:0;left:0}.viewer-toolbar>ul{margin:0 auto 5px;padding:6px 3px;display:inline-block;overflow:hidden}.viewer-toolbar>ul>li{cursor:pointer;float:left;background-color:#00000080;border-radius:50%;width:24px;height:24px;transition:background-color .15s;overflow:hidden}.viewer-toolbar>ul>li:focus,.viewer-toolbar>ul>li:hover{background-color:#000c}.viewer-toolbar>ul>li:focus{z-index:1;outline:0;position:relative;box-shadow:0 0 3px #fff}.viewer-toolbar>ul>li:before{margin:2px}.viewer-toolbar>ul>li+li{margin-left:1px}.viewer-toolbar>ul>.viewer-small{width:18px;height:18px;margin-top:3px;margin-bottom:3px}.viewer-toolbar>ul>.viewer-small:before{margin:-1px}.viewer-toolbar>ul>.viewer-large{width:30px;height:30px;margin-top:-3px;margin-bottom:-3px}.viewer-toolbar>ul>.viewer-large:before{margin:5px}.viewer-tooltip{color:#fff;text-align:center;background-color:#000c;border-radius:10px;width:50px;height:20px;margin-top:-10px;margin-left:-25px;font-size:12px;line-height:20px;display:none;position:absolute;top:50%;left:50%}.viewer-title{color:#ccc;opacity:.8;text-overflow:ellipsis;white-space:nowrap;max-width:90%;min-height:14px;margin:5px 5%;font-size:12px;line-height:1.2;transition:opacity .15s;display:inline-block;overflow:hidden}.viewer-title:hover{opacity:1}.viewer-button{-webkit-app-region:no-drag;cursor:pointer;background-color:#00000080;border-radius:50%;width:80px;height:80px;transition:background-color .15s;position:absolute;top:-40px;right:-40px;overflow:hidden}.viewer-button:focus,.viewer-button:hover{background-color:#000c}.viewer-button:focus{outline:0;box-shadow:0 0 3px #fff}.viewer-button:before{position:absolute;bottom:15px;left:15px}.viewer-fixed{position:fixed}.viewer-open{overflow:hidden}.viewer-show{display:block}.viewer-hide{display:none}.viewer-backdrop{background-color:#00000080}.viewer-invisible{visibility:hidden}.viewer-move{cursor:move;cursor:grab}.viewer-fade{opacity:0}.viewer-in{opacity:1}.viewer-transition{transition:all .3s}@keyframes viewer-spinner{0%{transform:rotate(0)}to{transform:rotate(1turn)}}.viewer-loading:after{content:\"\";z-index:1;border:4px solid #ffffff1a;border-left-color:#ffffff80;border-radius:50%;width:40px;height:40px;margin-top:-20px;margin-left:-20px;animation:1s linear infinite viewer-spinner;display:inline-block;position:absolute;top:50%;left:50%}@media (width<=767px){.viewer-hide-xs-down{display:none}}@media (width<=991px){.viewer-hide-sm-down{display:none}}@media (width<=1199px){.viewer-hide-md-down{display:none}}");
_css(".tabulator{text-align:left;background-color:#fff;font-size:14px;position:relative;overflow:hidden;transform:translateZ(0)}.tabulator[tabulator-layout=fitDataFill] .tabulator-tableholder .tabulator-table{min-width:100%}.tabulator[tabulator-layout=fitDataTable]{display:inline-block}.tabulator.tabulator-block-select,.tabulator.tabulator-ranges .tabulator-cell:not(.tabulator-editing){-webkit-user-select:none;user-select:none}.tabulator .tabulator-header{box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;-o-user-select:none;white-space:nowrap;border-bottom:1px solid #999;outline:none;width:100%;position:relative;overflow:hidden}.tabulator .tabulator-header.tabulator-header-hidden{display:none}.tabulator .tabulator-header .tabulator-header-contents{position:relative;overflow:hidden}.tabulator .tabulator-header .tabulator-header-contents .tabulator-headers{display:inline-block}.tabulator .tabulator-header .tabulator-col{box-sizing:border-box;text-align:left;vertical-align:bottom;background:#f9fafb;border-right:1px solid #ddd;flex-direction:column;justify-content:flex-start;display:inline-flex;position:relative;overflow:hidden}.tabulator .tabulator-header .tabulator-col.tabulator-moving{pointer-events:none;background:#dae1e7;border:1px solid #999;position:absolute}.tabulator .tabulator-header .tabulator-col.tabulator-range-highlight{color:#000;background-color:#d6d6d6}.tabulator .tabulator-header .tabulator-col.tabulator-range-selected{color:#fff;background-color:#3876ca}.tabulator .tabulator-header .tabulator-col .tabulator-col-content{box-sizing:border-box;padding:4px;position:relative}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-header-popup-button{padding:0 8px}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-header-popup-button:hover{cursor:pointer;opacity:.6}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title-holder{position:relative}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title{box-sizing:border-box;text-overflow:ellipsis;vertical-align:bottom;white-space:nowrap;width:100%;overflow:hidden}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title.tabulator-col-title-wrap{text-overflow:clip;white-space:normal}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title .tabulator-title-editor{box-sizing:border-box;background:#fff;border:1px solid #999;width:100%;padding:1px}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title .tabulator-header-popup-button+.tabulator-title-editor{width:calc(100% - 22px)}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter{align-items:center;display:flex;position:absolute;top:0;bottom:0;right:4px}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{border-bottom:6px solid #bbb;border-left:6px solid #0000;border-right:6px solid #0000;width:0;height:0}.tabulator .tabulator-header .tabulator-col.tabulator-col-group .tabulator-col-group-cols{border-top:1px solid #ddd;margin-right:-1px;display:flex;position:relative;overflow:hidden}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter{box-sizing:border-box;text-align:center;width:100%;margin-top:2px;position:relative}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter textarea{height:auto!important}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter svg{margin-top:3px}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter input::-ms-clear{width:0;height:0}.tabulator .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-title{padding-right:25px}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-header .tabulator-col.tabulator-sortable.tabulator-col-sorter-element:hover{cursor:pointer;background-color:#dae1e7}}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=none] .tabulator-col-content .tabulator-col-sorter{color:#bbb}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=none] .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover{cursor:pointer;border-bottom:6px solid #555}}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=none] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{border-top:none;border-bottom:6px solid #bbb}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=ascending] .tabulator-col-content .tabulator-col-sorter{color:#666}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=ascending] .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover{cursor:pointer;border-bottom:6px solid #555}}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=ascending] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{border-top:none;border-bottom:6px solid #666}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=descending] .tabulator-col-content .tabulator-col-sorter{color:#666}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=descending] .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover{cursor:pointer;border-top:6px solid #555}}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=descending] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{color:#666;border-top:6px solid #666;border-bottom:none}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical .tabulator-col-content .tabulator-col-title{text-orientation:mixed;writing-mode:vertical-rl;justify-content:center;align-items:center;display:flex}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-col-vertical-flip .tabulator-col-title{transform:rotate(180deg)}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-sortable .tabulator-col-title{padding-top:20px;padding-right:0}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-sortable.tabulator-col-vertical-flip .tabulator-col-title{padding-bottom:20px;padding-right:0}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-sortable .tabulator-col-sorter{justify-content:center;inset:4px 0 auto}.tabulator .tabulator-header .tabulator-frozen{z-index:11;position:sticky;left:0}.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-left{border-right:2px solid #ddd}.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-right{border-left:2px solid #ddd}.tabulator .tabulator-header .tabulator-calcs-holder{box-sizing:border-box;border-top:1px solid #ddd;border-bottom:1px solid #ddd;display:inline-block;background:#fff!important}.tabulator .tabulator-header .tabulator-calcs-holder .tabulator-row{background:#fff!important}.tabulator .tabulator-header .tabulator-calcs-holder .tabulator-row .tabulator-col-resize-handle{display:none}.tabulator .tabulator-header .tabulator-frozen-rows-holder{display:inline-block}.tabulator .tabulator-header .tabulator-frozen-rows-holder:empty{display:none}.tabulator .tabulator-tableholder{-webkit-overflow-scrolling:touch;white-space:nowrap;width:100%;position:relative;overflow:auto}.tabulator .tabulator-tableholder:focus{outline:none}.tabulator .tabulator-tableholder .tabulator-placeholder{box-sizing:border-box;justify-content:center;align-items:center;width:100%;min-width:100%;display:flex}.tabulator .tabulator-tableholder .tabulator-placeholder[tabulator-render-mode=virtual]{min-height:100%}.tabulator .tabulator-tableholder .tabulator-placeholder .tabulator-placeholder-contents{color:#ccc;text-align:center;white-space:normal;padding:10px;font-size:20px;font-weight:700;display:inline-block}.tabulator .tabulator-tableholder .tabulator-table{color:#333;white-space:nowrap;background-color:#fff;display:inline-block;position:relative;overflow:visible}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs{font-weight:700;background:#e2e2e2!important}.tabulator .tabulator-tableholder .tabulator-range-overlay{pointer-events:none;z-index:10;position:absolute;inset:0}.tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range{box-sizing:border-box;border:1px solid #2975dd;position:absolute}.tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range.tabulator-range-active:after{content:\"\";background-color:#2975dd;border-radius:999px;width:6px;height:6px;position:absolute;bottom:-3px;right:-3px}.tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range-cell-active{box-sizing:border-box;border:2px solid #2975dd;position:absolute}.tabulator .tabulator-footer{color:#555;-webkit-user-select:none;user-select:none;-khtml-user-select:none;-o-user-select:none;white-space:nowrap;background-color:#fff;border-top:1px solid #999;font-weight:700}.tabulator .tabulator-footer .tabulator-footer-contents{flex-direction:row;justify-content:space-between;align-items:center;padding:5px 10px;display:flex}.tabulator .tabulator-footer .tabulator-footer-contents:empty{display:none}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs{margin-top:-5px;overflow-x:auto}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs .tabulator-spreadsheet-tab{border:1px solid #22242626;border-top:none;border-bottom-right-radius:5px;border-bottom-left-radius:5px;padding:5px;font-size:.9em;display:inline-block}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs .tabulator-spreadsheet-tab:hover{cursor:pointer;opacity:.7}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs .tabulator-spreadsheet-tab.tabulator-spreadsheet-tab-active{background:#fff}.tabulator .tabulator-footer .tabulator-calcs-holder{box-sizing:border-box;text-align:left;border-top:1px solid #ddd;border-bottom:1px solid #ddd;width:100%;overflow:hidden}.tabulator .tabulator-footer .tabulator-calcs-holder .tabulator-row{display:inline-block}.tabulator .tabulator-footer .tabulator-calcs-holder .tabulator-row .tabulator-col-resize-handle{display:none}.tabulator .tabulator-footer .tabulator-calcs-holder:only-child{margin-bottom:-5px}.tabulator .tabulator-footer>*+.tabulator-page-counter{margin-left:10px}.tabulator .tabulator-footer .tabulator-page-counter{font-weight:400}.tabulator .tabulator-footer .tabulator-paginator{color:#555;font-family:inherit;font-size:inherit;font-weight:inherit;text-align:right;flex:1}.tabulator .tabulator-footer .tabulator-page-size{border:1px solid #aaa;border-radius:3px;margin:0 5px;padding:2px 5px;display:inline-block}.tabulator .tabulator-footer .tabulator-pages{margin:0 7px}.tabulator .tabulator-footer .tabulator-page{background:#fff3;border:1px solid #aaa;border-radius:3px;margin:0 2px;padding:2px 5px;display:inline-block}.tabulator .tabulator-footer .tabulator-page.active{color:#d00}.tabulator .tabulator-footer .tabulator-page:disabled{opacity:.5}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-footer .tabulator-page:not(disabled):hover{color:#fff;cursor:pointer;background:#0003}}.tabulator .tabulator-col-resize-handle{vertical-align:middle;z-index:11;width:6px;margin-left:-3px;margin-right:-3px;display:inline-block;position:relative}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-col-resize-handle:hover{cursor:ew-resize}}.tabulator .tabulator-col-resize-handle:last-of-type{width:3px;margin-right:0}.tabulator .tabulator-col-resize-guide{opacity:.5;background-color:#999;width:4px;height:100%;margin-left:-.5px;position:absolute;top:0}.tabulator .tabulator-row-resize-guide{opacity:.5;background-color:#999;width:100%;height:4px;margin-top:-.5px;position:absolute;left:0}.tabulator .tabulator-alert{text-align:center;z-index:100;background:#0006;align-items:center;width:100%;height:100%;display:flex;position:absolute;top:0;left:0}.tabulator .tabulator-alert .tabulator-alert-msg{background:#fff;border-radius:10px;margin:0 auto;padding:10px 20px;font-size:16px;font-weight:700;display:inline-block}.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg{color:#000;border:4px solid #333}.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-error{color:#590000;border:4px solid #d00}.tabulator-row{box-sizing:border-box;background-color:#fff;min-height:22px;position:relative}@media (hover:hover) and (pointer:fine){.tabulator-row.tabulator-selectable:hover{cursor:pointer;background-color:#bbb}}@media (hover:hover) and (pointer:fine){.tabulator-row.tabulator-selected:hover{cursor:pointer;background-color:#769bcc}}.tabulator-row.tabulator-row-moving{background:#fff;border:1px solid #000}.tabulator-row.tabulator-moving{pointer-events:none;z-index:15;border-top:1px solid #ddd;border-bottom:1px solid #ddd;position:absolute}.tabulator-row.tabulator-range-highlight .tabulator-cell.tabulator-range-row-header{color:#000;background-color:#d6d6d6}.tabulator-row.tabulator-range-highlight.tabulator-range-selected .tabulator-cell.tabulator-range-row-header,.tabulator-row.tabulator-range-selected .tabulator-cell.tabulator-range-row-header{color:#fff;background-color:#3876ca}.tabulator-row .tabulator-row-resize-handle{height:5px;position:absolute;bottom:0;left:0;right:0}.tabulator-row .tabulator-row-resize-handle.prev{top:0;bottom:auto}@media (hover:hover) and (pointer:fine){.tabulator-row .tabulator-row-resize-handle:hover{cursor:ns-resize}}.tabulator-row .tabulator-responsive-collapse{box-sizing:border-box;border-top:1px solid #ddd;border-bottom:1px solid #ddd;padding:5px}.tabulator-row .tabulator-responsive-collapse:empty{display:none}.tabulator-row .tabulator-responsive-collapse table{font-size:14px}.tabulator-row .tabulator-responsive-collapse table tr td{position:relative}.tabulator-row .tabulator-responsive-collapse table tr td:first-of-type{padding-right:10px}.tabulator-row .tabulator-cell{box-sizing:border-box;text-overflow:ellipsis;white-space:nowrap;border-right:1px solid #ddd;outline:none;padding:4px;display:inline-block;position:relative;overflow:hidden}.tabulator-row .tabulator-cell.tabulator-row-header{background:#f9fafb;border-bottom:1px solid #ddd;border-right:1px solid #22242626}.tabulator-row .tabulator-cell.tabulator-frozen{background-color:inherit;z-index:11;display:inline-block;position:sticky;left:0}.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left{border-right:2px solid #ddd}.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-right{border-left:2px solid #ddd}.tabulator-row .tabulator-cell.tabulator-editing{border:1px solid #1d68cd;outline:none;padding:0}.tabulator-row .tabulator-cell.tabulator-editing input,.tabulator-row .tabulator-cell.tabulator-editing select{background:0 0;border:1px;outline:none}.tabulator-row .tabulator-cell.tabulator-validation-fail{border:1px solid #db2828}.tabulator-row .tabulator-cell.tabulator-validation-fail input,.tabulator-row .tabulator-cell.tabulator-validation-fail select{color:#db2828;background:0 0;border:1px}.tabulator-row .tabulator-cell.tabulator-row-handle{-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;-o-user-select:none;justify-content:center;align-items:center;display:inline-flex}.tabulator-row .tabulator-cell.tabulator-row-handle .tabulator-row-handle-box{width:80%}.tabulator-row .tabulator-cell.tabulator-row-handle .tabulator-row-handle-box .tabulator-row-handle-bar{background:#666;width:100%;height:3px;margin-top:2px}.tabulator-row .tabulator-cell.tabulator-range-selected:not(.tabulator-range-only-cell-selected):not(.tabulator-range-row-header){background-color:#9abcea}.tabulator-row .tabulator-cell .tabulator-data-tree-branch-empty{width:7px;display:inline-block}.tabulator-row .tabulator-cell .tabulator-data-tree-branch{vertical-align:middle;border-bottom:2px solid #ddd;border-left:2px solid #ddd;border-bottom-left-radius:1px;width:7px;height:9px;margin-top:-9px;margin-right:5px;display:inline-block}.tabulator-row .tabulator-cell .tabulator-data-tree-control{vertical-align:middle;background:#0000001a;border:1px solid #333;border-radius:2px;justify-content:center;align-items:center;width:11px;height:11px;margin-right:5px;display:inline-flex;overflow:hidden}@media (hover:hover) and (pointer:fine){.tabulator-row .tabulator-cell .tabulator-data-tree-control:hover{cursor:pointer;background:#0003}}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-collapse{background:0 0;width:1px;height:7px;display:inline-block;position:relative}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-collapse:after{content:\"\";background:#333;width:7px;height:1px;position:absolute;top:3px;left:-3px}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-expand{background:#333;width:1px;height:7px;display:inline-block;position:relative}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-expand:after{content:\"\";background:#333;width:7px;height:1px;position:absolute;top:3px;left:-3px}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle{-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;-o-user-select:none;background:#666;border-radius:20px;justify-content:center;align-items:center;width:15px;height:15px;font-size:1.1em;font-weight:700;display:inline-flex}@media (hover:hover) and (pointer:fine){.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle:hover{cursor:pointer;opacity:.7}}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle.open .tabulator-responsive-collapse-toggle-close{display:initial}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle.open .tabulator-responsive-collapse-toggle-open{display:none}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle svg{stroke:#fff}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle .tabulator-responsive-collapse-toggle-close{display:none}.tabulator-row .tabulator-cell .tabulator-traffic-light{border-radius:14px;width:14px;height:14px;display:inline-block}.tabulator-row.tabulator-group{box-sizing:border-box;background:#ccc;border-top:1px solid #999;border-bottom:1px solid #999;border-right:1px solid #ddd;min-width:100%;padding:5px 5px 5px 10px;font-weight:700}@media (hover:hover) and (pointer:fine){.tabulator-row.tabulator-group:hover{cursor:pointer;background-color:#0000001a}}.tabulator-row.tabulator-group.tabulator-group-visible .tabulator-arrow{border:6px solid #0000;border-top-color:#666;border-bottom:0;margin-right:10px}.tabulator-row.tabulator-group.tabulator-group-level-1{padding-left:30px}.tabulator-row.tabulator-group.tabulator-group-level-2{padding-left:50px}.tabulator-row.tabulator-group.tabulator-group-level-3{padding-left:70px}.tabulator-row.tabulator-group.tabulator-group-level-4{padding-left:90px}.tabulator-row.tabulator-group.tabulator-group-level-5{padding-left:110px}.tabulator-row.tabulator-group .tabulator-group-toggle{display:inline-block}.tabulator-row.tabulator-group .tabulator-arrow{vertical-align:middle;border:6px solid #0000;border-left-color:#666;border-right:0;width:0;height:0;margin-right:16px;display:inline-block}.tabulator-row.tabulator-group span{color:#d00;margin-left:10px}.tabulator-toggle{box-sizing:border-box;background:#dcdcdc;border:1px solid #ccc;flex-direction:row;display:flex}.tabulator-toggle.tabulator-toggle-on{background:#1c6cc2}.tabulator-toggle .tabulator-toggle-switch{box-sizing:border-box;background:#fff;border:1px solid #ccc}.tabulator-popup-container{-webkit-overflow-scrolling:touch;box-sizing:border-box;z-index:10000;background:#fff;border:1px solid #ddd;font-size:14px;display:inline-block;position:absolute;overflow-y:auto;box-shadow:0 0 5px #0003}.tabulator-popup{border-radius:3px;padding:5px}.tabulator-tooltip{box-shadow:none;pointer-events:none;border-radius:2px;max-width:min(500px,100%);padding:3px 5px;font-size:12px}.tabulator-menu .tabulator-menu-item{box-sizing:border-box;-webkit-user-select:none;user-select:none;padding:5px 10px;position:relative}.tabulator-menu .tabulator-menu-item.tabulator-menu-item-disabled{opacity:.5}@media (hover:hover) and (pointer:fine){.tabulator-menu .tabulator-menu-item:not(.tabulator-menu-item-disabled):hover{cursor:pointer;background:#efefef}}.tabulator-menu .tabulator-menu-item.tabulator-menu-item-submenu{padding-right:25px}.tabulator-menu .tabulator-menu-item.tabulator-menu-item-submenu:after{content:\"\";vertical-align:top;border:1px solid #ddd;border-width:1px 1px 0 0;width:7px;height:7px;display:inline-block;position:absolute;top:calc(5px + .4em);right:10px;transform:rotate(45deg)}.tabulator-menu .tabulator-menu-separator{border-top:1px solid #ddd}.tabulator-edit-list{-webkit-overflow-scrolling:touch;max-height:200px;font-size:14px;overflow-y:auto}.tabulator-edit-list .tabulator-edit-list-item{color:#333;outline:none;padding:4px}.tabulator-edit-list .tabulator-edit-list-item.active{color:#fff;background:#1d68cd}.tabulator-edit-list .tabulator-edit-list-item.active.focused{outline:1px solid #ffffff80}.tabulator-edit-list .tabulator-edit-list-item.focused{outline:1px solid #1d68cd}@media (hover:hover) and (pointer:fine){.tabulator-edit-list .tabulator-edit-list-item:hover{color:#fff;cursor:pointer;background:#1d68cd}}.tabulator-edit-list .tabulator-edit-list-placeholder{color:#333;text-align:center;padding:4px}.tabulator-edit-list .tabulator-edit-list-group{color:#333;border-bottom:1px solid #ddd;padding:6px 4px 4px;font-weight:700}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-2,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-2{padding-left:12px}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-3,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-3{padding-left:20px}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-4,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-4{padding-left:28px}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-5,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-5{padding-left:36px}.tabulator.tabulator-ltr{direction:ltr}.tabulator.tabulator-rtl{text-align:initial;direction:rtl}.tabulator.tabulator-rtl .tabulator-header .tabulator-col{border-left:1px solid #ddd;border-right:initial;text-align:initial}.tabulator.tabulator-rtl .tabulator-header .tabulator-col.tabulator-col-group .tabulator-col-group-cols{margin-left:-1px;margin-right:0}.tabulator.tabulator-rtl .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-title{padding-left:25px;padding-right:0}.tabulator.tabulator-rtl .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter{left:8px;right:auto}.tabulator.tabulator-rtl .tabulator-tableholder .tabulator-range-overlay .tabulator-range.tabulator-range-active:after{content:\"\";background-color:#2975dd;border-radius:999px;width:6px;height:6px;position:absolute;bottom:-3px;left:-3px;right:auto}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell{border-left:1px solid #ddd;border-right:initial}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell .tabulator-data-tree-branch{border-left:initial;border-right:2px solid #ddd;border-bottom-right-radius:1px;border-bottom-left-radius:0;margin-left:5px;margin-right:0}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell .tabulator-data-tree-control{margin-left:5px;margin-right:0}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left{border-left:2px solid #ddd}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-right{border-right:2px solid #ddd}.tabulator.tabulator-rtl .tabulator-row .tabulator-col-resize-handle:last-of-type{width:3px;margin-left:0;margin-right:-3px}.tabulator.tabulator-rtl .tabulator-footer .tabulator-calcs-holder{text-align:initial}.tabulator-print-fullscreen{z-index:10000;position:absolute;inset:0}body.tabulator-print-fullscreen-hide>:not(.tabulator-print-fullscreen){display:none!important}.tabulator-print-table{border-collapse:collapse}.tabulator-print-table .tabulator-data-tree-branch{vertical-align:middle;border-bottom:2px solid #ddd;border-left:2px solid #ddd;border-bottom-left-radius:1px;width:7px;height:9px;margin-top:-9px;margin-right:5px;display:inline-block}.tabulator-print-table .tabulator-print-table-group{box-sizing:border-box;background:#ccc;border-top:1px solid #999;border-bottom:1px solid #999;border-right:1px solid #ddd;min-width:100%;padding:5px 5px 5px 10px;font-weight:700}@media (hover:hover) and (pointer:fine){.tabulator-print-table .tabulator-print-table-group:hover{cursor:pointer;background-color:#0000001a}}.tabulator-print-table .tabulator-print-table-group.tabulator-group-visible .tabulator-arrow{border:6px solid #0000;border-top-color:#666;border-bottom:0;margin-right:10px}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-1 td{padding-left:30px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-2 td{padding-left:50px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-3 td{padding-left:70px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-4 td{padding-left:90px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-5 td{padding-left:110px!important}.tabulator-print-table .tabulator-print-table-group .tabulator-group-toggle{display:inline-block}.tabulator-print-table .tabulator-print-table-group .tabulator-arrow{vertical-align:middle;border:6px solid #0000;border-left-color:#666;border-right:0;width:0;height:0;margin-right:16px;display:inline-block}.tabulator-print-table .tabulator-print-table-group span{color:#d00;margin-left:10px}.tabulator-print-table .tabulator-data-tree-control{vertical-align:middle;background:#0000001a;border:1px solid #333;border-radius:2px;justify-content:center;align-items:center;width:11px;height:11px;margin-right:5px;display:inline-flex;overflow:hidden}@media (hover:hover) and (pointer:fine){.tabulator-print-table .tabulator-data-tree-control:hover{cursor:pointer;background:#0003}}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-collapse{background:0 0;width:1px;height:7px;display:inline-block;position:relative}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-collapse:after{content:\"\";background:#333;width:7px;height:1px;position:absolute;top:3px;left:-3px}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-expand{background:#333;width:1px;height:7px;display:inline-block;position:relative}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-expand:after{content:\"\";background:#333;width:7px;height:1px;position:absolute;top:3px;left:-3px}.tabulator{box-shadow:none;color:#000000de;border:1px solid #22242626;border-radius:.28571rem;width:100%;margin:1em 0}.tabulator .tabulator-header{box-shadow:none;color:#000000de;font-style:none;text-transform:none;border-bottom:1px solid #2224261a;font-weight:700}.tabulator .tabulator-header,.tabulator .tabulator-header .tabulator-col{background-color:#f9fafb;border-right:none}.tabulator .tabulator-header .tabulator-col .tabulator-col-content{padding:.92857em .78571em}.tabulator .tabulator-tableholder .tabulator-table{background-color:#0000}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs{background:#f2f2f2!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs.tabulator-calcs-top{border-bottom:2px solid #ddd}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs.tabulator-calcs-bottom{border-top:2px solid #ddd}.tabulator .tabulator-footer{box-shadow:none;color:#000000de;text-align:right;text-transform:none;background:#f9fafb;border-top:1px solid #22242626;padding:.78571em;font-style:normal;font-weight:400}.tabulator .tabulator-footer .tabulator-calcs-holder{margin:-.78571em -.78571em .78571em;background:#fff!important}.tabulator .tabulator-footer .tabulator-calcs-holder .tabulator-row{background:#fff!important}.tabulator .tabulator-footer .tabulator-calcs-holder:only-child{border-bottom:none;margin-bottom:-.78571em}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs{margin-top:calc(-.78571em - 5px)}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs .tabulator-spreadsheet-tab.tabulator-spreadsheet-tab-active{color:#d00}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.positive,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.positive{box-shadow:inset 0 0 #a3c293;color:#21ba45!important;background:#fcfff5!important}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.positive:hover,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.positive:hover{color:#13ae38!important;background:#f7ffe6!important}}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.negative,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.negative{box-shadow:inset 0 0 #e0b4b4;color:#db2828!important;background:#fff6f6!important}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.negative:hover,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.negative:hover{color:#d41616!important;background:#ffe7e7!important}}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.error,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.error{box-shadow:inset 0 0 #e0b4b4;color:#db2828!important;background:#fff6f6!important}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.error:hover,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.error:hover{color:#d12323!important;background:#ffe7e7!important}}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.warning,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.warning{box-shadow:inset 0 0 #c9ba9b;color:#f2c037!important;background:#fffaf3!important}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.warning:hover,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.warning:hover{color:#f1bb29!important;background:#fff4e4!important}}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.active,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.active{box-shadow:inset 0 0 #000000de;color:#000000de!important;background:#e0e0e0!important}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.active:hover,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.active:hover{color:#13ae38!important;background:#f7ffe6!important}}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.active,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.active{color:#0003;pointer-events:none}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.disabled:hover{color:#0003;pointer-events:none}}.tabulator.inverted{color:#ffffffe6;background:#333;border:none}.tabulator.inverted .tabulator-header{color:#ffffffe6;background-color:#00000026}.tabulator.inverted .tabulator-header,.tabulator.inverted .tabulator-header .tabulator-col{border-color:#ffffff1a!important}.tabulator.inverted .tabulator-tableholder .tabulator-table .tabulator-row{color:#ffffffe6;border:none}.tabulator.inverted .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell{border-color:#ffffff1a!important}.tabulator.inverted .tabulator-footer{background:#fff}.tabulator.striped .tabulator-row:nth-child(2n){background-color:#f2f2f2}.tabulator.celled{border:1px solid #22242626}.tabulator.celled .tabulator-header .tabulator-col,.tabulator.celled .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell{border-right:1px solid #2224261a}.tabulator[class*=single\\ line] .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell{border-right:none}.tabulator.red{border-top:.2em solid #db2828}.tabulator.inverted.red{color:#fff!important;background-color:#db2828!important}.tabulator.orange{border-top:.2em solid #f2711c}.tabulator.inverted.orange{color:#fff!important;background-color:#f2711c!important}.tabulator.yellow{border-top:.2em solid #fbbd08}.tabulator.inverted.yellow{color:#fff!important;background-color:#fbbd08!important}.tabulator.olive{border-top:.2em solid #b5cc18}.tabulator.inverted.olive{color:#fff!important;background-color:#b5cc18!important}.tabulator.green{border-top:.2em solid #21ba45}.tabulator.inverted.green{color:#fff!important;background-color:#21ba45!important}.tabulator.teal{border-top:.2em solid #00b5ad}.tabulator.inverted.teal{color:#fff!important;background-color:#00b5ad!important}.tabulator.blue{border-top:.2em solid #2185d0}.tabulator.inverted.blue{color:#fff!important;background-color:#2185d0!important}.tabulator.violet{border-top:.2em solid #6435c9}.tabulator.inverted.violet{color:#fff!important;background-color:#6435c9!important}.tabulator.purple{border-top:.2em solid #a333c8}.tabulator.inverted.purple{color:#fff!important;background-color:#a333c8!important}.tabulator.pink{border-top:.2em solid #e03997}.tabulator.inverted.pink{color:#fff!important;background-color:#e03997!important}.tabulator.brown{border-top:.2em solid #a5673f}.tabulator.inverted.brown{color:#fff!important;background-color:#a5673f!important}.tabulator.grey{border-top:.2em solid #767676}.tabulator.inverted.grey{color:#fff!important;background-color:#767676!important}.tabulator.black{border-top:.2em solid #1b1c1d}.tabulator.inverted.black{color:#fff!important;background-color:#1b1c1d!important}.tabulator.padded .tabulator-header .tabulator-col .tabulator-col-content{padding:1em}.tabulator.padded .tabulator-header .tabulator-col .tabulator-col-content .tabulator-arrow{top:20px}.tabulator.padded .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell{padding:1em}.tabulator.padded.very .tabulator-header .tabulator-col .tabulator-col-content{padding:1.5em}.tabulator.padded.very .tabulator-header .tabulator-col .tabulator-col-content .tabulator-arrow{top:26px}.tabulator.padded.very .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell{padding:1.5em}.tabulator.compact .tabulator-header .tabulator-col .tabulator-col-content{padding:.5em .7em}.tabulator.compact .tabulator-header .tabulator-col .tabulator-col-content .tabulator-arrow{top:12px}.tabulator.compact .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell{padding:.5em .7em}.tabulator.compact.very .tabulator-header .tabulator-col .tabulator-col-content{padding:.4em .6em}.tabulator.compact.very .tabulator-header .tabulator-col .tabulator-col-content .tabulator-arrow{top:10px}.tabulator.compact.very .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell{padding:.4em .6em}.tabulator-row{border-bottom:1px solid #2224261a}.tabulator-row.tabulator-row-even{background-color:#fff}@media (hover:hover) and (pointer:fine){.tabulator-row.tabulator-selectable:hover{box-shadow:inset 0 0 #000000de;color:#000000de!important;background:#e0e0e0!important}}.tabulator-row.tabulator-selected{background-color:#9abcea!important}@media (hover:hover) and (pointer:fine){.tabulator-row.tabulator-selected:hover{cursor:pointer;background-color:#769bcc!important}}.tabulator-row.tabulator-moving{pointer-events:none!important}.tabulator-row .tabulator-cell{vertical-align:middle;border-right:none;padding:.78571em}.tabulator-row .tabulator-cell:last-of-type{border-right:none}.tabulator-row .tabulator-cell.tabulator-row-header{border-bottom:none}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle{color:#fff}.tabulator-row.tabulator-group{background:#fafafa}.tabulator-row.tabulator-group span{color:#666}.tabulator-menu{background:#fff}@media (hover:hover) and (pointer:fine){.tabulator-menu .tabulator-menu-item:not(.tabulator-menu-item-disabled):hover{background:#f9fafb}}.tabulator-edit-select-list{background:#fff}.tabulator-edit-select-list .tabulator-edit-select-list-item.active{color:#fff}.tabulator-edit-select-list .tabulator-edit-select-list-item.active.focused{outline:1px solid #ffffff80}@media (hover:hover) and (pointer:fine){.tabulator-edit-select-list .tabulator-edit-select-list-item:hover{color:#fff}}.tabulator-edit-select-list .tabulator-edit-select-list-notice{color:inherit}.tabulator-print-table .tabulator-print-table-group{background:#fafafa}.tabulator-print-table .tabulator-print-table-group span{color:#666}");
var win = window;
win.layer = import_layer.default;
win.Tabulator = TabulatorFull$1;
win.Toastify = import_toastify.default;
win.localforage = import_localforage.default;
win.Viewer = import_viewer.default;
win.md5 = import_md5.default;
var currentHref = window.location.href;
var isJavdbSite = currentHref.includes("javdb");
var isMissavSite = /missav\.(ws|live|com)/.test(currentHref);
var isSearchOrUserPage = currentHref.includes("/search?q") || currentHref.includes("/search/") || currentHref.includes("/users/");
var JAVDB = "javdb";
var ACTOR = "actor";
var ACTRESS = "actress";
var CENSORED = "censored";
var UNCENSORED = "uncensored";
var loading_default = ".loading-container {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n background-color: rgba(0, 0, 0, 0.1);\n z-index: 99999999;\n}\n\n.loading-animation {\n position: relative;\n width: 60px;\n height: 12px;\n background: linear-gradient(90deg, #4facfe 0%, #00f2fe 100%);\n border-radius: 6px;\n animation: loading-animate 1.8s ease-in-out infinite;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n}\n\n.loading-animation:before,\n.loading-animation:after {\n position: absolute;\n display: block;\n content: '';\n animation: loading-animate 1.8s ease-in-out infinite;\n height: 12px;\n border-radius: 6px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n}\n\n.loading-animation:before {\n top: -20px;\n left: 10px;\n width: 40px;\n background: linear-gradient(90deg, #ff758c 0%, #ff7eb3 100%);\n}\n\n.loading-animation:after {\n bottom: -20px;\n width: 35px;\n background: linear-gradient(90deg, #ff9a9e 0%, #fad0c4 100%);\n}\n\n@keyframes loading-animate {\n 0% {\n transform: translateX(40px);\n }\n 50% {\n transform: translateX(-30px);\n }\n 100% {\n transform: translateX(40px);\n }\n}\n";
var viewer_default = ".viewer-canvas {\n overflow: auto !important;\n}\n\n.viewer-close {\n background: rgba(255, 0, 0, 0.6) !important;\n}\n.viewer-close:hover {\n background: rgba(255, 0, 0, 0.8) !important;\n}\n";
var logger_default = ".console-logger-container {\n position: fixed;\n bottom: 0;\n right: 0;\n z-index: 99999999;\n font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n width: fit-content;\n}\n\n.console-logger-toggle {\n width: 40px;\n height: 30px;\n background: #2c3e50;\n border-radius: 120px 10px 0 0;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: -2px 0 5px rgba(0, 0, 0, 0.1);\n transition: all 0.3s ease;\n color: white;\n font-size: 16px;\n}\n\n.console-logger-toggle:hover {\n background: #34495e;\n}\n\n.console-logger-toggle::after {\n content: '▼';\n transition: transform 0.3s ease;\n}\n\n.console-logger-toggle.collapsed::after {\n content: '▲';\n}\n\n.console-logger-window {\n width: 400px;\n height: 400px;\n background: white;\n border-radius: 10px 0 10px 10px;\n box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n transform: translateY(0);\n opacity: 1;\n /* 简化过渡属性 */\n transition:\n width 0.3s ease,\n height 0.3s ease,\n opacity 0.3s ease,\n transform 0.3s ease;\n}\n\n.console-logger-window.maximized {\n width: 600px !important;\n height: 85vh !important;\n border-radius: 10px 0 0 10px; /* 调整圆角以匹配右下角 */\n}\n\n.console-logger-window.collapsed {\n height: 0 !important;\n min-height: 0 !important;\n opacity: 0;\n}\n\n.console-logger-header {\n background: #2c3e50;\n color: white;\n padding: 12px 15px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-shrink: 0;\n}\n\n.console-logger-title {\n font-weight: 600;\n font-size: 16px;\n}\n\n.console-logger-controls {\n display: flex;\n gap: 10px;\n}\n\n.console-logger-controls button {\n background: transparent;\n border: 1px solid rgba(255, 255, 255, 0.3);\n padding: 5px 10px;\n font-size: 12px;\n color: white;\n border-radius: 4px;\n cursor: pointer;\n transition: background 0.3s;\n}\n\n.console-logger-controls button:hover {\n background: rgba(255, 255, 255, 0.1);\n}\n\n/* 新增的按钮样式 */\n.console-logger-maximize-toggle {\n line-height: 1;\n font-size: 14px !important; /* 使箭头看起来更大 */\n padding: 5px 8px !important;\n}\n.console-logger-maximize-toggle::before {\n content: '⇱'; /* Unicode symbol for maximized */\n}\n.console-logger-maximize-toggle.active::before {\n content: '⇲'; /* Unicode symbol for minimized */\n}\n\n.console-logger-filters {\n display: flex;\n align-items: center;\n gap: 5px;\n padding: 10px;\n background: #f8f9fa;\n border-bottom: 1px solid #e9ecef;\n flex-shrink: 0;\n overflow-x: hidden;\n}\n\n/* 新增: 过滤器按钮组的容器,负责滚动 */\n.console-logger-filter-group {\n display: flex;\n gap: 5px;\n overflow-x: auto; /* 允许过滤器按钮滚动 */\n flex-grow: 1; /* 占据剩余空间 */\n padding-right: 10px; /* 避免滚动条影响按钮 */\n}\n\n.console-logger-filter {\n padding: 5px 10px;\n font-size: 12px;\n border-radius: 15px;\n background: #ecf0f1;\n color: #7f8c8d;\n border: 1px solid #ddd;\n cursor: pointer;\n transition: all 0.3s;\n white-space: nowrap;\n flex-shrink: 0; /* 确保不被压缩 */\n}\n\n.console-logger-filter.active {\n background: #3498db;\n color: white;\n border-color: #3498db;\n}\n\n/* 新增: 滚动到底部按钮的样式 (位于 filtersContainer 内部右侧) */\n.console-logger-scroll-to-bottom {\n background: #3498db;\n border: none;\n padding: 5px 10px;\n font-size: 12px;\n color: white;\n border-radius: 4px;\n cursor: pointer;\n transition: background 0.3s;\n line-height: 1;\n height: fit-content;\n white-space: nowrap;\n margin-left: auto; /* 将按钮推到最右侧 */\n flex-shrink: 0; /* 确保不被压缩 */\n}\n\n.console-logger-scroll-to-bottom:hover {\n background: #2980b9;\n}\n\n.console-logger-content {\n flex: 1;\n overflow-y: auto;\n padding: 10px;\n background: #ffffff;\n word-wrap: break-word;\n text-align: left;\n}\n\n.console-logger-entry {\n padding: 8px 10px;\n margin-bottom: 3px;\n border-radius: 4px;\n font-size: 12px;\n line-height: 1.4;\n /*animation: consoleFadeIn 0.3s ease;*/\n border-left: 3px solid transparent;\n}\n\n@keyframes consoleFadeIn {\n from {\n opacity: 0;\n transform: translateY(5px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.console-logger-timestamp {\n color: #7f8c8d;\n font-size: 11px;\n margin-right: 2px;\n}\n\n@media (max-width: 768px) {\n .console-logger-container {\n right: 10px;\n bottom: 10px;\n }\n\n .console-logger-window {\n width: calc(100vw - 20px);\n height: 300px;\n }\n}\n\n.console-logger-message[data-type='json'] {\n white-space: pre-wrap;\n}\n";
var javdb_site_default = "/*__HIDENAV2__*/\n\n.navbar {\n z-index: 12345679 !important;\n padding: 0 0;\n}\n\n.navbar-link:not(.is-arrowless) {\n padding-right: 33px;\n}\n\n.sub-header,\n /*#search-bar-container, !*搜索框*!*/\n #footer,\n /*.search-recent-keywords, !*搜索框底部热搜词条*!*/\n .app-desktop-banner,\n div[data-controller=\"movie-tab\"] .tabs,\n h3.main-title,\n div.video-detail > div:nth-child(4) > div > div.tabs.no-bottom > ul > li:nth-child(3), /* 相关清单*/\n div.video-detail > div:nth-child(4) > div > div.tabs.no-bottom > ul > li:nth-child(2), /* 短评按钮*/\n div.video-detail > div:nth-child(4) > div > div.tabs.no-bottom > ul > li:nth-child(1), /*磁力面板 按钮*/\n .top-meta,\n .float-buttons {\n display: none !important;\n}\n\ndiv.tabs.no-bottom,\n.tabs ul {\n border-bottom: none !important;\n}\n\n/* 视频列表项 相对相对 方便标签绝对定位*/\n.movie-list .item {\n position: relative !important;\n}\n\n.video-title {\n white-space: normal !important;\n height: 80px; /* 固定高度 容器就不会出现高低不一*/\n\n display: -webkit-box; /* 必须设置,使接下来的属性生效 */\n -webkit-box-orient: vertical; /* 垂直方向堆叠行 */\n -webkit-line-clamp: 3; /* 设置文本最多显示的行数*/\n line-clamp: 3;\n}\n\n/* 列表页顶部分类自适应 */\n.main-tabs,\n.tabs {\n overflow-x: hidden;\n flex-wrap: wrap;\n justify-content: flex-start;\n}\n\n.main-tabs ul,\n.tabs ul {\n flex-wrap: wrap;\n flex-grow: 0;\n}\n\n/* 二级工具栏 大小封面,可播放,含磁链...*/\n.toolbar {\n display: flex;\n}\n";
var common_toolbar_default = "/* 全局通用样式 */\n.fr-btn {\n float: right;\n margin-left: 4px !important;\n}\n\n.menu-box {\n position: fixed;\n right: 10px;\n top: 50%;\n transform: translateY(-50%);\n display: flex;\n flex-direction: column;\n z-index: 1000;\n gap: 6px;\n}\n\n.menu-btn {\n display: inline-block;\n min-width: 80px;\n padding: 7px 12px;\n border-radius: 4px;\n color: white !important;\n text-decoration: none;\n font-weight: bold;\n font-size: 12px;\n text-align: center;\n cursor: pointer;\n transition: all 0.3s ease;\n box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);\n text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);\n border: none;\n line-height: 1.3;\n margin: 0;\n}\n\n.menu-btn:hover {\n transform: translateY(-1px);\n box-shadow: 0 3px 6px rgba(0, 0, 0, 0.15);\n opacity: 0.9;\n}\n\n.menu-btn:active {\n transform: translateY(0);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n\n.do-hide {\n display: none !important;\n}\n\n.main-tab-btn {\n border-bottom: none !important;\n border-radius: 3px !important;\n height: 30px;\n margin-left: 5px !important;\n}\n\n.jhs-icon {\n width: 16px;\n height: 16px;\n}\n\n.tool-box .jhs-icon {\n width: 1.5rem;\n height: 1.5rem;\n}\n\n/*表格内按钮溢出,防止被隐藏*/\n.tabulator .tabulator-row .action-cell-dropdown {\n overflow: visible !important;\n}\n/* 去除行内鼠标小手*/\n.tabulator .tabulator-row.tabulator-selectable:hover {\n cursor: default !important;\n}\n\n/* 排序小箭头颜色 */\n.tabulator .tabulator-col.tabulator-sortable[aria-sort='ascending'] .tabulator-arrow {\n border-bottom-color: #337ab7 !important;\n}\n.tabulator .tabulator-col.tabulator-sortable[aria-sort='descending'] .tabulator-arrow {\n border-top-color: #337ab7 !important;\n}\n\n/* 针对折叠行的容器或内容进行样式修改 */\n.tabulator-responsive-collapse {\n border-top: none !important;\n}\n\n.tabulator-responsive-collapse table {\n margin-left: 50px !important;\n}\n\n.tabulator-cell {\n height: auto !important;\n}\n\n/* 列允许换行,去除省略号 */\n.tabulator .tabulator-cell {\n white-space: normal !important;\n text-overflow: clip !important;\n}\n\n.tabulator-tableholder {\n overflow-x: hidden !important;\n}\n\n/*\n * Toastify 宽度修复:toastify-js 源 CSS 中 .toastify-center 有两行\n * max-width: fit-content;\n * max-width: -moz-fit-content;\n * lightningcss 压缩时删除了标准 fit-content 只留 -moz-fit-content(Firefox\n * 前缀),Chrome 不认 -moz- 前缀致 max-width 失效,toast 退回 .toastify 的\n * calc(50% - 20px) 变成超宽(~937px)。此处用 !important 强制 fit-content\n * 覆盖,恢复 toast 自适应内容宽度。详见 doc/32-css-layout-fix.md。\n */\n.toastify-center {\n max-width: fit-content !important;\n}\n\n/*__SCROLLBAR__*/\n";
var a_normal_buttons_default = ".a-normal, /* 白色 */\n .a-primary, /* 浅蓝色 */\n .a-success, /* 浅绿色 */\n .a-danger, /* 浅粉色 */\n .a-warning, /* 浅橙色 */\n .a-info /* 灰色 */ {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 6px 14px;\n margin-right: 10px;\n border-radius: 6px;\n text-decoration: none;\n font-size: 13px;\n font-weight: 500;\n transition: all 0.2s ease;\n cursor: pointer;\n border: 1px solid rgba(0, 0, 0, 0.08);\n white-space: nowrap;\n}\n\n.a-primary {\n background: #e0f2fe;\n color: #0369a1;\n border-color: #bae6fd;\n}\n\n.a-primary:hover {\n background: #bae6fd;\n}\n\n.a-success {\n background: #dcfce7;\n color: #166534;\n border-color: #bbf7d0;\n}\n\n.a-success:hover {\n background: #bbf7d0;\n}\n\n.a-danger {\n background: #fee2e2;\n color: #b91c1c;\n border-color: #fecaca;\n}\n\n.a-danger:hover {\n background: #fecaca;\n}\n\n.a-warning {\n background: #ffedd5;\n color: #9a3412;\n border-color: #fed7aa;\n}\n\n.a-warning:hover {\n background: #fed7aa;\n}\n\n.a-info {\n background: #e2e8f0;\n color: #334155;\n border-color: #cbd5e1;\n}\n\n.a-info:hover {\n background: #cbd5e1;\n}\n\n.a-normal {\n background: transparent;\n color: #64748b;\n border-color: #cbd5e1;\n}\n\n.a-normal:hover {\n background: #f8fafc;\n}\n";
var Hotkey = class Hotkey {
static isMac = navigator.platform.indexOf("Mac") === 0;
static registerHotKeyMap = new Map();
static handleKeydown = (event) => {
for (const [, entry] of Hotkey.registerHotKeyMap) {
const hotkeyString = entry.hotkeyString;
const callback = entry.callback;
if (Hotkey.judgeHotkey(hotkeyString, event)) callback(event);
}
};
static handleKeyup = (event) => {
for (const [, entry] of Hotkey.registerHotKeyMap) {
const hotkeyString = entry.hotkeyString;
const keyupCallback = entry.keyupCallback;
if (keyupCallback && Hotkey.judgeHotkey(hotkeyString, event)) keyupCallback(event);
}
};
constructor() {
if (new.target === Hotkey) throw new Error("HotkeyManager cannot be instantiated.");
}
static registerHotkey(hotkeyStr, keydownCallback, keyupCallback = null) {
if (Array.isArray(hotkeyStr)) {
const ids = [];
hotkeyStr.forEach((item) => {
if (!Hotkey.isHotkeyFormat(item)) throw new Error("快捷键格式错误");
const id = Hotkey.recordHotkey(item, keydownCallback, keyupCallback);
ids.push(id);
});
return ids;
}
if (!Hotkey.isHotkeyFormat(hotkeyStr)) throw new Error("快捷键格式错误");
return Hotkey.recordHotkey(hotkeyStr, keydownCallback, keyupCallback);
}
static recordHotkey(hotkeyStr, keydownCallback, keyupCallback) {
const id = Math.random().toString(36).substr(2);
Hotkey.registerHotKeyMap.set(id, {
hotkeyString: hotkeyStr,
callback: keydownCallback,
keyupCallback
});
return id;
}
static unregisterHotkey(id) {
if (Hotkey.registerHotKeyMap.has(id)) Hotkey.registerHotKeyMap.delete(id);
}
static isHotkeyFormat(hotkeyStr) {
return hotkeyStr.toLowerCase().split("+").map((item) => item.trim()).every((item) => [
"ctrl",
"shift",
"alt"
].includes(item) || item.length === 1);
}
static judgeHotkey(hotkeyStr, event) {
const parts = hotkeyStr.toLowerCase().split("+").map((item) => item.trim());
const withCtrl = parts.includes("ctrl");
const withShift = parts.includes("shift");
const withAlt = parts.includes("alt");
const mainKey = parts.find((item) => item !== "ctrl" && item !== "shift" && item !== "alt");
return (Hotkey.isMac ? event.metaKey : event.ctrlKey) === withCtrl && event.shiftKey === withShift && event.altKey === withAlt && event.key.toLowerCase() === mainKey;
}
};
function injectCss(css) {
if (css) if (css.includes("<style>")) document.head.insertAdjacentHTML("beforeend", css);
else {
const el = document.createElement("style");
el.textContent = css;
document.head.appendChild(el);
}
}
var GFRIENDS_SOURCES = [{
name: "jsDelivr (全球CDN)",
json: "https://cdn.jsdelivr.net/gh/gfriends/gfriends/Filetree.json",
base: "https://cdn.jsdelivr.net/gh/gfriends/gfriends/Content/"
}, {
name: "GitHub Raw (备用)",
json: "https://raw.githubusercontent.com/gfriends/gfriends/master/Filetree.json",
base: "https://raw.githubusercontent.com/gfriends/gfriends/master/Content/"
}];
var GFRIENDS_CDN_INDEX_KEY = "jhs_img_cdn_index";
var GFRIENDS_DB_NAME = "GfriendsAvatarDB";
var FILETREE_STORE = "filetreeStore";
var FILETREE_DATA_KEY = "filetree_data";
var FiletreeDb = class {
db = null;
async open() {
if (this.db) return this.db;
return new Promise((resolve, reject) => {
const request = indexedDB.open(GFRIENDS_DB_NAME, 1);
request.onupgradeneeded = () => {
const database = request.result;
this.db = database;
if (!database.objectStoreNames.contains("filetreeStore")) database.createObjectStore(FILETREE_STORE);
};
request.onsuccess = () => {
const database = request.result;
this.db = database;
resolve(database);
};
request.onerror = () => {
console.error("IndexedDB open error:", request.error);
reject(new Error("Failed to open IndexedDB"));
};
});
}
async get(key) {
const db = await this.open();
return new Promise((resolve) => {
const request = db.transaction([FILETREE_STORE], "readonly").objectStore(FILETREE_STORE).get(key);
request.onsuccess = () => resolve(request.result ?? null);
request.onerror = () => resolve(null);
});
}
async set(key, value) {
const db = await this.open();
return new Promise((resolve, reject) => {
const request = db.transaction([FILETREE_STORE], "readwrite").objectStore(FILETREE_STORE).put(value, key);
request.onsuccess = () => resolve();
request.onerror = () => {
console.error("IndexedDB set error:", request.error);
reject(new Error("Failed to write to IndexedDB"));
};
});
}
};
var filetreeDb = new FiletreeDb();
var cachedFiletreeRaw = null;
var cachedFiletreeParsed = null;
function clearCache() {
cachedFiletreeRaw = null;
cachedFiletreeParsed = null;
}
function getCurrentCdnSource() {
const rawIndex = parseInt(localStorage.getItem("jhs_img_cdn_index") || "0", 10);
const index = rawIndex >= 0 && rawIndex < GFRIENDS_SOURCES.length ? rawIndex : 0;
const source = GFRIENDS_SOURCES[index];
return {
json: source.json,
base: source.base,
index
};
}
function parseFiletree(data) {
if (!data || !data.Content) return null;
const result = {};
const content = data.Content;
const baseUrl = getCurrentCdnSource().base;
for (const folderKey in content) {
const encodedFolder = encodeURIComponent(folderKey);
const folder = content[folderKey];
for (const fileName in folder) {
let namePart = fileName.replace(/\.jpg$/i, "").split("-")[0];
if (namePart.startsWith("AI-Fix-")) namePart = namePart.substring(7);
const normalizedName = namePart.toLowerCase().trim();
if (normalizedName.length > 0) {
const urlPath = folder[fileName];
const queryIndex = urlPath.indexOf("?");
let encodedPath;
let queryString = "";
if (queryIndex > -1) {
encodedPath = encodeURIComponent(urlPath.substring(0, queryIndex));
queryString = urlPath.substring(queryIndex);
} else encodedPath = encodeURIComponent(urlPath);
const fullUrl = `${baseUrl}${encodedFolder}/${encodedPath}${queryString}`;
if (!result[normalizedName]) result[normalizedName] = [];
if (!result[normalizedName].includes(fullUrl)) result[normalizedName].push(fullUrl);
}
}
}
return result;
}
async function ensureFiletreeLoaded() {
if (cachedFiletreeRaw && cachedFiletreeParsed) return;
let idbData = null;
try {
idbData = await filetreeDb.get(FILETREE_DATA_KEY);
} catch (error) {
console.error("读取 IndexedDB 失败:", error);
}
if (idbData && idbData.Content) {
cachedFiletreeRaw = idbData;
cachedFiletreeParsed = parseFiletree(idbData);
if (cachedFiletreeParsed) return;
}
show.info("正在载入头像数据源...");
const response = await fetch(getCurrentCdnSource().json);
if (!response.ok) throw new Error(`请求头像源失败: ${response.status}`);
const filetree = await response.json();
if (filetree && filetree.Content) {
cachedFiletreeRaw = filetree;
cachedFiletreeParsed = parseFiletree(filetree);
try {
await filetreeDb.set(FILETREE_DATA_KEY, filetree);
clog.debug("载入头像数据源并写入缓存成功!");
} catch (error) {
clog.error(error);
show.error("头像数据源写入缓存失败,可能磁盘已满或其他权限问题。");
}
return;
}
console.log(filetree);
throw new Error("解析头像数据源失败");
}
async function loadGfriends(actressNames) {
const loadingHandle = loading();
try {
await ensureFiletreeLoaded();
} catch (error) {
show.error(error);
return [];
} finally {
loadingHandle.close();
}
const filetreeIndex = cachedFiletreeParsed;
if (!filetreeIndex) return [];
const urlSet = new Set();
const normalizedNames = actressNames.map((name) => name.toLowerCase().trim()).filter((name) => name.length > 0);
if (normalizedNames.length === 0) return [];
for (const name of normalizedNames) {
const urls = filetreeIndex[name];
if (urls) urls.forEach((url) => urlSet.add(url));
}
return Array.from(urlSet);
}
var WebDavClient = class {
davUrl;
username;
password;
folderName;
constructor(davUrl, username, password) {
this.davUrl = davUrl.endsWith("/") ? davUrl : davUrl + "/";
this.username = username;
this.password = password;
this.folderName = null;
}
_getAuthHeaders() {
return {
Authorization: `Basic ${btoa(`${this.username}:${this.password}`)}`,
Depth: "1"
};
}
_sendRequest(method, path, headers = {}, body) {
return new Promise((resolve, reject) => {
const url = this.davUrl + path;
const requestHeaders = {
...this._getAuthHeaders(),
...headers
};
GM_xmlhttpRequest({
method,
url,
headers: requestHeaders,
data: body,
onload: (response) => {
if (response.status >= 200 && response.status < 300) resolve(response);
else {
console.error(response);
reject(new Error(`请求失败 ${response.status}: ${response.statusText}`));
}
},
onerror: (error) => {
console.error("请求WebDav发生错误:", error);
reject(new Error("请求WebDav失败, 请检查服务是否启动, 凭证是否正确"));
}
});
});
}
async backup(folder, filename, content) {
await this._sendRequest("MKCOL", folder);
const path = folder + "/" + filename;
await this._sendRequest("PUT", path, { "Content-Type": "text/plain" }, content);
}
async getFileList(folder) {
const responseText = (await this._sendRequest("PROPFIND", folder, { "Content-Type": "application/xml" }, "<?xml version=\"1.0\"?>\n <d:propfind xmlns:d=\"DAV:\">\n <d:prop>\n <d:displayname />\n <d:getcontentlength />\n <d:creationdate />\n <d:getlastmodified />\n <d:iscollection />\n </d:prop>\n </d:propfind>\n ")).responseText;
const responses = new DOMParser().parseFromString(responseText, "text/xml").getElementsByTagNameNS("DAV:", "response");
const items = [];
for (let index = 0; index < responses.length; index++) {
if (index === 0) continue;
const responseElement = responses[index];
console.log(responseElement);
const displayName = responseElement.getElementsByTagNameNS("DAV:", "displayname")[0]?.textContent || "";
const contentLength = responseElement.getElementsByTagNameNS("DAV:", "getcontentlength")[0]?.textContent || "0";
const createTime = responseElement.getElementsByTagNameNS("DAV:", "creationdate")[0]?.textContent || responseElement.getElementsByTagNameNS("DAV:", "getlastmodified")[0]?.textContent || "";
if (contentLength !== "0") items.push({
fileId: displayName,
name: displayName,
size: Number(contentLength),
createTime
});
}
items.reverse();
return items;
}
async deleteFile(filename) {
const path = this.folderName + "/" + encodeURI(filename);
await this._sendRequest("DELETE", path, { "Cache-Control": "no-cache" });
}
async getBackupList(folder) {
this.folderName = folder;
await this._sendRequest("MKCOL", folder);
return this.getFileList(folder);
}
async getFileContent(filename) {
const path = this.folderName + "/" + filename;
return (await this._sendRequest("GET", path, { Accept: "application/octet-stream" })).responseText;
}
};
function createLoading() {
const container = document.createElement("div");
container.className = "loading-container";
const animation = document.createElement("div");
animation.className = "loading-animation";
container.appendChild(animation);
document.body.appendChild(container);
return { close: () => {
if (container && container.parentNode) container.parentNode.removeChild(container);
} };
}
var createToast = (message, type, position, duration, onClick) => {
let userOptions;
if (typeof position == "object") userOptions = position;
else {
userOptions = typeof duration == "object" ? duration : onClick || {};
userOptions.gravity = position || "top";
userOptions.position = typeof duration == "string" ? duration : "center";
}
if (!userOptions.gravity || userOptions.gravity === "center") userOptions.offset = { y: "calc(50vh - 150px)" };
const infoFrom = "#60A5FA";
const infoTo = "#93C5FD";
const successFrom = "#10B981";
const successTo = "#6EE7B7";
const errorFrom = "#EF4444";
const errorTo = "#FCA5A5";
const baseStyle = {
borderRadius: "12px",
color: "white",
padding: "12px 16px",
boxShadow: "0 4px 6px rgba(0,0,0,0.1)",
minWidth: "150px",
textAlign: "center",
zIndex: 999999999
};
const toastOptions = {
text: message,
duration: 1e3,
close: false,
gravity: "top",
position: "center",
style: {
info: {
...baseStyle,
background: `linear-gradient(to right, ${infoFrom}, ${infoTo})`
},
success: {
...baseStyle,
background: `linear-gradient(to right, ${successFrom}, ${successTo})`
},
error: {
...baseStyle,
background: `linear-gradient(to right, ${errorFrom}, ${errorTo})`
}
}[type],
stopOnFocus: true,
oldestFirst: false,
...userOptions
};
if (toastOptions.duration === -1) toastOptions.close = true;
const toast = Toastify(toastOptions);
toast.showToast();
toast.closeShow = () => {
toast.toastElement.remove();
};
return toast;
};
var show$1 = {
ok: (message, position = "center", duration, onClick) => createToast(message, "success", position, duration, onClick),
error: (message, position = "center", duration, onClick) => createToast(message, "error", position, duration, onClick),
info: (message, position = "center", duration, onClick) => createToast(message, "info", position, duration, onClick)
};
var VIEWER_CONFIG = (ctx) => ({
zIndex: 999999990,
navbar: false,
zoomOnWheel: false,
zoomRatio: .1,
toggleOnDblclick: false,
toolbar: {
zoomIn: 1,
zoomOut: 1,
reset: 1,
rotateLeft: 0,
rotateRight: 0,
flipHorizontal: 0,
flipVertical: 0
},
title: false,
keyboard: false,
viewed() {
const viewer = ctx.viewerRef.current;
viewer.zoomTo(1.4);
const offsetX = (viewer.viewerData.width - viewer.imageData.width) / 2;
viewer.moveTo(offsetX, 0);
},
shown() {
const viewer = ctx.viewerRef.current;
if (ctx.isTemporary) ctx.container.remove();
document.documentElement.style.overflow = "hidden";
document.body.style.overflow = "hidden";
viewer.handleKeydown = function(event) {
if (event.key === "Escape" || event.key === " ") {
event.preventDefault();
event.stopPropagation();
viewer.destroy();
document.removeEventListener("keydown", viewer.handleKeydown);
document.documentElement.style.overflow = "";
document.body.style.overflow = "";
ctx.resetOverflow();
}
};
document.addEventListener("keydown", viewer.handleKeydown);
},
hidden() {
const viewer = ctx.viewerRef.current;
if (viewer && viewer.handleKeydown) document.removeEventListener("keydown", viewer.handleKeydown);
viewer.destroy();
document.documentElement.style.overflow = "";
document.body.style.overflow = "";
ctx.resetOverflow();
}
});
var VOID_TAGS = new Set([
"img",
"input",
"br",
"hr",
"meta",
"link",
"area",
"base",
"col",
"embed",
"param",
"source",
"track",
"wbr"
]);
var REACT_FRAGMENT_TYPE = Symbol.for("react.fragment");
function isReactElement(node) {
return node != null && typeof node === "object" && "type" in node && "props" in node && typeof node.props === "object" && node.props !== null;
}
function escapeText(s) {
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
}
function camelToKebab(s) {
return s.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
}
function styleToCss(style) {
return Object.entries(style).filter(([, v]) => v != null && v !== false).map(([k, v]) => `${camelToKebab(k)}:${v}`).join(";");
}
function renderAttrs(props) {
const parts = [];
for (const [key, value] of Object.entries(props)) {
if (value == null || value === false) continue;
if (key === "children") continue;
if (key === "dangerouslySetInnerHTML") continue;
if (key.startsWith("on")) continue;
if (key === "className") {
if (value !== "") parts.push(`class="${String(value)}"`);
continue;
}
if (key === "style") {
if (typeof value === "string") parts.push(`style="${value}"`);
else if (typeof value === "object" && value !== null) {
const css = styleToCss(value);
if (css) parts.push(`style="${css}"`);
}
continue;
}
if (value === true) {
parts.push(key);
continue;
}
parts.push(`${key}="${String(value)}"`);
}
return parts.length ? " " + parts.join(" ") : "";
}
function renderChildren(children) {
if (children == null || typeof children === "boolean") return "";
if (typeof children === "string") return escapeText(children);
if (typeof children === "number" || typeof children === "bigint") return String(children);
if (Array.isArray(children)) return children.map((c) => renderChildren(c)).join("");
if (isReactElement(children)) return jsxToString(children);
return "";
}
function jsxToString(node) {
if (node == null || typeof node === "boolean") return "";
if (typeof node === "string") return escapeText(node);
if (typeof node === "number" || typeof node === "bigint") return String(node);
if (Array.isArray(node)) return node.map(jsxToString).join("");
if (!isReactElement(node)) return "";
const { type, props } = node;
if (type === REACT_FRAGMENT_TYPE) return renderChildren(props.children);
if (typeof type === "function") return jsxToString(type(props));
if (typeof type === "string") {
const tag = type;
const attrs = renderAttrs(props);
if (VOID_TAGS.has(tag)) return `<${tag}${attrs} />`;
const dsi = props.dangerouslySetInnerHTML;
if (dsi && typeof dsi.__html === "string") return `<${tag}${attrs}>${dsi.__html}</${tag}>`;
return `<${tag}${attrs}>${renderChildren(props.children)}</${tag}>`;
}
return "";
}
var require_react_jsx_runtime_production = __commonJSMin(((exports) => {
var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment");
function jsxProd(type, config, maybeKey) {
var key = null;
void 0 !== maybeKey && (key = "" + maybeKey);
void 0 !== config.key && (key = "" + config.key);
if ("key" in config) {
maybeKey = {};
for (var propName in config) "key" !== propName && (maybeKey[propName] = config[propName]);
} else maybeKey = config;
config = maybeKey.ref;
return {
$$typeof: REACT_ELEMENT_TYPE,
type,
key,
ref: void 0 !== config ? config : null,
props: maybeKey
};
}
exports.Fragment = REACT_FRAGMENT_TYPE;
exports.jsx = jsxProd;
exports.jsxs = jsxProd;
}));
var import_jsx_runtime = __commonJSMin(((exports, module) => {
module.exports = require_react_jsx_runtime_production();
}))();
function TemporaryImageContainer({ src, alt = "" }) {
return (0, import_jsx_runtime.jsx)("div", {
className: "temporary-container",
style: { display: "none" },
children: (0, import_jsx_runtime.jsx)("img", {
src,
alt
})
});
}
var INDENT_BEFORE = "\n ";
var INDENT_BETWEEN = "\n ";
var INDENT_AFTER = "\n ";
function LoggerLogEntry({ timeStr, messageType, message }) {
return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
INDENT_BEFORE,
(0, import_jsx_runtime.jsxs)("span", {
className: "console-logger-timestamp",
children: [
"[",
timeStr,
"]"
]
}),
INDENT_BETWEEN,
(0, import_jsx_runtime.jsx)("span", {
className: "console-logger-message",
"data-type": messageType,
dangerouslySetInnerHTML: { __html: message }
}),
INDENT_AFTER
] });
}
var LOG_TYPE_STYLES = {
base: {
label: "信息",
background: "#e8f4fd",
borderLeftColor: "#3498db"
},
warn: {
label: "警告",
background: "#fef9e7",
borderLeftColor: "#f39c12"
},
error: {
label: "错误",
background: "#fdedec",
borderLeftColor: "#e74c3c"
},
debug: {
label: "调试",
background: "#f4f6f6",
borderLeftColor: "#95a5a6"
}
};
var FILTER_TYPE_MAP = {
base: [
"base",
"warn",
"error"
],
warn: ["warn"],
error: ["error"],
debug: [
"base",
"warn",
"error",
"debug"
]
};
var MAXIMIZE_KEY = "jhs_clog_maximize";
var EXPAND_KEY = "jhs_clog_expand";
var FILTER_KEY = "jhs_clog_filter";
var Logger = class {
currentFilter;
logs = [];
isInitialized = false;
userScrolledUp = false;
container;
toggleBtn;
window;
maximizeBtn;
filtersContainer;
filterButtonGroup;
scrollToBottomBtn;
content;
maxLogCount = 2e3;
maxLogCountInitialized = false;
constructor() {
const stored = localStorage.getItem(FILTER_KEY);
this.currentFilter = stored && LOG_TYPE_STYLES[stored] ? stored : "base";
}
tryInitialize() {
return document.readyState !== "loading" && (this.isInitialized || (this.init(), this.isInitialized = true, true));
}
init() {
this.createContainer();
this.bindEvents();
this.checkInitialMaximizeState();
this.checkInitialCollapseState();
}
createContainer() {
this.container = document.createElement("div");
this.container.className = "console-logger-container";
this.container.style.display = "none";
this.toggleBtn = document.createElement("div");
this.toggleBtn.className = "console-logger-toggle collapsed";
this.container.appendChild(this.toggleBtn);
this.window = document.createElement("div");
this.window.className = "console-logger-window collapsed";
const header = document.createElement("div");
header.className = "console-logger-header";
const title = document.createElement("div");
title.className = "console-logger-title";
title.textContent = "JHS V3.3.2";
const controls = document.createElement("div");
controls.className = "console-logger-controls";
this.maximizeBtn = document.createElement("button");
this.maximizeBtn.textContent = "";
this.maximizeBtn.classList.add("console-logger-maximize-toggle");
controls.appendChild(this.maximizeBtn);
const clearBtn = document.createElement("button");
clearBtn.textContent = "清空";
clearBtn.addEventListener("click", () => this.clear());
controls.appendChild(clearBtn);
header.appendChild(title);
header.appendChild(controls);
this.filtersContainer = document.createElement("div");
this.filtersContainer.className = "console-logger-filters";
this.filterButtonGroup = document.createElement("div");
this.filterButtonGroup.className = "console-logger-filter-group";
this.filtersContainer.appendChild(this.filterButtonGroup);
this.scrollToBottomBtn = document.createElement("button");
this.scrollToBottomBtn.className = "console-logger-scroll-to-bottom";
this.scrollToBottomBtn.textContent = "到底部";
this.filtersContainer.appendChild(this.scrollToBottomBtn);
this.content = document.createElement("div");
this.content.className = "console-logger-content jhs-scrollbar";
this.window.appendChild(header);
this.window.appendChild(this.filtersContainer);
this.window.appendChild(this.content);
this.container.appendChild(this.window);
document.body.appendChild(this.container);
Object.keys(LOG_TYPE_STYLES).forEach((typeName) => {
const filterBtn = document.createElement("div");
filterBtn.className = "console-logger-filter";
if (typeName === this.currentFilter) filterBtn.classList.add("active");
filterBtn.textContent = LOG_TYPE_STYLES[typeName].label;
filterBtn.dataset.type = typeName;
filterBtn.addEventListener("click", () => this.setFilter(typeName));
this.filterButtonGroup.appendChild(filterBtn);
});
}
bindEvents() {
this.toggleBtn.addEventListener("click", () => {
this.toggleExpandCollapsed();
});
this.maximizeBtn.addEventListener("click", () => this.toggleMaximize());
this.scrollToBottomBtn.addEventListener("click", () => {
this.content.scrollTop = this.content.scrollHeight;
this.userScrolledUp = false;
});
this.content.addEventListener("scroll", () => {
const atBottom = this.content.scrollHeight - this.content.clientHeight <= this.content.scrollTop + 5;
this.userScrolledUp = !atBottom;
});
this.content.addEventListener("wheel", (evt) => {
const atTop = this.content.scrollTop === 0;
const atBottom = this.content.scrollHeight - this.content.clientHeight <= this.content.scrollTop + 1;
if (atTop && evt.deltaY < 0 || atBottom && evt.deltaY > 0) {
evt.preventDefault();
evt.stopPropagation();
}
}, { passive: false });
}
toggleExpandCollapsed() {
const isCollapsed = this.window.classList.toggle("collapsed");
this.toggleBtn.classList.toggle("collapsed");
if (isCollapsed) localStorage.setItem(EXPAND_KEY, "no");
else {
localStorage.setItem(EXPAND_KEY, "yes");
this.reRenderAllLogs();
}
}
checkInitialCollapseState() {
const stored = localStorage.getItem(EXPAND_KEY);
if (stored && stored !== "no") {
this.window.classList.toggle("collapsed");
this.toggleBtn.classList.toggle("collapsed");
setTimeout(() => {
this.content.scrollTop = this.content.scrollHeight;
}, 0);
} else {
this.window.classList.add("collapsed");
this.toggleBtn.classList.add("collapsed");
}
}
checkInitialMaximizeState() {
if (localStorage.getItem(MAXIMIZE_KEY) === "maximized") {
this.window.classList.add("maximized");
this.maximizeBtn.classList.add("active");
}
}
toggleMaximize() {
const isMaximized = this.window.classList.toggle("maximized");
this.maximizeBtn.classList.toggle("active", isMaximized);
if (isMaximized) localStorage.setItem(MAXIMIZE_KEY, "maximized");
else localStorage.setItem(MAXIMIZE_KEY, "minimized");
if (!this.window.classList.contains("collapsed")) this.content.scrollTop = this.content.scrollHeight;
}
addLog(message, typeArg = "base", ...extraArgs) {
if (!this.maxLogCountInitialized) {
this.maxLogCountInitialized = true;
storageManager.getSetting("clogMsgCount", 2e3).then((v) => {
this.maxLogCount = v;
});
}
const initialized = this.tryInitialize();
let resolvedType;
let resolvedExtra = [];
if (LOG_TYPE_STYLES[typeArg]) {
resolvedType = typeArg;
resolvedExtra = extraArgs;
} else {
resolvedType = "base";
resolvedExtra = [typeArg, ...extraArgs];
}
resolvedType = LOG_TYPE_STYLES[resolvedType] ? resolvedType : "base";
const allParts = [message, ...resolvedExtra];
let messageType = "msg";
const parts = [];
allParts.forEach((part) => {
if (Object.prototype.toString.call(part) === "[object Error]") parts.push(String(part));
else if (typeof part === "object" && part !== null) try {
parts.push("<br/>" + JSON.stringify(part, null, 2));
messageType = "json";
} catch {
parts.push(String(part));
messageType = "msg";
}
else parts.push(String(part));
});
let formattedMessage = parts.join(" ");
formattedMessage = formattedMessage.replace(/(?:(?:https?|ftp):\/\/|www\.|(?:\/\/))[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]/gi, (match) => {
const isHttpOrFtp = match.startsWith("http") || match.startsWith("ftp");
const isProtocolRelative = match.startsWith("//");
const isWww = match.startsWith("www.");
let href = match;
if (isProtocolRelative) href = `http:${match}`;
else if (!isHttpOrFtp && isWww) href = `http://${match}`;
return `<a href="${href}" target="_blank">${match}</a>`;
});
const entry = {
message: formattedMessage,
messageType,
type: resolvedType,
timestamp: new Date(),
id: Date.now() + Math.random()
};
this.logs.push(entry);
if (this.logs.length > this.maxLogCount) {
const firstEntry = this.logs[0];
if (initialized) {
const oldEl = this.content.querySelector(`.console-logger-entry[data-id="${firstEntry.id}"]`);
if (oldEl) {
this.logs.shift();
this.content.removeChild(oldEl);
}
}
}
if (initialized) this.renderLog(entry);
}
log(...args) {
const [first, ...rest] = args;
setTimeout(() => {
this.addLog(first, "base", ...rest);
}, 0);
}
error(...args) {
const [first, ...rest] = args;
console.error(...args);
setTimeout(() => {
this.addLog(first, "error", ...rest);
}, 0);
}
warn(...args) {
const [first, ...rest] = args;
setTimeout(() => {
this.addLog(first, "warn", ...rest);
}, 0);
}
debug(...args) {
const [first, ...rest] = args;
setTimeout(() => {
this.addLog(first, "debug", ...rest);
}, 0);
}
renderLog(entry) {
if (this.container.style.display === "none") return;
if (this.window.classList.contains("collapsed")) return;
if (!(FILTER_TYPE_MAP[this.currentFilter] || []).includes(entry.type)) return;
const el = this._createLogElement(entry);
this.content.appendChild(el);
if (!this.window.classList.contains("collapsed") && !this.userScrolledUp) this.content.scrollTop = this.content.scrollHeight;
}
reRenderAllLogs() {
if (this.container.style.display !== "none") {
if (!this.window.classList.contains("collapsed")) setTimeout(() => {
this.content.innerHTML = "";
if (this.logs.length === 0) return;
const filterTypes = FILTER_TYPE_MAP[this.currentFilter] || [];
const fragment = document.createDocumentFragment();
this.logs.forEach((entry) => {
if (filterTypes.includes(entry.type)) {
const el = this._createLogElement(entry);
fragment.appendChild(el);
}
});
this.content.appendChild(fragment);
this.content.scrollTop = this.content.scrollHeight;
}, 0);
}
}
_createLogElement(entry) {
const el = document.createElement("div");
el.className = "console-logger-entry";
el.dataset.type = entry.type;
el.dataset.id = String(entry.id);
const style = LOG_TYPE_STYLES[entry.type] || LOG_TYPE_STYLES.base;
el.style.borderLeft = "3px solid " + style.borderLeftColor;
el.style.background = style.background;
const timeStr = (entry.timestamp instanceof Date ? entry.timestamp : new Date(entry.timestamp)).toTimeString().split(" ")[0];
el.innerHTML = jsxToString((0, import_jsx_runtime.jsx)(LoggerLogEntry, {
timeStr,
messageType: entry.messageType,
message: entry.message
}));
return el;
}
setFilter(filterType) {
if (this.currentFilter === filterType) return;
this.currentFilter = filterType;
localStorage.setItem(FILTER_KEY, filterType);
this.filterButtonGroup.querySelectorAll(".console-logger-filter").forEach((btn) => {
if (btn.dataset.type === filterType) btn.classList.add("active");
else btn.classList.remove("active");
});
this.reRenderAllLogs();
}
clear() {
this.logs = [];
this.content.innerHTML = "";
}
show() {
if (this.isInitialized && this.container || this.tryInitialize() && this.container) {
this.container.style.display = "";
this.reRenderAllLogs();
}
}
hide() {
if (this.isInitialized && this.container) this.container.style.display = "none";
}
lowZIndex() {
if (this.isInitialized && this.container) this.container.style.zIndex = "12345678";
}
highZIndex() {
if (this.isInitialized && this.container) this.container.style.zIndex = "999999999";
}
};
var FILTER_ACTION = "filter";
var FAVORITE_ACTION = "favorite";
var HAS_WATCH_ACTION = "hasWatch";
var HAS_DOWN_ACTION = "hasDown";
var BLOCK_TEXT = "🚫 屏蔽";
var BLOCKED_TEXT = "🚫 已屏蔽";
var BLOCK_COLOR = "#de3333";
var FAVORITE_TEXT = "⭐ 收藏";
var FAVORITED_TEXT = "⭐ 已收藏";
var FAVORITE_COLOR = "#25b1dc";
var WATCHED_TEXT = "🔍 已观看";
var WATCHED_COLOR = "#d7a80c";
var HAS_DOWN_TEXT$1 = "📥️ 已下载";
var HAS_DOWN_COLOR = "#7bc73b";
var HAS_DOWN_STATUS = "hasDown";
var UNCENSORED_TAG = "(無碼)";
var StorageManager = class StorageManager {
static instance = null;
car_list_key = "car_list";
filter_keyword_title_key = "filter_keyword_title";
filter_keyword_review_key = "filter_keyword_review";
setting_key = "setting";
blacklist_key = "blacklist";
blacklist_car_list_key = "blacklist_car_list";
favorite_actresses_key = "favorite_actresses";
highlighted_tags_key = "highlighted_tags";
forage = localforage.createInstance({
driver: localforage.INDEXEDDB,
name: "JAV-JHS",
version: 1,
storeName: "appData"
});
cache_filter_actor_actress_car_list = null;
cacheSettingObj = null;
carListChangeCallback;
setCarListChangeCallback(cb) {
this.carListChangeCallback = cb;
}
clearFilterActorActressCarListCache() {
this.cache_filter_actor_actress_car_list = null;
}
clearSettingCache() {
this.cacheSettingObj = null;
}
constructor() {
if (StorageManager.instance) throw new Error("StorageManager已被实例化过了!");
StorageManager.instance = this;
}
async getCarList() {
return await this.forage.getItem(this.car_list_key) || [];
}
async getCar(carNum) {
return (await this.getCarList()).find((car) => car.carNum === carNum);
}
_saveSingleCar(input, list) {
let { carNum, url, names, actionType, publishTime, starId, score } = input;
if (!carNum) {
show.error("番号为空!");
throw new Error("番号为空!");
}
if (!url) {
show.error("url为空!");
throw new Error("url为空!");
}
if (!url.includes("http")) url = window.location.origin + url;
if (names) names = names.trim();
let car = list.find((item) => item.carNum === carNum);
if (car) {
if (names) car.names = names;
if (url) car.url = url;
if (publishTime) car.publishTime = publishTime;
if (score !== void 0) car.score = score;
car.updateDate = utils.getNowStr();
} else {
const now = utils.getNowStr();
car = {
carNum,
url,
names,
status: "",
createDate: now,
updateDate: now,
publishTime
};
if (starId) car.starId = starId;
if (score !== void 0) car.score = score;
list.push(car);
}
switch (actionType) {
case FILTER_ACTION:
if (car.status === "filter") {
const msg = `${carNum} 已在屏蔽列表中`;
show.error(msg);
throw new Error(msg);
}
car.status = FILTER_ACTION;
break;
case FAVORITE_ACTION:
if (car.status === "favorite") {
const msg = `${carNum} 已在收藏列表中`;
show.error(msg);
throw new Error(msg);
}
car.status = FAVORITE_ACTION;
break;
case HAS_DOWN_STATUS:
car.status = HAS_DOWN_STATUS;
break;
case HAS_WATCH_ACTION:
car.status = HAS_WATCH_ACTION;
break;
default: {
const msg = "actionType错误, 请联系作者更正: " + actionType;
show.error(msg);
throw new Error(msg);
}
}
}
async saveCar(input) {
const list = await this.forage.getItem(this.car_list_key) || [];
this._saveSingleCar(input, list);
await this.forage.setItem(this.car_list_key, list);
await this.removeNewVideoList([input.carNum]);
const car = list.find((c) => c.carNum === input.carNum);
if (car) this.carListChangeCallback?.({
action: "upsert",
upserts: [car]
});
}
async updateCarInfo(input) {
let { carNum, url, names, actionType, remark } = input;
if (!carNum) {
show.error("番号为空!");
throw new Error("番号为空!");
}
if (!url) {
show.error("url为空!");
throw new Error("url为空!");
}
if (names) names = names.trim();
const list = await this.forage.getItem(this.car_list_key) || [];
const car = list.find((item) => item.carNum === carNum);
if (!car) {
const msg = "数据不存在: " + carNum;
show.error(msg);
throw new Error(msg);
}
car.names = names;
car.url = url;
car.remark = remark;
car.updateDate = utils.getNowStr();
switch (actionType) {
case FAVORITE_ACTION:
car.status = FAVORITE_ACTION;
break;
case HAS_WATCH_ACTION:
car.status = HAS_WATCH_ACTION;
break;
default: {
const msg = "actionType错误, 请联系作者更正: " + actionType;
show.error(msg);
throw new Error(msg);
}
}
await this.forage.setItem(this.car_list_key, list);
this.carListChangeCallback?.({
action: "upsert",
upserts: [car]
});
}
async saveCarList(inputs) {
if (!inputs || !Array.isArray(inputs) || inputs.length === 0) {
show.error("记录列表为空!");
throw new Error("记录列表为空!");
}
const list = await this.forage.getItem(this.car_list_key) || [];
for (const item of inputs) try {
this._saveSingleCar(item, list);
} catch (err) {
throw err;
}
await this.forage.setItem(this.car_list_key, list);
const numSet = new Set(inputs.map((i) => i.carNum));
const upserts = list.filter((c) => numSet.has(c.carNum));
if (upserts.length > 0) this.carListChangeCallback?.({
action: "upsert",
upserts
});
}
async removeNewVideoList(carNums) {
const actressList = await this.getFavoriteActressList();
let changed = false;
const updated = actressList.map((actress) => {
if (!actress.newVideoList || !Array.isArray(actress.newVideoList)) return actress;
const filtered = actress.newVideoList.filter((carNum) => {
const matched = carNums.includes(carNum);
if (matched) {
clog.log("移除关联女优新作品", actress.name, carNum);
changed = true;
}
return !matched;
});
return {
...actress,
newVideoList: filtered
};
});
if (changed) await this.forage.setItem(this.favorite_actresses_key, updated);
}
async removeCar(carNum) {
const list = await this.getCarList();
const beforeLen = list.length;
const filtered = list.filter((item) => item.carNum !== carNum);
if (filtered.length === beforeLen) {
show.error(`${carNum} 不存在`);
return false;
} else {
await this.forage.setItem(this.car_list_key, filtered);
this.carListChangeCallback?.({
action: "delete",
deletes: [carNum]
});
return true;
}
}
async batchRemoveCars(carNums) {
const list = await this.getCarList();
const beforeLen = list.length;
const numSet = new Set(carNums);
const filtered = list.filter((item) => !numSet.has(item.carNum));
const removed = beforeLen - filtered.length;
if (removed === 0) return false;
await this.forage.setItem(this.car_list_key, filtered);
this.carListChangeCallback?.({
action: "delete",
deletes: carNums
});
return removed;
}
async getBlacklist() {
return await this.forage.getItem(this.blacklist_key) || [];
}
async addBlacklistItem(item) {
let { starId, name, allName, role, movieType, url } = item;
if (!starId) throw new Error("缺失starId");
if (!name) throw new Error("缺失name");
if (!role) throw new Error("缺失role");
const list = await this.getBlacklist();
const existing = list.find((entry) => entry.starId === starId);
if (existing) {
existing.url = url;
existing.role = role;
existing.movieType = movieType;
clog.log("更新黑名单演员信息", existing);
} else {
const created = {
starId,
name,
allName: allName || [name],
createTime: utils.getNowStr(),
role,
movieType,
url
};
list.push(created);
clog.log("增加黑名单演员信息", created);
}
await this.forage.setItem(this.blacklist_key, list);
}
async updateBlacklistItem(item) {
if (!item || !item.starId) throw new Error("参数不全");
const list = await this.getBlacklist();
const existing = list.find((entry) => entry.starId === item.starId);
if (!existing) throw new Error(`未找到黑名单演员信息:${item.name} ${item.starId}`);
if (item.checkTime) existing.checkTime = item.checkTime;
if (item.lastPublishTime) existing.lastPublishTime = item.lastPublishTime;
await this.forage.setItem(this.blacklist_key, list);
}
async deleteBlacklistItem(starId) {
const list = await this.getBlacklist();
const filtered = list.filter((entry) => entry.starId !== starId);
if (list.length !== filtered.length) await this.forage.setItem(this.blacklist_key, filtered);
}
async getBlacklistCarList() {
const cached = this.cache_filter_actor_actress_car_list;
if (cached && cached.length > 0) return cached;
const fresh = await this.forage.getItem(this.blacklist_car_list_key) || [];
this.cache_filter_actor_actress_car_list = fresh;
return fresh;
}
async batchSaveBlacklistCarList(inputs) {
const list = await this.getBlacklistCarList();
const cloned = JSON.parse(JSON.stringify(list));
let changed = false;
const newCarNums = [];
for (const item of inputs) if (!cloned.find((entry) => entry.carNum === item.carNum)) {
this._saveSingleCar(item, cloned);
clog.log(`屏蔽演员番号: <span style="color: #f40">${item.names} ${item.carNum}</span>`);
changed = true;
newCarNums.push(item.carNum);
}
if (changed) {
await this.forage.setItem(this.blacklist_car_list_key, cloned);
await this.removeNewVideoList(newCarNums);
window.cleanCache_filter_actor_actress_car_list();
}
}
async removeBlacklistCarList(starId) {
const list = await this.getBlacklistCarList();
const filtered = list.filter((item) => item.starId !== starId);
if (filtered.length !== list.length) {
await this.forage.setItem(this.blacklist_car_list_key, filtered);
window.cleanCache_filter_actor_actress_car_list();
}
}
async getFavoriteActressList() {
return await this.forage.getItem(this.favorite_actresses_key) || [];
}
async addFavoriteActressList(inputs) {
const list = await this.getFavoriteActressList();
let count = 0;
for (const item of inputs) {
let { starId, name, allName, avatar, lastCheckTime, lastPublishTime, actressType } = item;
if (!starId) throw new Error("缺失starId");
if (!name) throw new Error("缺失name");
if (!allName) allName = [name];
if (!actressType) actressType = name.includes(UNCENSORED_TAG) || allName.some((n) => n.includes(UNCENSORED_TAG)) ? UNCENSORED : CENSORED;
name = name.replace(UNCENSORED_TAG, "");
allName = allName.map((n) => n.replace(UNCENSORED_TAG, ""));
const existing = list.find((entry) => entry.starId === starId);
if (existing) {
if (!existing.avatar || !existing.avatar.includes("https")) {
if (avatar) {
clog.log(avatar);
existing.avatar = avatar;
clog.log(`<span style="color: #f40">补全女优头像: ${name}</span>`);
count++;
}
}
if (!existing.actressType && actressType) {
existing.actressType = actressType;
clog.log(`<span style="color: #f40">补全女优类别: ${name} ${actressType}</span>`);
count++;
}
if (existing.name.includes(UNCENSORED_TAG)) {
existing.name = name;
existing.allName = allName;
clog.log(`<span style="color: #f40">更正女优名字: ${name} ${allName}</span>`);
count++;
}
continue;
}
const now = utils.getNowStr();
list.push({
starId,
name,
allName,
avatar,
lastCheckTime,
lastPublishTime,
createDate: now,
updateDate: now,
actressType
});
clog.log(`<span style="color: #f40">同步JavDB已收藏的演员: ${name}</span>`);
count++;
}
if (count > 0) await this.forage.setItem(this.favorite_actresses_key, list);
else clog.log("信息已记录, 无需要进行同步收藏的演员");
return count;
}
async removeFavoriteActress(starId) {
const list = await this.getFavoriteActressList();
const beforeLen = list.length;
const filtered = list.filter((entry) => entry.starId !== starId);
if (filtered.length === beforeLen) {
clog.error(`移除演员失败, ${starId} 不存在`);
return false;
} else {
await this.forage.setItem(this.favorite_actresses_key, filtered);
return true;
}
}
async updateFavoriteActress(item) {
const list = await this.getFavoriteActressList();
const { starId, name, allName, avatar, lastCheckTime, newVideoList, lastPublishTime, actressType, remark } = item;
if (!starId) throw new Error("缺失starId");
const existing = list.find((entry) => entry.starId === starId);
if (!existing) {
clog.error("未找到演员信息", starId, name);
return false;
}
if (name) existing.name = name;
if (allName) existing.allName = allName;
if (avatar) existing.avatar = avatar;
if (actressType != null) existing.actressType = actressType;
if (lastCheckTime) existing.lastCheckTime = lastCheckTime;
if (newVideoList) existing.newVideoList = newVideoList;
if (lastPublishTime) existing.lastPublishTime = lastPublishTime;
if (remark) existing.remark = remark;
existing.updateDate = utils.getNowStr();
await this.forage.setItem(this.favorite_actresses_key, list);
}
async getHighlightedTags() {
return await this.forage.getItem(this.highlighted_tags_key) || [];
}
async setHighlightedTags(tags) {
return await this.forage.setItem(this.highlighted_tags_key, tags);
}
async #saveKeyword(keyword, key, label) {
let list;
if (Array.isArray(keyword)) list = [...keyword];
else {
list = await this.forage.getItem(key) || [];
if (list.includes(keyword)) {
const msg = `${keyword} ${label}已存在`;
show.error(msg);
throw new Error(msg);
}
list.push(keyword);
}
await this.forage.setItem(key, list);
return list;
}
async saveTitleFilterKeyword(keyword) {
await this.#saveKeyword(keyword, this.filter_keyword_title_key, "标题关键词");
if (Array.isArray(keyword)) return null;
const actressList = await this.getFavoriteActressList();
let changed = false;
const updated = actressList.map((actress) => {
if (!actress.newVideoList || !Array.isArray(actress.newVideoList)) return actress;
const filtered = actress.newVideoList.filter((carNum) => {
const matched = carNum.startsWith(keyword);
if (matched) {
clog.log("移除关联女优新作品", actress.name, carNum);
changed = true;
}
return !matched;
});
return {
...actress,
newVideoList: filtered
};
});
if (changed) await this.forage.setItem(this.favorite_actresses_key, updated);
}
async saveReviewFilterKeyword(keyword) {
return this.#saveKeyword(keyword, this.filter_keyword_review_key, "评论关键词");
}
async getTitleFilterKeyword() {
return await this.forage.getItem(this.filter_keyword_title_key) || [];
}
async getReviewFilterKeywordList() {
return await this.forage.getItem(this.filter_keyword_review_key) || [];
}
async getSetting(key = null, defaultValue) {
if (!this.cacheSettingObj) this.cacheSettingObj = await this.forage.getItem(this.setting_key) || {};
const setting = this.cacheSettingObj;
if (key === null) return setting;
const val = setting[key];
if (val) if (val === "true" || val === "false") return val.toLowerCase() === "true";
else if (typeof val != "string" || val.trim() === "" || isNaN(Number(val))) return val;
else return Number(val);
else return defaultValue;
}
async saveSetting(setting) {
if (setting) {
await this.forage.setItem(this.setting_key, setting);
window.clean_cacheSettingObj();
} else show.error("设置对象为空");
}
async saveSettingItem(key, value) {
if (!key) {
show.error("key 不能为空");
return;
}
const setting = await this.getSetting();
setting[key] = value;
await this.saveSetting(setting);
window.clean_cacheSettingObj();
}
async importData(data) {
await this.forage.clear();
const tasks = [];
for (const key in data) {
const value = data[key];
const task = this.forage.setItem(key, value);
tasks.push(task);
}
await Promise.all(tasks);
}
async exportData() {
const data = {};
await this.forage.iterate((value, key) => {
data[key] = value;
});
if (Object.keys(data).length === 0) throw new Error("没有可导出的数据");
return data;
}
async merge_table_name() {
let oldKey = "filter_actor_actress_info_list";
let items = await this.forage.getItem(oldKey) || [];
if (items && items.length > 0) {
console.log("更正", oldKey);
await this.forage.setItem(this.blacklist_key, items);
}
await this.forage.removeItem(oldKey);
oldKey = "favorite_actresses_info_list";
items = await this.forage.getItem(oldKey) || [];
if (items && items.length > 0) {
console.log("更正", oldKey);
await this.forage.setItem(this.favorite_actresses_key, items);
}
await this.forage.removeItem(oldKey);
oldKey = "car_list_filter_actor_actress";
items = await this.forage.getItem(oldKey) || [];
if (items && items.length > 0) {
console.log("更正", oldKey);
await this.forage.setItem(this.blacklist_car_list_key, items);
}
await this.forage.removeItem(oldKey);
oldKey = "title_filter_keyword";
items = await this.forage.getItem(oldKey) || [];
if (items && items.length > 0) {
console.log("更正", oldKey);
await this.forage.setItem(this.filter_keyword_title_key, items);
}
await this.forage.removeItem(oldKey);
oldKey = "review_filter_keyword";
items = await this.forage.getItem(oldKey) || [];
if (items && items.length > 0) {
console.log("更正", oldKey);
await this.forage.setItem(this.filter_keyword_review_key, items);
}
await this.forage.removeItem(oldKey);
oldKey = "highlightedTags";
items = await this.forage.getItem(oldKey) || [];
if (items && items.length > 0) {
console.log("更正", oldKey);
await this.forage.setItem(this.highlighted_tags_key, items);
}
await this.forage.removeItem(oldKey);
}
async clean_no_url_blacklist() {
const [blacklistCars, blacklist] = await Promise.all([this.getBlacklistCarList(), this.getBlacklist()]);
if (blacklistCars.length && !blacklistCars[0].actress) return;
const nameSet = new Set(blacklist.map((item) => item.name));
const filteredCars = blacklistCars.filter((item) => !item.actress || nameSet.has(item.actress));
if (blacklistCars.length !== filteredCars.length) {
clog.debug("清理 blacklistCarList 前", blacklistCars.length);
clog.debug("清理 blacklistCarList 后", filteredCars.length);
await this.forage.setItem(this.blacklist_car_list_key, filteredCars);
this.cache_filter_actor_actress_car_list = null;
}
const actressSet = new Set(filteredCars.map((item) => item.actress));
let cleanedBlacklist = blacklist.filter((item) => actressSet.has(item.name));
cleanedBlacklist = cleanedBlacklist.map((item) => {
const cleaned = { ...item };
delete cleaned.key;
delete cleaned.recordTime;
if (item.recordTime !== void 0) cleaned.createTime = item.recordTime;
return cleaned;
});
if (blacklist.length !== cleanedBlacklist.length || blacklist.some((item) => "key" in item || "recordTime" in item)) {
clog.debug("清理 Blacklist 前", blacklist.length);
clog.debug("清理 Blacklist 后", cleanedBlacklist.length);
await this.forage.setItem(this.blacklist_key, cleanedBlacklist);
}
}
async async_merge_other() {
const setting = await this.getSetting();
let changed = false;
for (const key of [
"enableCheckFilterActorActress",
"checkIntervalTime_filterActorActress",
"checkIntervalTime_ruleTime",
"checkIntervalTime_newVideo",
"checkIntervalTime_favoriteActress",
"checkFilterTime",
"checkFilterConcurrencyCount",
"checkFilterSleep",
"enableCheckBlacklist",
"checkBlacklist_intervalTime",
"checkBlacklist_ruleTime",
"enableCheckFavoriteActress",
"checkFavoriteActress_IntervalTime",
"enableCheckNewVideo",
"checkNewVideo_intervalTime",
"checkNewVideo_ruleTime",
"checkConcurrencyCount",
"checkRequestSleep"
]) if (Object.prototype.hasOwnProperty.call(setting, key)) {
delete setting[key];
changed = true;
}
if (setting.downPath115) {
delete setting.downPath115;
changed = true;
}
if (changed) {
await this.saveSetting(setting);
clog.debug("配置数据已更正");
}
}
async merge_blacklist() {
const list = await this.getBlacklist();
if (!list || list.length === 0) return;
let changed = false;
const merged = list.map((item) => {
let itemChanged = false;
if (Object.prototype.hasOwnProperty.call(item, "isActor") && !item.role) {
item.role = item.isActor ? ACTOR : ACTRESS;
delete item.isActor;
itemChanged = true;
}
if (!item.starId && item.url) try {
const extracted = new URL(item.url).pathname.split("/").filter((seg) => seg.trim() !== "").pop();
if (item.starId !== extracted) {
item.starId = extracted;
itemChanged = true;
}
} catch (err) {
clog.error("提取url-starId发生错误", item.url, err);
}
if (!item.allName) {
item.allName = item.name ? [item.name] : [];
itemChanged = true;
}
if (!item.movieType) {
item.movieType = CENSORED;
itemChanged = true;
}
if (item.url && item.url.includes("sort_type")) try {
const urlObj = new URL(item.url);
urlObj.searchParams.delete("sort_type");
item.url = urlObj.toString();
itemChanged = true;
clog.debug("去除黑名单地址sort_type参数");
} catch (err) {
clog.error("去除黑名单地址sort_type参数失败", item.url, err);
}
if (itemChanged) changed = true;
return item;
});
if (changed) {
clog.debug("更正 Blacklist 数据结构");
await this.forage.setItem(this.blacklist_key, merged);
}
const carList = await this.getBlacklistCarList();
changed = false;
const mergedCars = carList.map((item) => {
if (!item.starId) {
const match = list.find((entry) => entry.name === item.actress);
if (match) item.starId = match.starId;
changed = true;
}
if (item.type) {
delete item.type;
changed = true;
}
return item;
});
if (changed) {
clog.debug("更正 blacklistCarList 数据结构");
await this.forage.setItem(this.blacklist_car_list_key, mergedCars);
}
}
async merge_favoriteActress() {
const list = await this.getFavoriteActressList();
if (!list || list.length === 0) return;
let changed = false;
const merged = list.map((item) => {
let itemChanged = false;
if (item.dbId) {
item.starId = item.dbId;
delete item.dbId;
itemChanged = true;
}
if (itemChanged) changed = true;
return item;
});
if (changed) {
clog.debug("更正 favoriteActressesInfoList 数据结构");
await this.forage.setItem(this.favorite_actresses_key, merged);
}
}
async merge_tow_car_list_table() {
const blacklistCars = await this.getBlacklistCarList();
const carList = await this.getCarList();
let changed = false;
const mergedBlacklistCars = blacklistCars.map((item) => {
let itemChanged = false;
if (item.actress !== void 0) {
item.names = item.actress;
delete item.actress;
itemChanged = true;
}
if (itemChanged) changed = true;
return item;
});
if (changed) {
clog.debug("更正 blacklistCarList 数据结构 actress->names");
await this.forage.setItem(this.blacklist_car_list_key, mergedBlacklistCars);
}
changed = false;
const mergedCars = carList.map((item) => {
let itemChanged = false;
if (item.actress !== void 0) {
item.names = item.actress;
delete item.actress;
itemChanged = true;
}
if (itemChanged) changed = true;
return item;
});
if (changed) {
clog.debug("更正 carList 数据结构 actress->names");
await this.forage.setItem(this.car_list_key, mergedCars);
}
}
};
var CommonUtil = class CommonUtil {
static instance;
intervalContainer = {};
mimeTypes = {
txt: "text/plain",
html: "text/html",
css: "text/css",
csv: "text/csv",
json: "application/json",
xml: "application/xml",
jpg: "image/jpeg",
jpeg: "image/jpeg",
png: "image/png",
gif: "image/gif",
webp: "image/webp",
svg: "image/svg+xml",
pdf: "application/pdf",
doc: "application/msword",
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
xls: "application/vnd.ms-excel",
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
ppt: "application/vnd.ms-powerpoint",
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
zip: "application/zip",
rar: "application/x-rar-compressed",
"7z": "application/x-7z-compressed",
mp3: "audio/mpeg",
wav: "audio/wav",
mp4: "video/mp4",
webm: "video/webm",
ogg: "audio/ogg"
};
timers = new Map();
insertStyle = (css) => {
if (css) {
if (css.indexOf("<style>") === -1) css = "<style>" + css + "</style>";
$("head").append(css);
}
};
layerIndexStack = [];
_boundHandler = null;
constructor() {
CommonUtil.instance ||= this;
return CommonUtil.instance;
}
importResource(url) {
let el;
if (url.indexOf("css") >= 0) {
const link = document.createElement("link");
link.setAttribute("rel", "stylesheet");
link.href = url;
el = link;
} else {
const script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.src = url;
el = script;
}
document.documentElement.appendChild(el);
}
openPage(url, title, shadeClose, event) {
shadeClose = shadeClose ?? true;
if (event && (event.ctrlKey || event.metaKey)) {
GM_openInTab(url.includes("http") ? url : window.location.origin + url, { insert: 0 });
return;
}
let content = url;
if (!url.includes("/actors/") && !url.includes("/star/")) content = url.includes("?") ? `${url}&hideNav=1` : `${url}?hideNav=1`;
layer.open({
type: 2,
title,
content,
scrollbar: false,
shadeClose,
area: this.getResponsiveArea(["85%", "90%"]),
isOutAnim: false,
anim: -1,
success: (_layerEl, layerIdx) => {
this.setupEscClose(layerIdx);
}
});
}
_handleGlobalEscKey(event) {
if (event.key !== "Escape" && event.keyCode !== 27) return;
if (this.layerIndexStack.length === 0) return;
const layerIdx = this.layerIndexStack[this.layerIndexStack.length - 1];
const layerEl = $(`#layui-layer${layerIdx}`);
let hasViewer = false;
if (layerEl.find(".viewer-container").length > 0) hasViewer = true;
else {
const iframeEl = layerEl.find(`#layui-layer-iframe${layerIdx}`)[0];
if (iframeEl && iframeEl.contentDocument) try {
if ($(iframeEl.contentDocument).find(".viewer-container").length > 0) hasViewer = true;
} catch {
clog.warn("无法检查跨域 iframe 内的 .viewer-container");
}
}
if (!hasViewer) {
this.layerIndexStack.pop();
layer.close(layerIdx);
}
}
setupEscClose(layerIdx) {
if (!this._boundHandler) {
this._boundHandler = this._handleGlobalEscKey.bind(this);
$(document).off("keydown.globalLayerEsc");
$(document).on("keydown.globalLayerEsc", this._boundHandler);
}
if (this.layerIndexStack.indexOf(layerIdx) === -1) this.layerIndexStack.push(layerIdx);
const iframeEl = $(`#layui-layer-iframe${layerIdx}`);
const eventNamespace = `keydown.layerEsc${layerIdx}`;
try {
const doc = iframeEl[0]?.contentDocument;
if (doc) {
if (iframeEl.attr("data-esc-bound") === "yes") return;
$(doc).off(eventNamespace);
$(doc).on(eventNamespace, this._boundHandler);
iframeEl.attr("data-esc-bound", "yes");
}
} catch (err) {
clog.error("iframe监听失败 (跨域或未加载完毕):", err);
}
}
closePage() {
storageManager.getSetting("needClosePage", "yes").then((setting) => {
if (setting !== "yes") return;
parent.document.documentElement.style.overflow = "auto";
[
".layui-layer-shade",
".layui-layer-move",
".layui-layer"
].forEach((selector) => {
const matches = parent.document.querySelectorAll(selector);
if (matches.length > 0) {
const el = matches.length > 1 ? matches[matches.length - 1] : matches[0];
el.parentNode.removeChild(el);
}
});
window.close();
});
}
loopDetector(checkFn, onSuccess, intervalMs = 20, timeoutMs = 1e4, callOnTimeout = true) {
const token = String(Math.random());
const startTime = new Date().getTime();
const finish = (triggered) => {
clearInterval(this.intervalContainer[token]);
if (triggered && onSuccess) onSuccess();
delete this.intervalContainer[token];
};
this.intervalContainer[token] = setInterval(() => {
const elapsed = new Date().getTime() - startTime;
if (checkFn()) finish(true);
else if (elapsed >= timeoutMs) finish(callOnTimeout);
}, intervalMs);
}
rightClick(container, targetSelector, handler) {
let el;
if (typeof container === "string") el = document.querySelector(container);
else if (container instanceof HTMLElement) el = container;
if (!el) {
console.warn("rightClick(), 容器无效或未提供,将使用 document.body 进行全局委托。");
el = document.body;
}
if (typeof targetSelector === "string" && targetSelector.trim() !== "") el.addEventListener("contextmenu", (event) => {
const target = event.target.closest(targetSelector);
if (target) handler(event, target);
});
else console.error("rightClick(), 必须提供有效的 targetSelector。");
}
q(event, content, onConfirm, onCancel) {
let left;
let top;
if (event) {
left = event.clientX - 130;
top = event.clientY - 120;
} else {
left = window.innerWidth / 2 - 120;
top = window.innerHeight / 2 - 120;
}
let layerIdx = layer.confirm(content, {
offset: [top, left],
title: "提示",
btn: ["确定", "取消"],
shade: 0,
zIndex: 999999991
}, function() {
if (onConfirm) onConfirm();
layer.close(layerIdx);
}, function() {
if (onCancel) onCancel();
});
}
getNowStr(dateSep = "-", timeSep = ":", timestamp = null) {
const date = timestamp ? new Date(timestamp) : new Date();
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
const hours = String(date.getHours()).padStart(2, "0");
const minutes = String(date.getMinutes()).padStart(2, "0");
const seconds = String(date.getSeconds()).padStart(2, "0");
return `${[
year,
month,
day
].join(dateSep)} ${[
hours,
minutes,
seconds
].join(timeSep)}`;
}
formatDate(input, dateSep = "-", timeSep = ":") {
let date;
if (input instanceof Date) date = input;
else {
if (typeof input !== "string") throw new Error("Invalid date input: must be Date object or date string");
date = new Date(input);
if (isNaN(date.getTime())) throw new Error("Invalid date string");
}
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
const hours = String(date.getHours()).padStart(2, "0");
const minutes = String(date.getMinutes()).padStart(2, "0");
const seconds = String(date.getSeconds()).padStart(2, "0");
return `${[
year,
month,
day
].join(dateSep)} ${[
hours,
minutes,
seconds
].join(timeSep)}`;
}
getHourDifference(start, end) {
const startMs = start.getTime();
const endMs = end.getTime();
const hours = Math.abs(endMs - startMs) / 36e5;
return Math.floor(hours);
}
isUnnecessaryCheck(timeStr, checkIntervalTime) {
if (!checkIntervalTime) throw new Error("未传入checkIntervalTime");
const hours = parseInt(String(checkIntervalTime), 10);
return this.getHourDifference(new Date(timeStr), new Date()) < hours;
}
download(data, filename) {
show.info("开始请求下载...");
const ext = filename.split(".").pop().toLowerCase();
const mimeType = this.mimeTypes[ext] || "application/octet-stream";
let blob;
if (data instanceof Blob) blob = data;
else if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) blob = new Blob([data], { type: mimeType });
else if (typeof data === "string" && data.startsWith("data:")) {
const raw = atob(data.split(",")[1]);
const buf = new ArrayBuffer(raw.length);
const bytes = new Uint8Array(buf);
for (let i = 0; i < raw.length; i++) bytes[i] = raw.charCodeAt(i);
blob = new Blob([bytes], { type: mimeType });
} else blob = new Blob([data], { type: mimeType });
const url = URL.createObjectURL(blob);
const anchor = document.createElement("a");
anchor.href = url;
anchor.download = filename;
document.body.appendChild(anchor);
anchor.click();
setTimeout(() => {
document.body.removeChild(anchor);
URL.revokeObjectURL(url);
}, 100);
}
smoothScrollToTop(duration = 500) {
return new Promise((resolve) => {
const startTime = performance.now();
const startY = window.pageYOffset;
window.requestAnimationFrame(function step(now) {
const elapsed = now - startTime;
const progress = Math.min(elapsed / duration, 1);
const eased = progress < .5 ? progress * 4 * progress * progress : 1 - Math.pow(progress * -2 + 2, 3) / 2;
window.scrollTo(0, startY * (1 - eased));
if (progress < 1) window.requestAnimationFrame(step);
else resolve();
});
});
}
simpleId() {
return crypto.randomUUID().replace("-", "");
}
isUrl(str) {
try {
new URL(str);
return true;
} catch {
return false;
}
}
setHrefParam(key, value) {
const url = new URL(window.location.href);
url.searchParams.set(key, value);
window.history.pushState({}, "", url.toString());
}
getUrlParam(url, param) {
const query = url.split("?")[1];
if (!query) return null;
const regex = new RegExp(`(?:^|&)${param}=([^&]*)`);
const match = query.match(regex);
let value = "";
if (match && match[1]) value = decodeURIComponent(match[1].replace(/\+/g, " "));
if (value) if (value === "true" || value === "false") return value.toLowerCase() === "true";
else if (typeof value !== "string" || value.trim() === "" || isNaN(Number(value))) return value;
else return Number(value);
else return value;
}
reBuildSignature() {
const tsKey = "jhs_review_ts";
const signKey = "jhs_review_sign";
const nowSec = Math.floor(Date.now() / 1e3);
if (nowSec - (Number(localStorage.getItem(tsKey)) || 0) <= 20) return localStorage.getItem(signKey);
const sign = `${nowSec}.lpw6vgqzsp.${md5(`${nowSec}71cf27bb3c0bcdf207b64abecddc970098c7421ee7203b9cdae54478478a199e7d5a6e1a57691123c1a931c057842fb73ba3b3c83bcd69c17ccf174081e3d8aa`)}`;
localStorage.setItem(tsKey, String(nowSec));
localStorage.setItem(signKey, sign);
return sign;
}
getResponsiveArea(area) {
const width = window.innerWidth;
if (width >= 1200) return area || this.getDefaultArea();
else if (width >= 768) return ["70%", "90%"];
else return ["95%", "95%"];
}
getDefaultArea() {
return ["85%", "90%"];
}
isMobile() {
const ua = navigator.userAgent.toLowerCase();
return [
"iphone",
"ipod",
"ipad",
"android",
"blackberry",
"windows phone",
"nokia",
"webos",
"opera mini",
"mobile",
"mobi",
"tablet"
].some((keyword) => ua.includes(keyword));
}
copyToClipboard(label, text) {
navigator.clipboard.writeText(text).then(() => show.info(`${label}已复制到剪切板, ${text}`)).catch((err) => console.error("复制失败: ", err));
}
htmlTo$dom(html) {
const parser = new DOMParser();
return $(parser.parseFromString(html, "text/html"));
}
addCookie(cookieStr, options = {}) {
const { maxAge = 604800, path = "/", domain = "", secure = false, sameSite = "Lax" } = options;
cookieStr.split(";").forEach((pair) => {
const trimmed = pair.trim();
if (trimmed) {
const parts = trimmed.split("=");
if (parts.length >= 2 && parts[0].trim()) {
const segments = [`${parts[0].trim()}=${parts.slice(1).join("=")}`];
if (maxAge > 0) segments.push(`max-age=${maxAge}`);
segments.push(`path=${path}`);
if (domain) segments.push(`domain=${domain}`);
if (secure) segments.push("Secure");
if (sameSite) segments.push(`SameSite=${sameSite}`);
console.log("document.cookie = '" + segments.join("; ") + "'");
document.cookie = segments.join("; ");
}
}
});
}
isHidden(el) {
const node = el.jquery ? el[0] : el;
return !node || node.offsetWidth <= 0 && node.offsetHeight <= 0 || window.getComputedStyle(node).display === "none";
}
time(label = "default", unit = "s", precision = 2) {
if (this.timers.has(label)) {
const entry = this.timers.get(label);
const elapsed = performance.now() - entry.startTime;
let formatted;
let unitLabel;
if (entry.unit === "s") {
formatted = (elapsed / 1e3).toFixed(entry.precision);
unitLabel = "秒";
} else {
formatted = elapsed.toFixed(entry.precision);
unitLabel = "毫秒";
}
this.timers.delete(label);
return `${label}: ${formatted}${unitLabel}`;
}
this.timers.set(label, {
startTime: performance.now(),
unit,
precision
});
}
sleep(ms = 1e3) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
genericSort(data, sortConfigs, nullsFirst = true) {
if (!Array.isArray(data) || data.length === 0) return [];
if (!Array.isArray(sortConfigs) || sortConfigs.length === 0) return [...data];
const items = [...data];
const coerceDate = (value) => {
if (value instanceof Date) return value;
if (typeof value === "string") {
const parsed = new Date(value);
if (!isNaN(parsed.getTime())) return parsed;
}
return value;
};
return items.sort((itemA, itemB) => {
for (const config of sortConfigs) {
const { key, order = "asc" } = config;
let valA = itemA;
let valB = itemB;
if (key != null) if (typeof key === "function") {
valA = key(itemA);
valB = key(itemB);
} else {
valA = itemA && typeof itemA === "object" ? itemA[key] : void 0;
valB = itemB && typeof itemB === "object" ? itemB[key] : void 0;
}
const coercedA = coerceDate(valA);
const coercedB = coerceDate(valB);
let cmp = 0;
const aIsNull = valA == null;
const bIsNull = valB == null;
if (aIsNull && bIsNull) return 0;
if (aIsNull) if (nullsFirst) return 1;
else return -1;
if (bIsNull) if (nullsFirst) return 1;
else return -1;
cmp = coercedA instanceof Date && coercedB instanceof Date ? coercedA.getTime() - coercedB.getTime() : typeof valA === "number" && typeof valB === "number" ? valA - valB : typeof valA === "string" && typeof valB === "string" ? valA.localeCompare(valB) : String(valA).localeCompare(String(valB));
if (order === "desc") cmp *= -1;
if (cmp !== 0) return cmp;
}
return 0;
});
}
async retry(fn, maxRetries = 3) {
let attempt = 0;
while (attempt < maxRetries) try {
const result = await fn();
if (attempt > 0) clog.debug(`[重试] 请求成功,共发起 ${attempt + 1} 次。`);
return result;
} catch (err) {
const msg = String(err);
if (msg.includes("Just a moment") || msg.includes("重定向") || msg.toLowerCase().includes("404 not found")) throw err;
attempt++;
if (attempt === maxRetries) {
clog.debug(`[重试] 达到最大重试次数 (${maxRetries}),最终失败:`, err);
throw err;
}
clog.debug(`[重试] 请求失败,准备第 ${attempt + 1} 次重试, 错误信息: ${msg}`);
}
}
};
var GmHttp = class {
async get(url, queryParams = {}, headers = {}, followRedirect) {
return this.gmRequest("GET", url, null, queryParams, headers, followRedirect);
}
post(url, body = {}, headers = {}) {
const requestHeaders = {
"Content-Type": "application/json",
...headers
};
const bodyString = JSON.stringify(body);
return this.gmRequest("POST", url, bodyString, null, requestHeaders);
}
postForm(url, formData = {}, headers = {}) {
const requestHeaders = headers || {};
requestHeaders["Content-Type"] ||= "application/x-www-form-urlencoded";
let bodyString = "";
if (formData && Object.keys(formData).length > 0) bodyString = Object.entries(formData).map(([key, value]) => `${key}=${String(value)}`).join("&");
return this.gmRequest("POST", url, bodyString, null, requestHeaders);
}
postFileFormData(url, formFields = {}, headers = {}) {
const requestHeaders = headers || {};
const boundary = `----WebKitFormBoundary${Math.random().toString(36).substring(2)}`;
requestHeaders["Content-Type"] = `multipart/form-data; boundary=${boundary}`;
let body = "";
if (formFields && Object.keys(formFields).length > 0) body = Object.entries(formFields).map(([key, value]) => `--${boundary}\r\nContent-Disposition: form-data; name="${key}"\r\n\r\n${String(value)}\r\n`).join("");
body += `--${boundary}--`;
return this.gmRequest("POST", url, body, null, requestHeaders);
}
async downloadFileInChunks(url, headers = {}, filename, transform) {
if (!filename) throw new Error("请提供文件名 (filename) 用于保存。");
const timeout = await storageManager.getSetting("httpTimeout", 5e3);
const retryCount = await storageManager.getSetting("httpRetryCount", 3);
let fileSize = 0;
let mimeType;
clog.log(`[${filename}] 正在获取文件大小...`);
try {
const sizeResponse = await utils.retry(() => new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url,
headers: {
...headers,
Range: "bytes=0-0"
},
timeout,
onload: resolve,
onerror: () => reject(new Error("网络错误:无法获取文件大小")),
ontimeout: () => reject(new Error("超时:获取文件大小"))
});
}), retryCount);
if (sizeResponse.status !== 206 && sizeResponse.status !== 200) throw new Error(`请求文件大小失败,状态码: ${sizeResponse.status}`);
{
const contentRangeMatch = sizeResponse.responseHeaders.match(/content-range:\s*bytes\s*\d+-\d+\/(\d+)/i);
const contentTypeMatch = sizeResponse.responseHeaders.match(/content-type:\s*([^\s;]+)/i);
if (contentRangeMatch && contentRangeMatch[1]) fileSize = parseInt(contentRangeMatch[1], 10);
else {
const contentLengthMatch = sizeResponse.responseHeaders.match(/content-length:\s*(\d+)/i);
if (!contentLengthMatch || sizeResponse.status !== 200) throw new Error("无法从响应头中获取文件总大小,服务器可能不支持 Range 请求。");
fileSize = parseInt(contentLengthMatch[1], 10);
clog.warn(`[${filename}] 服务器返回 200 状态码,可能不支持 Range 请求。将尝试完整下载。`);
}
if (contentTypeMatch && contentTypeMatch[1]) mimeType = contentTypeMatch[1];
clog.log(`[${filename}] 文件总大小:${(fileSize / 1024 / 1024).toFixed(2)} MB, MIME 类型: ${mimeType || "未知"}`);
}
} catch (err) {
clog.error(`[${filename}] 获取文件大小失败:`, err.message);
throw err;
}
if (!fileSize || fileSize <= 0) throw new Error("获取到的文件大小无效或服务器拒绝提供大小信息。");
const chunkSize = 1048576;
const chunkCount = Math.ceil(fileSize / chunkSize);
const promises = [];
const chunks = new Array(chunkCount);
clog.log(`[${filename}] 文件将被分为 ${chunkCount} 块进行下载 (每块约 ${1 .toFixed(2)} MB)`);
for (let index = 0; index < chunkCount; index++) {
const start = index * chunkSize;
const rangeHeader = `bytes=${start}-${Math.min(start + chunkSize - 1, fileSize - 1)}`;
const promise = await utils.retry(() => new Promise((resolve, reject) => {
const requestHeaders = {
...headers,
Range: rangeHeader,
Accept: "application/octet-stream"
};
GM_xmlhttpRequest({
method: "GET",
url,
headers: requestHeaders,
timeout,
responseType: "arraybuffer",
onload: (response) => {
if (response.status === 206 || response.status === 200) {
const chunkData = response.response;
if (chunkData instanceof ArrayBuffer) {
chunks[index] = chunkData;
clog.log(`[${filename}] 成功下载第 ${index + 1}/${chunkCount} 块 (${rangeHeader})`);
resolve();
} else reject(new Error(`第 ${index + 1} 块响应不是 ArrayBuffer。`));
} else reject(new Error(`第 ${index + 1} 块请求失败,状态码: ${response.status}`));
},
onerror: (errorEvent) => reject(new Error(`第 ${index + 1} 块网络错误: ${errorEvent.error}`)),
ontimeout: () => reject(new Error(`第 ${index + 1} 块超时。`))
});
}), retryCount);
promises.push(promise);
}
try {
await Promise.all(promises);
clog.log(`[${filename}] 所有分块下载完成,开始合并...`);
} catch (err) {
clog.error(`[${filename}] 分块下载过程中发生错误:`, err.message);
throw err;
}
const blob = new Blob(chunks);
if (blob.size !== fileSize) clog.warn(`[${filename}] 警告:合并后的 Blob 大小 (${blob.size}) 与预期文件大小 (${fileSize}) 不匹配!`);
const text = await blob.text();
const content = transform ? transform(text) : text;
utils.download(content, filename);
clog.log(`[${filename}] 文件合并完成,已触发浏览器下载。`);
}
async gmRequest(method, url, data = {}, queryParams = {}, headers = {}, followRedirect = false) {
let requestUrl = url;
if (queryParams && Object.keys(queryParams).length) {
const queryString = new URLSearchParams(queryParams).toString();
requestUrl += (requestUrl.includes("?") ? "&" : "?") + queryString;
}
const timeout = await storageManager.getSetting("httpTimeout", 5e3);
const retryCount = await storageManager.getSetting("httpRetryCount", 3);
const requestData = data || void 0;
return await utils.retry(() => new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method,
url: requestUrl,
headers,
timeout,
data: requestData,
onload: (response) => {
try {
if (followRedirect && response.finalUrl !== requestUrl) reject("请求被重定向了,URL是:" + response.finalUrl);
if (response.status >= 200 && response.status < 300) if (response.responseText) try {
resolve(JSON.parse(response.responseText));
} catch {
resolve(response.responseText);
}
else resolve(response.responseText || response);
else {
clog.error("请求失败,状态码:", response.status, requestUrl);
if (response.responseText) try {
reject(JSON.parse(response.responseText));
} catch {
reject(new Error(response.responseText || `请求发生错误 ${response.status}`));
}
else reject(new Error(`请求发生错误 ${response.status}`));
}
} catch (err) {
reject(err);
}
},
onerror: (errorEvent) => {
clog.error("网络错误:", requestUrl);
reject(new Error(errorEvent.error || "网络错误"));
},
ontimeout: () => {
reject(new Error("请求超时: " + requestUrl));
}
});
}), retryCount);
}
};
function resetOverflowByShadeCount(delay = 10) {
setTimeout(() => {
const shadeCount = document.querySelectorAll(".layui-layer-shade").length;
document.documentElement.style.overflow = shadeCount > 0 ? "hidden" : "";
}, delay);
}
function setupLayerWrapper() {
const originalClose = layer.close;
layer.close = function(index) {
const result = originalClose.call(this, index);
resetOverflowByShadeCount();
return result;
};
const originalOpen = layer.open;
layer.open = function(options) {
const opts = options || {};
const originalSuccess = opts.success;
opts.success = function(el, index) {
if (typeof originalSuccess == "function") originalSuccess.call(this, el, index);
utils.setupEscClose(index);
};
return originalOpen.call(this, opts);
};
}
var tooltip_default = ".js-tooltip {\n /* 通用样式 */\n position: fixed;\n padding: 8px 12px;\n border-radius: 6px;\n white-space: normal;\n max-width: 600px;\n\n pointer-events: none;\n font-size: 14px;\n line-height: 1.5;\n z-index: 9999999999;\n\n background: #f0fdf4;\n color: #166534;\n border: none;\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);\n\n display: none;\n}\n.js-tooltip.is-active {\n display: block !important;\n}\n";
var TOOLTIP_SELECTOR = "[data-tip-top], [data-tip-bottom], [data-tip-left], [data-tip-right], [data-tip]";
function createTooltipElement(content) {
const wrapper = document.createElement("div");
wrapper.classList.add("js-tooltip");
const inner = document.createElement("div");
inner.innerHTML = content;
wrapper.appendChild(inner);
document.body.appendChild(wrapper);
return wrapper;
}
function positionTooltip(element, content, direction) {
const tooltip = createTooltipElement(content);
tooltip.style.display = "block";
const elementRect = element.getBoundingClientRect();
const tooltipRect = tooltip.getBoundingClientRect();
tooltip.style.display = "none";
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
let left;
let top;
let actualDirection = direction;
const fitsVertically = (y) => y >= 8 && y + tooltipRect.height <= viewportHeight - 8;
const fitsHorizontally = (x) => x >= 8 && x + tooltipRect.width <= viewportWidth - 8;
const centerX = elementRect.left + elementRect.width / 2 - tooltipRect.width / 2;
const centerY = elementRect.top + elementRect.height / 2 - tooltipRect.height / 2;
switch (direction) {
case "top":
top = elementRect.top - tooltipRect.height - 0;
if (top < 8 && fitsVertically(elementRect.bottom + 0)) {
top = elementRect.bottom + 0;
actualDirection = "bottom";
}
break;
case "bottom":
top = elementRect.bottom + 0;
if (top + tooltipRect.height > viewportHeight - 8 && fitsVertically(elementRect.top - tooltipRect.height - 0)) {
top = elementRect.top - tooltipRect.height - 0;
actualDirection = "top";
}
break;
case "left":
left = elementRect.left - tooltipRect.width - 0;
if (left < 8 && fitsHorizontally(elementRect.right + 0)) {
left = elementRect.right + 0;
actualDirection = "right";
}
break;
case "right":
left = elementRect.right + 0;
if (left + tooltipRect.width > viewportWidth - 8 && fitsHorizontally(elementRect.left - tooltipRect.width - 0)) {
left = elementRect.left - tooltipRect.width - 0;
actualDirection = "left";
}
break;
}
const isHorizontal = actualDirection === "left" || actualDirection === "right";
if (actualDirection === "top" || actualDirection === "bottom") {
left = centerX;
if (left < 8) left = 8;
else if (left + tooltipRect.width > viewportWidth - 8) left = viewportWidth - tooltipRect.width - 8;
} else if (isHorizontal) {
top = centerY;
if (top < 8) top = 8;
else if (top + tooltipRect.height > viewportHeight - 8) top = viewportHeight - tooltipRect.height - 8;
}
tooltip.style.left = `${left}px`;
tooltip.style.top = `${top}px`;
tooltip.classList.add("is-active");
element.tooltipElement = tooltip;
}
function setupTooltip() {
injectCss(tooltip_default);
document.addEventListener("mouseover", (event) => {
const target = event.target.closest(TOOLTIP_SELECTOR);
if (target && !target.tooltipElement) {
let content = "";
let direction = "top";
if (target.hasAttribute("data-tip-bottom")) {
content = target.getAttribute("data-tip-bottom") ?? "";
direction = "bottom";
} else if (target.hasAttribute("data-tip-left")) {
content = target.getAttribute("data-tip-left") ?? "";
direction = "left";
} else if (target.hasAttribute("data-tip-right")) {
content = target.getAttribute("data-tip-right") ?? "";
direction = "right";
} else if (target.hasAttribute("data-tip-top")) {
content = target.getAttribute("data-tip-top") ?? "";
direction = "top";
} else if (target.hasAttribute("data-tip")) {
content = target.getAttribute("data-tip") ?? "";
direction = "top";
}
if (!content) return;
target.hoverTimeout = window.setTimeout(() => {
if (target.matches(":hover") && !target.tooltipElement) positionTooltip(target, content, direction);
}, 50);
}
});
document.addEventListener("mouseout", (event) => {
const target = event.target.closest(TOOLTIP_SELECTOR);
if (!target) return;
if (target.hoverTimeout) {
clearTimeout(target.hoverTimeout);
target.hoverTimeout = null;
}
if (!target.contains(event.relatedTarget)) {
if (target.tooltipElement) {
target.tooltipElement.remove();
target.tooltipElement = null;
}
}
});
}
var WEBDAV_SALT = "x7k9p3";
function encryptCredential(value) {
return (WEBDAV_SALT + value + WEBDAV_SALT).split("").map((ch) => {
const code = ch.codePointAt(0);
return String.fromCodePoint(code + 5);
}).join("");
}
function decryptCredential(value) {
return value.split("").map((ch) => {
const code = ch.codePointAt(0);
return String.fromCodePoint(code - 5);
}).join("").slice(6, -6);
}
var PluginManager = class {
plugins = new Map();
register(pluginClass) {
if (typeof pluginClass !== "function") throw new Error("插件必须是一个类");
const instance = new pluginClass();
instance.pluginManager = this;
const pluginName = instance.getName();
if (this.plugins.has(pluginName)) throw new Error(`插件"${pluginName}"已注册`);
this.plugins.set(pluginName, instance);
}
getBean(name) {
return this.plugins.get(name);
}
async processCss() {
const failed = (await Promise.all(Array.from(this.plugins).map(async ([name, plugin]) => {
try {
if (typeof plugin.initCss === "function") {
const css = await plugin.initCss();
if (css) utils.insertStyle(css);
return {
name,
status: "fulfilled"
};
}
return {
name,
status: "skipped"
};
} catch (err) {
console.error(`插件 ${name} 加载 CSS 失败`, err);
return {
name,
status: "rejected",
error: err
};
}
}))).filter((result) => result.status === "rejected");
if (failed.length) console.error("以下插件的 CSS 加载失败:", failed.map((result) => result.name));
}
async processPlugins() {
const failed = (await Promise.all(Array.from(this.plugins).map(async ([name, plugin]) => {
try {
if (typeof plugin.handle === "function") {
await plugin.handle();
return {
name,
status: "fulfilled"
};
}
return {
name,
status: "skipped"
};
} catch (err) {
clog.error(`插件 ${name} 执行失败`, err);
return {
name,
status: "rejected",
error: err
};
}
}))).filter((result) => result.status === "rejected");
if (failed.length) console.error("以下插件执行失败:", failed.map((result) => result.name));
}
};
var SETTING_SVG = "<svg t=\"1760926954860\" class=\"jhs-icon icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"4947\" width=\"200\" height=\"200\"><path d=\"M511.099222 365.825763c-80.7786 0-146.26579 65.482515-146.26579 146.259556 0 80.7786 65.48719 146.259556 146.26579 146.259556 80.777041 0 146.259556-65.480957 146.259556-146.259556C657.358779 431.308278 591.876263 365.825763 511.099222 365.825763L511.099222 365.825763zM511.099222 585.215097c-40.391637 0-73.136012-32.742816-73.136012-73.129778 0-40.391637 32.742816-73.129778 73.136012-73.129778 40.386962 0 73.129778 32.738141 73.129778 73.129778C584.229 552.472281 551.486184 585.215097 511.099222 585.215097L511.099222 585.215097zM511.099222 585.215097M900.893017 568.24369l-26.451395-15.268032c3.065451-27.021784 3.138697-54.472139 0.077922-81.822754l26.373473-15.225955c69.953678-40.391637 93.920921-129.844512 53.533959-199.799749-40.390079-69.95212-129.839837-93.925596-199.799749-53.533959l-26.373473 15.225955c-22.153219-16.330888-45.963059-29.99217-70.896534-40.843585l0-30.545416c0-80.777041-65.48719-146.259556-146.26579-146.259556-80.7786 0-146.259556 65.482515-146.259556 146.259556l0 30.515806c-12.377127 5.421811-24.587501 11.55583-36.562551 18.473743-11.97505 6.917913-23.396854 14.420242-34.277879 22.432179l-26.431136-15.258682c-69.958353-40.391637-159.406553-16.424395-199.79819 53.533959C27.378272 326.082437 51.343956 415.535311 121.299193 455.922273l26.449837 15.275825c-3.063892 27.020226-3.137139 54.465905-0.077922 81.822754l-26.373473 15.224397c-69.953678 40.391637-93.920921 129.841395-53.533959 199.799749 40.391637 69.95212 129.839837 93.920921 199.79819 53.533959l26.375032-15.224397c22.153219 16.32933 45.963059 29.984378 70.896534 40.843585l0 30.537624c0 80.7786 65.48719 146.26579 146.26579 146.26579 80.777041 0 146.259556-65.48719 146.259556-146.26579l0-30.515806c12.377127-5.415577 24.587501-11.55583 36.567226-18.467509 11.97505-6.917913 23.398412-14.420242 34.277879-22.432179l26.423343 15.258682c69.959912 40.391637 159.408111 16.418162 199.799749-53.533959C994.813938 698.085085 970.848254 608.635327 900.893017 568.24369L900.893017 568.24369zM891.096666 731.474653c-20.198936 34.982294-64.923035 46.962019-99.900654 26.770875l-63.331869-36.567226 0 0 0 0-7.988562-4.611422c-18.134004 18.450366-39.024886 34.787489-62.516805 48.353705-23.49971 13.559983-48.091888 23.482568-73.129778 29.964118l0 9.222846 0 0 0 65.828489 0 7.301289c0 40.391637-32.742816 73.136012-73.136012 73.136012-40.386962 0-73.129778-32.742816-73.129778-73.136012l0-7.402588 0-65.72719 0 0 0-9.300768c-50.682014-13.090892-97.855981-39.682547-135.652816-78.232109l-7.983886 4.606747 0 0-63.331869 36.567226c-34.977618 20.191144-79.706394 8.206743-99.900654-26.770875-20.192702-34.977618-8.206743-79.701718 26.770875-99.899095l6.341291-3.657657 0 0 64.972905-37.516316c-14.487254-52.005129-13.929333-106.151555 0.073247-156.593569l-8.057133-4.650384 0 0-63.331869-36.567226c-34.982294-20.192702-46.963578-64.923035-26.770875-99.900654 20.192702-34.97606 64.923035-46.962019 99.900654-26.763083l6.324148 3.649866 0 0 64.996282 37.528784c18.132445-18.450366 39.024886-34.790606 62.516805-48.353705 23.493477-13.559983 48.085654-23.485685 73.129778-29.964118l0-9.229079L437.960093 153.739276l0-7.309082c0-40.385404 32.742816-73.129778 73.129778-73.129778 40.391637 0 73.129778 32.744375 73.129778 73.129778l0 7.404147 0 65.72719 0 9.307001c50.686689 13.086217 97.862215 39.684106 135.657491 78.232109l48.487732-27.997368 22.828023-13.176607c34.977618-20.192702 79.701718-8.212977 99.89442 26.763083 20.198936 34.982294 8.212977 79.706394-26.764641 99.900654l-30.822819 17.79738-32.50905 18.769847 0 0 0 0-7.983886 4.605189c14.488813 52.009805 13.929333 106.159347-0.077922 156.599803l64.979139 37.511641 0 0 6.414537 3.701294C899.303409 651.772936 911.289368 696.498594 891.096666 731.474653L891.096666 731.474653zM891.096666 731.474653M197.330785 324.240361c-1.932465 3.232203-3.824411 6.497135-5.649343 9.785442L197.330785 324.240361 197.330785 324.240361zM197.330785 324.240361M830.515443 690.133926l-5.655577 9.804144C826.793889 696.699632 828.685835 693.433143 830.515443 690.133926L830.515443 690.133926zM830.515443 690.133926M505.297151 146.430195l11.304921 0C512.835324 146.369416 509.067017 146.374091 505.297151 146.430195L505.297151 146.430195zM505.297151 146.430195M516.898176 877.740444l-11.31583 0C509.350653 877.796547 513.125193 877.796547 516.898176 877.740444L516.898176 877.740444zM516.898176 877.740444\" fill=\"#272636\" p-id=\"4948\"></path></svg>";
var EDIT_SVG = "<svg t=\"1760920692801\" class=\"jhs-icon icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"3545\" width=\"200\" height=\"200\"><path d=\"M1013.929675 128.26571a143.759824 143.759824 0 0 1 10.44409 53.858738 84.576649 84.576649 0 0 1-5.836403 30.308339 92.870485 92.870485 0 0 1-18.635533 29.284408 1314.726599 1314.726599 0 0 1-24.983901 24.574329c-7.372299 7.06512-13.82306 13.311095-19.249891 18.737926-6.143582 6.143582-12.082378 11.672806-17.406817 16.382886L720.266444 82.598415c9.317766-8.601015 20.478607-18.942712 33.277737-31.02509s23.448006-21.604931 31.946628-28.67005a102.085858 102.085858 0 0 1 68.193763-22.731255c11.263234 0.307179 22.116896 2.047861 32.560985 5.222045 10.546483 3.071791 19.659463 6.655547 27.441334 10.546483 16.280493 8.601015 34.301667 23.550399 54.063524 45.052936 19.864249 21.502538 35.120812 43.82422 46.076867 67.272226z m-907.20231 570.943576l32.560986-33.38013c17.099637-17.509209 38.397389-39.216533 64.098041-64.917186l84.986221-85.395793 94.303987-94.815953 250.350976-251.477299L850.817567 389.163169 600.46659 640.640468l-93.177663 94.815953c-31.02509 30.410732-58.978389 58.364031-83.859898 83.655111-24.779115 25.29108-45.360116 46.17926-61.743001 62.562146a504.797674 504.797674 0 0 1-55.804206 50.274981c-10.239304 7.884264-20.581 14.130239-31.537055 18.737926a507.152714 507.152714 0 0 1-47.715156 19.86425 1609.311367 1609.311367 0 0 1-131.063087 42.185931c-20.478607 5.426831-35.837563 8.908194-45.974474 10.546483-20.88818 2.35504-34.813633-0.819144-41.981145-9.42016-6.860333-8.601015-8.805801-22.93604-5.73401-43.312254a396.261054 396.261054 0 0 1 11.058448-47.305584c5.836403-20.683394 12.082378-42.185931 18.635532-64.40522 6.553154-22.219289 13.003916-42.697897 19.249891-61.435822 6.143582-18.635533 11.263234-31.537055 15.15417-38.602176 4.607687-10.853662 9.829732-20.785787 15.666135-29.796373a192.49891 192.49891 0 0 1 25.086294-29.796374z\" fill=\"#FF9500\" p-id=\"3546\"></path></svg>";
var DELETE_SVG = "<svg t=\"1760921450746\" class=\"jhs-icon icon\" viewBox=\"0 0 1194 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"4530\" width=\"200\" height=\"200\"><path d=\"M761.086847 36.028779s309.754321-147.538628 424.952209 231.50509c2.047962 6.570546 71.337359 253.862013-220.838618 415.139055-12.970429 7.167869-267.515096 145.746661-370.339877 341.327076 0 0-90.963666-205.649563-393.379455-351.566888-6.399883-3.071944-304.549083-156.583796-163.751664-487.2444 3.669266-8.533177 163.666333-336.20717 466.423449-99.411511l24.575549 27.391498L387.931021 324.279495l237.648977 159.570408-109.139333 145.746661L625.579998 849.069874l-30.719437-205.820227 166.226286-169.81022-216.486698-168.103585L761.086847 36.028779z\" fill=\"#F4382E\" p-id=\"4531\"></path></svg>";
var CHECK_SVG = "<svg t=\"1760921633527\" class=\"jhs-icon icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"5603\" width=\"200\" height=\"200\"><path d=\"M924.928 544A413.76 413.76 0 0 1 544 924.736v3.264h-64v-3.2A413.696 413.696 0 0 1 99.072 544H96v-64h3.072A413.696 413.696 0 0 1 480 99.2V96h64v3.2a413.76 413.76 0 0 1 380.928 380.8h3.072v64h-3.072z m-64-64A350.016 350.016 0 0 0 544 163.2V288h-64V163.2A350.016 350.016 0 0 0 163.072 480H288v64H163.072A350.016 350.016 0 0 0 480 860.8V736h64v124.8a350.016 350.016 0 0 0 316.928-316.8H736v-64h124.928zM512 544a32 32 0 1 1 32-32 32 32 0 0 1-32 32z\" fill=\"#333333\" p-id=\"5604\"></path></svg>";
var ACTRESS_SVG = "<svg t=\"1760926744637\" class=\"jhs-icon icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"1948\" width=\"200\" height=\"200\"><path d=\"M265.950168 668.467036V209.809493A209.809493 209.809493 0 0 1 475.759661 0h40.949536A209.809493 209.809493 0 0 1 726.564189 209.809493v440.435\" p-id=\"1949\"></path><path d=\"M916.558657 825.861124a193.463804 193.463804 0 0 0-137.442564-155.83573l-186.001889-45.795231-10.487631-124.293214H424.106373L412.231008 624.025416l-170.623063 44.44162a193.452429 193.452429 0 0 0-133.666108 154.698244L76.410695 1023.192384h871.189985z\" fill=\"#FFE7D9\" p-id=\"1950\"></path><path d=\"M668.472724 265.682859c68.431223-29.187919 96.140409 100.349111 5.20969 151.774902z\" fill=\"#FFCFB5\" p-id=\"1951\"></path><path d=\"M676.378259 334.421203c1.137487-99.814492-38.674561-172.158671-38.674561-172.15867l-59.740822 11.920865a493.805894 493.805894 0 0 1-80.761583 9.099896 493.669396 493.669396 0 0 1-80.761583-9.099896l-59.683948-11.88674s-39.812048 72.344179-38.776934 172.15867l-1.080613 92.05683c5.209691 56.271486 92.4777 121.381247 195.022161 119.163147 61.196805 0.034125 165.59537-51.573665 165.59537-119.197272z\" fill=\"#FFE7D9\" p-id=\"1952\"></path><path d=\"M322.198905 274.703131c-68.419848-29.187919-96.140409 100.349111-5.209691 151.774902z\" fill=\"#FFCFB5\" p-id=\"1953\"></path><path d=\"M297.390311 812.461526H742.034014a38.458438 38.458438 0 0 1 38.458438 38.458439V1020.325917H258.931873V850.90859a38.458438 38.458438 0 0 1 38.458438-38.447064z\" fill=\"#FFD527\" p-id=\"1954\"></path><path d=\"M690.539973 92.284327c-20.645391 84.287793-275.613121 235.323328-424.589805 117.525166l104.955934-95.548915 139.399042-64.529643z\" p-id=\"1955\"></path><path d=\"M285.321573 383.708519h33.624119v177.118114h-33.624119zM675.855015 383.708519h33.624118v177.118114h-33.624118z\" fill=\"#FFD527\" p-id=\"1956\"></path></svg>";
var NEW_SVG = "<svg t=\"1760926857487\" class=\"jhs-icon icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"3954\" width=\"200\" height=\"200\"><path d=\"M508.330667 733.994667c-11.008-7.338667-13.44-17.109333-7.338667-29.333334 28.117333-37.888 41.557333-98.986667 40.341333-183.317333v-165.013333c0-14.656 7.338667-23.210667 21.994667-25.664 37.888-1.216 82.496-5.504 133.845333-12.842667 13.44-2.432 21.376 3.072 23.829334 16.512 1.216 12.224-4.266667 19.562667-16.512 21.994667a1787.093333 1787.093333 0 0 1-113.664 11.008c-6.101333 0-9.173333 3.669333-9.173334 10.986666v84.330667h135.68c12.224 1.237333 18.944 7.957333 20.16 20.181333-1.216 10.986667-7.936 17.109333-20.16 18.346667h-36.672v223.658667c-1.216 12.202667-7.936 18.944-20.16 20.16-11.008-1.216-17.109333-7.957333-18.346666-20.16V501.162667h-60.48v18.346666c1.216 92.885333-13.44 161.92-44.010667 207.146667-6.101333 12.224-15.893333 14.677333-29.333333 7.338667z m-131.989334-282.325334c-1.237333 0-2.453333 0.618667-3.669333 1.834667h45.824a522.666667 522.666667 0 0 0 16.512-31.168c7.317333-12.224 12.224-20.778667 14.656-25.664 6.122667-11.008 15.274667-14.677333 27.52-11.008 9.770667 6.122667 12.202667 14.058667 7.317333 23.829333-4.906667 9.792-13.44 24.448-25.664 44.010667h49.493334c9.770667 1.216 15.274667 6.72 16.512 16.490667-1.237333 11.008-6.741333 17.109333-16.512 18.346666h-82.496a12.437333 12.437333 0 0 1 3.669333 9.173334v38.485333h69.653333c9.792 1.216 15.296 6.72 16.512 16.490667-1.216 11.008-6.72 17.130667-16.512 18.346666h-69.653333v108.16c0 34.218667-15.274667 51.946667-45.845333 53.162667h-16.490667a195.157333 195.157333 0 0 1-20.16 1.834667c-12.224 0-19.562667-6.72-22.016-20.16 1.237333-12.224 7.338667-18.944 18.346667-20.16 2.432 0 6.101333 0.597333 10.986666 1.834666h11.008c15.893333 0 23.829333-8.554667 23.829334-25.685333v-98.986667H314.026667c-11.008-1.216-17.109333-7.338667-18.346667-18.346666 1.237333-9.770667 7.338667-15.274667 18.346667-16.490667h75.157333V497.493333c0-3.669333 1.216-6.72 3.669333-9.173333h-89.813333c-11.029333-1.216-17.130667-7.317333-18.346667-18.325333 1.216-9.770667 7.317333-15.274667 18.346667-16.490667h56.810667c-3.669333-1.216-6.72-4.266667-9.173334-9.173333-1.216-1.216-3.050667-4.266667-5.482666-9.173334a758.336 758.336 0 0 0-14.677334-23.829333c-4.885333-9.770667-3.050667-17.706667 5.504-23.829333 11.008-3.669333 19.562667-1.216 25.664 7.338666 2.453333 2.432 6.122667 7.338667 11.008 14.656 6.101333 8.554667 9.770667 14.08 10.986667 16.512 4.906667 9.770667 2.453333 18.346667-7.317333 25.664z m-60.501333-71.509333c-9.792-1.216-15.274667-7.317333-16.512-18.346667 1.237333-9.749333 6.72-15.253333 16.512-16.490666h75.157333c-3.669333-12.202667-7.338667-21.973333-10.986666-29.333334-1.237333-12.202667 3.648-19.541333 14.656-21.973333 12.224-2.453333 21.397333 1.216 27.52 10.986667 0 1.216 0.597333 3.669333 1.813333 7.338666 4.906667 15.872 9.173333 26.88 12.842667 32.981334h60.48c11.008 1.237333 17.130667 6.741333 18.346666 16.512-1.216 11.008-7.338667 17.109333-18.346666 18.346666h-181.482667z m-14.677333 311.68c-8.533333-6.122667-10.986667-14.08-7.338667-23.829333a1659.648 1659.648 0 0 0 33.002667-66.005334c4.906667-9.792 12.224-12.842667 22.016-9.173333 9.770667 4.906667 13.44 12.224 10.986666 21.994667-3.669333 6.122667-9.173333 17.728-16.490666 34.837333-8.554667 15.893333-14.677333 27.52-18.346667 34.837333-4.885333 8.554667-12.821333 11.008-23.829333 7.338667z m201.664-25.664c-9.770667 4.885333-18.346667 2.432-25.664-7.338667a1138.56 1138.56 0 0 1-27.498667-44.010666c-4.885333-8.533333-3.050667-16.490667 5.504-23.829334 9.770667-3.669333 18.346667-1.216 25.664 7.338667l14.677333 21.994667c6.101333 9.770667 10.389333 17.109333 12.821334 21.994666 4.906667 8.554667 3.050667 16.512-5.504 23.850667z\" fill=\"#333333\" p-id=\"3955\"></path><path d=\"M675.328 117.717333A425.429333 425.429333 0 0 0 512 85.333333C276.352 85.333333 85.333333 276.352 85.333333 512s191.018667 426.666667 426.666667 426.666667 426.666667-191.018667 426.666667-426.666667c0-56.746667-11.093333-112-32.384-163.328a21.333333 21.333333 0 0 0-39.402667 16.341333A382.762667 382.762667 0 0 1 896 512c0 212.074667-171.925333 384-384 384S128 724.074667 128 512 299.925333 128 512 128c51.114667 0 100.8 9.984 146.986667 29.12a21.333333 21.333333 0 0 0 16.341333-39.402667z\" fill=\"#333333\" p-id=\"3956\"></path></svg>";
var REFRESH_SVG = "<svg t=\"1760926993643\" class=\"jhs-icon icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"5942\" width=\"200\" height=\"200\"><path d=\"M511.966722 0a511.966722 511.966722 0 1 0 179.828311 32.445891l-22.46254 59.964102A447.970882 447.970882 0 1 1 511.966722 63.99584a31.99792 31.99792 0 0 0 0-63.99584z\" fill=\"#333333\" p-id=\"5943\"></path><path d=\"M649.2378 9.151405A30.909991 30.909991 0 0 1 671.316364 0h193.267438a31.99792 31.99792 0 0 1 31.357962 31.99792c0 17.662852-13.759106 31.99792-31.357962 31.99792H703.954243v160.629559a31.99792 31.99792 0 0 1-31.99792 31.357962 31.485953 31.485953 0 0 1-31.99792-31.357962V31.357962c0-8.511447 3.647763-16.318939 9.343392-21.950573z\" fill=\"#333333\" p-id=\"5944\"></path></svg>";
var BLACKLIST_SVG = "<svg t=\"1761386375897\" class=\"jhs-icon icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"1936\" width=\"200\" height=\"200\"><path d=\"M513.199827 65.667605c-246.537999 0-446.399933 199.861934-446.399933 446.399933 0 246.553349 199.861934 446.399933 446.399933 446.399933 246.553349 0 446.399933-199.846584 446.399933-446.399933C959.599759 265.529539 759.753175 65.667605 513.199827 65.667605zM513.199827 894.697075c-211.320916 0-382.629537-171.322947-382.629537-382.628514 0-94.183056 34.029024-180.417069 90.461291-247.080352l165.389818 165.389818c4.320399 39.651069 26.816762 73.840752 58.981323 94.068446-72.189136 27.369348-123.517151 97.156784-123.517151 178.936345l337.541643 0 100.846826 100.846826C693.608709 860.664981 607.375719 894.697075 513.199827 894.697075zM805.362956 759.14175 697.264982 651.0448c-16.556071-58.332547-60.10082-105.306394-116.275213-126.601396 35.888372-22.570042 59.752896-62.511729 59.752896-108.032482 0-70.436212-57.108672-127.542838-127.542838-127.542838-48.218188 0-90.184999 26.765597-111.865787 66.245773L266.120498 219.900316c66.663282-56.432267 152.897296-90.461291 247.079328-90.461291 211.304544 0 382.628514 171.308621 382.628514 382.629537C895.82834 606.244454 861.796246 692.476421 805.362956 759.14175z\" fill=\"#272636\" p-id=\"1937\"></path></svg>";
var BasePlugin = class {
pluginManager = null;
settingSvg = SETTING_SVG;
editSvg = EDIT_SVG;
deleteSvg = DELETE_SVG;
checkSvg = CHECK_SVG;
actressSvg = ACTRESS_SVG;
newSvg = NEW_SVG;
refreshSvg = REFRESH_SVG;
blacklistSvg = BLACKLIST_SVG;
getName() {
throw new Error(`${this.constructor.name} 未显示getName()`);
}
getBean(name) {
return this.pluginManager.getBean(name);
}
async initCss() {
return "";
}
async handle() {}
getPageInfo() {
let carNum = null;
let url = null;
let actress = null;
let actors = null;
let publishTime = null;
const href = window.location.href;
if (isJavdbSite) {
carNum = $("a[title=\"複製番號\"]").attr("data-clipboard-text");
url = href.split("?")[0].split("#")[0];
actress = $(".female").prev().map((_index, el) => $(el).text()).get().join(" ");
actors = $(".male").prev().map((_index, el) => $(el).text()).get().join(" ");
publishTime = $("strong:contains(\"日期:\")").parent(".panel-block").find(".value").text().trim();
}
return {
carNum,
url,
actress,
actors,
publishTime
};
}
getActressId() {
const match = currentHref.match(/\/actors\/([^/?]+)/);
if (match && match.length > 1) return match[1];
else return null;
}
getActressPageInfo() {
const href = window.location.href;
if (!href.includes("/actors/") && !href.includes("/star/")) throw new Error("接口调用错误, 非演员详情页");
const allName = [];
const nameEl = $(".actor-section-name");
if (nameEl.length) nameEl.text().trim().split(",").forEach((part) => {
allName.push(part.trim());
});
const metaEl = $(".section-meta:not(:contains('影片'))");
if (metaEl.length) metaEl.text().trim().split(",").forEach((part) => {
allName.push(part.trim());
});
const role = $(".section-meta:contains('男優')").length > 0 ? ACTOR : ACTRESS;
let movieType = CENSORED;
if (allName.some((part) => part.includes("無碼"))) movieType = UNCENSORED;
if (href.includes("uncensored")) movieType = UNCENSORED;
let blacklistUrl = null;
let starId = null;
const urlObj = new URL(href);
if (isJavdbSite) {
starId = urlObj.pathname.split("/").filter((seg) => seg.trim() !== "").pop() ?? null;
const searchParams = urlObj.searchParams;
searchParams.delete("sort_type");
searchParams.delete("page");
blacklistUrl = urlObj.toString();
}
return {
starId,
name: allName[0],
allName,
role,
movieType,
blacklistUrl
};
}
getSelector(siteType) {
const type = siteType || "javdb";
const selectors = { javdb: {
boxSelector: ".movie-list",
itemSelector: ".movie-list .item",
coverImgSelector: ".cover img",
requestDomItemSelector: ".movie-list .item",
nextPageSelector: ".pagination-next"
} };
if (!type || !selectors[type]) throw new Error("类型错误: 无法确定选择器类型 (JavDb)");
return selectors[type];
}
parseMovieId(url) {
return url.split("/").pop().split(/[?#]/)[0];
}
getBoxCarInfo(boxEl) {
let titleAttr;
let imgTitleAttr;
let dataTitleAttr;
const linkEl = boxEl.find("a");
const url = linkEl.attr("href");
let carNum = null;
let title = null;
let publishTime = null;
const videoTitleEl = boxEl.find(".video-title");
if (videoTitleEl.length > 0) {
const strongEl = videoTitleEl.find("strong");
if (strongEl.length > 0) carNum = strongEl.text().trim();
title = (titleAttr = linkEl.attr("title")) == null ? void 0 : titleAttr.trim();
if (!title) {
const text = videoTitleEl.text().trim();
title = carNum && text.includes(carNum) ? text.replace(carNum, "").trim() : text;
}
publishTime = boxEl.find(".meta").text().trim();
}
if (!carNum) {
const imgEl = boxEl.find("img");
if (imgEl.length > 0) title = ((imgTitleAttr = imgEl.attr("title")) == null ? void 0 : imgTitleAttr.trim()) || ((dataTitleAttr = imgEl.attr("data-title")) == null ? void 0 : dataTitleAttr.trim());
const dates = boxEl.find("date").map((_index, el) => $(el).text().trim()).get();
const isDate = (val) => /^\d{4}-\d{1,2}-\d{1,2}$/.test(val);
publishTime = dates.find(isDate) || null;
carNum = dates.find((val) => !isDate(val)) || null;
}
if (!carNum) {
const msg = "提取番号信息失败: carNum 为空";
console.error("Error in getBoxCarInfo:", msg, "Box Element:", boxEl.get(0));
show.error(msg);
throw new Error(msg);
}
return {
carNum,
url: url || "",
title: title || "",
publishTime: publishTime || ""
};
}
getBoxCarInfoList(boxEls = null) {
boxEls ||= $(this.getSelector().itemSelector);
if (boxEls.length === 0) {
clog.error("获取当前列表页所有item的番号信息失败!");
return [];
}
const list = [];
boxEls.each((index, element) => {
const itemEl = $(element);
try {
const info = this.getBoxCarInfo(itemEl);
list.push(info);
} catch (err) {
clog.error("[getBoxCarInfoList] 提取单个 boxCar 信息失败:", err.message, "元素索引:", index);
}
});
return list;
}
checkDuplicateCarNumbers(list, other) {
if (!list || list.length === 0 || !other || other.length === 0) return false;
const existing = new Set(list.map((item) => item.carNum).filter(Boolean));
if (existing.size === 0) return false;
let consecutive = 0;
for (let i = 0; i < other.length; i++) {
const car = other[i] ? other[i].carNum : null;
if (car && existing.has(car)) {
consecutive++;
if (consecutive >= 2) {
clog.warn("警告: 检测到连续番号信息重复, 该类别可能已被限制页码。");
return true;
}
} else consecutive = 0;
}
return false;
}
};
var DetailPagePlugin = class extends BasePlugin {
getName() {
return "DetailPagePlugin";
}
constructor() {
super();
}
async handle() {
if (window.isDetailPage) {
$(".video-meta-panel a").each((_index, element) => {
const href = $(element).attr("href");
if (href && (href.startsWith("http://") || href.startsWith("https://") || href.startsWith("/"))) $(element).attr("target", "_blank");
});
this.handleFancyBox();
}
}
handleFancyBox() {
document.addEventListener("click", (event) => {
if (event.target.closest(".fancybox-button--thumbs")) {
const thumbsVisible = !$(".fancybox-thumbs").is(":hidden");
localStorage.setItem("jhs_fancyboxThumbs", thumbsVisible.toString());
unsafeWindow.$.fancybox.defaults.thumbs.autoStart = thumbsVisible;
}
});
if (unsafeWindow.$.fancybox !== void 0) {
const storedValue = localStorage.getItem("jhs_fancyboxThumbs");
unsafeWindow.$.fancybox.defaults.thumbs.autoStart = storedValue === "true";
}
}
};
var FilterTitleKeywordPlugin = class extends BasePlugin {
getName() {
return "FilterTitleKeywordPlugin";
}
async handle() {
if (!window.isDetailPage && !window.isFc2Page) return;
if (await storageManager.getSetting("enableTitleSelectFilter", "yes") !== "yes") return;
let selector;
if (isJavdbSite) selector = ".title strong, .current-title";
utils.rightClick(document.body, selector, (event) => {
const selectedText = window.getSelection()?.toString() ?? "";
if (selectedText) {
event.preventDefault();
const position = {
clientX: event.clientX,
clientY: event.clientY + 80
};
utils.q(position, `是否屏蔽标题关键词 ${selectedText}?`, async () => {
await storageManager.saveTitleFilterKeyword(selectedText);
window.refresh();
utils.closePage();
});
}
});
}
};
var HighlightMagnetPlugin = class extends BasePlugin {
getName() {
return "HighlightMagnetPlugin";
}
doFilterMagnet() {
this.handleDb();
}
handleDb() {
if (!isJavdbSite) return;
const nameEls = $("#magnets-content .name");
if (nameEls.length === 0) return;
const highQualityMarkers = [
"4k",
"-c",
"-u",
"-uc"
];
let hasHighQuality = false;
nameEls.each((_index, element) => {
const nameEl = $(element);
const nameText = nameEl.text().toLowerCase();
const isHighQuality = highQualityMarkers.some((marker) => nameText.includes(marker));
nameEl.parent().parent().parent().addClass("magnet-row");
if (nameText.includes("4k")) nameEl.css("color", "#f40");
if (isHighQuality) {
hasHighQuality = true;
nameEl.parent().parent().parent().addClass("high-quality");
}
});
if (hasHighQuality) $("#magnets-content .magnet-row").not(".high-quality").hide();
else $("#enable-magnets-filter").addClass("do-hide");
}
showAll() {
if (isJavdbSite) $("#magnets-content .item").toArray().forEach((element) => $(element).show());
}
};
function FoldCategorySectionButton() {
return (0, import_jsx_runtime.jsx)("div", {
id: "foldCategoryBtn",
children: (0, import_jsx_runtime.jsxs)("a", {
className: "menu-btn",
style: {
backgroundColor: "#d23e60 !important",
marginLeft: "20px",
borderBottom: "none !important",
borderRadius: "3px"
},
children: [(0, import_jsx_runtime.jsx)("span", {}), (0, import_jsx_runtime.jsx)("i", { style: { marginLeft: "10px" } })]
})
});
}
function FoldCategoryToolbar({ selectedTagsText, hotkey }) {
return (0, import_jsx_runtime.jsxs)("div", {
style: {
display: "flex",
alignItems: "center",
flexGrow: 1,
justifyContent: "flex-end"
},
children: [(0, import_jsx_runtime.jsxs)("div", { children: ["已选分类: ", (0, import_jsx_runtime.jsx)("span", {
id: "jhs-check-tag",
children: selectedTagsText
})] }), (0, import_jsx_runtime.jsxs)("a", {
className: "menu-btn main-tab-btn",
id: "foldCategoryBtn",
style: { backgroundColor: "#d23e60 !important" },
children: [
(0, import_jsx_runtime.jsx)("span", {}),
hotkey ? ` (${hotkey})` : "",
(0, import_jsx_runtime.jsx)("i", { style: { marginLeft: "10px" } })
]
})]
});
}
function HighlightButton() {
return (0, import_jsx_runtime.jsx)("button", {
className: "highlight-btn",
title: "高亮显示",
children: "★"
});
}
var fold_category_plugin_default = "#tags a.tag,\n.tags a.tag {\n position: relative;\n}\n.highlight-btn {\n position: absolute;\n top: -10px;\n right: -10px;\n background-color: #4caf50;\n color: white;\n border: none;\n border-radius: 50%;\n width: 24px;\n height: 24px;\n font-size: 14px;\n line-height: 24px;\n text-align: center;\n cursor: pointer;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);\n display: none;\n z-index: 999;\n}\n/* 当父元素被高亮时,按钮变为其他颜色 */\n.highlighted .highlight-btn {\n background-color: #ff5722;\n}\n/* 高亮状态下的标签样式 */\n.highlighted {\n /* 浅黄色 */\n border: __HIGHLIGHTED_TAG_NUMBER__px solid __HIGHLIGHTED_TAG_COLOR__;\n}\n";
var FoldCategoryPlugin = class extends BasePlugin {
getName() {
return "FoldCategoryPlugin";
}
async initCss() {
const settings = await storageManager.getSetting();
return fold_category_plugin_default.replace("__HIGHLIGHTED_TAG_NUMBER__", String(settings.highlightedTagNumber || 1)).replace("__HIGHLIGHTED_TAG_COLOR__", settings.highlightedTagColor || "#ce2222");
}
async handle() {
if (window.isListPage) {
if (!currentHref.includes("advanced_search")) {
this.highlightTag();
utils.loopDetector(() => $("#waitCheckBtn").length, () => {
this.createFoldBtn();
}, 1, 1e4, true);
$("#tags .tag-category .tag-expand").each((_index, expandEl) => {
if ($(expandEl).parent().hasClass("collapse")) expandEl.click();
});
}
}
}
highlightTag() {
(async () => {
const highlightedTags = await storageManager.getHighlightedTags();
if (highlightedTags) highlightedTags.forEach((tagName) => {
$(`#tags a.tag:contains(${tagName})`).addClass("highlighted");
$(`.tags a.tag:contains(${tagName})`).addClass("highlighted");
});
})().then();
$("#tags a.tag, .tags a.tag").hover(function() {
const tagEl = $(this);
const btnEl = $(jsxToString((0, import_jsx_runtime.jsx)(HighlightButton, {})));
tagEl.append(btnEl);
btnEl.fadeIn(0);
}, function() {
$(this).find(".highlight-btn").fadeOut(0, function() {
$(this).remove();
});
});
$(document).on("click", ".highlight-btn", async function(event) {
event.stopPropagation();
event.preventDefault();
const tagEl = $(this).closest("a.tag");
const cloneEl = tagEl.clone();
cloneEl.find(".highlight-btn").remove();
const tagName = cloneEl.text().trim().replace(/\s*\(\d+\)$/, "");
let highlightedTags = await storageManager.getHighlightedTags();
if (highlightedTags.includes(tagName)) {
highlightedTags = highlightedTags.filter((item) => item !== tagName);
tagEl.removeClass("highlighted");
} else {
highlightedTags.push(tagName);
tagEl.addClass("highlighted");
}
await storageManager.setHighlightedTags(highlightedTags);
});
}
async createFoldBtn() {
const hotkey = await storageManager.getSetting("foldCategoryHotKey");
let tagsEl = $("#tags");
let selectedTagsText = $("#tags dl div.tag.is-info").map(function() {
return $(this).text().replaceAll("\n", "").replaceAll(" ", "");
}).get().join(" ");
if (!selectedTagsText) return;
$(".tabs").append(jsxToString((0, import_jsx_runtime.jsx)(FoldCategoryToolbar, {
selectedTagsText,
hotkey: hotkey || ""
})));
let sectionTitleEl = $("h2.section-title");
if (sectionTitleEl.length > 0) {
sectionTitleEl.append(jsxToString((0, import_jsx_runtime.jsx)(FoldCategorySectionButton, {})));
tagsEl = $("section > div > div.box");
}
if (!tagsEl) return;
const foldBtnEl = $("#foldCategoryBtn");
let isFolded = localStorage.getItem("jhs_foldCategory") === "yes";
let [label, iconClass] = isFolded ? ["展开", "icon-angle-double-down"] : ["折叠", "icon-angle-double-up"];
foldBtnEl.find("span").text(label).end().find("i").attr("class", iconClass);
if (!window.location.href.includes("noFold=1")) tagsEl[isFolded ? "hide" : "show"]();
foldBtnEl.on("click", async (event) => {
event.preventDefault();
isFolded = !isFolded;
localStorage.setItem("jhs_foldCategory", isFolded ? "yes" : "no");
const [nextLabel, nextIconClass] = isFolded ? ["展开", "icon-angle-double-down"] : ["折叠", "icon-angle-double-up"];
foldBtnEl.find("span").text(nextLabel).end().find("i").attr("class", nextIconClass);
tagsEl[isFolded ? "hide" : "show"]();
});
}
};
var actress_info_plugin_default = ".info-tag {\n background-color: #ecf5ff;\n display: inline-block;\n height: 32px;\n padding: 0 10px;\n line-height: 30px;\n font-size: 12px;\n color: #409eff;\n border: 1px solid #d9ecff;\n border-radius: 4px;\n box-sizing: border-box;\n white-space: nowrap;\n}\n";
function ActressInfoDetailSegment({ actressName, info, wikiApiUrl }) {
if (info) return (0, import_jsx_runtime.jsxs)("div", {
className: "panel-block actress-info",
children: [(0, import_jsx_runtime.jsxs)("strong", { children: [actressName, ":"] }), (0, import_jsx_runtime.jsxs)("a", {
href: info.url,
style: { marginLeft: "5px" },
target: "_blank",
children: [
(0, import_jsx_runtime.jsxs)("span", {
className: "info-tag",
children: [
info.birthday,
" ",
info.age
]
}),
(0, import_jsx_runtime.jsxs)("span", {
className: "info-tag",
children: [
info.height,
" ",
info.weight
]
}),
(0, import_jsx_runtime.jsxs)("span", {
className: "info-tag",
children: [
info.threeSizeText,
" ",
info.braSize
]
})
]
})]
});
return (0, import_jsx_runtime.jsx)("div", {
className: "panel-block actress-info",
children: (0, import_jsx_runtime.jsx)("a", {
href: wikiApiUrl + actressName,
target: "_blank",
children: (0, import_jsx_runtime.jsxs)("strong", { children: [actressName, ":"] })
})
});
}
function ActressInfoStarPageHtml({ info }) {
if (info) return (0, import_jsx_runtime.jsx)("a", {
className: "actress-info",
href: info.url,
target: "_blank",
children: (0, import_jsx_runtime.jsxs)("div", {
style: {
fontSize: "17px",
fontWeight: "normal",
marginTop: "5px"
},
children: [(0, import_jsx_runtime.jsxs)("div", {
style: {
display: "flex",
marginBottom: "10px"
},
children: [
(0, import_jsx_runtime.jsxs)("span", {
style: { width: "300px" },
children: ["出生日期: ", info.birthday]
}),
(0, import_jsx_runtime.jsxs)("span", {
style: { width: "200px" },
children: ["年龄: ", info.age]
}),
(0, import_jsx_runtime.jsxs)("span", {
style: { width: "200px" },
children: ["身高: ", info.height]
})
]
}), (0, import_jsx_runtime.jsxs)("div", {
style: {
display: "flex",
marginBottom: "10px"
},
children: [
(0, import_jsx_runtime.jsxs)("span", {
style: { width: "300px" },
children: ["体重: ", info.weight]
}),
(0, import_jsx_runtime.jsxs)("span", {
style: { width: "200px" },
children: ["三围: ", info.threeSizeText]
}),
(0, import_jsx_runtime.jsxs)("span", {
style: { width: "200px" },
children: ["罩杯: ", info.braSize]
})
]
})]
})
});
return (0, import_jsx_runtime.jsx)("div", {
className: "actress-info",
style: {
fontSize: "17px",
fontWeight: "normal",
marginTop: "5px"
},
children: "无此相关演员信息"
});
}
var ActressInfoPlugin = class extends BasePlugin {
apiUrl = "https://ja.wikipedia.org/wiki/";
getName() {
return "ActressInfoPlugin";
}
async handle() {
if (await storageManager.getSetting("enableLoadActressInfo", "yes") === "yes") this.loadActressInfo();
}
loadActressInfo() {
this.handleDetailPage().then();
this.handleStarPage().then();
}
async initCss() {
return actress_info_plugin_default;
}
async handleDetailPage() {
if ($(".actress-info").length > 0) return;
const actressNames = $(".female").prev().map((_index, element) => $(element).text().trim()).get();
if (!actressNames.length) return;
const storageKey = "jhs_actress_info";
const rawCache = localStorage.getItem(storageKey);
const cache = rawCache ? JSON.parse(rawCache) : {};
let info = null;
let html = "";
for (const actressName of actressNames) {
info = cache[actressName];
if (!info) try {
info = await this.searchInfo(actressName);
if (info) cache[actressName] = info;
} catch {
console.error("该名称查询失败,尝试其它名称");
}
const segment = jsxToString((0, import_jsx_runtime.jsx)(ActressInfoDetailSegment, {
actressName,
info,
wikiApiUrl: this.apiUrl
}));
html += segment;
}
$("strong:contains(\"演員\")").parent().after(html);
localStorage.setItem(storageKey, JSON.stringify(cache));
}
async handleStarPage() {
if ($(".actress-info").length > 0) return;
let names = [];
const nameSectionEl = $(".actor-section-name");
if (nameSectionEl.length) nameSectionEl.text().trim().split(",").forEach((name) => {
names.push(name.trim());
});
const metaEl = $(".section-meta:not(:contains('影片'))");
if (metaEl.length) metaEl.text().trim().split(",").forEach((name) => {
names.push(name.trim());
});
if (!names.length) return;
const storageKey = "jhs_actress_info";
const rawCache = localStorage.getItem(storageKey);
const cache = rawCache ? JSON.parse(rawCache) : {};
let info = null;
for (const actressName of names) {
info = cache[actressName];
if (info) break;
try {
info = await this.searchInfo(actressName);
} catch {
console.error("该名称查询失败,尝试其它名称");
}
if (info) break;
}
if (info) names.forEach((actressName) => {
cache[actressName] = info;
});
const html = jsxToString((0, import_jsx_runtime.jsx)(ActressInfoStarPageHtml, { info }));
nameSectionEl.parent().append(html);
localStorage.setItem(storageKey, JSON.stringify(cache));
}
async searchInfo(actressName) {
if (actressName === "三上悠亞") actressName = "三上悠亜";
const url = this.apiUrl + actressName;
const responseHtml = await gmHttp.get(url);
const domParser = new DOMParser();
const $parsed = $(domParser.parseFromString(responseHtml, "text/html"));
const birthday = $parsed.find("a[title=\"誕生日\"]").parent().parent().find("td").text().trim();
const age = $parsed.find("th:contains('現年齢')").parent().find("td").text().trim() ? parseInt($parsed.find("th:contains('現年齢')").parent().find("td").text().trim()) + "岁" : "";
const height = $parsed.find("tr:has(a[title=\"身長\"]) td").text().trim().split(" ")[0] + "cm";
let weight = $parsed.find("tr:has(a[title=\"体重\"]) td").text().trim().split("/")[1].trim();
if (weight === "― kg") weight = "";
return {
birthday,
age,
height,
weight,
threeSizeText: $parsed.find("a[title=\"スリーサイズ\"]").closest("tr").find("td").text().replace("cm", "").trim(),
braSize: $parsed.find("th:contains(\"ブラサイズ\")").next("td").contents().first().text().trim(),
url
};
}
};
var API_BASE = "https://jdforrepam.com/api";
var SIGNATURE_TIME_KEY = "jhs_review_ts";
var SIGNATURE_VALUE_KEY = "jhs_review_sign";
var SIGNATURE_TTL_SECONDS = 20;
var SIGNATURE_NAMESPACE = "lpw6vgqzsp";
var SIGNATURE_SALT = "71cf27bb3c0bcdf207b64abecddc970098c7421ee7203b9cdae54478478a199e7d5a6e1a57691123c1a931c057842fb73ba3b3c83bcd69c17ccf174081e3d8aa";
function reBuildSignature() {
const now = Math.floor(Date.now() / 1e3);
if (now - Number(localStorage.getItem(SIGNATURE_TIME_KEY) || 0) <= SIGNATURE_TTL_SECONDS) return localStorage.getItem(SIGNATURE_VALUE_KEY);
const sig = `${now}.${SIGNATURE_NAMESPACE}.${md5(`${now}${SIGNATURE_SALT}`)}`;
localStorage.setItem(SIGNATURE_TIME_KEY, String(now));
localStorage.setItem(SIGNATURE_VALUE_KEY, sig);
return sig;
}
async function fetchMovieReviews(movieId, page = 1, limit = 20) {
const url = `${API_BASE}/v1/movies/${movieId}/reviews`;
const headers = { jdSignature: await reBuildSignature() };
return (await gmHttp.get(url, {
page,
sort_by: "hotly",
limit
}, headers)).data.reviews;
}
async function fetchMovieDetail(movieId) {
const url = `${API_BASE}/v4/movies/${movieId}`;
const headers = { jdSignature: await reBuildSignature() };
const resp = await gmHttp.get(url, null, headers);
if (!resp.data) {
show.error("获取视频详情失败: " + resp.message);
throw new Error(resp.message);
}
const movie = resp.data.movie;
const imgList = [];
movie.preview_images.forEach((img) => {
imgList.push(img.large_url.replace("https://tp-iu.cmastd.com/rhe951l4q", "https://c0.jdbstatic.com"));
});
return {
movieId: movie.id,
actors: movie.actors,
duration: movie.duration,
title: movie.origin_title,
carNum: movie.number,
score: movie.score,
releaseDate: movie.release_date,
watchedCount: movie.watched_count,
imgList
};
}
async function fetchRelatedCollections(movieId, page = 1, limit = 20) {
const url = `${API_BASE}/v1/lists/related?movie_id=${movieId}&page=${page}&limit=${limit}`;
const headers = { jdSignature: await reBuildSignature() };
const resp = await gmHttp.get(url, null, headers);
const list = [];
resp.data.lists.forEach((item) => {
list.push({
relatedId: item.id,
name: item.name,
movieCount: item.movies_count,
collectionCount: item.collections_count,
viewCount: item.views_count,
createTime: utils.formatDate(item.created_at)
});
});
return list;
}
async function fetchPlaybackRanking(period = "daily", filterBy = "high_score") {
const url = `${API_BASE}/v1/rankings/playback?period=${period}&filter_by=${filterBy}`;
const headers = { jdSignature: await reBuildSignature() };
return (await gmHttp.get(url, null, headers)).data.movies;
}
var APP_AUTH_KEY$1 = "jhs_appAuthorization";
async function DEFAULT_REQUEST_HEADERS() {
return {
"user-agent": "Dart/3.5 (dart:io)",
"accept-language": "zh-TW",
host: "jdforrepam.com",
authorization: "Bearer " + localStorage.getItem(APP_AUTH_KEY$1),
jdsignature: await reBuildSignature()
};
}
async function fetchTopMovies(type = "all", typeValue = "", page = 1, limit = 40) {
const url = `${API_BASE}/v1/movies/top?start_rank=1&type=${type}&type_value=${typeValue}&ignore_watched=false&page=${page}&limit=${limit}`;
const headers = await DEFAULT_REQUEST_HEADERS();
return await gmHttp.get(url, null, headers);
}
function HitShowMovieItem({ movie }) {
return (0, import_jsx_runtime.jsx)("div", {
className: "item",
id: movie.id,
children: (0, import_jsx_runtime.jsxs)("a", {
href: `/v/${movie.id}`,
className: "box",
title: movie.origin_title,
children: [
(0, import_jsx_runtime.jsx)("div", {
className: "cover ",
children: (0, import_jsx_runtime.jsx)("img", {
loading: "lazy",
src: movie.cover_url.replace("https://tp-iu.cmastd.com/rhe951l4q", "https://c0.jdbstatic.com"),
alt: ""
})
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "video-title",
children: [
(0, import_jsx_runtime.jsx)("strong", { children: movie.number }),
" ",
movie.origin_title
]
}),
(0, import_jsx_runtime.jsx)("div", {
className: "score",
id: `score_${movie.id}`
}),
(0, import_jsx_runtime.jsx)("div", {
className: "meta",
children: movie.release_date
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "tags has-addons",
children: [
movie.has_cnsub ? (0, import_jsx_runtime.jsx)("span", {
className: "tag is-warning",
children: "含中字磁鏈"
}) : movie.magnets_count > 0 ? (0, import_jsx_runtime.jsx)("span", {
className: "tag is-success",
children: "含磁鏈"
}) : (0, import_jsx_runtime.jsx)("span", {
className: "tag is-info",
children: "无磁鏈"
}),
" ",
movie.new_magnets ? (0, import_jsx_runtime.jsx)("span", {
className: "tag is-info",
children: "今日新種"
}) : null
]
})
]
})
});
}
function getStarRating(score) {
const stars = [];
const fullStars = Math.floor(score);
for (let i = 0; i < fullStars; i++) stars.push((0, import_jsx_runtime.jsx)("i", { className: "icon-star" }));
for (let i = 0; i < 5 - fullStars; i++) stars.push((0, import_jsx_runtime.jsx)("i", { className: "icon-star gray" }));
return stars;
}
function HitShowScore({ score, watchedCount }) {
return (0, import_jsx_runtime.jsxs)("span", {
className: "value",
children: [
(0, import_jsx_runtime.jsx)("span", {
className: "score-stars",
children: getStarRating(score)
}),
" \xA0 ",
score,
"分,由",
watchedCount,
"人評價"
]
});
}
function HitShowToolBar({ period }) {
return (0, import_jsx_runtime.jsx)("div", {
className: "button-group",
style: { marginTop: "18px" },
children: (0, import_jsx_runtime.jsxs)("div", {
className: "buttons has-addons",
id: "conditionBox",
children: [
(0, import_jsx_runtime.jsx)("a", {
style: { padding: "18px 18px !important" },
className: `button is-small ${period === "daily" ? "is-info" : ""}`,
href: "/advanced_search?handlePlayback=1&period=daily",
children: "日榜"
}),
" ",
(0, import_jsx_runtime.jsx)("a", {
style: { padding: "18px 18px !important" },
className: `button is-small ${period === "weekly" ? "is-info" : ""}`,
href: "/advanced_search?handlePlayback=1&period=weekly",
children: "周榜"
}),
" ",
(0, import_jsx_runtime.jsx)("a", {
style: { padding: "18px 18px !important" },
className: `button is-small ${period === "monthly" ? "is-info" : ""}`,
href: "/advanced_search?handlePlayback=1&period=monthly",
children: "月榜"
})
]
})
});
}
function RankingContainers() {
return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("div", {
className: "tool-box",
style: { marginTop: "10px" }
}), (0, import_jsx_runtime.jsx)("div", {
className: "movie-list h cols-4 vcols-8",
style: { marginTop: "10px" }
})] });
}
var HitShowPlugin = class extends BasePlugin {
contentBox = $(".section .container");
getName() {
return "HitShowPlugin";
}
async handle() {
$("a[href*=\"rankings/playback\"]").on("click", (event) => {
event.preventDefault();
event.stopPropagation();
window.location.href = "/advanced_search?handlePlayback=1&period=daily";
});
this.handlePlayback().then();
}
hookPage() {
const titleEl = $("h2.section-title");
titleEl.contents().first().replaceWith("热播");
titleEl.css("marginBottom", "0");
$(".empty-message").remove();
$(".section .container .box").remove();
$("#sort-toggle-btn").remove();
this.contentBox.append(jsxToString((0, import_jsx_runtime.jsx)(RankingContainers, {})));
}
async handlePlayback() {
if (!window.location.href.includes("handlePlayback=1")) return;
const period = new URLSearchParams(window.location.search).get("period");
this.toolBar(period);
this.hookPage();
const movieListEl = $(".movie-list");
movieListEl.html("");
const loadingOverlay = loading();
let success = false;
for (let attempt = 1; attempt <= 3 && !success; attempt++) try {
const movies = await fetchPlaybackRanking(period ?? "daily");
const html = this.markDataListHtml(movies);
movieListEl.html(html);
this.loadScore(movies);
success = true;
} catch (error) {
if (attempt < 3) {
clog.error(`获取热播数据失败 (第 ${attempt} 次重试)`, error);
await new Promise((resolve) => setTimeout(resolve, 1e3));
} else clog.error("所有重试尝试均失败,无法获取数据。", error);
} finally {
if (success || attempt === 3) loadingOverlay.close();
}
}
toolBar(period) {
this.contentBox.append(jsxToString((0, import_jsx_runtime.jsx)(HitShowToolBar, { period })));
}
loadScore(movies) {
if (movies.length === 0) return;
(async () => {
const storageKey = "jhs_score_info";
for (const movie of movies) try {
const movieId = movie.id;
if (!$(`#score_${movieId}`).length) return;
if ($(`#${movieId}`).is(":hidden")) continue;
const rawCache = localStorage.getItem(storageKey);
const cache = rawCache ? JSON.parse(rawCache) : {};
const cachedHtml = cache[movieId];
if (cachedHtml) {
this.appendScoreHtml(movieId, cachedHtml);
continue;
}
while (!document.hasFocus()) await new Promise((resolve) => setTimeout(resolve, 500));
const detail = await fetchMovieDetail(movieId);
const score = detail.score;
const watchedCount = detail.watchedCount;
const scoreHtml = jsxToString((0, import_jsx_runtime.jsx)(HitShowScore, {
score,
watchedCount
}));
this.appendScoreHtml(movieId, scoreHtml);
cache[movieId] = scoreHtml;
localStorage.setItem(storageKey, JSON.stringify(cache));
await new Promise((resolve) => setTimeout(resolve, 500));
} catch (error) {
clog.error(`🚨 解析评分数据失败 | 编号: ${movie.number}\n`, `错误详情: ${error.message}\n`, error.stack ? `调用栈:\n${error.stack}` : "");
}
})();
}
appendScoreHtml(movieId, html) {
const scoreEl = $(`#score_${movieId}`);
if (scoreEl.length && scoreEl.html().trim() === "") scoreEl.slideUp(0, function() {
$(this).html(html).slideDown(500);
});
}
markDataListHtml(movies) {
let html = "";
movies.forEach((movie) => {
html += jsxToString((0, import_jsx_runtime.jsx)(HitShowMovieItem, { movie }));
});
return html;
}
};
function LoginDialog() {
return (0, import_jsx_runtime.jsxs)("div", {
style: {
padding: "30px",
fontFamily: "'Helvetica Neue', Arial, sans-serif"
},
children: [
(0, import_jsx_runtime.jsx)("div", {
style: { marginBottom: "25px" },
children: (0, import_jsx_runtime.jsx)("input", {
type: "text",
id: "username",
name: "username",
style: {
width: "100%",
padding: "12px 15px",
border: "1px solid #e0e0e0",
borderRadius: "4px",
boxSizing: "border-box",
transition: "all 0.3s",
fontSize: "14px",
background: "#f9f9f9",
color: "#333"
},
placeholder: "用户名 | 邮箱"
})
}),
(0, import_jsx_runtime.jsx)("div", {
style: { marginBottom: "15px" },
children: (0, import_jsx_runtime.jsx)("input", {
type: "password",
id: "password",
name: "password",
style: {
width: "100%",
padding: "12px 15px",
border: "1px solid #e0e0e0",
borderRadius: "4px",
boxSizing: "border-box",
transition: "all 0.3s",
fontSize: "14px",
background: "#f9f9f9",
color: "#333"
},
placeholder: "密码"
})
}),
(0, import_jsx_runtime.jsx)("button", {
id: "loginBtn",
style: {
width: "100%",
padding: "12px",
background: "#4a8bfc",
color: "white",
border: "none",
borderRadius: "4px",
fontSize: "15px",
cursor: "pointer",
transition: "background 0.3s"
},
children: "登录"
})
]
});
}
function Top250ErrorMessage({ message }) {
return (0, import_jsx_runtime.jsx)("h3", { children: message });
}
function Top250LoadError() {
return (0, import_jsx_runtime.jsx)("h3", { children: "无法加载数据,请稍后再试。" });
}
function Top250NavLink() {
return (0, import_jsx_runtime.jsx)("a", {
href: "/rankings/top",
children: (0, import_jsx_runtime.jsx)("span", { children: "Top250" })
});
}
function Top250Pagination({ page }) {
const hasMore = page >= 5;
return (0, import_jsx_runtime.jsxs)("nav", {
className: "pagination",
children: [
(0, import_jsx_runtime.jsx)("a", {
className: `pagination-previous ${page <= 1 ? "do-hide" : ""}`,
"data-page": page - 1,
children: "上一頁"
}),
(0, import_jsx_runtime.jsx)("a", {
className: `pagination-next ${hasMore ? "do-hide" : ""}`,
"data-page": page + 1,
children: "下一頁"
}),
(0, import_jsx_runtime.jsx)("ul", {
className: "pagination-list",
children: Array.from({ length: 5 }, (_, i) => i + 1).map((i) => (0, import_jsx_runtime.jsx)("li", { children: (0, import_jsx_runtime.jsx)("a", {
className: `pagination-link ${page === i ? "is-current" : ""}`,
"data-page": i,
children: i
}) }, i))
})
]
});
}
function Top250ToolBar({ handleType, typeValue, hasCnsub, yearButtonsHtml }) {
return (0, import_jsx_runtime.jsxs)("div", {
className: "button-group",
children: [(0, import_jsx_runtime.jsxs)("div", {
className: "buttons has-addons",
id: "conditionBox",
style: { marginBottom: "0!important" },
children: [
(0, import_jsx_runtime.jsx)("a", {
style: { padding: "18px 18px !important" },
className: `button is-small ${handleType === "all" ? "is-info" : ""}`,
href: `/advanced_search?handleTop=1&handleType=all&type_value=&has_cnsub=${hasCnsub}`,
children: "全部"
}),
" ",
(0, import_jsx_runtime.jsx)("a", {
style: { padding: "18px 18px !important" },
className: `button is-small ${typeValue === "0" ? "is-info" : ""}`,
href: `/advanced_search?handleTop=1&handleType=video_type&type_value=0&has_cnsub=${hasCnsub}`,
children: "有码"
}),
" ",
(0, import_jsx_runtime.jsx)("a", {
style: { padding: "18px 18px !important" },
className: `button is-small ${typeValue === "1" ? "is-info" : ""}`,
href: `/advanced_search?handleTop=1&handleType=video_type&type_value=1&has_cnsub=${hasCnsub}`,
children: "无码"
}),
" ",
(0, import_jsx_runtime.jsx)("a", {
style: { padding: "18px 18px !important" },
className: `button is-small ${typeValue === "2" ? "is-info" : ""}`,
href: `/advanced_search?handleTop=1&handleType=video_type&type_value=2&has_cnsub=${hasCnsub}`,
children: "欧美"
}),
" ",
(0, import_jsx_runtime.jsx)("a", {
style: { padding: "18px 18px !important" },
className: `button is-small ${typeValue === "3" ? "is-info" : ""}`,
href: `/advanced_search?handleTop=1&handleType=video_type&type_value=3&has_cnsub=${hasCnsub}`,
children: "Fc2"
}),
" ",
(0, import_jsx_runtime.jsx)("a", {
style: {
padding: "18px 18px !important",
marginLeft: "50px"
},
className: `button is-small ${hasCnsub === "1" ? "is-info" : ""}`,
"data-cnsub-value": "1",
children: "含中字磁鏈"
}),
" ",
(0, import_jsx_runtime.jsx)("a", {
style: { padding: "18px 18px !important" },
className: `button is-small ${hasCnsub === "0" ? "is-info" : ""}`,
"data-cnsub-value": "0",
children: "无字幕"
}),
" ",
(0, import_jsx_runtime.jsx)("a", {
style: { padding: "18px 18px !important" },
className: "button is-small",
"data-cnsub-value": "",
children: "重置"
})
]
}), (0, import_jsx_runtime.jsx)("div", {
className: "buttons has-addons",
id: "conditionBox",
dangerouslySetInnerHTML: { __html: yearButtonsHtml }
})]
});
}
function Top250YearButton({ year, typeValue, hasCnsub }) {
return (0, import_jsx_runtime.jsx)("a", {
style: { padding: "18px 18px !important" },
className: `button is-small ${typeValue === year.toString() ? "is-info" : ""}`,
href: `/advanced_search?handleTop=1&handleType=year&type_value=${year}&has_cnsub=${hasCnsub}`,
children: year
});
}
var APP_AUTH_KEY = "jhs_appAuthorization";
var Top250Plugin = class extends BasePlugin {
hasCnsub = "";
contentBox = $(".section .container");
movies = [];
getName() {
return "TOP250Plugin";
}
async handle() {
$(".main-tabs ul li:contains(\"猜你喜歡\")").html(jsxToString((0, import_jsx_runtime.jsx)(Top250NavLink, {})));
$("a[href*=\"rankings/top\"]").on("click", (event) => {
event.preventDefault();
event.stopPropagation();
const target = $(event.target);
const href = (target.is("a") ? target : target.closest("a")).attr("href");
const queryString = href.includes("?") ? href.split("?")[1] : href;
const params = new URLSearchParams(queryString);
this.checkLogin(event, params);
});
this.handleTop().then();
}
hookPage() {
$("h2.section-title").contents().first().replaceWith("Top250");
$(".empty-message").remove();
$(".section .container .box").remove();
$("#sort-toggle-btn").remove();
this.contentBox.append(jsxToString((0, import_jsx_runtime.jsx)(RankingContainers, {})));
this.renderPagination();
}
renderPagination() {
const params = new URLSearchParams(window.location.search);
const page = parseInt(params.get("page") ?? "") || 1;
this.contentBox.append(jsxToString((0, import_jsx_runtime.jsx)(Top250Pagination, { page })));
this.contentBox.on("click", ".pagination-link, .pagination-previous, .pagination-next", (event) => {
event.preventDefault();
const pageNum = parseInt($(event.currentTarget).data("page"));
if (!isNaN(pageNum) && pageNum > 0) ((targetPage) => {
params.set("page", String(targetPage));
window.history.pushState({}, "", "?" + params.toString());
window.location.reload();
})(pageNum);
});
}
async handleTop() {
if (!window.location.href.includes("handleTop=1")) return;
const params = new URLSearchParams(window.location.search);
const handleType = params.get("handleType") || "all";
const typeValue = params.get("type_value") || "";
this.hasCnsub = params.get("has_cnsub") || "";
const page = parseInt(params.get("page") ?? "") || 1;
this.toolBar(handleType, typeValue, page);
this.hookPage();
const movieListEl = $(".movie-list");
movieListEl.html("");
const loadingOverlay = loading();
let success = false;
for (let attempt = 1; attempt <= 3 && !success; attempt++) try {
const response = await fetchTopMovies(handleType, typeValue, page, 50);
const successFlag = response.success;
const message = response.message;
const action = response.action;
if (successFlag === 1) {
const movies = response.data.movies;
if (movies.length === 0) {
show.error("无数据");
loadingOverlay.close();
return;
}
this.movies = movies;
const filteredMovies = movies.filter((movie) => this.hasCnsub === "1" ? movie.has_cnsub : this.hasCnsub !== "0" || !movie.has_cnsub);
const hitShowPlugin = this.getBean("HitShowPlugin");
const html = hitShowPlugin.markDataListHtml(filteredMovies);
movieListEl.html(html);
hitShowPlugin.loadScore(filteredMovies);
success = true;
} else {
console.error(response);
movieListEl.html(jsxToString((0, import_jsx_runtime.jsx)(Top250ErrorMessage, { message })));
show.error(message);
if (action === "JWTVerificationError") {
await localStorage.removeItem(APP_AUTH_KEY);
await this.checkLogin(null, new URLSearchParams(window.location.search));
}
success = true;
}
} catch (error) {
if (attempt < 3) {
clog.error(`获取Top数据失败 (第 ${attempt} 次重试):`, error);
await new Promise((resolve) => setTimeout(resolve, 1e3));
} else {
clog.error("所有重试尝试均失败,无法获取Top数据。", error);
movieListEl.html(jsxToString((0, import_jsx_runtime.jsx)(Top250LoadError, {})));
}
} finally {
if (success || attempt === 3) loadingOverlay.close();
}
}
toolBar(handleType, typeValue, page) {
if (page.toString() === "5") $(".pagination-next").remove();
$(".pagination-ellipsis").closest("li").remove();
$(".pagination-list li a").each(function() {
if (parseInt($(this).text()) > 5) $(this).closest("li").remove();
});
let yearButtonsHtml = "";
for (let year = new Date().getFullYear(); year >= 2008; year--) yearButtonsHtml += jsxToString((0, import_jsx_runtime.jsx)(Top250YearButton, {
year,
typeValue,
hasCnsub: this.hasCnsub
}));
this.contentBox.append(jsxToString((0, import_jsx_runtime.jsx)(Top250ToolBar, {
handleType,
typeValue,
hasCnsub: this.hasCnsub,
yearButtonsHtml
})));
$("a[data-cnsub-value]").on("click", (event) => {
const cnsubValue = $(event.currentTarget).data("cnsub-value");
this.hasCnsub = cnsubValue.toString();
$("a[data-cnsub-value]").removeClass("is-info");
$(event.currentTarget).addClass("is-info");
$(".toolbar a.button").not("[data-cnsub-value]").each((_index, el) => {
const hrefEl = $(el);
const url = new URL(hrefEl.attr("href"), window.location.origin);
url.searchParams.set("has_cnsub", cnsubValue);
hrefEl.attr("href", url.toString());
});
const filteredMovies = this.movies.filter((movie) => this.hasCnsub === "1" ? movie.has_cnsub : this.hasCnsub !== "0" || !movie.has_cnsub);
const hitShowPlugin = this.getBean("HitShowPlugin");
const listHtml = hitShowPlugin.markDataListHtml(filteredMovies);
$(".movie-list").html(listHtml);
hitShowPlugin.loadScore(filteredMovies);
});
}
async checkLogin(event, params) {
if (!localStorage.getItem(APP_AUTH_KEY)) {
show.error("该类别依赖移动端接口,请先完成登录");
this.openLoginDialog();
return;
}
let handleType = "all";
let typeValue = "";
const tValue = params.get("t") || "";
if (/^y\d+$/.test(tValue)) {
handleType = "year";
typeValue = tValue.substring(1);
} else if (tValue !== "") {
handleType = "video_type";
typeValue = tValue;
}
const path = `/advanced_search?handleTop=1&handleType=${handleType}&type_value=${typeValue}`;
if (event && (event.ctrlKey || event.metaKey)) GM_openInTab(window.location.origin + path, { insert: 0 });
else window.location.href = path;
}
openLoginDialog() {
layer.open({
type: 1,
title: "JavDB",
closeBtn: 1,
area: ["360px", "auto"],
shadeClose: false,
content: jsxToString((0, import_jsx_runtime.jsx)(LoginDialog, {})),
success: (_layero, index) => {
$("#username, #password").on("focus", function() {
this.style.borderColor = "#4a8bfc";
this.style.background = "#fff";
}).on("blur", function() {
this.style.borderColor = "#e0e0e0";
this.style.background = "#f9f9f9";
});
$("#loginBtn").on("mouseover", function() {
this.style.background = "#3a7be0";
}).on("mouseout", function() {
this.style.background = "#4a8bfc";
});
$("#loginBtn").click(function() {
const username = $("#username").val();
const password = $("#password").val();
if (!username || !password) {
show.error("请输入用户名和密码");
return;
}
const loadingOverlay = loading();
(async (username, password) => {
const url = `${API_BASE}/v1/sessions?username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}&device_uuid=04b9534d-5118-53de-9f87-2ddded77111e&device_name=iPhone&device_model=iPhone&platform=ios&system_version=17.4&app_version=official&app_version_number=1.9.29&app_channel=official`;
const headers = {
"user-agent": "Dart/3.5 (dart:io)",
"accept-language": "zh-TW",
"content-type": "multipart/form-data; boundary=--dio-boundary-2210433284",
jdsignature: await reBuildSignature()
};
return await gmHttp.post(url, null, headers);
})(username, password).then(async (response) => {
const successFlag = response.success;
if (successFlag === 0) show.error(response.message);
else {
if (successFlag !== 1) {
clog.error("登录失败", response);
throw new Error(response.message);
}
{
const token = response.data.token;
await localStorage.setItem(APP_AUTH_KEY, token);
show.ok("登录成功");
layer.close(index);
window.location.href = "/advanced_search?handleTop=1&period=daily";
}
}
}).catch((error) => {
clog.error("登录异常:", error);
show.error(error.message);
}).finally(() => {
loadingOverlay.close();
});
});
}
});
}
};
function NavOtherDropdown() {
return (0, import_jsx_runtime.jsxs)("div", {
className: "navbar-item has-dropdown is-hoverable",
children: [(0, import_jsx_runtime.jsx)("a", {
className: "navbar-link",
children: "其它"
}), (0, import_jsx_runtime.jsxs)("div", {
className: "navbar-dropdown is-boxed",
children: [(0, import_jsx_runtime.jsx)("a", {
className: "navbar-item",
href: "/feedbacks/new",
target: "_blank",
children: "反饍"
}), (0, import_jsx_runtime.jsx)("a", {
className: "navbar-item",
rel: "nofollow noopener",
target: "_blank",
href: "https://theporndude.com/zh",
children: "ThePornDude"
})]
})]
});
}
function NavSearchBox() {
return (0, import_jsx_runtime.jsx)("div", {
className: "navbar-menu",
id: "search-box",
children: (0, import_jsx_runtime.jsxs)("div", {
className: "navbar-start",
style: {
display: "flex",
alignItems: "center",
gap: "5px"
},
children: [
(0, import_jsx_runtime.jsxs)("select", {
id: "search-type",
style: {
padding: "8px 12px",
border: "1px solid #555",
borderRadius: "4px",
backgroundColor: "#333",
color: "#eee",
fontSize: "14px",
outline: "none"
},
children: [
(0, import_jsx_runtime.jsx)("option", {
value: "all",
children: "影片"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "actor",
children: "演員"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "series",
children: "系列"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "maker",
children: "片商"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "director",
children: "導演"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "code",
children: "番號"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "list",
children: "清單"
})
]
}),
(0, import_jsx_runtime.jsx)("input", {
id: "search-keyword",
type: "text",
placeholder: "輸入影片番號,演員名等關鍵字進行檢索",
style: {
padding: "8px 12px",
border: "1px solid #555",
borderRadius: "4px",
flexGrow: "1",
fontSize: "14px",
backgroundColor: "#333",
color: "#eee",
outline: "none"
}
}),
(0, import_jsx_runtime.jsx)("a", {
href: "/advanced_search?noFold=1",
title: "進階檢索",
style: {
padding: "6px 12px",
backgroundColor: "#444",
borderRadius: "4px",
textDecoration: "none",
color: "#ddd",
fontSize: "14px",
border: "1px solid #555"
},
children: (0, import_jsx_runtime.jsx)("span", { children: "..." })
}),
(0, import_jsx_runtime.jsx)("a", {
id: "search-btn",
style: {
padding: "6px 16px",
backgroundColor: "#444",
color: "#fff",
borderRadius: "4px",
textDecoration: "none",
fontWeight: "500",
cursor: "pointer",
border: "1px solid #555"
},
children: "检索"
})
]
})
});
}
var nav_bar_plugin_default = ".highlight-red {\n /* 核心要求:高亮红色文本 */\n color: red !important;\n\n /* 建议:增加字体加粗,效果更明显 */\n font-weight: bold;\n\n /* 建议:增加背景色,效果更突出 */\n /* background-color: yellow; */\n}\n";
var NavBarPlugin = class extends BasePlugin {
getName() {
return "NavBarPlugin";
}
async initCss() {
return nav_bar_plugin_default;
}
async handle() {
this.mergeNav();
this.hookSearch();
this.hookOldSearch();
this.toggleOtherNavItem();
$(window).resize(this.toggleOtherNavItem);
if (window.location.href.includes("/search")) {
const params = new URLSearchParams(window.location.search);
const keyword = params.get("q");
const searchType = params.get("f");
$("#search-keyword").val(keyword);
if (searchType) $("#search-type").val(searchType);
if (keyword) this.highlightKeyword(keyword);
}
}
highlightKeyword(keyword) {
const trimmed = keyword.trim();
if (!trimmed) return;
const lower = trimmed.toLowerCase();
$(".video-title strong, .actor-box strong").each(function() {
const el = $(this);
if (el.text().toLowerCase().includes(lower)) el.addClass("highlight-red");
});
}
hookSearch() {
$("#navbar-menu-hero").after(jsxToString((0, import_jsx_runtime.jsx)(NavSearchBox, {})));
$("#search-keyword").on("paste", (event) => {
const items = event.originalEvent.clipboardData.items;
for (let index = 0; index < items.length; index++) if (items[index].type.indexOf("image") !== -1) return;
setTimeout(() => {
$("#search-btn").click();
}, 0);
}).on("keypress", (event) => {
if (event.key === "Enter") setTimeout(() => {
$("#search-btn").click();
}, 0);
});
$("#search-btn").on("click", (_event) => {
const keyword = $("#search-keyword").val();
const searchType = $("#search-type option:selected").val();
if (keyword !== "") if (window.location.href.includes("/search")) window.location.href = "/search?q=" + keyword + "&f=" + searchType;
else window.open("/search?q=" + keyword + "&f=" + searchType);
});
}
hookOldSearch() {
const searchImageEl = document.querySelector(".search-image");
if (!searchImageEl) return;
const clonedEl = searchImageEl.cloneNode(true);
searchImageEl.parentNode.replaceChild(clonedEl, searchImageEl);
$("#button-search-image").attr("data-tooltip", "以图识图");
}
mergeNav() {
$("a[href*=\"/feedbacks/new\"]").remove();
$("a[href*=\"theporndude.com\"]").remove();
$("a.navbar-link[href=\"/makers\"]").parent().after(jsxToString((0, import_jsx_runtime.jsx)(NavOtherDropdown, {})));
}
toggleOtherNavItem() {
const searchBox = $("#search-box");
const searchBarContainer = $("#search-bar-container");
if ($(window).width() < 1600 && $(window).width() > 1023) {
searchBox.hide();
searchBarContainer.show();
}
if ($(window).width() > 1600) {
searchBox.show();
searchBarContainer.hide();
}
}
};
var AsyncTaskQueue = class {
queue;
constructor() {
this.queue = Promise.resolve();
}
addTask(task) {
this.queue = this.queue.then(() => task()).catch((err) => {
clog.error("执行异步队列任务失败:", err);
});
}
async waitAllFinished() {
return this.queue;
}
};
function OtherSiteBox({ siteButtonsHtml, isJavdbSite }) {
return (0, import_jsx_runtime.jsx)("div", {
id: "otherSiteBox",
className: "panel-block",
style: {
marginTop: isJavdbSite ? "8px" : "10px",
fontSize: "13px",
userSelect: "none"
},
children: (0, import_jsx_runtime.jsx)("div", {
style: {
display: "flex",
gap: "5px",
flexWrap: "wrap"
},
dangerouslySetInnerHTML: { __html: siteButtonsHtml }
})
});
}
function OtherSiteBtn({ id, enabled }) {
return (0, import_jsx_runtime.jsx)("a", {
target: "_blank",
className: "site-btn",
style: enabled ? void 0 : { display: "none" },
id,
children: (0, import_jsx_runtime.jsx)("span", { children: id.replace("Btn", "") })
});
}
function OtherSiteCheckbox({ id, isEnabled, isJavdbSite }) {
return (0, import_jsx_runtime.jsxs)("div", {
style: {
marginRight: "15px",
display: "flex",
alignItems: isJavdbSite ? "center" : "flex-start"
},
children: [(0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: `checkbox-${id}`,
"data-site-id": id,
checked: isEnabled,
style: {
marginRight: "8px",
cursor: "pointer"
}
}), (0, import_jsx_runtime.jsx)("label", {
for: `checkbox-${id}`,
style: {
color: "#333",
fontWeight: "500",
cursor: "pointer"
},
children: id.replace("Btn", "")
})]
});
}
function SiteResultTag() {
return (0, import_jsx_runtime.jsx)("span", {
className: "site-tag",
style: { top: "-15px" },
children: "多结果"
});
}
var other_site_plugin_default = ".site-btn {\n position: relative !important;\n min-width: 80px;\n display: inline-block;\n padding: 5px 10px;\n color: white !important;\n background-color: #938585;\n text-decoration: none;\n border-radius: 4px;\n text-align: center;\n margin-bottom: 5px;\n}\n.site-btn:hover {\n color: white;\n transform: translateY(-2px);\n box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);\n}\n.site-tag {\n position: absolute;\n top: -15px;\n right: 0;\n background-color: #ffc107;\n color: #333;\n font-size: 12px;\n padding: 2px 6px;\n border-radius: 4px;\n}\n";
var OtherSitePlugin = class extends BasePlugin {
okBackgroundColor = "#7bc73b";
errorBackgroundColor = "#de3333";
warnBackgroundColor = "#d7a80c";
domainErrorBackgroundColor = "#d7780c";
siteConfigs = [{
id: "missAvBtn",
getBaseUrl: async () => await this.getMissAvUrl(),
itemSelector: ".text-secondary",
searchPath: (baseUrl, carNum) => `${baseUrl}/search/${carNum}`,
getDetailPageHref: (item) => item.attr("href"),
findCarNumOrTitle: (item) => item.text()
}, {
id: "supJavBtn",
getBaseUrl: async () => await this.getSupJavUrl(),
itemSelector: ".posts post",
searchPath: (baseUrl, carNum) => `${baseUrl}/?s=${carNum}`,
getDetailPageHref: (item) => item.attr("href"),
findCarNumOrTitle: (item) => item.attr("title")
}];
settingCache = null;
lastFetchTime = 0;
CACHE_DURATION = 1e4;
getName() {
return "OtherSitePlugin";
}
async initCss() {
return other_site_plugin_default;
}
async handle() {
if (window.isDetailPage) this.loadOtherSite().then();
}
async loadOtherSite(carNum, sourceCarNum) {
if (await storageManager.getSetting("enableLoadOtherSite", "yes") !== "yes") return;
carNum ||= this.getPageInfo().carNum ?? "";
const enabledSiteIds = this.getEnabledSites();
const boxHtml = jsxToString((0, import_jsx_runtime.jsx)(OtherSiteBox, {
siteButtonsHtml: this.siteConfigs.map((siteConfig) => {
siteConfig.sourceCarNum = sourceCarNum;
if (siteConfig.condition && siteConfig.condition(siteConfig.sourceCarNum) === false) return "";
return jsxToString((0, import_jsx_runtime.jsx)(OtherSiteBtn, {
id: siteConfig.id,
enabled: enabledSiteIds.includes(siteConfig.id)
}));
}).join(""),
isJavdbSite
}));
$(".movie-panel-info").append(boxHtml);
$(".container .info").append(boxHtml);
await Promise.all(this.siteConfigs.map(async (siteConfig) => {
if (!siteConfig.condition || siteConfig.condition(siteConfig.sourceCarNum) !== false) await this.handleSite(carNum, siteConfig);
}));
this.renderSettingsArea();
this.setupEventListeners();
}
async handleSite(carNum, siteConfig) {
const buttonEl = $(`#${siteConfig.id}`);
if (siteConfig.initUrl) {
buttonEl.attr("href", siteConfig.initUrl(carNum));
buttonEl.css("backgroundColor", this.warnBackgroundColor);
}
if (siteConfig.noHandle && siteConfig.noHandle === true) {
const dmmStorageKey = "jhs_other_site_dmm";
const dmmCachedResult = (localStorage.getItem(dmmStorageKey) ? JSON.parse(localStorage.getItem(dmmStorageKey)) : {})[carNum];
if (dmmCachedResult) {
if (dmmCachedResult.type === "single") {
buttonEl.attr("href", dmmCachedResult.url);
buttonEl.css("backgroundColor", this.okBackgroundColor);
} else if (dmmCachedResult.type === "multiple") {
buttonEl.attr("href", dmmCachedResult.url);
buttonEl.append(jsxToString((0, import_jsx_runtime.jsx)(SiteResultTag, {})));
buttonEl.css("backgroundColor", this.okBackgroundColor);
}
}
} else try {
if (buttonEl.attr("href")) return;
if (utils.isHidden(buttonEl)) return;
const storageKey = "jhs_other_site";
const cache = localStorage.getItem(storageKey) ? JSON.parse(localStorage.getItem(storageKey)) : {};
const cacheKey = carNum + "_" + siteConfig.id.replace("Btn", "");
const cachedResult = cache[cacheKey];
if (cachedResult) {
if (cachedResult.type === "single") {
buttonEl.attr("href", cachedResult.url);
buttonEl.css("backgroundColor", this.okBackgroundColor);
} else if (cachedResult.type === "multiple") {
buttonEl.attr("href", cachedResult.url);
buttonEl.append(jsxToString((0, import_jsx_runtime.jsx)(SiteResultTag, {})));
buttonEl.css("backgroundColor", this.okBackgroundColor);
}
return;
}
const baseUrl = await siteConfig.getBaseUrl();
const searchUrl = siteConfig.searchPath(baseUrl, carNum);
buttonEl.attr("href", searchUrl);
const htmlContent = await gmHttp.get(searchUrl, null, siteConfig.headers, true);
const $dom = utils.htmlTo$dom(htmlContent);
const detailHrefs = [];
$dom.find(siteConfig.itemSelector).each((_index, element) => {
const itemEl = $(element);
if (!siteConfig.findCarNumOrTitle(itemEl).toLowerCase().includes(carNum.toLowerCase())) return;
let href = siteConfig.getDetailPageHref(itemEl, baseUrl, carNum);
if (!href) throw new Error("解析href失败");
if (!href.includes("http")) href = baseUrl + (href.startsWith("/") ? href : "/" + href);
detailHrefs.push(href);
});
let tagHtml = "";
let resultData = null;
if (detailHrefs.length === 1) {
const detailHref = detailHrefs[0];
buttonEl.attr("href", detailHref);
buttonEl.css("backgroundColor", this.okBackgroundColor);
resultData = {
type: "single",
url: detailHref
};
} else if (detailHrefs.length > 1) {
buttonEl.attr("href", searchUrl);
tagHtml += jsxToString((0, import_jsx_runtime.jsx)(SiteResultTag, {}));
buttonEl.css("backgroundColor", this.okBackgroundColor);
resultData = {
type: "multiple",
url: searchUrl
};
} else {
buttonEl.attr("href", searchUrl);
buttonEl.attr("title", "未查询到, 点击前往搜索页");
buttonEl.css("backgroundColor", this.errorBackgroundColor);
}
if (resultData) new AsyncTaskQueue().addTask(() => {
const cache = localStorage.getItem(storageKey) ? JSON.parse(localStorage.getItem(storageKey)) : {};
cache[cacheKey] = resultData;
localStorage.setItem(storageKey, JSON.stringify(cache));
});
if (tagHtml) buttonEl.append(tagHtml);
} catch (error) {
const errorMsg = String(error);
const siteName = siteConfig.id.replace("Btn", "");
if (errorMsg.includes("Just a moment")) {
buttonEl.attr("title", "请求失败:Cloudflare 安全检查。");
buttonEl.css("backgroundColor", this.warnBackgroundColor);
clog.warn(`检测第三方资源失败, ${siteName} 需Cloudflare安全检查`);
} else if (errorMsg.includes("重定向")) {
buttonEl.attr("title", "域名失效");
buttonEl.css("backgroundColor", this.domainErrorBackgroundColor);
clog.warn(`检测第三方资源失败, ${siteName} 域名被重定向`);
} else if (errorMsg.includes("404 Page Not Found")) {
buttonEl.attr("title", "未查询到, 点击前往搜索页");
buttonEl.css("backgroundColor", this.errorBackgroundColor);
} else {
console.error(error);
buttonEl.attr("title", "请求失败。");
buttonEl.css("backgroundColor", this.errorBackgroundColor);
clog.warn(`检测第三方资源失败, ${siteName}`);
}
}
}
async getSettingCache() {
const now = Date.now();
if (!this.settingCache || now - this.lastFetchTime > this.CACHE_DURATION) {
this.settingCache = await storageManager.getSetting();
this.lastFetchTime = now;
}
return this.settingCache;
}
async getMissAvUrl() {
return (await this.getSettingCache()).missAvUrl || "https://missav.live";
}
async getJavDbUrl() {
return (await this.getSettingCache()).javDbUrl || "https://javdb.com";
}
async getSupJavUrl() {
return (await this.getSettingCache()).supJavUrl || "https://supjav.com";
}
getEnabledSites() {
const stored = localStorage.getItem("jhs_enabled_sites");
if (stored) return JSON.parse(stored);
else return this.siteConfigs.map((siteConfig) => siteConfig.id);
}
saveEnabledSites(siteIds) {
localStorage.setItem("jhs_enabled_sites", JSON.stringify(siteIds));
}
renderSettingsArea() {
const enabledSiteIds = this.getEnabledSites();
const checkboxContainer = document.getElementById("siteCheckboxes");
if (checkboxContainer) checkboxContainer.innerHTML = this.siteConfigs.map((siteConfig) => {
const isEnabled = enabledSiteIds.includes(siteConfig.id);
return jsxToString((0, import_jsx_runtime.jsx)(OtherSiteCheckbox, {
id: siteConfig.id,
isEnabled,
isJavdbSite
}));
}).join("");
}
setupEventListeners() {
const settingsArea = document.getElementById("settingsArea");
settingsArea?.addEventListener("change", (event) => {
const target = event.target;
if (target.type === "checkbox") {
const siteId = target.getAttribute("data-site-id");
if (target.checked) {
$(`#${siteId}`).show();
const carNum = this.getPageInfo().carNum ?? "";
const siteConfig = this.siteConfigs.find((config) => config.id === siteId);
this.handleSite(carNum, siteConfig).then();
} else $(`#${siteId}`).hide();
const checkedSiteIds = Array.from(settingsArea.querySelectorAll("input[type=\"checkbox\"]:checked")).map((checkbox) => checkbox.getAttribute("data-site-id"));
this.saveEnabledSites(checkedSiteIds);
}
});
}
};
function ReviewContainers() {
return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("div", { id: "reviewsContainer" }), (0, import_jsx_runtime.jsx)("div", { id: "reviewsFooter" })] });
}
function ReviewEmpty() {
return (0, import_jsx_runtime.jsx)("div", {
style: {
marginTop: "15px",
backgroundColor: "#ffffff",
padding: "10px",
marginLeft: "-10px"
},
children: "无评论"
});
}
function ReviewEnd() {
return (0, import_jsx_runtime.jsx)("div", {
style: {
textAlign: "center",
padding: "10px",
color: "#666",
marginTop: "10px"
},
children: "已加载全部评论"
});
}
function ReviewError() {
return (0, import_jsx_runtime.jsxs)("div", {
style: {
marginTop: "15px",
backgroundColor: "#ffffff",
padding: "10px",
marginLeft: "-10px"
},
children: ["获取评论失败", (0, import_jsx_runtime.jsx)("a", {
id: "retryFetchReviews",
href: "javascript:;",
style: {
marginLeft: "10px",
color: "#1890ff",
textDecoration: "none"
},
children: "重试"
})]
});
}
function ReviewHeader({ foldText, iconText }) {
return (0, import_jsx_runtime.jsxs)("div", {
style: {
display: "flex",
alignItems: "center",
margin: "16px 0",
color: "#666",
fontSize: "14px"
},
children: [
(0, import_jsx_runtime.jsx)("span", { style: {
flex: 1,
height: "1px",
background: "linear-gradient(to right, transparent, #999, transparent)"
} }),
(0, import_jsx_runtime.jsx)("span", {
style: { padding: "0 10px" },
"data-tip": "想要发表评论? 滑上去, 点击上面的按钮-看过",
children: "❓ 评论区"
}),
(0, import_jsx_runtime.jsxs)("a", {
id: "reviewsFold",
style: {
marginLeft: "8px",
color: "#1890ff",
textDecoration: "none",
display: "flex",
alignItems: "center"
},
children: [(0, import_jsx_runtime.jsx)("span", {
className: "toggle-text",
children: foldText
}), (0, import_jsx_runtime.jsx)("span", {
className: "toggle-icon",
style: { marginLeft: "4px" },
children: iconText
})]
}),
(0, import_jsx_runtime.jsx)("span", { style: {
flex: 1,
height: "1px",
background: "linear-gradient(to right, transparent, #999, transparent)"
} })
]
});
}
function ReviewItem({ floor, username, stars, time, likesCount, content }) {
return (0, import_jsx_runtime.jsxs)("div", {
className: "item columns is-desktop",
style: {
display: "block",
marginTop: "6px",
backgroundColor: "#ffffff",
padding: "10px",
marginLeft: "-10px",
wordBreak: "break-word",
position: "relative"
},
children: [
(0, import_jsx_runtime.jsxs)("span", {
style: {
position: "absolute",
top: "5px",
right: "10px",
color: "#999",
fontSize: "12px"
},
children: [
"#",
floor,
"楼"
]
}),
username,
" \xA0\xA0",
" ",
(0, import_jsx_runtime.jsx)("span", {
className: "score-stars",
dangerouslySetInnerHTML: { __html: stars }
}),
" ",
(0, import_jsx_runtime.jsx)("span", {
className: "time",
children: time
}),
" \xA0\xA0 点赞:",
likesCount,
(0, import_jsx_runtime.jsx)("p", {
className: "review-content",
style: { marginTop: "5px" },
dangerouslySetInnerHTML: { __html: ` ${content} ` }
})
]
});
}
function ReviewLinkContent({ match }) {
if (match.startsWith("ed2k://")) return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
" ",
(0, import_jsx_runtime.jsx)("span", {
style: {
wordBreak: "break-all",
background: "#e0f2fe",
color: "#0369a1"
},
children: match
}),
" ",
(0, import_jsx_runtime.jsx)("button", {
className: "button is-info down-115",
"data-magnet": match,
style: { fontSize: "11px" },
children: "115离线下载"
}),
" "
] });
if (match.startsWith("magnet:")) return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
" ",
(0, import_jsx_runtime.jsx)("a", {
href: match,
className: "a-primary",
style: {
padding: 0,
wordBreak: "break-all",
whiteSpace: "pre-wrap"
},
target: "_blank",
rel: "noopener noreferrer",
children: match
}),
" ",
(0, import_jsx_runtime.jsx)("button", {
className: "button is-info down-115",
"data-magnet": match,
style: { fontSize: "11px" },
children: "115离线下载"
}),
" "
] });
if (match.startsWith("http://") || match.startsWith("https://")) return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
" ",
(0, import_jsx_runtime.jsx)("a", {
href: match,
className: "a-primary",
style: {
padding: 0,
wordBreak: "break-all",
whiteSpace: "pre-wrap"
},
target: "_blank",
rel: "noopener noreferrer",
children: match
}),
" "
] });
return match;
}
function ReviewLoadMore() {
return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("button", {
id: "loadMoreReviews",
style: {
width: "100%",
backgroundColor: "#e1f5fe",
border: "none",
padding: "10px",
marginTop: "10px",
cursor: "pointer",
color: "#0277bd",
fontWeight: "bold",
borderRadius: "4px"
},
children: "加载更多评论"
}), (0, import_jsx_runtime.jsx)("div", {
id: "reviewsEnd",
style: {
display: "none",
textAlign: "center",
padding: "10px",
color: "#666",
marginTop: "10px"
},
children: "已加载全部评论"
})] });
}
function ReviewLoading() {
return (0, import_jsx_runtime.jsx)("div", {
id: "reviewsLoading",
style: {
marginTop: "15px",
backgroundColor: "#ffffff",
padding: "10px",
marginLeft: "-10px"
},
children: "获取评论中..."
});
}
var ReviewPlugin = class extends BasePlugin {
floorIndex = 1;
isInit = false;
constructor() {
super();
}
getName() {
return "ReviewPlugin";
}
async handle() {
if (window.isDetailPage) {
if (isJavdbSite) {
const movieId = this.parseMovieId(window.location.href);
await this.showReview(movieId);
await this.getBean("RelatedPlugin").showRelated($("#magnets-content"), movieId);
}
}
}
async showReview(movieId, container) {
const isExpanded = await storageManager.getSetting("enableLoadReview", "yes");
const target = container || $("#magnets-content");
target.append(jsxToString((0, import_jsx_runtime.jsx)(ReviewHeader, {
foldText: isExpanded === "yes" ? "折叠" : "展开",
iconText: isExpanded === "yes" ? "▲" : "▼"
})));
$("#reviewsFold").on("click", (event) => {
event.preventDefault();
event.stopPropagation();
const toggleText = $("#reviewsFold .toggle-text");
const toggleIcon = $("#reviewsFold .toggle-icon");
const isExpand = toggleText.text() === "展开";
toggleText.text(isExpand ? "折叠" : "展开");
toggleIcon.text(isExpand ? "▲" : "▼");
if (isExpand) {
$("#reviewsContainer").show();
$("#reviewsFooter").show();
if (!this.isInit) {
this.fetchAndDisplayReviews(movieId);
this.isInit = true;
}
storageManager.saveSettingItem("enableLoadReview", "yes");
} else {
$("#reviewsContainer").hide();
$("#reviewsFooter").hide();
storageManager.saveSettingItem("enableLoadReview", "no");
}
});
target.append(jsxToString((0, import_jsx_runtime.jsx)(ReviewContainers, {})));
if (isExpanded === "yes") await this.fetchAndDisplayReviews(movieId);
}
async fetchAndDisplayReviews(movieId) {
const container = $("#reviewsContainer");
const footer = $("#reviewsFooter");
container.append(jsxToString((0, import_jsx_runtime.jsx)(ReviewLoading, {})));
const limit = await storageManager.getSetting("reviewCount", 20);
let reviews = null;
try {
reviews = await fetchMovieReviews(movieId, 1, limit);
} catch (err) {
if (err.toString().includes("簽名已過期")) show.error("生成签名失败, 请检查系统时间及时区是否正确!");
clog.error("获取评论失败:", err);
console.error("获取评论失败:", err);
} finally {
$("#reviewsLoading").remove();
}
if (!reviews) {
container.append(jsxToString((0, import_jsx_runtime.jsx)(ReviewError, {})));
$("#retryFetchReviews").on("click", async () => {
$("#retryFetchReviews").parent().remove();
await this.fetchAndDisplayReviews(movieId);
});
return;
}
if (reviews.length === 0) {
container.append(jsxToString((0, import_jsx_runtime.jsx)(ReviewEmpty, {})));
return;
}
const filterKeywords = await storageManager.getReviewFilterKeywordList();
this.displayReviews(reviews, container, filterKeywords);
if (reviews.length === limit) {
footer.html(jsxToString((0, import_jsx_runtime.jsx)(ReviewLoadMore, {})));
let page = 1;
const loadMoreBtn = $("#loadMoreReviews");
loadMoreBtn.on("click", async () => {
let moreReviews;
loadMoreBtn.text("加载中...").prop("disabled", true);
page++;
try {
moreReviews = await fetchMovieReviews(movieId, page, limit);
} catch (err) {
console.error("加载更多评论失败:", err);
} finally {
loadMoreBtn.text("加载失败, 请点击重试").prop("disabled", false);
}
if (moreReviews) {
this.displayReviews(moreReviews, container, filterKeywords);
if (moreReviews.length < limit) {
loadMoreBtn.remove();
$("#reviewsEnd").show();
} else loadMoreBtn.text("加载更多评论").prop("disabled", false);
}
});
} else footer.html(jsxToString((0, import_jsx_runtime.jsx)(ReviewEnd, {})));
}
displayReviews(reviews, container, filterKeywords) {
if (reviews.length) {
reviews.forEach((review) => {
if (filterKeywords.some((keyword) => review.content.includes(keyword))) return;
const stars = Array(review.score).fill("<i class=\"icon-star\"></i>").join("");
const content = review.content.replace(/ed2k:\/\/\|file\|[^|]+\|\d+\|[a-fA-F0-9]{32}\|\/|magnet:\?[^\s"'<>`\u4e00-\u9fa5,。?!()【】]+|https?:\/\/[^\s"'<>`\u4e00-\u9fa5,。?!()【】]+/g, (match) => jsxToString((0, import_jsx_runtime.jsx)(ReviewLinkContent, { match })));
const html = jsxToString((0, import_jsx_runtime.jsx)(ReviewItem, {
floor: this.floorIndex++,
username: review.username,
stars,
time: utils.formatDate(review.created_at),
likesCount: review.likes_count,
content
}));
container.append(html);
});
this.rightClickFilter();
}
}
async rightClickFilter() {
if (await storageManager.getSetting("enableTitleSelectFilter", "yes") === "yes") utils.rightClick(document.body, ".review-content", async (event) => {
const selectedText = window.getSelection().toString();
if (selectedText) {
event.preventDefault();
await utils.q(event, `是否将 '${selectedText}' 加入评论区关键词?`, async () => {
await storageManager.saveReviewFilterKeyword(selectedText);
show.ok("操作成功, 刷新页面后生效");
});
}
});
}
};
var BLACKLIST_DEFAULT_LABEL = "加入黑名单";
var BLACKLIST_DEFAULT_COLOR = "#d22020";
var BLACKLIST_TIP = "将演员加入黑名单, 后续有作品更新也会纳入屏蔽中";
var FILTER_ALL_TIP = "一键屏蔽已选分类的视频列表至鉴定记录中";
var SORT_DEFAULT_LABEL = "当前排序方式: 默认";
function menuBtnStyle(backgroundColor) {
return { backgroundColor: `${backgroundColor} !important` };
}
function MenuButtonBoxHtml({ blacklistLabel = BLACKLIST_DEFAULT_LABEL, blacklistColor = BLACKLIST_DEFAULT_COLOR, actorsPage = false, tagsPage = false, advancedSearch = false, searchOrUserPage = false, sortLabel = SORT_DEFAULT_LABEL, newVideoCount = 0 }) {
const showSortToggle = !searchOrUserPage && !advancedSearch;
return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsxs)("div", {
style: {
display: "flex",
alignItems: "center",
flexGrow: advancedSearch ? void 0 : 1
},
children: [
(0, import_jsx_runtime.jsx)("a", {
id: "waitCheckBtn",
className: "menu-btn main-tab-btn",
style: menuBtnStyle("#56c938"),
children: (0, import_jsx_runtime.jsx)("span", { children: "打开待鉴定" })
}),
(0, import_jsx_runtime.jsx)("a", {
id: "waitDownBtn",
className: "menu-btn main-tab-btn",
style: menuBtnStyle("#2caac0"),
children: (0, import_jsx_runtime.jsx)("span", { children: "打开已收藏" })
}),
actorsPage && (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("a", {
id: "addBlacklistBtn",
className: "menu-btn main-tab-btn",
style: menuBtnStyle(blacklistColor),
"data-tip": BLACKLIST_TIP,
children: (0, import_jsx_runtime.jsx)("span", { children: blacklistLabel })
}), (0, import_jsx_runtime.jsx)("a", {
id: "filterAllVideo",
className: "menu-btn main-tab-btn",
style: {
backgroundColor: "#e8ab39 !important",
marginRight: "30px!important"
},
"data-tip": FILTER_ALL_TIP,
children: (0, import_jsx_runtime.jsx)("span", { children: "一键屏蔽所有作品" })
})] }),
tagsPage && (0, import_jsx_runtime.jsx)("a", {
id: "addBlacklistBtn",
className: "menu-btn main-tab-btn",
style: menuBtnStyle(blacklistColor),
"data-tip": BLACKLIST_TIP,
children: (0, import_jsx_runtime.jsx)("span", { children: blacklistLabel })
})
]
}), (0, import_jsx_runtime.jsxs)("div", {
style: {
display: "flex",
alignItems: "center"
},
children: [
(0, import_jsx_runtime.jsx)("a", {
id: "newVideoBtn",
className: "menu-btn main-tab-btn",
style: menuBtnStyle("#2c6cc0"),
children: (0, import_jsx_runtime.jsxs)("span", { children: [
"新作品检测 (",
(0, import_jsx_runtime.jsx)("span", {
id: "newVideoCount",
children: newVideoCount
}),
")"
] })
}),
(0, import_jsx_runtime.jsx)("a", {
id: "blacklistBtn",
className: "menu-btn main-tab-btn",
style: menuBtnStyle("#34393f"),
children: (0, import_jsx_runtime.jsx)("span", { children: "演员黑名单" })
}),
showSortToggle && (0, import_jsx_runtime.jsx)("a", {
id: "sort-toggle-btn",
className: "menu-btn main-tab-btn",
style: menuBtnStyle("#8783ab"),
children: ` ${sortLabel} `
})
]
})] });
}
var HAS_DOWN_TEXT = "📥️ 已下载";
var ListPageButtonPlugin = class extends BasePlugin {
loadObj = null;
getName() {
return "ListPageButtonPlugin";
}
async handle() {
if (!window.isListPage) return;
await this.createMenuBtn();
this.bindEvent();
if (await storageManager.getSetting("autoPage") === "yes") $("#sort-toggle-btn").hide();
else this.sortItems().then();
}
async createMenuBtn() {
if (isJavdbSite) {
const isActorsPage = currentHref.includes("/actors/");
let containerEl = $(".main-tabs, .tabs");
let blacklistLabel = "加入黑名单";
let blacklistColor = "#d22020";
let tagBlacklistEntry = null;
if (isActorsPage) {
containerEl = $(".toolbar, .section-addition").filter(":last");
const blacklist = await storageManager.getBlacklist();
const actressInfo = this.getActressPageInfo();
if (blacklist.find((entry) => entry.starId === actressInfo.starId)) {
blacklistLabel = "已加入黑名单";
blacklistColor = "#885d5d";
}
} else if (currentHref.includes("/tags")) utils.loopDetector(() => $("#jhs-check-tag").text().trim(), async () => {
const addBlacklistBtnEl = $("#addBlacklistBtn");
addBlacklistBtnEl.attr("data-tip", "将当前分类标签加入到黑名单, 后续有作品更新也会纳入屏蔽中");
const tagName = $("#jhs-check-tag").text().trim();
if (!tagName) return;
const tagStarId = "no-" + tagName;
tagBlacklistEntry = (await storageManager.getBlacklist()).find((entry) => entry.starId === tagStarId);
if (tagBlacklistEntry) {
addBlacklistBtnEl.css("backgroundColor", "#885d5d");
$("#addBlacklistBtn span").text("已加入黑名单");
}
});
const isAdvancedSearch = currentHref.includes("advanced_search");
if (isAdvancedSearch) containerEl = $("h2.section-title");
const sortMethod = localStorage.getItem("jhs_sortMethod");
const sortLabel = "当前排序方式: " + (sortMethod === "rateCount" ? "评价人数" : sortMethod === "date" ? "时间" : "默认");
containerEl.append(jsxToString((0, import_jsx_runtime.jsx)(MenuButtonBoxHtml, {
blacklistLabel,
blacklistColor,
actorsPage: isActorsPage,
tagsPage: currentHref.includes("/tags"),
advancedSearch: isAdvancedSearch,
searchOrUserPage: isSearchOrUserPage,
sortLabel
})));
}
}
bindEvent() {
$("#waitCheckBtn").on("click", () => {
this.openWaitCheck().then();
});
$("#waitDownBtn").on("click", () => {
this.openFavorite().then();
});
$("#newVideoBtn").on("click", () => {
this.getBean("NewVideoPlugin").openDialog();
});
$("#blacklistBtn").on("click", () => {
this.getBean("BlacklistPlugin").openBlacklistDialog();
});
$("#sort-toggle-btn").on("click", (event) => {
const currentMethod = localStorage.getItem("jhs_sortMethod");
const nextMethod = currentMethod && currentMethod !== "default" ? currentMethod === "rateCount" ? "date" : "default" : "rateCount";
$(event.target).text(`当前排序方式: ${{
default: "默认",
rateCount: "评价人数",
date: "时间"
}[nextMethod]}`);
localStorage.setItem("jhs_sortMethod", nextMethod);
this.sortItems().then();
});
const blacklistPlugin = this.getBean("BlacklistPlugin");
$("#addBlacklistBtn").on("click", async (event) => {
await blacklistPlugin.addBlacklist(event);
});
$("#filterAllVideo").on("click", async (event) => {
const position = {
clientX: event.clientX,
clientY: event.clientY + 80
};
const nameEl = $(".actor-section-name");
if (nameEl.length === 0) {
show.error("获取演员名称失败");
return;
}
const actressName = nameEl.text().trim().split(",")[0];
utils.q(position, "一键屏蔽视频列表?", async () => {
this.loadObj = loading();
try {
await blacklistPlugin.filterAllVideo(actressName);
window.refresh();
} catch (err) {
console.error(err);
} finally {
this.loadObj?.close();
}
});
});
}
async sortItems() {
if (currentHref.includes("handle") || currentHref.includes("advanced_search")) return;
const autoPage = await storageManager.getSetting("autoPage");
if (isSearchOrUserPage || autoPage === "yes") return;
const sortMethod = localStorage.getItem("jhs_sortMethod");
if (!sortMethod) return;
$(".movie-list .item").each((index, element) => {
if (!$(element).attr("data-original-index")) $(element).attr("data-original-index", index);
});
const listEl = $(".movie-list");
const itemEls = $(".item", listEl);
if (sortMethod === "default") itemEls.sort((itemA, itemB) => $(itemA).data("original-index") - $(itemB).data("original-index")).appendTo(listEl);
else {
const items = itemEls.get();
items.sort((itemA, itemB) => {
if (sortMethod === "rateCount") {
const getRateCount = (el) => {
const match = $(el).find(".score .value").text().match(/由(\d+)人/);
if (match) return parseFloat(match[1]);
else return 0;
};
return getRateCount(itemB) - getRateCount(itemA);
} else {
const getDate = (el) => {
const dateStr = $(el).find(".meta").text().trim();
return new Date(dateStr).getTime();
};
return getDate(itemB) - getDate(itemA);
}
});
listEl.empty().append(items);
}
}
async openWaitCheck() {
const selectorConfig = this.getSelector();
const maxCount = await storageManager.getSetting("waitCheckCount", 5);
const skipTags = [
BLOCKED_TEXT,
FAVORITED_TEXT,
HAS_DOWN_TEXT,
WATCHED_TEXT
];
let openedCount = 0;
$(`${selectorConfig.itemSelector}:visible`).each((_index, element) => {
if (openedCount >= maxCount) return false;
const itemEl = $(element);
if (skipTags.some((tagText) => itemEl.find(`span.tag:contains('${tagText}')`).length > 0)) return;
const { carNum, aHref } = this.getBean("ListPagePlugin").findCarNumAndHref(itemEl);
if (carNum.includes("FC2-")) {
const movieId = this.parseMovieId(aHref);
this.getBean("Fc2Plugin")?.openFc2Page(movieId, carNum, aHref);
} else {
const url = aHref + (aHref.includes("?") ? "&autoPlay=1" : "?autoPlay=1");
window.open(url);
}
openedCount++;
});
if (openedCount === 0) show.info("没有需鉴定的视频");
}
async openFavorite() {
const maxCount = await storageManager.getSetting("waitCheckCount", 5);
const favoriteList = (await storageManager.getCarList()).filter((item) => item.status === FAVORITE_ACTION).sort((a, b) => b.createDate - a.createDate);
for (let i = 0; i < maxCount; i++) {
if (i >= favoriteList.length) return;
const carInfo = favoriteList[i];
const carNum = carInfo.carNum;
const url = carInfo.url;
if (carNum.includes("FC2-")) {
const movieId = this.parseMovieId(url);
await this.getBean("Fc2Plugin")?.openFc2Page(movieId, carNum, url);
} else window.open(url);
clog.debug("打开已收藏", carNum, url);
}
}
};
var auto_page_plugin_default = ".jhs-scroll {\n text-align: center;\n padding-top: 20px;\n font-size: 14px;\n}\n.jhs-scroll.waterfall-loading {\n color: #000;\n}\n.jhs-scroll.waterfall-error {\n color: #f44336;\n cursor: pointer;\n}\n.jhs-scroll.waterfall-no-more {\n color: #4caf50;\n}\n";
var AutoPagePlugin = class extends BasePlugin {
preloadDistance = 500;
currentPage = this.getInitialPageNumber();
pageItems = [];
container = null;
loader = null;
nextUrl = void 0;
hasMore = false;
isLoading = false;
getName() {
return "AutoPagePlugin";
}
async initCss() {
return auto_page_plugin_default;
}
async handle() {
this.waterfall().then();
}
getInitialPageNumber() {
if (isJavdbSite) {
const match = currentHref.match(/[?&]page=(\d+)/);
if (match) return parseInt(match[1], 10);
else return 1;
}
return 1;
}
async waterfall() {
if (await this.shouldDisablePaging()) return;
const selectorConfig = this.getSelector();
this.container = document.querySelector(selectorConfig.boxSelector);
if (!this.container) {
console.error("没有找到容器节点,停止瀑布流!");
return;
}
const container = this.container;
this.loader = document.createElement("div");
const loader = this.loader;
loader.className = "jhs-scroll";
container.parentNode.insertBefore(loader, container.nextSibling);
this.pageItems.push({
page: this.currentPage,
top: 0,
url: window.location.href
});
loader.addEventListener("click", () => {
if (loader.classList.contains("waterfall-error")) this.loadNextPage().then();
});
window.addEventListener("scroll", () => {
this.checkLoad();
this.checkScrollPosition();
});
const nextLinkEl = document.querySelector(selectorConfig.nextPageSelector);
this.nextUrl = nextLinkEl == null ? void 0 : nextLinkEl.href;
this.hasMore = !!this.nextUrl;
setTimeout(() => {
this.checkLoad();
}, 1e3);
if (!this.hasMore) this.setState("waterfall-no-more", "已经到底了");
}
async loadNextPage() {
if (await storageManager.getSetting("autoPage", "yes") === "no") {
this.setState("waterfall-loading", "");
return;
}
if (this.isLoading || !this.nextUrl) return;
this.isLoading = true;
this.setState("waterfall-loading", "加载中...");
const selectorConfig = this.getSelector();
try {
const pageNum = utils.getUrlParam(this.nextUrl, "page");
let maxPage = 60;
if (currentHref.includes("c11")) maxPage = 30;
if (isJavdbSite && pageNum > maxPage || currentHref.includes("month")) {
const beyond60Plugin = this.getBean("Beyond60Plugin");
if (beyond60Plugin) {
const { html, nextUrl: beyondNextUrl, hasMore: beyondHasMore } = await beyond60Plugin.handleBeyond60(this.nextUrl);
if (html) {
const scrollHeight = this.container.scrollHeight;
this.pageItems.push({
page: this.currentPage + 1,
top: scrollHeight,
url: this.nextUrl
});
$(".movie-list").append(html);
}
this.hasMore = beyondHasMore;
this.nextUrl = beyondNextUrl;
const paginationHtml = beyond60Plugin.createPagination(pageNum, beyondHasMore);
$(".pagination").html(paginationHtml);
this.setState("waterfall-loading", "");
if (!this.hasMore) this.setState("waterfall-no-more", "已经到底了");
return;
}
}
const responseHtml = await gmHttp.get(this.nextUrl);
clog.log("请求下一页内容:", this.nextUrl);
const $dom = utils.htmlTo$dom(responseHtml);
const items = $dom.find(this.getSelector().requestDomItemSelector);
const existingList = this.getBoxCarInfoList();
const newList = this.getBoxCarInfoList(items);
if (this.checkDuplicateCarNumbers(existingList, newList)) {
this.nextUrl = null;
this.hasMore = false;
this.setState("waterfall-error", "翻页内容出现重复数据, 页码受JavDB限制, 已停止瀑布流");
return;
}
const scrollHeight = this.container.scrollHeight;
this.pageItems.push({
page: this.currentPage + 1,
top: scrollHeight,
url: this.nextUrl
});
const listPagePlugin = this.getBean("ListPagePlugin");
const coverImgs = $dom.find(this.getSelector().coverImgSelector);
listPagePlugin.replaceHdImg(coverImgs);
$(this.getSelector().boxSelector).append(items);
const nextLinkEl = $dom.find(selectorConfig.nextPageSelector);
this.nextUrl = nextLinkEl == null ? void 0 : nextLinkEl.attr("href");
this.hasMore = !!this.nextUrl;
const paginationEl = $dom.find(".pagination");
$(".pagination").replaceWith(paginationEl);
this.setState("waterfall-loading", "");
if (!this.hasMore) this.setState("waterfall-no-more", "已经到底了");
} catch (err) {
clog.error("加载失败:", err);
this.setState("waterfall-error", "加载失败,点击重试");
} finally {
this.isLoading = false;
}
}
checkScrollPosition() {
const scrollY = window.scrollY;
for (let i = this.pageItems.length - 1; i >= 0; i--) {
const item = this.pageItems[i];
if (scrollY >= item.top) {
if (this.currentPage !== item.page) {
this.currentPage = item.page;
this.updatePageUrl(item.url);
}
break;
}
}
}
checkLoad() {
if (!this.loader) return;
if (this.loader.getBoundingClientRect().top < window.innerHeight + this.preloadDistance) this.loadNextPage().then();
}
async shouldDisablePaging() {
if (!window.isListPage) return true;
await storageManager.getSetting("autoPage", "yes");
return [
"search?q",
"handlePlayback=1",
"handleTop=1",
"/want_watch_videos",
"/watched_videos",
"/advanced_search?type=100"
].some((pattern) => currentHref.includes(pattern));
}
updatePageUrl_old(url) {
window.history.pushState({}, "", url);
}
updatePageUrl(url) {
window.history.replaceState({}, "", url);
}
setState(stateClass, text) {
this.loader.className = `jhs-scroll ${stateClass}`;
this.loader.textContent = text;
}
};
function BlacklistDialog({ showUrlType }) {
return (0, import_jsx_runtime.jsxs)("div", {
style: {
padding: "10px 20px",
height: "100%",
overflow: "hidden"
},
children: [(0, import_jsx_runtime.jsxs)("div", {
style: {
display: "flex",
justifyContent: "space-between"
},
children: [(0, import_jsx_runtime.jsx)("div", { style: {
display: "flex",
gap: "5px"
} }), (0, import_jsx_runtime.jsxs)("div", {
style: {
display: "flex",
gap: "5px"
},
children: [
(0, import_jsx_runtime.jsxs)("select", {
id: "dataType",
style: {
textAlign: "center",
minWidth: "150px"
},
children: [
(0, import_jsx_runtime.jsx)("option", {
value: "",
selected: true,
children: "所有"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "actor",
children: "男演员"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "actress",
children: "女演员"
})
]
}),
(0, import_jsx_runtime.jsxs)("select", {
id: "statusType",
style: {
textAlign: "center",
minWidth: "150px"
},
children: [
(0, import_jsx_runtime.jsx)("option", {
value: "",
selected: true,
children: "--检测状态--"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "normal",
children: "正常检测"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "stop",
children: "停止检测"
})
]
}),
(0, import_jsx_runtime.jsxs)("select", {
id: "urlType",
"data-tip": "在演员页屏蔽时,是否选择了分类",
style: {
textAlign: "center",
minWidth: "150px",
display: showUrlType ? void 0 : "none"
},
children: [
(0, import_jsx_runtime.jsx)("option", {
value: "",
selected: true,
children: "--屏蔽类型--"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "hasT",
children: "按所选分类屏蔽"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "noT",
children: "未筛选分类"
})
]
}),
(0, import_jsx_runtime.jsx)("input", {
id: "searchValue",
type: "text",
placeholder: "搜索演员",
style: { padding: "4px 5px" }
}),
(0, import_jsx_runtime.jsx)("a", {
id: "cleanQueryBtn",
className: "a-info",
style: { marginLeft: "0" },
children: "重置"
})
]
})]
}), (0, import_jsx_runtime.jsx)("div", {
id: "table-container",
style: { height: "calc(100% - 50px)" }
})]
});
}
function BlacklistConfirmMessage({ tagName, name, isAlreadyBlacklisted, isActress, notFirstPageByQuery }) {
return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
isAlreadyBlacklisted ? isActress ? "演员 " : "分类 " : isActress ? "是否将该演员 " : "是否将分类 ",
(0, import_jsx_runtime.jsx)("span", {
style: { color: "#f40" },
children: isActress ? name : tagName
}),
isAlreadyBlacklisted ? " 已在黑名单中, 是否从当前页开始追加屏蔽?" : " 加入到黑名单中?",
notFirstPageByQuery && (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("br", {}), " 注意: 当前页面非第一页, 屏蔽数据将从此页面开始"] })
] });
}
function BlacklistDataTypeOptions({ totalCount, actorCount, actressCount }) {
return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
(0, import_jsx_runtime.jsxs)("option", {
value: "",
children: [
"所有 (",
totalCount,
")"
]
}),
(0, import_jsx_runtime.jsxs)("option", {
value: "actor",
children: [
"男演员 (",
actorCount,
")"
]
}),
(0, import_jsx_runtime.jsxs)("option", {
value: "actress",
children: [
"女演员 (",
actressCount,
")"
]
})
] });
}
function BlacklistNameCell({ url, name }) {
return (0, import_jsx_runtime.jsx)("a", {
className: "open-url",
"data-url": url,
href: url,
"data-name": name,
target: "_blank",
children: name
});
}
function BlacklistUrlTypeCell({ hasTag }) {
return (0, import_jsx_runtime.jsx)("span", {
style: { color: hasTag ? "#cc4444" : void 0 },
children: hasTag ? "按所选分类屏蔽" : "未筛选分类"
});
}
function BlacklistStatusCell({ tipText, statusText }) {
return (0, import_jsx_runtime.jsx)("span", {
"data-tip": tipText,
style: { color: tipText ? "#cc4444" : void 0 },
children: statusText
});
}
function BlacklistActionCell() {
return (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: (0, import_jsx_runtime.jsxs)("a", {
className: "a-danger delete-btn",
children: [
" ",
(0, import_jsx_runtime.jsx)("span", { children: "✂️ 删除" }),
" "
]
}) });
}
function MovieListWrapper({ html, nextUrl }) {
return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("div", {
className: "movie-list",
dangerouslySetInnerHTML: { __html: html }
}), nextUrl ? (0, import_jsx_runtime.jsx)("a", {
className: "pagination-next",
href: nextUrl
}) : null] });
}
function BlacklistPaginationCounter({ actorCount, currentCarCount }) {
return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
"演员: ",
actorCount,
" \xA0\xA0\xA0番号总数: ",
currentCarCount,
" ",
(0, import_jsx_runtime.jsx)("span", {
id: "checkBlacklistMsg",
style: { marginLeft: "10px" }
})
] });
}
var BlacklistPlugin = class extends BasePlugin {
loadObj;
tableObj;
nextPageLink;
lastPageLink;
checkBlacklist_ruleTime = 8760;
currentCarCount = 0;
getName() {
return "BlacklistPlugin";
}
async addBlacklist(event) {
const position = {
clientX: event.clientX,
clientY: event.clientY + 80
};
const isAlreadyBlacklisted = $("#addBlacklistBtn span").text().includes("已加入");
let blacklistInfo;
let isActress;
let tagName = "";
if (currentHref.includes("/tags")) {
const tagUrl = new URL(currentHref);
tagUrl.searchParams.delete("page");
tagName = $("#jhs-check-tag").text().trim();
blacklistInfo = {
starId: "no-" + tagName,
name: "虚拟演员-" + tagName,
allName: ["虚拟演员"],
role: "虚拟演员",
movieType: tagName,
blacklistUrl: tagUrl.toString()
};
isActress = false;
} else {
blacklistInfo = this.getActressPageInfo();
isActress = true;
}
const { starId, name, allName, role, movieType, blacklistUrl } = blacklistInfo;
const notFirstPageByQuery = currentHref.includes("page") && !currentHref.includes("page=1");
const confirmMessage = jsxToString((0, import_jsx_runtime.jsx)(BlacklistConfirmMessage, {
tagName,
name,
isAlreadyBlacklisted,
isActress,
notFirstPageByQuery
}));
utils.q(position, confirmMessage, async () => {
navigator.locks.request("checkNewActressActorFilterCar", { ifAvailable: true }, async (lock) => {
clog.debug("获取锁", lock);
if (lock) {
this.loadObj = loading();
try {
await storageManager.addBlacklistItem({
starId,
name,
allName,
role,
movieType,
url: blacklistUrl
});
await this.filterActorVideo(name, starId);
const okShow = show.ok(`屏蔽结束,是否跳转到最后一页: ${this.lastPageLink}`, {
duration: -1,
close: true,
onClick: () => {
okShow.closeShow();
window.location.href = this.lastPageLink;
}
});
} catch (error) {
clog.error(error);
const errorShow = show.error("发生错误, 是否填转到解析失败的那一页? (点击并跳转)", {
duration: -1,
close: true,
onClick: () => {
errorShow.closeShow();
window.location.href = this.nextPageLink;
}
});
} finally {
this.loadObj.close();
}
} else show.error("当前有定时任务在后台执行中, 无法发起此操作");
}).catch((lockError) => {
console.error("锁任务出现错误:", lockError);
clog.error("锁任务出现错误:", lockError);
});
});
}
async resetBtnTip() {
this.checkBlacklist_ruleTime = await storageManager.getSetting("checkBlacklist_ruleTime", 8760);
}
async openBlacklistDialog() {
const dialogHtml = jsxToString((0, import_jsx_runtime.jsx)(BlacklistDialog, { showUrlType: isJavdbSite }));
layer.open({
type: 1,
title: "演员黑名单",
content: dialogHtml,
scrollbar: false,
area: utils.getResponsiveArea(["80%", "90%"]),
anim: -1,
success: async (_layerEl) => {
await this.loadTableData();
$(".layui-layer-content").on("click", "#cleanQueryBtn", async (_event) => {
$("#searchValue").val("");
$("#dataType").val("");
$("#statusType").val("");
await this.reloadTable();
}).on("focusout keydown", "#searchValue", async (event) => {
if (event.type === "focusout" || event.key === "Enter") {
if (event.key === "Enter") event.preventDefault();
if (event.type === "keydown" && event.key !== "Enter") return;
$("#dataType").val("");
await this.reloadTable();
}
}).on("change", "#dataType", async () => {
$("#searchValue").val("");
await this.reloadTable();
}).on("change", "#statusType", async () => {
await this.reloadTable();
}).on("change", "#urlType", async () => {
await this.reloadTable();
}).on("click", ".open-url", (event) => {
event.preventDefault();
const $link = $(event.currentTarget);
const url = $link.attr("data-url");
const name = $link.attr("data-name");
utils.openPage(url, name, true, event);
});
},
end: () => {
if (this.tableObj) {
this.tableObj.destroy();
this.tableObj = null;
}
refresh();
}
});
}
async reloadTable() {
if (!this.tableObj) return;
const data = await this.getTableData();
this.tableObj.setData(data);
}
async getTableData() {
const blacklist = await storageManager.getBlacklist();
const blacklistCars = await storageManager.getBlacklistCarList();
const searchValue = $("#searchValue").val();
const statusType = $("#statusType").val();
const $dataTypeSelect = $("#dataType");
const dataType = $dataTypeSelect.val();
const urlType = $("#urlType").val();
const totalCount = blacklist.length;
let actorCount = 0;
let actressCount = 0;
const enrichedList = blacklist.map((item) => {
if (item.role === "actor") actorCount++;
else if (item.role === "actress") actressCount++;
let isUnCheck = false;
if (item.lastPublishTime) isUnCheck = !utils.isUnnecessaryCheck(item.lastPublishTime, this.checkBlacklist_ruleTime);
return {
...item,
isUnCheck
};
}).filter((item) => (!searchValue || !!item.name.includes(searchValue)) && (statusType !== "normal" || !item.isUnCheck) && (statusType !== "stop" || !!item.isUnCheck) && (dataType ? item.role === dataType : (urlType !== "hasT" || !!item.url.includes("t=")) && (urlType !== "noT" || !item.url.includes("t="))));
$dataTypeSelect.html(jsxToString((0, import_jsx_runtime.jsx)(BlacklistDataTypeOptions, {
totalCount,
actorCount,
actressCount
})));
$dataTypeSelect.val(dataType);
const carsByStarId = new Map();
for (const carItem of blacklistCars) {
const starId = carItem.starId;
if (!carsByStarId.has(starId)) carsByStarId.set(starId, []);
carsByStarId.get(starId).push(carItem);
}
const finalData = enrichedList.map((item) => {
const starId = item.starId;
const cars = carsByStarId.get(starId) || [];
return {
...item,
carList: cars,
count: cars.length
};
});
this.currentCarCount = finalData.reduce((sum, row) => sum + (row.count || 0), 0);
return finalData;
}
async loadTableData() {
this.checkBlacklist_ruleTime = await storageManager.getSetting("checkBlacklist_ruleTime") || 8760;
const data = await this.getTableData();
this.tableObj = new Tabulator("#table-container", {
layout: "fitColumns",
placeholder: "暂无数据",
virtualDom: true,
data,
pagination: true,
paginationMode: "local",
paginationSize: 20,
paginationSizeSelector: [
20,
50,
100,
1e3,
99999
],
paginationCounter: (_pageSize, _pageNo, _maxPage, actorCount, _pages) => jsxToString((0, import_jsx_runtime.jsx)(BlacklistPaginationCounter, {
actorCount,
currentCarCount: this.currentCarCount
})),
responsiveLayout: "collapse",
responsiveLayoutCollapse: true,
columnDefaults: {
headerHozAlign: "center",
hozAlign: "center"
},
index: "starId",
columns: [
{
title: "演员",
field: "name",
sorter: "string",
minWidth: 100,
responsive: 0,
headerSort: false,
formatter: (cell, _formatterParams, _onRendered) => {
const rowData = cell.getData();
return jsxToString((0, import_jsx_runtime.jsx)(BlacklistNameCell, {
url: rowData.url,
name: rowData.name
}));
}
},
{
title: "性别角色",
field: "role",
sorter: "string",
width: 120,
responsive: 5,
formatter: (cell, _formatterParams, _onRendered) => {
const role = cell.getData().role;
let roleText = role;
if (role === "actor") roleText = "男演员";
else if (role === "actress") roleText = "女演员";
return roleText;
}
},
{
title: "影视类别",
field: "movieType",
sorter: "string",
width: 120,
responsive: 5,
formatter: (cell, _formatterParams, _onRendered) => {
const movieType = cell.getData().movieType;
let movieTypeText = movieType;
if (movieType === "censored") movieTypeText = "有码";
else if (movieType === "uncensored") movieTypeText = "无码";
return movieTypeText;
}
},
{
title: "屏蔽类型",
field: "url",
sorter: "string",
minWidth: 120,
responsive: 4,
visible: isJavdbSite,
formatter: (cell, _formatterParams, _onRendered) => {
return jsxToString((0, import_jsx_runtime.jsx)(BlacklistUrlTypeCell, { hasTag: cell.getData().url.includes("t=") }));
}
},
{
title: "番号数量",
field: "count",
sorter: "number",
width: 170,
responsive: 1
},
{
title: "创建时间",
field: "createTime",
sorter: "string",
width: 170,
responsive: 5
},
{
title: "最后发行时间",
field: "lastPublishTime",
sorter: "string",
width: 170,
responsive: 1
},
{
title: "状态",
field: "isUnCheck",
sorter: "string",
width: 120,
responsive: 1,
formatter: (cell, _formatterParams, _onRendered) => {
let tipText = "";
let statusText = "正常检测";
if (cell.getData().isUnCheck) {
tipText = `停更${this.checkBlacklist_ruleTime / 24 / 365}年以上, 下轮任务不再进行检测`;
statusText = "停止检测";
}
return jsxToString((0, import_jsx_runtime.jsx)(BlacklistStatusCell, {
tipText,
statusText
}));
}
},
{
title: "操作",
sorter: "string",
cssClass: "action-cell-dropdown",
minWidth: 150,
responsive: 0,
headerSort: false,
formatter: (cell, _formatterParams, onRendered) => {
const rowData = cell.getData();
onRendered(() => {
const deleteBtn = cell.getElement().querySelector(".delete-btn");
if (deleteBtn != null) deleteBtn.addEventListener("click", (event) => {
const name = rowData.name;
const starId = rowData.starId;
if (name) if (starId) utils.q(event, `是否移除对 ${name} 的屏蔽?`, async () => {
await storageManager.removeBlacklistCarList(starId);
await storageManager.deleteBlacklistItem(starId);
show.info("操作成功");
this.reloadTable().then();
});
else show.error("获取starId失败");
else show.error("获取名称失败");
});
const keywordBtn = cell.getElement().querySelector(".keyword-btn");
if (keywordBtn != null) keywordBtn.addEventListener("click", () => {
const prefixCounts = rowData.carList.reduce((acc, carItem) => {
const prefix = carItem.carNum.split("-")[0] + "-";
acc[prefix] = (acc[prefix] || 0) + 1;
return acc;
}, {});
const sortedPrefixes = Object.entries(prefixCounts).map(([prefix, count]) => ({
prefix,
count
})).sort((a, b) => b.count - a.count);
console.log(sortedPrefixes);
});
});
return jsxToString((0, import_jsx_runtime.jsx)(BlacklistActionCell, {}));
}
}
],
initialSort: [{
column: "createTime",
dir: "desc"
}],
locale: "zh-cn",
langs: { "zh-cn": { pagination: {
first: "首页",
first_title: "首页",
last: "尾页",
last_title: "尾页",
prev: "上一页",
prev_title: "上一页",
next: "下一页",
next_title: "下一页",
all: "所有",
page_size: "每页行数"
} } }
});
}
getCurrentStarUrl() {
let url = window.location.href.replace(/([&?])sort_type=[^&]+(&|$)/, "$1");
url = url.replace(/[&?]$/, "");
url = url.replace(/\?&/, "?");
let result = url;
result = result.replace(/([&?])page=\d+(&|$)/, "$1");
result = result.replace(/[&?]$/, "");
result = result.replace(/\?&/, "?");
result = result.replace(/\/(\d+)(?:\/(\d+))?(\?|$)/, (match, seg1, seg2, tail) => seg2 !== void 0 ? `/${seg1}${tail}` : match);
return result;
}
parseUrlId(url) {
if (!url) throw new Error("url未传入");
return new URL(url).pathname.split("/").filter((seg) => seg.trim() !== "").pop();
}
async filterAllVideo(names, $dom) {
let items;
let nextPageHref;
if ($dom) {
items = $dom.find(this.getSelector().requestDomItemSelector);
nextPageHref = $dom.find(this.getSelector().nextPageSelector).attr("href");
} else {
items = $(this.getSelector().itemSelector);
nextPageHref = $(this.getSelector().nextPageSelector).attr("href");
}
if (nextPageHref && items.length === 0) {
show.error("解析列表失败");
throw new Error("解析列表失败");
}
for (const itemEl of items) {
const $item = $(itemEl);
const { carNum, url, publishTime } = this.getBean("ListPagePlugin").findCarNumAndHref($item);
if (url && carNum) try {
if (await storageManager.getCar(carNum)) continue;
await storageManager.saveCar({
carNum,
url,
names,
actionType: FILTER_ACTION,
publishTime
});
clog.log("屏蔽演员番号", names, carNum);
} catch (error) {
console.error(`保存失败 [${carNum}]:`, error);
}
}
if (nextPageHref) {
show.info("请不要关闭窗口, 正在解析下一页:" + nextPageHref);
await new Promise((resolve) => setTimeout(resolve, 500));
const pageHtml = await gmHttp.get(nextPageHref);
const domParser = new DOMParser();
const $parsed = $(domParser.parseFromString(pageHtml, "text/html"));
await this.filterAllVideo(names, $parsed);
} else {
show.ok("执行结束!");
refresh();
}
}
async filterActorVideo(name, starId, $dom) {
const { nextPageLink } = await this.parseAndSaveFilterInfo($dom, name, starId);
this.nextPageLink = nextPageLink;
if (nextPageLink) {
let nextDom;
this.lastPageLink = nextPageLink;
show.info("请不要关闭窗口, 正在解析下一页:" + nextPageLink);
const pageNum = utils.getUrlParam(nextPageLink, "page") || 0;
const beyond60Plugin = this.getBean("Beyond60Plugin");
if (isJavdbSite && beyond60Plugin && pageNum > 60) {
const { html, nextUrl, hasMore: _hasMore } = await beyond60Plugin.handleBeyond60(nextPageLink);
const wrapperHtml = jsxToString((0, import_jsx_runtime.jsx)(MovieListWrapper, {
html,
nextUrl
}));
nextDom = utils.htmlTo$dom(wrapperHtml);
} else {
clog.log("正在请求下一页内容:", nextPageLink);
const pageHtml = await gmHttp.get(nextPageLink);
nextDom = utils.htmlTo$dom(pageHtml);
}
await this.filterActorVideo(name, starId, nextDom);
} else {
show.ok("执行结束!");
refresh();
}
}
async parseAndSaveFilterInfo($dom, names, starId) {
let items;
let nextPageHref;
if ($dom) {
let siteType = JAVDB;
items = $dom.find(this.getSelector(siteType).requestDomItemSelector);
nextPageHref = $dom.find(this.getSelector(siteType).nextPageSelector).attr("href");
} else {
items = $(this.getSelector().itemSelector);
nextPageHref = $(this.getSelector().nextPageSelector).attr("href");
}
if (nextPageHref && items.length === 0) return {
nextPageLink: null,
lastPublishTime: null
};
let carList = [];
let lastPublishTime = null;
for (const itemEl of items) {
const $item = $(itemEl);
const { carNum, url, publishTime } = this.getBean("ListPagePlugin").findCarNumAndHref($item);
lastPublishTime ||= publishTime;
if (url && carNum) carList.push({
carNum,
url,
names,
actionType: FILTER_ACTION,
starId,
publishTime
});
}
try {
await storageManager.batchSaveBlacklistCarList(carList);
} catch (error) {
clog.error("保存失败:", error);
console.error("保存失败:", error);
}
return {
nextPageLink: nextPageHref,
lastPublishTime
};
}
};
function WantWatchedHintSpan({ variant }) {
return (0, import_jsx_runtime.jsxs)("span", {
style: {
marginLeft: "8px",
color: "#888",
fontSize: "12px"
},
children: [
"(JHS 现已在详情页自动同步\"",
variant === "want" ? "想看" : "看過",
"\",本页按钮仅用于初始补录)"
]
});
}
function WantWatchedImportButton({ variant }) {
return (0, import_jsx_runtime.jsx)("a", {
className: variant === "want" ? "a-primary" : "a-success",
id: "wantWatchBtn",
style: { padding: "10px" },
children: "导入至 JHS"
});
}
var WantAndWatchedVideosPlugin = class extends BasePlugin {
type = null;
getName() {
return "WantAndWatchedVideosPlugin";
}
async handle() {
if (window.location.href.includes("/want_watch_videos")) {
$("h3").append(jsxToString((0, import_jsx_runtime.jsx)(WantWatchedImportButton, { variant: "want" })));
$("h3").append(jsxToString((0, import_jsx_runtime.jsx)(WantWatchedHintSpan, { variant: "want" })));
$("#wantWatchBtn").on("click", (clickEvent) => {
this.type = FAVORITE_ACTION;
this.importWantWatchVideos(clickEvent, "是否将 想看的影片 导入到 JHS-收藏?");
});
}
if (window.location.href.includes("/watched_videos")) {
$("h3").append(jsxToString((0, import_jsx_runtime.jsx)(WantWatchedImportButton, { variant: "watched" })));
$("h3").append(jsxToString((0, import_jsx_runtime.jsx)(WantWatchedHintSpan, { variant: "watched" })));
$("#wantWatchBtn").on("click", (clickEvent) => {
this.type = HAS_WATCH_ACTION;
this.importWantWatchVideos(clickEvent, "是否将 看过的影片 导入到 JHS-已观看?");
});
}
}
importWantWatchVideos(_clickEvent, confirmMessage) {
utils.q(null, `${confirmMessage} <br/> <span style='color: #f40'>执行此功能前请记得备份数据</span>`, async () => {
const loadingOverlay = loading();
try {
await this.parseMovieList();
} catch (error) {
console.error(error);
} finally {
loadingOverlay.close();
}
});
}
async parseMovieList(rootEl) {
let itemElements;
let nextPageHref;
if (rootEl) {
itemElements = rootEl.find(this.getSelector().itemSelector);
nextPageHref = rootEl.find(".pagination-next").attr("href");
} else {
itemElements = $(this.getSelector().itemSelector);
nextPageHref = $(".pagination-next").attr("href");
}
for (const rawItem of itemElements) {
const $item = $(rawItem);
const href = $item.find("a").attr("href");
const carNum = $item.find(".video-title strong").text().trim();
const metaText = $item.find(".meta").text().trim();
if (href && carNum) try {
if (await storageManager.getCar(carNum)) {
show.info(`${carNum} 已存在, 跳过`);
continue;
}
await storageManager.saveCar({
carNum,
url: href,
names: null,
actionType: this.type,
publishTime: metaText
});
} catch (error) {
console.error(`保存失败 [${carNum}]:`, error);
}
}
if (nextPageHref) {
show.info("发现下一页,正在解析:", nextPageHref);
await new Promise((resolve) => setTimeout(resolve, 1e3));
$.ajax({
url: nextPageHref,
method: "GET",
success: (responseHtml) => {
const domParser = new DOMParser();
const $parsedDom = $(domParser.parseFromString(responseHtml, "text/html"));
this.parseMovieList($parsedDom);
},
error: function(request) {
console.error(request);
show.error("加载下一页失败:" + request.message);
}
});
} else {
show.ok("导入结束!");
refresh();
}
}
};
function RelatedContainers() {
return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("div", { id: "relatedContainer" }), (0, import_jsx_runtime.jsx)("div", { id: "relatedFooter" })] });
}
function RelatedEmpty() {
return (0, import_jsx_runtime.jsx)("div", {
style: {
marginTop: "15px",
backgroundColor: "#ffffff",
padding: "10px",
marginLeft: "-10px"
},
children: "无清单"
});
}
function RelatedEnd() {
return (0, import_jsx_runtime.jsx)("div", {
style: {
textAlign: "center",
padding: "10px",
color: "#666",
marginTop: "10px"
},
children: "已加载全部清单"
});
}
function RelatedError() {
return (0, import_jsx_runtime.jsxs)("div", {
style: {
marginTop: "15px",
backgroundColor: "#ffffff",
padding: "10px",
marginLeft: "-10px"
},
children: ["获取清单失败", (0, import_jsx_runtime.jsx)("a", {
id: "retryFetchRelateds",
href: "javascript:;",
style: {
marginLeft: "10px",
color: "#1897ff",
textDecoration: "none"
},
children: "重试"
})]
});
}
function RelatedHeader({ foldText, iconText }) {
return (0, import_jsx_runtime.jsxs)("div", {
style: {
display: "flex",
alignItems: "center",
margin: "16px 0",
color: "#666",
fontSize: "14px"
},
children: [
(0, import_jsx_runtime.jsx)("span", { style: {
flex: 1,
height: "1px",
background: "linear-gradient(to right, transparent, #999, transparent)"
} }),
(0, import_jsx_runtime.jsx)("span", {
style: { padding: "0 10px" },
children: "相关清单"
}),
(0, import_jsx_runtime.jsxs)("a", {
id: "relatedFold",
style: {
marginLeft: "8px",
color: "#1897ff",
textDecoration: "none",
display: "flex",
alignItems: "center"
},
children: [(0, import_jsx_runtime.jsx)("span", {
className: "toggle-text",
children: foldText
}), (0, import_jsx_runtime.jsx)("span", {
className: "toggle-icon",
style: { marginLeft: "4px" },
children: iconText
})]
}),
(0, import_jsx_runtime.jsx)("span", { style: {
flex: 1,
height: "1px",
background: "linear-gradient(to right, transparent, #999, transparent)"
} })
]
});
}
function RelatedItem({ index, relatedId, name, movieCount, collectionCount, viewCount, createTime }) {
return (0, import_jsx_runtime.jsxs)("div", {
className: "item columns is-desktop",
style: {
display: "block",
marginTop: "6px",
backgroundColor: "#ffffff",
padding: "10px",
marginLeft: "-10px",
wordBreak: "break-word",
position: "relative"
},
children: [
(0, import_jsx_runtime.jsxs)("span", {
style: {
position: "absolute",
top: "5px",
right: "10px",
color: "#999",
fontSize: "12px"
},
children: ["#", index]
}),
(0, import_jsx_runtime.jsxs)("span", {
style: {
position: "absolute",
bottom: "5px",
right: "10px",
color: "#999",
fontSize: "12px"
},
children: ["创建时间: ", createTime]
}),
(0, import_jsx_runtime.jsx)("p", { children: (0, import_jsx_runtime.jsx)("a", {
href: `/lists/${relatedId}`,
target: "_blank",
style: { color: "#2e8abb" },
children: name
}) }),
(0, import_jsx_runtime.jsxs)("p", {
style: { marginTop: "5px" },
children: ["视频个数: ", movieCount]
}),
(0, import_jsx_runtime.jsxs)("p", {
style: { marginTop: "5px" },
children: [
"收藏次数: ",
collectionCount,
" 被查看次数: ",
viewCount
]
})
]
});
}
function RelatedLoadMore() {
return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("button", {
id: "loadMoreRelateds",
style: {
width: "100%",
backgroundColor: "#e1f5fe",
border: "none",
padding: "10px",
marginTop: "10px",
cursor: "pointer",
color: "#0277bd",
fontWeight: "bold",
borderRadius: "4px"
},
children: "加载更多清单"
}), (0, import_jsx_runtime.jsx)("div", {
id: "relatedEnd",
style: {
display: "none",
textAlign: "center",
padding: "10px",
color: "#666",
marginTop: "10px"
},
children: "已加载全部清单"
})] });
}
function RelatedLoading() {
return (0, import_jsx_runtime.jsx)("div", {
id: "relatedLoading",
style: {
marginTop: "15px",
backgroundColor: "#ffffff",
padding: "10px",
marginLeft: "-10px"
},
children: "获取清单中..."
});
}
var RelatedPlugin = class extends BasePlugin {
floorIndex = 1;
isInit = false;
getName() {
return "RelatedPlugin";
}
async showRelated(container, movieId) {
const isExpanded = await storageManager.getSetting("enableLoadRelated", "no");
const target = container || $("#magnets-content");
target.append(jsxToString((0, import_jsx_runtime.jsx)(RelatedHeader, {
foldText: isExpanded === "yes" ? "折叠" : "展开",
iconText: isExpanded === "yes" ? "▲" : "▼"
})));
$("#relatedFold").on("click", (event) => {
event.preventDefault();
event.stopPropagation();
const toggleText = $("#relatedFold .toggle-text");
const toggleIcon = $("#relatedFold .toggle-icon");
const isExpand = toggleText.text() === "展开";
toggleText.text(isExpand ? "折叠" : "展开");
toggleIcon.text(isExpand ? "▲" : "▼");
if (isExpand) {
$("#relatedContainer").show();
$("#relatedFooter").show();
if (!this.isInit) {
this.fetchAndDisplayRelateds(movieId);
this.isInit = true;
}
storageManager.saveSettingItem("enableLoadRelated", "yes");
} else {
$("#relatedContainer").hide();
$("#relatedFooter").hide();
storageManager.saveSettingItem("enableLoadRelated", "no");
}
});
target.append(jsxToString((0, import_jsx_runtime.jsx)(RelatedContainers, {})));
if (isExpanded === "yes") await this.fetchAndDisplayRelateds(movieId);
}
async fetchAndDisplayRelateds(movieId) {
const container = $("#relatedContainer");
const footer = $("#relatedFooter");
container.append(jsxToString((0, import_jsx_runtime.jsx)(RelatedLoading, {})));
const limit = 20;
let list = null;
try {
list = await fetchRelatedCollections(movieId, 1, limit);
} catch (err) {
if (err.toString().includes("簽名已過期")) show.error("生成签名失败, 请检查系统时间及时区是否正确!");
clog.error("获取清单失败:", err);
console.error("获取清单失败:", err);
} finally {
$("#relatedLoading").remove();
}
if (!list) {
container.append(jsxToString((0, import_jsx_runtime.jsx)(RelatedError, {})));
$("#retryFetchRelateds").on("click", async () => {
$("#retryFetchRelateds").parent().remove();
await this.fetchAndDisplayRelateds(movieId);
});
return;
}
if (list.length === 0) {
container.append(jsxToString((0, import_jsx_runtime.jsx)(RelatedEmpty, {})));
return;
}
this.displayRelateds(list, container);
if (list.length === limit) {
footer.html(jsxToString((0, import_jsx_runtime.jsx)(RelatedLoadMore, {})));
let page = 1;
const loadMoreBtn = $("#loadMoreRelateds");
loadMoreBtn.on("click", async () => {
let moreList;
loadMoreBtn.text("加载中...").prop("disabled", true);
page++;
try {
moreList = await fetchRelatedCollections(movieId, page, limit);
} catch (err) {
console.error("加载更多清单失败:", err);
} finally {
loadMoreBtn.text("加载失败, 请点击重试").prop("disabled", false);
}
if (moreList) {
this.displayRelateds(moreList, container);
if (moreList.length < limit) {
loadMoreBtn.remove();
$("#relatedEnd").show();
} else loadMoreBtn.text("加载更多清单").prop("disabled", false);
}
});
} else footer.html(jsxToString((0, import_jsx_runtime.jsx)(RelatedEnd, {})));
}
displayRelateds(list, container) {
if (list.length) list.forEach((item) => {
const html = jsxToString((0, import_jsx_runtime.jsx)(RelatedItem, {
index: this.floorIndex++,
relatedId: item.relatedId,
name: item.name,
movieCount: item.movieCount,
collectionCount: item.collectionCount,
viewCount: item.viewCount,
createTime: item.createTime
}));
container.append(html);
});
}
};
function FavoriteActressAvatarColumn() {
return (0, import_jsx_runtime.jsx)("div", {
className: "column actor-avatar",
children: (0, import_jsx_runtime.jsx)("div", {
className: "image",
children: (0, import_jsx_runtime.jsx)("span", { className: "avatar" })
})
});
}
var FavoriteActressesPlugin = class extends BasePlugin {
getName() {
return "FavoriteActressesPlugin";
}
async handle() {
this.bindEvent();
await this.highlightActress();
this.replaceActressAvatar();
}
async highlightActress() {
if (!window.isDetailPage) return;
if (await storageManager.getSetting("enableFavoriteActresses", "yes") !== "yes") return;
const favoriteActresses = await storageManager.getFavoriteActressList();
if (!favoriteActresses || favoriteActresses.length === 0) return;
const starIdSet = new Set();
favoriteActresses.forEach((actress) => {
if (actress.starId) starIdSet.add(String(actress.starId).trim());
});
if (starIdSet.size !== 0) $(".female").prev().each((_index, element) => {
const $link = $(element);
const href = $link.attr("href");
let urlStarId = null;
if (href) {
const segments = (href.endsWith("/") ? href.slice(0, -1) : href).split("/");
const lastSegment = segments[segments.length - 1];
if (lastSegment) urlStarId = lastSegment.trim();
}
let isFavorite = false;
if (urlStarId) isFavorite = starIdSet.has(urlStarId);
if (isFavorite) {
$link.addClass("highlighted");
$link.attr("title", "高亮已收藏演员, 可在设置-基础配置中关闭");
}
});
}
async removeActorFromStorage(starId) {
if (await storageManager.removeFavoriteActress(starId)) clog.log("移除演员成功");
}
bindEvent() {
const actorIdRegex = /\/actors\/(\w+)\/(collect|uncollect)/;
$(document).on("confirm:complete", "a[href*=\"/actors/\"][href*=\"/uncollect\"]", async (event) => {
const [confirmResult] = event.detail;
if (!confirmResult) return;
const match = $(event.currentTarget).attr("href").match(actorIdRegex);
const actorId = match ? match[1] : null;
if (actorId) await this.removeActorFromStorage(actorId);
});
$("#button-collect-actor").click(async (_event) => {
const match = $("#button-collect-actor").attr("href").match(actorIdRegex);
const actorId = match ? match[1] : null;
const actressNames = [];
const $nameSection = $(".actor-section-name");
if ($nameSection.length) $nameSection.text().trim().split(",").forEach((name) => {
actressNames.push(name.trim());
});
const $metaSection = $(".section-meta:not(:contains('影片'))");
if ($metaSection.length) $metaSection.text().trim().split(",").forEach((name) => {
actressNames.push(name.trim());
});
if (!actressNames) {
clog.error("获取演员名称失败");
return;
}
const firstName = actressNames[0];
if (!actorId) {
clog.error("无法获取演员ID进行收藏操作。");
return;
}
const actressData = {
starId: actorId,
name: firstName,
allName: actressNames,
avatar: ($(".avatar").first().css("background-image") || "").replace(/^url\(["']?|["']?\)$/g, "")
};
if (await storageManager.addFavoriteActressList([actressData]) === 1) clog.log(`收藏演员成功: ${firstName} (ID: ${actorId})`);
else clog.log(`收藏演员失败: ${firstName} (ID: ${actorId})`);
});
$("#button-uncollect-actor").click(async (_event) => {
const match = $("#button-uncollect-actor").attr("href").match(actorIdRegex);
const actorId = match ? match[1] : null;
if (actorId) await this.removeActorFromStorage(actorId);
else clog.error("无法获取演员ID进行取消收藏操作。");
});
}
async replaceActressAvatar() {
const actressId = this.getActressId();
if (!actressId) return;
const matchedActress = (await storageManager.getFavoriteActressList()).find((actress) => actress.starId === actressId);
if (matchedActress && matchedActress.avatar) {
const cssUrl = `url('${matchedActress.avatar}')`;
let $avatar = $(".avatar").first();
if ($avatar.length === 0) {
const avatarColumnHtml = jsxToString((0, import_jsx_runtime.jsx)(FavoriteActressAvatarColumn, {}));
$(".section-columns").prepend(avatarColumnHtml);
$avatar = $(".avatar").first();
}
if ($avatar.length === 0) return;
if ($avatar.css("background-image").trim().toLowerCase() !== cssUrl.trim().toLowerCase()) {
$avatar.css("background-image", cssUrl);
$avatar.css("background-size", "cover");
$avatar.css("background-position", "top center");
$avatar.css("background-repeat", "no-repeat");
}
}
}
};
var new_video_plugin_default = "#actress-card-container {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(243px, 1fr)); /* 响应式3-5列 */\n gap: 20px;\n padding-bottom: 20px;\n padding-right: 10px;\n background: #f9f9f9;\n border-radius: 5px;\n overflow-y: auto;\n}\n.actress-card {\n background: #fff;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.08);\n padding: 15px;\n text-align: center;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n position: relative;\n overflow: hidden;\n}\n.actress-card:hover {\n box-shadow: 0 8px 15px rgba(0, 0, 0, 0.15);\n}\n.actress-card-name {\n font-size: 1.2em;\n font-weight: bold;\n color: #007bff;\n margin-top: 10px;\n}\n.actress-card-allname {\n font-size: 0.9em;\n color: #999;\n margin-top: 5px;\n height: 30px; /* 保证高度一致性 */\n overflow: hidden;\n white-space: nowrap; /* 防止文字换行 */\n text-overflow: ellipsis; /* 当文本溢出时,显示省略号 */\n}\n.actress-card-avatar {\n width: 100px;\n height: 100px;\n border-radius: 50%;\n object-fit: contain;\n margin: 0 auto;\n border: 4px solid #f0f0f0;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n}\n\n.card-tag {\n position: absolute;\n top: 15px; /* 调整标签距离顶部的距离 */\n right: -50px; /* 调整标签距离右侧的距离,负值让它移到外面一点 */\n\n width: 150px; /* 标签的宽度,影响斜角长度 */\n padding: 5px 0; /* 上下内边距 */\n text-align: center;\n\n background-color: #ff4757; /* 标签颜色 */\n color: white; /* 文字颜色 */\n font-size: 14px;\n font-weight: bold;\n z-index: 10; /* 确保标签在其他内容之上 */\n\n /* 3. 核心:旋转标签,使其倾斜 */\n transform: rotate(45deg); /* 45度斜角 */\n\n /* 可选:添加一些阴影或边框效果 */\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n}\n\n.card-new-count-tag {\n position: absolute;\n top: 5px;\n text-align: center;\n font-size: 14px;\n font-weight: bold;\n z-index: 10;\n}\n\n#actress-pagination {\n padding-top: 10px;\n text-align: center;\n border-top: 1px solid #ddd;\n}\n@media (max-width: 600px) {\n .page-number-btn {\n display: none !important;\n }\n}\n\n.card-btn {\n width: 44px;\n height: 44px;\n border-radius: 50%;\n display: flex;\n justify-content: center;\n align-items: center;\n text-decoration: none;\n border: none;\n cursor: pointer;\n background: linear-gradient(145deg, #e0e0e0 0%, #f7f7f7 100%);\n box-shadow:\n 8px 8px 16px rgba(0, 0, 0, 0.08),\n -8px -8px 16px rgba(255, 255, 255, 1);\n transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\n}\n\n.card-btn svg,\n.card-btn svg path {\n transition: fill 0.3s ease;\n}\n\n.card-btn:hover {\n box-shadow:\n inset 5px 5px 10px rgba(0, 0, 0, 0.1),\n inset -5px -5px 10px rgba(255, 255, 255, 0.9);\n transform: scale(0.97);\n background: #e0e0e0;\n}\n\n.btn-check-actress svg path {\n fill: #4caf50;\n}\n.btn-check-actress:hover svg path {\n fill: #388e3c;\n}\n\n.btn-edit-actress svg path {\n fill: #ffc107;\n}\n.btn-edit-actress:hover svg path {\n fill: #ffb300;\n}\n\n.btn-delete-actress svg path {\n fill: #f44336;\n}\n.btn-delete-actress:hover svg path {\n fill: #d32f2f;\n}\n";
var avatar_select_dialog_default = "/* 保持上一个回答的美化样式 */\n#gfriends-image-list-container {\n padding: 15px;\n height: 100%;\n box-sizing: border-box;\n background-color: #f8f9fa;\n}\n#gfriends-prompt {\n color: #555;\n font-weight: 500;\n border-bottom: 1px solid #eee;\n padding-bottom: 10px;\n}\n#gfriends-image-list {\n display: flex;\n flex-wrap: wrap;\n gap: 15px;\n justify-content: center;\n}\n.gfriends-image-item-wrapper {\n width: 160px;\n height: 225px; /* 增加高度以容纳尺寸标签 */\n overflow: hidden;\n border-radius: 6px;\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n transition:\n transform 0.2s ease,\n box-shadow 0.2s ease;\n cursor: pointer;\n position: relative;\n padding-bottom: 25px; /* 为尺寸标签留出空间 */\n}\n.gfriends-selectable-img {\n width: 100%;\n height: 200px; /* 固定图片高度 */\n object-fit: cover;\n border: 3px solid transparent;\n border-radius: 6px;\n transition: border 0.2s ease;\n}\n.gfriends-image-item-wrapper:hover {\n transform: translateY(-4px) scale(1.02);\n box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);\n}\n.gfriends-selectable-img.is-selected {\n border-color: #ff6347;\n box-shadow: 0 0 0 3px #ff6347;\n}\n/* 新增:尺寸标签样式 */\n.gfriends-size-tag {\n position: absolute;\n bottom: 0; /* 定位到图片容器底部 */\n left: 0;\n right: 0;\n height: 25px;\n line-height: 25px;\n text-align: center;\n background-color: rgba(0, 0, 0, 0.7); /* 半透明背景 */\n color: #fff;\n font-size: 11px;\n font-weight: bold;\n border-bottom-left-radius: 6px;\n border-bottom-right-radius: 6px;\n user-select: none;\n}\n";
function NewVideoDialog({ refreshSvg }) {
return (0, import_jsx_runtime.jsxs)("div", {
className: "newVideoToolBox",
style: {
display: "flex",
flexDirection: "column",
height: "100%",
overflow: "hidden",
padding: "10px"
},
children: [
(0, import_jsx_runtime.jsxs)("div", {
style: {
marginBottom: "15px",
display: "flex",
justifyContent: "space-between"
},
children: [(0, import_jsx_runtime.jsx)("div", { children: (0, import_jsx_runtime.jsx)("span", { id: "checkNewVideoMsg" }) }), (0, import_jsx_runtime.jsxs)("div", {
style: {
display: "flex",
alignItems: "flex-start"
},
children: [(0, import_jsx_runtime.jsxs)("select", {
id: "paramActressType",
style: {
textAlign: "center",
height: "100%",
minWidth: "150px",
border: "1px solid #ddd",
marginRight: "10px"
},
children: [
(0, import_jsx_runtime.jsx)("option", {
value: "all",
selected: true,
children: "所有"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "uncensored",
children: "无码"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "censored",
children: "有码"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "",
children: "未知"
})
]
}), (0, import_jsx_runtime.jsx)("a", {
className: "a-normal",
id: "reLoad",
dangerouslySetInnerHTML: { __html: `${refreshSvg} 刷新` }
})]
})]
}),
(0, import_jsx_runtime.jsx)("div", {
id: "actress-card-container",
className: "jhs-scrollbar"
}),
(0, import_jsx_runtime.jsx)("div", { id: "actress-pagination" })
]
});
}
var LABEL_STYLE$1 = {
display: "block",
marginBottom: "5px",
fontWeight: "bold"
};
var FIELD_ROW_STYLE$1 = { marginBottom: "15px" };
function EditActressDialog({ avatar, name, textareaStyle, allNameText, actressType, newVideoText, remark }) {
return (0, import_jsx_runtime.jsxs)("div", {
style: { padding: "20px" },
children: [
(0, import_jsx_runtime.jsxs)("div", {
style: {
marginBottom: "15px",
textAlign: "center"
},
children: [(0, import_jsx_runtime.jsx)("img", {
id: "edit-avatar-preview",
src: avatar,
alt: "Avatar Preview",
style: {
width: "100px",
height: "100px",
borderRadius: "50%",
objectFit: "cover",
marginBottom: "10px",
border: "2px solid #ddd"
}
}), (0, import_jsx_runtime.jsxs)("div", {
style: { textAlign: "left" },
children: [
(0, import_jsx_runtime.jsx)("label", {
style: LABEL_STYLE$1,
children: "头像链接:"
}),
(0, import_jsx_runtime.jsx)("input", {
type: "text",
id: "edit-actress-avatar",
value: avatar,
style: {
width: "100%",
padding: "8px",
border: "1px solid #ccc",
borderRadius: "4px"
}
}),
(0, import_jsx_runtime.jsxs)("div", {
style: {
display: "flex",
gap: "5px",
marginTop: "5px"
},
children: [(0, import_jsx_runtime.jsx)("button", {
type: "button",
id: "search-avatar-btn",
style: {
flexGrow: 1,
padding: "8px",
backgroundColor: "#007bff",
color: "white",
border: "none",
borderRadius: "4px",
cursor: "pointer"
},
children: "搜索头像"
}), (0, import_jsx_runtime.jsx)("button", {
type: "button",
id: "select-cdn-btn",
style: {
width: "100px",
padding: "8px",
backgroundColor: "#6c757d",
color: "white",
border: "none",
borderRadius: "4px",
cursor: "pointer",
fontSize: "12px"
},
children: "选择 CDN 源"
})]
})
]
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
style: FIELD_ROW_STYLE$1,
children: [(0, import_jsx_runtime.jsx)("label", {
style: LABEL_STYLE$1,
children: "主名称:"
}), (0, import_jsx_runtime.jsx)("input", {
type: "text",
id: "edit-actress-name",
value: name,
style: {
width: "100%",
padding: "8px",
border: "1px solid #ccc",
borderRadius: "4px"
}
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
style: FIELD_ROW_STYLE$1,
children: [(0, import_jsx_runtime.jsx)("label", {
style: LABEL_STYLE$1,
children: "所有别名(用逗号隔开):"
}), (0, import_jsx_runtime.jsx)("textarea", {
id: "edit-actress-allname",
style: textareaStyle,
children: allNameText
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
style: FIELD_ROW_STYLE$1,
children: [(0, import_jsx_runtime.jsx)("label", {
style: LABEL_STYLE$1,
children: "演员类别:"
}), (0, import_jsx_runtime.jsxs)("select", {
id: "actressType",
style: {
width: "100%",
padding: "10px",
border: "1px solid #ddd"
},
children: [
(0, import_jsx_runtime.jsx)("option", {
value: "",
selected: actressType === "",
children: "未知"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "censored",
selected: actressType === "censored",
children: "有码"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "uncensored",
selected: actressType === "uncensored",
children: "无码"
})
]
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
style: FIELD_ROW_STYLE$1,
children: [(0, import_jsx_runtime.jsx)("label", {
style: LABEL_STYLE$1,
children: "最新作品(用逗号隔开):"
}), (0, import_jsx_runtime.jsx)("textarea", {
id: "edit-actress-newvideolist",
style: textareaStyle,
children: newVideoText
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
style: FIELD_ROW_STYLE$1,
children: [(0, import_jsx_runtime.jsx)("label", {
style: LABEL_STYLE$1,
children: "备注:"
}), (0, import_jsx_runtime.jsx)("textarea", {
id: "edit-remark",
style: textareaStyle,
children: remark
})]
})
]
});
}
function CdnSelectDialog({ sources, currentIndex }) {
return (0, import_jsx_runtime.jsxs)("div", {
style: { padding: "20px" },
children: [
(0, import_jsx_runtime.jsxs)("p", {
style: {
marginBottom: "15px",
fontWeight: "bold",
color: "#333"
},
children: [
"请选择头像数据源 (当前: ",
sources[currentIndex].name,
"):"
]
}),
sources.map((source, index) => (0, import_jsx_runtime.jsxs)("div", {
style: { marginBottom: "10px" },
children: [(0, import_jsx_runtime.jsx)("input", {
type: "radio",
id: `cdn-${index}`,
name: "cdn-source",
value: index,
checked: index === currentIndex,
style: { marginRight: "10px" }
}), (0, import_jsx_runtime.jsxs)("label", {
for: `cdn-${index}`,
children: [
source.name,
" ",
source.json.includes("jsdelivr") ? "(推荐)" : ""
]
})]
}, index)),
(0, import_jsx_runtime.jsx)("p", {
style: {
marginTop: "20px",
color: "#555",
fontSize: "12px"
},
children: "切换源会清除本地缓存的数据,并在下次搜索时重新加载。"
})
]
});
}
function AvatarSelectDialog({ avatarUrls }) {
return (0, import_jsx_runtime.jsxs)("div", {
id: "gfriends-image-list-container",
children: [(0, import_jsx_runtime.jsxs)("p", {
id: "gfriends-prompt",
style: {
textAlign: "center",
fontSize: "15px",
marginBottom: "15px"
},
children: [
"点击图片即可选择(初始共 ",
avatarUrls.length,
" 张)"
]
}), (0, import_jsx_runtime.jsx)("div", {
style: {
overflowY: "auto",
height: "calc(100% - 40px)"
},
children: (0, import_jsx_runtime.jsx)("div", {
id: "gfriends-image-list",
children: avatarUrls.map((url, index) => (0, import_jsx_runtime.jsxs)("div", {
id: `wrapper-${index}`,
className: "gfriends-image-item-wrapper",
children: [(0, import_jsx_runtime.jsx)("img", {
alt: "",
src: url,
"data-url": url,
className: "gfriends-selectable-img",
"data-wrapper-id": `wrapper-${index}`
}), (0, import_jsx_runtime.jsx)("div", {
className: "gfriends-size-tag",
"data-size-for": `wrapper-${index}`,
children: "..."
})]
}, index))
})
})]
});
}
function ActressCard({ starId, avatar, name, allNameText, actressUrl, lastCheckTime, lastPublishTime, isStale, ruleTimeYears, remark, editSvg, deleteSvg, btnStyle, typeLabel, typeColor, newVideoCount }) {
return (0, import_jsx_runtime.jsxs)("div", {
className: "actress-card",
"data-starId": starId,
style: {
...isStale ? { background: "#d4cece" } : null,
minHeight: "370px"
},
children: [
(0, import_jsx_runtime.jsx)("a", {
href: actressUrl,
target: "_blank",
style: {
textDecoration: "none",
color: "inherit",
display: "block",
flexGrow: 1
},
children: (0, import_jsx_runtime.jsx)("img", {
src: avatar,
alt: allNameText,
className: "actress-card-avatar"
})
}),
(0, import_jsx_runtime.jsxs)("div", { children: [(0, import_jsx_runtime.jsx)("a", {
href: actressUrl,
target: "_blank",
style: {
textDecoration: "none",
color: "inherit",
display: "block",
flexGrow: 1
},
children: (0, import_jsx_runtime.jsx)("div", {
className: "actress-card-name",
children: name
})
}), (0, import_jsx_runtime.jsx)("div", {
className: "actress-card-allname",
title: allNameText,
children: allNameText
})] }),
(0, import_jsx_runtime.jsx)("div", {
style: {
fontSize: "0.8em",
marginTop: "5px"
},
children: (0, import_jsx_runtime.jsxs)("span", { children: ["上次检测: ", lastCheckTime] })
}),
(0, import_jsx_runtime.jsx)("div", {
style: {
fontSize: "0.8em",
marginTop: "5px"
},
children: (0, import_jsx_runtime.jsxs)("span", { children: ["最后发行作品: ", lastPublishTime] })
}),
(0, import_jsx_runtime.jsx)("div", {
style: {
fontSize: "0.7em",
color: "#cc4444",
marginTop: "5px",
minHeight: "18px"
},
children: (0, import_jsx_runtime.jsx)("span", { children: isStale ? `停更${ruleTimeYears}年以上, 下轮任务不再进行检测` : "" })
}),
(0, import_jsx_runtime.jsx)("div", {
style: {
fontSize: "0.8em",
marginTop: "5px",
color: "#3765c5",
minHeight: "10px"
},
children: (0, import_jsx_runtime.jsx)("span", { children: remark })
}),
(0, import_jsx_runtime.jsxs)("div", {
style: {
marginTop: "10px",
display: "flex",
justifyContent: "center",
gap: "10px"
},
children: [(0, import_jsx_runtime.jsx)("a", {
title: "编辑",
className: "card-btn btn-edit-actress",
style: btnStyle,
"data-starId": starId,
dangerouslySetInnerHTML: { __html: editSvg }
}), (0, import_jsx_runtime.jsx)("a", {
title: "取消收藏",
className: "card-btn btn-delete-actress",
style: btnStyle,
"data-starId": starId,
dangerouslySetInnerHTML: { __html: deleteSvg }
})]
}),
(0, import_jsx_runtime.jsx)("div", {
className: "card-tag",
style: { backgroundColor: typeColor },
children: typeLabel
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "card-new-count-tag",
"data-tip": `最新作品数量: ${newVideoCount}`,
children: ["🔔 ", newVideoCount]
})
]
});
}
var NAV_BTN_STYLE = {
padding: "8px 12px",
margin: "0 5px",
background: "#f0f0f0",
border: "1px solid #ddd",
borderRadius: "4px",
cursor: "pointer"
};
var PAGE_BTN_BASE_STYLE = {
padding: "8px 12px",
margin: "0 3px",
border: "1px solid #ddd",
borderRadius: "4px",
cursor: "pointer"
};
var ACTIVE_STYLE = {
background: "#007bff",
color: "white",
borderColor: "#007bff"
};
function ActressPagination({ totalCount, totalPages, page }) {
if (totalPages === 0) return (0, import_jsx_runtime.jsx)("span", {
style: { color: "#666" },
children: "共 0 条记录"
});
let rangeStart = Math.max(1, page - Math.floor(2.5));
let rangeEnd = Math.min(totalPages, rangeStart + 5 - 1);
if (rangeEnd - rangeStart < 4) rangeStart = Math.max(1, rangeEnd - 5 + 1);
return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
page > 1 && totalPages > 5 && (0, import_jsx_runtime.jsx)("button", {
className: "pagination-btn",
"data-page": 1,
style: NAV_BTN_STYLE,
children: "首页"
}),
page > 1 && (0, import_jsx_runtime.jsx)("button", {
className: "pagination-btn",
"data-page": page - 1,
style: NAV_BTN_STYLE,
children: "上一页"
}),
Array.from({ length: rangeEnd - rangeStart + 1 }, (_, i) => {
const pageNum = rangeStart + i;
return (0, import_jsx_runtime.jsx)("button", {
className: `pagination-btn page-number-btn ${pageNum === page ? "active" : ""}`,
"data-page": pageNum,
style: {
...PAGE_BTN_BASE_STYLE,
...pageNum === page ? ACTIVE_STYLE : null
},
children: pageNum
}, pageNum);
}),
page < totalPages && (0, import_jsx_runtime.jsx)("button", {
className: "pagination-btn",
"data-page": page + 1,
style: NAV_BTN_STYLE,
children: "下一页"
}),
page < totalPages && totalPages > 5 && (0, import_jsx_runtime.jsx)("button", {
className: "pagination-btn",
"data-page": totalPages,
style: NAV_BTN_STYLE,
children: "尾页"
}),
(0, import_jsx_runtime.jsxs)("span", {
style: {
marginLeft: "20px",
color: "#666"
},
children: [
"共 ",
totalCount,
" 条记录 (第 ",
page,
"/",
totalPages,
" 页)"
]
})
] });
}
function NewVideoDialogTitle() {
return (0, import_jsx_runtime.jsx)("span", {
style: { padding: "0 10px" },
"data-tip": "数据来源: 女优页面首页,含磁链分类",
children: "新作品检测 ❓"
});
}
var NewVideoPlugin = class extends BasePlugin {
currentPage = 1;
pageSize = 30;
getName() {
return "NewVideoPlugin";
}
async initCss() {
return new_video_plugin_default;
}
async handle() {
await this.showNewVideoCount();
}
async showNewVideoCount() {
const totalCount = (await storageManager.getFavoriteActressList()).reduce((total, actress) => {
return total + (actress.newVideoList?.length ?? 0);
}, 0);
$("#newVideoCount").text(`${totalCount}`);
}
async resetBtnTip() {}
async openDialog() {
const dialogContent = jsxToString((0, import_jsx_runtime.jsx)(NewVideoDialog, { refreshSvg: this.refreshSvg }));
layer.open({
type: 1,
title: jsxToString((0, import_jsx_runtime.jsx)(NewVideoDialogTitle, {})),
content: dialogContent,
scrollbar: false,
area: utils.getResponsiveArea(["80%", "90%"]),
anim: -1,
success: async (_layerEl, layerIndex) => {
this.loadData();
this.bindClick();
utils.setupEscClose(layerIndex);
}
});
}
bindClick() {
$("#reLoad").on("click", (_event) => {
this.loadData();
$("#checkNewVideoMsg").text("");
});
$("#paramActressType").on("change", (_event) => {
this.loadData();
});
}
loadData() {
this.currentPage = 1;
this.renderActressCards().then();
}
async renderActressCards() {
const $container = $("#actress-card-container");
if (!$container.length) return;
let favoriteActresses = await storageManager.getFavoriteActressList();
const typeFilter = $("#paramActressType").val();
if (typeFilter !== "all") favoriteActresses = favoriteActresses.filter((actress) => actress.actressType === typeFilter);
const sortedActresses = utils.genericSort(favoriteActresses, [{
key: (actress) => actress.newVideoList?.length ?? 0,
order: "desc"
}, {
key: "lastPublishTime",
order: "desc"
}]);
const totalCount = sortedActresses.length;
const totalPages = Math.ceil(totalCount / this.pageSize);
const startIndex = (this.currentPage - 1) * this.pageSize;
const endIndex = startIndex + this.pageSize;
const pageActresses = sortedActresses.slice(startIndex, endIndex);
const javDbUrl = await this.getBean("OtherSitePlugin").getJavDbUrl();
const ruleTimeHours = await storageManager.getSetting("checkNewVideo_ruleTime") || 8760;
const cardsHtml = pageActresses.map((actress) => {
const allNameText = Array.isArray(actress.allName) ? actress.allName.join(",") : "";
if (Array.isArray(actress.newVideoList)) actress.newVideoList.join(",");
const actressUrl = `${javDbUrl}/actors/${actress.starId}?t=d`;
let isStale = false;
if (actress.lastPublishTime) isStale = !utils.isUnnecessaryCheck(actress.lastPublishTime, ruleTimeHours);
let typeLabel = "未知";
let typeColor = "#9E9E9E";
if (actress.actressType === "uncensored") {
typeLabel = "无码";
typeColor = "#4CAF50";
} else if (actress.actressType === "censored") {
typeLabel = "有码";
typeColor = "#FF9800";
}
let btnStyle = {};
if (isStale) btnStyle = {
background: "linear-gradient(145deg, #e0e0e0 0%, #cabdbd 100%)",
boxShadow: "none"
};
return jsxToString((0, import_jsx_runtime.jsx)(ActressCard, {
starId: actress.starId,
avatar: actress.avatar || "https://c0.jdbstatic.com/images/actor_unknow.jpg",
name: actress.name,
allNameText,
actressUrl,
lastCheckTime: actress.lastCheckTime || "",
lastPublishTime: actress.lastPublishTime || "",
isStale,
ruleTimeYears: ruleTimeHours / 24 / 365,
remark: actress.remark || "",
editSvg: this.editSvg,
deleteSvg: this.deleteSvg,
btnStyle,
typeLabel,
typeColor,
newVideoCount: actress.newVideoList?.length || 0
}));
}).join("");
$container.html(cardsHtml);
$(".btn-delete-actress").off("click").on("click", (event) => {
event.preventDefault();
const starId = $(event.currentTarget).attr("data-starId");
const actress = sortedActresses.find((item) => item.starId === starId);
utils.q(event, `是否取消收藏 ${actress.name}?`, async () => {
const uncollectUrl = `${await this.getBean("OtherSitePlugin").getJavDbUrl()}/actors/${starId}/uncollect`;
const csrfToken = document.querySelector("meta[name=csrf-token]")?.getAttribute("content") ?? "";
const response = await gmHttp.post(uncollectUrl, null, { "x-csrf-token": csrfToken });
if (response.includes("removeClass")) {
await storageManager.removeFavoriteActress(starId);
this.loadData();
} else {
show.error("移除失败");
clog.error("移除失败,返回值:", response);
}
});
});
$(".btn-edit-actress").off("click").on("click", (event) => {
event.preventDefault();
const starId = $(event.currentTarget).attr("data-starId");
const actress = sortedActresses.find((item) => item.starId === starId);
if (actress) this.editActress(actress);
else show.error(`未找到 starId 为 ${starId} 的女优记录。`);
});
this.renderPagination(totalCount, totalPages);
show.ok("加载完成");
}
async editActress(actress) {
const name = actress.name;
const avatar = actress.avatar;
const remark = actress.remark || "";
const allNameText = Array.isArray(actress.allName) ? actress.allName.join(",") : "";
const newVideoText = Array.isArray(actress.newVideoList) ? actress.newVideoList.join(",") : "";
const starId = actress.starId;
const dialogContent = jsxToString((0, import_jsx_runtime.jsx)(EditActressDialog, {
avatar,
name,
textareaStyle: {
width: "100%",
padding: "8px",
border: "1px solid #ccc",
borderRadius: "4px",
minHeight: "60px",
overflowY: "hidden"
},
allNameText,
actressType: actress.actressType || "",
newVideoText,
remark
}));
layer.open({
type: 1,
title: `编辑女优: ${name} (${starId})`,
area: ["500px", "750px"],
content: dialogContent,
btn: ["保存", "取消"],
success: (_layerEl, layerIndex) => {
const autoHeight = ($textarea) => {
$textarea.css("height", "auto");
$textarea.css("height", $textarea[0].scrollHeight + 15 + "px");
};
$("#edit-actress-avatar").on("input", (event) => {
const val = $(event.currentTarget).val();
$("#edit-avatar-preview").attr("src", val);
});
const $allNameArea = $("#edit-actress-allname");
$allNameArea.on("input", (event) => {
autoHeight($(event.currentTarget));
});
autoHeight($allNameArea);
const $newVideoArea = $("#edit-actress-newvideolist");
$newVideoArea.on("input", (event) => {
autoHeight($(event.currentTarget));
});
autoHeight($newVideoArea);
$("#search-avatar-btn").on("click", async () => {
await this.searchAvatar();
});
$("#select-cdn-btn").on("click", async () => {
const currentIndex = getCurrentCdnSource().index;
const cdnDialogContent = jsxToString((0, import_jsx_runtime.jsx)(CdnSelectDialog, {
sources: GFRIENDS_SOURCES,
currentIndex
}));
layer.open({
type: 1,
title: "选择 CDN 源",
area: ["400px", "auto"],
content: cdnDialogContent,
btn: ["确定", "取消"],
success: (_cdnLayerEl, cdnLayerIndex) => {
utils.setupEscClose(cdnLayerIndex);
},
yes: async (cdnLayerIndex) => {
const selectedValue = $("input[name=\"cdn-source\"]:checked").val();
const selectedIndex = parseInt(selectedValue, 10);
if (selectedIndex !== currentIndex) {
localStorage.setItem(GFRIENDS_CDN_INDEX_KEY, selectedIndex.toString());
clearCache();
try {
await window.filetreeDb.set(FILETREE_DATA_KEY, null);
} catch (error) {
clog.error("清除 IndexedDB 缓存失败:", error);
}
show.ok(`CDN 源已切换为: ${GFRIENDS_SOURCES[selectedIndex].name}`);
layer.close(cdnLayerIndex);
} else layer.close(cdnLayerIndex);
}
});
});
utils.setupEscClose(layerIndex);
},
yes: async (layerIndex) => {
const avatar = $("#edit-actress-avatar").val().trim();
const name = $("#edit-actress-name").val().trim();
const allNameText = $("#edit-actress-allname").val().trim();
const newVideoText = $("#edit-actress-newvideolist").val().trim();
const remark = $("#edit-remark").val().trim();
const actressType = $("#actressType").val();
if (!name) {
show.error("主名称不能为空");
return false;
}
const allNameArray = allNameText.split(/[\uff0c,]/).map((part) => part.trim()).filter((part) => part.length > 0);
const newVideoArray = newVideoText.split(/[\uff0c,]/).map((part) => part.trim()).filter((part) => part.length > 0);
actress.avatar = avatar;
actress.name = name;
actress.allName = allNameArray;
actress.newVideoList = newVideoArray;
actress.actressType = actressType;
actress.remark = remark;
if (await storageManager.updateFavoriteActress(actress)) show.error("修改失败");
else {
this.renderActressCards().then();
show.ok(`女优 ${name} 信息已更新`);
layer.close(layerIndex);
}
}
});
}
renderPagination(totalCount, totalPages) {
const page = this.currentPage;
$("#actress-pagination").html(jsxToString((0, import_jsx_runtime.jsx)(ActressPagination, {
totalCount,
totalPages,
page
})));
$(".pagination-btn").off("click").on("click", (event) => {
if ($(event.currentTarget).is("[disabled]")) return;
const targetPage = parseInt($(event.currentTarget).data("page"));
if (targetPage >= 1 && targetPage <= totalPages && targetPage !== this.currentPage) {
this.currentPage = targetPage;
this.renderActressCards();
}
});
}
async searchAvatar() {
const $nameInput = $("#edit-actress-name");
const $allNameInput = $("#edit-actress-allname");
const nameText = $nameInput.val().trim();
const searchNames = $allNameInput.val().trim().split(/[\uff0c,]/).map((name) => name.trim()).filter((name) => name.length > 0);
if (nameText) searchNames.unshift(nameText);
if (searchNames.length === 0) {
show.error("请先填写女优主名称或别名进行搜索。");
return;
}
const loader = loading("正在搜索头像...");
let avatarUrls = [];
try {
avatarUrls = await loadGfriends(searchNames);
} catch (error) {
show.error(`头像数据加载或搜索失败: ${error.message || error}`);
return;
} finally {
loader.close();
}
if (avatarUrls.length === 0) {
show.error(`未找到与 '${searchNames.join("、")}' 相关的头像。请检查名称。`);
return;
}
const dialogContent = "<style>" + avatar_select_dialog_default + "</style>" + jsxToString((0, import_jsx_runtime.jsx)(AvatarSelectDialog, { avatarUrls }));
let errorCount = 0;
layer.open({
type: 1,
title: `选择女优头像 (${avatarUrls.length} 张)`,
area: utils.getResponsiveArea(["900px", "85%"]),
content: dialogContent,
btn: ["关闭"],
success: (layerEl, layerIndex) => {
const $layer = $(layerEl);
const $images = $layer.find(".gfriends-selectable-img");
const $prompt = $layer.find("#gfriends-prompt");
$images.each((_index, element) => {
const $img = $(element);
const wrapperId = $img.data("wrapper-id");
const $wrapper = $layer.find(`#${wrapperId}`);
const $sizeTag = $layer.find(`.gfriends-size-tag[data-size-for="${wrapperId}"]`);
$img.on("load", () => {
const width = element.naturalWidth;
const height = element.naturalHeight;
$sizeTag.text(`${width} x ${height}`);
});
$img.on("error", () => {
$wrapper.remove();
errorCount++;
const remaining = avatarUrls.length - errorCount;
$prompt.text(`点击图片即可选择(已移除 ${errorCount} 张错误图片,剩余 ${remaining} 张)`);
if (remaining === 0) {
show.error("所有搜索到的头像链接均已失效,无法选择。");
layer.close(layerIndex);
}
});
if (element.complete) if (element.naturalWidth > 0) $img.trigger("load");
else $img.trigger("error");
});
$images.on("click", (event) => {
const $img = $(event.currentTarget);
const url = $img.data("url");
$("#edit-actress-avatar").val(url);
$("#edit-avatar-preview").attr("src", url);
$images.removeClass("is-selected");
$img.addClass("is-selected");
setTimeout(() => {
layer.close(layerIndex);
}, 150);
});
utils.setupEscClose(layerIndex);
}
});
}
};
var LABEL_STYLE = {
display: "block",
marginBottom: "5px",
fontWeight: "bold"
};
var FIELD_ROW_STYLE = { marginBottom: "15px" };
function EditRecordDialog({ carNum, names, status, url, remark, inputStyle, textareaStyle, statusOptions }) {
return (0, import_jsx_runtime.jsxs)("div", {
style: { padding: "20px" },
children: [
(0, import_jsx_runtime.jsxs)("div", {
style: FIELD_ROW_STYLE,
children: [(0, import_jsx_runtime.jsx)("label", {
style: LABEL_STYLE,
children: "番号:"
}), (0, import_jsx_runtime.jsx)("input", {
type: "text",
id: "edit-carNum",
value: carNum,
style: {
...inputStyle,
backgroundColor: "#f0f0f0"
},
readOnly: true
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
style: FIELD_ROW_STYLE,
children: [(0, import_jsx_runtime.jsx)("label", {
style: LABEL_STYLE,
children: "演员 (用空格隔开):"
}), (0, import_jsx_runtime.jsx)("textarea", {
id: "edit-names",
style: textareaStyle,
children: names
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
style: FIELD_ROW_STYLE,
children: [(0, import_jsx_runtime.jsx)("label", {
style: LABEL_STYLE,
children: "状态:"
}), (0, import_jsx_runtime.jsxs)("select", {
id: "edit-status",
style: {
width: "100%",
padding: "10px",
border: "1px solid #ddd"
},
children: [(0, import_jsx_runtime.jsx)("option", {
value: "",
selected: status === "",
children: "-- 请选择 --"
}), statusOptions.map((opt) => (0, import_jsx_runtime.jsx)("option", {
value: opt.value,
selected: status === opt.value,
children: opt.text
}, opt.value))]
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
style: FIELD_ROW_STYLE,
children: [(0, import_jsx_runtime.jsx)("label", {
style: LABEL_STYLE,
children: "链接:"
}), (0, import_jsx_runtime.jsx)("input", {
type: "text",
id: "edit-url",
value: url,
style: inputStyle
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
style: FIELD_ROW_STYLE,
children: [(0, import_jsx_runtime.jsx)("label", {
style: LABEL_STYLE,
children: "备注:"
}), (0, import_jsx_runtime.jsx)("textarea", {
id: "edit-remark",
style: textareaStyle,
children: remark
})]
})
]
});
}
function HistoryActionButtons({ carNum, url, watchedColor, watchedText, favoriteColor, favoriteText, blockColor, blockText }) {
return (0, import_jsx_runtime.jsxs)("div", {
className: "action-btns",
style: {
display: "flex",
gap: "5px",
justifyContent: "center"
},
"data-car-num": carNum,
"data-href": url,
children: [(0, import_jsx_runtime.jsxs)("div", {
className: "sub-btns",
children: [(0, import_jsx_runtime.jsx)("a", {
className: "menu-btn sub-btns-toggle",
style: {
backgroundColor: "#c59d36",
color: "white",
marginBottom: "5px"
},
children: (0, import_jsx_runtime.jsx)("span", { children: "✏️ 变更" })
}), (0, import_jsx_runtime.jsxs)("div", {
className: "sub-btns-menu",
children: [
(0, import_jsx_runtime.jsx)("a", {
className: "menu-btn history-editBtn",
style: {
backgroundColor: "#007bff",
color: "white",
marginBottom: "5px"
},
children: (0, import_jsx_runtime.jsx)("span", { children: "✏️ 编辑" })
}),
(0, import_jsx_runtime.jsx)("a", {
className: "menu-btn history-deleteBtn",
style: {
backgroundColor: "#8c8080",
color: "white",
marginBottom: "5px"
},
children: (0, import_jsx_runtime.jsx)("span", { children: "✂️ 移除" })
}),
(0, import_jsx_runtime.jsx)("a", {
className: "menu-btn history-hasWatchBtn",
style: {
backgroundColor: watchedColor,
marginBottom: "5px"
},
children: watchedText
}),
(0, import_jsx_runtime.jsx)("a", {
className: "menu-btn history-favoriteBtn",
style: {
backgroundColor: favoriteColor,
marginBottom: "5px"
},
children: favoriteText
}),
(0, import_jsx_runtime.jsx)("a", {
className: "menu-btn history-filterBtn",
style: {
backgroundColor: blockColor,
marginBottom: "5px"
},
children: blockText
})
]
})]
}), (0, import_jsx_runtime.jsx)("a", {
className: "menu-btn history-detailBtn",
style: {
backgroundColor: "#3397de",
color: "white",
marginBottom: "5px"
},
children: (0, import_jsx_runtime.jsx)("span", { children: "📄 详情页" })
})]
});
}
function HistoryDialog({ blockedText, favoritedText, watchedText, watchedColor, favoriteColor, favoriteText, blockColor, blockText }) {
return (0, import_jsx_runtime.jsxs)("div", {
style: {
padding: "10px 20px",
height: "100%",
overflow: "hidden"
},
children: [
(0, import_jsx_runtime.jsxs)("div", {
id: "filterBox",
style: {
display: "flex",
gap: "5px"
},
children: [
(0, import_jsx_runtime.jsxs)("select", {
id: "dataType",
style: {
textAlign: "center",
minWidth: "150px"
},
children: [
(0, import_jsx_runtime.jsx)("option", {
value: "all",
selected: true,
children: "所有"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "filter",
children: blockedText
}),
(0, import_jsx_runtime.jsx)("option", {
value: "favorite",
children: favoritedText
}),
(0, import_jsx_runtime.jsx)("option", {
value: "hasWatch",
children: watchedText
})
]
}),
(0, import_jsx_runtime.jsx)("input", {
id: "searchCarNum",
type: "text",
placeholder: "搜索番号|演员",
style: { padding: "4px 5px" }
}),
(0, import_jsx_runtime.jsx)("a", {
id: "clearSearchbtn",
className: "a-info",
style: { marginLeft: "0" },
children: "重置"
})
]
}),
(0, import_jsx_runtime.jsxs)("div", {
id: "allSelectBox",
style: {
marginTop: "8px",
display: "none"
},
children: [
(0, import_jsx_runtime.jsx)("a", {
className: "menu-btn multiple-history-deleteBtn",
style: {
backgroundColor: "#8c8080",
color: "white",
marginBottom: "5px"
},
children: (0, import_jsx_runtime.jsx)("span", { children: "✂️ 移除" })
}),
(0, import_jsx_runtime.jsx)("a", {
className: "menu-btn multiple-history-hasWatchBtn",
style: {
backgroundColor: watchedColor,
marginBottom: "5px"
},
children: watchedText
}),
(0, import_jsx_runtime.jsx)("a", {
className: "menu-btn multiple-history-favoriteBtn",
style: {
backgroundColor: favoriteColor,
marginBottom: "5px"
},
children: favoriteText
}),
(0, import_jsx_runtime.jsx)("a", {
className: "menu-btn multiple-history-filterBtn",
style: {
backgroundColor: blockColor,
marginBottom: "5px"
},
children: blockText
})
]
}),
(0, import_jsx_runtime.jsx)("div", {
id: "table-container",
style: {
height: "calc(100% - 50px)",
overflowX: "hidden"
}
})
]
});
}
function HistoryNavButton({ variant }) {
switch (variant) {
case "desktop": return (0, import_jsx_runtime.jsx)("div", {
className: "navbar-item has-sub-btns is-hoverable historyBtnBox",
children: (0, import_jsx_runtime.jsx)("a", {
id: "historyBtn",
className: "navbar-link nav-btn",
style: {
color: "#aade66 !important",
paddingRight: "15px !important"
},
children: "鉴定记录"
})
});
case "mini": return (0, import_jsx_runtime.jsx)("div", {
className: "navbar-item miniHistoryBtnBox",
children: (0, import_jsx_runtime.jsx)("a", {
id: "miniHistoryBtn",
className: "navbar-link nav-btn",
style: {
color: "#aade66 !important",
paddingLeft: "0 !important",
paddingRight: "0 !important"
},
children: "鉴定记录"
})
});
default: return null;
}
}
function HistorySourceCell({ text, color }) {
return (0, import_jsx_runtime.jsx)("span", {
style: { color },
children: text
});
}
function HistoryStatusCell({ text, color }) {
return (0, import_jsx_runtime.jsx)("span", {
style: { color },
children: text
});
}
var history_plugin_default = "/* 下拉菜单容器(相对定位) */\n.sub-btns {\n position: relative;\n display: inline-block;\n}\n\n/* 下拉菜单内容(默认隐藏) */\n.sub-btns-menu {\n display: none;\n position: absolute;\n right: 80px;\n top: -10px;\n background: white;\n padding: 10px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n z-index: 100;\n border-radius: 4px;\n overflow: hidden;\n}\n\n/* 点击后显示菜单(JS 控制) */\n.sub-btns-menu.show {\n display: flex !important;\n flex-direction: column;\n}\n\n.table-link-param {\n cursor: pointer;\n}\n";
var HistoryPlugin = class extends BasePlugin {
tableObj = null;
allCount = 0;
filterCount = 0;
favoriteCount = 0;
hasWatchCount = 0;
constructor() {
super();
}
getName() {
return "HistoryPlugin";
}
async initCss() {
return history_plugin_default;
}
handleResize() {
if ($(".navbar-search").is(":hidden")) {
$(".historyBtnBox").show();
$(".miniHistoryBtnBox").hide();
} else {
$(".historyBtnBox").hide();
$(".miniHistoryBtnBox").show();
}
}
async handle() {
if (isJavdbSite) {
$(".navbar-end").prepend(jsxToString((0, import_jsx_runtime.jsx)(HistoryNavButton, { variant: "desktop" })));
$(".navbar-search").css("margin-left", "0").before(jsxToString((0, import_jsx_runtime.jsx)(HistoryNavButton, { variant: "mini" })));
this.handleResize();
$(window).resize(() => {
this.handleResize();
});
$("#historyBtn,#miniHistoryBtn").on("click", () => this.openHistory());
}
this.bindClick();
}
openHistory() {
layer.open({
type: 1,
title: "鉴定记录",
content: jsxToString((0, import_jsx_runtime.jsx)(HistoryDialog, {
blockedText: BLOCKED_TEXT,
favoritedText: FAVORITED_TEXT,
watchedText: WATCHED_TEXT,
watchedColor: WATCHED_COLOR,
favoriteColor: FAVORITE_COLOR,
favoriteText: FAVORITE_TEXT,
blockColor: BLOCK_COLOR,
blockText: BLOCK_TEXT
})),
scrollbar: false,
shadeClose: true,
area: utils.getResponsiveArea(["70%", "90%"]),
anim: -1,
success: async () => {
await this.loadTableData();
$(".layui-layer-content").on("click", "#clearSearchbtn", async () => {
$("#searchCarNum").val("");
$("#dataType").val("all");
await this.reloadTable();
$("#allSelectBox").hide();
}).on("focusout keydown", "#searchCarNum", async (event) => {
if (event.type === "focusout" || event.key === "Enter") {
if (event.key === "Enter") event.preventDefault();
if (event.type === "keydown" && event.key !== "Enter") return;
await this.reloadTable();
}
}).on("click", ".table-link-param", async (event) => {
const link = $(event.currentTarget);
$("#searchCarNum").val(link.text());
await this.reloadTable();
}).on("change", "#dataType", async () => {
await this.reloadTable();
});
},
end: () => {
if (this.tableObj) {
this.tableObj.destroy();
this.tableObj = null;
}
refresh();
}
});
}
async reloadTable() {
this.tableObj.deselectRow();
this.tableObj.setPage(1);
}
bindClick() {
document.addEventListener("click", function(event) {
const target = event.target;
if (target.closest(".sub-btns-toggle")) {
const menu = target.closest(".sub-btns").querySelector(".sub-btns-menu");
document.querySelectorAll(".sub-btns-menu.show").forEach((el) => {
if (el !== menu) el.classList.remove("show");
});
menu.classList.toggle("show");
} else document.querySelectorAll(".sub-btns-menu.show").forEach((el) => {
el.classList.remove("show");
});
});
$(document).on("click", ".history-deleteBtn, .history-filterBtn, .history-favoriteBtn, .history-hasWatchBtn, .history-detailBtn", (event) => {
event.preventDefault();
event.stopPropagation();
const btn = $(event.currentTarget);
const actionBtns = btn.closest(".action-btns");
const carNum = actionBtns.attr("data-car-num");
const href = actionBtns.attr("data-href");
const applyAction = async (actionType) => {
await storageManager.saveCar({
carNum,
url: href,
names: null,
actionType
});
refresh();
await this.reloadTable();
};
if (btn.hasClass("history-filterBtn")) utils.q(event, `是否屏蔽${carNum}?`, () => applyAction(FILTER_ACTION));
else if (btn.hasClass("history-favoriteBtn")) applyAction(FAVORITE_ACTION).then();
else if (btn.hasClass("history-hasWatchBtn")) applyAction(HAS_WATCH_ACTION).then();
else if (btn.hasClass("history-deleteBtn")) this.handleDelete(event, carNum);
else if (btn.hasClass("history-detailBtn")) this.handleClickDetail(event, {
carNum,
url: href
}).then();
});
$(document).on("click", ".multiple-history-deleteBtn, .multiple-history-filterBtn, .multiple-history-favoriteBtn, .multiple-history-hasWatchBtn", (event) => {
event.preventDefault();
event.stopPropagation();
const btn = $(event.currentTarget);
const selectedRows = this.tableObj.getSelectedData();
let actionLabel = "";
let actionType = "";
if (btn.hasClass("multiple-history-filterBtn")) {
actionLabel = "屏蔽";
actionType = FILTER_ACTION;
} else if (btn.hasClass("multiple-history-favoriteBtn")) {
actionLabel = "收藏";
actionType = FAVORITE_ACTION;
} else if (btn.hasClass("multiple-history-hasWatchBtn")) {
actionLabel = "已观看";
actionType = HAS_WATCH_ACTION;
} else if (btn.hasClass("multiple-history-deleteBtn")) {
actionLabel = "移除";
actionType = "delete";
}
utils.q(event, `当前已勾选${selectedRows.length}条数据, 是否全标记为 ${actionLabel}?`, async () => {
const loader = loading();
try {
if (actionType === "delete") {
const carNums = selectedRows.map((row) => row.carNum);
const removed = await storageManager.batchRemoveCars(carNums);
if (removed > 0) show.ok(`已成功删除 ${removed} 个番号`);
else if (removed === false) show.error("提供的番号中没有一个存在于列表中。");
} else {
const updates = JSON.parse(JSON.stringify(selectedRows));
updates.forEach((item) => {
item.actionType = actionType;
});
await storageManager.saveCarList(updates);
show.ok("操作成功");
}
this.tableObj.deselectRow();
this.reloadTable().then();
} catch (err) {
console.error(err);
} finally {
loader.close();
}
});
});
}
async getDataList(page, size, sort) {
const carList = await storageManager.getCarList();
this.allCount = carList.length;
this.filterCount = 0;
this.favoriteCount = 0;
this.hasWatchCount = 0;
carList.forEach((car) => {
switch (car.status) {
case FILTER_ACTION:
this.filterCount++;
break;
case FAVORITE_ACTION:
this.favoriteCount++;
break;
case HAS_WATCH_ACTION: this.hasWatchCount++;
}
});
$("#dataType option[value=\"all\"]").text(`所有 (${this.allCount})`);
$("#dataType option[value=\"filter\"]").text(`${BLOCKED_TEXT} (${this.filterCount})`);
$("#dataType option[value=\"favorite\"]").text(`${FAVORITED_TEXT} (${this.favoriteCount})`);
$("#dataType option[value=\"hasWatch\"]").text(`${WATCHED_TEXT} (${this.hasWatchCount})`);
const selectedType = $("#dataType").val();
let filtered = selectedType === "all" ? carList : carList.filter((car) => car.status === selectedType);
const searchText = $("#searchCarNum").val().trim();
if (searchText) {
const normalizedSearch = searchText.toLowerCase().replace("-c", "").replace("-uc", "").replace("-4k", "");
filtered = filtered.filter((row) => {
const matchCar = row.carNum.toLowerCase().includes(normalizedSearch);
const matchName = (row.names ? row.names : "").toLowerCase().includes(normalizedSearch);
return matchCar || matchName;
});
}
if (sort && sort.length > 0) {
const sortConfig = sort[0];
const field = sortConfig.field;
const dir = sortConfig.dir;
filtered.sort((rowA, rowB) => {
const valA = rowA[field];
const valB = rowB[field];
const isEmptyA = valA == null || valA === "";
const isEmptyB = valB == null || valB === "";
if (isEmptyA && !isEmptyB) return 1;
else if (!isEmptyA && isEmptyB) return -1;
else if (isEmptyA && isEmptyB) return 0;
else if (valA < valB) if (dir === "asc") return -1;
else return 1;
else if (valA > valB) if (dir === "asc") return 1;
else return -1;
else return 0;
});
}
const totalCount = filtered.length;
const maxPage = Math.ceil(totalCount / size);
const start = (page - 1) * size;
const end = start + size;
filtered = filtered.slice(start, end);
return {
maxPage,
dataList: filtered,
totalCount
};
}
async loadTableData() {
this.tableObj = new Tabulator("#table-container", {
layout: "fitColumns",
placeholder: "暂无数据",
virtualDom: true,
pagination: true,
paginationMode: "remote",
sortMode: "remote",
ajaxURL: "queryRealm",
dataLoader: false,
ajaxRequestFunc: async (_url, _config, params) => {
const page = params.page;
const size = params.size;
const sort = params.sort;
return await this.getDataList(page, size, sort);
},
dataReceiveParams: {
last_page: "maxPage",
last_row: "totalCount",
data: "dataList"
},
paginationSize: 50,
paginationSizeSelector: [
50,
100,
1e3,
99999
],
paginationCounter: (_pageNumber, _pageSize, _totalPages, recordCount, _data) => `共 ${recordCount} 条记录`,
responsiveLayout: "collapse",
responsiveLayoutCollapse: true,
columnDefaults: {
headerHozAlign: "center",
hozAlign: "center"
},
selectableRowsPersistence: false,
index: "carNum",
columns: [
{
formatter: "rowSelection",
titleFormatter: "rowSelection",
hozAlign: "center",
headerSort: false,
responsive: 0,
width: 40,
titleFormatterParams: { rowRange: "active" },
cellClick: (_event, cell) => {
cell.getRow().toggleSelect();
}
},
{
title: "番号",
field: "carNum",
width: 120,
sorter: "string",
responsive: 0,
formatter: (cell, _formatterParams, _onRendered) => {
const carNum = cell.getData().carNum;
const dashIndex = carNum.indexOf("-");
if (dashIndex === -1) return carNum;
return `<a class="table-link-param">${carNum.substring(0, dashIndex + 1)}</a>${carNum.substring(dashIndex + 1)}`;
}
},
{
title: "演员",
field: "names",
minWidth: 200,
sorter: "string",
responsive: 5,
headerSort: true,
formatter: (cell, _formatterParams, _onRendered) => (cell.getData().names || "").split(" ").filter((part) => part.trim() !== "").map((part) => `<a class="table-link-param">${part}</a>`).join(" ")
},
{
title: "创建时间",
field: "createDate",
width: 170,
sorter: "string",
responsive: 4
},
{
title: "修改时间",
field: "updateDate",
width: 170,
sorter: "string",
responsive: 4
},
{
title: "发行时间",
field: "publishTime",
width: 170,
sorter: "string",
responsive: 4
},
{
title: "来源",
field: "url",
width: 80,
sorter: "string",
responsive: 5,
hozAlign: "left",
formatter: (cell, _formatterParams, _onRendered) => {
let url = cell.getData().url;
if (url) if (url.includes("javdb")) return jsxToString((0, import_jsx_runtime.jsx)(HistorySourceCell, {
text: "Javdb",
color: "#d34f9e"
}));
else return jsxToString((0, import_jsx_runtime.jsx)(HistorySourceCell, {
text: url,
color: "#050505"
}));
else return "";
}
},
{
title: "状态",
field: "status",
width: 100,
sorter: "string",
responsive: 1,
headerSort: false,
formatter: (cell, _formatterParams, _onRendered) => {
const status = cell.getData().status;
let color = "";
let text = "";
switch (status) {
case "filter":
color = BLOCK_COLOR;
text = BLOCK_TEXT;
break;
case "favorite":
color = FAVORITE_COLOR;
text = FAVORITE_TEXT;
break;
case "hasWatch":
color = WATCHED_COLOR;
text = WATCHED_TEXT;
break;
default: text = status;
}
return jsxToString((0, import_jsx_runtime.jsx)(HistoryStatusCell, {
text,
color
}));
}
},
{
title: "备注",
field: "remark",
width: 100,
sorter: "string",
responsive: 6
},
{
title: "操作",
sorter: "string",
minWidth: 150,
cssClass: "action-cell-dropdown",
responsive: 0,
headerSort: false,
formatter: (cell, _formatterParams, onRendered) => {
const data = cell.getData();
onRendered(() => {
const editBtn = cell.getElement().querySelector(".history-editBtn");
if (editBtn != null) editBtn.addEventListener("click", () => {
this.editRecord(data);
});
});
return jsxToString((0, import_jsx_runtime.jsx)(HistoryActionButtons, {
carNum: data.carNum,
url: data.url || "",
watchedColor: WATCHED_COLOR,
watchedText: WATCHED_TEXT,
favoriteColor: FAVORITE_COLOR,
favoriteText: FAVORITE_TEXT,
blockColor: BLOCK_COLOR,
blockText: BLOCK_TEXT
}));
}
}
],
initialSort: [{
column: "updateDate",
dir: "desc"
}],
locale: "zh-cn",
langs: { "zh-cn": { pagination: {
first: "首页",
first_title: "首页",
last: "尾页",
last_title: "尾页",
prev: "上一页",
prev_title: "上一页",
next: "下一页",
next_title: "下一页",
all: "所有",
page_size: "每页行数"
} } }
});
this.tableObj.on("rowSelectionChanged", (rows, _deselectedRows, _selected, _deselected) => {
const selectBox = $("#allSelectBox");
const filterBox = $("#filterBox");
if (rows && rows.length > 0) {
filterBox.hide();
selectBox.show();
} else {
filterBox.show();
selectBox.hide();
}
});
this.tableObj.on("rowDblClick", (_event, row) => {
row.toggleSelect();
});
this.tableObj.on("tableBuilt", async () => {});
}
handleDelete(event, carNum) {
utils.q(event, `是否移除${carNum}?`, async () => {
await storageManager.removeCar(carNum);
this.getBean("ListPagePlugin").showCarNumBox(carNum);
this.reloadTable().then();
});
}
async handleClickDetail(event, carInfo) {
if (isJavdbSite) if (carInfo.carNum.includes("FC2-")) {
const movieId = this.parseMovieId(carInfo.url);
this.getBean("Fc2Plugin")?.openFc2Dialog(movieId, carInfo.carNum, carInfo.url);
} else {
if (!carInfo.url) {
window.open("/search?q=" + carInfo.carNum, "_blank");
return;
}
utils.openPage(carInfo.url, carInfo.carNum, false, event);
}
}
async editRecord(record) {
const carNum = record.carNum;
const names = record.names || "";
const url = record.url || "";
const status = record.status;
const remark = record.remark || "";
const textareaStyle = {
width: "100%",
padding: "8px",
border: "1px solid #ccc",
borderRadius: "4px",
minHeight: "60px",
overflowY: "hidden"
};
const inputStyle = {
width: "100%",
padding: "8px",
border: "1px solid #ccc",
borderRadius: "4px"
};
const statusOptions = [
{
value: FILTER_ACTION,
text: BLOCK_TEXT
},
{
value: FAVORITE_ACTION,
text: FAVORITE_TEXT
},
{
value: HAS_WATCH_ACTION,
text: WATCHED_TEXT
}
];
console.log(statusOptions);
layer.open({
type: 1,
title: `编辑记录: ${carNum}`,
area: ["500px", "650px"],
content: jsxToString((0, import_jsx_runtime.jsx)(EditRecordDialog, {
carNum,
names,
status,
url,
remark,
inputStyle,
textareaStyle,
statusOptions
})),
btn: ["保存", "取消"],
success: () => {
const autoResize = (el) => {
el.css("height", "auto");
el.css("height", el[0].scrollHeight + 15 + "px");
};
const namesInput = $("#edit-names");
namesInput.on("input", (event) => autoResize($(event.currentTarget)));
autoResize(namesInput);
const remarkInput = $("#edit-remark");
remarkInput.on("input", (event) => autoResize($(event.currentTarget)));
autoResize(remarkInput);
},
yes: async (index) => {
const names = $("#edit-names").val().trim();
const status = $("#edit-status").val();
const url = $("#edit-url").val().trim();
const remark = $("#edit-remark").val().trim();
const updated = {
...record,
names,
actionType: status,
url,
remark
};
await storageManager.updateCarInfo(updated);
this.tableObj.setData();
layer.close(index);
}
});
}
};
var VIDEO_QUALITY_LIST = [
{
id: "video-mhb",
quality: "dmb_w",
text: "旧视频源-中画质宽版 (404p)",
canSelect: false
},
{
id: "video-mhb",
quality: "sm_s",
text: "旧视频源-低画质 (240p)",
canSelect: false
},
{
id: "video-mhb",
quality: "dm_s",
text: "旧视频源-中画质 (360p)",
canSelect: false
},
{
id: "video-mhb",
quality: "dmb_s",
text: "旧视频源-中画质 (480p)",
canSelect: false
},
{
id: "video-mhb",
quality: "mhb_w",
text: "旧视频源-高画质宽版 (404p)",
canSelect: false
},
{
id: "video-mmb",
quality: "mmb",
text: "中画质 (432p)",
canSelect: true
},
{
id: "video-mhb",
quality: "mhb",
text: "高画质 (576p)",
canSelect: true
},
{
id: "video-hmb",
quality: "hmb",
text: "HD (720p)",
canSelect: true
},
{
id: "video-hhb",
quality: "hhb",
text: "FullHD (1080p)",
canSelect: true
},
{
id: "video-hhbs",
quality: "hhbs",
text: "FullHD (1080p60fps)",
canSelect: true
},
{
id: "video-4k",
quality: "4k",
text: "4K (2160p)",
canSelect: true
},
{
id: "video-4ks",
quality: "4ks",
text: "4K (2160p60fps)",
canSelect: true
}
];
var image_preview_default = ".image-hover-preview {\n position: fixed;\n display: none;\n z-index: 9999999999; /*__Z_INDEX__*/\n border-radius: 4px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n overflow: hidden;\n pointer-events: none;\n opacity: 0;\n transition: opacity 0.2s ease; /*__TRANSITION__*/\n background-color: #fff;\n}\n\n.image-hover-preview.active {\n opacity: 1;\n}\n\n.image-hover-preview img {\n max-width: 1000px; /*__MAX_WIDTH__*/\n max-height: 1000px; /*__MAX_HEIGHT__*/\n display: block;\n object-fit: contain;\n}\n\n.image-hover-preview::after {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.03);\n pointer-events: none;\n}\n\n.image-hover-preview.loading::before {\n content: '加载中...';\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n color: #666;\n font-size: 14px;\n}\n";
var errorStyle = {
padding: "10px",
color: "#f00"
};
function ImagePreviewError() {
return (0, import_jsx_runtime.jsx)("div", {
style: errorStyle,
children: "图片加载失败"
});
}
function ImagePreviewImg({ src }) {
return (0, import_jsx_runtime.jsx)("img", {
src,
alt: "预览图"
});
}
var ImagePreview = class {
config;
preview = null;
currentTarget = null;
timer = null;
imgElement = null;
boundElements = new WeakSet();
constructor(options = {}) {
this.config = {
selector: ".hover-preview",
dataAttribute: "data-full",
maxWidth: 1e3,
maxHeight: 1e3,
offsetX: 20,
offsetY: 20,
zIndex: 9999999999,
transition: .2,
autoAdjustPosition: true,
...options
};
this.init();
}
init() {
this.injectStyles();
this.createPreviewElement();
this.bindEvents();
}
injectStyles() {
injectCss(image_preview_default.replace("9999999999; /*__Z_INDEX__*/", `${this.config.zIndex}; /*__Z_INDEX__*/`).replace("0.2s ease; /*__TRANSITION__*/", `${this.config.transition}s ease; /*__TRANSITION__*/`).replace("1000px; /*__MAX_WIDTH__*/", `${this.config.maxWidth}px; /*__MAX_WIDTH__*/`).replace("1000px; /*__MAX_HEIGHT__*/", `${this.config.maxHeight}px; /*__MAX_HEIGHT__*/`));
}
createPreviewElement() {
this.preview = document.createElement("div");
this.preview.className = "image-hover-preview";
document.body.appendChild(this.preview);
}
bindEvents() {
document.querySelectorAll(this.config.selector).forEach((element) => {
if (!this.boundElements.has(element)) {
element.addEventListener("mouseenter", (event) => this.handleMouseEnter(event));
element.addEventListener("mouseleave", (event) => this.handleMouseLeave(event));
element.addEventListener("mousemove", (event) => this.handleMouseMove(event));
this.boundElements.add(element);
}
});
}
handleMouseEnter(event) {
clearTimeout(this.timer);
const target = event.currentTarget;
this.currentTarget = target;
const imgSrc = target.getAttribute(this.config.dataAttribute) || target.src;
if (!imgSrc) return;
const preview = this.preview;
preview.innerHTML = "";
preview.classList.add("loading");
preview.style.display = "block";
preview.classList.remove("active");
const img = new Image();
img.onload = () => {
preview.classList.remove("loading");
preview.innerHTML = jsxToString((0, import_jsx_runtime.jsx)(ImagePreviewImg, { src: imgSrc }));
this.imgElement = preview.querySelector("img");
const { width, height } = this.calculateImageSize(img);
preview.style.width = `${width}px`;
preview.style.height = `${height}px`;
preview.offsetHeight;
preview.classList.add("active");
this.handleMouseMove(event);
};
img.onerror = () => {
preview.classList.remove("loading");
preview.innerHTML = jsxToString((0, import_jsx_runtime.jsx)(ImagePreviewError, {}));
};
img.src = imgSrc;
}
calculateImageSize(img) {
let width = img.naturalWidth;
let height = img.naturalHeight;
if (width > this.config.maxWidth || height > this.config.maxHeight) {
const scale = Math.min(this.config.maxWidth / width, this.config.maxHeight / height);
width *= scale;
height *= scale;
}
return {
width,
height
};
}
handleMouseMove(event) {
const preview = this.preview;
if (!this.currentTarget || !preview.classList.contains("active")) return;
let { offsetX, offsetY } = this.config;
let left = event.clientX + offsetX;
let top = event.clientY + offsetY;
if (this.config.autoAdjustPosition) {
const previewWidth = preview.offsetWidth;
const previewHeight = preview.offsetHeight;
if (left + previewWidth > window.innerWidth) left = event.clientX - previewWidth - offsetX;
if (top + previewHeight > window.innerHeight) top = event.clientY - previewHeight - offsetY;
left = Math.max(0, left);
top = Math.max(0, top);
}
preview.style.left = `${left}px`;
preview.style.top = `${top}px`;
}
handleMouseLeave(_event) {
const preview = this.preview;
preview.classList.remove("active");
preview.style.display = "none";
this.currentTarget = null;
this.imgElement = null;
}
destroy() {
document.querySelectorAll(this.config.selector).forEach((element) => {
if (this.boundElements.has(element)) {
element.removeEventListener("mouseenter", this.handleMouseEnter);
element.removeEventListener("mouseleave", this.handleMouseLeave);
element.removeEventListener("mousemove", this.handleMouseMove);
this.boundElements.delete(element);
}
});
const preview = this.preview;
if (preview && preview.parentNode) preview.parentNode.removeChild(preview);
}
};
var setting_plugin_default = "__CSS_TEXT__ .nav-btn::after {\n content: none !important;\n}\n\n#cache-data-display pre {\n font-family: Consolas, Monaco, 'Andale Mono', monospace;\n white-space: pre-wrap;\n word-wrap: break-word;\n line-height: 1.5;\n color: #333;\n border: 1px solid #ddd;\n}\n\n.cache-item {\n transition: all 0.2s ease;\n}\n.cache-item:hover {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n transform: translateY(-2px);\n}\n\n.tooltip-icon {\n display: inline-block;\n width: 16px;\n height: 16px;\n line-height: 16px;\n text-align: center;\n border-radius: 50%;\n background-color: #ccc;\n color: white;\n font-size: 12px;\n margin-right: 5px;\n cursor: help;\n}\n.setting-item {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n margin-bottom: 3px;\n padding: 3px;\n /*border: 1px solid #ddd;\n border-radius: 5px;*/\n}\n.simple-setting .setting-item {\n align-items: center;\n}\n.setting-label {\n font-size: 14px;\n min-width: 160px;\n font-weight: bold;\n margin-right: 10px;\n}\n.form-content {\n max-width: 160px;\n min-width: 160px;\n}\n.form-content * {\n width: 100%;\n padding: 5px;\n margin-right: 10px;\n text-align: center;\n}\n\n.keyword-label {\n display: inline-flex;\n align-items: center;\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 14px;\n position: relative;\n margin-left: 8px;\n margin-bottom: 5px;\n}\n.keyword-remove {\n margin-left: 6px;\n cursor: pointer;\n font-size: 12px;\n line-height: 1;\n}\n.keyword-input {\n padding: 6px 12px;\n border: 1px solid #ccc;\n border-radius: 4px;\n font-size: 14px;\n float: right;\n}\n.add-tag-btn {\n padding: 6px 12px;\n background-color: #e2e8f0;\n color: #334155;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 14px;\n margin-left: 8px;\n float: right;\n}\n.add-tag-btn:hover {\n background-color: #cbd5e1;\n}\n.tag-box {\n margin-top: 15px;\n}\n\n#saveBtn,\n#moreBtn,\n#helpBtn,\n#clean-all {\n padding: 8px 20px;\n background-color: #4caf50;\n color: white;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 16px;\n margin-top: 10px;\n}\n#saveBtn:hover {\n background-color: #45a049;\n}\n#moreBtn {\n background-color: #5cb85c;\n color: white;\n}\n#moreBtn:hover {\n background-color: #4cae4c;\n}\n#helpBtn {\n background-color: #e67e22;\n color: white;\n}\n#helpBtn:hover {\n background-color: #d35400;\n}\n.simple-setting,\n.mini-simple-setting {\n display: none;\n background: rgba(255, 255, 255, 1);\n position: absolute;\n top: __SIMPLE_SETTING_TOP__;\n right: __SIMPLE_SETTING_RIGHT__;\n z-index: 1000;\n border: 1px solid #ddd;\n border-radius: 4px;\n box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);\n padding: 0;\n margin-top: 5px; /* 稍微拉开一点距离 */\n color: #333;\n}\n\n.mini-switch {\n appearance: none;\n -webkit-appearance: none;\n width: 40px;\n height: 20px;\n background: #e0e0e0;\n border-radius: 20px;\n position: relative;\n cursor: pointer;\n outline: none;\n /*transition: all 0.2s ease;*/\n}\n\n.mini-switch:checked {\n background: #4caf50;\n}\n\n.mini-switch::before {\n content: '';\n position: absolute;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: white;\n top: 2px;\n left: 2px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n /*transition: all 0.2s ease;*/\n}\n\n.mini-switch:checked::before {\n left: calc(100% - 18px);\n}\n\n.side-menu-item {\n padding: 10px 14px;\n cursor: pointer;\n color: #333;\n border-left: 3px solid transparent;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n gap: 5px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: 14px;\n}\n\n.side-menu-item .icon {\n height: 24px;\n width: 24px;\n}\n\n.side-menu-item:hover {\n background-color: #e9e9e9;\n}\n\n.side-menu-item.active {\n background-color: #e0e0e0;\n border-left: 3px solid #5d87c2;\n font-weight: bold;\n}\n\n.content-panel {\n display: none;\n margin-top: 20px;\n padding: 0 10px 10px 0;\n height: 100%;\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n.content-panel.active {\n display: block;\n}\n\ninput[type='checkbox']:disabled {\n opacity: 0.6;\n cursor: default !important;\n}\n";
var help_dialog_default = ".help-container {\n font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n color: #333;\n padding: 15px;\n max-height: 100%;\n overflow-y: auto;\n}\n\n.help-section {\n margin-bottom: 25px;\n}\n\n.help-section summary {\n font-size: 18px;\n color: #3498db;\n margin-bottom: 12px;\n cursor: pointer;\n}\n\n.help-content {\n background-color: #f9f9f9;\n border-radius: 5px;\n padding: 15px;\n border-left: 4px solid #3498db;\n}\n\n.help-content p {\n line-height: 1.6;\n margin-bottom: 10px;\n}\n.help-section img {\n max-width: 100%;\n height: auto;\n border: 1px solid #ddd;\n border-radius: 4px;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n}\n";
var back_to_top_button_default = "#jhs-back-to-top {\n position: fixed;\n bottom: 40px;\n right: 40px;\n width: 44px;\n height: 44px;\n background-color: rgba(30, 30, 30, 0.9);\n backdrop-filter: blur(4px);\n color: #e0e0e0;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: 9999;\n opacity: 0;\n visibility: hidden;\n transform: translateY(20px) scale(0.9);\n transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n border: 1px solid rgba(255, 255, 255, 0.05);\n user-select: none;\n}\n#jhs-back-to-top:hover {\n background-color: #ff8400;\n color: #fff;\n transform: translateY(0) scale(1);\n box-shadow: 0 8px 20px rgba(255, 132, 0, 0.3);\n border-color: #ff8400;\n}\n#jhs-back-to-top.show {\n opacity: 1;\n visibility: visible;\n transform: translateY(0) scale(1);\n}\n#jhs-back-to-top svg {\n width: 22px;\n height: 22px;\n fill: currentColor;\n stroke: currentColor;\n stroke-width: 0;\n}\n";
var setting_image_mode_vertical_default = ".cover {\n min-height: 350px !important;\n overflow: hidden !important;\n padding-top: 142% !important;\n}\n\n.cover img {\n object-fit: cover !important;\n object-position: 100% 50% !important; /*__OBJECT_POSITION__*/\n}\n\n/* bus的 */\n.masonry .movie-box img {\n min-height: 500px !important;\n object-fit: cover !important;\n object-position: top right;\n}\n";
var setting_image_mode_horizontal_default = ".cover {\n min-height: auto !important;\n padding-top: 67% !important;\n}\n.cover img {\n object-fit: contain !important;\n object-position: 50% 50% !important;\n}\n\n/* bus的 */\n.masonry .movie-box img {\n min-height: auto !important;\n object-fit: contain !important;\n object-position: top;\n}\n";
var HR_STYLE$1 = {
border: 0,
height: "1px",
margin: "20px 0",
backgroundImage: "linear-gradient(to right, rgba(0,0,0,0), rgba(159,137,137,0.75), rgba(0,0,0,0))"
};
function SettingDialog({ panelName, cacheItemsHtml, qualityOptionsHtml, isJavdbSite, blockText, favoriteText, watchedText }) {
return (0, import_jsx_runtime.jsxs)("div", {
style: {
display: "flex",
height: "100%"
},
children: [(0, import_jsx_runtime.jsxs)("div", {
style: {
width: "170px",
flexShrink: 0,
padding: "15px 0",
background: "#f5f5f5",
borderRight: "1px solid #ddd",
overflowY: "auto"
},
children: [
(0, import_jsx_runtime.jsx)("div", {
className: `side-menu-item ${panelName === "backup-panel" ? "active" : ""}`,
"data-panel": "backup-panel",
children: "💾 数据备份"
}),
(0, import_jsx_runtime.jsx)("div", {
className: `side-menu-item ${panelName === "base-panel" ? "active" : ""}`,
"data-panel": "base-panel",
children: "⚙️ 基础配置"
}),
(0, import_jsx_runtime.jsx)("div", {
className: `side-menu-item ${panelName === "filter-panel" ? "active" : ""}`,
"data-panel": "filter-panel",
children: "🚫 屏蔽配置"
}),
(0, import_jsx_runtime.jsx)("div", {
className: `side-menu-item ${panelName === "domain-panel" ? "active" : ""}`,
"data-panel": "domain-panel",
title: "第三方视频资源域名配置",
children: "🌐 外部网站"
}),
(0, import_jsx_runtime.jsx)("div", {
className: `side-menu-item ${panelName === "hotkey-panel" ? "active" : ""}`,
"data-panel": "hotkey-panel",
children: "⌨️ 快捷键配置"
}),
(0, import_jsx_runtime.jsx)("div", {
className: `side-menu-item ${panelName === "cache-panel" ? "active" : ""}`,
"data-panel": "cache-panel",
children: "🧹 缓存管理"
}),
(0, import_jsx_runtime.jsx)("div", {
className: `side-menu-item ${panelName === "vlt-panel" ? "active" : ""}`,
"data-panel": "vlt-panel",
children: "📋 收藏清单关系"
}),
(0, import_jsx_runtime.jsx)("div", {
className: `side-menu-item ${panelName === "missav-panel" ? "active" : ""}`,
"data-panel": "missav-panel",
children: "🎬 MissAV 同步"
})
]
}), (0, import_jsx_runtime.jsxs)("div", {
style: {
flex: 1,
display: "flex",
flexDirection: "column",
height: "100%"
},
children: [(0, import_jsx_runtime.jsxs)("div", {
style: {
flex: 1,
margin: "0 10px",
paddingBottom: "20px",
overflow: "hidden"
},
children: [
(0, import_jsx_runtime.jsxs)("div", {
id: "backup-panel",
className: "content-panel",
style: { display: panelName === "backup-panel" ? "block" : "none" },
children: [
(0, import_jsx_runtime.jsxs)("div", {
style: { marginBottom: "20px" },
children: [
(0, import_jsx_runtime.jsx)("a", {
id: "importBtn",
className: "menu-btn",
style: { backgroundColor: "#d25a88" },
children: (0, import_jsx_runtime.jsx)("span", { children: "导入数据" })
}),
" ",
(0, import_jsx_runtime.jsx)("a", {
id: "exportBtn",
className: "menu-btn",
style: { backgroundColor: "#85d0a3" },
children: (0, import_jsx_runtime.jsx)("span", { children: "导出数据" })
})
]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "WebDav备份"
}), (0, import_jsx_runtime.jsxs)("div", { children: [
(0, import_jsx_runtime.jsx)("a", {
id: "webdavBackupListBtn",
className: "menu-btn",
style: { backgroundColor: "#5d87c2" },
children: (0, import_jsx_runtime.jsx)("span", { children: "查看备份" })
}),
" ",
(0, import_jsx_runtime.jsx)("a", {
id: "webdavBackupBtn",
className: "menu-btn",
style: { backgroundColor: "#64bb69" },
children: (0, import_jsx_runtime.jsx)("span", { children: "备份数据" })
})
] })]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "服务地址:"
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", { id: "webDavUrl" })
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "用户名:"
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", { id: "webDavUsername" })
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "密码:"
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", { id: "webDavPassword" })
})]
})
]
}),
(0, import_jsx_runtime.jsxs)("div", {
id: "base-panel",
className: "content-panel",
style: { display: panelName === "base-panel" ? "block" : "none" },
children: [
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "打开待鉴定|已收藏 窗口数:"
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", {
type: "number",
id: "waitCheckCount",
min: "1",
max: "20",
style: { width: "100%" }
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "已鉴定标签展示位置:"
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsxs)("select", {
id: "tagPosition",
children: [(0, import_jsx_runtime.jsx)("option", {
value: "rightTop",
children: "右上"
}), (0, import_jsx_runtime.jsx)("option", {
value: "leftTop",
children: "左上"
})]
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsxs)("span", {
className: "setting-label",
style: {
display: "flex",
alignItems: "center",
gap: "5px"
},
children: [
"鉴定补录演员信息",
" ",
(0, import_jsx_runtime.jsx)("span", {
"data-tip": "在列表页进行鉴定是获取不到演员名称的, 开启后, 额外解析详情页补录演员名称, 因发请求解析费时, 会被以往慢1秒左右",
children: "❓"
})
]
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "enableSaveActressCarInfo",
className: "mini-switch"
})
})]
}),
(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE$1 }),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "预览视频默认画质:"
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("select", {
id: "videoQuality",
dangerouslySetInnerHTML: { __html: qualityOptionsHtml }
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "评论区条数:"
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsxs)("select", {
id: "reviewCount",
children: [
(0, import_jsx_runtime.jsx)("option", {
value: "10",
children: "10条"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "20",
children: "20条"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "30",
children: "30条"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "40",
children: "40条"
}),
(0, import_jsx_runtime.jsx)("option", {
value: "50",
children: "50条"
})
]
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: `setting-item ${isJavdbSite ? "" : "do-hide"}`,
children: [(0, import_jsx_runtime.jsxs)("span", {
className: "setting-label",
children: [
"高亮已收藏演员",
" ",
(0, import_jsx_runtime.jsx)("span", {
"data-tip": "详情页, 对已收藏的演员进行边框高亮提醒",
children: "❓"
})
]
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "enableFavoriteActresses",
className: "mini-switch"
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: `setting-item ${isJavdbSite ? "" : "do-hide"}`,
children: [(0, import_jsx_runtime.jsx)("span", {
id: "highlightedTagLabel",
className: "setting-label",
children: "分类标签|高亮演员-边框样式:"
}), (0, import_jsx_runtime.jsxs)("div", {
className: "form-content",
style: {
display: "flex",
alignItems: "center"
},
children: [(0, import_jsx_runtime.jsx)("input", {
type: "number",
id: "highlightedTagNumber",
min: "0",
max: "20"
}), (0, import_jsx_runtime.jsx)("input", {
type: "color",
id: "highlightedTagColor"
})]
})]
}),
(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE$1 }),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "请求超时时间(毫秒):"
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", {
type: "number",
id: "httpTimeout",
min: "1000",
max: "10000",
style: { width: "100%" }
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "请求失败重试次数:"
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", {
type: "number",
id: "httpRetryCount",
min: "0",
max: "10",
style: { width: "100%" }
})
})]
}),
(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE$1 }),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "启用控制台日志:"
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsxs)("select", {
id: "enableClog",
children: [(0, import_jsx_runtime.jsx)("option", {
value: "no",
children: "禁用"
}), (0, import_jsx_runtime.jsx)("option", {
value: "yes",
children: "开启"
})]
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "日志最大行数:"
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", {
type: "number",
id: "clogMsgCount",
min: "100",
max: "3000",
style: { width: "100%" }
})
})]
})
]
}),
(0, import_jsx_runtime.jsxs)("div", {
id: "domain-panel",
className: "content-panel",
style: { display: panelName === "domain-panel" ? "block" : "none" },
children: [(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "域名 - MissAv:"
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", { id: "missAvUrl" })
})]
}), (0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "域名 - SupJav:"
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", { id: "supJavUrl" })
})]
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
id: "hotkey-panel",
className: "content-panel",
style: { display: panelName === "hotkey-panel" ? "block" : "none" },
children: [
(0, import_jsx_runtime.jsx)("p", {
style: {
color: "#666",
fontSize: "0.9em"
},
children: "修改后, 刷新页面生效"
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsxs)("span", {
className: "setting-label",
children: [blockText, ":"]
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", {
id: "filterHotKey",
placeholder: "录入快捷键",
"data-default-hotkey": "a"
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsxs)("span", {
className: "setting-label",
children: [favoriteText, ":"]
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", {
id: "favoriteHotKey",
placeholder: "录入快捷键",
"data-default-hotkey": "s"
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsxs)("span", {
className: "setting-label",
children: [watchedText, ":"]
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", {
id: "hasWatchHotKey",
placeholder: "录入快捷键"
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "⏩ 快进:"
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", {
id: "speedVideoHotKey",
placeholder: "录入快捷键",
"data-default-hotkey": "z"
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "▲ 折叠:"
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", {
id: "foldCategoryHotKey",
placeholder: "录入快捷键"
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "💻 控制台:"
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", {
id: "clogHotKey",
placeholder: "录入快捷键"
})
})]
}),
(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE$1 }),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsxs)("span", {
className: "setting-label",
children: [
(0, import_jsx_runtime.jsx)("span", {
"data-tip": "列表页,鼠标放置图片上时可使用快捷键",
children: "❓"
}),
" ",
"对视频列表页启用快捷键:"
]
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "enableImageHotKey",
className: "mini-switch"
})
})]
})
]
}),
(0, import_jsx_runtime.jsxs)("div", {
id: "filter-panel",
className: "content-panel",
style: { display: panelName === "filter-panel" ? "block" : "none" },
children: [
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsxs)("span", {
className: "setting-label",
children: [
"启用划词屏蔽",
" ",
(0, import_jsx_runtime.jsx)("span", {
"data-tip": "视频详情页中, 标题或评论区选中文字, 按右键可快捷加入屏蔽词",
children: "❓"
})
]
}), (0, import_jsx_runtime.jsx)("div", {
style: { display: "flex" },
children: (0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "enableTitleSelectFilter",
className: "mini-switch"
})
})]
}),
(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE$1 }),
(0, import_jsx_runtime.jsxs)("div", {
id: "reviewKeywordContainer",
children: [(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "评论区屏蔽词:"
}), (0, import_jsx_runtime.jsxs)("div", {
style: { display: "flex" },
children: [(0, import_jsx_runtime.jsx)("input", {
type: "text",
className: "keyword-input",
placeholder: "添加屏蔽词"
}), (0, import_jsx_runtime.jsx)("button", {
className: "add-tag-btn",
children: "添加"
})]
})]
}), (0, import_jsx_runtime.jsx)("div", {
className: "tag-box",
children: " "
})]
}),
(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE$1 }),
(0, import_jsx_runtime.jsxs)("div", {
id: "filterKeywordContainer",
children: [(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "视频标题屏蔽词:"
}), (0, import_jsx_runtime.jsxs)("div", {
style: { display: "flex" },
children: [(0, import_jsx_runtime.jsx)("input", {
type: "text",
className: "keyword-input",
placeholder: "添加屏蔽词"
}), (0, import_jsx_runtime.jsx)("button", {
className: "add-tag-btn",
children: "添加"
})]
})]
}), (0, import_jsx_runtime.jsx)("div", {
className: "tag-box",
children: " "
})]
})
]
}),
(0, import_jsx_runtime.jsxs)("div", {
id: "cache-panel",
className: "content-panel",
style: { display: panelName === "cache-panel" ? "block" : "none" },
children: [
(0, import_jsx_runtime.jsxs)("div", {
style: {
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginBottom: "4px"
},
children: [(0, import_jsx_runtime.jsx)("h1", {
style: {
fontSize: "18px",
fontWeight: "bold",
margin: "0"
},
children: "缓存管理"
}), (0, import_jsx_runtime.jsx)("span", {
id: "cache-total-size",
style: {
fontSize: "13px",
color: "#999"
}
})]
}),
(0, import_jsx_runtime.jsx)("p", {
style: {
color: "#999",
fontSize: "12px",
margin: "0 0 16px 0"
},
children: "以下操作不会对核心数据造成影响,可安全清理"
}),
(0, import_jsx_runtime.jsx)("div", {
style: {
display: "grid",
gridTemplateColumns: "repeat(2, 1fr)",
gap: "15px",
marginTop: "20px"
},
dangerouslySetInnerHTML: { __html: cacheItemsHtml }
}),
(0, import_jsx_runtime.jsx)("div", {
id: "cache-data-display",
style: {
marginTop: "20px",
display: "none"
},
children: (0, import_jsx_runtime.jsx)("pre", { style: {
background: "#f5f5f5",
padding: "10px",
borderRadius: "5px",
maxHeight: "400px",
overflow: "auto"
} })
})
]
}),
(0, import_jsx_runtime.jsxs)("div", {
id: "vlt-panel",
className: "content-panel",
style: {
display: panelName === "vlt-panel" ? "block" : "none",
padding: "15px"
},
children: [
(0, import_jsx_runtime.jsx)("h3", {
style: {
margin: "0 0 12px 0",
fontSize: "16px",
color: "#333"
},
children: "收藏清单关系"
}),
(0, import_jsx_runtime.jsxs)("p", {
style: {
margin: "0 0 16px 0",
color: "#6c757d",
fontSize: "13px",
lineHeight: "1.6"
},
children: [
"管理影片与清单的关联数据(本地 IndexedDB,随 WebDav 备份)。",
(0, import_jsx_runtime.jsx)("br", {}),
(0, import_jsx_runtime.jsx)("strong", { children: "导入" }),
":从 JSON 文件导入数据(如 PostgreSQL 迁移数据)。",
(0, import_jsx_runtime.jsx)("br", {}),
(0, import_jsx_runtime.jsx)("strong", { children: "导出" }),
":将当前数据导出为 JSON 文件(备份/迁移)。"
]
}),
(0, import_jsx_runtime.jsxs)("div", {
style: {
display: "flex",
gap: "12px",
marginBottom: "20px"
},
children: [
(0, import_jsx_runtime.jsx)("a", {
id: "vlt-import-btn",
className: "menu-btn",
style: {
backgroundColor: "#0d6efd",
cursor: "pointer"
},
children: (0, import_jsx_runtime.jsx)("span", { children: "导入数据" })
}),
" ",
(0, import_jsx_runtime.jsx)("a", {
id: "vlt-export-btn",
className: "menu-btn",
style: {
backgroundColor: "#198754",
cursor: "pointer"
},
children: (0, import_jsx_runtime.jsx)("span", { children: "导出数据" })
})
]
}),
(0, import_jsx_runtime.jsx)("div", {
id: "vlt-status",
style: {
fontSize: "13px",
color: "#6c757d",
marginTop: "8px"
}
}),
(0, import_jsx_runtime.jsx)("input", {
type: "file",
id: "vlt-file-input",
accept: ".json,application/json",
style: { display: "none" }
})
]
}),
(0, import_jsx_runtime.jsxs)("div", {
id: "missav-panel",
className: "content-panel",
style: {
display: panelName === "missav-panel" ? "block" : "none",
padding: "15px"
},
children: [
(0, import_jsx_runtime.jsx)("h3", {
style: {
margin: "0 0 12px 0",
fontSize: "16px",
color: "#333"
},
children: "MissAV 状态标签同步"
}),
(0, import_jsx_runtime.jsxs)("p", {
style: {
margin: "0 0 16px 0",
color: "#6c757d",
fontSize: "13px",
lineHeight: "1.6"
},
children: [
"在 MissAV 站点显示 JHS 鉴定状态标签(已收藏/已观看/已屏蔽/已下载)。",
(0, import_jsx_runtime.jsx)("br", {}),
"数据通过油猴 GM 存储跨域同步,无需后端服务器。",
(0, import_jsx_runtime.jsx)("br", {}),
(0, import_jsx_runtime.jsx)("strong", { children: "立即同步" }),
":读取当前 car_list 并推送到 GM 存储。",
(0, import_jsx_runtime.jsx)("br", {}),
(0, import_jsx_runtime.jsx)("strong", { children: "导入" }),
":从后端服务器导出的 JSON 导入历史数据。",
(0, import_jsx_runtime.jsx)("br", {}),
(0, import_jsx_runtime.jsx)("strong", { children: "导出" }),
":将 MissAV 本地 IndexedDB 数据导出为 JSON(可走 WebDav 备份)。"
]
}),
(0, import_jsx_runtime.jsxs)("div", {
style: {
display: "flex",
gap: "12px",
marginBottom: "20px"
},
children: [
(0, import_jsx_runtime.jsx)("a", {
id: "missav-sync-btn",
className: "menu-btn",
style: {
backgroundColor: "#25b1dc",
cursor: "pointer"
},
children: (0, import_jsx_runtime.jsx)("span", { children: "立即同步" })
}),
" ",
(0, import_jsx_runtime.jsx)("a", {
id: "missav-import-btn",
className: "menu-btn",
style: {
backgroundColor: "#0d6efd",
cursor: "pointer"
},
children: (0, import_jsx_runtime.jsx)("span", { children: "导入数据" })
}),
" ",
(0, import_jsx_runtime.jsx)("a", {
id: "missav-export-btn",
className: "menu-btn",
style: {
backgroundColor: "#198754",
cursor: "pointer"
},
children: (0, import_jsx_runtime.jsx)("span", { children: "导出数据" })
})
]
}),
(0, import_jsx_runtime.jsx)("div", {
id: "missav-status",
style: {
fontSize: "13px",
color: "#6c757d",
marginTop: "8px"
}
}),
(0, import_jsx_runtime.jsx)("input", {
type: "file",
id: "missav-file-input",
accept: ".json,application/json",
style: { display: "none" }
})
]
})
]
}), (0, import_jsx_runtime.jsxs)("div", {
style: {
flexShrink: 0,
padding: "15px 20px",
textAlign: "right",
borderTop: "1px solid #eee",
background: "white"
},
children: [(0, import_jsx_runtime.jsx)("button", {
id: "saveBtn",
children: "保存设置"
}), (0, import_jsx_runtime.jsx)("button", {
id: "clean-all",
style: { display: "none" },
children: "♾️ 清理全部缓存"
})]
})]
})]
});
}
function HelpDialog() {
return (0, import_jsx_runtime.jsxs)("div", {
className: "help-container",
children: [
(0, import_jsx_runtime.jsx)("h1", {
style: {
fontSize: "22px",
marginBottom: "20px",
color: "#2c3e50",
borderBottom: "1px solid #eee",
paddingBottom: "10px"
},
children: "使用说明"
}),
(0, import_jsx_runtime.jsxs)("details", {
className: "help-section",
children: [(0, import_jsx_runtime.jsx)("summary", { children: "1. 无法查看预览视频,提示分流?" }), (0, import_jsx_runtime.jsxs)("div", {
className: "help-content",
children: [
(0, import_jsx_runtime.jsx)("p", { children: "JavDB限制日本IP的访问,而预览视频来自DMM,需要日本IP才能访问。" }),
(0, import_jsx_runtime.jsx)("p", { children: "这样会导致二者无法同时使用,需要对其一进行代理转发。" }),
(0, import_jsx_runtime.jsx)("p", { children: "将 cc3001.dmm.co.jp 及 dmm.co 分流到日本ip。" }),
(0, import_jsx_runtime.jsxs)("p", { children: [
(0, import_jsx_runtime.jsxs)("a", {
href: "https://youtu.be/wQUK8z_YeU4?t=121",
target: "_blank",
children: ["Clash Verge分流规则设置", " "]
}),
" ",
"(如果你是别的代理软件,自行搜索如何分流)"
] })
]
})]
}),
(0, import_jsx_runtime.jsxs)("details", {
className: "help-section",
children: [(0, import_jsx_runtime.jsx)("summary", { children: "2. 如何屏蔽某一系列的番号?" }), (0, import_jsx_runtime.jsxs)("div", {
className: "help-content",
children: [
(0, import_jsx_runtime.jsx)("p", { children: "方法一:设置中-添加视频标题关键词,如: VENX-" }),
(0, import_jsx_runtime.jsx)("p", { children: "方法二:进入详情页,选中标题文字,右键可加入" }),
(0, import_jsx_runtime.jsx)("img", {
src: "https://i.imgur.com/lVnhK5A.png",
alt: "进入详情页,选中标题,进行右键"
})
]
})]
}),
(0, import_jsx_runtime.jsxs)("details", {
className: "help-section",
children: [(0, import_jsx_runtime.jsx)("summary", { children: "3. 屏蔽某演员,如何只屏蔽单体影片?" }), (0, import_jsx_runtime.jsxs)("div", {
className: "help-content",
children: [(0, import_jsx_runtime.jsx)("p", { children: "屏蔽演员前,先筛选分类,再点屏蔽" }), (0, import_jsx_runtime.jsx)("img", {
src: "https://imgur.com/Ue7eCAi.png",
alt: "屏蔽演员前,先筛选分类,再点屏蔽"
})]
})]
}),
(0, import_jsx_runtime.jsxs)("details", {
className: "help-section",
children: [
(0, import_jsx_runtime.jsx)("summary", { children: "4. 如何多浏览器同时登录115网盘?" }),
(0, import_jsx_runtime.jsxs)("div", {
className: "help-content",
children: [(0, import_jsx_runtime.jsx)("p", { children: "① 访问115登录页, 选择JHS-扫码面板, 并扫码登录" }), (0, import_jsx_runtime.jsx)("img", {
src: "https://imgur.com/XbaisWD.png",
alt: ""
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "help-content",
children: [(0, import_jsx_runtime.jsx)("p", { children: "② 进入网盘后, 右下角悬浮按钮, 复制Cookie" }), (0, import_jsx_runtime.jsx)("img", {
src: "https://imgur.com/GvzJ2Gy.png",
alt: ""
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "help-content",
children: [(0, import_jsx_runtime.jsx)("p", { children: "③ 打开另一个浏览器(需装JHS脚本), 进入登录页面, 选择JHS-扫码面板, 输入Cookie并回车" }), (0, import_jsx_runtime.jsx)("img", {
src: "https://imgur.com/FX08qdO.png",
alt: ""
})]
})
]
})
]
});
}
function BackupFileDialog() {
return (0, import_jsx_runtime.jsx)("div", {
style: {
height: "100%",
overflow: "hidden"
},
children: (0, import_jsx_runtime.jsx)("div", {
id: "table-container",
style: { margin: "auto auto !important" }
})
});
}
function BackToTopButton() {
return (0, import_jsx_runtime.jsx)("div", {
id: "jhs-back-to-top",
title: "回到顶部",
children: (0, import_jsx_runtime.jsx)("svg", {
viewBox: "0 0 24 24",
children: (0, import_jsx_runtime.jsx)("path", { d: "M12 4l-8 8h6v8h4v-8h6z" })
})
});
}
function CacheItemHtml({ text, cacheKey, title, size, count }) {
return (0, import_jsx_runtime.jsxs)("div", {
className: "cache-item",
"data-cache-key": cacheKey,
style: {
border: "1px solid #eee",
borderRadius: "8px",
padding: "12px"
},
children: [
(0, import_jsx_runtime.jsx)("div", {
style: {
fontWeight: "bold",
marginBottom: "4px"
},
children: text
}),
(0, import_jsx_runtime.jsxs)("div", {
style: {
fontSize: "12px",
color: "#999",
marginBottom: "8px"
},
children: [
(0, import_jsx_runtime.jsx)("span", {
className: "cache-size",
children: size
}),
" · ",
(0, import_jsx_runtime.jsx)("span", {
className: "cache-count",
children: count
})
]
}),
(0, import_jsx_runtime.jsxs)("div", {
style: {
display: "flex",
gap: "6px"
},
children: [
(0, import_jsx_runtime.jsx)("a", {
className: "menu-btn clean-btn",
"data-key": cacheKey,
style: {
backgroundColor: "#448cc2",
flex: 1,
textAlign: "center",
fontSize: "13px"
},
title,
children: (0, import_jsx_runtime.jsx)("span", { children: "清理" })
}),
(0, import_jsx_runtime.jsx)("a", {
className: "menu-btn view-btn",
"data-key": cacheKey,
style: {
backgroundColor: "#b2bec0",
flex: 1,
textAlign: "center",
fontSize: "13px"
},
children: (0, import_jsx_runtime.jsx)("span", { children: "查看" })
}),
(0, import_jsx_runtime.jsx)("a", {
className: "menu-btn export-btn",
"data-key": cacheKey,
style: {
backgroundColor: "#85d0a3",
flex: 1,
textAlign: "center",
fontSize: "13px"
},
title: "导出为 JSON 文件",
children: (0, import_jsx_runtime.jsx)("span", { children: "导出" })
})
]
})
]
});
}
function KeywordLabel({ keyword, bgColor, textColor, variant, href }) {
const style = {
backgroundColor: bgColor,
color: textColor
};
if (variant === "link") return (0, import_jsx_runtime.jsxs)("a", {
className: "keyword-label",
"data-keyword": keyword,
style,
href,
target: "_blank",
children: [keyword, (0, import_jsx_runtime.jsx)("span", {
className: "keyword-remove",
children: "×"
})]
});
return (0, import_jsx_runtime.jsxs)("div", {
className: "keyword-label",
"data-keyword": keyword,
style,
children: [keyword, (0, import_jsx_runtime.jsx)("span", {
className: "keyword-remove",
children: "×"
})]
});
}
function SettingMountBox({ variant }) {
switch (variant) {
case "navbar": return (0, import_jsx_runtime.jsxs)("div", {
className: "navbar-item has-dropdown is-hoverable setting-box",
style: { position: "relative" },
children: [(0, import_jsx_runtime.jsx)("a", {
id: "setting-btn",
className: "navbar-link nav-btn",
style: {
color: "#ff8400 !important",
paddingRight: "15px !important"
},
children: "设置"
}), (0, import_jsx_runtime.jsx)("div", { className: "simple-setting" })]
});
case "mini": return (0, import_jsx_runtime.jsxs)("div", {
className: "navbar-item mini-setting-box",
style: {
position: "relative",
marginLeft: "auto"
},
children: [(0, import_jsx_runtime.jsx)("a", {
id: "mini-setting-btn",
className: "navbar-link nav-btn",
style: {
color: "#ff8400 !important",
paddingLeft: "0 !important",
paddingRight: "0 !important"
},
children: "设置"
}), (0, import_jsx_runtime.jsx)("div", { className: "mini-simple-setting" })]
});
}
}
var HR_STYLE = {
border: 0,
height: "1px",
margin: "10px 0",
backgroundImage: "linear-gradient(to right, rgba(0,0,0,0), rgba(159,137,137,0.75), rgba(0,0,0,0))"
};
var LABEL_SPAN_STYLE = {
display: "inline-block",
width: "80px",
fontSize: "13px",
fontWeight: "bold",
textAlign: "left"
};
function SimpleSettingPanel({ isJavdbSite }) {
return (0, import_jsx_runtime.jsxs)("div", {
className: "jhs-scrollbar",
style: {
marginTop: "20px",
maxHeight: "90vh",
overflowY: "auto"
},
children: [(0, import_jsx_runtime.jsxs)("div", {
style: { margin: "0 10px" },
children: [
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "显示已鉴定内容:"
}), (0, import_jsx_runtime.jsxs)("div", {
className: "form-content",
style: {
display: "flex",
flexWrap: "wrap",
alignItems: "center",
justifyContent: "flex-end"
},
children: [
(0, import_jsx_runtime.jsx)("span", {
style: LABEL_SPAN_STYLE,
children: "屏蔽单番号: "
}),
(0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "showFilterItem",
className: "mini-switch"
}),
(0, import_jsx_runtime.jsx)("br", {}),
(0, import_jsx_runtime.jsx)("span", {
style: LABEL_SPAN_STYLE,
children: "屏蔽演员: "
}),
(0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "showFilterActorItem",
className: "mini-switch"
}),
(0, import_jsx_runtime.jsx)("br", {}),
(0, import_jsx_runtime.jsx)("span", {
style: LABEL_SPAN_STYLE,
children: "屏蔽关键词: "
}),
(0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "showFilterKeywordItem",
className: "mini-switch"
}),
(0, import_jsx_runtime.jsx)("br", {}),
(0, import_jsx_runtime.jsx)("span", {
style: LABEL_SPAN_STYLE,
children: "收藏: "
}),
(0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "showFavoriteItem",
className: "mini-switch"
}),
(0, import_jsx_runtime.jsx)("br", {}),
(0, import_jsx_runtime.jsx)("span", {
style: LABEL_SPAN_STYLE,
children: "已观看: "
}),
(0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "showHasWatchItem",
className: "mini-switch"
}),
(0, import_jsx_runtime.jsx)("br", {})
]
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsxs)("span", {
className: "setting-label",
children: [
(0, import_jsx_runtime.jsx)("span", {
"data-tip": "快速显示所有已鉴定内容,减少对以上开关的频繁操作",
children: "❓"
}),
" ",
"显示所有:"
]
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
style: {
display: "flex",
flexWrap: "wrap",
alignItems: "center",
justifyContent: "flex-end"
},
children: (0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "showAllItem",
className: "mini-switch"
})
})]
}),
(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE }),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsxs)("span", {
className: "setting-label",
children: [(0, import_jsx_runtime.jsx)("span", {
"data-tip": "点击封面的打开方式,弹窗|新窗口",
children: "❓"
}), " 弹窗方式打开页面:"]
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
style: { textAlign: "right" },
children: (0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "dialogOpenDetail",
className: "mini-switch"
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "鉴定后立即关闭页面:"
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
style: { textAlign: "right" },
children: (0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "needClosePage",
className: "mini-switch"
})
})]
}),
(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE }),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsxs)("span", {
className: "setting-label",
children: [(0, import_jsx_runtime.jsx)("span", {
"data-tip": "使用瀑布流模式, 排序方式将调整为默认",
children: "❓"
}), " 瀑布流模式:"]
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
style: { textAlign: "right" },
children: (0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "autoPage",
className: "mini-switch"
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "启用标题翻译:"
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
style: { textAlign: "right" },
children: (0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "translateTitle",
className: "mini-switch"
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "启用悬浮大图:"
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
style: { textAlign: "right" },
children: (0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "hoverBigImg",
className: "mini-switch"
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsx)("span", {
className: "setting-label",
children: "启用115视频匹配: "
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
style: { textAlign: "right" },
children: (0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "enable115Match",
className: "mini-switch"
})
})]
}),
(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE }),
isJavdbSite && (0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsxs)("span", {
className: "setting-label",
children: [
(0, import_jsx_runtime.jsx)("span", {
"data-tip": "详情页是否展示女优年龄、三围等信息",
children: "❓"
}),
" ",
"加载女优信息:"
]
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
style: { textAlign: "right" },
children: (0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "enableLoadActressInfo",
className: "mini-switch"
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsxs)("span", {
className: "setting-label",
children: [
(0, import_jsx_runtime.jsx)("span", {
"data-tip": "详情页第三方资源检测,如missAv,SupJav",
children: "❓"
}),
" ",
"加载第三方视频资源:"
]
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
style: { textAlign: "right" },
children: (0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "enableLoadOtherSite",
className: "mini-switch"
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsxs)("span", {
className: "setting-label",
children: [(0, import_jsx_runtime.jsx)("span", {
"data-tip": "详情页图片区首列位置加载长缩略图",
children: "❓"
}), " 加载长缩略图:"]
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
style: { textAlign: "right" },
children: (0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "enableLoadScreenShot",
className: "mini-switch"
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsxs)("span", {
className: "setting-label",
children: [
(0, import_jsx_runtime.jsx)("span", {
"data-tip": "详情页解析更多更高画质的预览视频",
children: "❓"
}),
" ",
"更高画质预览视频:"
]
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
style: { textAlign: "right" },
children: (0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "enableLoadPreviewVideo",
className: "mini-switch"
})
})]
}),
(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE }),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsxs)("span", {
className: "setting-label",
children: [(0, import_jsx_runtime.jsx)("span", {
"data-tip": "列数6以上,建议开启竖图",
children: "❓"
}), " 竖图模式:"]
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
style: { textAlign: "right" },
children: (0, import_jsx_runtime.jsx)("input", {
type: "checkbox",
id: "enableVerticalModel",
className: "mini-switch"
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsxs)("span", {
className: "setting-label",
children: ["页面列数: ", (0, import_jsx_runtime.jsx)("span", { id: "showContainerColumns" })]
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", {
type: "range",
id: "containerColumns",
min: "2",
max: "10",
step: "1",
style: { padding: "5px 0" }
})
})]
}),
(0, import_jsx_runtime.jsxs)("div", {
className: "setting-item",
children: [(0, import_jsx_runtime.jsxs)("span", {
className: "setting-label",
children: ["页面宽度: ", (0, import_jsx_runtime.jsx)("span", { id: "showContainerWidth" })]
}), (0, import_jsx_runtime.jsx)("div", {
className: "form-content",
children: (0, import_jsx_runtime.jsx)("input", {
type: "range",
id: "containerWidth",
min: "0",
max: "30",
step: "1",
style: { padding: "5px 0" }
})
})]
})
]
}), (0, import_jsx_runtime.jsxs)("div", {
style: {
padding: "0 20px 15px",
textAlign: "right",
borderTop: "1px solid #eee"
},
children: [(0, import_jsx_runtime.jsx)("button", {
id: "helpBtn",
style: { float: "left" },
children: "常见问题"
}), (0, import_jsx_runtime.jsx)("button", {
id: "moreBtn",
children: "更多设置"
})]
})]
});
}
function VideoQualityOption({ quality, text }) {
return (0, import_jsx_runtime.jsx)("option", {
value: quality,
children: text
});
}
var DB_NAME = "JAV-JHS";
var STORE_NAME = "appData";
var MAX_COUNT = 501;
var BOOTSTRAP_COLORS = [
{
name: "primary",
bg: "#0d6efd",
text: "#fff"
},
{
name: "secondary",
bg: "#6c757d",
text: "#fff"
},
{
name: "success",
bg: "#198754",
text: "#fff"
},
{
name: "danger",
bg: "#dc3545",
text: "#fff"
},
{
name: "warning",
bg: "#ffc107",
text: "#212529"
},
{
name: "info",
bg: "#0dcaf0",
text: "#212529"
},
{
name: "dark",
bg: "#212529",
text: "#fff"
}
];
function randomBootstrapStyle() {
return BOOTSTRAP_COLORS[Math.floor(Math.random() * BOOTSTRAP_COLORS.length)];
}
var KEYS = {
MOVIES: "vlt_movies",
INVENTORY: "vlt_inventory",
MOVIE_INVENTORY: "vlt_movie_inventory",
META: "vlt_meta"
};
function openDb() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(DB_NAME);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains(STORE_NAME)) db.createObjectStore(STORE_NAME);
};
});
}
function dbGet(db, key) {
return new Promise((resolve, reject) => {
const req = db.transaction(STORE_NAME, "readonly").objectStore(STORE_NAME).get(key);
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
}
function dbPut(db, key, value) {
return new Promise((resolve, reject) => {
const tx = db.transaction(STORE_NAME, "readwrite");
tx.objectStore(STORE_NAME).put(value, key);
tx.oncomplete = () => resolve();
tx.onerror = () => reject(tx.error);
});
}
var VltDb = class {
static async sync(designation, listId, movie, list, action) {
const db = await openDb();
try {
const movies = await dbGet(db, KEYS.MOVIES) || {};
const inventory = await dbGet(db, KEYS.INVENTORY) || {};
const mi = await dbGet(db, KEYS.MOVIE_INVENTORY) || {};
const movieExisted = !!movies[designation];
const score = movie.score != null ? Number(movie.score) : null;
if (movieExisted) movies[designation] = {
...movies[designation],
href: movie.href,
title: movie.title ?? null,
coverSrc: movie.cover_src ?? null,
score,
releaseDate: movie.release_date ?? null,
series: movie.series ?? null,
code: movie.code ?? null
};
else movies[designation] = {
designation,
href: movie.href,
title: movie.title ?? null,
coverSrc: movie.cover_src ?? null,
score,
releaseDate: movie.release_date ?? null,
createdAt: new Date().toISOString(),
series: movie.series ?? null,
code: movie.code ?? null
};
const movieStatus = movieExisted ? "existed" : "created";
const listExisted = !!inventory[listId];
if (!listExisted) inventory[listId] = {
listId,
name: list.name,
url: list.url ?? null,
count: 0,
style: randomBootstrapStyle()
};
const listStatus = listExisted ? "existed" : "created";
const assocKey = `${designation}::${listId}`;
let associationStatus;
if (action === "add") if (mi[assocKey]) associationStatus = "existed";
else {
const currentCount = inventory[listId]?.count ?? 0;
if (currentCount >= MAX_COUNT) associationStatus = "limit_exceeded";
else {
mi[assocKey] = true;
inventory[listId].count = currentCount + 1;
associationStatus = "created";
}
}
else if (mi[assocKey]) {
delete mi[assocKey];
if (inventory[listId]) inventory[listId].count = Math.max(0, inventory[listId].count - 1);
associationStatus = "deleted";
} else associationStatus = "unchanged";
await dbPut(db, KEYS.MOVIES, movies);
await dbPut(db, KEYS.INVENTORY, inventory);
await dbPut(db, KEYS.MOVIE_INVENTORY, mi);
return {
movie: movieStatus,
list: listStatus,
association: associationStatus
};
} finally {
db.close();
}
}
static async queryMoviesLists(designations) {
const db = await openDb();
try {
const inventory = await dbGet(db, KEYS.INVENTORY) || {};
const mi = await dbGet(db, KEYS.MOVIE_INVENTORY) || {};
const result = {};
for (const des of designations) result[des] = [];
for (const key of Object.keys(mi)) {
const sepIdx = key.indexOf("::");
if (sepIdx < 0) continue;
const des = key.substring(0, sepIdx);
const lid = key.substring(sepIdx + 2);
if (result[des] !== void 0) {
const inv = inventory[lid];
if (inv) result[des].push({
name: inv.name,
url: inv.url,
style: inv.style
});
}
}
return result;
} finally {
db.close();
}
}
static async check(designation, listId) {
const db = await openDb();
try {
const movies = await dbGet(db, KEYS.MOVIES) || {};
const inventory = await dbGet(db, KEYS.INVENTORY) || {};
const mi = await dbGet(db, KEYS.MOVIE_INVENTORY) || {};
return {
movie: !!movies[designation],
inventory: !!inventory[listId],
movieInventory: !!mi[`${designation}::${listId}`]
};
} finally {
db.close();
}
}
static async importData(data) {
const db = await openDb();
try {
await dbPut(db, KEYS.MOVIES, data.movies);
await dbPut(db, KEYS.INVENTORY, data.inventory);
await dbPut(db, KEYS.MOVIE_INVENTORY, data.movieInventory);
await dbPut(db, KEYS.META, {
version: data._version,
exportedAt: data._exportedAt,
importedAt: new Date().toISOString(),
source: data._source
});
return {
movies: Object.keys(data.movies).length,
inventory: Object.keys(data.inventory).length,
movieInventory: Object.keys(data.movieInventory).length
};
} finally {
db.close();
}
}
static async isImported() {
const db = await openDb();
try {
return !!(await dbGet(db, KEYS.META))?.importedAt;
} finally {
db.close();
}
}
static async getAllInventory() {
const db = await openDb();
try {
return await dbGet(db, KEYS.INVENTORY) || {};
} finally {
db.close();
}
}
static async exportData() {
const db = await openDb();
try {
const movies = await dbGet(db, KEYS.MOVIES) || {};
const inventory = await dbGet(db, KEYS.INVENTORY) || {};
const mi = await dbGet(db, KEYS.MOVIE_INVENTORY) || {};
const meta = await dbGet(db, KEYS.META);
return {
_version: meta?.version ?? 1,
_exportedAt: meta?.exportedAt ?? new Date().toISOString(),
_source: "IndexedDB (local export)",
movies,
inventory,
movieInventory: mi
};
} finally {
db.close();
}
}
};
var queue = {
MAX_VISIBLE: 2,
SIMULTANEOUS_WINDOW: 500,
EXTRA_DURATION: 1e3,
visible: [],
overflow: [],
lastAddTime: 0
};
var ICONS = {
success: "<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>",
error: "<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"/><line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"/></svg>",
warning: "<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"/><line x1=\"12\" y1=\"17\" x2=\"12\" y2=\"17.01\"/></svg>",
info: "<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"8.01\"/></svg>"
};
function getToastContainer() {
let el = document.getElementById("jdb-toast-container");
if (!el) {
el = document.createElement("div");
el.id = "jdb-toast-container";
document.body.appendChild(el);
}
return el;
}
function promoteOverflow() {
if (queue.overflow.length === 0 || queue.visible.length >= queue.MAX_VISIBLE) return;
const stacked = queue.visible.find((v) => v.el.classList.contains("jdb-toast--stacked"));
if (stacked) stacked.el.classList.remove("jdb-toast--stacked");
const next = queue.overflow.shift();
getToastContainer().appendChild(next.el);
next.el.offsetHeight;
const now = Date.now();
const isSimultaneous = now - queue.lastAddTime < queue.SIMULTANEOUS_WINDOW;
let adjustedDuration = next.duration;
if (isSimultaneous) adjustedDuration += queue.EXTRA_DURATION;
queue.lastAddTime = now;
queue.visible.push({
el: next.el,
timerId: setTimeout(() => dismissToast(next.el), adjustedDuration),
createdAt: now
});
}
function dismissToast(el) {
const idx = queue.visible.findIndex((v) => v.el === el);
if (idx < 0) return;
const onTransitionEnd = () => {
el.removeEventListener("transitionend", onTransitionEnd);
el.remove();
const i = queue.visible.findIndex((v) => v.el === el);
if (i >= 0) queue.visible.splice(i, 1);
promoteOverflow();
};
el.classList.add("removing");
el.addEventListener("transitionend", onTransitionEnd);
setTimeout(() => {
if (el.parentNode) {
el.remove();
const i = queue.visible.findIndex((v) => v.el === el);
if (i >= 0) queue.visible.splice(i, 1);
promoteOverflow();
}
}, 300);
if (idx >= 0) clearTimeout(queue.visible[idx].timerId);
}
function showToast$1(msg, type = "info", duration = 2500) {
const container = getToastContainer();
const toast = document.createElement("div");
toast.className = `jdb-toast jdb-toast--${type}`;
toast.innerHTML = `<span class="jdb-toast__icon">${ICONS[type]}</span><span class="jdb-toast__msg"></span>`;
toast.querySelector(".jdb-toast__msg").textContent = msg;
toast.addEventListener("click", () => dismissToast(toast));
if (queue.visible.length < queue.MAX_VISIBLE) {
const now = Date.now();
const isSimultaneous = now - queue.lastAddTime < queue.SIMULTANEOUS_WINDOW;
let adjustedDuration = duration;
if (isSimultaneous) adjustedDuration += queue.EXTRA_DURATION;
queue.lastAddTime = now;
container.appendChild(toast);
queue.visible.push({
el: toast,
timerId: setTimeout(() => dismissToast(toast), adjustedDuration),
createdAt: now
});
} else {
toast.classList.add("jdb-toast--stacked");
toast.addEventListener("click", (e) => {
e.stopPropagation();
if (queue.overflow.find((o) => o.el === toast)) {
const i = queue.overflow.findIndex((o) => o.el === toast);
queue.overflow.splice(i, 1);
promoteOverflow();
}
});
queue.overflow.push({
el: toast,
msg,
type,
duration
});
}
}
var STATUS_CONFIG = {
favorite: {
label: "⭐ 已收藏",
color: "#25b1dc"
},
hasWatch: {
label: "🔍 已观看",
color: "#d7a80c"
},
filter: {
label: "🚫 已屏蔽",
color: "#de3333"
},
hasDown: {
label: "💾 已下载",
color: "#1f7a3d"
}
};
var GM_KEY_CAR_STATUS_DATA = "jhs_car_status_data";
var GM_KEY_CAR_STATUS_DELTA = "jhs_car_status_delta";
var MISSAV_DB_NAME = "MissAV-CarStatus";
var MISSAV_DB_STORE = "cars";
var LOG_PREFIX_JHS = "[JHS CarSync]";
var LOG_PREFIX_MISSAV = "[MissAV]";
function normalizeUrl(rawUrl) {
let path = rawUrl;
try {
if (/^https?:\/\//.test(rawUrl)) {
const u = new URL(rawUrl);
path = u.pathname + (u.search || "");
} else if (rawUrl.startsWith("/")) path = rawUrl;
else return {
code: rawUrl,
malformed: true
};
} catch {
return {
code: rawUrl,
malformed: true
};
}
if (path.startsWith("/v/")) return {
code: path.slice(3),
malformed: false
};
return {
code: path,
malformed: false
};
}
function buildJavdbUrl(urlPath) {
if (!urlPath) return "https://javdb.com";
if (urlPath.startsWith("/")) return "https://javdb.com" + urlPath;
return "https://javdb.com/v/" + urlPath;
}
function toColumnar(carList) {
const groups = Object.create(null);
let dropped = 0;
let malformed = 0;
for (const item of carList) {
if (!item || typeof item !== "object") {
dropped++;
continue;
}
if (!item.carNum || !item.url || !item.status) {
dropped++;
continue;
}
const status = item.status;
if (!groups[status]) groups[status] = new Map();
const { code, malformed: bad } = normalizeUrl(item.url);
if (bad) malformed++;
groups[status].set(item.carNum, {
url: code,
updateDate: item.updateDate || ""
});
}
const byStatus = {};
for (const status of Object.keys(groups)) {
const map = groups[status];
const carNums = [];
const urls = [];
const update_date = [];
for (const [carNum, { url, updateDate }] of map) {
carNums.push(carNum);
urls.push(url);
update_date.push(updateDate);
}
byStatus[status] = {
carNums,
urls,
update_date
};
}
return {
byStatus,
dropped,
malformed
};
}
function columnarToFlat(store) {
const records = [];
for (const status of Object.keys(store)) {
const group = store[status];
if (!group || !group.carNums || !group.urls) continue;
const { carNums, urls } = group;
for (let i = 0; i < carNums.length; i++) records.push({
carNum: carNums[i],
status,
url_path: urls[i]
});
}
return records;
}
function countColumnar(store) {
let n = 0;
for (const status of Object.keys(store)) {
const col = store[status];
if (col && col.carNums) n += col.carNums.length;
}
return n;
}
async function gzipToBase64(value) {
try {
if (typeof CompressionStream === "undefined") return null;
const json = JSON.stringify(value);
const blob = new Blob([json], { type: "application/json" });
const cs = new CompressionStream("gzip");
const stream = blob.stream().pipeThrough(cs);
const buf = await new Response(stream).arrayBuffer();
const bytes = new Uint8Array(buf);
let binary = "";
const chunkSize = 32768;
for (let i = 0; i < bytes.length; i += chunkSize) binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));
return btoa(binary);
} catch {
return null;
}
}
async function gunzipFromBase64(base64) {
try {
if (typeof DecompressionStream === "undefined") return null;
const binary = atob(base64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
const ds = new DecompressionStream("gzip");
const stream = new Blob([bytes]).stream().pipeThrough(ds);
const text = await new Response(stream).text();
return JSON.parse(text);
} catch {
return null;
}
}
function openLocalDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(MISSAV_DB_NAME, 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains("cars")) db.createObjectStore(MISSAV_DB_STORE, { keyPath: "carNum" });
};
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
request.onblocked = () => reject(new Error("数据库被阻塞,请关闭其他标签页后刷新"));
});
}
async function upsertLocalCars(records) {
const BATCH_SIZE = 3e3;
let totalWritten = 0;
const db = await openLocalDB();
try {
for (let i = 0; i < records.length; i += BATCH_SIZE) {
const batch = records.slice(i, i + BATCH_SIZE);
totalWritten += await new Promise((resolveBatch, rejectBatch) => {
const tx = db.transaction(MISSAV_DB_STORE, "readwrite");
const store = tx.objectStore(MISSAV_DB_STORE);
let count = 0;
for (const rec of batch) {
if (!rec.carNum || !rec.status || rec.url_path === void 0) continue;
const req = store.put({
carNum: rec.carNum.toUpperCase(),
status: rec.status,
url: buildJavdbUrlLocal(rec.url_path),
updateDate: ""
});
req.onsuccess = () => {
count++;
};
req.onerror = () => {
console.warn("[MissAV] 写入失败", rec.carNum, req.error);
};
}
tx.oncomplete = () => resolveBatch(count);
tx.onerror = () => rejectBatch(tx.error || new Error("事务失败"));
tx.onabort = () => rejectBatch(tx.error || new Error("事务中止"));
});
}
return totalWritten;
} finally {
db.close();
}
}
async function queryLocalCars(carNums) {
if (!carNums || carNums.length === 0) return new Map();
const db = await openLocalDB();
try {
return await new Promise((resolve) => {
const store = db.transaction(MISSAV_DB_STORE, "readonly").objectStore(MISSAV_DB_STORE);
const result = new Map();
let pending = carNums.length;
if (pending === 0) {
resolve(result);
return;
}
for (const cn of carNums) {
const req = store.get(cn);
req.onsuccess = () => {
if (req.result) result.set(cn, {
status: req.result.status,
url: req.result.url
});
pending--;
if (pending === 0) resolve(result);
};
req.onerror = () => {
pending--;
if (pending === 0) resolve(result);
};
}
});
} finally {
db.close();
}
}
async function deleteLocalCars(carNums) {
if (!carNums || carNums.length === 0) return;
const db = await openLocalDB();
try {
await new Promise((resolve) => {
const tx = db.transaction(MISSAV_DB_STORE, "readwrite");
const store = tx.objectStore(MISSAV_DB_STORE);
for (const cn of carNums) store.delete(cn);
tx.oncomplete = () => resolve();
tx.onerror = () => resolve();
});
} finally {
db.close();
}
}
async function exportLocalDB() {
const db = await openLocalDB();
try {
return await new Promise((resolve, reject) => {
const store = db.transaction(MISSAV_DB_STORE, "readonly").objectStore(MISSAV_DB_STORE);
const result = [];
const req = store.openCursor();
req.onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
result.push({
carNum: cursor.value.carNum,
status: cursor.value.status,
url: cursor.value.url
});
cursor.continue();
} else resolve(result);
};
req.onerror = () => reject(req.error);
});
} finally {
db.close();
}
}
async function importLocalDB(records) {
const db = await openLocalDB();
try {
await new Promise((resolve, reject) => {
const tx = db.transaction(MISSAV_DB_STORE, "readwrite");
tx.objectStore(MISSAV_DB_STORE).clear();
tx.oncomplete = () => resolve();
tx.onerror = () => reject(tx.error);
});
} finally {
db.close();
}
let written = 0;
const BATCH_SIZE = 3e3;
const db2 = await openLocalDB();
try {
for (let i = 0; i < records.length; i += BATCH_SIZE) {
const batch = records.slice(i, i + BATCH_SIZE);
written += await new Promise((resolveBatch, rejectBatch) => {
const tx = db2.transaction(MISSAV_DB_STORE, "readwrite");
const store = tx.objectStore(MISSAV_DB_STORE);
let count = 0;
for (const rec of batch) {
const req = store.put({
carNum: rec.carNum.toUpperCase(),
status: rec.status,
url: rec.url,
updateDate: ""
});
req.onsuccess = () => count++;
}
tx.oncomplete = () => resolveBatch(count);
tx.onerror = () => rejectBatch(tx.error);
});
}
} finally {
db2.close();
}
return written;
}
function buildJavdbUrlLocal(urlPath) {
if (!urlPath) return "https://javdb.com";
if (urlPath.startsWith("/")) return "https://javdb.com" + urlPath;
return "https://javdb.com/v/" + urlPath;
}
function getCacheStats(key) {
const raw = localStorage.getItem(key);
if (!raw) return {
size: 0,
count: 0
};
const size = new Blob([raw]).size;
let count = 0;
try {
const parsed = JSON.parse(raw);
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) count = Object.keys(parsed).length;
else if (Array.isArray(parsed)) count = parsed.length;
} catch {}
return {
size,
count
};
}
function formatSize(bytes) {
if (bytes === 0) return "0 B";
if (bytes < 1024) return `${bytes} B`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}
var SettingPlugin = class extends BasePlugin {
folderName = "JHS-数据备份";
cacheItems = [
{
key: "jhs_dmm_video",
text: "🎥 预览视频缓存",
title: "DMM 预告片画质→URL 映射(联动清理 jhs_other_site_dmm)"
},
{
key: "jhs_other_site",
text: "🌍 第三方站点缓存",
title: "missav/supjav 等站点搜索结果"
},
{
key: "jhs_translate",
text: "🆎 标题翻译",
title: "番号→中文标题翻译(Google Translate)"
},
{
key: "jhs_actress_info",
text: "👩 演员信息",
title: "演员身高/体重/三围/罩杯/生日(日文维基百科)"
},
{
key: "jhs_score_info",
text: "⭐ Top250|热播 评分数据",
title: "影片评分 HTML 快照(javdb 详情页)"
}
];
getName() {
return "SettingPlugin";
}
async initCss() {
const settings = await storageManager.getSetting();
const containerWidth = (settings == null ? void 0 : settings.containerWidth) ?? "100";
const containerColumns = utils.isMobile() && window.innerWidth < 1e3 ? 1 : (settings == null ? void 0 : settings.containerColumns) ?? 5;
this.applyImageMode().then();
let cssText = `\n section .container{\n max-width: 1000px !important;\n min-width: ${containerWidth}%;\n }\n .movie-list, .movie-list.v{\n grid-template-columns: repeat(${containerColumns}, minmax(0, 1fr));\n }\n `;
return setting_plugin_default.replace("__CSS_TEXT__", cssText).replace("__SIMPLE_SETTING_TOP__", "35px").replace("__SIMPLE_SETTING_RIGHT__", "-300%");
}
async handle() {
if (await storageManager.getSetting("enableClog", "yes") === "yes") clog.show();
if (isJavdbSite) {
const toggleSettingBox = function() {
if ($(".navbar-search").is(":hidden")) {
$(".mini-setting-box").hide();
$(".setting-box").show();
} else {
$(".mini-setting-box").show();
$(".setting-box").hide();
}
};
$("#navbar-menu-user .navbar-end").prepend(jsxToString((0, import_jsx_runtime.jsx)(SettingMountBox, { variant: "navbar" })));
utils.loopDetector(() => $("#miniHistoryBtn").length > 0, () => {
$(".miniHistoryBtnBox").before(jsxToString((0, import_jsx_runtime.jsx)(SettingMountBox, { variant: "mini" })));
toggleSettingBox();
});
$(window).resize(toggleSettingBox);
}
$(".main-nav, .container-fluid").on("click", "#setting-btn, #mini-setting-btn", () => {
clog.lowZIndex();
this.openSettingDialog();
});
$(".main-nav, .container-fluid").on("mouseenter", ".setting-box", () => {
$(".simple-setting").html(this.simpleSetting()).show();
this.initSimpleSettingForm().then();
clog.lowZIndex();
}).on("mouseleave", ".setting-box", () => {
$(".simple-setting").html("").hide();
});
$(".main-nav, .container-fluid").on("mouseenter", ".mini-setting-box", () => {
$(".mini-simple-setting").html(this.simpleSetting()).show();
this.initSimpleSettingForm().then();
clog.lowZIndex();
}).on("mouseleave", ".mini-setting-box", () => {
$(".mini-simple-setting").html("").hide();
});
this.addBackToTopBtn();
}
addBackToTopBtn() {
utils.insertStyle(back_to_top_button_default);
const btn = $(jsxToString((0, import_jsx_runtime.jsx)(BackToTopButton, {})));
$("body").append(btn);
btn.on("click", () => {
utils.smoothScrollToTop(500);
});
let ticking = false;
$(window).on("scroll", () => {
if (!ticking) {
window.requestAnimationFrame(() => {
if ($(window).scrollTop() > 300) btn.addClass("show");
else btn.removeClass("show");
ticking = false;
});
ticking = true;
}
});
}
async openSettingDialog(panelName = "backup-panel", callback) {
const cacheItemsHtml = this.cacheItems.map((item) => {
const stats = getCacheStats(item.key);
return jsxToString((0, import_jsx_runtime.jsx)(CacheItemHtml, {
text: item.text,
cacheKey: item.key,
title: item.title,
size: formatSize(stats.size),
count: stats.count > 0 ? `${stats.count} 条` : "空"
}));
}).join("");
let qualityOptionsHtml = "";
VIDEO_QUALITY_LIST.forEach((option) => {
if (option.canSelect) qualityOptionsHtml += jsxToString((0, import_jsx_runtime.jsx)(VideoQualityOption, {
quality: option.quality,
text: option.text
}));
});
const dialogHtml = jsxToString((0, import_jsx_runtime.jsx)(SettingDialog, {
panelName,
cacheItemsHtml,
qualityOptionsHtml,
isJavdbSite,
blockText: BLOCK_TEXT,
favoriteText: FAVORITE_TEXT,
watchedText: WATCHED_TEXT
}));
layer.open({
type: 1,
title: "设置",
content: dialogHtml,
area: utils.getResponsiveArea(["55%", "90%"]),
scrollbar: false,
success: (layerEl, layerIndex) => {
$(layerEl).find(".layui-layer-content").css("position", "relative");
this.loadForm();
this.bindClick();
utils.setupEscClose(layerIndex);
if (callback) callback();
}
});
}
simpleSetting() {
return jsxToString((0, import_jsx_runtime.jsx)(SimpleSettingPanel, { isJavdbSite }));
}
async loadForm() {
const settings = await storageManager.getSetting();
$("#videoQuality").val(settings.videoQuality);
$("#reviewCount").val(settings.reviewCount || 20);
$("#tagPosition").val(settings.tagPosition || "rightTop");
$("#waitCheckCount").val(settings.waitCheckCount || 5);
const tagNumber = settings.highlightedTagNumber || 1;
const tagColor = settings.highlightedTagColor || "#ce2222";
$("#highlightedTagNumber").val(settings.highlightedTagNumber || 1);
$("#highlightedTagColor").val(settings.highlightedTagColor || "#ce2222");
$("#highlightedTagLabel").css("border", `${tagNumber}px solid ${tagColor}`);
$("#enableClog").val(settings.enableClog || "yes");
$("#clogMsgCount").val(settings.clogMsgCount || 2e3);
$("#httpTimeout").val(settings.httpTimeout || 5e3);
$("#httpRetryCount").val(settings.httpRetryCount || 3);
$("#webDavUrl").val(settings.webDavUrl || "");
$("#webDavUsername").val(settings.webDavUsername || "");
$("#webDavPassword").val(settings.webDavPassword || "");
$("#enableTitleSelectFilter").prop("checked", !settings.enableTitleSelectFilter || settings.enableTitleSelectFilter === "yes");
$("#enableFavoriteActresses").prop("checked", !settings.enableFavoriteActresses || settings.enableFavoriteActresses === "yes");
$("#enableSaveActressCarInfo").prop("checked", !!settings.enableSaveActressCarInfo && settings.enableSaveActressCarInfo === "yes");
const otherSitePlugin = this.getBean("OtherSitePlugin");
const missAvUrl = await otherSitePlugin.getMissAvUrl();
const supJavUrl = await otherSitePlugin.getSupJavUrl();
$("#missAvUrl").val(missAvUrl);
$("#supJavUrl").val(supJavUrl);
const reviewFilterKeywordList = await storageManager.getReviewFilterKeywordList();
const titleFilterKeyword = await storageManager.getTitleFilterKeyword();
if (reviewFilterKeywordList) reviewFilterKeywordList.forEach((keyword) => {
this.addLabelTag("#reviewKeywordContainer", keyword);
});
if (titleFilterKeyword) titleFilterKeyword.forEach((keyword) => {
this.addLabelTag("#filterKeywordContainer", keyword);
});
["#reviewKeywordContainer", "#filterKeywordContainer"].forEach((containerSelector) => {
$(`${containerSelector} .add-tag-btn`).on("click", () => this.addKeyword(containerSelector));
$(`${containerSelector} .keyword-input`).on("keypress", (event) => {
if (event.key === "Enter") this.addKeyword(containerSelector);
});
});
$("#hotkey-panel [id]").map((_index, element) => element.id).get().forEach((inputId) => {
const $input = $(`#${inputId}`);
const hotkeyValue = settings[inputId] !== void 0 ? settings[inputId] : $input.attr("data-default-hotkey") || "";
$input.val(hotkeyValue).on("input", (event) => {
const value = $(event.target).val();
if (/[\u4e00-\u9fa5]/.test(value) || /^Shift[a-zA-Z0-9]+$/.test(value)) {
$(event.target).val("");
show.error("非法输入:不能输入中文或输入法转换错误");
}
}).on("keydown", (event) => this.handleHotkeyInput(event, $input));
});
$("#enableImageHotKey").prop("checked", !!settings.enableImageHotKey && settings.enableImageHotKey === "yes");
}
handleHotkeyInput(event, $input) {
event.preventDefault();
const hotkeyString = this.parseHotkey(event);
if (hotkeyString !== "") if (this.isDuplicateHotkey(hotkeyString, $input.attr("id"))) show.error("该快捷键已被其他功能使用!");
else $input.val(hotkeyString);
else $input.val("");
}
parseHotkey(event) {
if (event.key === "Backspace" || event.key === "Process") return "";
const parts = [];
if (event.ctrlKey) parts.push("Ctrl");
if (event.shiftKey) parts.push("Shift");
if (event.altKey) parts.push("Alt");
if (event.metaKey) parts.push("Cmd");
const keyName = {
" ": "Space",
Control: "Ctrl",
Meta: "Cmd",
ArrowUp: "Up",
ArrowDown: "Down",
ArrowLeft: "Left",
ArrowRight: "Right"
}[event.key] || (event.key.length > 1 ? event.key.replace("Arrow", "") : event.key);
if (![
"Control",
"Shift",
"Alt",
"Meta"
].includes(event.key)) parts.push(keyName);
if (parts.length > 0) return parts.join("+");
else return "";
}
isDuplicateHotkey(hotkeyString, inputId) {
let isDuplicate = false;
$("#hotkey-panel [id]").each((_index, element) => {
if (element.id !== inputId && hotkeyString && hotkeyString === $(element).val()) {
isDuplicate = true;
return false;
}
});
return isDuplicate;
}
async initSimpleSettingForm() {
const settings = await storageManager.getSetting();
$("#containerColumns").val(settings.containerColumns || 5);
$("#showContainerColumns").text(settings.containerColumns || 5);
$("#containerWidth").val((settings.containerWidth || 100) - 70);
$("#showContainerWidth").text((settings.containerWidth || 100) + "%");
$("#dialogOpenDetail").prop("checked", !settings.dialogOpenDetail || settings.dialogOpenDetail === "yes");
$("#needClosePage").prop("checked", !settings.needClosePage || settings.needClosePage === "yes");
$("#autoPage").prop("checked", !settings.autoPage || settings.autoPage === "yes");
$("#translateTitle").prop("checked", !settings.translateTitle || settings.translateTitle === "yes");
$("#enableLoadActressInfo").prop("checked", !settings.enableLoadActressInfo || settings.enableLoadActressInfo === "yes");
$("#enableLoadOtherSite").prop("checked", !settings.enableLoadOtherSite || settings.enableLoadOtherSite === "yes");
$("#containerColumns").on("input", async () => {
const columns = $("#containerColumns").val();
$("#showContainerColumns").text(columns);
if (isJavdbSite) document.querySelector(".movie-list").style.gridTemplateColumns = `repeat(${columns}, minmax(0, 1fr))`;
await storageManager.saveSettingItem("containerColumns", columns);
this.applyImageMode();
});
$("#containerWidth").on("input", async (event) => {
const rangeValue = parseInt($(event.target).val());
const widthPercent = rangeValue + 70 + "%";
$("#showContainerWidth").text(widthPercent);
if (isJavdbSite) document.querySelector("section .container").style.minWidth = widthPercent;
storageManager.saveSettingItem("containerWidth", rangeValue + 70);
});
$("#dialogOpenDetail").on("change", () => {
const value = $("#dialogOpenDetail").is(":checked") ? "yes" : "no";
storageManager.saveSettingItem("dialogOpenDetail", value);
});
$("#showFilterItem").prop("checked", !!settings.showFilterItem && settings.showFilterItem === "yes");
$("#showFilterActorItem").prop("checked", !!settings.showFilterActorItem && settings.showFilterActorItem === "yes");
$("#showFilterKeywordItem").prop("checked", !!settings.showFilterKeywordItem && settings.showFilterKeywordItem === "yes");
$("#showFavoriteItem").prop("checked", !settings.showFavoriteItem || settings.showFavoriteItem === "yes");
$("#showHasWatchItem").prop("checked", !settings.showHasWatchItem || settings.showHasWatchItem === "yes");
$("#showFilterItem").on("change", async () => {
const value = $("#showFilterItem").is(":checked") ? "yes" : "no";
await storageManager.saveSettingItem("showFilterItem", value);
refresh();
});
$("#showFilterActorItem").on("change", async () => {
const value = $("#showFilterActorItem").is(":checked") ? "yes" : "no";
await storageManager.saveSettingItem("showFilterActorItem", value);
refresh();
});
$("#showFilterKeywordItem").on("change", async () => {
const value = $("#showFilterKeywordItem").is(":checked") ? "yes" : "no";
await storageManager.saveSettingItem("showFilterKeywordItem", value);
refresh();
});
$("#showFavoriteItem").on("change", async () => {
const value = $("#showFavoriteItem").is(":checked") ? "yes" : "no";
await storageManager.saveSettingItem("showFavoriteItem", value);
refresh();
});
$("#showHasWatchItem").on("change", async () => {
const value = $("#showHasWatchItem").is(":checked") ? "yes" : "no";
await storageManager.saveSettingItem("showHasWatchItem", value);
refresh();
});
const $filterCheckboxes = $("#showFilterItem, #showFilterActorItem, #showFilterKeywordItem, #showFavoriteItem, #showHasWatchItem");
const updateDisabledState = () => {
const isChecked = $("#showAllItem").is(":checked");
$filterCheckboxes.prop("disabled", isChecked);
if (isChecked) $filterCheckboxes.attr("data-tip", "请先关闭显示所有才可点击");
else $filterCheckboxes.removeAttr("data-tip");
};
$("#showAllItem").prop("checked", !!settings.showAllItem && settings.showAllItem === "yes");
$("#showAllItem").on("change", async () => {
const value = $("#showAllItem").is(":checked") ? "yes" : "no";
await storageManager.saveSettingItem("showAllItem", value);
updateDisabledState();
refresh();
});
updateDisabledState();
$("#needClosePage").on("change", async () => {
await storageManager.saveSettingItem("needClosePage", $("#needClosePage").is(":checked") ? "yes" : "no");
refresh();
});
$("#autoPage").on("change", async () => {
const value = $("#autoPage").is(":checked") ? "yes" : "no";
await storageManager.saveSettingItem("autoPage", value);
if (value === "yes") $("#sort-toggle-btn").hide();
else $("#sort-toggle-btn").show();
});
$("#translateTitle").on("change", async () => {
const value = $("#translateTitle").is(":checked") ? "yes" : "no";
await storageManager.saveSettingItem("translateTitle", value);
if (value === "yes") await this.getBean("ListPagePlugin").doFilter();
else {
await this.getBean("ListPagePlugin").revertTranslation();
$(".translated-title").remove();
}
});
$("#hoverBigImg").prop("checked", !!settings.hoverBigImg && settings.hoverBigImg === "yes");
$("#hoverBigImg").on("change", async () => {
const value = $("#hoverBigImg").is(":checked") ? "yes" : "no";
await storageManager.saveSettingItem("hoverBigImg", value);
if (value === "yes") window.imageHoverPreviewObj = new ImagePreview({ selector: this.getSelector().coverImgSelector });
else if (window.imageHoverPreviewObj) window.imageHoverPreviewObj.destroy();
});
$("#enableLoadActressInfo").on("change", async () => {
const value = $("#enableLoadActressInfo").is(":checked") ? "yes" : "no";
await storageManager.saveSettingItem("enableLoadActressInfo", value);
if (value === "yes") this.getBean("ActressInfoPlugin").loadActressInfo();
else $(".actress-info").remove();
});
$("#enableLoadOtherSite").on("change", async () => {
const value = $("#enableLoadOtherSite").is(":checked") ? "yes" : "no";
await storageManager.saveSettingItem("enableLoadOtherSite", value);
if (value === "yes") this.getBean("OtherSitePlugin").loadOtherSite().then();
else $("#otherSiteBox").remove();
});
$("#enableLoadScreenShot").prop("checked", !settings.enableLoadScreenShot || settings.enableLoadScreenShot === "yes");
$("#enableLoadScreenShot").on("change", async () => {
const value = $("#enableLoadScreenShot").is(":checked") ? "yes" : "no";
await storageManager.saveSettingItem("enableLoadScreenShot", value);
if (value !== "yes") $(".screen-container").remove();
});
$("#enableLoadPreviewVideo").prop("checked", !settings.enableLoadPreviewVideo || settings.enableLoadPreviewVideo === "yes");
$("#enableLoadPreviewVideo").on("change", async () => {
const value = $("#enableLoadPreviewVideo").is(":checked") ? "yes" : "no";
await storageManager.saveSettingItem("enableLoadPreviewVideo", value);
});
$("#enable115Match").prop("checked", !!settings.enable115Match && settings.enable115Match === "yes");
$("#enable115Match").on("change", async () => {
const value = $("#enable115Match").is(":checked") ? "yes" : "no";
await storageManager.saveSettingItem("enable115Match", value);
});
$("#enableVerticalModel").prop("checked", !!settings.enableVerticalModel && settings.enableVerticalModel === "yes");
$("#enableVerticalModel").on("change", async () => {
const value = $("#enableVerticalModel").is(":checked") ? "yes" : "no";
await storageManager.saveSettingItem("enableVerticalModel", value);
this.applyImageMode();
});
$("#moreBtn").on("click", () => {
$(".simple-setting").html("").hide();
this.openSettingDialog("base-panel");
});
$("#helpBtn").on("click", () => {
layer.open({
type: 1,
title: "",
shadeClose: true,
scrollbar: false,
content: "<style>" + help_dialog_default + "</style>" + jsxToString((0, import_jsx_runtime.jsx)(HelpDialog, {})),
area: utils.getResponsiveArea(["50%", "90%"])
});
});
}
async applyImageMode() {
$("#verticalImgStyle").remove();
if (await storageManager.getSetting("enableVerticalModel", "no") === "yes") {
let objectPosition = "100% 50% !important";
if (window.location.href.includes("/advanced_search?type=100")) objectPosition = "50% 50% !important";
const verticalCss = setting_image_mode_vertical_default.replace("100% 50% !important; /*__OBJECT_POSITION__*/", `${objectPosition}; /*__OBJECT_POSITION__*/`);
$("<style>").attr("id", "verticalImgStyle").text(verticalCss).appendTo("head");
} else $("<style>").attr("id", "verticalImgStyle").text(setting_image_mode_horizontal_default).appendTo("head");
}
bindClick() {
$(".side-menu-item").on("click", function() {
$(".side-menu-item").removeClass("active");
$(this).addClass("active");
$(".content-panel").hide();
const panelName = $(this).data("panel");
$("#" + panelName).show();
if (panelName === "cache-panel") {
$("#saveBtn").hide();
$("#clean-all").show();
this.refreshAllCacheStats();
} else if (panelName === "vlt-panel") {
$("#saveBtn").hide();
$("#clean-all").hide();
} else if (panelName === "missav-panel") {
$("#saveBtn").hide();
$("#clean-all").hide();
} else {
$("#saveBtn").show();
$("#clean-all").hide();
}
});
$("#importBtn").on("click", () => this.importData());
$("#exportBtn").on("click", () => this.exportData());
$("#webdavBackupBtn").on("click", () => this.backupDataByWebDav());
$("#webdavBackupListBtn").on("click", () => this.backupListBtnByWebDav());
$("#saveBtn").on("click", () => this.saveForm());
this.refreshAllCacheStats();
$(".clean-btn").on("click", (event) => {
const cacheKey = $(event.currentTarget).data("key");
const cacheItem = this.cacheItems.find((item) => item.key === cacheKey);
localStorage.removeItem(cacheKey);
if (cacheKey === "jhs_dmm_video") localStorage.removeItem("jhs_other_site_dmm");
show.ok(`${cacheItem.text} 清理成功`);
$("#cache-data-display").hide();
this.refreshCacheStats(cacheKey);
this.refreshAllCacheStats();
});
$("#clean-all").on("click", () => {
this.cacheItems.forEach((item) => localStorage.removeItem(item.key));
localStorage.removeItem("jhs_other_site_dmm");
show.ok("全部缓存已清理");
$("#cache-data-display").hide();
this.refreshAllCacheStats();
});
$(".view-btn").on("click", (event) => {
const cacheKey = $(event.currentTarget).data("key");
const cachedData = localStorage.getItem(cacheKey);
const $display = $("#cache-data-display");
const $pre = $display.find("pre");
$display.show();
if (cachedData) try {
const parsed = JSON.parse(cachedData);
$pre.text(JSON.stringify(parsed, null, 2));
} catch {
$pre.text(cachedData);
}
else $pre.text("无数据");
});
$(".export-btn").on("click", (event) => {
const cacheKey = $(event.currentTarget).data("key");
const cachedData = localStorage.getItem(cacheKey);
if (!cachedData) {
show.error("缓存为空,无可导出数据");
return;
}
const cacheItem = this.cacheItems.find((item) => item.key === cacheKey);
const blob = new Blob([cachedData], { type: "application/json" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = `${cacheKey}-${new Date().toISOString().split("T")[0]}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
show.ok(`${cacheItem.text} 已导出`);
});
const $tagNumber = $("#highlightedTagNumber");
const $tagColor = $("#highlightedTagColor");
const $tagLabel = $("#highlightedTagLabel");
function updateBorder() {
const number = $tagNumber.val();
const color = $tagColor.val();
$tagLabel.css("border", `${number}px solid ${color}`);
}
$tagNumber.on("input", updateBorder);
$tagColor.on("input", updateBorder);
$("#vlt-import-btn").on("click", () => {
$("#vlt-file-input").trigger("click");
});
$("#vlt-file-input").on("change", async (e) => {
const file = e.target.files?.[0];
if (!file) return;
const $status = $("#vlt-status");
$status.text("⏳ 导入中...").css("color", "#0d6efd");
try {
const text = await file.text();
const data = JSON.parse(text);
const stats = await VltDb.importData(data);
$status.html(`✓ 导入完成:${stats.movies} 部影片, ${stats.inventory} 个清单, ${stats.movieInventory} 条关联`).css("color", "#198754");
showToast$1(`✓ 导入完成:${stats.movies} 部影片, ${stats.inventory} 个清单, ${stats.movieInventory} 条关联`, "success");
setTimeout(() => window.location.reload(), 1500);
} catch (err) {
$status.text(`✗ 导入失败:${err.message}`).css("color", "#dc3545");
showToast$1(`✗ 导入失败:${err.message}`, "error");
}
e.target.value = "";
});
$("#vlt-export-btn").on("click", async () => {
const $status = $("#vlt-status");
$status.text("⏳ 导出中...").css("color", "#0d6efd");
try {
const data = await VltDb.exportData();
const json = JSON.stringify(data, null, 2);
const blob = new Blob([json], { type: "application/json" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = `vlt-export-${new Date().toISOString().split("T")[0]}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
$status.html(`✓ 导出完成:${Object.keys(data.movies).length} 部影片, ${Object.keys(data.inventory).length} 个清单, ${Object.keys(data.movieInventory).length} 条关联`).css("color", "#198754");
showToast$1("✓ 导出完成", "success");
} catch (err) {
$status.text(`✗ 导出失败:${err.message}`).css("color", "#dc3545");
showToast$1(`✗ 导出失败:${err.message}`, "error");
}
});
$("#missav-sync-btn").on("click", async () => {
const $status = $("#missav-status");
$status.text("⏳ 同步中...").css("color", "#0d6efd");
try {
const carList = await storageManager.getCarList();
if (carList.length === 0) {
$status.text("✗ car_list 为空").css("color", "#dc3545");
return;
}
const colRes = toColumnar(carList);
const count = countColumnar(colRes.byStatus);
const base64 = await gzipToBase64(colRes.byStatus);
if (!base64) {
$status.text("✗ 压缩失败").css("color", "#dc3545");
return;
}
const payload = {
data: base64,
hwm: new Date().toISOString(),
count,
ts: Date.now()
};
GM_setValue(GM_KEY_CAR_STATUS_DATA, payload);
$status.html(`✓ 同步完成:${count} 条记录已推送到 GM 存储`).css("color", "#198754");
showToast$1(`✓ 同步完成:${count} 条`, "success");
} catch (err) {
$status.text(`✗ 同步失败:${err.message}`).css("color", "#dc3545");
showToast$1(`✗ 同步失败:${err.message}`, "error");
}
});
$("#missav-import-btn").on("click", () => {
$("#missav-file-input").trigger("click");
});
$("#missav-file-input").on("change", async (e) => {
const file = e.target.files?.[0];
if (!file) return;
const $status = $("#missav-status");
$status.text("⏳ 导入中...").css("color", "#0d6efd");
try {
const text = await file.text();
const data = JSON.parse(text);
let records;
if (Array.isArray(data)) records = data;
else if (data.records && Array.isArray(data.records)) records = data.records;
else records = columnarToFlat(data).map((r) => ({
carNum: r.carNum,
status: r.status,
url: buildJavdbUrl(r.url_path)
}));
const written = await importLocalDB(records);
$status.html(`✓ 导入完成:${written} 条记录`).css("color", "#198754");
showToast$1(`✓ 导入完成:${written} 条`, "success");
} catch (err) {
$status.text(`✗ 导入失败:${err.message}`).css("color", "#dc3545");
showToast$1(`✗ 导入失败:${err.message}`, "error");
}
e.target.value = "";
});
$("#missav-export-btn").on("click", async () => {
const $status = $("#missav-status");
$status.text("⏳ 导出中...").css("color", "#0d6efd");
try {
const records = await exportLocalDB();
const json = JSON.stringify(records, null, 2);
const blob = new Blob([json], { type: "application/json" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = `missav-status-${new Date().toISOString().split("T")[0]}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
$status.html(`✓ 导出完成:${records.length} 条记录`).css("color", "#198754");
showToast$1("✓ 导出完成", "success");
} catch (err) {
$status.text(`✗ 导出失败:${err.message}`).css("color", "#dc3545");
showToast$1(`✗ 导出失败:${err.message}`, "error");
}
});
}
refreshCacheStats(cacheKey) {
const stats = getCacheStats(cacheKey);
const $item = $(`.cache-item[data-cache-key="${cacheKey}"]`);
$item.find(".cache-size").text(formatSize(stats.size));
$item.find(".cache-count").text(stats.count > 0 ? `${stats.count} 条` : "空");
}
refreshAllCacheStats() {
let totalSize = 0;
for (const item of this.cacheItems) {
const stats = getCacheStats(item.key);
totalSize += stats.size;
const $item = $(`.cache-item[data-cache-key="${item.key}"]`);
$item.find(".cache-size").text(formatSize(stats.size));
$item.find(".cache-count").text(stats.count > 0 ? `${stats.count} 条` : "空");
}
totalSize += getCacheStats("jhs_other_site_dmm").size;
$("#cache-total-size").text(`总占用 ${formatSize(totalSize)}`);
}
async saveForm() {
const settings = await storageManager.getSetting();
settings.videoQuality = $("#videoQuality").val();
settings.reviewCount = $("#reviewCount").val();
settings.tagPosition = $("#tagPosition").val();
settings.waitCheckCount = $("#waitCheckCount").val();
settings.highlightedTagNumber = $("#highlightedTagNumber").val();
settings.highlightedTagColor = $("#highlightedTagColor").val();
settings.httpTimeout = $("#httpTimeout").val();
settings.httpRetryCount = $("#httpRetryCount").val();
settings.enableClog = $("#enableClog").val();
if (settings.enableClog === "yes") clog.show();
else clog.hide();
settings.clogMsgCount = $("#clogMsgCount").val();
settings.webDavUrl = $("#webDavUrl").val();
settings.webDavUsername = $("#webDavUsername").val();
settings.webDavPassword = $("#webDavPassword").val();
settings.missAvUrl = $("#missAvUrl").val().replace(/\/$/, "");
settings.supJavUrl = $("#supJavUrl").val().replace(/\/$/, "");
settings.enableTitleSelectFilter = $("#enableTitleSelectFilter").is(":checked") ? "yes" : "no";
settings.enableFavoriteActresses = $("#enableFavoriteActresses").is(":checked") ? "yes" : "no";
settings.enableSaveActressCarInfo = $("#enableSaveActressCarInfo").is(":checked") ? "yes" : "no";
$("#hotkey-panel [id]").map((_index, element) => element.id).get().forEach((inputId) => {
settings[inputId] = $(`#${inputId}`).val();
});
settings.enableImageHotKey = $("#enableImageHotKey").is(":checked") ? "yes" : "no";
await storageManager.saveSetting(settings);
const reviewKeywordList = [];
$("#reviewKeywordContainer .keyword-label").toArray().forEach((label) => {
const keyword = $(label).text().replace("×", "").replace(/[\r\n]+/g, " ").replace(/\s{2,}/g, " ").trim();
reviewKeywordList.push(keyword);
});
await storageManager.saveReviewFilterKeyword(reviewKeywordList);
const titleFilterKeywordList = [];
$("#filterKeywordContainer .keyword-label").toArray().forEach((label) => {
const keyword = $(label).text().replace("×", "").replace(/[\r\n]+/g, " ").replace(/\s{2,}/g, " ").trim();
titleFilterKeywordList.push(keyword);
});
await storageManager.saveTitleFilterKeyword(titleFilterKeywordList);
show.ok("保存成功");
refresh();
const newVideoPlugin = this.getBean("NewVideoPlugin");
if (newVideoPlugin) newVideoPlugin.resetBtnTip();
this.getBean("BlacklistPlugin").resetBtnTip();
this.getBean("BlacklistPlugin").reloadTable();
}
addLabelTag(containerSelector, keyword) {
const $tagBox = $(`${containerSelector} .tag-box`);
let $label;
const bgColor = "#cbd5e1";
let textColor = "#333";
if (/^[a-z]{2,}-/i.test(keyword) && isJavdbSite) {
textColor = "#3477ad";
$label = $(jsxToString((0, import_jsx_runtime.jsx)(KeywordLabel, {
keyword,
bgColor,
textColor,
variant: "link",
href: `/video_codes/${keyword.replace("-", "")}`
})));
} else $label = $(jsxToString((0, import_jsx_runtime.jsx)(KeywordLabel, {
keyword,
bgColor,
textColor,
variant: "div"
})));
$label.find(".keyword-remove").click((event) => {
event.stopPropagation();
event.preventDefault();
const $removeBtn = $(event.currentTarget);
const removeKeyword = $removeBtn.closest(".keyword-label").attr("data-keyword").split(" ")[0];
utils.q(event, `是否移除屏蔽词 ${removeKeyword}?`, async () => {
$removeBtn.parent().remove();
});
});
$tagBox.append($label);
}
addKeyword(containerSelector) {
const $input = $(`${containerSelector} .keyword-input`);
const keyword = $input.val().trim();
if (keyword) {
this.addLabelTag(containerSelector, keyword);
$input.val("");
}
}
importData() {
try {
const fileInput = document.createElement("input");
fileInput.type = "file";
fileInput.accept = ".json";
fileInput.onchange = (event) => {
const file = event.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (loadEvent) => {
try {
const resultText = loadEvent.target.result.toString();
const parsedData = JSON.parse(resultText);
layer.confirm("确定是否要覆盖导入?", {
icon: 3,
title: "确认覆盖",
btn: ["确定", "取消"]
}, async (layerIndex) => {
await storageManager.importData(parsedData);
show.ok("数据导入成功");
layer.close(layerIndex);
location.reload();
});
} catch (err) {
console.error(err);
show.error("导入失败:文件内容不是有效的JSON格式 " + err);
}
};
reader.onerror = () => {
show.error("读取文件时出错");
};
reader.readAsText(file);
};
document.body.appendChild(fileInput);
fileInput.click();
setTimeout(() => document.body.removeChild(fileInput), 1e3);
} catch (err) {
console.error(err);
show.error("导入数据时出错: " + err.message);
}
}
async backupDataByWebDav() {
const settings = await storageManager.getSetting();
const webDavUrl = settings.webDavUrl;
if (!webDavUrl) {
show.error("请填写webDav服务地址并保存后, 再试此功能");
return;
}
const webDavUsername = settings.webDavUsername;
if (!webDavUsername) {
show.error("请填写webDav用户名并保存后, 再试此功能");
return;
}
const webDavPassword = settings.webDavPassword;
if (!webDavPassword) {
show.error("请填写webDav密码并保存后, 再试此功能");
return;
}
const fileName = utils.getNowStr("_", "_") + ".json";
let exportText = JSON.stringify(await storageManager.exportData());
exportText = window.encryptCredential(exportText);
const loadingHandle = loading();
try {
await new window.WebDavClient(webDavUrl, webDavUsername, webDavPassword).backup(this.folderName, fileName, exportText);
show.ok("备份完成");
} catch (err) {
console.error(err);
show.error(err.toString());
} finally {
loadingHandle.close();
}
}
async backupListBtnByWebDav() {
const settings = await storageManager.getSetting();
const webDavUrl = settings.webDavUrl;
if (!webDavUrl) {
show.error("请填写webDav服务地址并保存后, 再试此功能");
return;
}
const webDavUsername = settings.webDavUsername;
if (!webDavUsername) {
show.error("请填写webDav用户名并保存后, 再试此功能");
return;
}
const webDavPassword = settings.webDavPassword;
if (!webDavPassword) {
show.error("请填写webDav密码并保存后, 再试此功能");
return;
}
const loadingHandle = loading();
try {
const webdavClient = new window.WebDavClient(webDavUrl, webDavUsername, webDavPassword);
const backupList = await webdavClient.getBackupList(this.folderName);
this.openFileListDialog(backupList, webdavClient, "WebDav");
} catch (err) {
console.error(err);
show.error(`发生错误: ${err ? err.message : err}`);
} finally {
loadingHandle.close();
}
}
openFileListDialog(backupList, webdavClient, titlePrefix) {
layer.open({
type: 1,
title: titlePrefix + "备份文件",
content: jsxToString((0, import_jsx_runtime.jsx)(BackupFileDialog, {})),
area: ["800px", "70%"],
anim: -1,
success: () => {
const table = new Tabulator("#table-container", {
layout: "fitColumns",
placeholder: "暂无数据",
virtualDom: true,
data: backupList,
responsiveLayout: "collapse",
responsiveLayoutCollapse: true,
columnDefaults: {
headerHozAlign: "center",
hozAlign: "center"
},
columns: [
{
title: "文件名",
field: "name",
width: 200,
headerSort: false,
responsive: 0
},
{
title: "文件大小",
field: "size",
responsive: 1,
headerSort: false,
formatter: (cell, _params, _onRendered) => {
const units = [
"B",
"KB",
"MB",
"GB",
"TB",
"PB"
];
let unitIndex = 0;
let size = cell.getData().size;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
return `${size % 1 == 0 ? size.toFixed(0) : size.toFixed(2)} ${units[unitIndex]}`;
}
},
{
title: "备份日期",
field: "createTime",
responsive: 2,
headerSort: false,
formatter: (cell, _params, _onRendered) => {
const data = cell.getData();
return `${utils.getNowStr("-", ":", data.createTime)}`;
}
},
{
title: "操作",
minWidth: 250,
responsive: 0,
headerSort: false,
formatter: (cell, _params, onRendered) => {
const rowData = cell.getData();
onRendered(() => {
const $dangerBtn = cell.getElement().querySelector(".a-danger");
const $primaryBtn = cell.getElement().querySelector(".a-primary");
const $successBtn = cell.getElement().querySelector(".a-success");
if ($dangerBtn) $dangerBtn.addEventListener("click", (_event) => {
layer.confirm(`是否删除 ${rowData.name} ?`, {
icon: 3,
title: "提示",
btn: ["确定", "取消"]
}, async (layerIndex) => {
layer.close(layerIndex);
let loadingHandle = loading();
try {
await webdavClient.deleteFile(rowData.fileId);
let newList = await webdavClient.getBackupList(this.folderName);
table.replaceData(newList);
layer.alert("删除成功");
} catch (err) {
console.error(err);
show.error(`发生错误: ${err ? err.message : err}`);
} finally {
loadingHandle.close();
}
});
});
if ($primaryBtn) $primaryBtn.addEventListener("click", async (_event) => {
let loadingHandle = loading();
try {
const decrypted = window.decryptCredential(await webdavClient.getFileContent(rowData.fileId));
utils.download(decrypted, rowData.name);
} catch (err) {
clog.error(err);
show.error("下载失败: " + err);
} finally {
loadingHandle.close();
}
});
if ($successBtn) $successBtn.addEventListener("click", (_event) => {
layer.confirm(`是否将该云备份数据 ${rowData.name} 导入?`, {
icon: 3,
title: "提示",
btn: ["确定", "取消"]
}, async (layerIndex) => {
layer.close(layerIndex);
let loadingHandle = loading();
try {
let fileContent = await webdavClient.getFileContent(rowData.fileId);
show.info("解密文件内容...");
fileContent = window.decryptCredential(fileContent);
show.info("解密完成, 开始导入...");
const parsedData = JSON.parse(fileContent);
await storageManager.importData(parsedData);
show.ok("导入成功!");
window.location.reload();
} catch (err) {
console.error(err);
show.error(err);
} finally {
loadingHandle.close();
}
});
});
});
return "\n <a class=\"a-danger\">删除</a>\n <a class=\"a-primary\">下载</a>\n <a class=\"a-success\">导入</a>\n ";
}
}
],
locale: "zh-cn",
langs: { "zh-cn": { pagination: {
first: "首页",
first_title: "首页",
last: "尾页",
last_title: "尾页",
prev: "上一页",
prev_title: "上一页",
next: "下一页",
next_title: "下一页",
all: "所有",
page_size: "每页行数"
} } }
});
}
});
}
async exportData() {
try {
const exportText = JSON.stringify(await storageManager.exportData());
const fileName = `${utils.getNowStr("_", "_")}.json`;
utils.download(exportText, fileName);
show.ok("数据导出成功");
} catch (err) {
console.error(err);
show.error("导出数据时出错: " + err.message);
}
}
};
function SubtitleActionCell() {
return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
(0, import_jsx_runtime.jsx)("a", {
className: "a-primary",
children: "预览"
}),
" ",
(0, import_jsx_runtime.jsx)("a", {
className: "a-success",
children: "下载"
})
] });
}
function SubtitleLine({ paddedNum, line }) {
return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
(0, import_jsx_runtime.jsx)("span", {
style: { color: "#AAA" },
children: `${paddedNum}. `
}),
line,
"\n"
] });
}
function SubtitlePreviewDialog({ content }) {
return (0, import_jsx_runtime.jsx)("div", {
style: {
padding: "15px 5px",
background: "#1E1E1E",
color: "#FFF",
fontFamily: "Consolas,Monaco,monospace",
whiteSpace: "pre-wrap",
overflow: "auto",
height: "100%"
},
dangerouslySetInnerHTML: { __html: content }
});
}
function SubtitleTableDialog() {
return (0, import_jsx_runtime.jsx)("div", {
style: {
height: "100%",
overflow: "hidden"
},
children: (0, import_jsx_runtime.jsx)("div", {
id: "xunlei-table-container",
style: {
height: "100%",
paddingBottom: "20px"
}
})
});
}
var wrapperStyle = {
margin: "10px auto",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
flexWrap: "wrap",
gap: "20px"
};
var rowStyle = {
display: "flex",
gap: "10px",
flexWrap: "wrap"
};
function statusBtnStyle(width, backgroundColor) {
return {
width,
backgroundColor,
color: "white",
textAlign: "center",
padding: "8px 0"
};
}
function DetailMenuButtons({ filterText, filterColor, favoriteText, favoriteColor, watchedText, watchedColor }) {
return (0, import_jsx_runtime.jsxs)("div", {
style: wrapperStyle,
children: [(0, import_jsx_runtime.jsxs)("div", {
style: rowStyle,
children: [
(0, import_jsx_runtime.jsx)("a", {
id: "filterBtn",
className: "menu-btn",
style: statusBtnStyle("120px", filterColor),
children: (0, import_jsx_runtime.jsx)("span", { children: filterText })
}),
(0, import_jsx_runtime.jsx)("a", {
id: "favoriteBtn",
className: "menu-btn",
style: statusBtnStyle("120px", favoriteColor),
children: (0, import_jsx_runtime.jsx)("span", { children: favoriteText })
}),
(0, import_jsx_runtime.jsx)("a", {
id: "hasWatchBtn",
className: "menu-btn",
style: statusBtnStyle("120px", watchedColor),
children: (0, import_jsx_runtime.jsx)("span", { children: watchedText })
})
]
}), (0, import_jsx_runtime.jsxs)("div", {
style: rowStyle,
children: [
(0, import_jsx_runtime.jsx)("a", {
id: "enable-magnets-filter",
className: "menu-btn",
style: {
width: "140px",
backgroundColor: "#c2bd4c",
color: "white",
textAlign: "center",
padding: "8px 0"
},
children: (0, import_jsx_runtime.jsx)("span", {
id: "magnets-span",
children: "关闭磁力过滤"
})
}),
(0, import_jsx_runtime.jsx)("a", {
id: "xunLeiSubtitleBtn",
className: "menu-btn",
style: {
width: "120px",
background: "linear-gradient(to left, #375f7c, #2196F3)",
color: "white",
textAlign: "center",
padding: "8px 0"
},
children: (0, import_jsx_runtime.jsx)("span", { children: "字幕 (迅雷)" })
}),
(0, import_jsx_runtime.jsx)("a", {
id: "search-subtitle-btn",
className: "menu-btn",
style: {
width: "160px",
background: "linear-gradient(to bottom, #8d5656, rgb(196,159,91))",
color: "white",
textAlign: "center",
padding: "8px 0"
},
children: (0, import_jsx_runtime.jsx)("span", { children: "字幕 (SubTitleCat)" })
})
]
})]
});
}
function RatingBarHtml() {
return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("div", {
className: "jhs-stars",
"data-score": 0,
children: [
1,
2,
3,
4,
5
].map((n) => (0, import_jsx_runtime.jsx)("span", {
className: "jhs-star",
"data-score": n,
children: "★"
}, n))
}), (0, import_jsx_runtime.jsxs)("div", {
className: "jhs-rating-actions",
children: [(0, import_jsx_runtime.jsx)("button", {
className: "jhs-fav-btn",
type: "button",
title: "设为想看(收藏)",
children: "♥ 收藏"
}), (0, import_jsx_runtime.jsx)("button", {
className: "jhs-read-btn",
type: "button",
title: "设为已观看(0星)",
children: "已读"
})]
})] });
}
function ListPanel() {
return (0, import_jsx_runtime.jsx)("div", { className: "jhs-list-panel" });
}
var rating_bar_default = "/* 隐藏 review-buttons 内第二个 panel-block(下載/訂正磁力按钮) */\n.review-buttons > .panel-block ~ .panel-block {\n display: none !important;\n}\n/* 隐藏 review-buttons 后紧跟的 panel-block(N人想看/看過统计) */\n.review-buttons + .panel-block {\n display: none !important;\n}\n/* 隐藏原生评价状态标签和按钮(星星组件已替代) */\n.review-buttons .review-title {\n display: none !important;\n}\n.review-buttons .buttons.are-small.review-buttons {\n display: none !important;\n}\n/* 永久隐藏清单 modal(DOM 保留供 Stimulus ajax 操作) */\n#modal-save-list {\n display: none !important;\n}\n/* 星星评分组件 */\n.jhs-rating-bar {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin: 4px 0 12px;\n user-select: none;\n}\n.jhs-stars {\n display: inline-flex;\n gap: 6px;\n align-items: center;\n}\n.jhs-star {\n font-size: 26px;\n line-height: 1.2;\n padding: 2px 4px;\n cursor: pointer;\n color: #d0d0d0;\n transition:\n color 0.15s,\n transform 0.15s;\n}\n.jhs-star:hover {\n transform: scale(1.15);\n}\n.jhs-star.is-preview {\n color: #f5b301;\n}\n.jhs-star.is-active {\n color: #f5b301;\n}\n.jhs-star.is-active:hover {\n color: #ffce3a;\n}\n.jhs-star.is-popping {\n animation: jhs-star-pop 0.3s ease;\n}\n@keyframes jhs-star-pop {\n 0% {\n transform: scale(1);\n }\n 40% {\n transform: scale(1.4);\n }\n 100% {\n transform: scale(1);\n }\n}\n.jhs-stars.is-disabled .jhs-star {\n cursor: default;\n opacity: 0.4;\n pointer-events: none;\n}\n.jhs-rating-actions {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n.jhs-read-btn,\n.jhs-fav-btn {\n border: 1px solid #dbdbdb;\n border-radius: 6px;\n padding: 5px 16px;\n font-size: 14px;\n background: #fff;\n cursor: pointer;\n transition: all 0.15s;\n white-space: nowrap;\n}\n.jhs-read-btn:hover,\n.jhs-fav-btn:hover {\n border-color: #b5b5b5;\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);\n}\n.jhs-read-btn.is-active {\n background: #48c774;\n border-color: #48c774;\n color: #fff;\n}\n.jhs-fav-btn.is-active {\n background: #3273dc;\n border-color: #3273dc;\n color: #fff;\n}\n.jhs-read-btn.is-popping,\n.jhs-fav-btn.is-popping {\n animation: jhs-star-pop 0.3s ease;\n}\n.jhs-rating-bar.is-busy {\n pointer-events: none;\n opacity: 0.6;\n}\n/* 清单平铺面板(位于 #otherSiteBox 下方) */\n.jhs-list-panel {\n display: flex;\n flex-wrap: wrap;\n gap: 8px 16px;\n margin: 8px 0;\n padding: 8px 12px;\n background: #fafafa;\n border-radius: 6px;\n min-height: 36px;\n}\n.jhs-list-panel:empty {\n display: none;\n}\n.jhs-list-panel .control {\n margin: 0;\n}\n.jhs-list-panel .checkbox {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 13px;\n cursor: pointer;\n}\n.jhs-list-panel .checkbox input {\n margin: 0;\n}\n";
var DetailPageButtonPlugin = class extends BasePlugin {
answerCount = 1;
filterHotKey = null;
favoriteHotKey = null;
hasWatchHotKey = null;
speedVideoHotKey = null;
_wantWatchedObserved = false;
_lastWantState = null;
_wantWatchedSyncing = false;
_wantWatchedDebounce = null;
_wantWatchedListenerInstalled = false;
_quickActionAdded = false;
_listPanelEnsured = false;
_listPanelIniting = false;
_listAjaxTriggered = false;
_ratingSyncDebounce = null;
_reviewChain = null;
getName() {
return "DetailPageButtonPlugin";
}
constructor() {
super();
this.answerCount = 1;
}
async handle() {
const settings = await storageManager.getSetting();
this.filterHotKey = settings.filterHotKey;
this.favoriteHotKey = settings.favoriteHotKey;
this.hasWatchHotKey = settings.hasWatchHotKey;
this.speedVideoHotKey = settings.speedVideoHotKey;
this.bindHotkey().then();
this.hideVideoControls();
if (window.isDetailPage) {
this.createMenuBtn();
this.hookWantAndWatchedButtons();
this.addQuickActionButtons();
this.setupWantWatchedSyncListener();
}
}
async createMenuBtn() {
const carNum = this.getPageInfo().carNum;
const menuHtml = jsxToString((0, import_jsx_runtime.jsx)(DetailMenuButtons, {
filterText: BLOCK_TEXT,
filterColor: BLOCK_COLOR,
favoriteText: FAVORITE_TEXT,
favoriteColor: FAVORITE_COLOR,
watchedText: WATCHED_TEXT,
watchedColor: WATCHED_COLOR
}));
if (isJavdbSite) $(".tabs").after(menuHtml);
$("#favoriteBtn").on("click", () => this.favoriteOne());
$("#filterBtn").on("click", (event) => this.filterOne(event));
$("#hasWatchBtn").on("click", async () => this.hasWatchOne());
const highlightPlugin = this.getBean("HighlightMagnetPlugin");
const enableFilter = await storageManager.getSetting("enableMagnetsFilter", "yes");
$("#magnets-span").text(enableFilter === "yes" ? "关闭磁力过滤" : "开启磁力过滤");
if (enableFilter === "yes") highlightPlugin.doFilterMagnet();
$("#enable-magnets-filter").on("click", (_event) => {
const $span = $("#magnets-span");
if ($span.text() === "关闭磁力过滤") {
highlightPlugin.showAll();
$span.text("开启磁力过滤");
storageManager.saveSettingItem("enableMagnetsFilter", "no");
} else {
highlightPlugin.doFilterMagnet();
$span.text("关闭磁力过滤");
storageManager.saveSettingItem("enableMagnetsFilter", "yes");
}
});
$("#search-subtitle-btn").on("click", (event) => utils.openPage(`https://subtitlecat.com/index.php?search=${carNum}`, carNum, false, event));
$("#xunLeiSubtitleBtn").on("click", () => this.searchXunLeiSubtitle(carNum));
this.showStatus(carNum).then();
}
async showStatus(carNum) {
const $filterSpan = $("#filterBtn span");
const $favoriteSpan = $("#favoriteBtn span");
const $hasWatchSpan = $("#hasWatchBtn span");
const formatHotkey = (key) => key ? `(${key})` : "";
$filterSpan.text(`${BLOCK_TEXT} ${formatHotkey(this.filterHotKey)}`);
$favoriteSpan.text(`${FAVORITE_TEXT} ${formatHotkey(this.favoriteHotKey)}`);
$hasWatchSpan.text(`${WATCHED_TEXT} ${formatHotkey(this.hasWatchHotKey)}`);
const carRecord = await storageManager.getCar(carNum);
if (carRecord) switch (carRecord.status) {
case FILTER_ACTION:
$filterSpan.text(`${BLOCKED_TEXT} ${formatHotkey(this.filterHotKey)}`);
break;
case FAVORITE_ACTION:
$favoriteSpan.text(`${FAVORITED_TEXT} ${formatHotkey(this.favoriteHotKey)}`);
break;
case HAS_WATCH_ACTION: $hasWatchSpan.text(`🔍 已标记观看 ${formatHotkey(this.hasWatchHotKey)}`);
}
}
hookWantAndWatchedButtons() {
if (!isJavdbSite) return;
if (this._wantWatchedObserved) return;
const self = this;
const ensure = () => {
const container = document.querySelector("body > section > div > div.video-detail > div.video-meta-panel > div > div:nth-child(2) > nav > div.review-buttons");
if (!container) {
setTimeout(ensure, 200);
return;
}
if (container.__jhsObserved) return;
container.__jhsObserved = true;
self._wantWatchedObserved = true;
self._lastWantState = self.detectWantWatchedState(container);
new MutationObserver(() => {
if (self._wantWatchedSyncing) return;
clearTimeout(self._wantWatchedDebounce);
self._wantWatchedDebounce = setTimeout(() => {
self._wantWatchedSyncing = true;
try {
const currentState = self.detectWantWatchedState(container);
const lastState = self._lastWantState || {
want: false,
watched: false
};
if (currentState.want !== lastState.want) if (currentState.want) self.onWantAdded();
else self.onWantRemoved();
if (currentState.watched !== lastState.watched) if (currentState.watched) self.onWatchedAdded();
else self.onWatchedRemoved();
self._lastWantState = currentState;
} finally {
self._wantWatchedSyncing = false;
}
}, 150);
}).observe(container, {
childList: true,
subtree: true
});
};
ensure();
}
detectWantWatchedState(container) {
const wantTag = container.querySelector("a[href='/users/want_watch_videos'] .tag.is-info.is-light");
const watchedTag = container.querySelector("a[href='/users/watched_videos'] .tag.is-success.is-light");
return {
want: !!wantTag,
watched: !!watchedTag
};
}
async onWantAdded() {
const pageInfo = this.getPageInfo();
try {
const carRecord = await storageManager.getCar(pageInfo.carNum);
if (carRecord && carRecord.status === "favorite") {} else {
await storageManager.saveCar({
carNum: pageInfo.carNum,
url: pageInfo.url,
names: pageInfo.actress,
actionType: FAVORITE_ACTION,
publishTime: pageInfo.publishTime
});
this.broadcastWantWatchedSync({
carNum: pageInfo.carNum,
status: FAVORITE_ACTION,
op: "add"
});
show.ok(`${pageInfo.carNum} 已收藏`);
}
} catch (err) {
console.error("[JHS-想看自动同步] 写入失败", err);
}
this.showStatus(pageInfo.carNum).then();
}
async onWantRemoved() {
const pageInfo = this.getPageInfo();
try {
if (await this.removeCarIfStatus(pageInfo.carNum, "favorite")) {
this.broadcastWantWatchedSync({
carNum: pageInfo.carNum,
status: FAVORITE_ACTION,
op: "remove"
});
show.ok(`${pageInfo.carNum} 已取消收藏`);
}
} catch (err) {
console.error("[JHS-想看自动同步] 移除失败", err);
}
this.showStatus(pageInfo.carNum).then();
}
async onWatchedAdded() {
const pageInfo = this.getPageInfo();
try {
const carRecord = await storageManager.getCar(pageInfo.carNum);
if (carRecord && carRecord.status === "hasWatch") {} else {
await storageManager.saveCar({
carNum: pageInfo.carNum,
url: pageInfo.url,
names: pageInfo.actress,
actionType: HAS_WATCH_ACTION,
publishTime: pageInfo.publishTime
});
this.broadcastWantWatchedSync({
carNum: pageInfo.carNum,
status: HAS_WATCH_ACTION,
op: "add"
});
show.ok(`${pageInfo.carNum} 已标记看过`);
}
} catch (err) {
console.error("[JHS-观看自动同步] 写入失败", err);
}
this.showStatus(pageInfo.carNum).then();
}
async onWatchedRemoved() {
const pageInfo = this.getPageInfo();
try {
if (await this.removeCarIfStatus(pageInfo.carNum, "hasWatch")) {
this.broadcastWantWatchedSync({
carNum: pageInfo.carNum,
status: HAS_WATCH_ACTION,
op: "remove"
});
show.ok(`${pageInfo.carNum} 已取消看过`);
}
} catch (err) {
console.error("[JHS-观看自动同步] 移除失败", err);
}
this.showStatus(pageInfo.carNum).then();
}
async removeCarIfStatus(carNum, status) {
const carRecord = await storageManager.getCar(carNum);
if (!carRecord) return false;
if (carRecord.status !== status) return false;
return await storageManager.removeCar(carNum);
}
broadcastWantWatchedSync(payload) {
try {
const json = JSON.stringify({
...payload,
time: Date.now()
});
try {
GM_setValue("jdb:want-watched-sync", json);
} catch {}
try {
localStorage.setItem("jdb:want-watched-sync", json);
} catch {}
try {
document.dispatchEvent(new CustomEvent("jdb:want-watched-sync", { detail: payload }));
} catch {}
} catch (err) {
console.error("[JHS-想看/观看同步] 广播失败", err);
}
}
setupWantWatchedSyncListener() {
if (!isJavdbSite) return;
if (this._wantWatchedListenerInstalled) return;
this._wantWatchedListenerInstalled = true;
const self = this;
const handleSync = (rawData) => {
const payload = rawData && rawData.detail || (() => {
try {
return JSON.parse(rawData);
} catch {
return null;
}
})();
if (!payload || !payload.carNum) return;
try {
const currentCarNum = self.getPageInfo().carNum;
if (currentCarNum && payload.carNum === currentCarNum) self.showStatus(currentCarNum).then(() => {});
} catch {}
self.refreshItemStatusTag(payload.carNum);
};
document.addEventListener("jdb:want-watched-sync", (event) => handleSync(event.detail));
window.addEventListener("storage", (event) => {
if (event.key !== "jdb:want-watched-sync" || !event.newValue) return;
handleSync(event.newValue);
});
try {
GM_addValueChangeListener("jdb:want-watched-sync", (_name, _oldValue, newValue) => {
if (!newValue) return;
handleSync(newValue);
});
} catch {}
}
refreshItemStatusTag(carNum) {
try {
const itemSelector = this.getSelector().itemSelector;
const items = document.querySelectorAll(itemSelector);
for (const item of items) {
const strongEl = item.querySelector("a > div.video-title > strong");
if (!strongEl || strongEl.innerHTML !== carNum) continue;
const listPagePlugin = this.getBean("ListPagePlugin");
if (!listPagePlugin) continue;
listPagePlugin.renderItemStatusTag(item, carNum);
}
} catch (err) {
console.error("[JHS-想看/观看] 刷新列表项 status-tag 失败", err);
}
}
addQuickActionButtons() {
if (!window.isDetailPage) return;
if (this._quickActionAdded) return;
this._quickActionAdded = true;
const self = this;
this._injectRatingStyles();
const ensure = () => {
const nav = document.querySelector("body > section > div > div.video-detail > div.video-meta-panel > div > div:nth-child(2) > nav");
if (!nav) {
setTimeout(ensure, 400);
return;
}
self._buildRatingBar(nav);
self._syncRatingBar();
self._ensureListPanel(nav);
const rb = nav.querySelector(".review-buttons");
if (rb && !rb.__jhsRatingObserved) {
rb.__jhsRatingObserved = true;
new MutationObserver(() => {
if (self._wantWatchedSyncing) return;
clearTimeout(self._ratingSyncDebounce);
self._ratingSyncDebounce = setTimeout(() => {
self._buildRatingBar(nav);
self._syncRatingBar();
}, 200);
}).observe(rb, {
childList: true,
subtree: true
});
}
};
ensure();
}
_buildRatingBar(nav) {
const column = nav.querySelector("div.review-buttons > div:nth-child(1) > div > div");
if (!column) return;
if (column.querySelector(".jhs-rating-bar")) return;
const self = this;
const bar = document.createElement("div");
bar.className = "jhs-rating-bar";
bar.innerHTML = jsxToString((0, import_jsx_runtime.jsx)(RatingBarHtml, {}));
const starsEl = bar.querySelector(".jhs-stars");
const stars = bar.querySelectorAll(".jhs-star");
const readBtn = bar.querySelector(".jhs-read-btn");
const favBtn = bar.querySelector(".jhs-fav-btn");
starsEl.addEventListener("pointerover", (e) => {
const star = e.target.closest(".jhs-star");
if (!star) return;
const score = +star.dataset.score;
stars.forEach((s, i) => s.classList.toggle("is-preview", i < score));
});
starsEl.addEventListener("pointerleave", () => stars.forEach((s) => s.classList.remove("is-preview")));
stars.forEach((star) => {
star.addEventListener("click", async (e) => {
e.preventDefault();
const score = +star.dataset.score;
star.classList.add("is-popping");
setTimeout(() => star.classList.remove("is-popping"), 300);
self._setRatingBusy(true);
try {
await self.quickSetHasWatch(score);
} finally {
self._setRatingBusy(false);
self.showStatus(self.getPageInfo().carNum).then();
}
});
});
readBtn.addEventListener("click", async (e) => {
e.preventDefault();
readBtn.classList.add("is-popping");
setTimeout(() => readBtn.classList.remove("is-popping"), 300);
self._setRatingBusy(true);
try {
await self.quickSetHasWatch(0);
} finally {
self._setRatingBusy(false);
self.showStatus(self.getPageInfo().carNum).then();
}
});
favBtn.addEventListener("click", async (e) => {
e.preventDefault();
favBtn.classList.add("is-popping");
setTimeout(() => favBtn.classList.remove("is-popping"), 300);
self._setRatingBusy(true);
try {
await self.quickConvertToFav();
} finally {
self._setRatingBusy(false);
self.showStatus(self.getPageInfo().carNum).then();
}
});
column.insertBefore(bar, column.firstChild);
}
_ensureListPanel(nav) {
if (this._listPanelEnsured) return;
const otherSite = nav.querySelector("#otherSiteBox");
if (!otherSite) {
setTimeout(() => this._ensureListPanel(nav), 400);
return;
}
this._listPanelEnsured = true;
const self = this;
if (!nav.querySelector(".jhs-list-panel")) otherSite.insertAdjacentHTML("afterend", jsxToString((0, import_jsx_runtime.jsx)(ListPanel, {})));
self._initListPanel();
const listPanel = nav.querySelector(".jhs-list-panel");
if (listPanel && !listPanel.__jhsListClickBound) {
listPanel.__jhsListClickBound = true;
listPanel.addEventListener("change", (e) => {
if (e.target.type !== "checkbox") return;
const listContainer = document.querySelector("#modal-save-list")?.querySelector("[data-list-target=\"listContainer\"]");
if (!listContainer) return;
const idx = Array.from(listPanel.querySelectorAll("input[type=\"checkbox\"]")).indexOf(e.target);
const target = listContainer.querySelectorAll("input[type=\"checkbox\"]")[idx];
if (target) {
target.checked = e.target.checked;
target.dispatchEvent(new Event("change", { bubbles: true }));
}
});
}
}
_initListPanel() {
if (this._listPanelIniting) return;
this._listPanelIniting = true;
const self = this;
const ensure = () => {
const btn = document.querySelector("#save-list-button");
const modal = document.querySelector("#modal-save-list");
if (!btn || !modal) {
setTimeout(ensure, 400);
return;
}
const listContainer = modal.querySelector("[data-list-target=\"listContainer\"]");
if (!listContainer) return;
if (!self._listAjaxTriggered) {
self._listAjaxTriggered = true;
btn.click();
}
if (!listContainer.__jhsListObserved) {
listContainer.__jhsListObserved = true;
const sync = () => {
const panel = document.querySelector(".jhs-list-panel");
if (!panel) return;
panel.innerHTML = "";
Array.from(listContainer.children).forEach((child) => {
if (child.textContent.includes("預設清單")) return;
const clone = child.cloneNode(true);
panel.appendChild(clone);
});
};
new MutationObserver(sync).observe(listContainer, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ["checked", "disabled"]
});
setTimeout(sync, 500);
}
};
ensure();
}
_injectRatingStyles() {
if (document.getElementById("jhs-rating-styles")) return;
const style = document.createElement("style");
style.id = "jhs-rating-styles";
style.textContent = rating_bar_default;
document.head?.appendChild(style);
}
_syncRatingBar() {
let bar = document.querySelector(".jhs-rating-bar");
if (!bar) {
const nav = document.querySelector("body > section > div > div.video-detail > div.video-meta-panel > div > div:nth-child(2) > nav");
if (nav) this._buildRatingBar(nav);
bar = document.querySelector(".jhs-rating-bar");
}
if (!bar) return;
const rb = document.querySelector(".review-buttons");
if (!rb) return;
const want = !!rb.querySelector("a[href='/users/want_watch_videos'] .tag.is-info.is-light");
const watched = !!rb.querySelector("a[href='/users/watched_videos'] .tag.is-success.is-light");
const checked = rb.querySelector("input[name=\"video_review[score]\"][checked]");
const score = checked ? +checked.value : 0;
const stars = bar.querySelectorAll(".jhs-star");
const starsEl = bar.querySelector(".jhs-stars");
const readBtn = bar.querySelector(".jhs-read-btn");
const favBtn = bar.querySelector(".jhs-fav-btn");
if (want) {
stars.forEach((s) => s.classList.remove("is-active"));
starsEl.classList.remove("is-disabled");
readBtn.classList.remove("is-active");
favBtn.classList.add("is-active");
} else if (watched) {
stars.forEach((s, i) => s.classList.toggle("is-active", i < score));
starsEl.classList.remove("is-disabled");
readBtn.classList.toggle("is-active", score === 0);
favBtn.classList.remove("is-active");
} else {
stars.forEach((s) => s.classList.remove("is-active"));
starsEl.classList.remove("is-disabled");
readBtn.classList.remove("is-active");
favBtn.classList.remove("is-active");
}
}
_setRatingBusy(busy) {
const bar = document.querySelector(".jhs-rating-bar");
if (bar) bar.classList.toggle("is-busy", busy);
}
async quickSetHasWatch(score) {
const pageInfo = this.getPageInfo();
if (!pageInfo.carNum) return;
try {
const carRecord = await storageManager.getCar(pageInfo.carNum);
if (carRecord && carRecord.status === "favorite") await storageManager.removeCar(pageInfo.carNum);
if (carRecord && carRecord.status === "hasWatch" && carRecord.score === score) {
show.ok(pageInfo.carNum + " 评分未变化");
return;
}
await storageManager.saveCar({
carNum: pageInfo.carNum,
url: pageInfo.url,
names: pageInfo.actress,
actionType: HAS_WATCH_ACTION,
publishTime: pageInfo.publishTime,
score
});
this.broadcastWantWatchedSync({
carNum: pageInfo.carNum,
status: HAS_WATCH_ACTION,
op: "add"
});
show.ok(pageInfo.carNum + " 已标记看过 " + (score > 0 ? "★" + score : ""));
} catch (err) {
console.error("[JHS-快键] 设为已观看失败", err);
show.error("操作失败: " + err.message);
return;
}
this._reviewChain = (this._reviewChain || Promise.resolve()).then(async () => {
this._wantWatchedSyncing = true;
try {
await this._triggerJavdbReview(score);
this._syncRatingBar();
} finally {
this._wantWatchedSyncing = false;
}
}).catch(() => {});
}
_getCsrfToken() {
const meta = document.querySelector("meta[name=\"csrf-token\"]");
return meta ? meta.content : null;
}
_getVideoId() {
return location.pathname.match(/\/v\/([^/]+)/)?.[1] || null;
}
_getReviewId() {
const del = document.querySelector(".review-buttons a[data-method='delete'][href*='/reviews/']");
if (!del) return null;
return del.getAttribute("href")?.match(/\/reviews\/(\d+)/)?.[1] || null;
}
_execRailsJs(jsText) {
try {
const script = document.createElement("script");
script.textContent = jsText;
document.head?.appendChild(script);
script.remove();
} catch (err) {
console.error("[JHS-快键] 执行 Rails JS 失败", err);
}
}
async _javdbReviewApi(action, score = 0) {
const token = this._getCsrfToken();
if (!token) throw new Error("无法获取 CSRF token");
const videoId = this._getVideoId();
if (!videoId) throw new Error("无法获取 videoId");
const reviewId = this._getReviewId();
const headers = {
"Content-Type": "application/x-www-form-urlencoded",
"X-CSRF-Token": token
};
const tokenParam = `authenticity_token=${encodeURIComponent(token)}`;
if (action === "watched") {
const url = reviewId ? `/v/${videoId}/reviews/${reviewId}` : `/v/${videoId}/reviews`;
const body = `${tokenParam}${reviewId ? "&_method=patch" : ""}&video_review[status]=watched&video_review[score]=${score}&video_review[content]=`;
const res = await fetch(url, {
method: "POST",
headers,
body,
credentials: "same-origin"
});
if (!res.ok) throw new Error(`设为已观看失败: HTTP ${res.status}`);
this._execRailsJs(await res.text());
} else if (action === "wanted") {
if (reviewId) {
const delRes = await fetch(`/v/${videoId}/reviews/${reviewId}`, {
method: "POST",
headers,
body: `${tokenParam}&_method=delete`,
credentials: "same-origin"
});
if (!delRes.ok) throw new Error(`删除旧评价失败: HTTP ${delRes.status}`);
this._execRailsJs(await delRes.text());
}
const res = await fetch(`/v/${videoId}/reviews/want_to_watch`, {
method: "POST",
headers,
body: tokenParam,
credentials: "same-origin"
});
if (!res.ok) throw new Error(`设为想看失败: HTTP ${res.status}`);
this._execRailsJs(await res.text());
}
const rb = document.querySelector(".review-buttons");
if (rb && this._wantWatchedObserved) this._lastWantState = this.detectWantWatchedState(rb);
}
async _triggerJavdbReview(score) {
await this._javdbReviewApi("watched", score);
}
_waitForDomChange(selector, ms) {
return new Promise((resolve) => {
const start = Date.now();
const el = document.querySelector(selector);
if (!el) {
resolve(null);
return;
}
const before = el.innerHTML;
const check = () => {
const cur = document.querySelector(selector);
if (!cur) {
resolve(null);
return;
}
if (cur.innerHTML !== before) {
resolve(cur);
return;
}
if (Date.now() - start > ms) {
resolve(cur);
return;
}
setTimeout(check, 200);
};
setTimeout(check, 200);
});
}
_waitForEl(fn, ms) {
return new Promise((resolve) => {
const start = Date.now();
const check = () => {
const el = fn();
if (el) {
resolve(el);
return;
}
if (Date.now() - start > ms) {
resolve(null);
return;
}
setTimeout(check, 150);
};
check();
});
}
async quickConvertToFav() {
const pageInfo = this.getPageInfo();
if (!pageInfo.carNum) return;
try {
const carRecord = await storageManager.getCar(pageInfo.carNum);
if (carRecord && carRecord.status === "favorite") {
show.ok(pageInfo.carNum + " 已是已收藏");
return;
}
if (carRecord) await storageManager.removeCar(pageInfo.carNum);
await storageManager.saveCar({
carNum: pageInfo.carNum,
url: pageInfo.url,
names: pageInfo.actress,
actionType: FAVORITE_ACTION,
publishTime: pageInfo.publishTime
});
this.broadcastWantWatchedSync({
carNum: pageInfo.carNum,
status: FAVORITE_ACTION,
op: "add"
});
show.ok(pageInfo.carNum + " 已转为收藏");
} catch (err) {
console.error("[JHS-快键] 转为已收藏失败", err);
show.error("操作失败: " + err.message);
return;
}
this._reviewChain = (this._reviewChain || Promise.resolve()).then(async () => {
this._wantWatchedSyncing = true;
try {
await this._triggerJavdbWant();
this._syncRatingBar();
} finally {
this._wantWatchedSyncing = false;
}
}).catch(() => {});
}
async _triggerJavdbWant() {
await this._javdbReviewApi("wanted");
}
async favoriteOne() {
const pageInfo = this.getPageInfo();
await storageManager.saveCar({
carNum: pageInfo.carNum,
url: pageInfo.url,
names: pageInfo.actress,
actionType: FAVORITE_ACTION,
publishTime: pageInfo.publishTime
});
this.showStatus(pageInfo.carNum).then();
refresh();
utils.closePage();
}
async hasWatchOne() {
const pageInfo = this.getPageInfo();
await storageManager.saveCar({
carNum: pageInfo.carNum,
url: pageInfo.url,
names: pageInfo.actress,
actionType: HAS_WATCH_ACTION,
publishTime: pageInfo.publishTime
});
this.showStatus(pageInfo.carNum).then();
refresh();
utils.closePage();
}
searchXunLeiSubtitle(carNum) {
const loadingHandle = loading();
gmHttp.get(`https://api-shoulei-ssl.xunlei.com/oracle/subtitle?gcid=&cid=&name=${carNum}`).then((response) => {
const subtitleList = response.data;
if (subtitleList && subtitleList.length !== 0) layer.open({
type: 1,
title: "迅雷字幕",
content: jsxToString((0, import_jsx_runtime.jsx)(SubtitleTableDialog, {})),
scrollbar: false,
area: utils.getResponsiveArea(["60%", "70%"]),
anim: -1,
success: (_layero, index) => {
new Tabulator("#xunlei-table-container", {
layout: "fitColumns",
placeholder: "暂无数据",
virtualDom: true,
data: subtitleList,
responsiveLayout: "collapse",
responsiveLayoutCollapse: true,
columnDefaults: {
headerHozAlign: "center",
hozAlign: "center"
},
columns: [
{
title: "文件名",
field: "name",
headerSort: false,
responsive: 0
},
{
title: "类型",
field: "ext",
headerSort: false,
responsive: 0
},
{
title: "操作",
responsive: 0,
headerSort: false,
formatter: (cell, _formatterParams, onRendered) => {
const rowData = cell.getData();
onRendered(() => {
const previewBtn = cell.getElement().querySelector(".a-primary");
const downloadBtn = cell.getElement().querySelector(".a-success");
if (previewBtn) previewBtn.addEventListener("click", async (_event) => {
const subUrl = rowData.url;
const subFilename = carNum + "." + rowData.ext;
this.previewSubtitle(subUrl, subFilename);
});
if (downloadBtn) downloadBtn.addEventListener("click", async (_event) => {
const subUrl = rowData.url;
const subFilename = carNum + "." + rowData.ext;
const content = await gmHttp.get(subUrl);
utils.download(content, subFilename);
});
});
return jsxToString((0, import_jsx_runtime.jsx)(SubtitleActionCell, {}));
}
}
],
locale: "zh-cn",
langs: { "zh-cn": { pagination: {
first: "首页",
first_title: "首页",
last: "尾页",
last_title: "尾页",
prev: "上一页",
prev_title: "上一页",
next: "下一页",
next_title: "下一页",
all: "所有",
page_size: "每页行数"
} } }
});
utils.setupEscClose(index);
}
});
else show.error("迅雷中找不到相关字幕!");
}).catch((err) => {
console.error(err);
show.error(err);
}).finally(() => {
loadingHandle.close();
});
}
async filterOne(event, force) {
if (event) event.preventDefault();
const pageInfo = this.getPageInfo();
if (force) {
await storageManager.saveCar({
carNum: pageInfo.carNum,
url: pageInfo.url,
names: pageInfo.actress,
actionType: FILTER_ACTION,
publishTime: pageInfo.publishTime
});
this.showStatus(pageInfo.carNum).then();
refresh();
utils.closePage();
layer.closeAll();
this.answerCount = 1;
} else utils.q(event, `是否屏蔽${pageInfo.carNum}?`, async () => {
await storageManager.saveCar({
carNum: pageInfo.carNum,
url: pageInfo.url,
names: pageInfo.actress,
actionType: FILTER_ACTION,
publishTime: pageInfo.publishTime
});
this.showStatus(pageInfo.carNum).then();
refresh();
utils.closePage();
}, () => {
this.answerCount = 1;
});
}
speedVideo() {
if ($("#preview-video").is(":visible")) {
const videoEl = document.getElementById("preview-video");
if (videoEl) {
videoEl.muted = false;
videoEl.controls = false;
if (videoEl.currentTime + 5 < videoEl.duration) videoEl.currentTime += 5;
else {
show.info("预览视频结束, 已回到开头");
videoEl.currentTime = 1;
}
}
return;
}
const $iframe = $("iframe[id^=\"layui-layer-iframe\"]");
if ($iframe.length > 0) {
$iframe[0].contentWindow.postMessage("speedVideo", "*");
return;
}
const $container = $(".preview-video-container");
if ($container.length > 0) {
$container[0].click();
const videoEl = document.getElementById("preview-video");
if (videoEl) {
videoEl.currentTime += 5;
videoEl.muted = false;
}
} else $("#javTrailersBtn").click();
}
hideVideoControls() {
$(document).on("mouseenter", "#preview-video", function() {
$(this).prop("controls", true);
});
}
async bindHotkey() {
const hotkeyMap = {};
if (this.filterHotKey) hotkeyMap[this.filterHotKey] = () => {
if (this.answerCount >= 2) this.filterOne(null, true);
else this.filterOne(null);
this.answerCount++;
};
if (this.favoriteHotKey) hotkeyMap[this.favoriteHotKey] = () => this.favoriteOne();
if (this.hasWatchHotKey) hotkeyMap[this.hasWatchHotKey] = () => this.hasWatchOne();
if (this.speedVideoHotKey) hotkeyMap[this.speedVideoHotKey] = () => this.speedVideo();
const register = (hotkeyStr, callback) => {
Hotkey.registerHotkey(hotkeyStr, (_keyEvent) => {
const activeEl = document.activeElement;
if (activeEl.tagName !== "INPUT" && activeEl.tagName !== "TEXTAREA" && !activeEl.isContentEditable) if (window.isDetailPage) callback();
else ((key) => {
const $iframe = $(".layui-layer-content iframe");
if ($iframe.length !== 0) $iframe[0].contentWindow.postMessage(key, "*");
})(hotkeyStr);
});
};
if (window.isDetailPage) window.addEventListener("message", (messageEvent) => {
if (hotkeyMap[messageEvent.data]) hotkeyMap[messageEvent.data]();
});
Object.entries(hotkeyMap).forEach(([key, cb]) => {
register(key, cb);
});
}
async previewSubtitle(url, filename) {
if (!url) {
console.error("未提供文件URL");
return;
}
const ext = url.split(".").pop().toLowerCase();
if (ext === "ass" || ext === "srt") try {
const subtitleContent = await gmHttp.get(url);
let title = "字幕预览";
if (ext === "ass") title = "ASS字幕预览 - " + filename;
else if (ext === "srt") title = "SRT字幕预览 - " + filename;
const lines = subtitleContent.split("\n");
let output = "";
const numWidth = String(lines.length).length;
lines.forEach((line, idx) => {
const paddedNum = String(idx + 1).padStart(numWidth, " ");
output += jsxToString((0, import_jsx_runtime.jsx)(SubtitleLine, {
paddedNum,
line
}));
});
const htmlContent = output;
layer.open({
type: 1,
title,
area: ["80%", "80%"],
scrollbar: false,
content: jsxToString((0, import_jsx_runtime.jsx)(SubtitlePreviewDialog, { content: htmlContent })),
btn: ["下载", "关闭"],
btn1: function(_index, _layero, _instance) {
utils.download(subtitleContent, filename);
return false;
}
});
} catch (err) {
show.error(`预览失败: ${err.message}`);
console.error("预览字幕文件出错:", err);
}
else show.error("仅支持预览ASS和SRT字幕文件");
}
};
function parsePositionStyle(positionStyle) {
if (positionStyle.includes("right")) return {
right: 0,
top: "5px"
};
return {
left: 0,
top: "5px"
};
}
function StatusTagHtml({ text, color, dataTip, positionStyle }) {
const posStyle = parsePositionStyle(positionStyle);
return (0, import_jsx_runtime.jsx)("span", {
className: "tag is-success status-tag",
"data-tip": dataTip,
title: "",
style: {
marginRight: "5px",
borderRadius: "10px",
position: "absolute",
zIndex: 10,
backgroundColor: `${color} !important`,
...posStyle
},
children: text
});
}
function JumpPageControl({ controlId, value }) {
return (0, import_jsx_runtime.jsxs)("li", {
id: controlId,
children: [(0, import_jsx_runtime.jsx)("input", {
type: "number",
id: "jumpPageInput",
placeholder: "页码",
min: "1",
style: {
width: "60px",
marginLeft: "10px",
padding: "10px",
border: "1px solid #ccc",
fontSize: "14px"
},
value
}), (0, import_jsx_runtime.jsx)("button", {
style: {
marginLeft: "5px",
padding: "9px 8px",
cursor: "pointer",
border: "1px solid #ccc",
backgroundColor: "#f0f0f0",
fontSize: "14px"
},
children: "跳转"
})]
});
}
function PageCountTable({ readDataTime, assembleDataTime, processPageTime, totalTime, filterCount, favoriteCount, actorFilterCount, keywordFilterCount, hasWatchCount, waitCheckCount, totalCount }) {
const tableStyle = {
borderCollapse: "collapse",
width: "100%"
};
const tdStyle = {
padding: "3px",
border: "1px solid #ccc"
};
const tdBoldStyle = {
padding: "3px",
border: "1px solid #ccc",
fontWeight: "bold"
};
return (0, import_jsx_runtime.jsxs)("table", {
className: "countTable",
style: tableStyle,
children: [
(0, import_jsx_runtime.jsxs)("tr", { children: [(0, import_jsx_runtime.jsx)("td", {
colSpan: 2,
style: tdStyle,
children: readDataTime
}), (0, import_jsx_runtime.jsx)("td", {
colSpan: 2,
style: tdStyle,
children: assembleDataTime
})] }),
(0, import_jsx_runtime.jsxs)("tr", { children: [(0, import_jsx_runtime.jsx)("td", {
colSpan: 2,
style: tdStyle,
children: processPageTime
}), (0, import_jsx_runtime.jsx)("td", {
colSpan: 2,
style: tdStyle,
children: totalTime
})] }),
(0, import_jsx_runtime.jsxs)("tr", { children: [
(0, import_jsx_runtime.jsx)("td", {
style: tdBoldStyle,
children: "项目"
}),
(0, import_jsx_runtime.jsx)("td", {
style: tdBoldStyle,
children: "数量"
}),
(0, import_jsx_runtime.jsx)("td", {
style: tdBoldStyle,
children: "项目"
}),
(0, import_jsx_runtime.jsx)("td", {
style: tdBoldStyle,
children: "数量"
})
] }),
(0, import_jsx_runtime.jsxs)("tr", { children: [
(0, import_jsx_runtime.jsx)("td", {
style: tdStyle,
children: "屏蔽单番号"
}),
(0, import_jsx_runtime.jsx)("td", {
style: tdStyle,
children: (0, import_jsx_runtime.jsx)("strong", { children: filterCount })
}),
(0, import_jsx_runtime.jsx)("td", {
style: tdStyle,
children: "收藏"
}),
(0, import_jsx_runtime.jsx)("td", {
style: tdStyle,
children: (0, import_jsx_runtime.jsx)("strong", { children: favoriteCount })
})
] }),
(0, import_jsx_runtime.jsxs)("tr", { children: [(0, import_jsx_runtime.jsx)("td", {
style: tdStyle,
children: "屏蔽演员"
}), (0, import_jsx_runtime.jsx)("td", {
style: tdStyle,
children: (0, import_jsx_runtime.jsx)("strong", { children: actorFilterCount })
})] }),
(0, import_jsx_runtime.jsxs)("tr", { children: [
(0, import_jsx_runtime.jsx)("td", {
style: tdStyle,
children: "屏蔽关键词"
}),
(0, import_jsx_runtime.jsx)("td", {
style: tdStyle,
children: (0, import_jsx_runtime.jsx)("strong", { children: keywordFilterCount })
}),
(0, import_jsx_runtime.jsx)("td", {
style: tdStyle,
children: "已观看"
}),
(0, import_jsx_runtime.jsx)("td", {
style: tdStyle,
children: (0, import_jsx_runtime.jsx)("strong", { children: hasWatchCount })
})
] }),
(0, import_jsx_runtime.jsxs)("tr", { children: [
(0, import_jsx_runtime.jsx)("td", {
style: tdStyle,
children: "待鉴定"
}),
(0, import_jsx_runtime.jsx)("td", {
style: tdStyle,
children: (0, import_jsx_runtime.jsx)("strong", { children: waitCheckCount })
}),
(0, import_jsx_runtime.jsx)("td", { style: tdStyle }),
(0, import_jsx_runtime.jsx)("td", { style: tdStyle })
] }),
(0, import_jsx_runtime.jsxs)("tr", { children: [(0, import_jsx_runtime.jsx)("td", {
style: tdStyle,
children: (0, import_jsx_runtime.jsx)("strong", { children: "总数" })
}), (0, import_jsx_runtime.jsx)("td", {
style: tdStyle,
children: (0, import_jsx_runtime.jsx)("strong", { children: totalCount })
})] })
]
});
}
var STATUS_TAG_CONFIG = {
IS_FILTERED: {
text: BLOCKED_TEXT,
color: BLOCK_COLOR,
reasonType: "单番号屏蔽",
isCounted: true,
countKey: "currentPageFilterCount"
},
IS_FAVORITE: {
text: FAVORITED_TEXT,
color: FAVORITE_COLOR,
reasonType: "",
isCounted: true,
countKey: "currentPageFavoriteCount"
},
IS_HAS_WATCH: {
text: WATCHED_TEXT,
color: WATCHED_COLOR,
reasonType: "",
isCounted: true,
countKey: "currentPageHasWatchCount"
},
IS_KEYWORD_FILTER: {
text: "❌ 关键词屏蔽",
color: "#de3333",
reasonType: "",
isCounted: true,
countKey: "currentPageKeywordFilterCount"
},
IS_ACTOR_FILTER: {
text: "♂️ 男演员屏蔽",
color: "#b22222",
reasonType: "",
isCounted: true,
countKey: "currentPageActorFilterCount"
},
IS_ACTRESS_FILTER: {
text: "♀️ 女演员屏蔽",
color: "#cd5c5c",
reasonType: "",
isCounted: true,
countKey: "currentPageActorFilterCount"
},
IS_WAIT_CHECK: {
text: "",
color: "",
reasonType: "",
isCounted: true,
countKey: "currentPageWaitCheckCount"
}
};
async function translateText(text, sourceLang = "ja", targetLang = "zh-CN") {
if (!text) throw new Error("翻译文本不能为空");
const url = "https://translate-pa.googleapis.com/v1/translate?" + new URLSearchParams({
"params.client": "gtx",
dataTypes: "TRANSLATION",
key: "AIzaSyDLEeFI5OtFBwYBIoK_jj5m32rZK5CkCXA",
"query.sourceLanguage": sourceLang,
"query.targetLanguage": targetLang,
"query.text": text
});
const response = await fetch(url);
if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);
return (await response.json()).translation;
}
var ListPagePlugin = class extends BasePlugin {
currentPageFilterCount = 0;
currentPageFavoriteCount = 0;
currentPageHasWatchCount = 0;
currentPageKeywordFilterCount = 0;
currentPageActorFilterCount = 0;
currentPageWaitCheckCount = 0;
currentPageTotalCount = 0;
cache = localStorage.getItem("jhs_translate") ? JSON.parse(localStorage.getItem("jhs_translate")) : {};
writeQueue = Promise.resolve();
$currentImage = null;
filterHotKey;
favoriteHotKey;
hasWatchHotKey;
enableImageHotKey;
clogHotKey;
foldCategoryHotKey;
getName() {
return "ListPagePlugin";
}
async handle() {
new BroadcastChannel("channel-refresh").addEventListener("message", async (event) => {
const msgType = event.data.type;
if (msgType === "refresh") {
await this.doFilter();
const historyPlugin = this.getBean("HistoryPlugin");
if (historyPlugin.tableObj) historyPlugin.tableObj.setData();
const newVideoPlugin = this.getBean("NewVideoPlugin");
if (newVideoPlugin) {
newVideoPlugin.showNewVideoCount().then();
newVideoPlugin.loadData();
}
} else if (msgType === "cleanCache_filter_actor_actress_car_list") storageManager.clearFilterActorActressCarListCache();
else if (msgType === "clean_cacheSettingObj") storageManager.clearSettingCache();
});
this.replaceHdImg();
this.addJumpPageControl();
await this.doFilter();
this.bindClick().then();
this.bindListPageHotKey().then();
this.rememberTagExpand();
$(this.getSelector().itemSelector + " a").attr("target", "_blank");
this.checkDom();
this.getBean("DetailPageButtonPlugin").setupWantWatchedSyncListener();
}
rememberTagExpand() {
if (!window.location.href.includes("actors")) return;
const expandBtn = $(".tag-expand");
if (expandBtn.length === 0) return;
const storageKey = "jhs_tag_expand";
const wasExpanded = localStorage.getItem(storageKey) === "true";
const contentEl = $(".actor-tags .content");
if (wasExpanded && contentEl.hasClass("collapse")) expandBtn[0].click();
expandBtn.on("click", function() {
const isExpanded = !contentEl.hasClass("collapse");
console.log("触发");
localStorage.setItem(storageKey, isExpanded.toString());
});
}
checkDom() {
if (!window.isListPage) return;
const selectorConfig = this.getSelector();
const containerEl = document.querySelector(selectorConfig.boxSelector);
if (!containerEl) {
console.error("没有找到容器节点!");
return;
}
const observerOptions = {
childList: true,
subtree: false
};
const observer = new MutationObserver(async () => {
observer.disconnect();
try {
this.replaceHdImg();
this.addJumpPageControl();
await this.doFilter();
await this.getBean("ListPageButtonPlugin").sortItems();
$(this.getSelector().itemSelector + " a").attr("target", "_blank");
this.getBean("AutoPagePlugin").checkLoad();
} finally {
observer.observe(containerEl, observerOptions);
}
});
observer.observe(containerEl, observerOptions);
}
async doFilter() {
if (!window.isListPage) return;
const itemEls = $(this.getSelector().itemSelector).toArray();
if (itemEls.length) await this.filterMovieList(itemEls);
}
async renderItemStatusTag(item, carNum) {
try {
const $item = $(item);
const carInfo = await storageManager.getCar(carNum);
const status = carInfo ? carInfo.status : "";
$item.find(".status-tag").remove();
let tagConfig = null;
if (status === "favorite") tagConfig = STATUS_TAG_CONFIG.IS_FAVORITE;
else if (status === "hasWatch") tagConfig = STATUS_TAG_CONFIG.IS_HAS_WATCH;
else if (status === "filter") tagConfig = STATUS_TAG_CONFIG.IS_FILTERED;
if (!tagConfig || !tagConfig.text) return;
const positionStyle = ((await storageManager.getSetting()).tagPosition || "rightTop") === "rightTop" ? "right: 0; top:5px;" : "left: 0; top:5px;";
const tagHtml = jsxToString((0, import_jsx_runtime.jsx)(StatusTagHtml, {
variant: "render",
text: tagConfig.text,
color: tagConfig.color,
dataTip: tagConfig.reasonType,
positionStyle
}));
const tagsEl = $item.find(".tags");
if (tagsEl.length) {
tagsEl.append(tagHtml);
return;
}
const itemTagEl = $item.find(".item-tag");
if (itemTagEl.length) {
itemTagEl.append(tagHtml);
return;
}
$item.find(".photo-info > span > div").append(tagHtml);
} catch (err) {
console.error("[JHS-想看/观看] renderItemStatusTag 失败", err);
}
}
async filterMovieList(itemEls) {
utils.time("累计耗费时间");
utils.time("读取数据耗时");
const [carList, titleFilterKeywords, blacklist, blacklistCarList, setting] = await Promise.all([
storageManager.getCarList(),
storageManager.getTitleFilterKeyword(),
storageManager.getBlacklist(),
storageManager.getBlacklistCarList(),
storageManager.getSetting()
]);
const readDataTime = utils.time("读取数据耗时");
const statusCarSets = carList.reduce((acc, car) => {
const status = car.status;
if (acc.hasOwnProperty(status)) acc[status].add(car.carNum);
return acc;
}, {
[FILTER_ACTION]: new Set(),
[FAVORITE_ACTION]: new Set(),
[HAS_WATCH_ACTION]: new Set()
});
utils.time("组装数据耗时");
const blacklistRoleMap = new Map(blacklist.map((item) => [item.starId, item.role]));
const { actorCarNumToNameMap, actressCarNumToNameMap } = blacklistCarList.reduce((acc, item) => {
const role = blacklistRoleMap.get(item.starId);
if (!role) {
clog.error("黑名单数据源丢失演员信息", item);
return acc;
}
const targetMap = role === "actor" ? acc.actorCarNumToNameMap : acc.actressCarNumToNameMap;
if (!targetMap.has(item.carNum)) targetMap.set(item.carNum, item.names);
return acc;
}, {
actorCarNumToNameMap: new Map(),
actressCarNumToNameMap: new Map()
});
const assembleDataTime = utils.time("组装数据耗时");
const showFilterItem = setting?.showFilterItem ?? "no";
const showFilterActorItem = setting?.showFilterActorItem ?? "no";
const showFilterKeywordItem = setting?.showFilterKeywordItem ?? "no";
const showFavoriteItem = setting?.showFavoriteItem ?? "yes";
const showHasWatchItem = setting?.showHasWatchItem ?? "yes";
const showAllItem = setting?.showAllItem ?? "no";
const tagPosition = setting?.tagPosition || "rightTop";
this.currentPageFilterCount = 0;
this.currentPageFavoriteCount = 0;
this.currentPageHasWatchCount = 0;
this.currentPageKeywordFilterCount = 0;
this.currentPageActorFilterCount = 0;
this.currentPageWaitCheckCount = 0;
this.currentPageTotalCount = 0;
utils.time("处理页面耗时");
await Promise.all(itemEls.map(async (itemEl) => {
const $item = $(itemEl);
const { carNum, title } = this.findCarNumAndHref($item);
const { filter: filterSet, favorite: favoriteSet, hasWatch: hasWatchSet } = statusCarSets;
const isFavorite = favoriteSet.has(carNum);
const isHasWatch = hasWatchSet.has(carNum);
const isFiltered = filterSet.has(carNum);
const isActorBlacklist = actorCarNumToNameMap.has(carNum);
const isActressBlacklist = actressCarNumToNameMap.has(carNum);
const isBlacklistActor = isActorBlacklist || isActressBlacklist;
const matchedKeyword = titleFilterKeywords.find((keyword) => title.includes(keyword) || carNum.startsWith(keyword));
const hasKeywordMatch = !!matchedKeyword;
if (!isSearchOrUserPage) {
let shouldHide = showFavoriteItem === "no" && isFavorite || showHasWatchItem === "no" && isHasWatch || showFilterItem === "no" && isFiltered && !isFavorite && !isHasWatch || showFilterActorItem === "no" && isBlacklistActor || showFilterKeywordItem === "no" && hasKeywordMatch;
const isHidden = $item.attr("data-hide") === "yes";
if (showAllItem === "yes") shouldHide = false;
if (shouldHide && !isHidden) $item.hide().attr("data-hide", "yes");
else if (!shouldHide && isHidden) $item.show().removeAttr("data-hide");
}
let tagConfig = STATUS_TAG_CONFIG.IS_WAIT_CHECK;
let reasonText = null;
if (isFiltered) tagConfig = STATUS_TAG_CONFIG.IS_FILTERED;
else if (isFavorite) tagConfig = STATUS_TAG_CONFIG.IS_FAVORITE;
else if (isHasWatch) tagConfig = STATUS_TAG_CONFIG.IS_HAS_WATCH;
else if (hasKeywordMatch) {
tagConfig = STATUS_TAG_CONFIG.IS_KEYWORD_FILTER;
reasonText = matchedKeyword || "未知";
} else if (isActorBlacklist) {
tagConfig = STATUS_TAG_CONFIG.IS_ACTOR_FILTER;
reasonText = actorCarNumToNameMap.get(carNum) || "";
} else if (isActressBlacklist) {
tagConfig = STATUS_TAG_CONFIG.IS_ACTRESS_FILTER;
reasonText = actressCarNumToNameMap.get(carNum) || "";
}
reasonText ||= tagConfig.reasonType;
if (tagConfig.isCounted) this[tagConfig.countKey]++;
this.currentPageTotalCount++;
$item.find(".status-tag").remove();
const positionStyle = tagPosition === "rightTop" ? "right: 0; top:5px;" : "left: 0; top:5px;";
if (tagConfig.text) {
const tagHtml = jsxToString((0, import_jsx_runtime.jsx)(StatusTagHtml, {
variant: "filter",
text: tagConfig.text,
color: tagConfig.color,
dataTip: reasonText,
positionStyle
}));
if (isJavdbSite) $item.find(".tags").append(tagHtml);
}
await this.translate($item);
}));
const processPageTime = utils.time("处理页面耗时");
const totalTime = utils.time("累计耗费时间");
$("#waitDownBtn span").text(`打开已收藏 (${statusCarSets.favorite.size})`);
clog.log(jsxToString((0, import_jsx_runtime.jsx)(PageCountTable, {
readDataTime,
assembleDataTime,
processPageTime,
totalTime,
filterCount: this.currentPageFilterCount,
favoriteCount: this.currentPageFavoriteCount,
actorFilterCount: this.currentPageActorFilterCount,
keywordFilterCount: this.currentPageKeywordFilterCount,
hasWatchCount: this.currentPageHasWatchCount,
waitCheckCount: this.currentPageWaitCheckCount,
totalCount: this.currentPageTotalCount
})));
}
async bindClick() {
const selectorConfig = this.getSelector();
$(selectorConfig.boxSelector).on("click", ".item img", async (event) => {
event.preventDefault();
event.stopPropagation();
if ($(event.target).closest("div.meta-buttons").length) return;
const $item = $(event.target).closest(".item");
const { carNum, aHref } = this.findCarNumAndHref($item);
const dialogOpenDetail = await storageManager.getSetting("dialogOpenDetail", "yes");
if (carNum.includes("FC2-")) {
const movieId = this.parseMovieId(aHref);
this.getBean("Fc2Plugin")?.openFc2Dialog(movieId, carNum, aHref);
} else if (dialogOpenDetail === "yes") {
utils.openPage(aHref, carNum, true, event);
this.$currentImage = null;
} else window.open(aHref);
});
$(selectorConfig.boxSelector).on("click", ".item video", async (event) => {
const videoEl = event.currentTarget;
if (videoEl.paused) videoEl.play().catch((err) => console.error("播放失败:", err));
else videoEl.pause();
event.preventDefault();
event.stopPropagation();
});
$(selectorConfig.boxSelector).on("click", ".item .video-title", async (event) => {
if ($(event.target).closest("[class^=\"jhs-match-\"]").length) return;
const $item = $(event.currentTarget).closest(".item");
const { carNum, aHref } = this.findCarNumAndHref($item);
if (carNum.includes("FC2-")) {
event.preventDefault();
const movieId = this.parseMovieId(aHref);
this.getBean("Fc2Plugin")?.openFc2Dialog(movieId, carNum, aHref);
}
});
$(selectorConfig.boxSelector).on("contextmenu", ".item img, .item video", async (event) => {
event.preventDefault();
const $item = $(event.target).closest(".item");
const { carNum, url, publishTime } = this.findCarNumAndHref($item);
const nameEl = $(".actor-section-name");
let actressName = "";
if (nameEl.length) actressName = nameEl.text().trim().split(",")[0].replace("(無碼)", "");
utils.q(event, `是否屏蔽番号 ${carNum}?`, async () => {
setTimeout(async () => {
actressName ||= await this.parseActressName(url);
await storageManager.saveCar({
carNum,
url,
names: actressName,
actionType: FILTER_ACTION,
publishTime
});
refresh();
show.ok("操作成功");
});
});
});
}
async parseActressName(url) {
let actressName = null;
if (await storageManager.getSetting("enableSaveActressCarInfo", "no") === "yes") {
clog.debug("鉴定补录演员信息-已启用, 开始解析详情页");
clog.debug("开始解析演员详情页", url);
const html = await gmHttp.get(url);
const $dom = utils.htmlTo$dom(html);
if (isJavdbSite) actressName = $dom.find(".female").prev().map((_index, el) => $(el).text()).get().join(" ");
clog.debug("解析到名称:", actressName);
}
return actressName;
}
async bindListPageHotKey() {
this.$currentImage = null;
$(document).on("mouseenter", this.getSelector().coverImgSelector, (event) => {
this.$currentImage = $(event.currentTarget);
}).on("mouseleave", this.getSelector().coverImgSelector, () => {
this.$currentImage = null;
});
const setting = await storageManager.getSetting();
this.filterHotKey = setting.filterHotKey;
this.favoriteHotKey = setting.favoriteHotKey;
this.hasWatchHotKey = setting.hasWatchHotKey;
this.enableImageHotKey = setting.enableImageHotKey || "no";
this.clogHotKey = setting.clogHotKey;
this.foldCategoryHotKey = setting.foldCategoryHotKey;
if (this.enableImageHotKey === "no") return;
const saveCarByHotkey = async (carInfo, actionType) => {
setTimeout(async () => {
const names = await this.parseActressName(carInfo.url);
await storageManager.saveCar({
carNum: carInfo.carNum,
url: carInfo.url,
names,
actionType,
publishTime: carInfo.publishTime
});
refresh();
show.ok("操作成功");
});
};
const hotkeyHandlers = {};
if (this.filterHotKey) hotkeyHandlers[this.filterHotKey] = (carInfo) => {
saveCarByHotkey(carInfo, FILTER_ACTION);
};
if (this.favoriteHotKey) hotkeyHandlers[this.favoriteHotKey] = (carInfo) => {
saveCarByHotkey(carInfo, FAVORITE_ACTION);
};
if (this.hasWatchHotKey) hotkeyHandlers[this.hasWatchHotKey] = (carInfo) => {
saveCarByHotkey(carInfo, HAS_WATCH_ACTION);
};
if (this.clogHotKey) Hotkey.registerHotkey(this.clogHotKey, () => {
clog.toggleExpandCollapsed();
});
if (this.foldCategoryHotKey) Hotkey.registerHotkey(this.foldCategoryHotKey, () => {
const foldBtn = $("#foldCategoryBtn");
if (foldBtn.length) foldBtn[0].click();
});
const registerImageHotkey = (hotkey, handler) => {
Hotkey.registerHotkey(hotkey, () => {
const activeEl = document.activeElement;
if (activeEl.tagName !== "INPUT" && activeEl.tagName !== "TEXTAREA" && !activeEl.isContentEditable && this.$currentImage) {
const $item = this.$currentImage.closest(".item");
handler(this.findCarNumAndHref($item));
}
});
};
Object.entries(hotkeyHandlers).forEach(([hotkey, handler]) => {
registerImageHotkey(hotkey, handler);
});
}
findCarNumAndHref($item) {
let carNum;
let title;
let publishTime;
const linkEl = $item.find("a");
const aHref = linkEl.attr("href");
const videoTitleEl = $item.find(".video-title");
if (videoTitleEl.length > 0) {
const strongEl = videoTitleEl.find("strong");
if (strongEl.length > 0) carNum = strongEl.text().trim();
title = linkEl.attr("title") ? linkEl.attr("title").trim() : carNum ? videoTitleEl.text().replace(carNum, "").trim() : videoTitleEl.text().trim();
publishTime = $item.find(".meta").text().trim();
}
if (!carNum) {
const imgEl = $item.find("img");
if (aHref && imgEl.length > 0) title = imgEl.attr("title")?.trim() || imgEl.attr("data-title")?.trim();
const isDate = (val) => /^\d{4}-\d{1,2}-\d{1,2}$/.test(val);
publishTime = $item.find("date").map((_index, el) => $(el).text().trim()).get().find(isDate);
carNum = $item.find("date").map((_index, el) => $(el).text().trim()).get().find((val) => !isDate(val));
}
if (!carNum) {
const errorMsg = "提取番号信息失败";
show.error(errorMsg);
throw new Error(errorMsg);
}
return {
carNum,
aHref: aHref || "",
url: aHref || "",
title: title || "",
publishTime: publishTime || ""
};
}
showCarNumBox(carNum) {
const matchedEl = $(".movie-list .item").toArray().find((itemEl) => $(itemEl).find(".video-title strong").text() === carNum);
if (matchedEl) {
const $matched = $(matchedEl);
if ($matched.attr("data-hide") === `${carNum}-hide`) {
$matched.show();
$matched.removeAttr("data-hide");
}
}
}
replaceHdImg(imgEls) {
if (imgEls && typeof imgEls.jquery == "string") imgEls = imgEls.toArray();
imgEls ||= document.querySelectorAll(this.getSelector().coverImgSelector);
if (isJavdbSite) imgEls.forEach((img) => {
img.src = img.src.replace("thumbs", "covers");
img.title = "";
});
storageManager.getSetting("hoverBigImg", "no").then((setting) => {
if (setting === "yes") {
const win = window;
if (win.imageHoverPreviewObj) win.imageHoverPreviewObj.bindEvents();
else win.imageHoverPreviewObj = new ImagePreview({ selector: this.getSelector().coverImgSelector });
}
});
}
async translate($item) {
if (await storageManager.getSetting("translateTitle", "yes") !== "yes") return;
let sourceText;
let carNum;
const videoTitleEl = $item.find(".video-title");
if (isJavdbSite) {
sourceText = videoTitleEl.contents().filter((_index, node) => node.nodeType === 3 && node.textContent.trim() !== "").text().trim();
carNum = $item.find(".video-title strong").text().trim();
}
if (this.cache[carNum]) {
videoTitleEl.contents().each((_index, node) => {
if (node.nodeType === 3 && node.textContent.trim() !== "") node.textContent = " " + this.cache[carNum] + " ";
});
videoTitleEl.attr("title", this.cache[carNum]);
return;
}
translateText(sourceText).then((translation) => {
if (isJavdbSite) {
videoTitleEl.contents().each((_index, node) => {
if (node.nodeType === 3 && node.textContent.trim() !== "" && !node.textContent.includes(carNum)) node.textContent = " " + translation + " ";
});
videoTitleEl.attr("title", translation);
}
this.writeQueue = this.writeQueue.then(() => {
this.cache[carNum] = translation;
localStorage.setItem("jhs_translate", JSON.stringify(this.cache));
});
}).catch((err) => {
console.error("翻译失败:", err);
});
}
async revertTranslation() {
$(this.getSelector().itemSelector).toArray().forEach((itemEl) => {
const $item = $(itemEl);
const originalTitle = $item.find(".box").attr("title") || $item.find(".video-title").attr("title") || $item.find("img").attr("data-title");
const carNum = $item.find(".video-title strong").text().trim();
const videoTitleEl = $item.find(".video-title");
videoTitleEl.contents().each((_index, node) => {
if (node.nodeType === 3 && node.textContent.trim() !== "" && !node.textContent.includes(carNum)) node.textContent = " " + originalTitle + " ";
});
videoTitleEl.removeAttr("title");
});
}
addJumpPageControl() {
const controlId = "gemini-jump-page-control";
if ($("#gemini-jump-page-control").length > 0) return;
if ($(".pagination-link.is-current").length === 0) return;
const currentPage = utils.getUrlParam(currentHref, "page") || 1;
const $li = $(jsxToString((0, import_jsx_runtime.jsx)(JumpPageControl, {
controlId,
value: currentPage + 1
})));
$(".pagination-list").append($li);
const $pageInput = $li.find("#jumpPageInput");
const $jumpBtn = $li.find("button");
const jumpToPage = () => {
const pageNum = parseInt($pageInput.val(), 10);
if (isNaN(pageNum) || pageNum < 1) {
$pageInput.focus();
return;
}
const url = new URL(window.location.href);
url.searchParams.set("page", pageNum.toString());
window.location.href = url.toString();
};
$jumpBtn.on("click", jumpToPage);
$pageInput.on("keypress", (event) => {
if (event.which === 13) {
jumpToPage();
event.preventDefault();
}
});
}
};
function PreviewVideoActionBtn({ id, color, label, hotKey }) {
return (0, import_jsx_runtime.jsxs)("button", {
className: "menu-btn",
id,
style: {
minWidth: "120px",
backgroundColor: color
},
children: [
label,
" ",
hotKey ? `(${hotKey})` : ""
]
});
}
function PreviewVideoQualityBtn({ opt, src, isActive }) {
return (0, import_jsx_runtime.jsx)("button", {
className: `video-control-btn${isActive ? " active" : ""}`,
id: opt.id,
"data-quality": opt.quality,
"data-video-src": src,
style: {
minWidth: "40px",
border: "1px solid #ccc",
backgroundColor: isActive ? "#007bff" : "#fff",
color: isActive ? "white" : "black"
},
children: opt.text
});
}
function PreviewVideoContainer({ coverSrc }) {
return (0, import_jsx_runtime.jsxs)("a", {
className: "preview-video-container",
"data-fancybox": "gallery",
href: "#preview-video",
children: [(0, import_jsx_runtime.jsx)("span", { children: "預告片" }), (0, import_jsx_runtime.jsx)("img", {
src: coverSrc,
className: "video-cover",
style: {
width: "150px",
height: "auto"
},
alt: ""
})]
});
}
var preview_video_plugin_default = ".video-control-btn {\n min-width: 120px;\n padding: 7px 12px;\n font-size: 12px;\n background: rgba(0, 0, 0, 0.7);\n color: white;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n}\n.video-control-btn.active {\n background-color: #1890ff;\n color: white;\n font-weight: bold;\n border: 2px solid #096dd9;\n}\n";
var DMM_VIDEO_CACHE_KEY = "jhs_dmm_video";
var DMM_OTHER_SITE_KEY = "jhs_other_site_dmm";
var VIDEO_MUTED_KEY = "jhs_videoMuted";
var selectAvailableVideoQuality = (available, desired) => {
if (!available || available.length === 0) return null;
const availableSet = new Set(available);
if (availableSet.has(desired)) return desired;
const descending = VIDEO_QUALITY_LIST.map((opt) => opt.quality).reverse();
for (const quality of descending) if (availableSet.has(quality)) return quality;
return available[0];
};
var DmmPreviewVideoResolver = class {
carNum;
showErrorMessages;
constructor(carNum, showErrorMessages = true) {
this.carNum = carNum;
this.showErrorMessages = showErrorMessages;
}
_checkCache() {
const rawCache = localStorage.getItem(DMM_VIDEO_CACHE_KEY);
const cache = rawCache ? JSON.parse(rawCache) : {};
if (cache[this.carNum]) {
clog.debug("缓存中存在预览视频信息", cache[this.carNum]);
return cache[this.carNum];
}
return null;
}
_updateCache(videoMap) {
const rawCache = localStorage.getItem(DMM_VIDEO_CACHE_KEY);
const cache = rawCache ? JSON.parse(rawCache) : {};
cache[this.carNum] = videoMap;
clog.debug("成功解析出预览视频并已缓存:", videoMap);
localStorage.setItem(DMM_VIDEO_CACHE_KEY, JSON.stringify(cache));
}
async _searchContentIds() {
const carNum = this.carNum;
const noHyphen = carNum.replace(/-/g, "");
const candidates = [
{
keyword: carNum.replace("-", "00"),
name: "00-替换关键词"
},
{
keyword: carNum,
name: "原始番号关键词"
},
{
keyword: noHyphen,
name: "无连字符关键词"
}
];
const carNumLower = carNum.toLowerCase();
for (const candidate of candidates) {
const { keyword, name } = candidate;
const keywordLower = keyword.toLowerCase();
clog.debug(`--- 尝试使用 ${name} (${keyword}) 进行 API 搜索 ---`);
const apiUrl = `https://api.dmm.com/affiliate/v3/ItemList?${new URLSearchParams({
api_id: "UrwskPfkqQ0DuVry2gYL",
affiliate_id: "10278-996",
output: "json",
site: "FANZA",
sort: "match",
keyword
}).toString()}`;
let response;
try {
response = await gmHttp.get(apiUrl);
} catch (err) {
clog.error(`API 请求失败,跳过 ${name}:`, err);
continue;
}
if (!response || !response.result || !response.result.result_count) {
clog.debug("API 返回无结果,尝试下一个关键词。");
continue;
}
const matched = [];
for (const item of response.result.items) {
if (matched.length >= 2) break;
const contentId = item.content_id || "";
const makerProduct = item.maker_product || "";
if (contentId.includes(keywordLower.replace("-", "")) || carNumLower === makerProduct.toLowerCase() || contentId.includes(noHyphen.toLowerCase())) {
matched.push({
serviceCode: item.service_code,
floorCode: item.floor_code,
contentId,
pageUrl: item.URL
});
clog.debug(`[${name}] cid|makerProduct 匹配成功:`, contentId, makerProduct);
}
}
if (matched.length > 0) {
clog.debug(`--- 成功通过 ${name} 找到 Content IDs ---`);
const $fanzaBtn = $("#fanzaBtn");
let siteUrl = `https://www.dmm.co.jp/search/=/searchstr=${keyword}`;
let linkType = "single";
if (matched.length > 1) {
$fanzaBtn.attr("href", siteUrl);
$fanzaBtn.append(jsxToString((0, import_jsx_runtime.jsx)(SiteResultTag, {})));
$fanzaBtn.css("backgroundColor", "#7bc73b");
linkType = "multiple";
} else {
siteUrl = matched[0].pageUrl;
$fanzaBtn.attr("href", siteUrl);
$fanzaBtn.css("backgroundColor", "#7bc73b");
}
const rawOther = localStorage.getItem(DMM_OTHER_SITE_KEY);
const otherSiteCache = rawOther ? JSON.parse(rawOther) : {};
otherSiteCache[this.carNum] = {
type: linkType,
url: siteUrl
};
localStorage.setItem(DMM_OTHER_SITE_KEY, JSON.stringify(otherSiteCache));
return matched;
}
clog.debug(`[${name}] API 返回结果数 ${response.result.result_count},但无精确匹配的 Content ID。`);
}
clog.warn("所有关键词尝试均未找到匹配的Content ID, 解析Dmm视频失败");
const $fanzaBtn = $("#fanzaBtn");
$fanzaBtn.attr("href", `https://www.dmm.co.jp/search/=/searchstr=${this.carNum}`);
$fanzaBtn.attr("title", "未查询到, 点击前往搜索页");
$fanzaBtn.css("backgroundColor", "#de3333");
return null;
}
async _extractTrailerLinks({ contentId, serviceCode, floorCode }) {
const playerUrl = `https://www.dmm.co.jp/service/digitalapi/-/html5_player/=/cid=${contentId}/mtype=AhRVShI_/service=${serviceCode}/floor=${floorCode}/mode=/`;
const html = await gmHttp.get(playerUrl, null, {
"accept-language": "ja-JP,ja;q=0.9",
Cookie: "age_check_done=1"
});
if (typeof html != "string") {
clog.error(html);
throw new Error("解析播放页内容失败, 非文本内容");
}
if (html.includes("このサービスはお住まいの地域からは")) throw new Error("节点不可用,请将DMM域名分流到日本ip");
const argsMatch = html.match(/const\s+args\s+=\s+(.*);/);
if (!argsMatch) throw new Error("未在脚本中找到 const args = ... 变量");
let bitrates;
try {
({bitrates} = JSON.parse(argsMatch[1]));
} catch (err) {
throw new Error(`解析播放器脚本 JSON 失败: ${err.message}`);
}
const videoMap = {};
const qualityPattern = VIDEO_QUALITY_LIST.map((opt) => opt.quality).join("|");
const qualityRegex = new RegExp(`(${qualityPattern})\\.mp4$`);
if (!Array.isArray(bitrates)) {
clog.error("解析画质链接失败: bitrates 字段不是一个数组或不存在");
throw new Error("解析画质链接失败: bitrates 字段不是一个数组或不存在");
}
clog.debug("原始数据返回:", bitrates);
for (const item of bitrates) {
const src = item == null ? void 0 : item.src;
if (!src || typeof src != "string" || !src.endsWith(".mp4")) continue;
const qualityMatch = src.match(qualityRegex);
let quality = "";
if (qualityMatch && qualityMatch[1]) quality = qualityMatch[1];
if (quality && !videoMap[quality]) videoMap[quality] = src;
}
if (Object.keys(videoMap).length === 0) throw new Error("未找到匹配要求的预览画质视频");
return videoMap;
}
async fetchVideo() {
const cached = this._checkCache();
if (cached) return cached;
let contentIds;
try {
const carNumLower = this.carNum.toLowerCase();
if (carNumLower.startsWith("heyzo") || /^(n\d+|\d+(-\d+)*)$/.test(carNumLower) || /^n\d+$/.test(carNumLower)) throw new Error("无码番号类型, 取消dmm解析");
if (this.carNum.includes("VR-")) throw new Error("VR类型, 取消dmm解析");
contentIds = await this._searchContentIds();
} catch (err) {
clog.error("DMM API 搜索失败:", err);
const $fanzaBtn = $("#fanzaBtn");
$fanzaBtn.attr("href", `https://www.dmm.co.jp/search/=/searchstr=${this.carNum}`);
$fanzaBtn.attr("title", "未查询到, 点击前往搜索页");
$fanzaBtn.css("backgroundColor", "#de3333");
return null;
}
if (!contentIds || contentIds.length === 0) return null;
try {
const videoMap = await Promise.any(contentIds.map((id) => this._extractTrailerLinks(id)));
this._updateCache(videoMap);
return videoMap;
} catch (err) {
const errors = err.errors || [err];
if (errors.some((e) => e.message.includes("节点不可用"))) {
if (this.showErrorMessages) show.error("节点不可用,请将DMM域名分流到日本ip");
} else {
const firstMsg = errors[0].message || errors[0];
clog.error(`解析失败: ${firstMsg}`, errors);
if (this.showErrorMessages) show.error(`解析失败: ${firstMsg}`);
}
const $fanzaBtn = $("#fanzaBtn");
$fanzaBtn.attr("href", `https://www.dmm.co.jp/search/=/searchstr=${this.carNum}`);
$fanzaBtn.attr("title", "未查询到, 点击前往搜索页");
$fanzaBtn.css("backgroundColor", "#de3333");
return null;
}
}
};
var fetchDmmPreviewVideo = async (carNum, showErrorMessages = true) => new DmmPreviewVideoResolver(carNum, showErrorMessages).fetchVideo();
var PreviewVideoPlugin = class extends BasePlugin {
filterHotKey = null;
favoriteHotKey = null;
speedVideoHotKey = null;
getName() {
return "PreviewVideoPlugin";
}
async initCss() {
return preview_video_plugin_default;
}
async handle() {
if (!window.isDetailPage) return;
const settings = await storageManager.getSetting();
this.filterHotKey = settings.filterHotKey;
this.favoriteHotKey = settings.favoriteHotKey;
this.speedVideoHotKey = settings.speedVideoHotKey;
const $container = $(".preview-video-container");
$container.on("click", () => {
utils.loopDetector(() => $(".fancybox-content #preview-video").length > 0, () => {
this.handleVideo().then();
});
});
if (await storageManager.getSetting("enableLoadPreviewVideo", "yes") === "yes" && !currentHref.includes("autoPlay=1")) this.initDmm().then();
const href = window.location.href;
if (href.includes("gallery-1") || href.includes("gallery-2")) utils.loopDetector(() => $(".fancybox-content #preview-video").length > 0, () => {
if ($(".fancybox-content #preview-video").length > 0) this.handleVideo().then();
});
if (href.includes("autoPlay=1") && $container.length > 0) $container[0].click();
}
async initDmm() {
try {
const videoMap = await fetchDmmPreviewVideo(this.getPageInfo().carNum, false);
if (!videoMap) return;
const desiredQuality = await storageManager.getSetting("videoQuality");
clog.debug("解析其它画质预览视频", "设置-期望画质", desiredQuality);
const videoUrl = videoMap[selectAvailableVideoQuality(Object.keys(videoMap), desiredQuality)];
clog.log("切换其它画质预览视频: ", videoUrl);
const $video = $("#preview-video");
const videoEl = $video.length ? $video[0] : null;
const isHidden = !videoEl || utils.isHidden($video);
if ($video.length) {
if (videoEl) {
const currentTime = videoEl.currentTime;
$video.attr("src", videoUrl);
if (!isHidden) {
clog.debug("播放器已手动打开, 变更进度条");
videoEl.currentTime = currentTime;
videoEl.play();
}
}
} else {
clog.debug("JavDB没有视频播放元素, 开始创建...");
const coverSrc = $(".column-video-cover img").attr("src");
$(".preview-images").prepend(jsxToString((0, import_jsx_runtime.jsx)(PreviewVideoContainer, { coverSrc })));
$(".preview-video-container").on("click", () => {
utils.loopDetector(() => $(".fancybox-content #preview-video").length > 0, async () => {
await this.handleVideo();
});
});
}
} catch (err) {
clog.error("预加载dmm失败:", err);
}
}
async handleVideo() {
if (await storageManager.getSetting("enableLoadPreviewVideo", "yes") === "no") return;
const $video = $("#preview-video");
if (!$video.length) return;
const $videoWrap = $video.parent();
$videoWrap.css("position", "relative");
const videoEl = $video[0];
const mutedStored = localStorage.getItem(VIDEO_MUTED_KEY);
if (mutedStored) videoEl.muted = mutedStored === "yes";
videoEl.addEventListener("volumechange", () => {
localStorage.setItem(VIDEO_MUTED_KEY, videoEl.muted ? "yes" : "no");
});
videoEl.play();
const carNum = this.getPageInfo().carNum;
const videoMap = await fetchDmmPreviewVideo(carNum);
const $toolbar = $("<div></div>").attr("id", "video-bottom-toolbar").css({
display: "flex",
gap: "5px",
"align-items": "center",
"flex-wrap": "wrap"
});
const $qualityGroup = $("<div></div>").css({
display: "flex",
gap: "5px",
"align-items": "center"
});
let currentQuality = null;
if (videoMap) {
const desiredQuality = await storageManager.getSetting("videoQuality");
currentQuality = selectAvailableVideoQuality(Object.keys(videoMap), desiredQuality);
const currentUrl = videoMap[currentQuality];
if ($video.attr("src") !== currentUrl) {
$video.attr("src", currentUrl);
videoEl.load();
videoEl.play();
}
VIDEO_QUALITY_LIST.forEach((opt) => {
const src = videoMap[opt.quality];
if (src) {
const isActive = currentQuality === opt.quality;
const $btn = $(jsxToString((0, import_jsx_runtime.jsx)(PreviewVideoQualityBtn, {
opt,
src,
isActive
})));
$qualityGroup.append($btn);
}
});
}
$toolbar.append($qualityGroup);
const $actionGroup = $("<div></div>").css({
display: "flex",
gap: "5px",
"align-items": "center",
"margin-left": "auto"
});
const $filterBtn = $(jsxToString((0, import_jsx_runtime.jsx)(PreviewVideoActionBtn, {
id: "video-filterBtn",
color: "#de3333",
label: "屏蔽",
hotKey: this.filterHotKey
})));
$actionGroup.append($filterBtn);
const $favoriteBtn = $(jsxToString((0, import_jsx_runtime.jsx)(PreviewVideoActionBtn, {
id: "video-favoriteBtn",
color: "#25b1dc",
label: "收藏",
hotKey: this.favoriteHotKey
})));
$actionGroup.append($favoriteBtn);
const $speedBtn = $(jsxToString((0, import_jsx_runtime.jsx)(PreviewVideoActionBtn, {
id: "speed-btn",
color: "#76b45d",
label: "快进",
hotKey: this.speedVideoHotKey
})));
$actionGroup.append($speedBtn);
$toolbar.append($actionGroup);
$videoWrap.append($toolbar);
$toolbar.on("click", ".video-control-btn", async (event) => {
const $btn = $(event.currentTarget);
const src = $btn.data("video-src");
if (!$btn.hasClass("active")) try {
const currentTime = videoEl.currentTime;
$video.attr("src", src);
videoEl.load();
videoEl.currentTime = currentTime;
await videoEl.play();
$toolbar.find(".video-control-btn").removeClass("active").css({
"background-color": "#fff",
color: "black"
});
$btn.addClass("active").css({
"background-color": "#007bff",
color: "white"
});
} catch (err) {
console.error("切换画质失败:", err);
}
});
$("#speed-btn").on("click", () => {
this.getBean("DetailPageButtonPlugin").speedVideo();
});
utils.rightClick(document.body, "#speed-btn", (event) => {
this.getBean("DetailPageButtonPlugin").filterOne(event);
});
$("#video-filterBtn").on("click", (event) => {
this.getBean("DetailPageButtonPlugin").filterOne(event);
});
$("#video-favoriteBtn").on("click", (event) => {
this.getBean("DetailPageButtonPlugin").favoriteOne(event);
});
}
};
var RatingRenderer = {
hideNativeBadge(cover) {
cover.querySelectorAll(":scope > span").forEach((s) => {
if (s.classList.length === 0 || s.className === "score") s.style.display = "none";
});
},
showPlaceholder(item) {
const cover = item.querySelector(".cover");
if (!cover) return;
if (cover.querySelector(".jhs-user-rating")) return;
this.hideNativeBadge(cover);
const el = document.createElement("div");
el.className = "jhs-user-rating is-placeholder";
el.textContent = "已看";
el.title = "已看(悬停加载评分)";
cover.appendChild(el);
},
showRating(item, rating) {
const cover = item.querySelector(".cover");
if (!cover) return;
let el = cover.querySelector(".jhs-user-rating");
if (!el) {
this.hideNativeBadge(cover);
el = document.createElement("div");
el.className = "jhs-user-rating";
cover.appendChild(el);
}
el.className = "jhs-user-rating";
el.innerHTML = "";
if (rating && rating >= 1 && rating <= 5) {
el.classList.add("is-rated");
el.innerHTML = jsxToString((0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("span", {
className: "jhs-rd-icon",
children: "★"
}), (0, import_jsx_runtime.jsx)("span", {
className: "jhs-rd-num",
children: rating
})] }));
el.title = `已看 · ${rating}/5 星`;
} else {
el.classList.add("is-placeholder");
el.textContent = "已看";
el.title = "已看(未评分)";
}
},
removeFrom(item) {
const el = item?.querySelector(".jhs-user-rating");
if (el) el.remove();
const cover = item?.querySelector(".cover");
if (cover) cover.querySelectorAll(":scope > span").forEach((s) => {
if (s.style.display === "none" && (s.classList.length === 0 || s.className === "score")) s.style.display = "";
});
}
};
var RATING_CONFIG = {
DEBUG_MODE: false,
IDB_NAME: "JAV-JHS",
IDB_STORE: "appData",
CAR_LIST_KEY: "car_list",
RATING_CACHE_KEY: "jdb:rating_cache_v2",
IDB_RATING_KEY: "jhsRatingDisplay_data",
ITEM_SELECTOR: ".movie-list .item, .is-user-page .column.is-one-quarter",
HOVER_DELAY: 500,
FETCH_CONCURRENCY: 3,
FETCH_TIMEOUT: 8e3,
FETCH_RETRY: 1
};
var parser = new DOMParser();
function log(action, ...args) {
if (RATING_CONFIG.DEBUG_MODE) console.log(`%c[JHS-Rating][${action}]`, "color:#fff;background:#ffc107;padding:2px 4px;border-radius:2px;", ...args);
}
function debounce(fn, wait) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), wait);
};
}
function createLimiter(max) {
let active = 0;
const queue = [];
const runNext = () => {
if (active >= max || queue.length === 0) return;
active++;
const job = queue.shift();
Promise.resolve().then(job.fn).then(job.resolve).catch(job.reject).finally(() => {
active--;
runNext();
});
};
return { run(fn) {
return new Promise((resolve, reject) => {
queue.push({
fn,
resolve,
reject
});
runNext();
});
} };
}
function getSafeUrl(url, base = window.location.origin) {
if (!url) return "";
try {
if (url.startsWith("http")) return url;
if (url.startsWith("//")) return "https:" + url;
return new URL(url, base).href;
} catch {
return url;
}
}
function normalizeCode(raw) {
if (!raw) return "";
return raw.trim().toUpperCase().replace(/\s+/g, "-");
}
function getCode$1(item) {
if (item.dataset.code) return item.dataset.code;
const code = normalizeCode(item.querySelector(".video-title strong")?.textContent || "");
if (code) item.dataset.code = code;
return code;
}
function getAnchor(item) {
return item?.querySelector("a.box, .box a") ?? null;
}
var RatingUtils = {
parser,
log,
debounce,
createLimiter,
getSafeUrl,
normalizeCode,
getCode: getCode$1,
getAnchor
};
function openIdb() {
return new Promise((resolve, reject) => {
const req = indexedDB.open(RATING_CONFIG.IDB_NAME);
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
}
async function buildWatchedMap() {
const list = await storageManager.getCarList();
const map = new Map();
list.forEach((item) => {
if (item && item.status === "hasWatch" && item.carNum) map.set(RatingUtils.normalizeCode(item.carNum), item);
});
RatingUtils.log("WATCHED_MAP", `${map.size} 项`);
return map;
}
var RatingCache = {
_data: {},
async load() {
try {
const raw = localStorage.getItem(RATING_CONFIG.RATING_CACHE_KEY);
if (raw) {
const parsed = JSON.parse(raw);
if (typeof parsed === "object" && parsed !== null) {
this._data = parsed;
RatingUtils.log("CACHE", `localStorage: ${Object.keys(parsed).length} 条`);
return;
}
}
} catch {}
try {
const db = await openIdb();
const idbData = await new Promise((resolve) => {
try {
const req = db.transaction(RATING_CONFIG.IDB_STORE, "readonly").objectStore(RATING_CONFIG.IDB_STORE).get(RATING_CONFIG.IDB_RATING_KEY);
req.onsuccess = () => resolve(req.result ?? null);
req.onerror = () => resolve(null);
} catch {
resolve(null);
}
});
if (idbData && typeof idbData === "object") {
this._data = idbData;
this.saveToLS();
RatingUtils.log("CACHE", `IndexedDB 恢复: ${Object.keys(idbData).length} 条`);
return;
}
} catch (e) {
RatingUtils.log("CACHE_IDB_LOAD_ERROR", e);
}
this._data = {};
},
saveToLS() {
try {
localStorage.setItem(RATING_CONFIG.RATING_CACHE_KEY, JSON.stringify(this._data));
} catch (e) {
RatingUtils.log("CACHE_SAVE_ERROR", e);
}
},
save() {
this.saveToLS();
this._syncToIdb();
},
async _syncToIdb() {
try {
(await openIdb()).transaction(RATING_CONFIG.IDB_STORE, "readwrite").objectStore(RATING_CONFIG.IDB_STORE).put(this._data, RATING_CONFIG.IDB_RATING_KEY);
} catch (e) {
RatingUtils.log("IDB_SYNC_ERROR", e);
}
},
get(code) {
return this._data[code] || null;
},
set(code, rating) {
const existed = this._data[code];
if (existed && existed.rating === rating) return false;
this._data[code] = {
rating,
updatedAt: Date.now()
};
this.save();
return true;
},
clear() {
this._data = {};
localStorage.removeItem(RATING_CONFIG.RATING_CACHE_KEY);
openIdb().then((db) => {
try {
db.transaction(RATING_CONFIG.IDB_STORE, "readwrite").objectStore(RATING_CONFIG.IDB_STORE).delete(RATING_CONFIG.IDB_RATING_KEY);
} catch {}
}).catch(() => {});
},
size() {
return Object.keys(this._data).length;
}
};
var limiter = RatingUtils.createLimiter(RATING_CONFIG.FETCH_CONCURRENCY);
async function request(url, retries = RATING_CONFIG.FETCH_RETRY) {
for (let i = 0; i <= retries; i++) try {
return await new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url,
timeout: RATING_CONFIG.FETCH_TIMEOUT,
headers: { "X-Requested-With": "XMLHttpRequest" },
onload: resolve,
onerror: reject,
ontimeout: reject,
onabort: reject
});
});
} catch (err) {
if (i === retries) throw err;
await new Promise((resolve) => setTimeout(resolve, 400 * (i + 1)));
}
throw new Error("unreachable");
}
function parseRating(doc) {
if (!doc.querySelector(".review-title .tag.is-success.is-light")) return null;
const chk = doc.querySelector("input[name=\"video_review[score]\"][checked], .rating-star input:checked");
if (!chk) return null;
const ratingValue = parseInt(chk.value, 10);
return ratingValue >= 1 && ratingValue <= 5 ? ratingValue : null;
}
async function fetchRating(item) {
if (item.dataset.jhsrdFetching === "true" || item.dataset.jhsrdLoaded === "true") return;
const anchor = RatingUtils.getAnchor(item);
if (!anchor) return;
const code = RatingUtils.getCode(item);
if (!code) return;
item.dataset.jhsrdFetching = "true";
try {
const url = RatingUtils.getSafeUrl(anchor.href);
const res = await limiter.run(() => request(url));
if (res.status !== 200) {
item.dataset.jhsrdLoaded = "true";
return;
}
const rating = parseRating(RatingUtils.parser.parseFromString(res.responseText, "text/html"));
if (rating !== null) {
RatingCache.set(code, rating);
RatingRenderer.showRating(item, rating);
}
item.dataset.jhsrdLoaded = "true";
} catch (err) {
RatingUtils.log("FETCH_ERROR", code, err);
} finally {
delete item.dataset.jhsrdFetching;
}
}
var rating_display_default = ".jhs-user-rating {\r\n position: absolute;\r\n bottom: 6px;\r\n right: 6px;\r\n z-index: 5;\r\n pointer-events: auto;\r\n font-size: 13px;\r\n font-weight: 700;\r\n line-height: 1;\r\n padding: 5px 10px;\r\n border-radius: 12px;\r\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35), 0 0 0 1px rgba(255,255,255,0.1) inset;\r\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);\r\n color: #fff;\r\n white-space: nowrap;\r\n opacity: 0.95;\r\n transition: transform 0.25s ease, opacity 0.2s ease, background 0.3s ease;\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 3px;\r\n letter-spacing: 0.5px;\r\n}\r\n\r\n/* 占位(绿色) */\r\n.jhs-user-rating.is-placeholder {\r\n background: linear-gradient(145deg, #48c78e, #2fb972);\r\n}\r\n\r\n/* 已评分(金色) */\r\n.jhs-user-rating.is-rated {\r\n background: linear-gradient(145deg, #ffc107, #f57c00);\r\n}\r\n\r\n.jhs-rd-icon {\r\n font-size: 14px;\r\n filter: drop-shadow(0 1px 1px rgba(0,0,0,0.3));\r\n}\r\n\r\n.jhs-rd-num {\r\n font-size: 14px;\r\n font-weight: 900;\r\n}\r\n\r\n.jhs-user-rating:hover {\r\n transform: scale(1.1);\r\n opacity: 1;\r\n}\r\n\r\n/* 加载中 */\r\n.jhs-user-rating.is-loading {\r\n animation: jhs-rd-pulse 1s infinite;\r\n pointer-events: none;\r\n}\r\n\r\n@keyframes jhs-rd-pulse {\r\n 0%, 100% { opacity: 0.55; }\r\n 50% { opacity: 1; }\r\n}\r\n\r\n/* Toast */\r\n.jhs-rd-toast {\r\n position: fixed;\r\n left: 50%;\r\n transform: translateX(-50%);\r\n bottom: 2.5rem;\r\n background: rgba(0, 0, 0, 0.88);\r\n color: #fff;\r\n padding: 0.5rem 0.9rem;\r\n border-radius: 0.5rem;\r\n z-index: 20000;\r\n font-size: 0.85rem;\r\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);\r\n animation: jhs-rd-toast-in 0.22s;\r\n pointer-events: none;\r\n}\r\n\r\n@keyframes jhs-rd-toast-in {\r\n from { opacity: 0; transform: translateX(-50%) translateY(8px); }\r\n to { opacity: 1; transform: translateX(-50%) translateY(0); }\r\n}\r\n";
var RatingDisplayPlugin = class extends BasePlugin {
watchedMap = new Map();
_dirty = false;
getName() {
return "RatingDisplayPlugin";
}
async initCss() {
return rating_display_default;
}
toast(msg) {
document.querySelector(".jhs-rd-toast")?.remove();
const div = document.createElement("div");
div.className = "jhs-rd-toast";
div.textContent = msg;
document.body.appendChild(div);
setTimeout(() => div.remove(), 2500);
}
processItem(item) {
if (!item || item.dataset.jhsrdProcessed === "true") return;
item.dataset.jhsrdProcessed = "true";
const code = RatingUtils.getCode(item);
if (!code) return;
if (!this.watchedMap.has(code)) {
RatingRenderer.removeFrom(item);
return;
}
const cached = RatingCache.get(code);
if (cached) {
RatingRenderer.showRating(item, cached.rating);
item.dataset.jhsrdLoaded = "true";
item.dataset.jhsrdFromCache = "true";
} else RatingRenderer.showPlaceholder(item);
}
refreshAll() {
document.querySelectorAll(RATING_CONFIG.ITEM_SELECTOR).forEach((item) => {
const el = item;
RatingRenderer.removeFrom(el);
el.dataset.jhsrdProcessed = "false";
delete el.dataset.jhsrdLoaded;
delete el.dataset.jhsrdFetching;
delete el.dataset.jhsrdFromCache;
this.processItem(el);
});
}
clearPageCache() {
const codes = new Set();
document.querySelectorAll(RATING_CONFIG.ITEM_SELECTOR).forEach((item) => {
const code = RatingUtils.getCode(item);
if (code) codes.add(code);
});
let cleared = 0;
codes.forEach((code) => {
if (RatingCache._data[code]) {
delete RatingCache._data[code];
cleared++;
}
});
if (cleared > 0) RatingCache.save();
document.querySelectorAll(RATING_CONFIG.ITEM_SELECTOR).forEach((item) => {
const el = item;
RatingRenderer.removeFrom(el);
delete el.dataset.jhsrdLoaded;
delete el.dataset.jhsrdFromCache;
el.dataset.jhsrdProcessed = "false";
this.processItem(el);
});
this.toast(`已清除 ${cleared} 个评分缓存,当前页 ${codes.size} 张卡片`);
}
loadAll() {
const targets = [];
document.querySelectorAll(RATING_CONFIG.ITEM_SELECTOR).forEach((item) => {
const el = item;
if (el.dataset.jhsrdFetching !== "true" && el.dataset.jhsrdLoaded !== "true") targets.push(el);
});
if (targets.length === 0) {
this.toast("当前页面所有卡片已加载评分");
return;
}
this.toast(`开始加载 ${targets.length} 个评分...`);
targets.forEach((item) => {
const tag = item.querySelector(".jhs-user-rating");
if (tag) tag.classList.add("is-loading");
fetchRating(item).finally(() => {
if (tag) tag.classList.remove("is-loading");
});
});
}
_invalidateCards(code, status, op) {
if (status === "hasWatch" && op === "add") {
if (!this.watchedMap.has(code)) this.watchedMap.set(code, {
carNum: code,
status: "hasWatch"
});
} else this.watchedMap.delete(code);
delete RatingCache._data[code];
RatingCache.save();
document.querySelectorAll(RATING_CONFIG.ITEM_SELECTOR).forEach((item) => {
const el = item;
if (RatingUtils.getCode(el) === code) {
RatingRenderer.removeFrom(el);
delete el.dataset.jhsrdLoaded;
delete el.dataset.jhsrdFromCache;
el.dataset.jhsrdProcessed = "false";
this.processItem(el);
}
});
this._dirty = true;
const cur = localStorage.getItem("jdb:want-watched-sync");
if (cur) localStorage.setItem("jhsrd:last-sync-digest", cur);
}
async init() {
await RatingCache.load();
const syncVal = localStorage.getItem("jdb:want-watched-sync");
const lastDigest = localStorage.getItem("jhsrd:last-sync-digest");
if (syncVal && syncVal !== lastDigest) {
RatingUtils.log("INIT_SYNC", "jhs 有新的同步事件,全量清空评分缓存");
RatingCache.clear();
this._dirty = true;
localStorage.setItem("jhsrd:last-sync-digest", syncVal);
}
this.watchedMap = await buildWatchedMap();
document.querySelectorAll(RATING_CONFIG.ITEM_SELECTOR).forEach((i) => this.processItem(i));
document.querySelectorAll(".jhs-user-rating.is-rated").forEach((el) => {
const item = el.closest(RATING_CONFIG.ITEM_SELECTOR);
if (item && item.dataset.jhsrdFromCache === "true") {
delete item.dataset.jhsrdLoaded;
delete item.dataset.jhsrdFromCache;
}
});
const pending = new Set();
const flushPending = RatingUtils.debounce(() => {
pending.forEach((item) => this.processItem(item));
pending.clear();
}, 150);
new MutationObserver((muts) => {
for (const mutation of muts) {
for (const addedNode of mutation.addedNodes) {
if (addedNode.nodeType !== 1) continue;
const el = addedNode;
if (el.matches(RATING_CONFIG.ITEM_SELECTOR)) pending.add(el);
const found = el.querySelectorAll(RATING_CONFIG.ITEM_SELECTOR);
if (found && found.length) found.forEach((node) => pending.add(node));
}
const target = mutation.target;
if (target instanceof Element && target.closest(".tags.has-addons")) {
const item = target.closest(RATING_CONFIG.ITEM_SELECTOR);
if (item) {
item.dataset.jhsrdProcessed = "false";
this.processItem(item);
}
}
}
flushPending();
}).observe(document.body, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ["class"]
});
let hoverTimer = null;
let hoveredItem = null;
document.body.addEventListener("pointerover", (e) => {
const item = e.target?.closest(RATING_CONFIG.ITEM_SELECTOR);
if (!item || item === hoveredItem) return;
hoveredItem = item;
if (item.dataset.jhsrdLoaded === "true") return;
const tag = item.querySelector(".jhs-user-rating.is-placeholder");
if (!tag) return;
if (hoverTimer) clearTimeout(hoverTimer);
hoverTimer = setTimeout(() => {
if (hoveredItem !== item) return;
tag.classList.add("is-loading");
fetchRating(item).finally(() => {
tag.classList.remove("is-loading");
});
}, RATING_CONFIG.HOVER_DELAY);
});
document.body.addEventListener("pointerout", (e) => {
const item = e.target?.closest(RATING_CONFIG.ITEM_SELECTOR);
if (!item || item !== hoveredItem) return;
hoveredItem = null;
if (hoverTimer) clearTimeout(hoverTimer);
const tag = item.querySelector(".jhs-user-rating.is-loading");
if (tag) tag.classList.remove("is-loading");
});
GM_registerMenuCommand("全量加载当前页评分", () => {
this.loadAll();
});
GM_registerMenuCommand("清空当前页评分缓存", () => {
this.clearPageCache();
});
GM_registerMenuCommand("清空所有评分缓存", () => {
RatingCache.clear();
this.refreshAll();
this.toast("所有评分缓存已清空");
});
GM_registerMenuCommand("刷新已看列表", async () => {
this.watchedMap = await buildWatchedMap();
this.refreshAll();
this.toast(`已看: ${this.watchedMap.size} 项 · 缓存: ${RatingCache.size()} 条`);
});
document.addEventListener("jdb:want-watched-sync", (e) => {
const { carNum, status, op } = e.detail || {};
if (!carNum || !status || !op) return;
const code = RatingUtils.normalizeCode(carNum);
RatingUtils.log("SYNC_EVENT", code, status, op);
this._invalidateCards(code, status, op);
}, { passive: true });
window.addEventListener("storage", (e) => {
if (e.key === "jdb:want-watched-sync" && e.newValue) try {
const payload = JSON.parse(e.newValue);
if (payload && payload.carNum && payload.status && payload.op) {
const code = RatingUtils.normalizeCode(payload.carNum);
RatingUtils.log("STORAGE_SYNC", "跨标签页精确刷新", code, payload.status, payload.op);
this._invalidateCards(code, payload.status, payload.op);
}
} catch {
this._dirty = true;
}
});
document.addEventListener("visibilitychange", () => {
if (document.hidden) return;
document.querySelectorAll(".jhs-user-rating.is-rated").forEach((el) => {
const item = el.closest(RATING_CONFIG.ITEM_SELECTOR);
if (item) item.dataset.jhsrdLoaded = "false";
});
if (this._dirty) {
this._dirty = false;
this.refreshAll();
}
}, { passive: true });
RatingUtils.log("INIT", `已看 ${this.watchedMap.size} · 缓存 ${RatingCache.size()}`);
}
async handle() {
await this.init();
}
};
var fc2_plugin_default = "/* Fc2Plugin 弹层样式(提取自未删减版 jhs.user.js Fc2Plugin.initCss) */\r\n\r\n/* 弹层样式 */\r\n.movie-detail-layer .layui-layer-title {\r\n font-size: 18px;\r\n color: #333;\r\n background: #f8f8f8;\r\n}\r\n\r\n/* 容器样式 */\r\n.movie-detail-container {\r\n margin: 40px;\r\n height: 100%;\r\n background: #fff;\r\n}\r\n\r\n.movie-poster-container {\r\n flex: 0 0 60%;\r\n padding: 15px;\r\n}\r\n\r\n.right-box {\r\n flex: 1;\r\n padding: 20px;\r\n overflow-y: auto;\r\n}\r\n\r\n/* 预告片iframe */\r\n.movie-trailer {\r\n width: 100%;\r\n height: 100%;\r\n min-height: 400px;\r\n background: #000;\r\n border-radius: 4px;\r\n}\r\n\r\n/* 电影信息样式 */\r\n.movie-title {\r\n font-size: 24px;\r\n margin-bottom: 15px;\r\n color: #333;\r\n}\r\n\r\n.movie-meta {\r\n margin-bottom: 20px;\r\n color: #666;\r\n}\r\n\r\n.movie-meta span {\r\n margin-right: 15px;\r\n}\r\n\r\n/* 演员列表 */\r\n.actor-list {\r\n display: flex;\r\n flex-wrap: wrap;\r\n gap: 8px;\r\n margin-top: 10px;\r\n}\r\n\r\n.actor-tag {\r\n padding: 4px 12px;\r\n background: #f0f0f0;\r\n border-radius: 15px;\r\n font-size: 12px;\r\n color: #555;\r\n}\r\n\r\n/* 图片列表 */\r\n.image-list {\r\n display: flex;\r\n flex-wrap: wrap;\r\n gap: 10px;\r\n margin-top: 10px;\r\n}\r\n\r\n.movie-image-thumb {\r\n width: 120px;\r\n height: 80px;\r\n object-fit: cover;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n transition: transform 0.3s;\r\n}\r\n\r\n.movie-image-thumb:hover {\r\n transform: scale(1.05);\r\n}\r\n\r\n/* 加载中和错误状态 */\r\n.search-loading,\r\n.movie-error {\r\n padding: 40px;\r\n text-align: center;\r\n color: #999;\r\n}\r\n\r\n.movie-error {\r\n color: #f56c6c;\r\n}\r\n\r\n.fancybox-container {\r\n z-index: 99999999;\r\n}\r\n\r\n/* 错误提示样式 */\r\n.movie-not-found,\r\n.movie-error {\r\n text-align: center;\r\n padding: 30px;\r\n color: #666;\r\n}\r\n\r\n.movie-not-found h3,\r\n.movie-error h3 {\r\n color: #f56c6c;\r\n margin: 15px 0;\r\n}\r\n\r\n.icon-warning,\r\n.icon-error {\r\n font-size: 50px;\r\n color: #e6a23c;\r\n}\r\n\r\n.icon-error {\r\n color: #f56c6c;\r\n}\r\n\r\n.fc2-movie-panel-info .panel-block {\r\n padding: 0 !important;\r\n}\r\n";
var Fc2Plugin = class extends BasePlugin {
getName() {
return "Fc2Plugin";
}
async initCss() {
return fc2_plugin_default;
}
async handle() {
const fc2SearchHref = "/advanced_search?type=3&score_min=0&d=1";
$(".navbar-item:contains(\"FC2\")").attr("href", fc2SearchHref);
$(".tabs a:contains(\"FC2\")").attr("href", fc2SearchHref);
if (currentHref.includes("advanced_search?type=3")) {
$("h2.section-title").contents().first().replaceWith("Fc2PPV");
$(".section .container > .box").remove();
}
if (currentHref.includes("collection_codes?movieId")) {
$("section").html("");
const params = new URLSearchParams(window.location.search);
const movieId = params.get("movieId");
const carNum = params.get("carNum");
const url = params.get("url");
if (movieId && carNum && url) this.openFc2Dialog(movieId, carNum, url);
}
}
openFc2Dialog(movieId, carNum, url) {
const carNumWithoutPrefix = carNum.replace("FC2-", "");
if (url.includes("123av")) {
const fc2By123Av = this.getBean("Fc2By123AvPlugin");
if (fc2By123Av) {
fc2By123Av.open123AvFc2Dialog(carNum, url);
return;
}
}
const dialogHtml = `
<div class="movie-detail-container">
<!--<div class="movie-poster-container">
<iframe class="movie-trailer" frameborder="0" allowfullscreen scrolling="no"></iframe>
</div>-->
<!-- <div class="right-box">-->
<div class="movie-info-container">
<div class="search-loading">加载中...</div>
</div>
<div class="movie-panel-info fc2-movie-panel-info" style="margin-top:20px"><strong>第三方资源: </strong></div>
<div style="margin: 30px 0">
<a id="filterBtn" class="menu-btn" style="background-color:${BLOCK_COLOR}"><span>${BLOCK_TEXT}</span></a>
<a id="favoriteBtn" class="menu-btn" style="background-color:${FAVORITE_COLOR}"><span>${FAVORITE_TEXT}</span></a>
<a id="hasDownBtn" class="menu-btn" style="background-color:${HAS_DOWN_COLOR}"><span>${HAS_DOWN_TEXT$1}</span></a>
<a id="hasWatchBtn" class="menu-btn" style="background-color:${WATCHED_COLOR};"><span>${WATCHED_TEXT}</span></a>
<a id="search-subtitle-btn" class="menu-btn fr-btn" style="background:linear-gradient(to bottom, #8d5656, rgb(196,159,91))">
<span>字幕 (SubTitleCat)</span>
</a>
<a id="xunLeiSubtitleBtn" class="menu-btn fr-btn" style="background:linear-gradient(to left, #375f7c, #2196F3)">
<span>字幕 (迅雷)</span>
</a>
<a id="magnetSearchBtn" class="menu-btn fr-btn" style="width: 120px; background: linear-gradient(to right, rgb(245,140,1), rgb(84,161,29)); color: white; text-align: center; padding: 8px 0;">
<span>磁力搜索</span>
</a>
</div>
<div class="message video-panel" style="margin-top:20px">
<div id="magnets-content" class="magnet-links" style="margin: 0 0.75rem">
<div class="search-loading">加载中...</div>
</div>
</div>
<div id="reviews-content">
</div>
<div id="related-content">
</div>
<span id="data-actress" style="display: none"></span>
<!--</div>-->
</div>
`;
layer.open({
type: 1,
title: carNum,
content: dialogHtml,
area: utils.getResponsiveArea(["70%", "90%"]),
skin: "movie-detail-layer",
scrollbar: false,
success: (_layerEl, layerIndex) => {
this.loadData(movieId, carNum);
$("#favoriteBtn").on("click", async () => {
const names = $("#data-actress").text();
const publishTime = $("#data-releaseDate").text();
await storageManager.saveCar({
carNum,
url,
names,
actionType: FAVORITE_ACTION,
publishTime
});
window.refresh();
layer.closeAll();
});
$("#filterBtn").on("click", (event) => {
utils.q(event, `是否屏蔽${carNum}?`, async () => {
const names = $("#data-actress").text();
const publishTime = $("#data-releaseDate").text();
await storageManager.saveCar({
carNum,
url,
names,
actionType: FILTER_ACTION,
publishTime
});
window.refresh();
layer.closeAll();
if (window.location.href.includes("collection_codes?movieId")) utils.closePage();
});
});
$("#hasDownBtn").on("click", async () => {
const names = $("#data-actress").text();
const publishTime = $("#data-releaseDate").text();
await storageManager.saveCar({
carNum,
url,
names,
actionType: HAS_DOWN_ACTION,
publishTime
});
window.refresh();
layer.closeAll();
});
$("#hasWatchBtn").on("click", async () => {
const names = $("#data-actress").text();
const publishTime = $("#data-releaseDate").text();
await storageManager.saveCar({
carNum,
url,
names,
actionType: HAS_WATCH_ACTION,
publishTime
});
window.refresh();
layer.closeAll();
});
$("#search-subtitle-btn").on("click", (event) => utils.openPage(`https://subtitlecat.com/index.php?search=${carNum}`, carNum, false, event));
$("#xunLeiSubtitleBtn").on("click", () => this.getBean("DetailPageButtonPlugin")?.searchXunLeiSubtitle(carNum));
$("#magnetSearchBtn").on("click", () => {
const magnetHub = this.getBean("MagnetHubPlugin");
if (!magnetHub) return;
const magnetHubHtml = magnetHub.createMagnetHub(carNum);
layer.open({
type: 1,
title: "磁力搜索",
content: "<div id=\"magnetHubBox\"></div>",
area: utils.getResponsiveArea(["60%", "80%"]),
scrollbar: false,
success: () => {
$("#magnetHubBox").append(magnetHubHtml);
}
});
});
this.getBean("OtherSitePlugin")?.loadOtherSite(carNumWithoutPrefix, carNum).then();
utils.setupEscClose(layerIndex);
},
end() {
if (window.location.href.includes("collection_codes?movieId")) utils.closePage();
}
});
}
loadData(movieId, carNum) {
const carNumWithoutPrefix = carNum.replace("FC2-", "");
this.handleMovieDetail(movieId);
this.handleLongImg(carNumWithoutPrefix);
this.handleMagnets(movieId);
this.getBean("ReviewPlugin")?.showReview(movieId, $("#reviews-content")).then();
this.getBean("RelatedPlugin")?.showRelated($("#related-content"), movieId).then();
}
handleMovieDetail(movieId) {
fetchMovieDetail(movieId).then((detail) => {
const actors = detail.actors || [];
const imgList = detail.imgList || [];
let actorsHtml = "";
if (actors.length > 0) {
let actressNames = "";
for (let i = 0; i < actors.length; i++) {
const actor = actors[i];
actorsHtml += `<span class="actor-tag"><a href="/actors/${actor.id}" target="_blank">${actor.name}</a></span>`;
if (actor.gender === 0) actressNames += actor.name + " ";
}
$("#data-actress").text(actressNames);
} else actorsHtml = "<span class=\"no-data\">暂无演员信息</span>";
let imagesHtml = "";
imagesHtml = Array.isArray(imgList) && imgList.length > 0 ? imgList.map((img, idx) => `
<a href="${img}" data-fancybox="movie-gallery" data-caption="剧照 ${idx + 1}">
<img src="${img}" class="movie-image-thumb" alt=""/>
</a>
`).join("") : "<div class=\"no-data\">暂无剧照</div>";
$(".movie-info-container").html(`
<h3 class="movie-title"><strong class="current-title">${detail.title || "无标题"}</strong></h3>
<div class="movie-meta">
<span><strong>番号: </strong>${detail.carNum || "未知"}</span>
<span><strong>年份: </strong>${detail.releaseDate || "未知"}</span>
<span><strong>评分: </strong>${detail.score || "无"}</span>
<span><strong>时长: </strong>${detail.duration + " m" || "无"}</span>
</div>
<div class="movie-meta">
<span>
<strong>站点: </strong>
<a href="https://fc2ppvdb.com/articles/${(detail.carNum || "").replace("FC2-", "")}" target="_blank">fc2ppvdb</a>
<a style="margin-left: 5px;" href="https://adult.contents.fc2.com/article/${(detail.carNum || "").replace("FC2-", "")}/" target="_blank">fc2电子市场</a>
</span>
</div>
<div class="movie-actors">
<div class="actor-list"><strong>主演: </strong>${actorsHtml}</div>
</div>
<div class="movie-gallery" style="margin-top:10px">
<strong>剧照: </strong>
<div class="image-list">${imagesHtml}</div>
</div>
<div id="data-releaseDate" style="display: none">${detail.releaseDate || ""}</div>
`);
this.getBean("TranslatePlugin")?.translate(detail.carNum, false)?.then();
}).catch((err) => {
console.error(err);
$(".movie-info-container").html(`
<div class="movie-error">加载失败: ${err.message}</div>
`);
});
}
handleLongImg(carNumWithoutPrefix) {
utils.loopDetector(() => $(".movie-gallery .image-list").length > 0, async () => {
$(".movie-gallery .image-list").prepend(" <a class=\"tile-item screen-container\" style=\"overflow:hidden;max-height: 150px;max-width:150px; text-align:center;\"><div style=\"margin-top: 50px;color: #000;cursor: auto\">正在加载缩略图</div></a> ");
const screenShot = this.getBean("ScreenShotPlugin");
if (!screenShot) return;
const screenshotUrl = await screenShot.getScreenshot(carNumWithoutPrefix);
if (screenshotUrl) await screenShot.addImg("缩略图", screenshotUrl);
});
}
handleMagnets(movieId) {
(async () => {
const url = `${API_BASE}/v1/movies/${movieId}/magnets`;
const headers = { jdSignature: await reBuildSignature() };
return (await gmHttp.get(url, null, headers)).data.magnets;
})().then((magnets) => {
let magnetsHtml = "";
if (magnets.length > 0) for (let i = 0; i < magnets.length; i++) {
const magnet = magnets[i];
let rowClass = "";
if (i % 2 === 0) rowClass = "odd";
magnetsHtml += `
<div class="item columns is-desktop ${rowClass}">
<div class="magnet-name column is-four-fifths">
<a href="magnet:?xt=urn:btih:${magnet.hash}" title="右鍵點擊並選擇「複製鏈接地址」">
<span class="name">${magnet.name}</span>
<br>
<span class="meta">
${(magnet.size / 1024).toFixed(2)}GB, ${magnet.files_count}個文件
</span>
<br>
<div class="tags">
${magnet.hd ? "<span class=\"tag is-primary is-small is-light\">高清</span>" : ""}
${magnet.cnsub ? "<span class=\"tag is-warning is-small is-light\">字幕</span>" : ""}
</div>
</a>
</div>
<div class="buttons column">
<button class="button is-info is-small copy-to-clipboard" data-clipboard-text="magnet:?xt=urn:btih:${magnet.hash}" type="button"> 複製 </button>
</div>
<div class="date column"><span class="time">${magnet.created_at}</span></div>
</div>
`;
}
else magnetsHtml = "<span class=\"no-data\">暂无磁力信息</span>";
$("#magnets-content").html(magnetsHtml);
$(".buttons button[data-clipboard-text*='magnet:']").each((_idx, btn) => {
$(btn).parent().append($("<button>").text("115离线下载").addClass("button is-info is-small").click(async (event) => {
event.stopPropagation();
event.preventDefault();
const loadingHandle = loading();
try {
await this.getBean("WangPan115TaskPlugin")?.handleAddTask($(btn).attr("data-clipboard-text"));
} catch (err) {
show.error("发生错误:" + err);
console.error(err);
} finally {
loadingHandle.close();
}
}));
});
}).catch((err) => {
console.error(err);
$("#magnets-content").html(`
<div class="movie-error">加载失败: ${err.message}</div>
`);
});
}
async openFc2Page(movieId, carNum, url) {
const javdbUrl = await this.getBean("OtherSitePlugin")?.getJavDbUrl();
window.open(`${javdbUrl}/users/collection_codes?movieId=${movieId}&carNum=${carNum}&url=${url}`);
}
};
var SELECTOR_LEFT = "body > section > div > nav > a.pagination-previous";
var SELECTOR_RIGHT = "body > section > div > nav > a.pagination-next";
var KeyPageTurningPlugin = class extends BasePlugin {
lockLeft = false;
lockRight = false;
getName() {
return "KeyPageTurningPlugin";
}
async initCss() {
return "";
}
async handle() {
if (window.isDetailPage) return;
window.addEventListener("keydown", (e) => {
if (this.isTyping()) return;
if (e.key === "ArrowLeft" && !this.lockLeft) {
const a = document.querySelector(SELECTOR_LEFT) || null;
if (a) {
e.preventDefault();
this.safeClick(a);
this.lockLeft = true;
}
} else if (e.key === "ArrowRight" && !this.lockRight) {
const a = document.querySelector(SELECTOR_RIGHT) || null;
if (a) {
e.preventDefault();
this.safeClick(a);
this.lockRight = true;
}
}
}, { passive: false });
window.addEventListener("keyup", (e) => {
if (e.key === "ArrowLeft") this.lockLeft = false;
if (e.key === "ArrowRight") this.lockRight = false;
});
}
isTyping() {
const el = document.activeElement;
if (!el) return false;
const tag = el.tagName;
return el.isContentEditable || tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT";
}
safeClick(a) {
if (!a) return false;
if (typeof a.click === "function") {
a.click();
return true;
}
const evt = new MouseEvent("click", {
bubbles: true,
cancelable: true
});
return a.dispatchEvent(evt);
}
};
var ModMyListOpenWayPlugin = class extends BasePlugin {
getName() {
return "ModMyListOpenWayPlugin";
}
async initCss() {
return "";
}
async handle() {
if (!location.pathname.includes("/users/lists")) return;
const segments = location.pathname.split("/").filter(Boolean);
const last = segments[segments.length - 1];
const ul = document.querySelector("#lists > ul");
if (!ul) return;
const lis = ul.children;
const isListsPage = last === "lists";
const page = Number(new URLSearchParams(location.search).get("page")) || 1;
if (isListsPage && page < 2) lis[0].style.display = "none";
for (let i = isListsPage && page < 2 ? 1 : 0; i < lis.length; i++) {
const a = lis[i].querySelector("div.column.is-10 > a");
if (!a) continue;
a.target = "_blank";
if (isListsPage) a.href = `/lists/${new URL(a.href).searchParams.get("id")}`;
}
}
};
var page_sort_plugin_default = "/**\r\n * page-sort 插件样式 —— 排序按钮选中态。\r\n *\r\n * 原脚本 injectSortStyles() 用 document.createElement('style') 注入:\r\n * style.textContent = `\r\n * .button.is-small.selected-method,\r\n * .button.is-small.selected-method:hover {\r\n * background-color: rgb(25, 135, 84) !important;\r\n * border-color: transparent !important;\r\n * color: #fff !important;\r\n * }\r\n * `;\r\n *\r\n * 此处提取为独立 .css,由 initCss() 返回 → PluginManager utils.insertStyle 注入。\r\n * CSS 规则内容与原脚本一致(缩进标准化为 4 空格,CSS 解析忽略空白,渲染等价)。\r\n */\r\n.button.is-small.selected-method,\r\n.button.is-small.selected-method:hover {\r\n background-color: rgb(25, 135, 84) !important;\r\n border-color: transparent !important;\r\n color: #fff !important;\r\n}\r\n";
var LOG$2 = "[pageSort]";
function compareItems($itemA, $itemB) {
const getStrongText = ($item) => {
const $strong = $item.find("a > div.video-title > strong");
return $strong.length ? $strong.text().trim() : "";
};
const textA = getStrongText($itemA);
const textB = getStrongText($itemB);
return textA.localeCompare(textB);
}
function getScore$1($item) {
const $span = $item.find("a > div.score > span");
if (!$span.length) return 0;
const match = $span.text().trim().match(/(\d+\.\d+)/);
if (!match) return 0;
return parseFloat(match[1]) || 0;
}
function newOption(text) {
return $("<span>", {
text,
class: "button is-small"
});
}
var SORT_CONFIGS = [
{
label: "按照名称升序",
sortFn: (items) => items.sort((a, b) => compareItems($(a), $(b))),
implemented: true
},
{
label: "按照名称降序",
sortFn: (items) => items.sort((a, b) => compareItems($(b), $(a))),
implemented: true
},
{
label: "按照评分升序",
sortFn: (items) => items.sort((a, b) => getScore$1($(a)) - getScore$1($(b))),
implemented: true
},
{
label: "按照评分降序",
sortFn: (items) => items.sort((a, b) => getScore$1($(b)) - getScore$1($(a))),
implemented: true
}
];
var PageSortPlugin = class extends BasePlugin {
$container = null;
activeSort = null;
isApplyingSort = false;
sortGuardRetries = 0;
MAX_GUARD_RETRIES = 5;
sortGuard = null;
$buttons = null;
getName() {
return "PageSortPlugin";
}
async initCss() {
return page_sort_plugin_default;
}
async handle() {
if (!window.isListPage) return;
if (await storageManager.getSetting("autoPage") === "yes") return;
this.waitForContainer();
}
waitForContainer() {
console.log(`${LOG$2} 等待页面容器加载...`);
new MutationObserver((_mutations, obs) => {
if ($("body > section > div").length) {
obs.disconnect();
console.log(`${LOG$2} 页面容器已就绪,开始注入排序选择器`);
this.createSortSelector();
}
}).observe(document.body, {
childList: true,
subtree: true
});
}
createSortSelector() {
const $toolbar = $("body > section > div > div.toolbar");
if (!$toolbar.length) {
console.warn(`${LOG$2} 未找到工具栏 .toolbar,跳过排序选择器注入`);
return;
}
const $container = $("body > section > div > div.movie-list.h.cols-4.vcols-8");
if (!$container.length) {
console.warn(`${LOG$2} 未找到视频列表容器 .movie-list,跳过排序选择器注入`);
return;
}
this.$container = $container;
const $items = $container.children(".item");
if ($items.length === 0) {
console.warn(`${LOG$2} 视频列表为空,跳过排序选择器注入`);
return;
}
$items.each(function(i) {
if (!this.hasAttribute("data-original-index")) this.setAttribute("data-original-index", String(i));
});
const sortGuard = new MutationObserver(() => {
if (this.activeSort && !this.isApplyingSort) {
if (this.sortGuardRetries >= this.MAX_GUARD_RETRIES) {
console.warn(`${LOG$2} 排序守卫重试已达上限 (${this.MAX_GUARD_RETRIES}),放弃自动恢复`);
return;
}
this.sortGuardRetries++;
console.log(`${LOG$2} 检测到 DOM 顺序被外部修改,重新应用排序 (${this.sortGuardRetries}/${this.MAX_GUARD_RETRIES})`);
this.applySort(this.activeSort);
}
});
this.sortGuard = sortGuard;
sortGuard.observe($container[0], { childList: true });
const $buttonGroup = $("<div>", { css: {
display: "inline-block",
marginBottom: ".1rem",
lineHeight: "2.2rem",
marginRight: ".4rem",
marginLeft: "auto"
} });
const $buttons = $("<div>", { class: "buttons has-addons" });
this.$buttons = $buttons;
$buttonGroup.append($buttons);
$toolbar.append($buttonGroup);
SORT_CONFIGS.forEach((config) => {
$buttons.append(newOption(config.label));
});
$buttons.on("click", ".button.is-small", (e) => {
e.preventDefault();
e.stopPropagation();
const $this = $(e.currentTarget);
const isActive = $this.hasClass("selected-method");
this.sortGuardRetries = 0;
localStorage.removeItem("jhs_sortMethod");
if (isActive) {
$this.removeClass("selected-method");
this.activeSort = null;
this.applySort(null);
} else {
$this.siblings(".selected-method").removeClass("selected-method");
$this.addClass("selected-method");
const method = $this.text();
this.activeSort = method;
this.applySort(method);
}
});
$("#sort-toggle-btn").on("click", () => {
this.activeSort = null;
this.sortGuardRetries = 0;
if (this.$buttons) this.$buttons.find(".selected-method").removeClass("selected-method");
});
console.log(`${LOG$2} 排序选择器已注入,共 ${$items.length} 个影片`);
}
applySort(sortMethod) {
if (this.isApplyingSort) return;
this.isApplyingSort = true;
this.sortGuard?.disconnect();
try {
const currentItems = this.$container.children(".item").get();
if (currentItems.length === 0) return;
if (sortMethod === null) {
currentItems.sort((a, b) => {
return (parseInt(a.getAttribute("data-original-index") || "0") || 0) - (parseInt(b.getAttribute("data-original-index") || "0") || 0);
});
this.$container.append(currentItems);
console.log(`${LOG$2} 已恢复原始顺序`);
} else {
const config = SORT_CONFIGS.find((c) => c.label === sortMethod);
if (!config) {
console.warn(`${LOG$2} 未识别的排序选项: ${sortMethod}`);
return;
}
if (!config.implemented || !config.sortFn) {
console.log(`${LOG$2} ${sortMethod} - 待实现`);
return;
}
config.sortFn(currentItems);
this.$container.append(currentItems);
console.log(`${LOG$2} 已${sortMethod}排列 ${currentItems.length} 个影片`);
}
this.sortGuard?.takeRecords();
} finally {
if (this.$container && this.sortGuard) this.sortGuard.observe(this.$container[0], { childList: true });
this.isApplyingSort = false;
}
}
};
var status_tag_filter_plugin_default = "/**\r\n * status-tag-filter 插件样式 —— 状态标签筛选栏 + 芯片。\r\n *\r\n * 原脚本 GM_addStyle(`...`) 注入,此处提取为独立 .css,由 initCss() 返回 →\r\n * PluginManager utils.insertStyle 注入。CSS 规则内容与原脚本一致(缩进标准化,\r\n * CSS 解析忽略空白,渲染等价)。\r\n */\r\n.status-tag-filter-bar {\r\n display: flex;\r\n align-items: flex-start;\r\n gap: 8px;\r\n padding: 8px 0 12px 0;\r\n border-bottom: 1px solid #e9ecef;\r\n}\r\n.status-tag-filter-label {\r\n flex-shrink: 0;\r\n font-size: 0.8em;\r\n font-weight: 600;\r\n color: #6c757d;\r\n line-height: 1.8;\r\n margin-right: 4px;\r\n}\r\n.status-tag-filter-chips {\r\n display: flex;\r\n flex-wrap: wrap;\r\n gap: 6px;\r\n}\r\n.status-tag-filter-chip {\r\n display: inline-block;\r\n padding: 0.25em 0.7em;\r\n font-size: 0.75em;\r\n font-weight: 600;\r\n line-height: 1.5;\r\n border-radius: 50rem;\r\n cursor: pointer;\r\n user-select: none;\r\n border: 1.5px solid #dee2e6;\r\n background: #fff;\r\n color: #495057;\r\n transition: all 0.15s ease;\r\n}\r\n.status-tag-filter-chip:hover {\r\n border-color: #adb5bd;\r\n background: #f8f9fa;\r\n}\r\n.status-tag-filter-chip.active {\r\n background: #198754;\r\n border-color: #198754;\r\n color: #fff;\r\n}\r\n.status-tag-filter-chip.no-status {\r\n border-style: dashed;\r\n color: #6c757d;\r\n}\r\n.status-tag-filter-chip.no-status.active {\r\n background: #6c757d;\r\n border-color: #6c757d;\r\n border-style: solid;\r\n color: #fff;\r\n}\r\n";
var LOG$1 = "[状态标签筛选]";
var HIDDEN_ATTR = "data-status-tag-hidden";
var JHS_HIDE_ATTR = "data-hide";
var STATUS_TAG_SELECTOR = ".item .tags.has-addons .tag.is-success.status-tag";
var NO_TAG_VALUE = "no-tag";
function collectStatusTagCounts() {
const counts = {};
document.querySelectorAll(STATUS_TAG_SELECTOR).forEach((el) => {
const itemEl = el.closest(".item");
if (itemEl && itemEl.hasAttribute(JHS_HIDE_ATTR)) return;
const text = el.textContent?.trim() || "";
if (text) counts[text] = (counts[text] || 0) + 1;
});
return counts;
}
function countNoStatusItems() {
let count = 0;
document.querySelectorAll(".item").forEach((item) => {
if (item.hasAttribute(JHS_HIDE_ATTR)) return;
if (!item.querySelector(STATUS_TAG_SELECTOR)) count++;
});
return count;
}
var StatusTagFilterPlugin = class extends BasePlugin {
observerDebounce = null;
observer = null;
getName() {
return "StatusTagFilterPlugin";
}
async initCss() {
return status_tag_filter_plugin_default;
}
async handle() {
if (!window.isListPage) return;
this.init();
}
init() {
console.log(`${LOG$1} 初始化, pathname:`, window.location.pathname);
if (!document.body) {
console.warn(`${LOG$1} document.body 不存在,延后初始化`);
setTimeout(() => this.init(), 100);
return;
}
if (this.tryBuild()) {
this.startObserving();
return;
}
console.log(`${LOG$1} 未找到挂载目标,开始 MutationObserver 等待`);
let mountDebounce = null;
const mountObserver = new MutationObserver(() => {
if (mountDebounce) clearTimeout(mountDebounce);
mountDebounce = setTimeout(() => {
if (this.tryBuild()) {
console.log(`${LOG$1} MutationObserver 挂载成功`);
mountObserver.disconnect();
this.startObserving();
if (mountTimeout) clearTimeout(mountTimeout);
}
}, 100);
});
mountObserver.observe(document.body, {
childList: true,
subtree: true
});
const mountTimeout = setTimeout(() => {
mountObserver.disconnect();
if (!document.querySelector(".status-tag-filter-bar")) {
const fallback = this.findMountTarget() || document.body.firstElementChild;
if (fallback) {
this.doBuild(fallback);
this.startObserving();
console.warn(`${LOG$1} 通过最终回退挂载`, fallback);
} else console.warn(`${LOG$1} 超时后仍无挂载目标`);
}
}, 1e4);
}
tryBuild() {
if (document.querySelector(".status-tag-filter-bar")) return true;
const mountTarget = this.findMountTarget();
if (!mountTarget) return false;
this.doBuild(mountTarget);
return true;
}
findMountTarget() {
const tagFilterBar = document.querySelector(".tag-filter-bar");
if (tagFilterBar) return tagFilterBar;
if (/^\/actors\//.test(window.location.pathname)) {
const actorTags = document.querySelector("body > section > div > div.actor-tags.tags");
if (actorTags) return actorTags;
} else {
const tabsBoxed = document.querySelector("body > section > div > div.tabs.is-boxed");
if (tabsBoxed) return tabsBoxed;
}
const section = document.querySelector("body > section > div > div");
if (section && section.firstElementChild) {
if (!section.firstElementChild.matches(".tag-filter-bar, .status-tag-filter-bar")) return section.firstElementChild;
}
const container = document.querySelector("body > section > div");
if (container && container.firstElementChild) {
if (!container.firstElementChild.matches(".tag-filter-bar, .status-tag-filter-bar")) return container.firstElementChild;
}
return null;
}
doBuild(mountTarget) {
if (document.querySelector(".status-tag-filter-bar")) return;
const filterBar = document.createElement("div");
filterBar.className = "status-tag-filter-bar";
const label = document.createElement("span");
label.className = "status-tag-filter-label";
label.textContent = "状态:";
filterBar.appendChild(label);
const chipsContainer = document.createElement("div");
chipsContainer.className = "status-tag-filter-chips";
filterBar.appendChild(chipsContainer);
const refreshChips = () => {
const activeValues = new Set(Array.from(chipsContainer.querySelectorAll(".status-tag-filter-chip.active")).map((c) => c.dataset.value || ""));
chipsContainer.innerHTML = "";
const noCount = countNoStatusItems();
const noTagChip = this.createFilterChip("无状态标签", NO_TAG_VALUE, {
isNoTag: true,
count: noCount
});
if (activeValues.has(NO_TAG_VALUE)) noTagChip.classList.add("active");
chipsContainer.appendChild(noTagChip);
const allCounts = collectStatusTagCounts();
Object.keys(allCounts).sort().forEach((tagName) => {
const chip = this.createFilterChip(tagName, tagName, { count: allCounts[tagName] });
if (activeValues.has(tagName)) chip.classList.add("active");
chipsContainer.appendChild(chip);
});
};
refreshChips();
if (mountTarget.matches(".tag-filter-bar, .actor-tags.tags, .tabs.is-boxed")) mountTarget.insertAdjacentElement("afterend", filterBar);
else mountTarget.insertAdjacentElement("beforebegin", filterBar);
filterBar._refreshChips = refreshChips;
console.log(`${LOG$1} 筛选栏已挂载`);
}
createFilterChip(labelText, value, opts = {}) {
const { isNoTag = false, count } = opts;
const chip = document.createElement("span");
chip.className = "status-tag-filter-chip";
if (isNoTag) chip.classList.add("no-status");
chip.textContent = count !== void 0 ? `${labelText} ${count}` : labelText;
chip.dataset.value = value;
chip.addEventListener("click", () => {
chip.classList.toggle("active");
this.applyFilter();
});
return chip;
}
applyFilter() {
const activeChips = document.querySelectorAll(".status-tag-filter-chip.active");
const selectedValues = new Set(Array.from(activeChips).map((c) => c.dataset.value || ""));
if (selectedValues.size === 0) {
document.querySelectorAll(`.item[${HIDDEN_ATTR}]`).forEach((item) => {
const htmlItem = item;
if (htmlItem.hasAttribute(JHS_HIDE_ATTR)) return;
htmlItem.removeAttribute(HIDDEN_ATTR);
htmlItem.style.display = "";
});
return;
}
const showNoTag = selectedValues.has(NO_TAG_VALUE);
const selectedTags = new Set([...selectedValues].filter((v) => v !== NO_TAG_VALUE));
document.querySelectorAll(".item").forEach((item) => {
const htmlItem = item;
const hiddenByJhs = htmlItem.hasAttribute(JHS_HIDE_ATTR);
const hiddenByOther = htmlItem.style.display === "none" && !htmlItem.hasAttribute(HIDDEN_ATTR);
if (hiddenByJhs || hiddenByOther) return;
const itemStatusTags = new Set();
item.querySelectorAll(STATUS_TAG_SELECTOR).forEach((el) => {
const text = el.textContent?.trim() || "";
if (text) itemStatusTags.add(text);
});
let tagMatch = false;
if (selectedTags.size > 0) tagMatch = [...selectedTags].some((t) => itemStatusTags.has(t));
const noTagMatch = showNoTag && itemStatusTags.size === 0;
if (tagMatch || noTagMatch) {
htmlItem.removeAttribute(HIDDEN_ATTR);
htmlItem.style.display = "";
} else {
htmlItem.setAttribute(HIDDEN_ATTR, "");
htmlItem.style.display = "none";
}
});
}
updateFilterBar() {
const filterBar = document.querySelector(".status-tag-filter-bar");
if (filterBar && filterBar._refreshChips) {
filterBar._refreshChips();
this.applyFilter();
}
}
startObserving() {
this.observer = new MutationObserver((mutations) => {
let shouldRefresh = false;
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
if (node.nodeType !== Node.ELEMENT_NODE) continue;
const el = node;
if (el.matches?.(".item") || el.querySelectorAll?.(".item").length > 0 || el.matches?.(".tag.is-success.status-tag") || el.querySelectorAll?.(".tag.is-success.status-tag").length > 0) {
shouldRefresh = true;
break;
}
}
if (shouldRefresh) break;
}
if (shouldRefresh) {
if (this.observerDebounce) clearTimeout(this.observerDebounce);
this.observerDebounce = setTimeout(() => {
this.updateFilterBar();
}, 150);
}
});
this.observer.observe(document.body, {
childList: true,
subtree: true
});
}
};
var list_waterfall_plugin_default = "/**\r\n * list-waterfall 插件样式 —— 瀑布流 loader 三态 + 回到顶部按钮。\r\n *\r\n * 原脚本 GM_addStyle(`...`) 注入(L80-153),此处提取为独立 .css,由 initCss()\r\n * 返回 → PluginManager utils.insertStyle 注入。CSS 规则内容与原脚本一致(缩进\r\n * 标准化,CSS 解析忽略空白,渲染等价)。\r\n */\r\n.jdb-wf-loader {\r\n text-align: center;\r\n padding: 24px 0 40px;\r\n font-size: 0.9rem;\r\n color: #6c757d;\r\n min-height: 44px;\r\n box-sizing: border-box;\r\n}\r\n.jdb-wf-loader.loading {\r\n color: #485fc7;\r\n}\r\n.jdb-wf-loader.loading::before {\r\n content: \"\";\r\n display: inline-block;\r\n width: 14px;\r\n height: 14px;\r\n margin-right: 8px;\r\n border: 2px solid currentColor;\r\n border-top-color: transparent;\r\n border-radius: 50%;\r\n vertical-align: -2px;\r\n animation: jdb-wf-spin 0.8s linear infinite;\r\n}\r\n.jdb-wf-loader.error {\r\n color: #f44336;\r\n cursor: pointer;\r\n text-decoration: underline;\r\n}\r\n.jdb-wf-loader.no-more {\r\n color: #4CAF50;\r\n}\r\n@keyframes jdb-wf-spin {\r\n to {\r\n transform: rotate(360deg);\r\n }\r\n}\r\n\r\n/* 回到顶部按钮 */\r\n#jdb-wf-back-to-top {\r\n position: fixed;\r\n bottom: 40px;\r\n right: 40px;\r\n width: 44px;\r\n height: 44px;\r\n background-color: rgba(30, 30, 30, 0.9);\r\n backdrop-filter: blur(4px);\r\n color: #e0e0e0;\r\n border-radius: 50%;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n cursor: pointer;\r\n z-index: 9999;\r\n opacity: 0;\r\n visibility: hidden;\r\n transform: translateY(20px) scale(0.9);\r\n transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\r\n border: 1px solid rgba(255, 255, 255, 0.05);\r\n user-select: none;\r\n}\r\n#jdb-wf-back-to-top:hover {\r\n background-color: #ff8400;\r\n color: #fff;\r\n transform: translateY(0) scale(1);\r\n box-shadow: 0 8px 20px rgba(255, 132, 0, 0.3);\r\n border-color: #ff8400;\r\n}\r\n#jdb-wf-back-to-top.show {\r\n opacity: 1;\r\n visibility: visible;\r\n transform: translateY(0) scale(1);\r\n}\r\n#jdb-wf-back-to-top svg {\r\n width: 22px;\r\n height: 22px;\r\n fill: currentColor;\r\n stroke: currentColor;\r\n stroke-width: 0;\r\n}\r\n";
var LOG_PREFIX$3 = "[listWaterfall]";
var ENABLED_KEY = "jdb:list-waterfall-enabled";
var PRELOAD_DISTANCE = 800;
var MAX_PAGES = 200;
var ALLOWED_PATHS = new Set(["/users/lists", "/users/favorite_lists"]);
var SEL = {
box: "#lists > ul",
item: "#lists > ul > li",
nextLink: "a.pagination-next",
paginationNav: "nav.pagination",
itemLink: "div.column.is-10 > a"
};
function getInitialPage() {
const m = location.search.match(/[?&]page=(\d+)/);
return m ? parseInt(m[1], 10) : 1;
}
function findNextUrl(doc) {
const a = doc.querySelector(SEL.nextLink);
return a ? a.getAttribute("href") : null;
}
function toAbsolute(href) {
return new URL(href, location.href).href;
}
function rewriteItemLinks(container) {
container.querySelectorAll(SEL.itemLink).forEach((a) => {
const anchor = a;
anchor.target = "_blank";
const href = anchor.getAttribute("href") || "";
if (/^\/lists\/[^/]+$/.test(href)) return;
const m = href.match(/[?&]id=([^&]+)/);
if (m) anchor.href = `/lists/${m[1]}`;
});
}
function gmGet(url) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url,
timeout: 3e4,
onload: (resp) => {
if (resp.status >= 200 && resp.status < 300) resolve(resp.responseText);
else reject(new Error(`HTTP ${resp.status}`));
},
onerror: () => reject(new Error("network error")),
ontimeout: () => reject(new Error("timeout"))
});
});
}
function isEnabled() {
return GM_getValue(ENABLED_KEY, true);
}
var ListWaterfallPlugin = class extends BasePlugin {
currentPage = getInitialPage();
nextUrl = null;
hasMore = false;
isLoading = false;
loader = null;
container = null;
loadedIds = new Set();
pageItems = [];
_onScroll = null;
backToTopBtn = null;
_ticking = false;
getName() {
return "ListWaterfallPlugin";
}
async initCss() {
return list_waterfall_plugin_default;
}
async handle() {
if (!ALLOWED_PATHS.has(location.pathname)) return;
if (!isEnabled()) {
console.log(`${LOG_PREFIX$3} 瀑布流已关闭,退出`);
return;
}
GM_registerMenuCommand(`${isEnabled() ? "✓" : "✗"} 清单瀑布流自动翻页`, this.toggleEnabled.bind(this));
this.init();
}
toggleEnabled() {
const next = !isEnabled();
GM_setValue(ENABLED_KEY, next);
console.log(`${LOG_PREFIX$3} 瀑布流开关: ${next ? "开启" : "关闭"}`);
if (window.confirm(`清单瀑布流自动翻页已${next ? "开启" : "关闭"},是否刷新页面应用?`)) window.location.reload();
}
init() {
this.container = document.querySelector(SEL.box);
if (!this.container) {
console.warn(`${LOG_PREFIX$3} 未找到容器 ${SEL.box},退出`);
return;
}
this.container.querySelectorAll(SEL.item).forEach((li) => {
if (li.id) this.loadedIds.add(li.id);
});
this.loader = document.createElement("div");
this.loader.className = "jdb-wf-loader";
this.container.parentNode.insertBefore(this.loader, this.container.nextSibling);
this.loader.addEventListener("click", () => {
if (this.loader.classList.contains("error")) this.loadNextPage();
});
const nextHref = findNextUrl(document);
this.nextUrl = nextHref ? toAbsolute(nextHref) : null;
this.hasMore = !!this.nextUrl;
this.pageItems.push({
page: this.currentPage,
top: 0,
url: window.location.href
});
this.createBackToTopBtn();
this._onScroll = () => {
this.checkLoad();
this.updateCurrentPageFromScroll();
this.updateBackToTopBtn();
};
window.addEventListener("scroll", this._onScroll, { passive: true });
setTimeout(() => this.checkLoad(), 500);
if (!this.hasMore) this.setState("no-more", "已经到底了");
else this.setState("", "");
console.log(`${LOG_PREFIX$3} 已启动 (页码 ${this.currentPage})`);
}
async loadNextPage() {
if (this.isLoading || !this.nextUrl || !this.hasMore) return;
if (this.currentPage >= MAX_PAGES) {
this.setState("no-more", `已达最大页数 ${MAX_PAGES},停止加载`);
this.hasMore = false;
return;
}
this.isLoading = true;
this.setState("loading", "加载中...");
try {
const html = await gmGet(this.nextUrl);
const doc = new DOMParser().parseFromString(html, "text/html");
const remoteUl = doc.querySelector(SEL.box);
if (!remoteUl) throw new Error("下一页未找到列表容器");
const newLis = Array.from(remoteUl.children).filter((li) => li.tagName === "LI");
if (newLis.length > 0 && newLis[0].id && this.loadedIds.has(newLis[0].id)) {
this.hasMore = false;
this.nextUrl = null;
this.setState("no-more", "已经到底了");
console.log(`${LOG_PREFIX$3} 检测到重复数据,停止瀑布流`);
return;
}
const topBefore = this.container.scrollHeight;
const fragment = document.createDocumentFragment();
newLis.forEach((li) => {
if (li.id) this.loadedIds.add(li.id);
fragment.appendChild(li);
});
this.container.appendChild(fragment);
rewriteItemLinks(this.container);
this.currentPage += 1;
this.pageItems.push({
page: this.currentPage,
top: topBefore,
url: this.nextUrl
});
const nextHref = findNextUrl(doc);
this.nextUrl = nextHref ? toAbsolute(nextHref) : null;
this.hasMore = !!this.nextUrl;
const remoteNav = doc.querySelector(SEL.paginationNav);
if (remoteNav) {
const currentNav = document.querySelector(SEL.paginationNav);
if (currentNav) currentNav.replaceWith(remoteNav);
}
this.setState("", "");
if (!this.hasMore) this.setState("no-more", "已经到底了");
console.log(`${LOG_PREFIX$3} 已加载第 ${this.currentPage} 页,追加 ${newLis.length} 项`);
} catch (err) {
console.error(`${LOG_PREFIX$3} 加载失败:`, err);
this.setState("error", "加载失败,点击重试");
} finally {
this.isLoading = false;
}
}
checkLoad() {
if (!this.loader || !this.hasMore) return;
if (this.loader.getBoundingClientRect().top < window.innerHeight + PRELOAD_DISTANCE) this.loadNextPage();
}
updateCurrentPageFromScroll() {
const y = window.scrollY;
for (let i = this.pageItems.length - 1; i >= 0; i--) {
const item = this.pageItems[i];
if (y >= item.top) {
if (this.currentPage !== item.page) {
this.currentPage = item.page;
window.history.replaceState({}, "", item.url);
}
break;
}
}
}
setState(cls, text) {
if (!this.loader) return;
this.loader.className = `jdb-wf-loader ${cls}`.trim();
this.loader.textContent = text;
}
createBackToTopBtn() {
const btn = document.createElement("div");
btn.id = "jdb-wf-back-to-top";
btn.title = "回到顶部";
btn.innerHTML = "<svg viewBox=\"0 0 24 24\"><path d=\"M12 4l-8 8h6v8h4v-8h6z\"></path></svg>";
document.body.appendChild(btn);
btn.addEventListener("click", () => {
window.scrollTo({
top: 0,
behavior: "smooth"
});
});
this.backToTopBtn = btn;
}
updateBackToTopBtn() {
if (!this.backToTopBtn || this._ticking) return;
this._ticking = true;
window.requestAnimationFrame(() => {
if (window.scrollY > 300) this.backToTopBtn.classList.add("show");
else this.backToTopBtn.classList.remove("show");
this._ticking = false;
});
}
};
var list_reading_status_plugin_default = "/**\r\n * list-reading-status 插件样式 —— 阅读进度下拉框 + 星级评分 + 排序筛选工具栏。\r\n *\r\n * 原脚本 3 段 GM_addStyle(L263-303 下拉框 / L305-349 星级评分+访问链接 /\r\n * L353-445 工具栏),此处合并提取为独立 .css,由 initCss() 返回 →\r\n * PluginManager utils.insertStyle 注入。CSS 规则内容与原脚本一致(缩进标准化,\r\n * CSS 解析忽略空白,渲染等价)。\r\n */\r\n\r\n/* ---------- 阅读进度下拉框 ---------- */\r\n.list-reading-dropdown {\r\n appearance: none;\r\n -webkit-appearance: none;\r\n display: inline-flex;\r\n align-items: center;\r\n height: 24px;\r\n padding: 0 24px 0 10px;\r\n font-size: 0.72rem;\r\n font-weight: 600;\r\n line-height: 22px;\r\n border-radius: 50rem;\r\n cursor: pointer;\r\n user-select: none;\r\n border: 1.5px solid #ced4da;\r\n color: #6c757d;\r\n background-color: #fff;\r\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%236c757d'/%3E%3C/svg%3E\");\r\n background-repeat: no-repeat;\r\n background-position: right 8px center;\r\n background-size: 10px 6px;\r\n transition: all 0.2s ease;\r\n margin-right: 6px;\r\n vertical-align: middle;\r\n}\r\n.list-reading-dropdown:hover {\r\n border-color: #adb5bd;\r\n background-color: #f8f9fa;\r\n}\r\n.list-reading-dropdown[data-status=\"read\"] {\r\n color: #fff;\r\n background-color: #198754;\r\n border-color: #198754;\r\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23fff'/%3E%3C/svg%3E\");\r\n}\r\n.list-reading-dropdown[data-status=\"read\"]:hover {\r\n background-color: #157347;\r\n border-color: #157347;\r\n}\r\n\r\n/* ---------- 星级评分 ---------- */\r\n.list-rating-stars {\r\n display: inline-flex;\r\n gap: 2px;\r\n cursor: pointer;\r\n user-select: none;\r\n margin-right: 10px;\r\n vertical-align: middle;\r\n align-items: center;\r\n}\r\n.list-rating-star {\r\n width: 18px;\r\n height: 18px;\r\n flex-shrink: 0;\r\n transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1),\r\n filter 0.2s ease;\r\n}\r\n.list-rating-star path {\r\n fill: #cbd5e1;\r\n stroke: #94a3b8;\r\n stroke-width: 0.6;\r\n transition: fill 0.2s ease, stroke 0.2s ease;\r\n}\r\n.list-rating-star.filled path {\r\n fill: #f59e0b;\r\n stroke: #d97706;\r\n}\r\n.list-rating-star:hover {\r\n transform: scale(1.25);\r\n}\r\n.list-rating-star.filled:hover {\r\n filter: drop-shadow(0 0 5px rgba(245, 158, 11, 0.45));\r\n}\r\n.list-last-uri-link {\r\n font-size: 0.72rem;\r\n color: #485fc7;\r\n margin-left: 8px;\r\n text-decoration: none;\r\n transition: color 0.15s ease;\r\n}\r\n.list-last-uri-link:hover {\r\n color: #363636;\r\n text-decoration: underline;\r\n}\r\n\r\n/* ---------- 排序与筛选工具栏 ---------- */\r\n.list-toolbar {\r\n display: flex;\r\n flex-wrap: wrap;\r\n align-items: center;\r\n gap: 8px 16px;\r\n padding: 10px 0;\r\n margin-bottom: 6px;\r\n border-bottom: 1px solid #e9ecef;\r\n font-size: 0.82rem;\r\n}\r\n.list-toolbar-group {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n flex-wrap: wrap;\r\n}\r\n.list-toolbar-label {\r\n font-weight: 600;\r\n color: #6c757d;\r\n flex-shrink: 0;\r\n}\r\n.list-sort-select {\r\n appearance: none;\r\n -webkit-appearance: none;\r\n height: 26px;\r\n padding: 0 22px 0 10px;\r\n font-size: 0.78rem;\r\n font-weight: 600;\r\n border: 1.5px solid #ced4da;\r\n border-radius: 50rem;\r\n color: #495057;\r\n background-color: #fff;\r\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%236c757d'/%3E%3C/svg%3E\");\r\n background-repeat: no-repeat;\r\n background-position: right 8px center;\r\n background-size: 10px 6px;\r\n cursor: pointer;\r\n transition: all 0.2s ease;\r\n}\r\n.list-sort-select:hover {\r\n border-color: #adb5bd;\r\n background-color: #f8f9fa;\r\n}\r\n.list-filter-chip {\r\n display: inline-flex;\r\n align-items: center;\r\n padding: 2px 10px;\r\n font-size: 0.76rem;\r\n font-weight: 600;\r\n border: 1.5px solid #dee2e6;\r\n border-radius: 50rem;\r\n color: #6c757d;\r\n background-color: #fff;\r\n cursor: pointer;\r\n user-select: none;\r\n transition: all 0.15s ease;\r\n line-height: 1.4;\r\n}\r\n.list-filter-chip:hover {\r\n border-color: #adb5bd;\r\n background-color: #f8f9fa;\r\n}\r\n.list-filter-chip.active {\r\n color: #fff;\r\n background-color: #485fc7;\r\n border-color: #485fc7;\r\n}\r\n.list-filter-chip .chip-count {\r\n margin-left: 4px;\r\n opacity: 0.85;\r\n font-weight: 700;\r\n}\r\n.list-filter-divider {\r\n width: 1px;\r\n height: 18px;\r\n background: #dee2e6;\r\n margin: 0 4px;\r\n flex-shrink: 0;\r\n}\r\n.list-toolbar-reset {\r\n font-size: 0.74rem;\r\n color: #adb5bd;\r\n cursor: pointer;\r\n text-decoration: none;\r\n margin-left: auto;\r\n transition: color 0.15s ease;\r\n}\r\n.list-toolbar-reset:hover {\r\n color: #6c757d;\r\n text-decoration: underline;\r\n}\r\n";
var LOG_PREFIX$2 = "[listReadingStatus]";
var STORAGE_KEY = "jdb:list-reading-status";
var RATING_STORAGE_KEY = "jdb:list-rating";
var LAST_URI_KEY = "jdb:list-last-uri";
var SORT_KEY = "jdb:list-sort";
var FILTER_READ_KEY = "jdb:list-filter-read";
var FILTER_RATING_KEY = "jdb:list-filter-rating";
var JHS_DB_NAME = "JAV-JHS";
var JHS_STORE_NAME = "appData";
var BACKUP_KEY = "listReadingStatus_data";
var LRS_HIDDEN_ATTR = "data-lrs-hidden";
var LRS_ORDER_ATTR = "data-lrs-order";
var STAR_PATH = "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z";
function getRatingMap() {
const raw = GM_getValue(RATING_STORAGE_KEY);
if (!raw) return {};
try {
return JSON.parse(raw);
} catch {
return {};
}
}
function saveRatingMap(map) {
GM_setValue(RATING_STORAGE_KEY, JSON.stringify(map));
syncToIndexedDB();
}
function setRating(listId, rating) {
const map = getRatingMap();
if (rating > 0) map[listId] = rating;
else delete map[listId];
saveRatingMap(map);
console.log(`${LOG_PREFIX$2} 评分 ${listId}: ${rating || "清除"}`);
}
function getRating(listId) {
return getRatingMap()[listId] || 0;
}
function getLastUriMap() {
const raw = GM_getValue(LAST_URI_KEY);
if (!raw) return {};
try {
return JSON.parse(raw);
} catch {
return {};
}
}
function saveLastUri(listId) {
const map = getLastUriMap();
map[listId] = {
path: location.pathname + location.search,
timestamp: Date.now()
};
GM_setValue(LAST_URI_KEY, JSON.stringify(map));
syncToIndexedDB();
}
function getLastUri(listId) {
return getLastUriMap()[listId] || null;
}
function getReadSet() {
const raw = GM_getValue(STORAGE_KEY);
if (!raw) return new Set();
try {
const arr = JSON.parse(raw);
return new Set(Array.isArray(arr) ? arr : []);
} catch {
return new Set();
}
}
function saveReadSet(readSet) {
GM_setValue(STORAGE_KEY, JSON.stringify([...readSet]));
syncToIndexedDB();
}
function markAsRead(listId) {
const readSet = getReadSet();
readSet.add(listId);
saveReadSet(readSet);
console.log(`${LOG_PREFIX$2} 已标记已读完: ${listId}`);
}
function markAsUnread(listId) {
const readSet = getReadSet();
readSet.delete(listId);
saveReadSet(readSet);
console.log(`${LOG_PREFIX$2} 已取消标记: ${listId}`);
}
function isRead(listId) {
return getReadSet().has(listId);
}
function openJhsDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(JHS_DB_NAME);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains(JHS_STORE_NAME)) db.createObjectStore(JHS_STORE_NAME);
};
});
}
function syncToIndexedDB() {
try {
const data = {
readingStatus: [...getReadSet()],
ratings: getRatingMap(),
lastUris: getLastUriMap(),
_updatedAt: new Date().toISOString()
};
openJhsDB().then((db) => {
const tx = db.transaction(JHS_STORE_NAME, "readwrite");
tx.objectStore(JHS_STORE_NAME).put(data, BACKUP_KEY);
tx.oncomplete = () => db.close();
tx.onerror = () => db.close();
}).catch(() => {});
} catch {}
}
async function restoreFromIndexedDB() {
try {
const db = await openJhsDB();
const store = db.transaction(JHS_STORE_NAME, "readonly").objectStore(JHS_STORE_NAME);
const data = await new Promise((resolve, reject) => {
const req = store.get(BACKUP_KEY);
req.onsuccess = () => resolve(req.result);
req.onerror = reject;
});
db.close();
if (!data || !data.readingStatus) return false;
let restored = false;
const localReadSet = getReadSet();
const cloudRead = Array.isArray(data.readingStatus) ? data.readingStatus : [];
const mergedRead = new Set([...localReadSet, ...cloudRead]);
if (mergedRead.size > localReadSet.size) {
GM_setValue(STORAGE_KEY, JSON.stringify([...mergedRead]));
restored = true;
}
const localRatings = getRatingMap();
const cloudRatings = data.ratings && typeof data.ratings === "object" ? data.ratings : {};
let ratingChanged = false;
for (const [id, rating] of Object.entries(cloudRatings)) if (!(id in localRatings)) {
localRatings[id] = rating;
ratingChanged = true;
}
if (ratingChanged) {
GM_setValue(RATING_STORAGE_KEY, JSON.stringify(localRatings));
restored = true;
}
const localLastUris = getLastUriMap();
const cloudLastUris = data.lastUris && typeof data.lastUris === "object" ? data.lastUris : {};
let lastUriChanged = false;
for (const [id, uri] of Object.entries(cloudLastUris)) {
const local = localLastUris[id];
const cloudUri = uri;
if (!local || cloudUri.timestamp && cloudUri.timestamp > (local.timestamp || 0)) {
localLastUris[id] = cloudUri;
lastUriChanged = true;
}
}
if (lastUriChanged) {
GM_setValue(LAST_URI_KEY, JSON.stringify(localLastUris));
restored = true;
}
if (restored) console.log(`${LOG_PREFIX$2} 已从云端合并恢复数据 (更新于 ${data._updatedAt || "未知"})`);
return restored;
} catch {
return false;
}
}
var ListReadingStatusPlugin = class extends BasePlugin {
isProcessing = false;
currentSort = "default";
filterReadStatus = "all";
filterRatingChips = new Set();
isToolbarProcessing = false;
orderCounter = 0;
lastLiCount = -1;
observer = null;
isDetailPage = false;
getName() {
return "ListReadingStatusPlugin";
}
async initCss() {
return list_reading_status_plugin_default;
}
async handle() {
const pathname = location.pathname;
const isListPage = pathname.startsWith("/users/favorite_lists") || pathname.startsWith("/users/lists");
const isDetail = /\/lists\/[^/]+$/.test(pathname);
if (!isListPage && !isDetail) return;
this.isDetailPage = isDetail;
this.loadToolbarState();
if (this.isDetailPage) this.ensureHeaderWidgets();
else {
this.processAllItems();
this.tryBuildToolbar();
}
restoreFromIndexedDB().then((restored) => {
if (restored) if (this.isDetailPage) this.ensureHeaderWidgets();
else {
this.processAllItems();
const tb = document.querySelector(".list-toolbar");
if (tb) this.refreshChips(tb);
}
});
this.observer = new MutationObserver(() => {
if (this.isProcessing) return;
if (this.isDetailPage) this.ensureHeaderWidgets();
else {
this.processAllItems();
const ul = document.querySelector("#lists > ul");
const cnt = ul ? ul.querySelectorAll(":scope > li").length : 0;
if (cnt !== this.lastLiCount) {
this.lastLiCount = cnt;
const tb = document.querySelector(".list-toolbar");
if (tb) this.refreshChips(tb);
}
}
});
this.observer.observe(document.body, {
childList: true,
subtree: true
});
if (typeof GM_addValueChangeListener !== "undefined") {
const refreshListToolbar = () => {
if (this.isDetailPage) return;
const tb = document.querySelector(".list-toolbar");
if (tb) this.refreshChips(tb);
};
GM_addValueChangeListener(STORAGE_KEY, () => {
if (this.isDetailPage) this.ensureHeaderWidgets();
else {
this.processAllItems();
refreshListToolbar();
}
});
GM_addValueChangeListener(RATING_STORAGE_KEY, () => {
if (this.isDetailPage) this.ensureHeaderWidgets();
else {
this.processAllItems();
refreshListToolbar();
}
});
GM_addValueChangeListener(SORT_KEY, () => {
const v = GM_getValue(SORT_KEY);
if (v) this.currentSort = v;
if (this.isDetailPage) return;
this.restoreToolbarUI();
this.applySortAndFilter();
});
GM_addValueChangeListener(FILTER_READ_KEY, () => {
const v = GM_getValue(FILTER_READ_KEY);
if (v === "read" || v === "unread") this.filterReadStatus = v;
else this.filterReadStatus = "all";
if (this.isDetailPage) return;
this.restoreToolbarUI();
this.applySortAndFilter();
});
GM_addValueChangeListener(FILTER_RATING_KEY, () => {
const rc = GM_getValue(FILTER_RATING_KEY);
try {
const arr = JSON.parse(rc);
this.filterRatingChips = new Set(Array.isArray(arr) ? arr : []);
} catch {
this.filterRatingChips = new Set();
}
if (this.isDetailPage) return;
this.restoreToolbarUI();
this.applySortAndFilter();
});
}
}
updateSelectAppearance(select) {
select.setAttribute("data-status", select.value);
}
renderStars(starsEl, rating) {
starsEl.querySelectorAll(".list-rating-star").forEach((svg, i) => {
if (i < rating) svg.classList.add("filled");
else svg.classList.remove("filled");
});
}
createStarWidget(listId) {
const container = document.createElement("span");
container.className = "list-rating-stars";
container.title = "评分 1-5 星,再次点击取消评分";
const currentRating = getRating(listId);
const NS = "http://www.w3.org/2000/svg";
for (let i = 1; i <= 5; i++) {
const svg = document.createElementNS(NS, "svg");
svg.setAttribute("viewBox", "0 0 24 24");
svg.classList.add("list-rating-star");
svg.dataset.rating = String(i);
const path = document.createElementNS(NS, "path");
path.setAttribute("d", STAR_PATH);
svg.appendChild(path);
if (i <= currentRating) svg.classList.add("filled");
svg.addEventListener("click", (e) => {
e.stopPropagation();
const clicked = parseInt(svg.dataset.rating || "0");
const newRating = clicked === getRating(listId) ? 0 : clicked;
setRating(listId, newRating);
this.renderStars(container, newRating);
});
svg.addEventListener("mouseenter", () => {
this.renderStars(container, parseInt(svg.dataset.rating || "0"));
});
container.appendChild(svg);
}
container.addEventListener("mouseleave", () => {
this.renderStars(container, getRating(listId));
});
return container;
}
createDropdown(listId) {
const select = document.createElement("select");
select.className = "list-reading-dropdown";
const optionUnread = document.createElement("option");
optionUnread.value = "unread";
optionUnread.textContent = "未读完";
const optionRead = document.createElement("option");
optionRead.value = "read";
optionRead.textContent = "已读完";
select.appendChild(optionUnread);
select.appendChild(optionRead);
select.value = isRead(listId) ? "read" : "unread";
this.updateSelectAppearance(select);
select.addEventListener("change", () => {
if (select.value === "read") markAsRead(listId);
else markAsUnread(listId);
this.updateSelectAppearance(select);
});
return select;
}
ensureWidgets(li) {
const listId = li.id;
if (!listId) return;
const container = li.querySelector(":scope > div");
if (!container) return;
let select = container.querySelector(".list-reading-dropdown");
if (select) {
select.value = isRead(listId) ? "read" : "unread";
this.updateSelectAppearance(select);
} else {
select = this.createDropdown(listId);
container.prepend(select);
}
let stars = container.querySelector(".list-rating-stars");
if (stars) this.renderStars(stars, getRating(listId));
else {
stars = this.createStarWidget(listId);
container.prepend(stars);
}
let uriLink = container.querySelector(".list-last-uri-link");
const lastUri = getLastUri(listId);
if (lastUri) {
if (!uriLink) {
uriLink = document.createElement("a");
uriLink.className = "list-last-uri-link";
const d = new Date(lastUri.timestamp);
const pad = (n) => String(n).padStart(2, "0");
const dateStr = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
const search = lastUri.path.includes("?") ? " " + lastUri.path.slice(lastUri.path.indexOf("?") + 1) : "";
uriLink.textContent = `继续浏览 →${search} (${dateStr})`;
container.appendChild(uriLink);
}
uriLink.href = lastUri.path;
} else if (uriLink) uriLink.remove();
}
ensureHeaderWidgets() {
if (this.isProcessing) return;
this.isProcessing = true;
const m = location.pathname.match(/\/lists\/([^/]+)$/);
if (!m) {
this.isProcessing = false;
return;
}
const listId = "list-" + m[1];
saveLastUri(listId);
const h2 = document.querySelector("body > section > div > div.columns.is-mobile.section-columns > div > h2");
if (!h2) {
this.isProcessing = false;
return;
}
let select = h2.querySelector(".list-reading-dropdown");
if (select) {
select.value = isRead(listId) ? "read" : "unread";
this.updateSelectAppearance(select);
} else {
select = this.createDropdown(listId);
h2.prepend(select);
}
let stars = h2.querySelector(".list-rating-stars");
if (stars) this.renderStars(stars, getRating(listId));
else {
stars = this.createStarWidget(listId);
h2.prepend(stars);
}
Promise.resolve().then(() => {
this.isProcessing = false;
});
}
processAllItems() {
if (this.isProcessing) return false;
this.isProcessing = true;
const ul = document.querySelector("#lists > ul");
if (!ul) {
this.isProcessing = false;
return false;
}
const items = ul.querySelectorAll(":scope > li");
items.forEach((li) => this.ensureWidgets(li));
this.applySortAndFilter();
Promise.resolve().then(() => {
this.isProcessing = false;
});
return items.length > 0;
}
loadToolbarState() {
const s = GM_getValue(SORT_KEY);
if (s) this.currentSort = s;
const r = GM_getValue(FILTER_READ_KEY);
if (r === "read" || r === "unread") this.filterReadStatus = r;
const rc = GM_getValue(FILTER_RATING_KEY);
if (rc) try {
const arr = JSON.parse(rc);
if (Array.isArray(arr)) this.filterRatingChips = new Set(arr);
} catch {
this.filterRatingChips = new Set();
}
}
saveSortState(v) {
this.currentSort = v;
GM_setValue(SORT_KEY, v);
}
saveFilterReadState(v) {
this.filterReadStatus = v;
GM_setValue(FILTER_READ_KEY, v);
}
saveFilterRatingState(set) {
this.filterRatingChips = set;
GM_setValue(FILTER_RATING_KEY, JSON.stringify([...set]));
}
getListMeta(li) {
const listId = li.id || "";
const titleEl = li.querySelector("a[href*='/lists/']");
const title = titleEl ? titleEl.textContent.trim() : "";
const metaTxt = li.querySelector(".meta")?.textContent ?? "";
const moviesMatch = metaTxt.match(/([\d,]+)\s*部影片/);
const clicksMatch = metaTxt.match(/點擊了\s*([\d,]+)/);
return {
listId,
title,
movies: moviesMatch ? parseInt(moviesMatch[1].replace(/,/g, "")) : 0,
clicks: clicksMatch ? parseInt(clicksMatch[1].replace(/,/g, "")) : 0,
rating: getRating(listId),
visited: getLastUri(listId)?.timestamp ?? 0,
order: parseInt(li.getAttribute(LRS_ORDER_ATTR) || "0") || 0
};
}
ensureLiOrder(li) {
if (!li.hasAttribute(LRS_ORDER_ATTR)) li.setAttribute(LRS_ORDER_ATTR, String(this.orderCounter++));
}
compareLi(a, b) {
const ma = this.getListMeta(a);
const mb = this.getListMeta(b);
let cmp = 0;
switch (this.currentSort) {
case "rating-desc":
cmp = mb.rating - ma.rating;
break;
case "rating-asc":
cmp = ma.rating - mb.rating;
break;
case "movies-desc":
cmp = mb.movies - ma.movies;
break;
case "movies-asc":
cmp = ma.movies - mb.movies;
break;
case "clicks-desc":
cmp = mb.clicks - ma.clicks;
break;
case "clicks-asc":
cmp = ma.clicks - mb.clicks;
break;
case "visited-desc":
cmp = mb.visited - ma.visited;
break;
case "visited-asc":
cmp = ma.visited - mb.visited;
break;
case "title-asc":
cmp = ma.title.localeCompare(mb.title, "zh");
break;
default: cmp = 0;
}
if (cmp === 0) cmp = ma.order - mb.order;
return cmp;
}
applySort() {
if (this.currentSort === "default") return;
const ul = document.querySelector("#lists > ul");
if (!ul) return;
const lis = [...ul.querySelectorAll(":scope > li")];
if (lis.length < 2) return;
lis.forEach((li) => this.ensureLiOrder(li));
lis.sort((a, b) => this.compareLi(a, b));
if (lis.map((li) => li.id).join(",") === [...ul.querySelectorAll(":scope > li")].map((li) => li.id).join(",")) return;
const frag = document.createDocumentFragment();
lis.forEach((li) => frag.appendChild(li));
ul.appendChild(frag);
}
matchesFilter(li) {
const listId = li.id;
if (!listId) return true;
if (this.filterReadStatus !== "all") {
const read = isRead(listId);
if (this.filterReadStatus === "read" && !read) return false;
if (this.filterReadStatus === "unread" && read) return false;
}
if (this.filterRatingChips.size > 0) {
const rating = getRating(listId);
let match = false;
if (this.filterRatingChips.has("rated") && rating > 0) match = true;
if (this.filterRatingChips.has("unrated") && rating === 0) match = true;
for (let i = 1; i <= 5; i++) if (this.filterRatingChips.has(`rating-${i}`) && rating === i) {
match = true;
break;
}
if (!match) return false;
}
return true;
}
applyFilter() {
const ul = document.querySelector("#lists > ul");
if (!ul) return;
const lis = ul.querySelectorAll(":scope > li");
if (this.filterReadStatus === "all" && this.filterRatingChips.size === 0) {
lis.forEach((li) => {
const htmlLi = li;
if (htmlLi.hasAttribute(LRS_HIDDEN_ATTR)) {
htmlLi.removeAttribute(LRS_HIDDEN_ATTR);
htmlLi.style.display = "";
}
});
return;
}
lis.forEach((li) => {
const htmlLi = li;
if (htmlLi.style.display === "none" && !htmlLi.hasAttribute(LRS_HIDDEN_ATTR)) return;
if (this.matchesFilter(htmlLi)) {
htmlLi.removeAttribute(LRS_HIDDEN_ATTR);
htmlLi.style.display = "";
} else {
htmlLi.setAttribute(LRS_HIDDEN_ATTR, "");
htmlLi.style.display = "none";
}
});
}
applySortAndFilter() {
if (this.isToolbarProcessing) return;
this.isToolbarProcessing = true;
try {
this.applySort();
this.applyFilter();
} finally {
this.isToolbarProcessing = false;
}
}
countFilterStats() {
const stats = {
read: 0,
unread: 0,
rated: 0,
unrated: 0,
stars: [
0,
0,
0,
0,
0
]
};
const ul = document.querySelector("#lists > ul");
if (!ul) return stats;
ul.querySelectorAll(":scope > li").forEach((li) => {
const id = li.id;
if (!id) return;
if (isRead(id)) stats.read++;
else stats.unread++;
const r = getRating(id);
if (r > 0) {
stats.rated++;
if (r >= 1 && r <= 5) stats.stars[r - 1]++;
} else stats.unrated++;
});
return stats;
}
createFilterChip(label, value, count) {
const chip = document.createElement("span");
chip.className = "list-filter-chip";
chip.dataset.value = value;
const labelText = document.createElement("span");
labelText.textContent = label;
chip.appendChild(labelText);
const countSpan = document.createElement("span");
countSpan.className = "chip-count";
countSpan.textContent = String(count);
chip.appendChild(countSpan);
chip.addEventListener("click", () => {
if (value === "read" || value === "unread") {
const wasActive = chip.classList.contains("active");
document.querySelectorAll(".list-filter-chip[data-value='read'], .list-filter-chip[data-value='unread']").forEach((c) => c.classList.remove("active"));
if (!wasActive) {
chip.classList.add("active");
this.saveFilterReadState(value);
} else this.saveFilterReadState("all");
} else {
chip.classList.toggle("active");
const next = new Set(this.filterRatingChips);
if (chip.classList.contains("active")) next.add(value);
else next.delete(value);
this.saveFilterRatingState(next);
}
this.applySortAndFilter();
});
return chip;
}
buildToolbar() {
if (this.isDetailPage) return null;
const lists = document.querySelector("#lists");
if (!lists) return null;
if (document.querySelector(".list-toolbar")) return document.querySelector(".list-toolbar");
const toolbar = document.createElement("div");
toolbar.className = "list-toolbar";
const sortGroup = document.createElement("div");
sortGroup.className = "list-toolbar-group";
const sortLabel = document.createElement("span");
sortLabel.className = "list-toolbar-label";
sortLabel.textContent = "排序:";
const sortSelect = document.createElement("select");
sortSelect.className = "list-sort-select";
[
["default", "默认"],
["rating-desc", "评分 ↓"],
["rating-asc", "评分 ↑"],
["movies-desc", "影片数 ↓"],
["movies-asc", "影片数 ↑"],
["clicks-desc", "点击数 ↓"],
["clicks-asc", "点击数 ↑"],
["visited-desc", "最近访问 ↓"],
["visited-asc", "最久访问 ↓"],
["title-asc", "标题 A-Z"]
].forEach(([val, txt]) => {
const opt = document.createElement("option");
opt.value = val;
opt.textContent = txt;
if (val === this.currentSort) opt.selected = true;
sortSelect.appendChild(opt);
});
sortSelect.addEventListener("change", () => {
this.saveSortState(sortSelect.value);
this.applySortAndFilter();
});
sortGroup.appendChild(sortLabel);
sortGroup.appendChild(sortSelect);
toolbar.appendChild(sortGroup);
const div1 = document.createElement("div");
div1.className = "list-filter-divider";
toolbar.appendChild(div1);
const readGroup = document.createElement("div");
readGroup.className = "list-toolbar-group";
const readLabel = document.createElement("span");
readLabel.className = "list-toolbar-label";
readLabel.textContent = "阅读:";
readGroup.appendChild(readLabel);
const readChipsHost = document.createElement("div");
readGroup.appendChild(readChipsHost);
toolbar.appendChild(readGroup);
const div2 = document.createElement("div");
div2.className = "list-filter-divider";
toolbar.appendChild(div2);
const ratingGroup = document.createElement("div");
ratingGroup.className = "list-toolbar-group";
const ratingLabel = document.createElement("span");
ratingLabel.className = "list-toolbar-label";
ratingLabel.textContent = "评分:";
ratingGroup.appendChild(ratingLabel);
const ratingChipsHost = document.createElement("div");
ratingGroup.appendChild(ratingChipsHost);
toolbar.appendChild(ratingGroup);
const reset = document.createElement("a");
reset.className = "list-toolbar-reset";
reset.textContent = "重置筛选";
reset.addEventListener("click", (e) => {
e.preventDefault();
this.saveSortState("default");
this.saveFilterReadState("all");
this.saveFilterRatingState(new Set());
sortSelect.value = "default";
toolbar.querySelectorAll(".list-filter-chip.active").forEach((c) => c.classList.remove("active"));
this.applySortAndFilter();
});
toolbar.appendChild(reset);
lists.insertAdjacentElement("beforebegin", toolbar);
toolbar._readHost = readChipsHost;
toolbar._ratingHost = ratingChipsHost;
toolbar._sortSelect = sortSelect;
this.refreshChips(toolbar);
console.log(`${LOG_PREFIX$2} 排序与筛选工具栏已挂载`);
return toolbar;
}
refreshChips(toolbar) {
const stats = this.countFilterStats();
const readHost = toolbar._readHost;
if (readHost) {
readHost.innerHTML = "";
const readChip = this.createFilterChip("已读完", "read", stats.read);
if (this.filterReadStatus === "read") readChip.classList.add("active");
readHost.appendChild(readChip);
const unreadChip = this.createFilterChip("未读完", "unread", stats.unread);
if (this.filterReadStatus === "unread") unreadChip.classList.add("active");
readHost.appendChild(unreadChip);
}
const ratingHost = toolbar._ratingHost;
if (ratingHost) {
ratingHost.innerHTML = "";
const ratedChip = this.createFilterChip("有评分", "rated", stats.rated);
if (this.filterRatingChips.has("rated")) ratedChip.classList.add("active");
ratingHost.appendChild(ratedChip);
const unratedChip = this.createFilterChip("无评分", "unrated", stats.unrated);
if (this.filterRatingChips.has("unrated")) unratedChip.classList.add("active");
ratingHost.appendChild(unratedChip);
for (let i = 1; i <= 5; i++) {
const starChip = this.createFilterChip(`${i}星`, `rating-${i}`, stats.stars[i - 1]);
if (this.filterRatingChips.has(`rating-${i}`)) starChip.classList.add("active");
ratingHost.appendChild(starChip);
}
}
}
tryBuildToolbar() {
if (this.isDetailPage) return false;
const toolbar = this.buildToolbar();
if (!toolbar) return false;
this.refreshChips(toolbar);
this.applySortAndFilter();
return true;
}
restoreToolbarUI() {
const toolbar = document.querySelector(".list-toolbar");
if (!toolbar) return;
const sortSelect = toolbar._sortSelect;
if (sortSelect) sortSelect.value = this.currentSort;
this.refreshChips(toolbar);
}
};
var LOG_PREFIX$1 = "[modalListDisabler]";
var TARGET_LIST_ID = 501;
var CONTAINER_SELECTOR = "#modal-save-list > div.modal-card.fixed-height-600 > section > div > div:nth-child(1)";
var ModalListDisablerPlugin = class extends BasePlugin {
observer = null;
getName() {
return "ModalListDisablerPlugin";
}
async initCss() {
return "";
}
async handle() {
this.tryDisable();
this.observer = new MutationObserver(() => {
this.tryDisable();
});
this.observer.observe(document.body, {
childList: true,
subtree: true
});
}
disableTargetItem(container) {
let found = false;
for (const child of Array.from(container.children)) {
const span = child.querySelector("label > span");
if (!span) continue;
const match = span.innerHTML.match(/\((\d+)\)/);
if (match && parseInt(match[1], 10) === TARGET_LIST_ID) {
const input = child.querySelector("label > input");
if (input && !input.disabled && !input.checked) {
input.disabled = true;
console.log(`${LOG_PREFIX$1} 已禁用清单 #${TARGET_LIST_ID}`);
}
found = true;
}
}
return found;
}
tryDisable() {
const container = document.querySelector(CONTAINER_SELECTOR);
if (!container) return false;
return this.disableTargetItem(container);
}
};
var SPAN_SELECTOR = "div.columns.is-mobile.section-columns span.actor-section-name";
var MAX_RETRIES = 50;
var RETRY_INTERVAL = 200;
var ListParserPlugin = class extends BasePlugin {
getName() {
return "ListParserPlugin";
}
async initCss() {
return "";
}
async handle() {
if (!location.pathname.startsWith("/lists/")) return;
if (location.pathname.startsWith("/users/")) return;
this.waitForAndInsert();
}
waitForAndInsert(retries = MAX_RETRIES, interval = RETRY_INTERVAL) {
let attempts = 0;
const id = setInterval(() => {
if (this.insertWakeButton() || ++attempts >= retries) clearInterval(id);
}, interval);
}
insertWakeButton() {
const span = document.querySelector(SPAN_SELECTOR);
if (!span) return false;
if (document.getElementById("lists-protocol-wake-btn")) return true;
const btn = document.createElement("button");
btn.id = "lists-protocol-wake-btn";
btn.type = "button";
btn.textContent = "唤醒解析器";
btn.style.marginLeft = "8px";
btn.style.verticalAlign = "middle";
btn.style.display = "inline-block";
btn.style.fontWeight = "400";
btn.style.lineHeight = "1.5";
btn.style.textAlign = "center";
btn.style.whiteSpace = "nowrap";
btn.style.userSelect = "none";
btn.style.border = "1px solid #0d6efd";
btn.style.padding = "0.25rem 0.5rem";
btn.style.fontSize = "0.875rem";
btn.style.borderRadius = "0.25rem";
btn.style.backgroundColor = "#0d6efd";
btn.style.color = "#fff";
btn.style.cursor = "pointer";
btn.style.transition = "color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out";
btn.addEventListener("mouseenter", () => {
btn.style.backgroundColor = "#0b5ed7";
btn.style.borderColor = "#0a58ca";
});
btn.addEventListener("mouseleave", () => {
btn.style.backgroundColor = "#0d6efd";
btn.style.borderColor = "#0d6efd";
});
btn.addEventListener("click", (e) => {
e.preventDefault();
const fullUrl = location.origin + location.pathname;
const protocolUrl = "lists://?url=" + encodeURIComponent(fullUrl);
location.href = protocolUrl;
});
span.insertAdjacentElement("afterend", btn);
return true;
}
};
var video_lists_tag_default = "/**\r\n * video-lists-tag 插件样式 —— 标签显示 + 筛选栏 + Toast。\r\n *\r\n * 合并自 archetype/videoListsTag.user.js 的 GM_addStyle(L24-275)\r\n * 和 archetype/listsOptionSync.user.js 的 injectToastStyles(L40-115)。\r\n * CSS 规则内容与原脚本一致(缩进标准化,渲染等价)。\r\n */\r\n\r\n/* ---------- 标签显示(Bootstrap Badge Pill 风格) ---------- */\r\n.custom-tags-display {\r\n margin: 5px 0;\r\n padding: 6px;\r\n white-space: nowrap;\r\n overflow-x: auto;\r\n overflow-y: hidden;\r\n scrollbar-width: none;\r\n -webkit-overflow-scrolling: touch;\r\n padding-bottom: 2px;\r\n}\r\n.custom-tags-display::-webkit-scrollbar {\r\n display: none;\r\n}\r\n.custom-tag-link {\r\n display: inline-block;\r\n padding: 0.35em 0.65em;\r\n margin-right: 6px;\r\n font-size: 0.75em;\r\n font-weight: 700;\r\n line-height: 1;\r\n text-align: center;\r\n white-space: nowrap;\r\n vertical-align: baseline;\r\n border-radius: 50rem;\r\n text-decoration: none;\r\n color: #fff;\r\n transition: filter 0.15s ease, transform 0.15s ease;\r\n box-shadow: 0 1px 2px rgba(0,0,0,0.1);\r\n}\r\n.custom-tag-link:hover {\r\n filter: brightness(0.92);\r\n transform: translateY(-1px);\r\n box-shadow: 0 2px 5px rgba(0,0,0,0.15);\r\n}\r\n.custom-tag-link.light-bg {\r\n color: #212529;\r\n}\r\n\r\n/* ---------- 标签筛选栏 ---------- */\r\n.tag-filter-bar {\r\n display: flex;\r\n align-items: flex-start;\r\n gap: 8px;\r\n padding: 8px 0 12px 0;\r\n border-bottom: 1px solid #e9ecef;\r\n}\r\n.tag-filter-label {\r\n flex-shrink: 0;\r\n font-size: 0.8em;\r\n font-weight: 600;\r\n color: #6c757d;\r\n line-height: 1.8;\r\n margin-right: 4px;\r\n}\r\n.tag-filter-chips {\r\n display: flex;\r\n flex-wrap: wrap;\r\n gap: 6px;\r\n}\r\n.tag-filter-chip {\r\n display: inline-block;\r\n padding: 0.25em 0.7em;\r\n font-size: 0.75em;\r\n font-weight: 600;\r\n line-height: 1.5;\r\n border-radius: 50rem;\r\n cursor: pointer;\r\n user-select: none;\r\n border: 1.5px solid #dee2e6;\r\n background: #fff;\r\n color: #495057;\r\n transition: all 0.15s ease;\r\n}\r\n.tag-filter-chip:hover {\r\n border-color: #adb5bd;\r\n background: #f8f9fa;\r\n}\r\n.tag-filter-chip.active {\r\n background: #0d6efd;\r\n border-color: #0d6efd;\r\n color: #fff;\r\n}\r\n.tag-filter-chip.no-tag {\r\n border-style: dashed;\r\n color: #6c757d;\r\n}\r\n.tag-filter-chip.no-tag.active {\r\n background: #6c757d;\r\n border-color: #6c757d;\r\n border-style: solid;\r\n color: #fff;\r\n}\r\n\r\n/* ---------- 自动刷新开关 ---------- */\r\n.auto-refresh-toggle {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n margin-left: auto;\r\n flex-shrink: 0;\r\n font-size: 0.78em;\r\n color: #6c757d;\r\n user-select: none;\r\n}\r\n.auto-refresh-switch {\r\n position: relative;\r\n width: 36px;\r\n height: 20px;\r\n flex-shrink: 0;\r\n}\r\n.auto-refresh-switch input {\r\n opacity: 0;\r\n width: 0;\r\n height: 0;\r\n}\r\n.auto-refresh-slider {\r\n position: absolute;\r\n inset: 0;\r\n background: #ced4da;\r\n border-radius: 50rem;\r\n cursor: pointer;\r\n transition: background 0.2s;\r\n}\r\n.auto-refresh-slider::before {\r\n content: \"\";\r\n position: absolute;\r\n left: 2px;\r\n top: 2px;\r\n width: 16px;\r\n height: 16px;\r\n border-radius: 50%;\r\n background: #fff;\r\n transition: transform 0.2s;\r\n}\r\n.auto-refresh-switch input:checked + .auto-refresh-slider {\r\n background: #198754;\r\n}\r\n.auto-refresh-switch input:checked + .auto-refresh-slider::before {\r\n transform: translateX(16px);\r\n}\r\n\r\n/* ---------- 筛选模式下拉 ---------- */\r\n.filter-mode-dropdown {\r\n position: relative;\r\n display: inline-block;\r\n flex-shrink: 0;\r\n}\r\n.filter-mode-summary {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 0.25em 0.7em;\r\n font-size: 0.75em;\r\n font-weight: 600;\r\n line-height: 1.5;\r\n border-radius: 50rem;\r\n cursor: pointer;\r\n user-select: none;\r\n border: 1.5px solid #dee2e6;\r\n background: #fff;\r\n color: #495057;\r\n transition: all 0.15s ease;\r\n list-style: none;\r\n}\r\n.filter-mode-summary::-webkit-details-marker {\r\n display: none;\r\n}\r\n.filter-mode-summary:hover {\r\n border-color: #adb5bd;\r\n background: #f8f9fa;\r\n}\r\n.filter-mode-indicator {\r\n display: inline-block;\r\n width: 8px;\r\n height: 8px;\r\n border-radius: 50%;\r\n flex-shrink: 0;\r\n}\r\n.filter-mode-indicator.include {\r\n background: #0d6efd;\r\n box-shadow: 0 0 0 2px rgba(13, 110, 253, 0.2);\r\n}\r\n.filter-mode-indicator.exclude {\r\n background: #dc3545;\r\n box-shadow: 0 0 0 2px rgba(220, 53, 69, 0.2);\r\n}\r\n.filter-mode-arrow {\r\n font-size: 0.7em;\r\n color: #adb5bd;\r\n transition: transform 0.2s;\r\n}\r\n.filter-mode-dropdown[open] .filter-mode-arrow {\r\n transform: rotate(180deg);\r\n}\r\n.filter-mode-panel {\r\n position: absolute;\r\n top: calc(100% + 4px);\r\n left: 0;\r\n min-width: 190px;\r\n background: #fff;\r\n border: 1px solid #dee2e6;\r\n border-radius: 8px;\r\n box-shadow: 0 4px 16px rgba(0,0,0,0.12);\r\n padding: 4px 0;\r\n z-index: 1000;\r\n animation: filterModeIn 0.15s ease;\r\n}\r\n@keyframes filterModeIn {\r\n from { opacity: 0; transform: translateY(-4px); }\r\n to { opacity: 1; transform: translateY(0); }\r\n}\r\n.filter-mode-item {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 6px 14px;\r\n font-size: 0.78em;\r\n font-weight: 500;\r\n color: #495057;\r\n cursor: pointer;\r\n transition: background 0.1s;\r\n white-space: nowrap;\r\n}\r\n.filter-mode-item:hover {\r\n background: #f8f9fa;\r\n}\r\n.filter-mode-item.selected {\r\n background: rgba(13, 110, 253, 0.08);\r\n color: #0d6efd;\r\n font-weight: 600;\r\n}\r\n.filter-mode-item.exclude.selected {\r\n background: rgba(220, 53, 69, 0.08);\r\n color: #dc3545;\r\n}\r\n.filter-mode-item .filter-mode-indicator {\r\n flex-shrink: 0;\r\n}\r\n.filter-mode-separator {\r\n height: 1px;\r\n margin: 4px 8px;\r\n background: #e9ecef;\r\n}\r\n\r\n/* ---------- Toast 通知 ---------- */\r\n#jdb-toast-container {\r\n position: fixed;\r\n top: 20px;\r\n left: 20px;\r\n z-index: 99999;\r\n display: flex;\r\n flex-direction: column;\r\n pointer-events: none;\r\n}\r\n.jdb-toast {\r\n display: flex;\r\n align-items: center;\r\n gap: 10px;\r\n min-width: 220px;\r\n max-width: 380px;\r\n max-height: 200px;\r\n padding: 12px 16px;\r\n border-radius: 8px;\r\n font-size: 13px;\r\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\r\n color: #fff;\r\n line-height: 1.4;\r\n box-shadow: 0 4px 16px rgba(0,0,0,.28);\r\n backdrop-filter: blur(6px);\r\n pointer-events: auto;\r\n overflow: hidden;\r\n margin-bottom: 8px;\r\n animation: jdb-toast-in .2s cubic-bezier(.21,1.02,.73,1) forwards;\r\n transition: opacity .2s, transform .2s, max-height .2s, margin-bottom .2s;\r\n}\r\n.jdb-toast:last-child {\r\n margin-bottom: 0;\r\n}\r\n.jdb-toast.removing {\r\n opacity: 0;\r\n max-height: 0;\r\n margin-bottom: 0;\r\n padding-top: 0;\r\n padding-bottom: 0;\r\n transform: translateX(-20px);\r\n}\r\n.jdb-toast--stacked {\r\n max-height: 10px;\r\n opacity: 0.35;\r\n transform: translateX(12px);\r\n margin-bottom: 2px;\r\n cursor: pointer;\r\n}\r\n.jdb-toast--success { background: rgba(22,163,74,.92); }\r\n.jdb-toast--error { background: rgba(220,38,38,.92); }\r\n.jdb-toast--warning { background: rgba(217,119,6,.92); }\r\n.jdb-toast--info { background: rgba(37,99,235,.92); }\r\n.jdb-toast__icon {\r\n flex-shrink: 0;\r\n width: 20px;\r\n height: 20px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n.jdb-toast__msg {\r\n flex: 1;\r\n word-break: break-word;\r\n}\r\n@keyframes jdb-toast-in {\r\n from { opacity: 0; transform: translateX(-30px); }\r\n to { opacity: 1; transform: translateX(0); }\r\n}\r\n";
var bootstrapColors = [
{
name: "primary",
bg: "#0d6efd",
text: "#fff"
},
{
name: "secondary",
bg: "#6c757d",
text: "#fff"
},
{
name: "success",
bg: "#198754",
text: "#fff"
},
{
name: "danger",
bg: "#dc3545",
text: "#fff"
},
{
name: "warning",
bg: "#ffc107",
text: "#212529"
},
{
name: "info",
bg: "#0dcaf0",
text: "#212529"
},
{
name: "dark",
bg: "#212529",
text: "#fff"
}
];
function getRandomBootstrapColor() {
const color = bootstrapColors[Math.floor(Math.random() * bootstrapColors.length)];
return {
bg: color.bg,
text: color.text,
isLight: color.text !== "#fff"
};
}
var TAG_HIDDEN_ATTR = "data-video-lists-tag-hidden";
var AUTO_REFRESH_KEY = "jdb:auto-refresh-enabled";
var LAST_SYNC_KEY$1 = "jdb:last-sync";
var FILTER_MODES = {
CONTAINS_ANY: "contains-any",
CONTAINS_ALL: "contains-all",
EXCLUDES_ALL: "excludes-all",
EXCLUDES_ANY: "excludes-any"
};
var FILTER_MODE_CONFIG = [
{
value: FILTER_MODES.CONTAINS_ANY,
label: "包含任意一个",
group: "include"
},
{
value: FILTER_MODES.CONTAINS_ALL,
label: "全都包含",
group: "include"
},
{
value: FILTER_MODES.EXCLUDES_ALL,
label: "不包含以下标签",
group: "exclude"
},
{
value: FILTER_MODES.EXCLUDES_ANY,
label: "不包含以下任意一个",
group: "exclude"
}
];
function tagsEqual(a, b) {
if (a === b) return true;
if (!a || !b) return false;
if (a.length !== b.length) return false;
return JSON.stringify(a) === JSON.stringify(b);
}
var VltTags = class {
tagsCache = null;
currentFilterMode = FILTER_MODES.CONTAINS_ANY;
autoRefreshEnabled = true;
pendingNewItems = [];
debounceTimer = null;
DEBOUNCE_MS = 300;
async fetchTags(designations) {
this.tagsCache = await VltDb.queryMoviesLists(designations);
}
async fetchAndMergeTags(designations) {
const newTags = await VltDb.queryMoviesLists(designations);
if (!this.tagsCache) this.tagsCache = newTags;
else Object.assign(this.tagsCache, newTags);
}
addTagDisplay(item) {
if (item.querySelector(".custom-tags-display")) return;
const strongEl = item.querySelector("a > div.video-title > strong");
if (!strongEl) return;
const designation = strongEl.innerHTML;
if (!this.tagsCache) return;
const meta = item.querySelector(".meta");
if (!meta) return;
const container = document.createElement("div");
container.className = "custom-tags-display";
const tags = this.tagsCache[designation];
if (tags && tags.length > 0) tags.forEach((tag) => {
const urlTrimmed = tag.url?.trim();
const hasUrl = !!urlTrimmed;
const el = document.createElement(hasUrl ? "a" : "span");
el.className = "custom-tag-link";
if (hasUrl && urlTrimmed) {
const anchor = el;
anchor.href = urlTrimmed;
anchor.target = "_blank";
anchor.rel = "noopener noreferrer";
}
el.textContent = tag.name;
const style = tag.style;
if (style && style.bg && style.text) {
el.style.backgroundColor = style.bg;
el.style.color = style.text;
if (style.text !== "#fff") el.classList.add("light-bg");
} else {
const color = getRandomBootstrapColor();
el.style.backgroundColor = color.bg;
el.style.color = color.text;
if (color.isLight) el.classList.add("light-bg");
}
container.appendChild(el);
});
else {
const placeholder = document.createElement("span");
placeholder.className = "custom-tag-link";
placeholder.textContent = "—";
placeholder.style.backgroundColor = "#e9ecef";
placeholder.style.color = "#6c757d";
placeholder.style.pointerEvents = "none";
placeholder.style.userSelect = "none";
container.appendChild(placeholder);
}
container.addEventListener("wheel", (e) => {
if (e.deltaY !== 0) {
const atStart = container.scrollLeft <= 0 && e.deltaY < 0;
const atEnd = container.scrollLeft + container.clientWidth >= container.scrollWidth - 1 && e.deltaY > 0;
if (!atStart && !atEnd) {
e.preventDefault();
container.scrollLeft += e.deltaY;
}
}
}, { passive: false });
meta.insertAdjacentElement("afterend", container);
}
async refreshAllTags() {
const items = document.querySelectorAll(".item");
const lists = Array.from(items).map((item) => {
const strong = item.querySelector("a > div.video-title > strong");
return strong ? strong.innerHTML : null;
}).filter((s) => !!s);
if (lists.length === 0) return;
console.log(`[视频清单标签] 开始刷新,共 ${lists.length} 个番号`);
try {
await this.fetchTags(lists);
} catch (err) {
console.error(`自动刷新标签数据失败(${lists.length} 个番号):`, err);
return;
}
document.querySelectorAll(".custom-tags-display").forEach((el) => el.remove());
document.querySelectorAll(".item").forEach((item) => this.addTagDisplay(item));
this.updateFilterBar();
console.log("[视频清单标签] 自动刷新完成");
}
async refreshDesignation(designation) {
console.log(`[视频清单标签] refreshDesignation: ${designation}`);
const allItems = document.querySelectorAll(".item");
const targetItem = Array.from(allItems).find((item) => {
const strong = item.querySelector("a > div.video-title > strong");
return strong && strong.innerHTML === designation;
});
if (!targetItem) {
console.log(`[视频清单标签] ${designation} 不在当前页面 (共 ${allItems.length} 张卡片)`);
return;
}
const oldTags = this.tagsCache ? this.tagsCache[designation] || [] : null;
try {
await this.fetchAndMergeTags([designation]);
} catch (err) {
console.error(`[视频清单标签] 刷新 ${designation} 失败:`, err);
return;
}
const newTags = this.tagsCache[designation] || [];
if (tagsEqual(oldTags, newTags)) {
console.log(`[视频清单标签] ${designation} 标签未变化,跳过 DOM 更新 (${newTags.length} 个标签)`);
return;
}
const oldContainer = targetItem.querySelector(".custom-tags-display");
if (oldContainer) oldContainer.remove();
this.addTagDisplay(targetItem);
this.updateFilterBar();
console.log(`[视频清单标签] ${designation} 标签已更新 (${oldTags ? oldTags.length : 0} → ${newTags.length})`);
}
loadAutoRefreshState() {
try {
const val = GM_getValue(AUTO_REFRESH_KEY);
if (val === void 0) {
this.autoRefreshEnabled = true;
console.log("[视频清单标签] 自动刷新: 未设置过 → 默认开启");
} else {
this.autoRefreshEnabled = val === true || val === "true";
console.log(`[视频清单标签] 自动刷新: 存储值 = ${this.autoRefreshEnabled} (原始=${JSON.stringify(val)})`);
}
} catch (e) {
this.autoRefreshEnabled = true;
console.warn("[视频清单标签] 自动刷新: 读取异常 → 默认开启", e);
}
}
saveAutoRefreshState(enabled) {
try {
GM_setValue(AUTO_REFRESH_KEY, enabled);
} catch {}
}
applyFilter() {
const activeChips = document.querySelectorAll(".tag-filter-chip.active");
const selectedValues = new Set(Array.from(activeChips).map((c) => c.dataset.value || ""));
if (selectedValues.size === 0) {
document.querySelectorAll(`.item[${TAG_HIDDEN_ATTR}]`).forEach((item) => {
item.removeAttribute(TAG_HIDDEN_ATTR);
item.style.display = "";
});
return;
}
const showNoTag = selectedValues.has("no-tag");
const selectedTags = new Set([...selectedValues].filter((v) => v !== "no-tag"));
document.querySelectorAll(".item").forEach((item) => {
const htmlItem = item;
if (htmlItem.style.display === "none" && !htmlItem.hasAttribute(TAG_HIDDEN_ATTR)) return;
const tagLinks = item.querySelectorAll(".custom-tag-link:not([style*='pointer-events: none'])");
const itemTagNames = new Set(Array.from(tagLinks).map((el) => el.textContent?.trim() || ""));
let tagMatch = false;
if (selectedTags.size > 0) switch (this.currentFilterMode) {
case FILTER_MODES.CONTAINS_ANY:
tagMatch = [...selectedTags].some((t) => itemTagNames.has(t));
break;
case FILTER_MODES.CONTAINS_ALL:
tagMatch = [...selectedTags].every((t) => itemTagNames.has(t));
break;
case FILTER_MODES.EXCLUDES_ALL:
tagMatch = ![...selectedTags].some((t) => itemTagNames.has(t));
break;
case FILTER_MODES.EXCLUDES_ANY:
tagMatch = ![...selectedTags].every((t) => itemTagNames.has(t));
break;
default: tagMatch = [...selectedTags].some((t) => itemTagNames.has(t));
}
const noTagMatch = showNoTag && itemTagNames.size === 0;
if (tagMatch || noTagMatch) {
htmlItem.removeAttribute(TAG_HIDDEN_ATTR);
htmlItem.style.display = "";
} else {
htmlItem.setAttribute(TAG_HIDDEN_ATTR, "");
htmlItem.style.display = "none";
}
});
}
buildFilterModeDropdown() {
const details = document.createElement("details");
details.className = "filter-mode-dropdown";
const summary = document.createElement("summary");
summary.className = "filter-mode-summary";
const indicator = document.createElement("span");
indicator.className = "filter-mode-indicator";
summary.appendChild(indicator);
const modeText = document.createElement("span");
modeText.className = "filter-mode-text";
summary.appendChild(modeText);
const arrow = document.createElement("span");
arrow.className = "filter-mode-arrow";
arrow.textContent = "▼";
summary.appendChild(arrow);
details.appendChild(summary);
const panel = document.createElement("div");
panel.className = "filter-mode-panel";
const updateModeUI = () => {
const config = FILTER_MODE_CONFIG.find((m) => m.value === this.currentFilterMode) || FILTER_MODE_CONFIG[0];
modeText.textContent = config.label;
indicator.className = "filter-mode-indicator " + config.group;
panel.querySelectorAll(".filter-mode-item").forEach((el) => {
el.classList.toggle("selected", el.dataset.mode === this.currentFilterMode);
});
};
let lastGroup = null;
FILTER_MODE_CONFIG.forEach((mode) => {
if (lastGroup && lastGroup !== mode.group) {
const separator = document.createElement("div");
separator.className = "filter-mode-separator";
panel.appendChild(separator);
}
lastGroup = mode.group;
const item = document.createElement("div");
item.className = "filter-mode-item";
if (mode.group === "exclude") item.classList.add("exclude");
item.dataset.mode = mode.value;
const dot = document.createElement("span");
dot.className = "filter-mode-indicator " + mode.group;
item.appendChild(dot);
const text = document.createElement("span");
text.textContent = mode.label;
item.appendChild(text);
item.addEventListener("click", () => {
this.currentFilterMode = mode.value;
updateModeUI();
details.open = false;
this.applyFilter();
});
panel.appendChild(item);
});
details.appendChild(panel);
details._updateModeUI = updateModeUI;
updateModeUI();
return details;
}
buildFilterBar() {
if (document.querySelector(".tag-filter-bar")) return;
const mountTarget = /^\/actors\//.test(window.location.pathname) ? document.querySelector("body > section > div > div.actor-tags.tags") : document.querySelector("body > section > div > div.tabs.is-boxed");
if (!mountTarget) return;
const filterBar = document.createElement("div");
filterBar.className = "tag-filter-bar";
const label = document.createElement("span");
label.className = "tag-filter-label";
label.textContent = "筛选:";
filterBar.appendChild(label);
const modeDropdown = this.buildFilterModeDropdown();
filterBar.appendChild(modeDropdown);
filterBar._modeDropdown = modeDropdown;
const chipsContainer = document.createElement("div");
chipsContainer.className = "tag-filter-chips";
filterBar.appendChild(chipsContainer);
const toggleWrapper = document.createElement("label");
toggleWrapper.className = "auto-refresh-toggle";
toggleWrapper.title = "监听清单操作,自动刷新标签";
const switchSpan = document.createElement("span");
switchSpan.className = "auto-refresh-switch";
const checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.checked = this.autoRefreshEnabled;
const slider = document.createElement("span");
slider.className = "auto-refresh-slider";
switchSpan.appendChild(checkbox);
switchSpan.appendChild(slider);
const toggleLabel = document.createElement("span");
toggleLabel.textContent = "自动刷新";
toggleWrapper.appendChild(switchSpan);
toggleWrapper.appendChild(toggleLabel);
filterBar.appendChild(toggleWrapper);
checkbox.addEventListener("change", () => {
this.autoRefreshEnabled = checkbox.checked;
this.saveAutoRefreshState(this.autoRefreshEnabled);
if (this.autoRefreshEnabled) console.log("[视频清单标签] 自动刷新已开启");
else console.log("[视频清单标签] 自动刷新已关闭");
});
const createFilterChip = (labelText, value, opts = {}) => {
const { isNoTag = false, count } = opts;
const chip = document.createElement("span");
chip.className = "tag-filter-chip";
if (isNoTag) chip.classList.add("no-tag");
chip.textContent = count !== void 0 ? `${labelText} ${count}` : labelText;
chip.dataset.value = value;
chip.addEventListener("click", () => {
chip.classList.toggle("active");
this.applyFilter();
});
return chip;
};
const refreshChips = () => {
const activeValues = new Set(Array.from(chipsContainer.querySelectorAll(".tag-filter-chip.active")).map((c) => c.dataset.value || ""));
chipsContainer.innerHTML = "";
const allCounts = this.collectTagCounts();
const noCount = this.countNoTagItems();
const noTagChip = createFilterChip("无标签", "no-tag", {
isNoTag: true,
count: noCount
});
if (activeValues.has("no-tag")) noTagChip.classList.add("active");
chipsContainer.appendChild(noTagChip);
this.collectAllUniqueTags().forEach((tagName) => {
const chip = createFilterChip(tagName, tagName, { count: allCounts[tagName] });
if (activeValues.has(tagName)) chip.classList.add("active");
chipsContainer.appendChild(chip);
});
};
refreshChips();
mountTarget.insertAdjacentElement("afterend", filterBar);
filterBar._refreshChips = refreshChips;
}
updateFilterBar() {
const filterBar = document.querySelector(".tag-filter-bar");
if (filterBar && filterBar._refreshChips) {
filterBar._refreshChips();
this.applyFilter();
}
}
collectAllUniqueTags() {
const tagNames = new Set();
document.querySelectorAll(".custom-tag-link:not([style*='pointer-events: none'])").forEach((el) => {
const name = el.textContent?.trim() || "";
if (name && name !== "—") tagNames.add(name);
});
return [...tagNames].sort();
}
collectTagCounts() {
const counts = {};
document.querySelectorAll(".custom-tag-link:not([style*='pointer-events: none'])").forEach((el) => {
const name = el.textContent?.trim() || "";
if (name && name !== "—") counts[name] = (counts[name] || 0) + 1;
});
return counts;
}
countNoTagItems() {
let count = 0;
document.querySelectorAll(".item").forEach((item) => {
if (item.querySelectorAll(".custom-tag-link:not([style*='pointer-events: none'])").length === 0) count++;
});
return count;
}
async initExistingItems() {
this.loadAutoRefreshState();
const items = document.querySelectorAll(".item");
if (items.length === 0) return;
const lists = Array.from(items).map((item) => {
const strong = item.querySelector("a > div.video-title > strong");
return strong ? strong.innerHTML : null;
}).filter((s) => !!s);
if (lists.length === 0) return;
try {
await this.fetchTags(lists);
console.log(`[视频清单标签] 初始化加载完成: ${lists.length} 个番号, ${Object.keys(this.tagsCache || {}).length} 个有标签`);
} catch (err) {
console.error("获取标签数据失败:", err);
this.tagsCache = {};
return;
}
items.forEach((item) => this.addTagDisplay(item));
this.buildFilterBar();
}
async handleNewItems(newItems) {
newItems.forEach((item) => this.addTagDisplay(item));
this.pendingNewItems.push(...newItems);
if (this.debounceTimer) clearTimeout(this.debounceTimer);
this.debounceTimer = setTimeout(async () => {
const itemsToRefresh = [...this.pendingNewItems];
this.pendingNewItems = [];
this.debounceTimer = null;
const uncachedCodes = [];
const seen = new Set();
for (const item of itemsToRefresh) {
const strong = item.querySelector("a > div.video-title > strong");
if (!strong) continue;
const code = strong.innerHTML;
if (!code || seen.has(code)) continue;
if (!this.tagsCache || !(code in this.tagsCache)) {
uncachedCodes.push(code);
seen.add(code);
}
}
if (uncachedCodes.length === 0) {
this.updateFilterBar();
return;
}
try {
await this.fetchAndMergeTags(uncachedCodes);
} catch (err) {
console.error("[视频清单标签] 获取新增标签数据失败:", err);
return;
}
itemsToRefresh.forEach((item) => {
const oldContainer = item.querySelector(".custom-tags-display");
if (oldContainer) oldContainer.remove();
this.addTagDisplay(item);
});
this.updateFilterBar();
console.log(`[视频清单标签] 已为 ${uncachedCodes.length} 个新番号获取标签`);
}, this.DEBOUNCE_MS);
}
setupAutoRefreshListener(onSync) {
let lastRefreshTime = 0;
const DEBOUNCE_MS = 500;
const NO_CHANGE_ASSOCS = new Set([
"existed",
"limit_exceeded",
"unchanged"
]);
const handleSyncNotify = (payload) => {
if (!this.autoRefreshEnabled) {
console.log("[视频清单标签] 收到同步事件但自动刷新已关闭,跳过");
return;
}
if (!payload || !payload.designation) {
console.warn("[视频清单标签] 收到同步事件但无 designation:", payload);
return;
}
if (NO_CHANGE_ASSOCS.has(payload.association)) {
console.log(`[视频清单标签] association=${payload.association} 不影响标签,跳过`);
return;
}
const now = Date.now();
if (now - lastRefreshTime < DEBOUNCE_MS) {
console.log(`[视频清单标签] 距上次刷新 ${now - lastRefreshTime}ms < ${DEBOUNCE_MS}ms,防抖跳过`);
return;
}
lastRefreshTime = now;
console.log("[视频清单标签] 收到同步事件 → 精准刷新", payload);
onSync(payload);
};
document.addEventListener("jdb:sync-complete", (e) => {
console.log("[视频清单标签] [CustomEvent] 收到 jdb:sync-complete");
handleSyncNotify(e.detail);
});
window.addEventListener("storage", (e) => {
if (e.key !== LAST_SYNC_KEY$1) return;
console.log(`[视频清单标签] [storage] key=${e.key} newValue=${e.newValue ? "<set>" : "<empty>"}`);
if (!e.newValue) return;
let payload;
try {
payload = JSON.parse(e.newValue);
} catch {
return;
}
handleSyncNotify(payload);
});
GM_addValueChangeListener(LAST_SYNC_KEY$1, (_name, _oldValue, newValue, remote) => {
console.log(`[视频清单标签] [GM_addValueChangeListener] remote=${remote} newValue=${newValue ? "<set>" : "<empty>"}`);
if (!newValue) return;
let payload;
try {
payload = JSON.parse(newValue);
} catch {
return;
}
handleSyncNotify(payload);
});
console.log(`[视频清单标签] 自动刷新监听已就绪 (autoRefreshEnabled=${this.autoRefreshEnabled})`);
}
};
var LOG_PREFIX = "[JavDB]";
var LAST_SYNC_KEY = "jdb:last-sync";
var ASSOC_TOAST = {
created: (des, lname, created) => {
return {
msg: `✓ [${des}] 已添加至「${lname}」${created.length > 0 ? `(已登记${created.join("和")})` : ""}`,
type: "success"
};
},
existed: (des, lname) => ({
msg: `✓ [${des}] 已在「${lname}」中,数据一致`,
type: "success"
}),
limit_exceeded: (des, lname) => ({
msg: `✗ [${des}]「${lname}」已达收藏上限(501 条)`,
type: "error"
}),
deleted: (des, lname) => ({
msg: `✓ [${des}] 已从「${lname}」移除`,
type: "success"
}),
unchanged: (des, lname) => ({
msg: `✓ [${des}] 未关联「${lname}」,数据一致`,
type: "success"
})
};
function getSeries(d) {
if (!d) return d;
const i = d.indexOf("-");
return i > 0 ? d.slice(0, i) : d;
}
function getCode(d) {
if (!d) return null;
const i = d.indexOf("-");
return i > 0 ? d.slice(i + 1) : null;
}
function getScore() {
const spans = document.querySelectorAll("nav span");
const found = Array.from(spans).find((s) => s.textContent?.trim().endsWith("人評價"));
if (!found) return 0;
const m = found.innerHTML.match(/(\d+\.\d+)/);
return m ? parseFloat(m[1]) : 0;
}
var _cachedScore;
function getScoreCached() {
if (_cachedScore === void 0) _cachedScore = getScore();
return _cachedScore;
}
function getMovieInfo(videoId) {
const detail = document.querySelector(".video-detail");
if (!detail) {
console.warn(`${LOG_PREFIX} 未找到 .video-detail,跳过`);
return null;
}
const desEl = detail.querySelector(".panel-block.first-block a[data-clipboard-text]");
if (!desEl) {
console.warn(`${LOG_PREFIX} 未找到番号元素,跳过`);
return null;
}
const designation = desEl.dataset.clipboardText || "";
if (!designation) {
console.warn(`${LOG_PREFIX} 番号为空,跳过`);
return null;
}
const href = "https://javdb.com/v/" + videoId;
const titleEl = detail.querySelector("strong.current-title");
const title = titleEl ? titleEl.innerHTML : "";
const dateEl = detail.querySelector(".video-meta-panel nav > div:nth-child(2) > span");
const release_date = dateEl ? dateEl.innerHTML : "";
const coverEl = detail.querySelector(".column-video-cover img");
return {
designation,
info: {
href,
title,
release_date,
cover_src: coverEl ? coverEl.src : "",
score: getScoreCached(),
series: getSeries(designation),
code: getCode(designation) || ""
}
};
}
function getListName(listId) {
const input = document.querySelector(`input[data-list-id="${listId}"]`);
if (!input) return "";
const label = input.closest("label");
if (!label) return "";
return label.textContent.replace(/\(.*?\)/g, "").replace(/\s+/g, " ").trim();
}
function getListInfo(listId) {
return {
list_id: listId,
info: {
url: "https://javdb.com/lists/" + listId + "?locale=zh",
name: getListName(listId)
}
};
}
async function syncMoviesLists(movieInfo, listInfo, action) {
console.log(`${LOG_PREFIX} 同步(IDB): ${movieInfo.designation} → ${listInfo.info.name} (${action})`);
const result = await VltDb.sync(movieInfo.designation, listInfo.list_id, {
href: movieInfo.info.href,
title: movieInfo.info.title,
cover_src: movieInfo.info.cover_src,
score: movieInfo.info.score,
release_date: movieInfo.info.release_date,
series: movieInfo.info.series,
code: movieInfo.info.code
}, {
url: listInfo.info.url,
name: listInfo.info.name
}, action);
console.log(`${LOG_PREFIX} 同步结果: movie=${result.movie} list=${result.list} association=${result.association}`);
return result;
}
var debounceTimers = new Map();
async function handleCheckboxChange(movieInfo, listInfo, checked) {
const des = movieInfo.designation;
const lname = listInfo.info.name;
const action = checked ? "add" : "remove";
console.log(`${LOG_PREFIX} ═══ ${checked ? "勾选" : "取消"} [${des}] → ${lname} ═══`);
let result;
try {
result = await syncMoviesLists(movieInfo, listInfo, action);
} catch (err) {
console.error(`${LOG_PREFIX} 同步失败`, err);
showToast$1(`✗ [${des}] 同步失败:${err.message || "请检查 IndexedDB"}`, "error");
return;
}
const created = [];
if (result.movie === "created") created.push("影片");
if (result.list === "created") created.push("清单");
const entry = ASSOC_TOAST[result.association];
if (entry) {
const { msg, type } = entry(des, lname, created);
showToast$1(msg, type);
} else showToast$1(`✗ [${des}] 未知响应:${result.association}`, "error");
console.log(`${LOG_PREFIX} ═══ 完成 ═══`);
const syncPayload = {
designation: des,
action,
association: result.association,
time: Date.now()
};
const payloadStr = JSON.stringify(syncPayload);
GM_setValue(LAST_SYNC_KEY, payloadStr);
localStorage.setItem(LAST_SYNC_KEY, payloadStr);
document.dispatchEvent(new CustomEvent("jdb:sync-complete", { detail: syncPayload }));
}
function setupCheckboxListener() {
document.addEventListener("change", (e) => {
const target = e.target;
if (target.tagName !== "INPUT" || target.type !== "checkbox" || target.dataset.action !== "change->list#listCheckboxChanged") return;
const input = target;
const movieInfo = getMovieInfo(input.value);
if (!movieInfo) {
console.warn(`${LOG_PREFIX} 无法获取影片信息,跳过`);
return;
}
const listInfo = getListInfo(input.dataset.listId || "");
if (!listInfo.info.name) {
console.warn(`${LOG_PREFIX} 无法获取清单名称,跳过`);
return;
}
const checked = input.checked;
const key = `${movieInfo.designation}::${listInfo.list_id}`;
clearTimeout(debounceTimers.get(key));
debounceTimers.set(key, setTimeout(() => {
handleCheckboxChange(movieInfo, listInfo, checked).then();
}, 300));
});
}
var VideoListsTagPlugin = class extends BasePlugin {
vltTags = null;
observer = null;
getName() {
return "VideoListsTagPlugin";
}
async initCss() {
return video_lists_tag_default;
}
async handle() {
if (window.isDetailPage) {
setupCheckboxListener();
return;
}
if (!window.isListPage) return;
this.vltTags = new VltTags();
await this.vltTags.initExistingItems();
this.setupItemObserver();
this.vltTags.setupAutoRefreshListener((payload) => {
if (payload?.designation) this.vltTags?.refreshDesignation(payload.designation).then();
});
}
setupItemObserver() {
this.observer = new MutationObserver((mutations) => {
const newItems = [];
for (const mutation of mutations) for (const node of mutation.addedNodes) {
if (node.nodeType !== Node.ELEMENT_NODE) continue;
const el = node;
if (el.matches?.(".item")) newItems.push(el);
else if (el.querySelectorAll?.(".item").length > 0) newItems.push(...Array.from(el.querySelectorAll(".item")));
}
if (newItems.length > 0) this.vltTags?.handleNewItems(newItems).then();
});
this.observer.observe(document.body, {
childList: true,
subtree: true
});
}
};
function logInfo$1(step, ...args) {
console.log(`%c${LOG_PREFIX_JHS} %c${step}`, "color:#25b1dc;font-weight:bold;", "color:inherit;font-weight:bold;", ...args);
}
function logOk$1(step, ...args) {
console.log(`%c${LOG_PREFIX_JHS} ✓ %c${step}`, "color:#1f7a3d;font-weight:bold;", "color:inherit;font-weight:bold;", ...args);
}
function logWarn$1(step, ...args) {
console.warn(`%c${LOG_PREFIX_JHS} ⚠ ${step}`, "color:#d7a80c;font-weight:bold;", ...args);
}
function logErr$1(step, ...args) {
console.error(`%c${LOG_PREFIX_JHS} ✗ ${step}`, "color:#de3333;font-weight:bold;", ...args);
}
var isFullSyncing = false;
var CarListReaderPlugin = class extends BasePlugin {
getName() {
return "CarListReaderPlugin";
}
async initCss() {
return "";
}
async handle() {
if (window.self !== window.top) return;
try {
GM_registerMenuCommand("🔁 全量同步车辆状态到 missav", () => {
this.syncFullCarStatus();
});
} catch {}
storageManager.setCarListChangeCallback((event) => {
this.pushDelta(event);
});
setTimeout(() => this.syncFullCarStatus(), 2e3);
}
pushDelta(event) {
try {
if (event.action === "upsert" && event.upserts) {
const items = event.upserts.map((car) => {
const { code } = normalizeUrl(car.url || "");
return {
carNum: car.carNum,
status: car.status,
url_path: code
};
});
const payload = {
action: "upsert",
items,
ts: Date.now()
};
GM_setValue(GM_KEY_CAR_STATUS_DELTA, payload);
logInfo$1("增量推送", `upsert ${items.length} 条`);
} else if (event.action === "delete" && event.deletes) {
const payload = {
action: "delete",
items: event.deletes.map((carNum) => ({ carNum })),
ts: Date.now()
};
GM_setValue(GM_KEY_CAR_STATUS_DELTA, payload);
logInfo$1("增量推送", `delete ${event.deletes.length} 条`);
}
} catch (err) {
logErr$1("增量推送失败", err.message || String(err));
}
}
async syncFullCarStatus() {
if (isFullSyncing) {
logWarn$1("全量同步任务在进行中,跳过");
return;
}
isFullSyncing = true;
try {
logInfo$1("全量同步开始");
const carList = await storageManager.getCarList();
logInfo$1("1-读取", `本地 car_list 记录数:${carList.length}`);
if (carList.length === 0) {
logWarn$1("car_list 为空,跳过同步(jhs 可能尚未写入数据)");
return;
}
const colRes = toColumnar(carList);
const count = countColumnar(colRes.byStatus);
logInfo$1("2-转列存", `列存 ${count} 条 / 丢弃 ${colRes.dropped} / url 异常 ${colRes.malformed}`);
if (count === 0) {
logWarn$1("列存后无有效记录,跳过");
return;
}
const base64 = await gzipToBase64(colRes.byStatus);
if (!base64) {
logErr$1("gzip 压缩失败(CompressionStream 不可用?非 https 环境?)");
return;
}
logInfo$1("3-压缩", `gzip+base64 体积:约 ${(base64.length / 1024).toFixed(1)} KB`);
const payload = {
data: base64,
hwm: new Date().toISOString(),
count,
ts: Date.now()
};
GM_setValue(GM_KEY_CAR_STATUS_DATA, payload);
logOk$1("4-完成", `已写入 GM 存储,count=${count},hwm=${payload.hwm}`);
} catch (err) {
logErr$1("全量同步失败", err.message || String(err), err);
} finally {
isFullSyncing = false;
}
}
};
function normalizeCarNum(raw) {
if (!raw) return "";
const filename = raw.split("/").pop() || "";
if (/^FC2-PPV-\d+$/i.test(filename)) return filename.toUpperCase();
const sep = filename.includes("_") ? "_" : "-";
const parts = filename.split(sep);
return (parts.length >= 2 ? parts[0] + "-" + parts[1] : filename).toUpperCase();
}
function createBadge(status, url) {
const cfg = STATUS_CONFIG[status];
if (!cfg) return null;
const a = document.createElement("a");
a.className = "missav-status-tag";
a.textContent = cfg.label;
a.href = url || "javascript:;";
a.target = "_blank";
a.rel = "noopener noreferrer";
a.title = "点击跳转到 javdb 详情页";
a.style.cssText = [
"border-radius:10px",
"position:absolute",
"z-index:10",
"right:5px",
"top:5px",
"left:auto",
"-webkit-font-smoothing:antialiased",
"text-rendering:optimizelegibility",
"font-family:\"Helvetica Neue\",\"Luxi Sans\",\"DejaVu Sans\",Tahoma,\"Hiragino Sans GB\",\"Microsoft Yahei\",sans-serif",
"cursor:pointer",
"align-items:center",
"display:inline-flex",
"font-size:0.75rem",
"height:2em",
"justify-content:center",
"line-height:1.5",
"white-space:nowrap",
"color:rgb(255,255,255)",
"pointer-events:auto",
`background-color:${cfg.color} !important`,
"width:80px",
"text-decoration:none"
].join(";");
return a;
}
function renderBadges(container, carMap) {
if (!container || carMap.size === 0) return {
total: 0,
matched: 0
};
const items = container.querySelectorAll(".thumbnail.group");
let total = 0;
let matched = 0;
for (const item of items) {
if (item.querySelector(".missav-status-tag")) continue;
total++;
const link = item.querySelector("a[alt]");
if (!link) continue;
const carNum = link.getAttribute("alt");
if (!carNum) continue;
const normalized = normalizeCarNum(carNum);
const record = carMap.get(normalized);
if (!record) continue;
const thumbDiv = item.querySelector("div.relative");
if (!thumbDiv) continue;
if (window.getComputedStyle(thumbDiv).position === "static") thumbDiv.style.position = "relative";
const badge = createBadge(record.status, record.url);
if (badge) {
thumbDiv.appendChild(badge);
matched++;
}
}
return {
total,
matched
};
}
function isVideoPage() {
return document.querySelector("#sprite-plyr") !== null;
}
function logInfo(msg, ...args) {
console.log(`%c${LOG_PREFIX_MISSAV} %c${msg}`, "color:#25b1dc;font-weight:bold;", "", ...args);
}
function logOk(msg, ...args) {
console.log(`%c${LOG_PREFIX_MISSAV} ✓%c ${msg}`, "color:#1f7a3d;font-weight:bold;", "", ...args);
}
function logWarn(msg, ...args) {
console.warn(`%c${LOG_PREFIX_MISSAV} ⚠%c ${msg}`, "color:#d7a80c;font-weight:bold;", "", ...args);
}
function logErr(msg, ...args) {
console.error(`%c${LOG_PREFIX_MISSAV} ✗%c ${msg}`, "color:#de3333;font-weight:bold;", "", ...args);
}
var isFullConsuming = false;
var MissavStatusTagPlugin = class extends BasePlugin {
getName() {
return "MissavStatusTagPlugin";
}
async initCss() {
return "";
}
async handle() {
logInfo("脚本启动", `页面类型: ${isVideoPage() ? "视频播放页" : "列表页"}`);
try {
GM_registerMenuCommand("🔄 MissAV 刷新标签", () => {
this.processAll();
});
} catch {}
try {
GM_addValueChangeListener(GM_KEY_CAR_STATUS_DELTA, (_key, _oldValue, newValue, remote) => {
if (remote && newValue) this.consumeDelta(newValue);
});
logOk("已注册增量变更监听");
} catch {
logWarn("GM_addValueChangeListener 不可用");
}
try {
GM_addValueChangeListener(GM_KEY_CAR_STATUS_DATA, (_key, _oldValue, newValue, remote) => {
if (remote && newValue) {
logInfo("收到 javdb 端全量数据通知");
this.consumeFull(newValue);
}
});
} catch {}
await this.consumeFull(void 0);
this.observeAndProcess();
}
async consumeDelta(delta) {
try {
if (delta.action === "upsert" && delta.items) {
const records = delta.items.map((item) => ({
carNum: item.carNum,
status: item.status || "",
url_path: item.url_path || ""
}));
await upsertLocalCars(records);
logInfo("增量更新", `upsert ${records.length} 条`);
} else if (delta.action === "delete" && delta.items) {
const carNums = delta.items.map((item) => item.carNum);
await deleteLocalCars(carNums);
logInfo("增量更新", `delete ${carNums.length} 条`);
}
await this.processAll();
} catch (err) {
logErr("增量消费失败", err.message || String(err));
}
}
async consumeFull(payload) {
if (isFullConsuming) {
logWarn("全量消费任务在进行中");
return;
}
isFullConsuming = true;
try {
const data = payload ?? GM_getValue("jhs_car_status_data");
if (!data || !data.data) {
if (payload !== void 0) logWarn("GM 存储中无全量数据");
return;
}
logInfo("全量消费开始", `count=${data.count} hwm=${data.hwm}`);
const store = await gunzipFromBase64(data.data);
if (!store) {
logErr("解压失败(DecompressionStream 不可用?数据损坏?)");
return;
}
const records = columnarToFlat(store);
if (records.length === 0) {
logWarn("解压后无有效记录");
return;
}
logInfo("解压完成", `${records.length} 条记录`);
logOk("写入本地 IDB", `${await upsertLocalCars(records)} 条`);
await this.processAll();
} catch (err) {
logErr("全量消费失败", err.message || String(err));
} finally {
isFullConsuming = false;
}
}
async processAll() {
try {
const allCarNums = new Set();
const allThumbs = document.querySelectorAll(".thumbnail.group");
for (const thumb of allThumbs) {
const link = thumb.querySelector("a[alt]");
if (link) {
const cn = link.getAttribute("alt");
if (cn) allCarNums.add(normalizeCarNum(cn));
}
}
if (allCarNums.size === 0) return;
const carMap = await queryLocalCars(Array.from(allCarNums));
if (carMap.size === 0) return;
this.processPage(carMap);
} catch (err) {
logErr("处理页面失败", err.message || String(err));
}
}
processPage(carMap) {
if (isVideoPage()) this.processVideoPage(carMap);
else this.processListPage(carMap);
}
processVideoPage(carMap) {
const bottomGrid = document.querySelector("body > div:nth-child(3) > div.sm\\:container.mx-auto.px-4.content-without-search.pb-12 > div > div.flex-1.order-first > div.relative.overflow-hidden > div.grid.grid-cols-2.md\\:grid-cols-3.xl\\:grid-cols-4.gap-5");
if (bottomGrid) this.queryAndRender(bottomGrid, carMap.size > 0 ? carMap : null, "视频页-底部推荐");
const sideContainer = document.querySelector("body > div:nth-child(3) > div.sm\\:container.mx-auto.px-4.content-without-search.pb-12 > div > div.hidden.lg\\:flex.h-full.ml-6.order-last > div");
if (sideContainer) this.queryAndRender(sideContainer, carMap.size > 0 ? carMap : null, "视频页-侧边推荐");
}
processListPage(carMap) {
this.queryAndRender(document.body, carMap.size > 0 ? carMap : null, "列表页");
}
async queryAndRender(container, existingMap, label) {
if (!container) return;
let map = existingMap;
if (!map || map.size === 0) {
const carNums = new Set();
const thumbs = container.querySelectorAll(".thumbnail.group");
for (const thumb of thumbs) {
const link = thumb.querySelector("a[alt]");
if (link) {
const cn = link.getAttribute("alt");
if (cn) carNums.add(normalizeCarNum(cn));
}
}
if (carNums.size === 0) return;
map = await queryLocalCars(Array.from(carNums));
}
if (!map || map.size === 0) return;
const { total, matched } = renderBadges(container, map);
const cumulativeMatched = container.querySelectorAll(".missav-status-tag").length;
const totalThumbs = container.querySelectorAll(".thumbnail.group").length;
logInfo("渲染标签", `${label}: +${total} 新增, +${matched} 命中 | 累计 ${cumulativeMatched}/${totalThumbs} 个标签`);
}
observeAndProcess() {
let retries = 0;
const maxRetries = 30;
const tryProcess = () => {
if (document.querySelectorAll(".thumbnail.group").length > 0) {
this.processAll();
return;
}
retries++;
if (retries < maxRetries) setTimeout(tryProcess, 500);
};
setTimeout(tryProcess, 1500);
let debounceTimer = null;
new MutationObserver((mutations) => {
let hasNewThumbnails = false;
for (const mutation of mutations) {
if (mutation.type === "childList") for (const node of mutation.addedNodes) {
if (node.nodeType !== Node.ELEMENT_NODE) continue;
const el = node;
if (el.matches?.(".thumbnail.group") || el.querySelector?.(".thumbnail.group")) {
hasNewThumbnails = true;
break;
}
}
if (mutation.type === "attributes" && mutation.attributeName === "alt" && mutation.target.matches?.("a[alt]") && mutation.target.closest?.(".thumbnail.group")) hasNewThumbnails = true;
if (hasNewThumbnails) break;
}
if (hasNewThumbnails) {
if (debounceTimer) clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => this.processAll(), 300);
}
}).observe(document.body, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ["alt"]
});
}
};
var LOG = "[MissAV 快速复制]";
var MENU_BAR_SELECTOR = "body > div:nth-child(3) > div.sm\\:container.mx-auto.px-4.content-without-search.pb-12 > div > div.flex-1.order-first > div.mt-4 > div";
function extractCode(pathname) {
const filename = pathname.split("/").pop() || "";
if (/^FC2-PPV-\d+$/i.test(filename)) return filename;
const parts = filename.split("-");
return parts.length >= 2 ? parts[0] + "-" + parts[1] : filename;
}
function copyToClipboard(text) {
return navigator.clipboard.writeText(text).then(() => true).catch(() => false);
}
function showToast(message, duration = 2e3) {
const toast = document.createElement("div");
toast.textContent = message;
Object.assign(toast.style, {
position: "fixed",
bottom: "20px",
left: "50%",
transform: "translateX(-50%)",
background: "rgba(0,0,0,0.7)",
color: "#fff",
padding: "8px 16px",
borderRadius: "4px",
fontSize: "14px",
zIndex: "9999",
transition: "opacity 0.3s",
opacity: "1"
});
document.body.appendChild(toast);
setTimeout(() => {
toast.style.opacity = "0";
setTimeout(() => toast.remove(), 300);
}, duration);
}
function openInNewTab(url) {
console.log(`${LOG} openInNewTab 触发`);
try {
const a = document.createElement("a");
a.href = url;
a.target = "_blank";
a.style.display = "none";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
console.log(`${LOG} 执行 模拟单击 a 标签`);
return true;
} catch (e) {
console.log(`${LOG} 单击 a 标签失败:`, e);
return false;
}
}
function createButton(label, svgElement, onClick) {
const button = document.createElement("button");
button.type = "button";
button.className = "inline-flex items-center whitespace-nowrap shadow-sm text-sm text-nord4 leading-4 font-medium focus:outline-none hover:text-nord6 mr-2";
button.appendChild(svgElement);
button.appendChild(document.createTextNode(label));
button.addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
onClick();
});
return button;
}
function createSVGClipboard() {
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
svg.setAttribute("width", "16");
svg.setAttribute("height", "16");
svg.setAttribute("fill", "currentColor");
svg.setAttribute("class", "bi bi-clipboard-check mr-1");
svg.setAttribute("viewBox", "0 0 16 16");
const path1 = document.createElementNS(svg.namespaceURI, "path");
path1.setAttribute("fill-rule", "evenodd");
path1.setAttribute("d", "M10.854 7.146a.5.5 0 0 1 0 .708l-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 1 1 .708-.708L7.5 9.793l2.646-2.647a.5.5 0 0 1 .708 0");
const path2 = document.createElementNS(svg.namespaceURI, "path");
path2.setAttribute("d", "M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1z");
const path3 = document.createElementNS(svg.namespaceURI, "path");
path3.setAttribute("d", "M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0z");
svg.appendChild(path1);
svg.appendChild(path2);
svg.appendChild(path3);
return svg;
}
function createSVGJavDB() {
const svgStr = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-letter-j-small"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M10 8h4v6a2 2 0 1 1 -4 0" /></svg>`;
const template = document.createElement("template");
template.innerHTML = svgStr.trim();
return template.content.firstChild;
}
function insertButtons(menuBar) {
const fanhao = extractCode(window.location.pathname);
const copyBtn = createButton("复制番号", createSVGClipboard(), () => {
copyToClipboard(fanhao).then((success) => {
showToast(success ? `番号 ${fanhao} 已复制` : "复制失败");
});
});
menuBar.prepend(copyBtn);
const javdbBtn = createButton("转到JavDB搜索", createSVGJavDB(), () => {
const javdbUrl = `https://javdb.com/search?q=${encodeURIComponent(fanhao)}&f=all`;
console.log(`${LOG} 尝试打开 JavDB 链接:`, javdbUrl);
if (openInNewTab(javdbUrl)) showToast(`正在跳转到 JavDB 搜索: ${fanhao}`);
else {
showToast("跳转失败,请检查弹窗阻止设置");
copyToClipboard(javdbUrl).then((copied) => {
if (copied) showToast("链接已复制到剪贴板,请手动打开");
});
}
});
menuBar.appendChild(javdbBtn);
console.log(`${LOG} ✅ Copy 和 JavDB 按钮已插入 menu_bar`);
}
var MissavQuickCopyPlugin = class extends BasePlugin {
observer = null;
getName() {
return "MissavQuickCopyPlugin";
}
async initCss() {
return "";
}
async handle() {
const existing = document.querySelector(MENU_BAR_SELECTOR);
if (existing) {
insertButtons(existing);
return;
}
this.observer = new MutationObserver(() => {
const menuBar = document.querySelector(MENU_BAR_SELECTOR);
if (menuBar) {
this.observer?.disconnect();
this.observer = null;
insertButtons(menuBar);
}
});
this.observer.observe(document.body, {
childList: true,
subtree: true
});
}
};
var javdbHideNavCss = "";
if (window.location.href.includes("hideNav=1")) javdbHideNavCss = "\n .main-nav,#search-bar-container {\n display: none !important;\n }\n \n html {\n padding-top:0px!important;\n }\n ";
var javdbSiteCss = javdb_site_default.replace("/*__HIDENAV2__*/", javdbHideNavCss);
function generateScrollbarCss() {
const scrollbarSelectors = [
".jhs-scrollbar",
".content-panel",
".tabulator-tableholder",
".has-navbar-fixed-top",
".layui-layer-content"
];
const appendPseudo = (selectors, pseudo) => selectors.map((selector) => `${selector}${pseudo}`).join(",");
return `\n ${appendPseudo(scrollbarSelectors, "::-webkit-scrollbar")}{width:6px;height:6px;}\n ${appendPseudo(scrollbarSelectors, "::-webkit-scrollbar-track")}{background:#f1f1f1;border-radius:10px;}\n ${appendPseudo(scrollbarSelectors, "::-webkit-scrollbar-thumb")}{background:#888;border-radius:10px;}\n ${appendPseudo(scrollbarSelectors, "::-webkit-scrollbar-thumb:hover")}{background:#555;}\n `.trim().replace(/\n/g, "");
}
var commonToolbarCss = common_toolbar_default.replace("/*__SCROLLBAR__*/", generateScrollbarCss());
if (isJavdbSite) injectCss(javdbSiteCss);
injectCss(a_normal_buttons_default);
injectCss(commonToolbarCss);
unsafeWindow.utils = window.utils = new CommonUtil();
unsafeWindow.gmHttp = window.gmHttp = new GmHttp();
unsafeWindow.storageManager = window.storageManager = new StorageManager();
unsafeWindow.loadGfriends = window.loadGfriends = loadGfriends;
unsafeWindow.filetreeDb = window.filetreeDb = filetreeDb;
unsafeWindow.WebDavClient = window.WebDavClient = WebDavClient;
var refreshChannel = new BroadcastChannel("channel-refresh");
window.refresh = function() {
refreshChannel.postMessage({ type: "refresh" });
};
window.cleanCache_filter_actor_actress_car_list = function() {
refreshChannel.postMessage({ type: "cleanCache_filter_actor_actress_car_list" });
};
window.clean_cacheSettingObj = function() {
refreshChannel.postMessage({ type: "clean_cacheSettingObj" });
};
injectCss(loading_default);
unsafeWindow.loading = window.loading = createLoading;
unsafeWindow.show = window.show = show$1;
(function() {
function resetOverflow(delay = 10) {
setTimeout(() => {
const shadeCount = document.querySelectorAll(".layui-layer-shade").length;
document.documentElement.style.overflow = shadeCount > 0 ? "hidden" : "";
}, delay);
}
injectCss(viewer_default);
window.showImageViewer = function(src, alt = "") {
let container = null;
let isTemporary = false;
if (typeof src == "string" || src instanceof String) {
container = $(jsxToString((0, import_jsx_runtime.jsx)(TemporaryImageContainer, {
src: String(src),
alt
}))).appendTo("body");
isTemporary = true;
} else container = $(src);
const viewerRef = { current: null };
const viewerOptions = VIEWER_CONFIG({
container,
isTemporary,
resetOverflow,
viewerRef
});
viewerRef.current = new Viewer(container[0], viewerOptions);
viewerRef.current.show();
};
})();
(async function() {
injectCss(logger_default);
try {
if (unsafeWindow.parent.clog && typeof unsafeWindow.parent.clog.log == "function") window.clog = unsafeWindow.clog = unsafeWindow.parent.clog;
else window.clog = unsafeWindow.clog = new Logger();
} catch (err) {
console.error("创建日志控制台出现异常", err);
window.clog = unsafeWindow.clog = new Logger();
}
(function() {
const logger = window.clog || console;
window.addEventListener("error", function(event) {
const filename = event.filename;
const message = event.message;
if (!filename.includes("javdb")) logger.error(`[全局 Error 异常捕获] ${message} 来源: ${filename}`);
});
window.addEventListener("unhandledrejection", function(event) {
const reason = event.reason;
const reasonMessage = (reason == null ? void 0 : reason.message) ?? "";
if (reasonMessage.includes("play()")) return;
if (reasonMessage.includes("The element has no supported sources")) {
show$1.error("播放失败, 请检查是否已对节点分流?");
logger.error("播放失败, 请检查是否已对节点分流?");
return;
}
if (reasonMessage.includes("<span>1005</span>") && reasonMessage.includes("fc2ppvdb")) return;
const logMessage = `[全局 Promise 异常捕获] ${reason.message || reason}`;
logger.error(logMessage, reason);
event.preventDefault();
});
})();
document.addEventListener("mousedown", (event) => {
const clog = window.clog;
if (!clog.isInitialized || !clog.container) return;
const target = event.target;
const loggerSelectors = [
".console-logger-container",
".layui-layer-shade",
".loading-container"
].join(",");
if (target.closest(loggerSelectors)) clog.highZIndex();
else clog.lowZIndex();
});
})();
setupTooltip();
document.addEventListener("keydown", (event) => {
Hotkey.handleKeydown(event);
});
document.addEventListener("keyup", (event) => {
Hotkey.handleKeyup(event);
});
unsafeWindow.encryptCredential = window.encryptCredential = encryptCredential;
unsafeWindow.decryptCredential = window.decryptCredential = decryptCredential;
setupLayerWrapper();
var pluginManager = (function() {
const manager = new PluginManager();
unsafeWindow.pluginManager = manager;
if (isJavdbSite) {
manager.register(ListPagePlugin);
manager.register(AutoPagePlugin);
manager.register(FoldCategoryPlugin);
manager.register(ListPageButtonPlugin);
manager.register(HistoryPlugin);
manager.register(SettingPlugin);
manager.register(NavBarPlugin);
manager.register(HitShowPlugin);
manager.register(Top250Plugin);
manager.register(DetailPagePlugin);
manager.register(ReviewPlugin);
manager.register(DetailPageButtonPlugin);
manager.register(HighlightMagnetPlugin);
manager.register(PreviewVideoPlugin);
manager.register(FilterTitleKeywordPlugin);
manager.register(ActressInfoPlugin);
manager.register(OtherSitePlugin);
manager.register(WantAndWatchedVideosPlugin);
manager.register(RelatedPlugin);
manager.register(BlacklistPlugin);
manager.register(FavoriteActressesPlugin);
manager.register(NewVideoPlugin);
manager.register(RatingDisplayPlugin);
manager.register(Fc2Plugin);
manager.register(KeyPageTurningPlugin);
manager.register(ModMyListOpenWayPlugin);
manager.register(PageSortPlugin);
manager.register(StatusTagFilterPlugin);
manager.register(ListWaterfallPlugin);
manager.register(ListReadingStatusPlugin);
manager.register(ModalListDisablerPlugin);
manager.register(ListParserPlugin);
manager.register(VideoListsTagPlugin);
manager.register(CarListReaderPlugin);
}
if (isMissavSite) {
manager.register(MissavStatusTagPlugin);
manager.register(MissavQuickCopyPlugin);
}
return manager;
})();
(async function() {
await pluginManager.processCss();
window.isDetailPage = (function() {
return window.location.href.split("?")[0].includes("/v/");
})();
window.isListPage = (function() {
const href = window.location.href;
return $(".movie-list").length > 0 || href.includes("advanced_search");
})();
window.isFc2Page = (function() {
const href = window.location.href;
return href.includes("advanced_search?type=3") || href.includes("advanced_search?type=100");
})();
if (isJavdbSite) {
await storageManager.merge_table_name();
await storageManager.clean_no_url_blacklist();
await storageManager.async_merge_other();
await storageManager.merge_blacklist();
await storageManager.merge_favoriteActress();
await storageManager.merge_tow_car_list_table();
}
if (isJavdbSite && /(^|;)\s*locale\s*=\s*en\s*($|;)/i.test(document.cookie)) show$1.error("请切换到中文语言下才可正常使用本脚本", { duration: -1 });
await pluginManager.processPlugins();
})();
})();