├── .eslintignore
├── babel.config.js
├── tests
└── unit
│ ├── .eslintrc.js
│ ├── mock.d.ts
│ ├── __snapshots__
│ ├── photoswipe.spec.ts.snap
│ ├── global.spec.ts.snap
│ └── pswpUI.spec.ts.snap
│ ├── utils.spec.ts
│ ├── pswpUI.spec.ts
│ ├── util.ts
│ ├── global.spec.ts
│ └── photoswipe.spec.ts
├── .postcssrc.js
├── types
├── shims-vue.d.ts
├── vue.d.ts
└── index.d.ts
├── .travis.yml
├── dist
├── demo.html
└── Photoswipe.umd.min.js
├── .editorconfig
├── .prettierignore
├── .gitignore
├── example
├── index.ts
├── video.vue
└── sample.vue
├── vue.config.js
├── .prettierrc.js
├── src
├── main.ts
├── config.ts
├── type.ts
├── components
│ ├── pswpUI.vue
│ └── photoswipe.vue
└── utils.ts
├── tsconfig.json
├── jest.config.js
├── .eslintrc.js
├── LICENSE
├── package.json
└── README.md
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist
2 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['@babel/env'],
3 | }
4 |
--------------------------------------------------------------------------------
/tests/unit/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | jest: true
4 | }
5 | }
--------------------------------------------------------------------------------
/.postcssrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {},
4 | },
5 | }
6 |
--------------------------------------------------------------------------------
/types/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import Vue from 'vue'
3 |
4 | export default Vue
5 | }
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 'lts/*'
4 | script: 'npm run test:coverage'
5 | after_success:
6 | - 'npx codecov'
7 |
--------------------------------------------------------------------------------
/tests/unit/mock.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'photoswipe' {
2 | const mocked: jest.Mock
3 | export default mocked
4 | }
5 |
6 | interface Window {
7 | Image: typeof Image
8 | }
9 |
--------------------------------------------------------------------------------
/dist/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
Photoswipe demo
3 |
4 |
5 |
6 |
9 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 4
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | ## OS
2 | .DS_Store
3 | .idea
4 | .editorconfig
5 | package-lock.json
6 | yarn.lock
7 |
8 | # Ignored suffix
9 | *.log
10 | *.md
11 | *.svg
12 | *.png
13 | *ignore
14 | *.gif
15 |
16 | ## Local
17 |
18 |
19 | ## Built-files
20 | .docz
21 | build
22 | dist
23 | dll
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | # local env files
5 | .env.local
6 | .env.*.local
7 |
8 | # Log files
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 |
13 | # Editor directories and files
14 | .idea
15 | .vscode
16 | *.suo
17 | *.ntvs*
18 | *.njsproj
19 | *.sln
20 | *.sw*
21 |
--------------------------------------------------------------------------------
/types/vue.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Augment the typings of Vue.js
3 | */
4 |
5 | import Vue from 'vue'
6 | import { Pswp, ManualCreateArgs } from '../src/type'
7 |
8 | interface $Pswp {
9 | open: (args: ManualCreateArgs) => Pswp
10 | current: Pswp
11 | }
12 |
13 | declare module 'vue/types/vue' {
14 | interface Vue {
15 | $Pswp: $Pswp
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/types/index.d.ts:
--------------------------------------------------------------------------------
1 | import Vue, { PluginFunction } from 'vue'
2 | import Photoswipe from '@/components/photoswipe.vue'
3 | import { PswpItem, PswpOptions, PswpDirectiveOptions } from '../src/type'
4 | import './vue.d'
5 |
6 | declare const VuePswipe: PluginFunction
7 |
8 | export { PswpItem, PswpOptions, PswpDirectiveOptions, Photoswipe }
9 |
10 | export default VuePswipe
11 |
--------------------------------------------------------------------------------
/example/index.ts:
--------------------------------------------------------------------------------
1 | import Vue, { CreateElement } from 'vue' // eslint-disable-line
2 |
3 | import PhotoswipePlugin from '../src/main'
4 | import Sample from './sample.vue'
5 |
6 | Vue.use(PhotoswipePlugin, {
7 | // history: true,
8 | })
9 |
10 | /* eslint-disable no-new */
11 | new Vue({
12 | el: '#app',
13 | components: {
14 | Sample,
15 | },
16 | render: (h: CreateElement) => h(Sample),
17 | })
18 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | chainWebpack: (config) => {
3 | config.module
4 | .rule('svg')
5 | .use('file-loader')
6 | .clear()
7 | .loader('url-loader')
8 | .options({
9 | limit: 5 * 1024,
10 | name: 'img/[name].[hash:8].[ext]',
11 | })
12 | },
13 | css: {
14 | extract: false,
15 | },
16 | lintOnSave: false,
17 | }
18 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | printWidth: 100,
3 | tabWidth: 4,
4 | useTabs: false,
5 | semi: false,
6 | singleQuote: true,
7 | quoteProps: 'as-needed',
8 | trailingComma: 'es5',
9 | bracketSpacing: true,
10 | arrowParens: 'always',
11 | rangeStart: 0,
12 | rangeEnd: Infinity,
13 | requirePragma: false,
14 | insertPragma: false,
15 | proseWrap: 'preserve',
16 | htmlWhitespaceSensitivity: 'css',
17 | endOfLine: 'lf',
18 | }
19 |
--------------------------------------------------------------------------------
/tests/unit/__snapshots__/photoswipe.spec.ts.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`photoswipe.vue :props :options render default options 1`] = `
4 | "{
5 | \\"galleryUID\\": 0,
6 | \\"history\\": false,
7 | \\"zoomEl\\": true,
8 | \\"shareEl\\": true,
9 | \\"shareButtons\\": [
10 | {
11 | \\"id\\": \\"download\\",
12 | \\"label\\": \\"Download image\\",
13 | \\"url\\": \\"{{raw_image_url}}\\",
14 | \\"download\\": true
15 | }
16 | ],
17 | \\"index\\": 0,
18 | \\"showHideOpacity\\": false
19 | }"
20 | `;
21 |
22 | exports[`photoswipe.vue render Photoswipe 1`] = `
`;
23 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { PluginFunction } from 'vue' // eslint-disable-line
2 | import { PswpOptions, ManualCreateArgs } from '@/type'
3 | import { GlobalOption } from '@/config'
4 | import { registerDirective, manualCreate, UI } from '@/utils'
5 | import PhotoswipeComponent from '@/components/photoswipe.vue'
6 |
7 | const install: PluginFunction = (Vue, options?: PswpOptions) => {
8 | if (options) GlobalOption.extend(options)
9 |
10 | registerDirective()
11 |
12 | Vue.component('Photoswipe', PhotoswipeComponent)
13 |
14 | // eslint-disable-next-line no-param-reassign
15 | Vue.prototype.$Pswp = {
16 | open(args: ManualCreateArgs) {
17 | UI.append()
18 | return manualCreate(args)
19 | },
20 | }
21 | }
22 |
23 | export const Photoswipe = PhotoswipeComponent
24 | export default install
25 |
--------------------------------------------------------------------------------
/src/config.ts:
--------------------------------------------------------------------------------
1 | import { PswpOptions } from '@/type'
2 | import { isMobile } from '@/utils'
3 |
4 | export const customEvents: string[] = ['beforeOpen', 'opened']
5 |
6 | const _isMobile = isMobile()
7 | export const defualtGlobalOption: PswpOptions = {
8 | // in spa no need history mode
9 | history: false,
10 | zoomEl: !_isMobile,
11 | shareEl: !_isMobile,
12 | shareButtons: [
13 | {
14 | id: 'download',
15 | label: 'Download image',
16 | url: '{{raw_image_url}}',
17 | download: true,
18 | },
19 | ],
20 | }
21 |
22 | export namespace GlobalOption {
23 | const _options: PswpOptions = defualtGlobalOption
24 | export const get = () => _options
25 | export const extend = (...partials: Partial[]) => {
26 | Object.assign(_options, ...partials)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "strict": true,
6 | "jsx": "preserve",
7 | "importHelpers": true,
8 | "moduleResolution": "node",
9 | "experimentalDecorators": true,
10 | "esModuleInterop": true,
11 | "allowSyntheticDefaultImports": true,
12 | "sourceMap": true,
13 | "baseUrl": ".",
14 | "paths": {
15 | "@/*": [
16 | "src/*"
17 | ]
18 | },
19 | "lib": [
20 | "esnext",
21 | "dom",
22 | "dom.iterable",
23 | "scripthost"
24 | ]
25 | },
26 | "include": [
27 | "types/**/*.ts",
28 | "example/**/*.ts",
29 | "example/**/*.vue",
30 | "src/**/*.ts",
31 | "src/**/*.tsx",
32 | "src/**/*.vue",
33 | "tests/**/*.ts",
34 | "tests/**/*.tsx"
35 | ],
36 | "exclude": [
37 | "node_modules"
38 | ]
39 | }
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | moduleFileExtensions: ['js', 'jsx', 'json', 'vue', 'ts', 'tsx'],
3 | transform: {
4 | '^.+\\.vue$': 'vue-jest',
5 | '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
6 | '^.+\\.tsx?$': 'ts-jest',
7 | },
8 | transformIgnorePatterns: ['/node_modules/'],
9 | coveragePathIgnorePatterns: ['/tests/unit/'],
10 | moduleNameMapper: {
11 | '^@/(.*)$': '/src/$1',
12 | },
13 | snapshotSerializers: ['jest-serializer-vue'],
14 | testMatch: ['**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'],
15 | testURL: 'http://localhost/',
16 | watchPlugins: ['jest-watch-typeahead/filename', 'jest-watch-typeahead/testname'],
17 | globals: {
18 | 'ts-jest': {
19 | babelConfig: true,
20 | },
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true,
5 | },
6 | extends: ['plugin:vue/essential', '@vue/airbnb', '@vue/typescript'],
7 | rules: {
8 | indent: ['error', 4],
9 | semi: ['error', 'never'],
10 | 'no-tabs': 'off',
11 | 'function-paren-newline': 'off',
12 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
13 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
14 | 'no-return-assign': 'off',
15 | 'no-nested-ternary': 'off',
16 | 'consistent-return': 'off',
17 | 'class-methods-use-this': 'off',
18 | camelcase: 'off',
19 | 'import/no-extraneous-dependencies': 'off',
20 | 'no-unused-expressions': 'off',
21 | 'no-underscore-dangle': 'off',
22 | 'arrow-parens': 'off',
23 | 'comma-dangle': 'off',
24 | },
25 | parserOptions: {
26 | parser: 'typescript-eslint-parser',
27 | },
28 | }
29 |
--------------------------------------------------------------------------------
/tests/unit/__snapshots__/global.spec.ts.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`global function v-pswp directive transform to custom dataset 1`] = `
4 |
12 | `;
13 |
14 | exports[`global function v-pswp directive update directive value 1`] = `
15 |
23 | `;
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 GuoQichen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/tests/unit/__snapshots__/pswpUI.spec.ts.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`pswpUI.vue render PswpUI 1`] = `
4 |
33 | `;
34 |
--------------------------------------------------------------------------------
/example/video.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
12 |
59 |
68 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-pswipe",
3 | "version": "0.15.3",
4 | "description": "a vue plugin for photoswipe",
5 | "author": "guoqichen",
6 | "scripts": {
7 | "build": "vue-cli-service build --target lib --name Photoswipe ./src/main.ts",
8 | "dev": "vue-cli-service serve ./example/index.ts",
9 | "report": "npm run build -- --report",
10 | "test": "vue-cli-service test:unit --silent",
11 | "test:coverage": "npm test -- --coverage --silent"
12 | },
13 | "main": "dist/Photoswipe.umd.min.js",
14 | "dependencies": {
15 | "@types/photoswipe": "^4.1.1",
16 | "photoswipe": "^4.1.3"
17 | },
18 | "devDependencies": {
19 | "@types/jest": "^23.1.4",
20 | "@vue/cli-plugin-babel": "^3.9.2",
21 | "@vue/cli-plugin-eslint": "^3.9.2",
22 | "@vue/cli-plugin-typescript": "^3.9.0",
23 | "@vue/cli-plugin-unit-jest": "^3.9.0",
24 | "@vue/cli-service": "^3.9.3",
25 | "@vue/eslint-config-airbnb": "^3.0.5",
26 | "@vue/eslint-config-typescript": "^3.2.1",
27 | "@vue/test-utils": "1.0.0-beta.29",
28 | "babel-core": "7.0.0-bridge.0",
29 | "codecov": "^3.5.0",
30 | "sass": "^1.22.7",
31 | "sass-loader": "^7.1.0",
32 | "ts-jest": "^23.0.0",
33 | "typescript": "^3.5.3",
34 | "video.js": "^5.20.5",
35 | "vue": "^2.6.10",
36 | "vue-class-component": "^6.3.2",
37 | "vue-property-decorator": "^7.3.0",
38 | "vue-template-compiler": "^2.6.10"
39 | },
40 | "browserslist": [
41 | "> 1%",
42 | "last 2 versions",
43 | "not ie <= 8"
44 | ],
45 | "keywords": [
46 | "vue",
47 | "photoswipe"
48 | ],
49 | "license": "MIT",
50 | "repository": {
51 | "type": "git",
52 | "url": "https://github.com/GuoQichen/vue-pswipe.git"
53 | },
54 | "types": "types/index.d.ts"
55 | }
56 |
--------------------------------------------------------------------------------
/tests/unit/utils.spec.ts:
--------------------------------------------------------------------------------
1 | import '@/config'
2 | import { Event } from '@/utils'
3 |
4 | const MOCK_EVENT = 'mockEvent'
5 |
6 | describe('Event', () => {
7 | let mockFn: jest.Mock
8 | beforeEach(() => {
9 | mockFn = jest.fn()
10 | })
11 |
12 | afterEach(() => {
13 | mockFn.mockReset()
14 | Event.off(MOCK_EVENT)
15 | })
16 |
17 | describe('emit', () => {
18 | it('invoke register function (without args)', () => {
19 | Event.on(MOCK_EVENT, mockFn)
20 | Event.emit(MOCK_EVENT)
21 | expect(mockFn).toBeCalled()
22 | })
23 |
24 | it('invoke register function (with args)', () => {
25 | const args = [1, 2, 3]
26 | Event.on(MOCK_EVENT, mockFn)
27 | Event.emit(MOCK_EVENT, ...args)
28 | expect(mockFn).toBeCalledWith(...args)
29 | })
30 |
31 | it('no invoke unregister function (registered event)', () => {
32 | Event.emit(MOCK_EVENT, mockFn)
33 | expect(mockFn).not.toBeCalled()
34 | })
35 |
36 | it('no invoke unregister function (unregister event)', () => {
37 | Event.emit('otherMockEvent', mockFn)
38 | expect(mockFn).not.toBeCalled()
39 | })
40 | })
41 |
42 | describe('once', () => {
43 | it('invoke register function once', () => {
44 | Event.once(MOCK_EVENT, mockFn)
45 | Event.emit(MOCK_EVENT)
46 | Event.emit(MOCK_EVENT)
47 | expect(mockFn).toBeCalledTimes(1)
48 | })
49 | })
50 |
51 | describe('off', () => {
52 | it('clear all register function by event name', () => {
53 | const otherMockFn = jest.fn()
54 | Event.on(MOCK_EVENT, mockFn)
55 | Event.on(MOCK_EVENT, otherMockFn)
56 | Event.off(MOCK_EVENT)
57 | expect(mockFn).not.toBeCalled()
58 | expect(otherMockFn).not.toBeCalled()
59 | })
60 |
61 | it('clear register function by returned value by on', () => {
62 | Event.on(MOCK_EVENT, mockFn)()
63 | expect(mockFn).not.toBeCalled()
64 | })
65 |
66 | it('clear register function by function ref (correct ref)', () => {
67 | Event.on(MOCK_EVENT, mockFn)
68 | Event.off(MOCK_EVENT, mockFn)
69 | expect(mockFn).not.toBeCalled()
70 | })
71 |
72 | it('clear register function by function ref (incorrect ref)', () => {
73 | Event.on(MOCK_EVENT, mockFn)
74 | Event.off(MOCK_EVENT, jest.fn())
75 | Event.emit(MOCK_EVENT)
76 | expect(mockFn).toBeCalled()
77 | })
78 | })
79 | })
80 |
--------------------------------------------------------------------------------
/tests/unit/pswpUI.spec.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/first */
2 | import { PhotoSwipe, PhotoSwipeMock, createPswp, createPswpUI, mockImageOnload } from './util'
3 |
4 | import '@/config'
5 | import { transitionEndEventName } from '@/utils'
6 | import { CurrentPswpItem } from '@/type'
7 |
8 | describe('pswpUI.vue', () => {
9 | beforeEach(() => {
10 | expect(PhotoSwipe).not.toHaveBeenCalled()
11 | })
12 |
13 | afterEach(() => {
14 | PhotoSwipe.mockClear()
15 | })
16 |
17 | it('render PswpUI ', () => {
18 | expect(createPswpUI()).toMatchSnapshot()
19 | })
20 |
21 | describe('rotate function', () => {
22 | const createRotatePswp = () => {
23 | const pswpUIWrapper = createPswpUI()
24 |
25 | const pswpWrapper = createPswp({
26 | propsData: {
27 | rotate: true,
28 | },
29 | })
30 |
31 | const pswp = PhotoSwipeMock.getPswp()
32 |
33 | return {
34 | pswp,
35 | pswpWrapper,
36 | pswpUIWrapper,
37 | }
38 | }
39 |
40 | it('render rotate buttons', () => {
41 | const pswpUIWrapper = createPswpUI()
42 | createPswp()
43 | const getRotateButton = () => pswpUIWrapper.findAll('.pswp__button--rotation')
44 | const pswp = PhotoSwipeMock.getPswp()
45 |
46 | expect(getRotateButton().length).toBe(0)
47 |
48 | pswpUIWrapper.setData({
49 | rotate: true,
50 | })
51 | expect(getRotateButton().length).toBe(2)
52 |
53 | pswp.destroy()
54 | expect(getRotateButton().length).toBe(0)
55 | })
56 |
57 | it('handleRotate', () => {
58 | mockImageOnload.enable()
59 | const { pswp, pswpUIWrapper } = createRotatePswp()
60 | const currentItem: CurrentPswpItem = pswp.currItem as any
61 | const img: HTMLImageElement = currentItem.container.lastChild as any
62 |
63 | const rotate = (direction: 'left' | 'right') => {
64 | pswpUIWrapper.find(`.pswp__button--rotation--${direction}`).trigger('pswpTap')
65 | img.dispatchEvent(new Event(transitionEndEventName))
66 | }
67 | const expectRotateDeg = (deg: number) => {
68 | expect(img.style.transform).toContain(`rotate(${deg}deg)`)
69 | }
70 |
71 | expect(img.style.transform).toBeFalsy()
72 |
73 | rotate('right')
74 | expectRotateDeg(90)
75 |
76 | // vertical
77 | rotate('right')
78 | expectRotateDeg(180)
79 |
80 | rotate('left')
81 | expectRotateDeg(90)
82 | mockImageOnload.disable()
83 | })
84 | })
85 | })
86 |
--------------------------------------------------------------------------------
/src/type.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import { Options, Item } from 'photoswipe/dist/photoswipe-ui-default'
3 |
4 | /**
5 | * v-pswp directive config options
6 | */
7 | export interface PswpDirectiveOptions {
8 | /**
9 | * path to image
10 | */
11 | src: string
12 | /**
13 | * image size, 'width x height', eg: '100x100'
14 | */
15 | size?: string
16 | /**
17 | * small image placeholder,
18 | * main (large) image loads on top of it,
19 | * if you skip this parameter - grey rectangle will be displayed,
20 | * try to define this property only when small image was loaded before
21 | */
22 | msrc?: string
23 | /**
24 | * used by Default PhotoSwipe UI
25 | * if you skip it, there won't be any caption
26 | */
27 | title?: string
28 | /**
29 | * to make URLs to a single image look like this: http://example.com/#&gid=1&pid=custom-first-id
30 | * instead of: http://example.com/#&gid=1&pid=1
31 | * enable options history:true, galleryPIDs:true and add pid (unique picture identifier)
32 | */
33 | pid?: string | number
34 | }
35 |
36 | export interface PswpItem extends Item {
37 | el: HTMLElement
38 | src: string
39 | msrc?: string
40 | pid?: number | string
41 | verticalRotated?: boolean
42 | }
43 |
44 | export interface ManualImgItem extends Partial- {
45 | src: string
46 | }
47 |
48 | export type ManualHtmlItem = Partial
-
49 |
50 | export interface CurrentPswpItem extends PswpItem {
51 | container: HTMLElement
52 | loaded: boolean
53 | }
54 |
55 | export type PswpOptions = Options
56 |
57 | export interface OpenPhotoSwipeArgs {
58 | index: number | string
59 | fromURL?: boolean
60 | thumbEls?: HTMLElement[]
61 | }
62 |
63 | export interface BeforeOpenEvent {
64 | index: number
65 | target: HTMLElement
66 | items: PswpItem[]
67 | options: PswpOptions
68 | }
69 |
70 | export interface Size {
71 | w: number
72 | h: number
73 | }
74 |
75 | export interface ManualCreateArgs {
76 | items: ManualOpenItem[]
77 | options?: PswpOptions
78 | }
79 |
80 | interface CreatePhotoSwipeArgs extends ManualCreateArgs {
81 | context?: Vue
82 | }
83 |
84 | export interface PswpProps {
85 | options: PswpOptions
86 | auto: boolean
87 | bubble: boolean
88 | lazy: boolean
89 | filter: Function
90 | rotate: boolean
91 | }
92 |
93 | // types
94 | export type Fn = (...args: any[]) => void
95 |
96 | export type Pswp = PhotoSwipe
97 |
98 | export type BeforeOpen = (continued?: boolean) => void
99 |
100 | export type Filter = (img: HTMLImageElement) => boolean
101 |
102 | export type FindIndex = (array: T[], predicate: (item: T, idx: number) => boolean) => number
103 |
104 | export type Closest = (
105 | el: Node | null,
106 | predicate: (el: HTMLElement) => boolean
107 | ) => HTMLElement | false
108 |
109 | export type Single = (fn: Function) => (...args: any[]) => T
110 |
111 | export type BindEvent = (pswp: Pswp, context?: Vue) => void
112 |
113 | export type CreatePhotoSwipe = (arg: CreatePhotoSwipeArgs) => Pswp
114 |
115 | export type HandleWithoutSize = (pswp: Pswp) => void
116 |
117 | export type GetContainSize = (
118 | areaWidth: number,
119 | areaHeight: number,
120 | width: number,
121 | height: number
122 | ) => Size
123 |
124 | export type RotateDirection = 'left' | 'right'
125 |
126 | export type StyleKey = Exclude
127 |
128 | export type ManualOpenItem = ManualImgItem | ManualHtmlItem
129 |
--------------------------------------------------------------------------------
/tests/unit/util.ts:
--------------------------------------------------------------------------------
1 | import PhotoSwipe from 'photoswipe'
2 | import defaultUI from 'photoswipe/dist/photoswipe-ui-default'
3 | import {
4 | mount,
5 | createLocalVue,
6 | shallowMount,
7 | ShallowMountOptions,
8 | MountOptions,
9 | } from '@vue/test-utils'
10 | import Photoswipe from '@/components/photoswipe.vue'
11 | import PswpUI from '@/components/pswpUI.vue'
12 | import VuePswipe from '@/main'
13 | import { UI } from '@/utils'
14 | import { Pswp } from '@/type'
15 | import { Component } from 'vue'
16 |
17 | /**
18 | * mock photoswipe
19 | */
20 | jest.mock('photoswipe', () => {
21 | const OriginalPhotoSwipe = jest.requireActual('photoswipe')
22 | return jest.fn((...args: any[]) => new OriginalPhotoSwipe(...args))
23 | })
24 |
25 | export { PhotoSwipe }
26 |
27 | /**
28 | * handy methods
29 | */
30 | export namespace PhotoSwipeMock {
31 | export const getReceiveItems = () => PhotoSwipe.mock.calls[0][2]
32 | export const getReceiveOptions = () => PhotoSwipe.mock.calls[0][3]
33 | export const getPswp = () => (PhotoSwipe.mock.results[0].value as any) as Pswp
34 | }
35 |
36 | /**
37 | * create PhotoSwipe instance
38 | */
39 | export const fakeSrc = 'https://placeimg.com/640/480/any'
40 | const imgSlots = `
`
41 |
42 | const commonLocalVue = createLocalVue()
43 | commonLocalVue.use(VuePswipe)
44 |
45 | export interface CreatePswpOptions extends MountOptions {
46 | defaultSlots?: string | Component | string | Component[]
47 | withClick?: boolean
48 | }
49 |
50 | export const createPswp = ({
51 | defaultSlots = imgSlots,
52 | localVue = commonLocalVue,
53 | withClick = true,
54 | ...options
55 | }: CreatePswpOptions = {}) => {
56 | const wrapper = mount(Photoswipe, {
57 | localVue,
58 | slots: {
59 | default: defaultSlots,
60 | },
61 | ...options,
62 | })
63 |
64 | withClick && wrapper.find('img').trigger('click')
65 | return wrapper
66 | }
67 |
68 | export const createPswpUI = (options?: ShallowMountOptions) =>
69 | shallowMount(PswpUI, {
70 | localVue: commonLocalVue,
71 | ...options,
72 | })
73 |
74 | /**
75 | * mock load image resource
76 | */
77 | export namespace mockImageOnload {
78 | const loadedImgs = new Set()
79 |
80 | const originalImgProtoDesc = Object.getOwnPropertyDescriptor(
81 | window.Image.prototype,
82 | 'src'
83 | ) as PropertyDescriptor
84 |
85 | const mockImgProtoDesc = {
86 | set(this: HTMLImageElement, value: string) {
87 | if (originalImgProtoDesc.set) {
88 | originalImgProtoDesc.set.call(this, value)
89 | }
90 | loadedImgs.add(value)
91 | this.dispatchEvent(new CustomEvent('load'))
92 | const [, width = 0, height = 0] =
93 | value.match(/https:\/\/placeimg.com\/(\d+)\/(\d+)\/any/) || []
94 | this.width = +width
95 | this.height = +height
96 | },
97 | } as PropertyDescriptor
98 |
99 | const setImgProtoSrc = (enableMock: boolean) => {
100 | const desc = enableMock ? mockImgProtoDesc : originalImgProtoDesc
101 |
102 | Object.defineProperty(window.Image.prototype, 'src', desc)
103 | }
104 |
105 | export const enable = () => setImgProtoSrc(true)
106 | export const disable = () => {
107 | setImgProtoSrc(false)
108 | loadedImgs.clear()
109 | }
110 | export const isLoaded = (srcs: string[]) => srcs.every((src) => loadedImgs.has(src))
111 | }
112 |
113 | /**
114 | * get fake images
115 | */
116 | const getRandomSize = () => Math.floor(Math.random() * 1e3 + 1e2)
117 |
118 | const getRandomImgSrc = () => {
119 | const width: number = getRandomSize()
120 | const height: number = getRandomSize()
121 | return `https://placeimg.com/${width}/${height}/any`
122 | }
123 |
124 | export const getFakeImages = (length: number = 1): string[] =>
125 | [...Array(length).keys()].map(() => getRandomImgSrc())
126 |
127 | export const createProtoPswp = () => {
128 | const buttonTemplate = ''
129 | const slideHtml =
130 | ''
131 |
132 | const wrapper = mount(
133 | {
134 | template: buttonTemplate,
135 | methods: {
136 | handleClick() {
137 | this.$Pswp.open({
138 | items: [{ html: slideHtml }],
139 | })
140 | },
141 | },
142 | },
143 | {
144 | localVue: commonLocalVue,
145 | }
146 | )
147 |
148 | wrapper.find('button').trigger('click')
149 |
150 | return wrapper
151 | }
152 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-pswipe  [](https://travis-ci.com/GuoQichen/vue-pswipe) [](https://codecov.io/gh/GuoQichen/vue-pswipe)
2 | a Vue plugin for PhotoSwipe without set image size
3 |
4 | ## online example
5 | [](https://codesandbox.io/s/619x48656r)
6 |
7 | ## install
8 | ```
9 | npm install vue-pswipe
10 | ```
11 |
12 | ## usage
13 |
14 | ```js
15 | // main.js
16 | import Photoswipe from 'vue-pswipe'
17 |
18 | Vue.use(Photoswipe, options)
19 | ```
20 | see [complete options](http://photoswipe.com/documentation/options.html)
21 |
22 | you can set `v-pswp` directive in element to mark as clickable
23 | ```vue
24 |
25 |
29 |
30 | ```
31 |
32 | ## props
33 |
34 | | Property | Type | Description | Default |
35 | | --- | --- | --- | --- |
36 | | options | object | original PhotoSwipe options, see [complete options](http://photoswipe.com/documentation/options.html) | - |
37 | | auto | boolean | automatically collect all img tags without the need for the `v-pswp` directive | false |
38 | | bubble | boolean | allow click event bubbling | false |
39 | | lazy | boolean | lazy loading image, you can set to false to preload all image | true |
40 | | rotate | boolean | add a rotate action button to the top bar, allow user to rotate the current image | false |
41 |
42 | ## directive
43 |
44 | ### `v-pswp: object|string`
45 | use for mark current element as gallery item, accept **image src** or **options object**
46 |
47 | Directive Options:
48 | ```typescript
49 | interface PswpDirectiveOptions {
50 | /**
51 | * path to image
52 | */
53 | src: string
54 | /**
55 | * image size, 'width x height', eg: '100x100'
56 | */
57 | size?: string
58 | /**
59 | * small image placeholder,
60 | * main (large) image loads on top of it,
61 | * if you skip this parameter - grey rectangle will be displayed,
62 | * try to define this property only when small image was loaded before
63 | */
64 | msrc?: string
65 | /**
66 | * used by Default PhotoSwipe UI
67 | * if you skip it, there won't be any caption
68 | */
69 | title?: string
70 | /**
71 | * to make URLs to a single image look like this: http://example.com/#&gid=1&pid=custom-first-id
72 | * instead of: http://example.com/#&gid=1&pid=1
73 | * enable options history: true, galleryPIDs: true and add pid (unique picture identifier)
74 | */
75 | pid?: string | number
76 | }
77 | ```
78 |
79 | ## event
80 |
81 | ### `beforeOpen`
82 | emit after click thumbnail, if listen to this event, **`next` function must be called to resolve this hook**
83 |
84 | Parameters:
85 | - `event`:
86 | - `index`: current image index
87 | - `target`: the target that triggers effective click event
88 | - `next`:
89 |
90 | must be called to resolve the hook. `next(false)` will abort open PhotoSwipe
91 |
92 | ### `opened`
93 | emit after photoswipe init, you can get current active photoswipe instance by parameter
94 |
95 | Parameters:
96 | - `pswp`:
97 |
98 | current photoswipe instance
99 |
100 | ### original PhotoSwipe event
101 | **support all original PhotoSwipe events**, see [original event](https://github.com/dimsemenov/PhotoSwipe/blob/master/website/documentation/api.md#events), eg:
102 | ```vue
103 |
104 |
108 |
109 | ```
110 |
111 | WARNING: If you using Photoswipe component in HTML, not in a SFC, use `v-on` instead, because HTML tag and attributes are case insensitive
112 | ```vue
113 |
114 |
118 |
119 | ```
120 |
121 | ## custom html
122 | In addition to using the `` tag, you can also use `Vue.prototype.$Pswp.open(params)` to directly open a PhotoSwipe. This is especially useful in the case of [Custom HTML Content in Slides](https://photoswipe.com/documentation/custom-html-in-slides.html).
123 | ```vue
124 |
125 |
126 |
127 |
142 | ```
143 |
144 | `Vue.prototyp.$Pswp.open`:
145 | ```typescript
146 | type Open = (params: {
147 | items: PswpItem[],
148 | options?: PswpOptions
149 | }) => pswp
150 | ```
151 |
152 | ## dynamic import
153 | **But cannot use `vue.prototype.$Pswp.open()`**
154 | ```vue
155 |
163 | ```
164 |
165 | ## example
166 | ```
167 | npm run dev
168 | ```
169 |
170 | ## License
171 | [MIT](http://opensource.org/licenses/MIT)
172 |
--------------------------------------------------------------------------------
/example/sample.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | use img tag
5 |
12 |
13 | use background-image
14 |
21 |
22 | use batch
23 |
30 |
31 | use bubble mode
32 |
33 |
34 |
35 |
36 | dynamic property
37 |
38 |
39 |
40 | use msrc option
41 |
48 |
49 |
50 |
51 | use dynamic template
52 |
53 |
54 |
55 | use auto mode
56 |
62 |
63 | use beforeOpen hook
64 |
65 |
66 |
67 |
68 |
69 |
manual open
70 |
71 |
72 |
73 |
177 |
190 |
--------------------------------------------------------------------------------
/tests/unit/global.spec.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/first */
2 | import {
3 | PhotoSwipe,
4 | PhotoSwipeMock,
5 | createPswp,
6 | fakeSrc,
7 | CreatePswpOptions,
8 | createProtoPswp,
9 | } from './util'
10 |
11 | import { createLocalVue } from '@vue/test-utils'
12 | import VuePswipe from '@/main'
13 | import Vue, { ComponentOptions } from 'vue'
14 | import { PswpDirectiveOptions } from '@/type'
15 |
16 | describe('global function', () => {
17 | beforeEach(() => {
18 | expect(PhotoSwipe).not.toHaveBeenCalled()
19 | })
20 |
21 | afterEach(() => {
22 | PhotoSwipe.mockClear()
23 | })
24 |
25 | it('global options', () => {
26 | const bgOpacity = 0.5
27 | const optionsLocalVue = createLocalVue()
28 | optionsLocalVue.use(VuePswipe, {
29 | bgOpacity,
30 | })
31 |
32 | createPswp({
33 | localVue: optionsLocalVue,
34 | })
35 |
36 | const receiveOptions = PhotoSwipeMock.getReceiveOptions()
37 | expect(receiveOptions.bgOpacity).toBe(bgOpacity)
38 | })
39 |
40 | it('allow listening to the original PhotoSwipe event', () => {
41 | const mock = jest.fn()
42 |
43 | createPswp({
44 | listeners: {
45 | gettingData: mock,
46 | },
47 | })
48 |
49 | expect(mock).toBeCalled()
50 | })
51 |
52 | describe('history mode', () => {
53 | const createHashPswp = (hashPath: string, options?: CreatePswpOptions) => {
54 | window.history.pushState({}, '', hashPath)
55 |
56 | const wrapper = createPswp({
57 | withClick: false,
58 | attachToDocument: true,
59 | propsData: {
60 | options: {
61 | history: true,
62 | },
63 | },
64 | ...options,
65 | })
66 |
67 | document.body.appendChild(wrapper.vm.$el)
68 |
69 | return wrapper
70 | }
71 |
72 | it('with history hash', () => {
73 | const wrapper = createHashPswp('/#&gid=1&pid=1')
74 |
75 | expect(PhotoSwipe).toBeCalled()
76 | wrapper.destroy()
77 | })
78 |
79 | it('with custom hash', () => {
80 | const customPid = 'custom-first-id'
81 |
82 | const wrapper = createHashPswp(`/#&gid=1&pid=${customPid}`, {
83 | defaultSlots: `
84 |
89 | `,
90 | propsData: {
91 | options: {
92 | history: true,
93 | galleryPIDs: true,
94 | },
95 | },
96 | })
97 |
98 | expect(PhotoSwipe).toBeCalled()
99 | wrapper.destroy()
100 | })
101 |
102 | it('with custom hash and set options.galleryPIDs to false', () => {
103 | const customPid = 'custom-first-id'
104 |
105 | expect(() => {
106 | createHashPswp(`/#&gid=1&pid=${customPid}`, {
107 | propsData: {
108 | options: {
109 | galleryPIDs: false,
110 | },
111 | },
112 | })
113 | }).toThrowError(
114 | '[vue-pswipe] PhotoSwipe cannot be opened because the index is invalid. If you use a custom pid, set options.galleryPIDs to true.'
115 | )
116 | })
117 | })
118 |
119 | describe('v-pswp directive', () => {
120 | const defaultPswpItem = {
121 | src: 'https://farm4.staticflickr.com/3894/15008518202_c265dfa55f_h.jpg',
122 | size: '1600x1600',
123 | msrc: 'https://farm4.staticflickr.com/3894/15008518202_b016d7d289_m.jpg',
124 | title: 'this is dummy caption',
125 | pid: 'custom-pid',
126 | }
127 |
128 | const createDirectivePswp = ({
129 | pswpItem = defaultPswpItem,
130 | ...slotOptions
131 | }: createDirectivePswpArgs = {}) =>
132 | createPswp({
133 | defaultSlots: {
134 | data: () => ({
135 | pswpItem,
136 | }),
137 | template: `
138 |
142 | `,
143 | ...slotOptions,
144 | },
145 | })
146 |
147 | it('transform to custom dataset', () => {
148 | const wrapper = createDirectivePswp()
149 |
150 | expect(wrapper.find('img').vm.$el).toMatchSnapshot()
151 | })
152 |
153 | it('data-pswp-src shorthand', () => {
154 | const wrapper = createDirectivePswp({
155 | pswpItem: fakeSrc,
156 | })
157 |
158 | const el = wrapper.find('img').vm.$el as HTMLElement
159 |
160 | expect(el.dataset.pswpSrc).toBe(fakeSrc)
161 | })
162 |
163 | it('update directive value', () => {
164 | const anotherPswpItem = {
165 | src: 'https://farm6.staticflickr.com/5591/15008867125_b61960af01_h.jpg',
166 | size: '1600x1068',
167 | msrc: 'https://farm6.staticflickr.com/5591/15008867125_68a8ed88cc_m.jpg',
168 | title: 'this is another dummy caption',
169 | pid: 'another-custom-pid',
170 | }
171 |
172 | const wrapper = createDirectivePswp({
173 | methods: {
174 | changePswpItem() {
175 | this.pswpItem = anotherPswpItem
176 | },
177 | },
178 | })
179 |
180 | const img = wrapper.find('img')
181 | const vm = img.vm as ImageComponent
182 |
183 | vm.changePswpItem()
184 | expect(vm.$el).toMatchSnapshot()
185 | })
186 | })
187 |
188 | describe('Vue.prototype.$Pswp', () => {
189 | it('open()', () => {
190 | createProtoPswp()
191 | expect(PhotoSwipe).toBeCalled()
192 | })
193 | })
194 | })
195 |
196 | interface ImageComponent extends Vue {
197 | pswpItem: PswpDirectiveOptions
198 | changePswpItem: () => void
199 | }
200 |
201 | type ImageOptions = ComponentOptions
202 |
203 | interface createDirectivePswpArgs extends ImageOptions {
204 | pswpItem?: string | PswpDirectiveOptions
205 | }
206 |
--------------------------------------------------------------------------------
/src/components/pswpUI.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
82 |
83 |
160 |
179 |
--------------------------------------------------------------------------------
/src/components/photoswipe.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
229 |
238 |
--------------------------------------------------------------------------------
/tests/unit/photoswipe.spec.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/first */
2 | import {
3 | PhotoSwipe,
4 | PhotoSwipeMock,
5 | createPswp,
6 | createPswpUI,
7 | fakeSrc,
8 | mockImageOnload,
9 | getFakeImages,
10 | CreatePswpOptions,
11 | } from './util'
12 |
13 | import { BeforeOpenEvent, BeforeOpen } from '@/type'
14 |
15 | describe('photoswipe.vue', () => {
16 | beforeEach(() => {
17 | expect(PhotoSwipe).not.toHaveBeenCalled()
18 | })
19 |
20 | afterEach(() => {
21 | PhotoSwipe.mockClear()
22 | })
23 |
24 | it('render Photoswipe', () => {
25 | expect(
26 | createPswp({
27 | withClick: false,
28 | })
29 | ).toMatchSnapshot()
30 | })
31 |
32 | describe(':props', () => {
33 | describe(':options', () => {
34 | const createOptionsPswp = (options: Record = {}) => {
35 | createPswp({
36 | propsData: {
37 | options,
38 | },
39 | })
40 |
41 | return PhotoSwipeMock.getReceiveOptions()
42 | }
43 |
44 | it('render default options', () => {
45 | const options = createOptionsPswp()
46 | expect(JSON.stringify(options, null, 2)).toMatchSnapshot()
47 | })
48 |
49 | it('set options', () => {
50 | const bgOpacity = 0.5
51 | const options = createOptionsPswp({
52 | bgOpacity,
53 | })
54 |
55 | expect(options.bgOpacity).toBe(bgOpacity)
56 | })
57 |
58 | it('set options.showHideOpacity', () => {
59 | const options = createOptionsPswp({
60 | showHideOpacity: true,
61 | })
62 |
63 | expect(options.showHideOpacity).toBe(true)
64 | })
65 | })
66 |
67 | describe(':auto', () => {
68 | const createAutoPswp = (auto: boolean, options?: CreatePswpOptions) =>
69 | createPswp({
70 | defaultSlots: `
`,
71 | propsData: {
72 | auto,
73 | },
74 | ...options,
75 | })
76 |
77 | it('without auto', () => {
78 | createAutoPswp(false)
79 | expect(PhotoSwipe).not.toBeCalled()
80 | })
81 |
82 | it('with auto', () => {
83 | createAutoPswp(true)
84 | expect(PhotoSwipe).toBeCalled()
85 | })
86 |
87 | it('with auto and empty img', () => {
88 | createAutoPswp(true, {
89 | defaultSlots: `
`,
90 | })
91 |
92 | expect(PhotoSwipeMock.getReceiveItems()).toEqual([
93 | expect.objectContaining({
94 | msrc: '',
95 | src: '',
96 | }),
97 | ])
98 | })
99 | })
100 |
101 | describe(':bubble', () => {
102 | const createBubblePswp = (bubble: boolean) => {
103 | createPswp({
104 | defaultSlots: `
105 |
106 |

107 |
108 | `,
109 | propsData: {
110 | bubble,
111 | },
112 | })
113 | }
114 |
115 | it('without bubble', () => {
116 | createBubblePswp(false)
117 | expect(PhotoSwipe).not.toBeCalled()
118 | })
119 |
120 | it('with bubble', () => {
121 | createBubblePswp(true)
122 | expect(PhotoSwipe).toBeCalled()
123 | })
124 | })
125 |
126 | describe(':rotate', () => {
127 | it('set pswpUI rotate', () => {
128 | const pswpUIWrapper = createPswpUI()
129 |
130 | createPswp({
131 | propsData: {
132 | rotate: true,
133 | },
134 | })
135 |
136 | expect(pswpUIWrapper.vm.$data.rotate).toBe(true)
137 | })
138 | })
139 |
140 | describe(':lazy', () => {
141 | const createLazyPswp = (lazy: boolean, fakeImageLength: number) => {
142 | const fakeImages = getFakeImages(fakeImageLength)
143 |
144 | const wrapper = createPswp({
145 | withClick: false,
146 | defaultSlots: fakeImages.map((src, index) => ({
147 | data: () => ({
148 | pswpItem: {
149 | src,
150 | },
151 | }),
152 | template: `
153 |
158 | `,
159 | })),
160 | propsData: {
161 | lazy,
162 | },
163 | })
164 |
165 | return {
166 | wrapper,
167 | fakeImages,
168 | }
169 | }
170 |
171 | beforeEach(() => {
172 | mockImageOnload.enable()
173 | })
174 |
175 | afterEach(() => {
176 | mockImageOnload.disable()
177 | })
178 |
179 | it('only load current, the previous and the next', () => {
180 | const len = 10
181 | const { wrapper, fakeImages } = createLazyPswp(true, len)
182 |
183 | wrapper.find('#img-5').trigger('click')
184 | const shouldLoadedIndex = [4, 5, 6]
185 |
186 | expect(mockImageOnload.isLoaded(shouldLoadedIndex.map((i) => fakeImages[i]))).toBe(
187 | true
188 | )
189 |
190 | expect(
191 | mockImageOnload.isLoaded(
192 | [...Array(len).keys()]
193 | .filter((i) => !shouldLoadedIndex.includes(i))
194 | .map((i) => fakeImages[i])
195 | )
196 | ).toBe(false)
197 | })
198 |
199 | it('preload all image', () => {
200 | const len = 10
201 | const { wrapper, fakeImages } = createLazyPswp(false, len)
202 |
203 | wrapper.find('#img-5').trigger('click')
204 |
205 | expect(
206 | mockImageOnload.isLoaded([...Array(len).keys()].map((i) => fakeImages[i]))
207 | ).toBe(true)
208 | })
209 | })
210 | })
211 |
212 | describe('@event', () => {
213 | describe('@beforeOpen', () => {
214 | const getMock = (continued: boolean) =>
215 | jest.fn((target: BeforeOpenEvent, next: BeforeOpen) => {
216 | next(continued)
217 |
218 | continued
219 | ? expect(PhotoSwipe).toBeCalled()
220 | : expect(PhotoSwipe).not.toBeCalled()
221 | })
222 |
223 | const createBeforeOpenPswp = (continued: boolean) => {
224 | const mock = getMock(continued)
225 |
226 | createPswp({
227 | listeners: {
228 | beforeOpen: mock,
229 | },
230 | })
231 |
232 | return {
233 | mock,
234 | }
235 | }
236 |
237 | it('called with specified parameters', () => {
238 | const { mock } = createBeforeOpenPswp(true)
239 | expect(mock.mock.calls[0].length).toBe(2)
240 | })
241 |
242 | it('abort open PhotoSwipe', () => {
243 | const { mock } = createBeforeOpenPswp(false)
244 | expect(mock).toBeCalled()
245 | })
246 | })
247 |
248 | describe('@opened', () => {
249 | it('get pswp from cb', () => {
250 | const mock = jest.fn()
251 | const wrapper = createPswp({
252 | withClick: false,
253 | })
254 | wrapper.vm.$on('opened', mock)
255 |
256 | wrapper.find('img').trigger('click')
257 | const pswp = PhotoSwipeMock.getPswp()
258 |
259 | expect(mock).toBeCalled()
260 | expect(mock).toBeCalledWith(pswp)
261 | })
262 | })
263 | })
264 | })
265 |
--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------
1 | import PhotoSwipe from 'photoswipe'
2 | import defaultUI from 'photoswipe/dist/photoswipe-ui-default'
3 | import {
4 | PswpItem,
5 | Size,
6 | FindIndex,
7 | Closest,
8 | Single,
9 | PswpDirectiveOptions,
10 | CreatePhotoSwipe,
11 | BindEvent,
12 | HandleWithoutSize,
13 | Pswp,
14 | GetContainSize,
15 | RotateDirection,
16 | CurrentPswpItem,
17 | StyleKey,
18 | ManualCreateArgs,
19 | ManualOpenItem,
20 | } from '@/type'
21 | import { customEvents, GlobalOption } from '@/config'
22 | import Vue from 'vue'
23 | import PswpUI from '@/components/pswpUI.vue'
24 |
25 | export const isMobile = (): boolean =>
26 | /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
27 |
28 | export const isNum = (value: any): value is number => typeof value === 'number'
29 |
30 | export const isStr = (value: any): value is string => typeof value === 'string'
31 |
32 | export const isObj = (value: any): value is object =>
33 | Object.prototype.toString.call(value) === '[object Object]'
34 |
35 | export const isFunction = (value: any): value is Function =>
36 | Object.prototype.toString.call(value) === '[object Function]'
37 |
38 | const isDef = (value: any): boolean => value !== undefined && value !== null
39 |
40 | export const isImg = (value: any): value is HTMLImageElement => value && value.tagName === 'IMG'
41 |
42 | const isEle = (node: Node): node is HTMLElement => node.nodeType === 1
43 |
44 | export const isBgImg = (el: HTMLElement): boolean => !isImg(el) && !!el.dataset.pswpSrc
45 |
46 | /**
47 | * default error handle method
48 | * @param hint error hint
49 | */
50 | export const errorHandler = (hint: string): never => {
51 | throw new Error(`[vue-pswipe] ${hint}`)
52 | }
53 |
54 | /**
55 | * get current active PhotoSwipe, else null
56 | */
57 | export namespace CurrentPswp {
58 | /* eslint-disable no-shadow */
59 | let currentPswp: Pswp | null = null
60 | const setupClean = (pswp: Pswp) => {
61 | pswp.listen('destroy', () => {
62 | currentPswp = null
63 | })
64 | }
65 | export const get = () => currentPswp
66 |
67 | export const set = (pswp: Pswp | null) => {
68 | currentPswp = pswp
69 | if (pswp) setupClean(pswp)
70 | }
71 | }
72 |
73 | /**
74 | * get image size by polling
75 | * @param path the image src to get size
76 | * @return return promise
77 | */
78 | export const getImageSize = (path: string) =>
79 | new Promise((resolve) => {
80 | const img = new Image()
81 | let timer: number
82 | img.src = path
83 | img.addEventListener('error', () => {
84 | clearTimeout(timer)
85 | })
86 | const check = () => {
87 | if (img.width > 0 || img.height > 0) {
88 | return resolve({
89 | w: img.width,
90 | h: img.height,
91 | })
92 | }
93 | timer = window.setTimeout(check, 40)
94 | }
95 | check()
96 | })
97 |
98 | /**
99 | * returns the index of the first element predicate returns truthy
100 | * @param array the array to search
101 | * @param predicate the function invoked per iteration.
102 | * @return return the index of the found element, else -1.
103 | */
104 | export const findIndex: FindIndex = (array, predicate) => {
105 | let index = -1
106 | array.some((item, idx) => {
107 | const result = predicate(item, idx)
108 | if (result) index = idx
109 | return result
110 | })
111 | return index
112 | }
113 |
114 | /**
115 | * parse picture index and gallery index from URL (#&pid=1&gid=2)
116 | * @return return parsed hash, eg: { pid: 1, gid: 2 }
117 | */
118 | export const parseHash = () => {
119 | const hash = window.location.hash.substring(1)
120 | const params: Record = {}
121 |
122 | if (hash.length < 5) return params
123 |
124 | hash.split('&').reduce((acc, cur) => {
125 | if (!cur) return acc
126 | const pair = cur.split('=')
127 | if (pair.length < 2) return acc
128 | const [key, value] = pair
129 | acc[key] = value
130 | return acc
131 | }, params)
132 |
133 | return params
134 | }
135 |
136 | /**
137 | * invoke querySelectorAll with specified context
138 | * @param selector css selector
139 | * @param context the query context
140 | * @return return the list of queries
141 | */
142 | export const querySelectorList = (
143 | selector: string,
144 | context: HTMLElement | Document = document
145 | ) => [...context.querySelectorAll(selector)] as T[]
146 |
147 | /**
148 | * find nearest parent element
149 | * @param el begin element
150 | * @param predicate the function invoked from begin element to body
151 | * @returns return the found element or false
152 | */
153 | export const closest: Closest = (el, predicate) =>
154 | !!el && isEle(el) && (predicate(el) ? el : closest(el.parentNode, predicate))
155 |
156 | /**
157 | * singleton pattern
158 | * @param fn the function should be invoked only once
159 | * @return wrapped function
160 | */
161 | export const single: Single = (fn) => {
162 | let result: any
163 | // eslint-disable-next-line func-names
164 | return function(this: any, ...args: any[]) {
165 | return result || (result = fn.apply(this, args))
166 | }
167 | }
168 |
169 | /**
170 | * append element to document.body
171 | * @param el the element to be append to body
172 | * @return return appended element
173 | */
174 | const append = (el: HTMLElement) => document.body.appendChild(el)
175 |
176 | /**
177 | * append element to body only once
178 | */
179 | export const appendOnce = single(append)
180 |
181 | /**
182 | * set data-pswp-size to element
183 | * @param el the element to set data-pswp-size
184 | * @param size the size object contains w and h property
185 | */
186 | export const setSize = (el: HTMLElement, { w, h }: Size) => {
187 | if (el && el.dataset) {
188 | // eslint-disable-next-line no-param-reassign
189 | el.dataset.pswpSize = `${w}x${h}`
190 | }
191 | }
192 |
193 | /**
194 | * get the image src according to auto
195 | * @param target the element to get the src
196 | * @param auto is it in auto mode
197 | */
198 | export const getSrc = (target: HTMLImageElement | HTMLElement, auto: boolean): string =>
199 | auto && isImg(target) ? target.src : target.dataset.pswpSrc || ''
200 |
201 | /**
202 | * determine whether el is a valid element based on auto and filter
203 | */
204 | export const relevant = (
205 | el: HTMLElement,
206 | auto: boolean,
207 | filter: (el: HTMLImageElement) => boolean
208 | ): boolean => (auto ? isImg(el) && filter(el) : !!el.dataset.pswpSrc)
209 |
210 | /**
211 | * Convert the first letter to uppercase
212 | */
213 | const upperFirst = (str: string) => str.replace(/^\S/, (match) => match.toUpperCase())
214 |
215 | /**
216 | * convert property to pswp property, eg: src => pswpSrc
217 | */
218 | const getPswpDataKey = (property: string) => `pswp${upperFirst(property)}`
219 |
220 | /**
221 | * Set pswp data to the data attribute of the specified element
222 | */
223 | export const setPswpData = (options: PswpDirectiveOptions, el: HTMLElement) => {
224 | Object.keys(options).forEach((key) => {
225 | el.dataset[getPswpDataKey(key)] = `${options[key as keyof PswpDirectiveOptions]}` // eslint-disable-line
226 | })
227 | }
228 |
229 | /**
230 | * Set the pswp data according to the type of the parameter
231 | */
232 | export const setPswpDataByCond = (el: HTMLElement, value: string | PswpDirectiveOptions) => {
233 | if (isStr(value)) setPswpData({ src: value }, el)
234 | if (isObj(value)) setPswpData(value as PswpDirectiveOptions, el)
235 | }
236 |
237 | /**
238 | * preset loaded msrc size to PswpItem
239 | */
240 | export const presetSize = (item: PswpItem): void => {
241 | /* eslint-disable no-param-reassign */
242 | const { src, msrc, el } = item
243 | if (item.w || item.h || !msrc) return
244 |
245 | let img: HTMLImageElement | null = new Image()
246 | img.src = msrc
247 | const { width: w, height: h } = img
248 | if (w && h) {
249 | item.w = w
250 | item.h = h
251 | src === msrc && setSize(el, { w, h })
252 | }
253 | img = null
254 | }
255 |
256 | /**
257 | * allow listen original PhotoSwipe event in Photoswipe component
258 | * @param pswp original PhotoSwipe
259 | * @param context Photoswipe component
260 | */
261 | const bindEvent: BindEvent = (pswp, context) => {
262 | if (!context) return
263 | Object.keys(context.$listeners)
264 | .filter((event) => !customEvents.includes(event))
265 | .forEach((event) => {
266 | const fn = context.$listeners[event]
267 | if (isFunction(fn)) {
268 | pswp.listen(event, (...args: any[]) => {
269 | context.$emit(event, ...args)
270 | })
271 | }
272 | })
273 | }
274 |
275 | /**
276 | * set the size of the image after src is loaded
277 | * @param item the item that will be proxy
278 | * @param pswp original Photoswipe
279 | */
280 | const hackItemImg = (item: PswpItem, pswp: Pswp) => {
281 | let img: HTMLImageElement | null = null
282 | Object.defineProperty(item, 'img', {
283 | get() {
284 | return img
285 | },
286 | set(value) {
287 | if (isImg(value)) {
288 | value.addEventListener('load', () => {
289 | const { naturalWidth: w, naturalHeight: h } = value
290 | item.w = w
291 | item.h = h
292 | setSize(item.el, { w, h })
293 | if (CurrentPswp.get() === pswp) {
294 | pswp.updateSize(true)
295 | }
296 | })
297 | }
298 | img = value
299 | },
300 | })
301 | }
302 |
303 | /**
304 | * handle item without set size, use msrc first
305 | * @param pswp original PhotoSwipe
306 | */
307 | const handleWithoutSize: HandleWithoutSize = (pswp) => {
308 | pswp.listen('gettingData', (index, item: PswpItem) => {
309 | presetSize(item)
310 |
311 | if ((item.el && item.el.dataset.pswpSize) || Object.getOwnPropertyDescriptor(item, 'img'))
312 | return
313 |
314 | // stop unexpected zoom-in animation
315 | if (pswp.currItem === item) {
316 | pswp.options.showAnimationDuration = 0
317 | }
318 |
319 | hackItemImg(item, pswp)
320 | })
321 | }
322 |
323 | const revertRotate = (pswp: Pswp) => {
324 | pswp.listen('gettingData', (index, item: PswpItem) => {
325 | if (!item.verticalRotated) return
326 |
327 | const { w } = item
328 | item.w = item.h
329 | item.h = w
330 | item.verticalRotated = false
331 | })
332 | }
333 |
334 | /**
335 | * manipulate Photoswipe default UI element
336 | */
337 | export namespace UI {
338 | // eslint-disable-next-line import/no-mutable-exports
339 | export let el: HTMLElement
340 | export const mount = () => {
341 | if (!el) {
342 | const PswpUIComponent = new Vue(PswpUI).$mount()
343 | el = PswpUIComponent.$el
344 | }
345 | }
346 | export const append = () => {
347 | mount()
348 | appendOnce(el)
349 | }
350 | }
351 |
352 | /**
353 | * define item.w/item.h if needed
354 | * @param items
355 | */
356 | const defineSize = (items: ManualOpenItem[]) =>
357 | items.map((item) => {
358 | if (!isDef(item.w)) item.w = 0
359 | if (!isDef(item.h)) item.h = 0
360 | return item
361 | })
362 |
363 | /**
364 | * create PhotoSwipe instance, setup listener, init PhotoSwipe
365 | * @return return created original PhotoSwipe instance
366 | */
367 | export const createPhotoSwipe: CreatePhotoSwipe = ({ items, options, context }) => {
368 | const pswp = new PhotoSwipe(UI.el, defaultUI, items, options)
369 | bindEvent(pswp, context)
370 | handleWithoutSize(pswp)
371 | revertRotate(pswp)
372 | CurrentPswp.set(pswp)
373 | pswp.init()
374 | return pswp
375 | }
376 |
377 | /**
378 | * used for this.$Pswp.open()
379 | */
380 | export const manualCreate = ({ items, options }: ManualCreateArgs) =>
381 | createPhotoSwipe({
382 | items: defineSize(items),
383 | options: {
384 | ...GlobalOption.get(),
385 | // disable transition entirely
386 | hideAnimationDuration: 0,
387 | showAnimationDuration: 0,
388 | ...options,
389 | // avoid refresh cant find match gallery
390 | history: false,
391 | },
392 | })
393 |
394 | /**
395 | * emulate background-size: contain, get calculated image size
396 | * @param areaWidth container width
397 | * @param areaHeight container height
398 | * @param width image width
399 | * @param height image height
400 | * @return calculated image size
401 | */
402 | export const getContainSize: GetContainSize = (areaWidth, areaHeight, width, height) => {
403 | if (width <= areaWidth && height <= areaHeight) return { w: width, h: height }
404 | const ratio = width / height
405 | const areaRatio = areaWidth / areaHeight
406 | return areaRatio < ratio
407 | ? { w: areaWidth, h: areaWidth / ratio }
408 | : { w: areaHeight * ratio, h: areaHeight }
409 | }
410 |
411 | /**
412 | * custom event
413 | */
414 | export namespace Event {
415 | const event: Record = {}
416 |
417 | export const off = (name: string, fn?: Function) => {
418 | if (!fn) return (event[name].length = 0)
419 | const pools = event[name]
420 | const index = pools.indexOf(fn)
421 | if (index !== -1) pools.splice(index, 1)
422 | }
423 |
424 | export const on = (name: string, fn: Function) => {
425 | if (!event[name]) event[name] = []
426 | event[name].push(fn)
427 | return () => off(name, fn)
428 | }
429 |
430 | export const once = (name: string, fn: Function) => {
431 | const teardown = on(name, (...args: any[]) => {
432 | teardown()
433 | fn(...args)
434 | })
435 | }
436 |
437 | export const emit = (name: string, ...args: any[]) => {
438 | const pools = event[name]
439 | if (!Array.isArray(pools)) return
440 | pools.forEach((fn) => fn(...args))
441 | }
442 | }
443 |
444 | /**
445 | * get next transform degree from current image element
446 | * @param img current image element
447 | * @param direction rotate direction
448 | * @return transform degree
449 | */
450 | export const getTransformDeg = (img: HTMLImageElement, direction: RotateDirection) => {
451 | const deg = Number(img.dataset.rotateDeg) || 0
452 | const offsets = direction === 'left' ? -90 : 90
453 | const transformDeg = deg + offsets
454 | img.dataset.rotateDeg = `${transformDeg}`
455 | return [deg, transformDeg]
456 | }
457 |
458 | /**
459 | * get container viewport size
460 | * @param container current container element
461 | * @param currentItem current pswp item
462 | * @return container viewport size
463 | */
464 | export const getContainerSize = (container: HTMLElement, currentItem: CurrentPswpItem) => {
465 | const containerWidth = container.clientWidth
466 | const containerHeight = currentItem.vGap
467 | ? container.clientHeight - currentItem.vGap.top - currentItem.vGap.bottom
468 | : container.clientHeight
469 | return {
470 | w: containerWidth,
471 | h: containerHeight,
472 | }
473 | }
474 |
475 | /**
476 | * get transform scale string
477 | * @param w scale width
478 | * @param h scale height
479 | */
480 | export const getScale = (w: number, h = w) => `scale(${w}, ${h})`
481 |
482 | /**
483 | * get transform scale
484 | * @param containerSize container size
485 | * @param img current image element
486 | * @param isVertical next rotate is vertical
487 | */
488 | export const getCalculatedScale = (
489 | containerSize: Size,
490 | img: HTMLImageElement,
491 | isVertical: boolean
492 | ): string[] => {
493 | const { naturalWidth, naturalHeight } = img
494 |
495 | const { w: horizontalWidth, h: horizontalHeight } = getContainSize(
496 | containerSize.w,
497 | containerSize.h,
498 | naturalWidth,
499 | naturalHeight
500 | )
501 |
502 | const { w: verticalWidth, h: verticalHeight } = getContainSize(
503 | containerSize.w,
504 | containerSize.h,
505 | naturalHeight,
506 | naturalWidth
507 | )
508 |
509 | const animatedScale = isVertical
510 | ? getScale(verticalHeight / horizontalWidth)
511 | : getScale(horizontalWidth / verticalWidth, horizontalHeight / verticalHeight)
512 |
513 | const verticalSilencedScale = getScale(
514 | verticalHeight / verticalWidth,
515 | verticalWidth / verticalHeight
516 | )
517 | return [animatedScale, verticalSilencedScale]
518 | }
519 |
520 | /**
521 | * add vendor prefix to css property
522 | */
523 | export const modernize = (() => {
524 | const cache: Record = {}
525 | const detectElement = document.createElement('div')
526 | const { style } = detectElement
527 |
528 | return (styleKey: T): T => {
529 | const cached = cache[styleKey]
530 | if (cached) return cached as T
531 |
532 | let key = styleKey
533 |
534 | /* istanbul ignore if */
535 | if (!isDef(style[styleKey])) {
536 | // eslint-disable-next-line array-callback-return
537 | ;['Moz', 'ms', 'O', 'Webkit'].some((prefix) => {
538 | const prefixedStyleKey = (prefix + upperFirst(styleKey))
539 | if (isDef(style[prefixedStyleKey])) {
540 | return (key = prefixedStyleKey)
541 | }
542 | })
543 | }
544 | cache[styleKey] = key
545 | return key
546 | }
547 | })()
548 |
549 | /**
550 | * get prefixed transition end event name
551 | */
552 | export const transitionEndEventName = (() => {
553 | const transitions = {
554 | transition: 'transitionend',
555 | OTransition: 'oTransitionEnd',
556 | MozTransition: 'transitionend',
557 | WebkitTransition: 'webkitTransitionEnd',
558 | }
559 | const detected = modernize('transition')
560 | return transitions[detected]
561 | })()
562 |
563 | /**
564 | * register v-pswp directive if needed
565 | */
566 | export const registerDirective = () => {
567 | const pswpDirective = Vue.directive('pswp')
568 | if (!pswpDirective) {
569 | Vue.directive('pswp', {
570 | bind(el: HTMLElement, { value }: any) {
571 | setPswpDataByCond(el, value)
572 | },
573 | update(el: HTMLElement, { value, oldValue }: any) {
574 | if (value === oldValue) return
575 | setPswpDataByCond(el, value)
576 | },
577 | })
578 | }
579 | }
580 |
--------------------------------------------------------------------------------
/dist/Photoswipe.umd.min.js:
--------------------------------------------------------------------------------
1 | (function(t,e){"object"===typeof exports&&"object"===typeof module?module.exports=e(require("vue")):"function"===typeof define&&define.amd?define([],e):"object"===typeof exports?exports["Photoswipe"]=e(require("vue")):t["Photoswipe"]=e(t["Vue"])})("undefined"!==typeof self?self:this,function(t){return function(t){var e={};function n(o){if(e[o])return e[o].exports;var i=e[o]={i:o,l:!1,exports:{}};return t[o].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=t,n.c=e,n.d=function(t,e,o){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:o})},n.r=function(t){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"===typeof t&&t&&t.__esModule)return t;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)n.d(o,i,function(e){return t[e]}.bind(null,i));return o},n.n=function(t){var e=t&&t.__esModule?function(){return t["default"]}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s="fb15")}({"14fd":function(t,e,n){var o,i;
2 | /*! PhotoSwipe Default UI - 4.1.3 - 2019-01-08
3 | * http://photoswipe.com
4 | * Copyright (c) 2019 Dmitry Semenov; */
5 | /*! PhotoSwipe Default UI - 4.1.3 - 2019-01-08
6 | * http://photoswipe.com
7 | * Copyright (c) 2019 Dmitry Semenov; */
8 | (function(r,a){o=a,i="function"===typeof o?o.call(e,n,e,t):o,void 0===i||(t.exports=i)})(0,function(){"use strict";var t=function(t,e){var n,o,i,r,a,s,l,u,c,p,d,f,m,h,w,b,g,v,y=this,_=!1,x=!0,A=!0,I={barsSize:{top:44,bottom:"auto"},closeElClasses:["item","caption","zoom-wrap","ui","top-bar"],timeToIdle:4e3,timeToIdleOutside:1e3,loadingIndicatorDelay:1e3,addCaptionHTMLFn:function(t,e){return t.title?(e.children[0].innerHTML=t.title,!0):(e.children[0].innerHTML="",!1)},closeEl:!0,captionEl:!0,fullscreenEl:!0,zoomEl:!0,shareEl:!0,counterEl:!0,arrowEl:!0,preloaderEl:!0,tapToClose:!1,tapToToggleControls:!0,clickToCloseNonZoomable:!0,shareButtons:[{id:"facebook",label:"Share on Facebook",url:"https://www.facebook.com/sharer/sharer.php?u={{url}}"},{id:"twitter",label:"Tweet",url:"https://twitter.com/intent/tweet?text={{text}}&url={{url}}"},{id:"pinterest",label:"Pin it",url:"http://www.pinterest.com/pin/create/button/?url={{url}}&media={{image_url}}&description={{text}}"},{id:"download",label:"Download image",url:"{{raw_image_url}}",download:!0}],getImageURLForShare:function(){return t.currItem.src||""},getPageURLForShare:function(){return window.location.href},getTextForShare:function(){return t.currItem.title||""},indexIndicatorSep:" / ",fitControlsWidth:1200},k=function(t){if(b)return!0;t=t||window.event,w.timeToIdle&&w.mouseUsed&&!c&&N();for(var n,o,i=t.target||t.srcElement,r=i.getAttribute("class")||"",a=0;a-1&&(n.onTap(),o=!0);if(o){t.stopPropagation&&t.stopPropagation(),b=!0;var s=e.features.isOldAndroid?600:30;setTimeout(function(){b=!1},s)}},M=function(){return!t.likelyTouchDevice||w.mouseUsed||screen.width>w.fitControlsWidth},T=function(t,n,o){e[(o?"add":"remove")+"Class"](t,"pswp__"+n)},C=function(){var t=1===w.getNumItemsFn();t!==h&&(T(o,"ui--one-slide",t),h=t)},S=function(){T(l,"share-modal--hidden",A)},E=function(){return A=!A,A?(e.removeClass(l,"pswp__share-modal--fade-in"),setTimeout(function(){A&&S()},300)):(S(),setTimeout(function(){A||e.addClass(l,"pswp__share-modal--fade-in")},30)),A||O(),!1},D=function(e){e=e||window.event;var n=e.target||e.srcElement;return t.shout("shareLinkClick",e,n),!!n.href&&(!!n.hasAttribute("download")||(window.open(n.href,"pswp_share","scrollbars=yes,resizable=yes,toolbar=no,location=yes,width=550,height=420,top=100,left="+(window.screen?Math.round(screen.width/2-275):100)),A||E(),!1))},O=function(){for(var t,e,n,o,i,r="",a=0;a"+t.label+"",w.parseShareButtonOut&&(r=w.parseShareButtonOut(t,r));l.children[0].innerHTML=r,l.children[0].onclick=D},L=function(t){for(var n=0;n=.95&&y.showControls()}),p("onPinchClose",function(e){x&&e<.9?(y.hideControls(),t=!0):t&&!x&&e>.9&&y.showControls()}),p("zoomGestureEnded",function(){t=!1,t&&!x&&y.showControls()})},H=[{name:"caption",option:"captionEl",onInit:function(t){i=t}},{name:"share-modal",option:"shareEl",onInit:function(t){l=t},onTap:function(){E()}},{name:"button--share",option:"shareEl",onInit:function(t){s=t},onTap:function(){E()}},{name:"button--zoom",option:"zoomEl",onTap:t.toggleDesktopZoom},{name:"counter",option:"counterEl",onInit:function(t){a=t}},{name:"button--close",option:"closeEl",onTap:t.close},{name:"button--arrow--left",option:"arrowEl",onTap:t.prev},{name:"button--arrow--right",option:"arrowEl",onTap:t.next},{name:"button--fs",option:"fullscreenEl",onTap:function(){n.isFullscreen()?n.exit():n.enter()}},{name:"preloader",option:"preloaderEl",onInit:function(t){d=t}}],Y=function(){var t,n,i,r=function(o){if(o)for(var r=o.length,a=0;a-1&&(w[i.option]?(e.removeClass(t,"pswp__element--disabled"),i.onInit&&i.onInit(t)):e.addClass(t,"pswp__element--disabled"))}};r(o.children);var a=e.getChildByClass(o,"pswp__top-bar");a&&r(a.children)};y.init=function(){e.extend(t.options,I,!0),w=t.options,o=e.getChildByClass(t.scrollWrap,"pswp__ui"),p=t.listen,B(),p("beforeChange",y.update),p("doubleTap",function(e){var n=t.currItem.initialZoomLevel;t.getZoomLevel()!==n?t.zoomTo(n,e,333):t.zoomTo(w.getDoubleTapZoom(!1,t.currItem),e,333)}),p("preventDragEvent",function(t,e,n){var o=t.target||t.srcElement;o&&o.getAttribute("class")&&t.type.indexOf("mouse")>-1&&(o.getAttribute("class").indexOf("__caption")>0||/(SMALL|STRONG|EM)/i.test(o.tagName))&&(n.prevent=!1)}),p("bindEvents",function(){e.bind(o,"pswpTap click",k),e.bind(t.scrollWrap,"pswpTap",y.onGlobalTap),t.likelyTouchDevice||e.bind(t.scrollWrap,"mouseover",y.onMouseOver)}),p("unbindEvents",function(){A||E(),g&&clearInterval(g),e.unbind(document,"mouseout",P),e.unbind(document,"mousemove",N),e.unbind(o,"pswpTap click",k),e.unbind(t.scrollWrap,"pswpTap",y.onGlobalTap),e.unbind(t.scrollWrap,"mouseover",y.onMouseOver),n&&(e.unbind(document,n.eventK,y.updateFullscreen),n.isFullscreen()&&(w.hideAnimationDuration=0,n.exit()),n=null)}),p("destroy",function(){w.captionEl&&(r&&o.removeChild(r),e.removeClass(i,"pswp__caption--empty")),l&&(l.children[0].onclick=null),e.removeClass(o,"pswp__ui--over-close"),e.addClass(o,"pswp__ui--hidden"),y.setIdle(!1)}),w.showAnimationDuration||e.removeClass(o,"pswp__ui--hidden"),p("initialZoomIn",function(){w.showAnimationDuration&&e.removeClass(o,"pswp__ui--hidden")}),p("initialZoomOut",function(){e.addClass(o,"pswp__ui--hidden")}),p("parseVerticalMargin",F),Y(),w.shareEl&&s&&l&&(A=!0),C(),U(),z(),R()},y.setIdle=function(t){c=t,T(o,"ui--idle",t)},y.update=function(){x&&t.currItem?(y.updateIndexIndicator(),w.captionEl&&(w.addCaptionHTMLFn(t.currItem,i),T(i,"caption--empty",!t.currItem.title)),_=!0):_=!1,A||E(),C()},y.updateFullscreen=function(o){o&&setTimeout(function(){t.setScrollOffset(0,e.getScrollY())},50),e[(n.isFullscreen()?"add":"remove")+"Class"](t.template,"pswp--fs")},y.updateIndexIndicator=function(){w.counterEl&&(a.innerHTML=t.getCurrentIndex()+1+w.indexIndicatorSep+w.getNumItemsFn())},y.onGlobalTap=function(n){n=n||window.event;var o=n.target||n.srcElement;if(!b)if(n.detail&&"mouse"===n.detail.pointerType){if(L(o))return void t.close();e.hasClass(o,"pswp__img")&&(1===t.getZoomLevel()&&t.getZoomLevel()<=t.currItem.fitRatio?w.clickToCloseNonZoomable&&t.close():t.toggleDesktopZoom(n.detail.releasePoint))}else if(w.tapToToggleControls&&(x?y.hideControls():y.showControls()),w.tapToClose&&(e.hasClass(o,"pswp__img")||L(o)))return void t.close()},y.onMouseOver=function(t){t=t||window.event;var e=t.target||t.srcElement;T(o,"ui--over-close",L(e))},y.hideControls=function(){e.addClass(o,"pswp__ui--hidden"),x=!1},y.showControls=function(){x=!0,_||y.update(),e.removeClass(o,"pswp__ui--hidden")},y.supportsFullscreen=function(){var t=document;return!!(t.exitFullscreen||t.mozCancelFullScreen||t.webkitExitFullscreen||t.msExitFullscreen)},y.getFullscreenAPI=function(){var e,n=document.documentElement,o="fullscreenchange";return n.requestFullscreen?e={enterK:"requestFullscreen",exitK:"exitFullscreen",elementK:"fullscreenElement",eventK:o}:n.mozRequestFullScreen?e={enterK:"mozRequestFullScreen",exitK:"mozCancelFullScreen",elementK:"mozFullScreenElement",eventK:"moz"+o}:n.webkitRequestFullscreen?e={enterK:"webkitRequestFullscreen",exitK:"webkitExitFullscreen",elementK:"webkitFullscreenElement",eventK:"webkit"+o}:n.msRequestFullscreen&&(e={enterK:"msRequestFullscreen",exitK:"msExitFullscreen",elementK:"msFullscreenElement",eventK:"MSFullscreenChange"}),e&&(e.enter=function(){if(u=w.closeOnScroll,w.closeOnScroll=!1,"webkitRequestFullscreen"!==this.enterK)return t.template[this.enterK]();t.template[this.enterK](Element.ALLOW_KEYBOARD_INPUT)},e.exit=function(){return w.closeOnScroll=u,document[this.exitK]()},e.isFullscreen=function(){return document[this.elementK]}),e}};return t})},"178d":function(t,e){t.exports="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQgAAABYCAQAAACjBqE3AAAB6klEQVR4Ae3bsWpUQRTG8YkkanwCa7GzVotsI/gEgk9h4Vu4ySLYmMYgbJrc3lrwZbJwC0FMt4j7F6Y4oIZrsXtgxvx/1c0ufEX4cnbmLCmSJEmSJEmSJEmSJP3XCBPvbJU+8doWmDFwyZpLBmYlNJebz0KwzykwsuSYJSNwykEJreV2BaBMaLIQZ2xYcFgqDlmw4ayE/FwL0dDk4Qh4W37DAjgqIT+3HRbigjH+iikVdxgZStgyN0Su2sXIeTwTT+esdpcbIlfNAuZ/TxresG4zV8kYWSZNiKUTokMMSWeIwTNEn4fK2TW3gRNgVkJLuVksROA9G+bEvoATNlBCa7nZXEwdxEZxzpKRKFh+bsv8LmPFmhX1OwfIz81jIRJQ5eeqG9B+riRJkiRJkiRJkiRJkiRJkiRJUkvA/8RQoEpKlJWINFkJ62AlrEP/mNBibnv2yz/A3t7Uq3LcpoxP8COjC1T5vxoAD5VdoEqdDrd5QuW1swtUSaueh3zkiuBiqgtA2OlkeMcP/uDqugsJdbjHF65VdPMKwS0+WQc/MgKvrIOHysB9vgPwk8+85hmPbnQdvHZyDMAFD7L3EOpgMcVdvnHFS0/vlatrXvCVx0U9gt3fxvnA0/hB4nmRJEmSJEmSJEmSJGmHfgFLaDPoMu5xWwAAAABJRU5ErkJggg=="},"1de3":function(t,e,n){var o=n("b041");e=t.exports=n("2350")(!1),e.push([t.i,"/*! PhotoSwipe Default UI CSS by Dmitry Semenov | photoswipe.com | MIT license */.pswp__button{width:44px;height:44px;position:relative;background:none;cursor:pointer;overflow:visible;-webkit-appearance:none;display:block;border:0;padding:0;margin:0;float:right;opacity:.75;-webkit-transition:opacity .2s;transition:opacity .2s;-webkit-box-shadow:none;box-shadow:none}.pswp__button:focus,.pswp__button:hover{opacity:1}.pswp__button:active{outline:none;opacity:.9}.pswp__button::-moz-focus-inner{padding:0;border:0}.pswp__ui--over-close .pswp__button--close{opacity:1}.pswp__button,.pswp__button--arrow--left:before,.pswp__button--arrow--right:before{background:url("+o(n("178d"))+") 0 0 no-repeat;background-size:264px 88px;width:44px;height:44px}@media (-webkit-min-device-pixel-ratio:1.1),(-webkit-min-device-pixel-ratio:1.09375),(min-resolution:1.1dppx),(min-resolution:105dpi){.pswp--svg .pswp__button,.pswp--svg .pswp__button--arrow--left:before,.pswp--svg .pswp__button--arrow--right:before{background-image:url("+o(n("f301"))+')}.pswp--svg .pswp__button--arrow--left,.pswp--svg .pswp__button--arrow--right{background:none}}.pswp__button--close{background-position:0 -44px}.pswp__button--share{background-position:-44px -44px}.pswp__button--fs{display:none}.pswp--supports-fs .pswp__button--fs{display:block}.pswp--fs .pswp__button--fs{background-position:-44px 0}.pswp__button--zoom{display:none;background-position:-88px 0}.pswp--zoom-allowed .pswp__button--zoom{display:block}.pswp--zoomed-in .pswp__button--zoom{background-position:-132px 0}.pswp--touch .pswp__button--arrow--left,.pswp--touch .pswp__button--arrow--right{visibility:hidden}.pswp__button--arrow--left,.pswp__button--arrow--right{background:none;top:50%;margin-top:-50px;width:70px;height:100px;position:absolute}.pswp__button--arrow--left{left:0}.pswp__button--arrow--right{right:0}.pswp__button--arrow--left:before,.pswp__button--arrow--right:before{content:"";top:35px;background-color:rgba(0,0,0,.3);height:30px;width:32px;position:absolute}.pswp__button--arrow--left:before{left:6px;background-position:-138px -44px}.pswp__button--arrow--right:before{right:6px;background-position:-94px -44px}.pswp__counter,.pswp__share-modal{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.pswp__share-modal{display:block;background:rgba(0,0,0,.5);width:100%;height:100%;top:0;left:0;padding:10px;position:absolute;z-index:1600;opacity:0;-webkit-transition:opacity .25s ease-out;transition:opacity .25s ease-out;-webkit-backface-visibility:hidden;will-change:opacity}.pswp__share-modal--hidden{display:none}.pswp__share-tooltip{z-index:1620;position:absolute;background:#fff;top:56px;border-radius:2px;display:block;width:auto;right:44px;-webkit-box-shadow:0 2px 5px rgba(0,0,0,.25);box-shadow:0 2px 5px rgba(0,0,0,.25);-webkit-transform:translateY(6px);transform:translateY(6px);-webkit-transition:-webkit-transform .25s;transition:-webkit-transform .25s;transition:transform .25s;transition:transform .25s,-webkit-transform .25s;-webkit-backface-visibility:hidden;will-change:transform}.pswp__share-tooltip a{display:block;padding:8px 12px;font-size:14px;line-height:18px}.pswp__share-tooltip a,.pswp__share-tooltip a:hover{color:#000;text-decoration:none}.pswp__share-tooltip a:first-child{border-radius:2px 2px 0 0}.pswp__share-tooltip a:last-child{border-radius:0 0 2px 2px}.pswp__share-modal--fade-in{opacity:1}.pswp__share-modal--fade-in .pswp__share-tooltip{-webkit-transform:translateY(0);transform:translateY(0)}.pswp--touch .pswp__share-tooltip a{padding:16px 12px}a.pswp__share--facebook:before{content:"";display:block;width:0;height:0;position:absolute;top:-12px;right:15px;border:6px solid transparent;border-bottom-color:#fff;-webkit-pointer-events:none;-moz-pointer-events:none;pointer-events:none}a.pswp__share--facebook:hover{background:#3e5c9a;color:#fff}a.pswp__share--facebook:hover:before{border-bottom-color:#3e5c9a}a.pswp__share--twitter:hover{background:#55acee;color:#fff}a.pswp__share--pinterest:hover{background:#ccc;color:#ce272d}a.pswp__share--download:hover{background:#ddd}.pswp__counter{position:absolute;left:0;top:0;height:44px;font-size:13px;line-height:44px;color:#fff;opacity:.75;padding:0 10px}.pswp__caption{position:absolute;left:0;bottom:0;width:100%;min-height:44px}.pswp__caption small{font-size:11px;color:#bbb}.pswp__caption__center{text-align:left;max-width:420px;margin:0 auto;font-size:13px;padding:10px;line-height:20px;color:#ccc}.pswp__caption--empty{display:none}.pswp__caption--fake{visibility:hidden}.pswp__preloader{width:44px;height:44px;position:absolute;top:0;left:50%;margin-left:-22px;opacity:0;-webkit-transition:opacity .25s ease-out;transition:opacity .25s ease-out;will-change:opacity;direction:ltr}.pswp__preloader__icn{width:20px;height:20px;margin:12px}.pswp__preloader--active{opacity:1}.pswp__preloader--active .pswp__preloader__icn{background:url('+o(n("76dc"))+") 0 0 no-repeat}.pswp--css_animation .pswp__preloader--active{opacity:1}.pswp--css_animation .pswp__preloader--active .pswp__preloader__icn{-webkit-animation:clockwise .5s linear infinite;animation:clockwise .5s linear infinite}.pswp--css_animation .pswp__preloader--active .pswp__preloader__donut{-webkit-animation:donut-rotate 1s cubic-bezier(.4,0,.22,1) infinite;animation:donut-rotate 1s cubic-bezier(.4,0,.22,1) infinite}.pswp--css_animation .pswp__preloader__icn{background:none;opacity:.75;width:14px;height:14px;position:absolute;left:15px;top:15px;margin:0}.pswp--css_animation .pswp__preloader__cut{position:relative;width:7px;height:14px;overflow:hidden}.pswp--css_animation .pswp__preloader__donut{-webkit-box-sizing:border-box;box-sizing:border-box;width:14px;height:14px;border:2px solid #fff;border-radius:50%;border-left-color:transparent;border-bottom-color:transparent;position:absolute;top:0;left:0;background:none;margin:0}@media screen and (max-width:1024px){.pswp__preloader{position:relative;left:auto;top:auto;margin:0;float:right}}@-webkit-keyframes clockwise{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes clockwise{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@-webkit-keyframes donut-rotate{0%{-webkit-transform:rotate(0);transform:rotate(0)}50%{-webkit-transform:rotate(-140deg);transform:rotate(-140deg)}to{-webkit-transform:rotate(0);transform:rotate(0)}}@keyframes donut-rotate{0%{-webkit-transform:rotate(0);transform:rotate(0)}50%{-webkit-transform:rotate(-140deg);transform:rotate(-140deg)}to{-webkit-transform:rotate(0);transform:rotate(0)}}.pswp__ui{-webkit-font-smoothing:auto;visibility:visible;opacity:1;z-index:1550}.pswp__top-bar{position:absolute;left:0;top:0;height:44px;width:100%}.pswp--has_mouse .pswp__button--arrow--left,.pswp--has_mouse .pswp__button--arrow--right,.pswp__caption,.pswp__top-bar{-webkit-backface-visibility:hidden;will-change:opacity;-webkit-transition:opacity 333ms cubic-bezier(.4,0,.22,1);transition:opacity 333ms cubic-bezier(.4,0,.22,1)}.pswp--has_mouse .pswp__button--arrow--left,.pswp--has_mouse .pswp__button--arrow--right{visibility:visible}.pswp__caption,.pswp__top-bar{background-color:rgba(0,0,0,.5)}.pswp__ui--fit .pswp__caption,.pswp__ui--fit .pswp__top-bar{background-color:rgba(0,0,0,.3)}.pswp__ui--idle .pswp__button--arrow--left,.pswp__ui--idle .pswp__button--arrow--right,.pswp__ui--idle .pswp__top-bar{opacity:0}.pswp__ui--hidden .pswp__button--arrow--left,.pswp__ui--hidden .pswp__button--arrow--right,.pswp__ui--hidden .pswp__caption,.pswp__ui--hidden .pswp__top-bar{opacity:.001}.pswp__ui--one-slide .pswp__button--arrow--left,.pswp__ui--one-slide .pswp__button--arrow--right,.pswp__ui--one-slide .pswp__counter{display:none}.pswp__element--disabled{display:none!important}.pswp--minimal--dark .pswp__top-bar{background:none}",""])},2350:function(t,e){function n(t,e){var n=t[1]||"",i=t[3];if(!i)return n;if(e&&"function"===typeof btoa){var r=o(i),a=i.sources.map(function(t){return"/*# sourceURL="+i.sourceRoot+t+" */"});return[n].concat(a).concat([r]).join("\n")}return[n].join("\n")}function o(t){var e=btoa(unescape(encodeURIComponent(JSON.stringify(t)))),n="sourceMappingURL=data:application/json;charset=utf-8;base64,"+e;return"/*# "+n+" */"}t.exports=function(t){var e=[];return e.toString=function(){return this.map(function(e){var o=n(e,t);return e[2]?"@media "+e[2]+"{"+o+"}":o}).join("")},e.i=function(t,n){"string"===typeof t&&(t=[[null,t,""]]);for(var o={},i=0;in.parts.length&&(o.parts.length=n.parts.length)}else{var a=[];for(i=0;i-1)e[t]=n[t];else{var o=Object.getOwnPropertyDescriptor(n,t);void 0!==o.value?"function"===typeof o.value?(e.methods||(e.methods={}))[t]=o.value:(e.mixins||(e.mixins=[])).push({data:function(){var e;return e={},e[t]=o.value,e}}):(o.get||o.set)&&((e.computed||(e.computed={}))[t]={get:o.get,set:o.set})}}),(e.mixins||(e.mixins=[])).push({data:function(){return f(this,t)}});var o=t.__decorators__;o&&(o.forEach(function(t){return t(e)}),delete t.__decorators__);var s=Object.getPrototypeOf(t.prototype),l=s instanceof i?s.constructor:i,u=l.extend(e);return w(u,t,l),r&&a(u,t),u}function w(t,e,n){Object.getOwnPropertyNames(e).forEach(function(o){if("prototype"!==o){var i=Object.getOwnPropertyDescriptor(t,o);if(!i||i.configurable){var r=Object.getOwnPropertyDescriptor(e,o);if(!u){if("cid"===o)return;var a=Object.getOwnPropertyDescriptor(n,o);if(!d(r.value)&&a&&a.value===r.value)return}0,Object.defineProperty(t,o,r)}}})}function b(t){return"function"===typeof t?h(t):function(e){return h(e,t)}}b.registerHooks=function(t){m.push.apply(m,t)},e.default=b,e.createDecorator=c,e.mixins=p},"76dc":function(t,e){t.exports="data:image/gif;base64,R0lGODlhFAAUAPMIAIeHhz8/P1dXVycnJ8/Pz7e3t5+fn29vb////wAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFBwAIACwAAAAAFAAUAEAEUxDJSatFxtwaggWAdIyHJAhXoRYSQUhDPGx0TbmujahbXGWZWqdDAYEsp5NupLPkdDwE7oXwWVasimzWrAE1tKFHErQRK8eL8mMUlRBJVI307uoiACH5BAUHAAgALAEAAQASABIAAAROEMkpS6E4W5upMdUmEQT2feFIltMJYivbvhnZ3R0A4NMwIDodz+cL7nDEn5CH8DGZh8MtEMBEoxkqlXKVIgQCibbK9YLBYvLtHH5K0J0IACH5BAUHAAgALAEAAQASABIAAAROEMkpjaE4W5spANUmFQX2feFIltMJYivbvhnZ3d1x4BNBIDodz+cL7nDEn5CH8DGZAsFtMMBEoxkqlXKVIgIBibbK9YLBYvLtHH5K0J0IACH5BAUHAAgALAEAAQASABIAAAROEMkpAaA4W5vpOdUmGQb2feFIltMJYivbvhnZ3Z0g4FNRIDodz+cL7nDEn5CH8DGZgcCNQMBEoxkqlXKVIgYDibbK9YLBYvLtHH5K0J0IACH5BAUHAAgALAEAAQASABIAAAROEMkpz6E4W5upENUmAQD2feFIltMJYivbvhnZ3V0Q4JNhIDodz+cL7nDEn5CH8DGZg8GtUMBEoxkqlXKVIggEibbK9YLBYvLtHH5K0J0IACH5BAUHAAgALAEAAQASABIAAAROEMkphaA4W5tpCNUmHQf2feFIltMJYivbvhnZ3d0w4BMAIDodz+cL7nDEn5CH8DGZBMLNYMBEoxkqlXKVIgoFibbK9YLBYvLtHH5K0J0IACH5BAUHAAgALAEAAQASABIAAAROEMkpQ6A4W5vpGNUmCQL2feFIltMJYivbvhnZ3R1B4NNxIDodz+cL7nDEn5CH8DGZhcINAMBEoxkqlXKVIgwGibbK9YLBYvLtHH5K0J0IACH5BAUHAAcALAEAAQASABIAAANCeLo6wzA6FxkhbaoQ4L3ZxnXLh0EjWZ4RV71VUcCLIByyTNt2PsO8m452sBGJBsNxkUwuD03lAQBASqnUJ7aq5UYSADs="},"8bbf":function(e,n){e.exports=t},b041:function(t,e){t.exports=function(t){return"string"!==typeof t?t:(/^['"].*['"]$/.test(t)&&(t=t.slice(1,-1)),/["'() \t\n]/.test(t)?'"'+t.replace(/"/g,'\\"').replace(/\n/g,"\\n")+'"':t)}},b24f:function(t,e,n){var o,i;
14 | /*! PhotoSwipe - v4.1.3 - 2019-01-08
15 | * http://photoswipe.com
16 | * Copyright (c) 2019 Dmitry Semenov; */
17 | /*! PhotoSwipe - v4.1.3 - 2019-01-08
18 | * http://photoswipe.com
19 | * Copyright (c) 2019 Dmitry Semenov; */
20 | (function(r,a){o=a,i="function"===typeof o?o.call(e,n,e,t):o,void 0===i||(t.exports=i)})(0,function(){"use strict";var t=function(t,e,n,o){var i={features:null,bind:function(t,e,n,o){var i=(o?"remove":"add")+"EventListener";e=e.split(" ");for(var r=0;r0&&(a=parseInt(a[1],10),a>=1&&a<8&&(o.isOldIOSPhone=!0))}var s=r.match(/Android\s([0-9\.]*)/),l=s?s[1]:0;l=parseFloat(l),l>=1&&(l<4.4&&(o.isOldAndroid=!0),o.androidVersion=l),o.isMobileOpera=/opera mini|opera mobi/i.test(r)}for(var u,c,p=["transform","perspective","animationName"],d=["","webkit","Moz","ms","O"],f=0;f<4;f++){n=d[f];for(var m=0;m<3;m++)u=p[m],c=n+(n?u.charAt(0).toUpperCase()+u.slice(1):u),!o[u]&&c in e&&(o[u]=c);n&&!o.raf&&(n=n.toLowerCase(),o.raf=window[n+"RequestAnimationFrame"],o.raf&&(o.caf=window[n+"CancelAnimationFrame"]||window[n+"CancelRequestAnimationFrame"]))}if(!o.raf){var h=0;o.raf=function(t){var e=(new Date).getTime(),n=Math.max(0,16-(e-h)),o=window.setTimeout(function(){t(e+n)},n);return h=e+n,o},o.caf=function(t){clearTimeout(t)}}return o.svg=!!document.createElementNS&&!!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect,i.features=o,o}};i.detectFeatures(),i.features.oldIE&&(i.bind=function(t,e,n,o){e=e.split(" ");for(var i,r=(o?"detach":"attach")+"Event",a=function(){n.handleEvent.call(n)},s=0;se-1?t-e:t<0?e+t:t},Mt={},Tt=function(t,e){return Mt[t]||(Mt[t]=[]),Mt[t].push(e)},Ct=function(t){var e=Mt[t];if(e){var n=Array.prototype.slice.call(arguments);n.shift();for(var o=0;or.currItem.fitRatio?At||(pn(r.currItem,!1,!0),At=!0):At&&(pn(r.currItem),At=!1)),Dt(ot,mt.x,mt.y,g))},Lt=function(t){t.container&&Dt(t.container.style,t.initialPosition.x,t.initialPosition.y,t.initialZoomLevel,t)},jt=function(t,e){e[E]=y+t+"px, 0px"+_},Nt=function(t,e){if(!l.loop&&e){var n=d+(gt.x*wt-t)/gt.x,o=Math.round(t-ge.x);(n<0&&o>0||n>=$e()-1&&o<0)&&(t=ge.x+o*l.mainScrollEndFriction)}ge.x=t,jt(t,f)},Pt=function(t,e){var n=ve[t]-bt[t];return ft[t]+dt[t]+n-n*(e/v)},zt=function(t,e){t.x=e.x,t.y=e.y,e.id&&(t.id=e.id)},Rt=function(t){t.x=Math.round(t.x),t.y=Math.round(t.y)},Zt=null,Ft=function(){Zt&&(i.unbind(document,"mousemove",Ft),i.addClass(t,"pswp--has_mouse"),l.mouseUsed=!0,Ct("mouseUsed")),Zt=setTimeout(function(){Zt=null},100)},Ut=function(){i.bind(document,"keydown",r),Z.transform&&i.bind(r.scrollWrap,"click",r),l.mouseUsed||i.bind(document,"mousemove",Ft),i.bind(window,"resize scroll orientationchange",r),Ct("bindEvents")},Bt=function(){i.unbind(window,"resize scroll orientationchange",r),i.unbind(window,"scroll",b.scroll),i.unbind(document,"keydown",r),i.unbind(document,"mousemove",Ft),Z.transform&&i.unbind(r.scrollWrap,"click",r),J&&i.unbind(window,h,r),clearTimeout(F),Ct("unbindEvents")},Ht=function(t,e){var n=sn(r.currItem,ht,t);return e&&(nt=n),n},Yt=function(t){return t||(t=r.currItem),t.initialZoomLevel},Wt=function(t){return t||(t=r.currItem),t.w>0?l.maxSpreadZoom:1},Gt=function(t,e,n,o){return o===r.currItem.initialZoomLevel?(n[t]=r.currItem.initialPosition[t],!0):(n[t]=Pt(t,o),n[t]>e.min[t]?(n[t]=e.min[t],!0):n[t]1?1:t.fitRatio,n=t.container.style,o=e*t.w,i=e*t.h;n.width=o+"px",n.height=i+"px",n.left=t.initialPosition.x+"px",n.top=t.initialPosition.y+"px"},Ot=function(){if(ot){var t=ot,e=r.currItem,n=e.fitRatio>1?1:e.fitRatio,o=n*e.w,i=n*e.h;t.width=o+"px",t.height=i+"px",t.left=mt.x+"px",t.top=mt.y+"px"}}},Kt=function(t){var e="";l.escKey&&27===t.keyCode?e="close":l.arrowKeys&&(37===t.keyCode?e="prev":39===t.keyCode&&(e="next")),e&&(t.ctrlKey||t.altKey||t.shiftKey||t.metaKey||(t.preventDefault?t.preventDefault():t.returnValue=!1,r[e]()))},Qt=function(t){t&&(V||Q||it||W)&&(t.preventDefault(),t.stopPropagation())},Vt=function(){r.setScrollOffset(0,i.getScrollY())},Xt={},qt=0,$t=function(t){Xt[t]&&(Xt[t].raf&&j(Xt[t].raf),qt--,delete Xt[t])},te=function(t){Xt[t]&&$t(t),Xt[t]||(qt++,Xt[t]={})},ee=function(){for(var t in Xt)Xt.hasOwnProperty(t)&&$t(t)},ne=function(t,e,n,o,i,r,a){var s,l=St();te(t);var u=function(){if(Xt[t]){if(s=St()-l,s>=o)return $t(t),r(n),void(a&&a());r((n-e)*i(s/o)+e),Xt[t].raf=L(u)}};u()},oe={shout:Ct,listen:Tt,viewportSize:ht,options:l,isMainScrollAnimating:function(){return it},getZoomLevel:function(){return g},getCurrentIndex:function(){return d},isDragging:function(){return J},isZooming:function(){return tt},setScrollOffset:function(t,e){bt.x=t,R=bt.y=e,Ct("updateScrollOffset",bt)},applyZoomPan:function(t,e,n,o){mt.x=e,mt.y=n,g=t,Ot(o)},init:function(){if(!u&&!c){var n;r.framework=i,r.template=t,r.bg=i.getChildByClass(t,"pswp__bg"),N=t.className,u=!0,Z=i.detectFeatures(),L=Z.raf,j=Z.caf,E=Z.transform,z=Z.oldIE,r.scrollWrap=i.getChildByClass(t,"pswp__scroll-wrap"),r.container=i.getChildByClass(r.scrollWrap,"pswp__container"),f=r.container.style,r.itemHolders=I=[{el:r.container.children[0],wrap:0,index:-1},{el:r.container.children[1],wrap:0,index:-1},{el:r.container.children[2],wrap:0,index:-1}],I[0].el.style.display=I[2].el.style.display="none",Jt(),b={resize:r.updateSize,orientationchange:function(){clearTimeout(F),F=setTimeout(function(){ht.x!==r.scrollWrap.clientWidth&&r.updateSize()},500)},scroll:Vt,keydown:Kt,click:Qt};var o=Z.isOldIOSPhone||Z.isOldAndroid||Z.isMobileOpera;for(Z.animationName&&Z.transform&&!o||(l.showAnimationDuration=l.hideAnimationDuration=0),n=0;n<_t.length;n++)r["init"+_t[n]]();if(e){var a=r.ui=new e(r,i);a.init()}Ct("firstUpdate"),d=d||l.index||0,(isNaN(d)||d<0||d>=$e())&&(d=0),r.currItem=qe(d),(Z.isOldIOSPhone||Z.isOldAndroid)&&(yt=!1),t.setAttribute("aria-hidden","false"),l.modal&&(yt?t.style.position="fixed":(t.style.position="absolute",t.style.top=i.getScrollY()+"px")),void 0===R&&(Ct("initialLayout"),R=P=i.getScrollY());var p="pswp--open ";for(l.mainClass&&(p+=l.mainClass+" "),l.showHideOpacity&&(p+="pswp--animate_opacity "),p+=O?"pswp--touch":"pswp--notouch",p+=Z.animationName?" pswp--css_animation":"",p+=Z.svg?" pswp--svg":"",i.addClass(t,p),r.updateSize(),m=-1,vt=null,n=0;nnt.min.x?t=nt.min.x:tnt.min.y?e=nt.min.y:e=s&&(m+=vt+(vt>0?-s:s),n=s);for(var o=0;o0?(e=I.shift(),I[s-1]=e,m++,jt((m+2)*gt.x,e.el.style),r.setContent(e,d-n+o+1+1)):(e=I.pop(),I.unshift(e),m--,jt(m*gt.x,e.el.style),r.setContent(e,d+n-o-1-1));if(ot&&1===Math.abs(vt)){var i=qe(k);i.initialZoomLevel!==g&&(sn(i,ht),pn(i),Lt(i))}vt=0,r.updateCurrZoomItem(),k=d,Ct("afterChange")}}},updateSize:function(e){if(!yt&&l.modal){var n=i.getScrollY();if(R!==n&&(t.style.top=n+"px",R=n),!e&&xt.x===window.innerWidth&&xt.y===window.innerHeight)return;xt.x=window.innerWidth,xt.y=window.innerHeight,t.style.height=xt.y+"px"}if(ht.x=r.scrollWrap.clientWidth,ht.y=r.scrollWrap.clientHeight,Vt(),gt.x=ht.x+Math.round(ht.x*l.spacing),gt.y=ht.y,Nt(gt.x*wt),Ct("beforeResize"),void 0!==m){for(var o,a,u,c=0;c2&&(u=kt(u)),a=qe(u),a&&(A||a.needsUpdate||!a.bounds)?(r.cleanSlide(a),r.setContent(o,u),1===c&&(r.currItem=a,r.updateCurrZoomItem(!0)),a.needsUpdate=!1):-1===o.index&&u>=0&&r.setContent(o,u),a&&a.container&&(sn(a,ht),pn(a),Lt(a));A=!1}v=g=r.currItem.initialZoomLevel,nt=r.currItem.bounds,nt&&(mt.x=nt.center.x,mt.y=nt.center.y,Ot(!0)),Ct("resize")},zoomTo:function(t,e,n,o,r){e&&(v=g,ve.x=Math.abs(e.x)-mt.x,ve.y=Math.abs(e.y)-mt.y,zt(ft,mt));var a=Ht(t,!1),s={};Gt("x",a,s,t),Gt("y",a,s,t);var l=g,u={x:mt.x,y:mt.y};Rt(s);var c=function(e){1===e?(g=t,mt.x=s.x,mt.y=s.y):(g=(t-l)*e+l,mt.x=(s.x-u.x)*e+u.x,mt.y=(s.y-u.y)*e+u.y),r&&r(e),Ot(1===e)};n?ne("customZoomTo",0,1,n,o||i.easing.sine.inOut,c):c(1)}},ie=30,re=10,ae={},se={},le={},ue={},ce={},pe=[],de={},fe=[],me={},he=0,we=pt(),be=0,ge=pt(),ve=pt(),ye=pt(),_e=function(t,e){return t.x===e.x&&t.y===e.y},xe=function(t,e){return Math.abs(t.x-e.x)-1)&&(e(t)?t:Te(t.parentNode,e)))},Ce={},Se=function(t,e){return Ce.prevent=!Te(t.target,l.isClickableElement),Ct("preventDragEvent",t,e,Ce),Ce.prevent},Ee=function(t,e){return e.x=t.pageX,e.y=t.pageY,e.id=t.identifier,e},De=function(t,e,n){n.x=.5*(t.x+e.x),n.y=.5*(t.y+e.y)},Oe=function(t,e,n){if(t-B>50){var o=fe.length>2?fe.shift():{};o.x=e,o.y=n,fe.push(o),B=t}},Le=function(){var t=mt.y-r.currItem.initialPosition.y;return 1-Math.abs(t/(ht.y/2))},je={},Ne={},Pe=[],ze=function(t){while(Pe.length>0)Pe.pop();return D?(ct=0,pe.forEach(function(t){0===ct?Pe[0]=t:1===ct&&(Pe[1]=t),ct++})):t.type.indexOf("touch")>-1?t.touches&&t.touches.length>0&&(Pe[0]=Ee(t.touches[0],je),t.touches.length>1&&(Pe[1]=Ee(t.touches[1],Ne))):(je.x=t.pageX,je.y=t.pageY,je.id="",Pe[0]=je),Pe},Re=function(t,e){var n,o,i,a,s=mt[t]+e[t],u=e[t]>0,c=ge.x+e.x,p=ge.x-de.x;if(n=s>nt.min[t]||snt.min[t]&&(n=l.panEndFriction,nt.min[t]-s,o=nt.min[t]-ft[t]),(o<=0||p<0)&&$e()>1?(a=c,p<0&&c>de.x&&(a=de.x)):nt.min.x!==nt.max.x&&(i=s)):(s0)&&$e()>1?(a=c,p>0&&cr.currItem.fitRatio&&(mt[t]+=e[t]*n)},Ze=function(t){if(!("mousedown"===t.type&&t.button>0))if(Xe)t.preventDefault();else if(!G||"mousedown"!==t.type){if(Se(t,!0)&&t.preventDefault(),Ct("pointerDown"),D){var e=i.arraySearch(pe,t.pointerId,"id");e<0&&(e=pe.length),pe[e]={x:t.pageX,y:t.pageY,id:t.pointerId}}var n=ze(t),o=n.length;$=null,ee(),J&&1!==o||(J=at=!0,i.bind(window,h,r),Y=ut=st=W=q=V=K=Q=!1,rt=null,Ct("firstTouchStart",n),zt(ft,mt),dt.x=dt.y=0,zt(ue,n[0]),zt(ce,ue),de.x=gt.x*wt,fe=[{x:ue.x,y:ue.y}],B=U=St(),Ht(g,!0),Ie(),ke()),!tt&&o>1&&!it&&!q&&(v=g,Q=!1,tt=K=!0,dt.y=dt.x=0,zt(ft,mt),zt(ae,n[0]),zt(se,n[1]),De(ae,se,ye),ve.x=Math.abs(ye.x)-mt.x,ve.y=Math.abs(ye.y)-mt.y,et=Ae(ae,se))}},Fe=function(t){if(t.preventDefault(),D){var e=i.arraySearch(pe,t.pointerId,"id");if(e>-1){var n=pe[e];n.x=t.pageX,n.y=t.pageY}}if(J){var o=ze(t);if(rt||V||tt)$=o;else if(ge.x!==gt.x*wt)rt="h";else{var r=Math.abs(o[0].x-ue.x)-Math.abs(o[0].y-ue.y);Math.abs(r)>=re&&(rt=r>0?"h":"v",$=o)}}},Ue=function(){if($){var t=$.length;if(0!==t)if(zt(ae,$[0]),le.x=ae.x-ue.x,le.y=ae.y-ue.y,tt&&t>1){if(ue.x=ae.x,ue.y=ae.y,!le.x&&!le.y&&_e($[1],se))return;zt(se,$[1]),Q||(Q=!0,Ct("zoomGestureStarted"));var e=Ae(ae,se),n=Ge(e);n>r.currItem.initialZoomLevel+r.currItem.initialZoomLevel/15&&(ut=!0);var o=1,i=Yt(),a=Wt();if(n1&&(o=1),n=i-o*(i/3);else n>a&&(o=(n-a)/(6*i),o>1&&(o=1),n=a+o*i);o<0&&(o=0),e,De(ae,se,we),dt.x+=we.x-ye.x,dt.y+=we.y-ye.y,zt(ye,we),mt.x=Pt("x",n),mt.y=Pt("y",n),Y=n>g,g=n,Ot()}else{if(!rt)return;if(at&&(at=!1,Math.abs(le.x)>=re&&(le.x-=$[0].x-ce.x),Math.abs(le.y)>=re&&(le.y-=$[0].y-ce.y)),ue.x=ae.x,ue.y=ae.y,0===le.x&&0===le.y)return;if("v"===rt&&l.closeOnVerticalDrag&&!Me()){dt.y+=le.y,mt.y+=le.y;var c=Le();return W=!0,Ct("onVerticalDrag",c),Et(c),void Ot()}Oe(St(),ae.x,ae.y),V=!0,nt=r.currItem.bounds;var p=Re("x",le);p||(Re("y",le),Rt(mt),Ot())}}},Be=function(t){if(Z.isOldAndroid){if(G&&"mouseup"===t.type)return;t.type.indexOf("touch")>-1&&(clearTimeout(G),G=setTimeout(function(){G=0},600))}var e;if(Ct("pointerUp"),Se(t,!1)&&t.preventDefault(),D){var n=i.arraySearch(pe,t.pointerId,"id");if(n>-1)if(e=pe.splice(n,1)[0],navigator.msPointerEnabled){var o={4:"mouse",2:"touch",3:"pen"};e.type=o[t.pointerType],e.type||(e.type=t.pointerType||"mouse")}else e.type=t.pointerType||"mouse"}var a,s=ze(t),u=s.length;if("mouseup"===t.type&&(u=0),2===u)return $=null,!0;1===u&&zt(ce,s[0]),0!==u||rt||it||(e||("mouseup"===t.type?e={x:t.pageX,y:t.pageY,type:"mouse"}:t.changedTouches&&t.changedTouches[0]&&(e={x:t.changedTouches[0].pageX,y:t.changedTouches[0].pageY,type:"touch"})),Ct("touchRelease",t,e));var c=-1;if(0===u&&(J=!1,i.unbind(window,h,r),Ie(),tt?c=0:-1!==be&&(c=St()-be)),be=1===u?St():-1,a=-1!==c&&c<150?"zoom":"swipe",tt&&u<2&&(tt=!1,1===u&&(a="zoomPointerUp"),Ct("zoomGestureEnded")),$=null,V||Q||it||W)if(ee(),H||(H=He()),H.calculateSwipeSpeed("x"),W){var p=Le();if(pr.currItem.fitRatio&&Ye(H):Je())}},He=function(){var t,e,n={lastFlickOffset:{},lastFlickDist:{},lastFlickSpeed:{},slowDownRatio:{},slowDownRatioReverse:{},speedDecelerationRatio:{},speedDecelerationRatioAbs:{},distanceOffset:{},backAnimDestination:{},backAnimStarted:{},calculateSwipeSpeed:function(o){fe.length>1?(t=St()-B+50,e=fe[fe.length-2][o]):(t=St()-U,e=ce[o]),n.lastFlickOffset[o]=ue[o]-e,n.lastFlickDist[o]=Math.abs(n.lastFlickOffset[o]),n.lastFlickDist[o]>20?n.lastFlickSpeed[o]=n.lastFlickOffset[o]/t:n.lastFlickSpeed[o]=0,Math.abs(n.lastFlickSpeed[o])<.1&&(n.lastFlickSpeed[o]=0),n.slowDownRatio[o]=.95,n.slowDownRatioReverse[o]=1-n.slowDownRatio[o],n.speedDecelerationRatio[o]=1},calculateOverBoundsAnimOffset:function(t,e){n.backAnimStarted[t]||(mt[t]>nt.min[t]?n.backAnimDestination[t]=nt.min[t]:mt[t]ie&&(u||e.lastFlickOffset.x>20)?o=-1:s<-ie&&(u||e.lastFlickOffset.x<-20)&&(o=1)}o&&(d+=o,d<0?(d=l.loop?$e()-1:0,a=!0):d>=$e()&&(d=l.loop?0:$e()-1,a=!0),a&&!l.loop||(vt+=o,wt-=o,n=!0));var c,p=gt.x*wt,f=Math.abs(p-ge.x);return n||p>ge.x===e.lastFlickSpeed.x>0?(c=Math.abs(e.lastFlickSpeed.x)>0?f/Math.abs(e.lastFlickSpeed.x):333,c=Math.min(c,400),c=Math.max(c,250)):c=333,he===d&&(n=!1),it=!0,Ct("mainScrollAnimStart"),ne("mainScroll",ge.x,p,c,i.easing.cubic.out,Nt,function(){ee(),it=!1,he=-1,(n||he!==d)&&r.updateCurrItem(),Ct("mainScrollAnimComplete")}),n&&r.updateCurrItem(!0),n},Ge=function(t){return 1/et*t*v},Je=function(){var t=g,e=Yt(),n=Wt();gn&&(t=n);var o,a=1,s=lt;return st&&!Y&&!ut&&g1||navigator.msMaxTouchPoints>1),r.likelyTouchDevice=O,b[M]=Ze,b[T]=Fe,b[C]=Be,S&&(b[S]=b[C]),Z.touch&&(w+=" mousedown",h+=" mousemove mouseup",b.mousedown=b[M],b.mousemove=b[T],b.mouseup=b[C]),O||(l.allowPanToNext=!1)}}});var Ke,Qe,Ve,Xe,qe,$e,tn=function(e,n,o,a){var s;Ke&&clearTimeout(Ke),Xe=!0,Ve=!0,e.initialLayout?(s=e.initialLayout,e.initialLayout=null):s=l.getThumbBoundsFn&&l.getThumbBoundsFn(d);var u=o?l.hideAnimationDuration:l.showAnimationDuration,c=function(){$t("initialZoom"),o?(r.template.removeAttribute("style"),r.bg.removeAttribute("style")):(Et(1),n&&(n.style.display="block"),i.addClass(t,"pswp--animated-in"),Ct("initialZoom"+(o?"OutEnd":"InEnd"))),a&&a(),Xe=!1};if(!u||!s||void 0===s.x)return Ct("initialZoom"+(o?"Out":"In")),g=e.initialZoomLevel,zt(mt,e.initialPosition),Ot(),t.style.opacity=o?0:1,Et(1),void(u?setTimeout(function(){c()},u):c());var f=function(){var n=p,a=!r.currItem.src||r.currItem.loadError||l.showHideOpacity;e.miniImg&&(e.miniImg.style.webkitBackfaceVisibility="hidden"),o||(g=s.w/e.w,mt.x=s.x,mt.y=s.y-P,r[a?"template":"bg"].style.opacity=.001,Ot()),te("initialZoom"),o&&!n&&i.removeClass(t,"pswp--animated-in"),a&&(o?i[(n?"remove":"add")+"Class"](t,"pswp--animate_opacity"):setTimeout(function(){i.addClass(t,"pswp--animate_opacity")},30)),Ke=setTimeout(function(){if(Ct("initialZoom"+(o?"Out":"In")),o){var r=s.w/e.w,l={x:mt.x,y:mt.y},p=g,d=lt,f=function(e){1===e?(g=r,mt.x=s.x,mt.y=s.y-R):(g=(r-p)*e+p,mt.x=(s.x-l.x)*e+l.x,mt.y=(s.y-R-l.y)*e+l.y),Ot(),a?t.style.opacity=1-e:Et(d-e*d)};n?ne("initialZoom",0,1,u,i.easing.cubic.out,f,c):(f(1),Ke=setTimeout(c,u+20))}else g=e.initialZoomLevel,zt(mt,e.initialPosition),Ot(),Et(1),a?t.style.opacity=1:Et(1),Ke=setTimeout(c,u+20)},o?25:90)};f()},en={},nn=[],on={index:0,errorMsg:'',forceProgressiveLoading:!1,preload:[1,1],getNumItemsFn:function(){return Qe.length}},rn=function(){return{center:{x:0,y:0},max:{x:0,y:0},min:{x:0,y:0}}},an=function(t,e,n){var o=t.bounds;o.center.x=Math.round((en.x-e)/2),o.center.y=Math.round((en.y-n)/2)+t.vGap.top,o.max.x=e>en.x?Math.round(en.x-e):o.center.x,o.max.y=n>en.y?Math.round(en.y-n)+t.vGap.top:o.center.y,o.min.x=e>en.x?0:o.center.x,o.min.y=n>en.y?t.vGap.top:o.center.y},sn=function(t,e,n){if(t.src&&!t.loadError){var o=!n;if(o&&(t.vGap||(t.vGap={top:0,bottom:0}),Ct("parseVerticalMargin",t)),en.x=e.x,en.y=e.y-t.vGap.top-t.vGap.bottom,o){var i=en.x/t.w,r=en.y/t.h;t.fitRatio=i1&&(n=1),t.initialZoomLevel=n,t.bounds||(t.bounds=rn())}if(!n)return;return an(t,t.w*n,t.h*n),o&&n===t.initialZoomLevel&&(t.initialPosition=t.bounds.center),t.bounds}return t.w=t.h=0,t.initialZoomLevel=t.fitRatio=1,t.bounds=rn(),t.initialPosition=t.bounds.center,t.bounds},ln=function(t,e,n,o,i,a){e.loadError||o&&(e.imageAppended=!0,pn(e,o,e===r.currItem&&At),n.appendChild(o),a&&setTimeout(function(){e&&e.loaded&&e.placeholder&&(e.placeholder.style.display="none",e.placeholder=null)},500))},un=function(t){t.loading=!0,t.loaded=!1;var e=t.img=i.createEl("pswp__img","img"),n=function(){t.loading=!1,t.loaded=!0,t.loadComplete?t.loadComplete(t):t.img=null,e.onload=e.onerror=null,e=null};return e.onload=n,e.onerror=function(){t.loadError=!0,n()},e.src=t.src,e},cn=function(t,e){if(t.src&&t.loadError&&t.container)return e&&(t.container.innerHTML=""),t.container.innerHTML=l.errorMsg.replace("%url%",t.src),!0},pn=function(t,e,n){if(t.src){e||(e=t.container.lastChild);var o=n?t.w:Math.round(t.w*t.fitRatio),i=n?t.h:Math.round(t.h*t.fitRatio);t.placeholder&&!t.loaded&&(t.placeholder.style.width=o+"px",t.placeholder.style.height=i+"px"),e.style.width=o+"px",e.style.height=i+"px"}},dn=function(){if(nn.length){for(var t,e=0;e=0,i=Math.min(n[0],$e()),a=Math.min(n[1],$e());for(e=1;e<=(o?a:i);e++)r.lazyLoadItem(d+e);for(e=1;e<=(o?i:a);e++)r.lazyLoadItem(d-e)}),Tt("initialLayout",function(){r.currItem.initialLayout=l.getThumbBoundsFn&&l.getThumbBoundsFn(d)}),Tt("mainScrollAnimComplete",dn),Tt("initialZoomInEnd",dn),Tt("destroy",function(){for(var t,e=0;e=0&&(void 0!==Qe[t]&&Qe[t])},allowProgressiveImg:function(){return l.forceProgressiveLoading||!O||l.mouseUsed||screen.width>1200},setContent:function(t,e){l.loop&&(e=kt(e));var n=r.getItemAt(t.index);n&&(n.container=null);var o,a=r.getItemAt(e);if(a){Ct("gettingData",e,a),t.index=e,t.item=a;var s=a.container=i.createEl("pswp__zoom-wrap");if(!a.src&&a.html&&(a.html.tagName?s.appendChild(a.html):s.innerHTML=a.html),cn(a),sn(a,ht),!a.src||a.loadError||a.loaded)a.src&&!a.loadError&&(o=i.createEl("pswp__img","img"),o.style.opacity=1,o.src=a.src,pn(a,o),ln(e,a,s,o,!0));else{if(a.loadComplete=function(n){if(u){if(t&&t.index===e){if(cn(n,!0))return n.loadComplete=n.img=null,sn(n,ht),Lt(n),void(t.index===d&&r.updateCurrZoomItem());n.imageAppended?!Xe&&n.placeholder&&(n.placeholder.style.display="none",n.placeholder=null):Z.transform&&(it||Xe)?nn.push({item:n,baseDiv:s,img:n.img,index:e,holder:t,clearPlaceholder:!0}):ln(e,n,s,n.img,it||Xe,!0)}n.loadComplete=null,n.img=null,Ct("imageLoadComplete",e,n)}},i.features.transform){var c="pswp__img pswp__img--placeholder";c+=a.msrc?"":" pswp__img--placeholder--blank";var p=i.createEl(c,a.msrc?"img":"");a.msrc&&(p.src=a.msrc),pn(a,p),s.appendChild(p),a.placeholder=p}a.loading||un(a),r.allowProgressiveImg()&&(!Ve&&Z.transform?nn.push({item:a,baseDiv:s,img:a.img,index:e,holder:t}):ln(e,a,s,a.img,!0,!0))}Ve||e!==d?Lt(a):(ot=s.style,tn(a,o||a.img)),t.el.innerHTML="",t.el.appendChild(s)}else t.el.innerHTML=""},cleanSlide:function(t){t.img&&(t.img.onload=t.img.onerror=null),t.loaded=t.loading=t.img=t.imageAppended=!1}}});var fn,mn,hn={},wn=function(t,e,n){var o=document.createEvent("CustomEvent"),i={origEvent:t,target:t.target,releasePoint:e,pointerType:n||"touch"};o.initCustomEvent("pswpTap",!0,!0,i),t.target.dispatchEvent(o)};It("Tap",{publicMethods:{initTap:function(){Tt("firstTouchStart",r.onTapStart),Tt("touchRelease",r.onTapRelease),Tt("destroy",function(){hn={},fn=null})},onTapStart:function(t){t.length>1&&(clearTimeout(fn),fn=null)},onTapRelease:function(t,e){if(e&&!V&&!K&&!qt){var n=e;if(fn&&(clearTimeout(fn),fn=null,xe(n,hn)))return void Ct("doubleTap",n);if("mouse"===e.type)return void wn(t,e,"mouse");var o=t.target.tagName.toUpperCase();if("BUTTON"===o||i.hasClass(t.target,"pswp__single-tap"))return void wn(t,e);zt(hn,n),fn=setTimeout(function(){wn(t,e),fn=null},300)}}}}),It("DesktopZoom",{publicMethods:{initDesktopZoom:function(){z||(O?Tt("mouseUsed",function(){r.setupDesktopZoom()}):r.setupDesktopZoom(!0))},setupDesktopZoom:function(e){mn={};var n="wheel mousewheel DOMMouseScroll";Tt("bindEvents",function(){i.bind(t,n,r.handleMouseWheel)}),Tt("unbindEvents",function(){mn&&i.unbind(t,n,r.handleMouseWheel)}),r.mouseZoomedIn=!1;var o,a=function(){r.mouseZoomedIn&&(i.removeClass(t,"pswp--zoomed-in"),r.mouseZoomedIn=!1),g<1?i.addClass(t,"pswp--zoom-allowed"):i.removeClass(t,"pswp--zoom-allowed"),s()},s=function(){o&&(i.removeClass(t,"pswp--dragging"),o=!1)};Tt("resize",a),Tt("afterChange",a),Tt("pointerDown",function(){r.mouseZoomedIn&&(o=!0,i.addClass(t,"pswp--dragging"))}),Tt("pointerUp",s),e||a()},handleMouseWheel:function(t){if(g<=r.currItem.fitRatio)return l.modal&&(!l.closeOnScroll||qt||J?t.preventDefault():E&&Math.abs(t.deltaY)>2&&(p=!0,r.close())),!0;if(t.stopPropagation(),mn.x=0,"deltaX"in t)1===t.deltaMode?(mn.x=18*t.deltaX,mn.y=18*t.deltaY):(mn.x=t.deltaX,mn.y=t.deltaY);else if("wheelDelta"in t)t.wheelDeltaX&&(mn.x=-.16*t.wheelDeltaX),t.wheelDeltaY?mn.y=-.16*t.wheelDeltaY:mn.y=-.16*t.wheelDelta;else{if(!("detail"in t))return;mn.y=t.detail}Ht(g,!0);var e=mt.x-mn.x,n=mt.y-mn.y;(l.modal||e<=nt.min.x&&e>=nt.max.x&&n<=nt.min.y&&n>=nt.max.y)&&t.preventDefault(),r.panTo(e,n)},toggleDesktopZoom:function(e){e=e||{x:ht.x/2+bt.x,y:ht.y/2+bt.y};var n=l.getDoubleTapZoom(!0,r.currItem),o=g===n;r.mouseZoomedIn=!o,r.zoomTo(o?r.currItem.initialZoomLevel:n,e,333),i[(o?"remove":"add")+"Class"](t,"pswp--zoomed-in")}}});var bn,gn,vn,yn,_n,xn,An,In,kn,Mn,Tn,Cn,Sn={history:!0,galleryUID:1},En=function(){return Tn.hash.substring(1)},Dn=function(){bn&&clearTimeout(bn),vn&&clearTimeout(vn)},On=function(){var t=En(),e={};if(t.length<5)return e;var n,o=t.split("&");for(n=0;n-1&&(An=An.split("&gid=")[0],An=An.split("?gid=")[0]),Tt("afterChange",r.updateURL),Tt("unbindEvents",function(){i.unbind(window,"hashchange",r.onHashChange)});var t=function(){xn=!0,kn||(Mn?history.back():An?Tn.hash=An:Cn?history.pushState("",document.title,Tn.pathname+Tn.search):Tn.hash=""),Dn()};Tt("unbindEvents",function(){p&&t()}),Tt("destroy",function(){xn||t()}),Tt("firstUpdate",function(){d=On().pid});var e=An.indexOf("pid=");e>-1&&(An=An.substring(0,e),"&"===An.slice(-1)&&(An=An.slice(0,-1))),setTimeout(function(){u&&i.bind(window,"hashchange",r.onHashChange)},40)}},onHashChange:function(){if(En()===An)return kn=!0,void r.close();yn||(_n=!0,r.goTo(On().pid),_n=!1)},updateURL:function(){Dn(),_n||(In?bn=setTimeout(Ln,800):Ln())}}}),i.extend(r,oe)};return t})},c1e2:function(t,e,n){var o=n("e46a");"string"===typeof o&&(o=[[t.i,o,""]]),o.locals&&(t.exports=o.locals);var i=n("499e").default;i("35f03c91",o,!0,{sourceMap:!1,shadowMode:!1})},d86b:function(t,e,n){e=t.exports=n("2350")(!1),e.push([t.i,"/*! PhotoSwipe main CSS by Dmitry Semenov | photoswipe.com | MIT license */.pswp{display:none;position:absolute;width:100%;height:100%;left:0;top:0;overflow:hidden;-ms-touch-action:none;touch-action:none;z-index:1500;-webkit-text-size-adjust:100%;-webkit-backface-visibility:hidden;outline:none}.pswp *{-webkit-box-sizing:border-box;box-sizing:border-box}.pswp img{max-width:none}.pswp--animate_opacity{opacity:.001;will-change:opacity;-webkit-transition:opacity 333ms cubic-bezier(.4,0,.22,1);transition:opacity 333ms cubic-bezier(.4,0,.22,1)}.pswp--open{display:block}.pswp--zoom-allowed .pswp__img{cursor:-webkit-zoom-in;cursor:-moz-zoom-in;cursor:zoom-in}.pswp--zoomed-in .pswp__img{cursor:-webkit-grab;cursor:-moz-grab;cursor:grab}.pswp--dragging .pswp__img{cursor:-webkit-grabbing;cursor:-moz-grabbing;cursor:grabbing}.pswp__bg{background:#000;opacity:0;-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-backface-visibility:hidden}.pswp__bg,.pswp__scroll-wrap{position:absolute;left:0;top:0;width:100%;height:100%}.pswp__scroll-wrap{overflow:hidden}.pswp__container,.pswp__zoom-wrap{-ms-touch-action:none;touch-action:none;position:absolute;left:0;right:0;top:0;bottom:0}.pswp__container,.pswp__img{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.pswp__zoom-wrap{position:absolute;width:100%;-webkit-transform-origin:left top;transform-origin:left top;-webkit-transition:-webkit-transform 333ms cubic-bezier(.4,0,.22,1);transition:-webkit-transform 333ms cubic-bezier(.4,0,.22,1);transition:transform 333ms cubic-bezier(.4,0,.22,1);transition:transform 333ms cubic-bezier(.4,0,.22,1),-webkit-transform 333ms cubic-bezier(.4,0,.22,1)}.pswp__bg{will-change:opacity;-webkit-transition:opacity 333ms cubic-bezier(.4,0,.22,1);transition:opacity 333ms cubic-bezier(.4,0,.22,1)}.pswp--animated-in .pswp__bg,.pswp--animated-in .pswp__zoom-wrap{-webkit-transition:none;transition:none}.pswp__container,.pswp__zoom-wrap{-webkit-backface-visibility:hidden}.pswp__item{right:0;bottom:0;overflow:hidden}.pswp__img,.pswp__item{position:absolute;left:0;top:0}.pswp__img{width:auto;height:auto}.pswp__img--placeholder{-webkit-backface-visibility:hidden}.pswp__img--placeholder--blank{background:#222}.pswp--ie .pswp__img{width:100%!important;height:auto!important;left:0;top:0}.pswp__error-msg{position:absolute;left:0;top:50%;width:100%;text-align:center;font-size:14px;line-height:16px;margin-top:-8px;color:#ccc}.pswp__error-msg a{color:#ccc;text-decoration:underline}",""])},e46a:function(t,e,n){e=t.exports=n("2350")(!1),e.push([t.i,'.pswp__button.pswp__button--rotation{background-position:50%;background-repeat:no-repeat;background-size:auto}.pswp__button.pswp__button--rotation.pswp__button.pswp__button--rotation--left,.pswp__button.pswp__button--rotation.pswp__button.pswp__button--rotation--right{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAASBJREFUeNqk00FLAkEYxnFHuwidypQ6eOkcgVcvWtkp7CiiR+ki9AUEP0mIXf0A1SUkhEAkwnOGQaghCtJF8OD2f2UWh0Fpy4Hfws7su+8y86xyHMe3yfCvmNvGNZ4whnTooYY0lPmwsr7gDLc4wCseMEEIp4jhGTl8LCrkBVoaM7wjacybEvhEH4eL5lwqOMc3OoisKXbto4smlEy86c5TXP1S7JKGMjJy03CWY46Cx5e0cS+n8KU3sIML3Hg8wTqO/bqwjCPc/SECQ+xucSlh/o8MhSUnaoMkttH3edwwW0pvetZeiCPsMQctBMyFHQx1EhNrik90EgduEu09SKKKKF7wiBH2rH8hj679L7iCKKKOiU6pdK3hUuJrPv8jwAASlMcqHuTzOgAAAABJRU5ErkJggg==")}.pswp__button.pswp__button--rotation.pswp__button.pswp__button--rotation--right{-webkit-transform:rotateY(180deg);transform:rotateY(180deg)}.pswp__img.pswp__img--transition{-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s}',""])},f301:function(t,e){t.exports="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjY0IiBoZWlnaHQ9Ijg4IiB2aWV3Qm94PSIwIDAgMjY0IDg4IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjx0aXRsZT5kZWZhdWx0LXNraW4gMjwvdGl0bGU+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48Zz48cGF0aCBkPSJNNjcuMDAyIDU5LjV2My43NjhjLTYuMzA3Ljg0LTkuMTg0IDUuNzUtMTAuMDAyIDkuNzMyIDIuMjItMi44MyA1LjU2NC01LjA5OCAxMC4wMDItNS4wOThWNzEuNUw3MyA2NS41ODUgNjcuMDAyIDU5LjV6IiBpZD0iU2hhcGUiIGZpbGw9IiNmZmYiLz48ZyBmaWxsPSIjZmZmIj48cGF0aCBkPSJNMTMgMjl2LTVoMnYzaDN2MmgtNXpNMTMgMTVoNXYyaC0zdjNoLTJ2LTV6TTMxIDE1djVoLTJ2LTNoLTN2LTJoNXpNMzEgMjloLTV2LTJoM3YtM2gydjV6IiBpZD0iU2hhcGUiLz48L2c+PGcgZmlsbD0iI2ZmZiI+PHBhdGggZD0iTTYyIDI0djVoLTJ2LTNoLTN2LTJoNXpNNjIgMjBoLTV2LTJoM3YtM2gydjV6TTcwIDIwdi01aDJ2M2gzdjJoLTV6TTcwIDI0aDV2MmgtM3YzaC0ydi01eiIvPjwvZz48cGF0aCBkPSJNMjAuNTg2IDY2bC01LjY1Ni01LjY1NiAxLjQxNC0xLjQxNEwyMiA2NC41ODZsNS42NTYtNS42NTYgMS40MTQgMS40MTRMMjMuNDE0IDY2bDUuNjU2IDUuNjU2LTEuNDE0IDEuNDE0TDIyIDY3LjQxNGwtNS42NTYgNS42NTYtMS40MTQtMS40MTRMMjAuNTg2IDY2eiIgZmlsbD0iI2ZmZiIvPjxwYXRoIGQ9Ik0xMTEuNzg1IDY1LjAzTDExMCA2My41bDMtMy41aC0xMHYtMmgxMGwtMy0zLjUgMS43ODUtMS40NjhMMTE3IDU5bC01LjIxNSA2LjAzeiIgZmlsbD0iI2ZmZiIvPjxwYXRoIGQ9Ik0xNTIuMjE1IDY1LjAzTDE1NCA2My41bC0zLTMuNWgxMHYtMmgtMTBsMy0zLjUtMS43ODUtMS40NjhMMTQ3IDU5bDUuMjE1IDYuMDN6IiBmaWxsPSIjZmZmIi8+PGc+PHBhdGggaWQ9IlJlY3RhbmdsZS0xMSIgZmlsbD0iI2ZmZiIgZD0iTTE2MC45NTcgMjguNTQzbC0zLjI1LTMuMjUtMS40MTMgMS40MTQgMy4yNSAzLjI1eiIvPjxwYXRoIGQ9Ik0xNTIuNSAyN2MzLjAzOCAwIDUuNS0yLjQ2MiA1LjUtNS41cy0yLjQ2Mi01LjUtNS41LTUuNS01LjUgMi40NjItNS41IDUuNSAyLjQ2MiA1LjUgNS41IDUuNXoiIGlkPSJPdmFsLTEiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiLz48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMTUwIDIxaDV2MWgtNXoiLz48L2c+PGc+PHBhdGggZD0iTTExNi45NTcgMjguNTQzbC0xLjQxNCAxLjQxNC0zLjI1LTMuMjUgMS40MTQtMS40MTQgMy4yNSAzLjI1eiIgZmlsbD0iI2ZmZiIvPjxwYXRoIGQ9Ik0xMDguNSAyN2MzLjAzOCAwIDUuNS0yLjQ2MiA1LjUtNS41cy0yLjQ2Mi01LjUtNS41LTUuNS01LjUgMi40NjItNS41IDUuNSAyLjQ2MiA1LjUgNS41IDUuNXoiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiLz48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMTA2IDIxaDV2MWgtNXoiLz48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMTA5LjA0MyAxOS4wMDhsLS4wODUgNS0xLS4wMTcuMDg1LTV6Ii8+PC9nPjwvZz48L2c+PC9zdmc+"},f6fd:function(t,e){(function(t){var e="currentScript",n=t.getElementsByTagName("script");e in t||Object.defineProperty(t,e,{get:function(){try{throw new Error}catch(o){var t,e=(/.*at [^\(]*\((.*):.+:.+\)$/gi.exec(o.stack)||[!1])[1];for(t in n)if(n[t].src==e||"interactive"==n[t].readyState)return n[t];return null}}})})(document)},fa4e:function(t,e,n){e=t.exports=n("2350")(!1),e.i(n("d86b"),""),e.i(n("1de3"),""),e.push([t.i,".pswipe-gallery [data-pswp-src]{cursor:pointer;cursor:-webkit-zoom-in;cursor:zoom-in}",""])},fb15:function(t,e,n){"use strict";var o;(n.r(e),"undefined"!==typeof window)&&(n("f6fd"),(o=window.document.currentScript)&&(o=o.src.match(/(.+\/)[^\/]+\.js(\?.*)?$/))&&(n.p=o[1]));var i=n("b24f"),r=n.n(i),a=n("14fd"),s=n.n(a),l=n("8bbf"),u=n.n(l),c=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"pswp",attrs:{tabindex:"-1",role:"dialog","aria-hidden":"true"}},[n("div",{staticClass:"pswp__bg"}),n("div",{staticClass:"pswp__scroll-wrap"},[t._m(0),n("div",{staticClass:"pswp__ui pswp__ui--hidden"},[n("div",{staticClass:"pswp__top-bar"},[n("div",{staticClass:"pswp__counter"}),n("button",{staticClass:"pswp__button pswp__button--close",attrs:{title:"Close (Esc)"}}),n("button",{staticClass:"pswp__button pswp__button--share",attrs:{title:"Share"}}),n("button",{staticClass:"pswp__button pswp__button--fs",attrs:{title:"Toggle fullscreen"}}),t.rotate?[n("button",{staticClass:"pswp__button pswp__button--rotation pswp__button--rotation--right",attrs:{title:"Rotate Right"},on:{pswpTap:function(e){return t.handleRotate("right")}}}),n("button",{staticClass:"pswp__button pswp__button--rotation pswp__button--rotation--left",attrs:{title:"Rotate Left"},on:{pswpTap:function(e){return t.handleRotate("left")}}})]:t._e(),n("button",{staticClass:"pswp__button pswp__button--zoom",attrs:{title:"Zoom in/out"}}),t._m(1)],2),t._m(2),n("button",{staticClass:"pswp__button pswp__button--arrow--left",attrs:{title:"Previous (arrow left)"}}),n("button",{staticClass:"pswp__button pswp__button--arrow--right",attrs:{title:"Next (arrow right)"}}),t._m(3)])])])},p=[function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"pswp__container"},[n("div",{staticClass:"pswp__item"}),n("div",{staticClass:"pswp__item"}),n("div",{staticClass:"pswp__item"})])},function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"pswp__preloader"},[n("div",{staticClass:"pswp__preloader__icn"},[n("div",{staticClass:"pswp__preloader__cut"},[n("div",{staticClass:"pswp__preloader__donut"})])])])},function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"pswp__share-modal pswp__share-modal--hidden pswp__single-tap"},[n("div",{staticClass:"pswp__share-tooltip"})])},function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"pswp__caption"},[n("div",{staticClass:"pswp__caption__center"})])}];function d(t,e,n,o){var i,r=arguments.length,a=r<3?e:null===o?o=Object.getOwnPropertyDescriptor(e,n):o;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)a=Reflect.decorate(t,e,n,o);else for(var s=t.length-1;s>=0;s--)(i=t[s])&&(a=(r<3?i(a):r>3?i(e,n,a):i(e,n))||a);return r>3&&a&&Object.defineProperty(e,n,a),a}var f=n("65d9"),m=n.n(f);function h(t){return void 0===t&&(t={}),Object(f["createDecorator"])(function(e,n){(e.props||(e.props={}))[n]=t})}function w(t){return w="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"===typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},w(t)}function b(t,e){return y(t)||v(t,e)||g()}function g(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}function v(t,e){var n=[],o=!0,i=!1,r=void 0;try{for(var a,s=t[Symbol.iterator]();!(o=(a=s.next()).done);o=!0)if(n.push(a.value),e&&n.length===e)break}catch(l){i=!0,r=l}finally{try{o||null==s["return"]||s["return"]()}finally{if(i)throw r}}return n}function y(t){if(Array.isArray(t))return t}function _(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function x(t,e){for(var n=0;n0||o.height>0)return e({w:o.width,h:o.height});n=window.setTimeout(t,40)};i()})},at=function(t,e){var n=-1;return t.some(function(t,o){var i=e(t,o);return i&&(n=o),i}),n},st=function(){var t=window.location.hash.substring(1),e={};return t.length<5?e:(t.split("&").reduce(function(t,e){if(!e)return t;var n=e.split("=");if(n.length<2)return t;var o=H(n,2),i=o[0],r=o[1];return t[i]=r,t},e),e)},lt=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:document;return Z(e.querySelectorAll(t))},ut=function t(e,n){return!!e&&et(e)&&(n(e)?e:t(e.parentNode,n))},ct=function(t){var e;return function(){for(var n=arguments.length,o=new Array(n),i=0;i1?n-1:0),i=1;i1&&void 0!==arguments[1]?arguments[1]:t;return"scale(".concat(t,", ").concat(e,")")},jt=function(t,e,n){var o=e.naturalWidth,i=e.naturalHeight,r=St(t.w,t.h,o,i),a=r.w,s=r.h,l=St(t.w,t.h,i,o),u=l.w,c=l.h,p=n?Lt(c/a):Lt(a/u,s/c),d=Lt(c/u,u/c);return[p,d]},Nt=function(){var t={},e=document.createElement("div"),n=e.style;return function(e){var o=t[e];if(o)return o;var i=e;return $(n[e])||["Moz","ms","O","Webkit"].some(function(t){var o=t+wt(e);if($(n[o]))return i=o}),t[e]=i,i}}(),Pt=function(){var t={transition:"transitionend",OTransition:"oTransitionEnd",MozTransition:"transitionend",WebkitTransition:"webkitTransitionEnd"},e=Nt("transition");return t[e]}(),zt=function(){var t=u.a.directive("pswp");t||u.a.directive("pswp",{bind:function(t,e){var n=e.value;vt(t,n)},update:function(t,e){var n=e.value,o=e.oldValue;n!==o&&vt(t,n)}})},Rt=["beforeOpen","opened"],Zt=K(),Ft={history:!1,zoomEl:!Zt,shareEl:!Zt,shareButtons:[{id:"download",label:"Download image",url:"{{raw_image_url}}",download:!0}]};(function(t){var e=Ft;t.get=function(){return e},t.extend=function(){for(var t=arguments.length,n=new Array(t),o=0;o0&&void 0!==arguments[0]?arguments[0]:this.getThumbEls();return e.map(function(e){var n=e.dataset,o=mt(e,t.auto)||"",i=n.pswpMsrc||o,r=(n.pswpSize||"").split("x"),a={msrc:i,src:o,el:e,w:Number(r[0]||0),h:Number(r[1]||0)},s=n.pswpTitle,l=n.pswpPid;return s&&(a.title=s),l&&(a.pid=l),a})}},{key:"onThumbClick",value:function(t){var e=!this.auto&&this.bubble&&ut(t.target,function(t){return!!t.dataset.pswpSrc})||t.target;if(ht(e,this.auto,this.filter)){var n=this.getThumbEls(),o=at(n,function(t){return t===e});-1!==o&&this.openPhotoSwipe({index:o,thumbEls:n})}}},{key:"getThumbBoundsFn",value:function(t){return function(e){var n=t[e].el,o=window.pageYOffset||document.documentElement.scrollTop,i=n.getBoundingClientRect();return{x:i.left,y:i.top+o,w:i.width}}}},{key:"parseIndex",value:function(t,e,n,o){return o?n.galleryPIDs?at(e,function(e){return e.pid===t}):+t-1:+t}},{key:"openPhotoSwipe",value:function(t){var e=this,n=t.index,o=t.fromURL,i=t.thumbEls,r=this.parseThumbEls(i),a=Wt({galleryUID:+(this.gallery.dataset.pswpUid||""),getThumbBoundsFn:this.getThumbBoundsFn(r)},Et.get(),{},this.options),s=this.parseIndex(n,r,a,o);if(s>=0&&(a.index=s),!Q(a.index)||Number.isNaN(a.index))return ot("PhotoSwipe cannot be opened because the index is invalid. If you use a custom pid, set options.galleryPIDs to true.");o&&(a.showAnimationDuration=0),a.showHideOpacity||(a.showHideOpacity=nt(r[s].el));var l=function(){e.pswp=Tt({items:r,options:a,context:e}),e.$emit("opened",e.pswp),kt.emit("opened",e.$props)};if(this.$listeners.beforeOpen){var u={index:s,items:r,options:a,target:r[s].el},c=function(){var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];t&&l()};this.$emit("beforeOpen",u,c)}else l()}},{key:"initPhotoSwipeFromDOM",value:function(t){var e=this,n=lt(t),o=at(n,function(t){return t===e.gallery}),i=o+1;this.gallery.dataset.pswpUid="".concat(i);var r=st(),a=r.pid,s=r.gid;a&&s&&+s===i&&setTimeout(function(){e.openPhotoSwipe({index:a,fromURL:!0})})}},{key:"openPswp",value:function(){this.initPhotoSwipeFromDOM(".pswipe-gallery")}},{key:"setImageSizeSeparately",value:function(t){return rt(mt(t,this.auto)).then(function(e){return ft(t,e)})}},{key:"setImageSize",value:function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.getThumbEls();return Promise.all(e.filter(function(t){return!t.dataset.pswpSize}).map(function(e){return t.setImageSizeSeparately(e)}))}},{key:"created",value:function(){it.mount()}},{key:"mounted",value:function(){it.append(),this.gallery=this.$refs.gallery,this.lazy||this.setImageSize(),this.openPswp()}}]),e}(u.a);d([h(Object)],ee.prototype,"options",void 0),d([h({type:Boolean,default:!1})],ee.prototype,"auto",void 0),d([h({type:Boolean,default:!1})],ee.prototype,"bubble",void 0),d([h({type:Boolean,default:!0})],ee.prototype,"lazy",void 0),d([h({type:Function,default:function(){return!0}})],ee.prototype,"filter",void 0),d([h({type:Boolean,default:!1})],ee.prototype,"rotate",void 0),ee=d([m()({name:"Photoswipe"})],ee);var ne=ee,oe=ne,ie=(n("3dfa"),L(oe,Ut,Bt,!1,null,null,null)),re=ie.exports,ae=function(t,e){e&&Et.extend(e),zt(),t.component("Photoswipe",re),t.prototype.$Pswp={open:function(t){return it.append(),Ct(t)}}},se=re,le=ae;n.d(e,"Photoswipe",function(){return se});e["default"]=le}})});
21 | //# sourceMappingURL=Photoswipe.umd.min.js.map
--------------------------------------------------------------------------------