Adjusting tooltip arrow position, added open and close events. Fixed search tooltip layout.
This commit is contained in:
parent
442e69187b
commit
8dd10f7e77
|
@ -162,8 +162,8 @@
|
||||||
<Tooltip
|
<Tooltip
|
||||||
class="search-compact"
|
class="search-compact"
|
||||||
:open="searching"
|
:open="searching"
|
||||||
@show="searching = true"
|
@open="searching = true"
|
||||||
@hide="searching = false"
|
@close="searching = false"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -172,12 +172,14 @@
|
||||||
icon="search"
|
icon="search"
|
||||||
/></button>
|
/></button>
|
||||||
|
|
||||||
<Search
|
<template v-slot:tooltip>
|
||||||
slot="tooltip"
|
<Search
|
||||||
:searching="searching"
|
:searching="searching"
|
||||||
class="compact"
|
class="compact"
|
||||||
@search="searching = false"
|
@search="searching = false"
|
||||||
/>
|
@click.stop
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
|
@ -27,10 +27,7 @@ async function search() {
|
||||||
|
|
||||||
function searching(to) {
|
function searching(to) {
|
||||||
if (to) {
|
if (to) {
|
||||||
setTimeout(() => {
|
this.$refs.search.focus();
|
||||||
// nextTick does not seem to work
|
|
||||||
this.$refs.search.focus();
|
|
||||||
}, 20);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,12 +76,12 @@ export default {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: none;
|
border: none;
|
||||||
|
|
||||||
.search-input {
|
.search-input {
|
||||||
border: solid 1px var(--shadow-hint);
|
padding: .75rem .5rem .75rem .75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-button {
|
.search-button {
|
||||||
padding: 0 .5rem 0 1rem;
|
padding: 1rem 1rem .75rem .25rem;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,11 @@
|
||||||
<div class="tooltip">
|
<div class="tooltip">
|
||||||
<slot name="tooltip" />
|
<slot name="tooltip" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="tooltip-arrow"
|
||||||
|
:style="{ transform: `translate3d(${arrowOffset}px, 0, 0)` }"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</teleport>
|
</teleport>
|
||||||
|
@ -30,19 +35,29 @@ import { nextTick } from 'vue';
|
||||||
|
|
||||||
function getX(triggerBoundary, tooltipBoundary) {
|
function getX(triggerBoundary, tooltipBoundary) {
|
||||||
const idealPosition = triggerBoundary.left + (triggerBoundary.width / 2) - (tooltipBoundary.width / 2);
|
const idealPosition = triggerBoundary.left + (triggerBoundary.width / 2) - (tooltipBoundary.width / 2);
|
||||||
|
const rightEdgeOverflow = Math.max((idealPosition + tooltipBoundary.width) - window.innerWidth, 0);
|
||||||
|
|
||||||
// don't overflow left edge
|
// don't overflow left edge
|
||||||
if (idealPosition < 0) {
|
if (idealPosition < 0) {
|
||||||
return 0;
|
return {
|
||||||
|
tooltipX: 0,
|
||||||
|
arrowOffset: idealPosition,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't overflow right edge
|
// don't overflow right edge
|
||||||
if (idealPosition + tooltipBoundary.width > window.innerWidth) {
|
if (rightEdgeOverflow > 0) {
|
||||||
return window.innerWidth - tooltipBoundary.width;
|
return {
|
||||||
|
tooltipX: window.innerWidth - tooltipBoundary.width,
|
||||||
|
arrowOffset: rightEdgeOverflow,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// position at the center of trigger
|
// position at the center of trigger
|
||||||
return idealPosition;
|
return {
|
||||||
|
tooltipX: idealPosition,
|
||||||
|
arrowOffset: 0,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function calculate() {
|
async function calculate() {
|
||||||
|
@ -53,8 +68,11 @@ async function calculate() {
|
||||||
const triggerBoundary = this.$refs.trigger.getBoundingClientRect();
|
const triggerBoundary = this.$refs.trigger.getBoundingClientRect();
|
||||||
const tooltipBoundary = this.$refs.tooltip.getBoundingClientRect();
|
const tooltipBoundary = this.$refs.tooltip.getBoundingClientRect();
|
||||||
|
|
||||||
|
const { tooltipX, arrowOffset } = this.getX(triggerBoundary, tooltipBoundary);
|
||||||
|
|
||||||
this.tooltipY = triggerBoundary.top + triggerBoundary.height;
|
this.tooltipY = triggerBoundary.top + triggerBoundary.height;
|
||||||
this.tooltipX = this.getX(triggerBoundary, tooltipBoundary);
|
this.tooltipX = tooltipX;
|
||||||
|
this.arrowOffset = arrowOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function open() {
|
async function open() {
|
||||||
|
@ -66,6 +84,7 @@ async function open() {
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
this.calculate();
|
this.calculate();
|
||||||
|
this.$emit('open');
|
||||||
}
|
}
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
|
@ -73,6 +92,9 @@ function close() {
|
||||||
|
|
||||||
this.tooltipY = 0;
|
this.tooltipY = 0;
|
||||||
this.tooltipX = 0;
|
this.tooltipX = 0;
|
||||||
|
this.arrowOffset = 0;
|
||||||
|
|
||||||
|
this.$emit('close');
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggle() {
|
function toggle() {
|
||||||
|
@ -100,6 +122,7 @@ export default {
|
||||||
opened: false,
|
opened: false,
|
||||||
tooltipX: 0,
|
tooltipX: 0,
|
||||||
tooltipY: 0,
|
tooltipY: 0,
|
||||||
|
arrowOffset: 0,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted,
|
mounted,
|
||||||
|
@ -127,24 +150,24 @@ export default {
|
||||||
.tooltip-inner {
|
.tooltip-inner {
|
||||||
position: relative;
|
position: relative;
|
||||||
box-shadow: 0 0 3px var(--darken-weak);
|
box-shadow: 0 0 3px var(--darken-weak);
|
||||||
|
|
||||||
&:after {
|
|
||||||
content: '';
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
position: absolute;
|
|
||||||
top: -.5rem;
|
|
||||||
left: calc(50% - .5rem);
|
|
||||||
border-left: .5rem solid transparent;
|
|
||||||
border-right: .5rem solid transparent;
|
|
||||||
border-bottom: .5rem solid var(--background-light);
|
|
||||||
margin: 0 auto;
|
|
||||||
filter: drop-shadow(0 0 3px var(--darken-weak));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip {
|
.tooltip {
|
||||||
position: relative;
|
position: relative;
|
||||||
background: var(--background-light);
|
background: var(--background-light);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tooltip-arrow {
|
||||||
|
content: '';
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
position: absolute;
|
||||||
|
top: -.5rem;
|
||||||
|
left: calc(50% - .5rem);
|
||||||
|
border-left: .5rem solid transparent;
|
||||||
|
border-right: .5rem solid transparent;
|
||||||
|
border-bottom: .5rem solid var(--background-light);
|
||||||
|
margin: 0 auto;
|
||||||
|
filter: drop-shadow(0 0 3px var(--darken-weak));
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const qu = require('../utils/qu');
|
const qu = require('../utils/qu');
|
||||||
|
const http = require('../utils/http');
|
||||||
|
|
||||||
function scrapeAll(scenes) {
|
function scrapeAll(scenes) {
|
||||||
return scenes.map(({ query }) => {
|
return scenes.map(({ query }) => {
|
||||||
|
@ -33,13 +34,11 @@ function scrapeAll(scenes) {
|
||||||
async function scrapeScene({ query }, url) {
|
async function scrapeScene({ query }, url) {
|
||||||
const release = { director: 'Mike Adriano' };
|
const release = { director: 'Mike Adriano' };
|
||||||
|
|
||||||
if (query.exists('a[href*="stackpath.com"]')) {
|
|
||||||
throw new Error('URL blocked by StackPath');
|
|
||||||
}
|
|
||||||
|
|
||||||
const pathname = new URL(url).pathname;
|
const pathname = new URL(url).pathname;
|
||||||
release.entryId = pathname.match(/\/view\/(\d+)/)?.[1] || pathname.match(/\/view\/([\w-]+)/)?.[1];
|
release.entryId = pathname.match(/\/view\/(\d+)/)?.[1] || pathname.match(/\/view\/([\w-]+)/)?.[1];
|
||||||
|
|
||||||
|
console.log(release);
|
||||||
|
|
||||||
release.title = query.cnt('.content-page-info .title');
|
release.title = query.cnt('.content-page-info .title');
|
||||||
release.description = query.cnt('.content-page-info .desc');
|
release.description = query.cnt('.content-page-info .desc');
|
||||||
release.date = query.date('.content-page-info .date, .content-page-info .hide, .post-date', 'Do MMM YYYY');
|
release.date = query.date('.content-page-info .date, .content-page-info .hide, .post-date', 'Do MMM YYYY');
|
||||||
|
@ -71,10 +70,40 @@ async function fetchLatest(channel, page = 1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchScene(url, channel) {
|
async function fetchScene(url, channel) {
|
||||||
const res = await qu.get(url);
|
const cookieJar = http.cookieJar();
|
||||||
|
const session = http.session({ cookieJar });
|
||||||
|
|
||||||
|
console.log(cookieJar);
|
||||||
|
|
||||||
|
const resA = await http.get(url, {
|
||||||
|
session,
|
||||||
|
extract: {
|
||||||
|
cookieJar,
|
||||||
|
// runScripts: 'dangerously',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(resA.headers, cookieJar.getCookiesSync(url));
|
||||||
|
const cookie = cookieJar.getCookieStringSync(url);
|
||||||
|
|
||||||
|
console.log(cookie);
|
||||||
|
|
||||||
|
const res = await http.get(url, {
|
||||||
|
headers: {
|
||||||
|
cookie,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// console.log(res.req);
|
||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
return scrapeScene(res.item, url, channel);
|
const item = qu.init(res.document);
|
||||||
|
|
||||||
|
if (item.query.exists('a[href*="stackpath.com"]')) {
|
||||||
|
throw new Error('URL blocked by StackPath');
|
||||||
|
}
|
||||||
|
|
||||||
|
return scrapeScene(item, url, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.status;
|
return res.status;
|
||||||
|
|
|
@ -6,7 +6,7 @@ const util = require('util');
|
||||||
const stream = require('stream');
|
const stream = require('stream');
|
||||||
const tunnel = require('tunnel');
|
const tunnel = require('tunnel');
|
||||||
const Bottleneck = require('bottleneck');
|
const Bottleneck = require('bottleneck');
|
||||||
const { JSDOM } = require('jsdom');
|
const { JSDOM, CookieJar } = require('jsdom');
|
||||||
|
|
||||||
const logger = require('../logger')(__filename);
|
const logger = require('../logger')(__filename);
|
||||||
const virtualConsole = require('./virtual-console')(__filename);
|
const virtualConsole = require('./virtual-console')(__filename);
|
||||||
|
@ -110,7 +110,7 @@ async function request(method = 'get', url, body, requestOptions = {}, limiter)
|
||||||
|
|
||||||
if (Buffer.isBuffer(res.body)) {
|
if (Buffer.isBuffer(res.body)) {
|
||||||
const html = res.body.toString();
|
const html = res.body.toString();
|
||||||
const window = new JSDOM(html, { virtualConsole }).window;
|
const window = new JSDOM(html, { virtualConsole, ...options.extract }).window;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...res,
|
...res,
|
||||||
|
@ -165,6 +165,10 @@ function getSession(options) {
|
||||||
return bhttp.session({ ...defaultOptions, ...options });
|
return bhttp.session({ ...defaultOptions, ...options });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCookieJar(store, options) {
|
||||||
|
return new CookieJar(store, options);
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
get,
|
get,
|
||||||
head,
|
head,
|
||||||
|
@ -173,5 +177,7 @@ module.exports = {
|
||||||
put,
|
put,
|
||||||
patch,
|
patch,
|
||||||
session: getSession,
|
session: getSession,
|
||||||
|
cookieJar: getCookieJar,
|
||||||
getSession,
|
getSession,
|
||||||
|
getCookieJar,
|
||||||
};
|
};
|
||||||
|
|
|
@ -118,6 +118,12 @@ function html(context, selector) {
|
||||||
return el && el.innerHTML;
|
return el && el.innerHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function htmls(context, selector) {
|
||||||
|
const els = all(context, selector, null, true);
|
||||||
|
|
||||||
|
return els.map(el => el.innerHTML);
|
||||||
|
}
|
||||||
|
|
||||||
function texts(context, selector, applyTrim = true, filter = true) {
|
function texts(context, selector, applyTrim = true, filter = true) {
|
||||||
const el = q(context, selector, null, applyTrim);
|
const el = q(context, selector, null, applyTrim);
|
||||||
if (!el) return null;
|
if (!el) return null;
|
||||||
|
@ -363,27 +369,28 @@ const legacyFuncs = {
|
||||||
|
|
||||||
const quFuncs = {
|
const quFuncs = {
|
||||||
all,
|
all,
|
||||||
html,
|
|
||||||
content,
|
|
||||||
contents,
|
|
||||||
cnt: content,
|
cnt: content,
|
||||||
cnts: contents,
|
cnts: contents,
|
||||||
|
content,
|
||||||
|
contents,
|
||||||
count,
|
count,
|
||||||
date,
|
date,
|
||||||
dateAgo,
|
dateAgo,
|
||||||
dur: duration,
|
dur: duration,
|
||||||
duration,
|
duration,
|
||||||
element: q,
|
|
||||||
el: q,
|
el: q,
|
||||||
|
element: q,
|
||||||
exists,
|
exists,
|
||||||
|
html,
|
||||||
|
htmls,
|
||||||
image,
|
image,
|
||||||
images,
|
images,
|
||||||
img: image,
|
img: image,
|
||||||
imgs: images,
|
imgs: images,
|
||||||
length: duration,
|
length: duration,
|
||||||
meta,
|
meta,
|
||||||
number,
|
|
||||||
num: number,
|
num: number,
|
||||||
|
number,
|
||||||
poster,
|
poster,
|
||||||
q,
|
q,
|
||||||
sourceSet,
|
sourceSet,
|
||||||
|
@ -444,8 +451,8 @@ function initAll(context, selector, window) {
|
||||||
.map(element => init(element, window));
|
.map(element => init(element, window));
|
||||||
}
|
}
|
||||||
|
|
||||||
function extract(htmlValue, selector) {
|
function extract(htmlValue, selector, options) {
|
||||||
const { window } = new JSDOM(htmlValue, { virtualConsole });
|
const { window } = new JSDOM(htmlValue, { virtualConsole, ...options });
|
||||||
|
|
||||||
if (selector) {
|
if (selector) {
|
||||||
return init(window.document.querySelector(selector), window);
|
return init(window.document.querySelector(selector), window);
|
||||||
|
@ -454,8 +461,8 @@ function extract(htmlValue, selector) {
|
||||||
return init(window.document, window);
|
return init(window.document, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractAll(htmlValue, selector) {
|
function extractAll(htmlValue, selector, options) {
|
||||||
const { window } = new JSDOM(htmlValue, { virtualConsole });
|
const { window } = new JSDOM(htmlValue, { virtualConsole, ...options });
|
||||||
|
|
||||||
return initAll(window.document, selector, window);
|
return initAll(window.document, selector, window);
|
||||||
}
|
}
|
||||||
|
@ -467,8 +474,8 @@ async function request(method = 'get', urlValue, body, selector, headers, option
|
||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const item = queryAll
|
const item = queryAll
|
||||||
? extractAll(res.body.toString(), selector)
|
? initAll(res.document, selector, res.window)
|
||||||
: extract(res.body.toString(), selector);
|
: init(res.document, selector, res.window);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
item,
|
item,
|
||||||
|
@ -506,6 +513,10 @@ async function postAll(urlValue, body, selector, headers, options) {
|
||||||
return request('post', urlValue, body, selector, headers, options, true);
|
return request('post', urlValue, body, selector, headers, options, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function session(headers, options) {
|
||||||
|
return http.session(headers, options);
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
extractDate,
|
extractDate,
|
||||||
extract,
|
extract,
|
||||||
|
@ -532,5 +543,6 @@ module.exports = {
|
||||||
post,
|
post,
|
||||||
postAll,
|
postAll,
|
||||||
prefixUrl,
|
prefixUrl,
|
||||||
|
session,
|
||||||
...legacyFuncs,
|
...legacyFuncs,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue