Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf97ae0536 | ||
|
|
4895bc03b4 | ||
|
|
86153752e6 | ||
|
|
63d5fa23b6 | ||
|
|
1869895b0a | ||
|
|
48a8e33ec3 | ||
|
|
2dbfc6bc5b | ||
|
|
017bf0a2c8 | ||
|
|
c44f2d6324 | ||
|
|
f3d0b8a553 | ||
|
|
4b4a261787 | ||
|
|
fb529f8315 | ||
|
|
93fca83122 | ||
|
|
7fd6e5fd72 | ||
|
|
b29c3b36ec | ||
|
|
b6d11b2b3a |
@@ -474,7 +474,7 @@ start there when looking for prior art. The sites below are exemplars, cited by
|
||||
data-view cell editors an explicit top-level transient parent.
|
||||
`DropDown::ShouldDismissOnTopWindowDeactivate` handles Wayland chains.
|
||||
- `CheckBox::CheckBox`, `SwitchButton`, `RadioBox`, `ScalableButton` (`wxExtensions.cpp`),
|
||||
`ObjColorDialog`, `PresetComboBoxes` call `RemoveButtonBorder`; `TextInput` and `SpinInput` call
|
||||
`PresetComboBoxes` call `RemoveButtonBorder`; `TextInput` and `SpinInput` call
|
||||
`RemoveInputBorder` on their inner `wxTextCtrl`.
|
||||
- `Plater::priv::priv` together with `sanitize_window_layout_for_wayland`: AUI floating is disabled on
|
||||
Wayland.
|
||||
@@ -812,7 +812,7 @@ widgets do it in their constructors.
|
||||
(`"*.GtkBitmapToggleButton"`, class `"GtkEntry"`). The first call changes every matching widget in
|
||||
the process, not just the one passed in.
|
||||
|
||||
**Callers:** `CheckBox::CheckBox`, `SwitchButton`, `RadioBox`, `ScalableButton`, `ObjColorDialog` and
|
||||
**Callers:** `CheckBox::CheckBox`, `SwitchButton`, `RadioBox`, `ScalableButton` and
|
||||
`PresetComboBoxes` (`RemoveButtonBorder`); the inner `wxTextCtrl` of `TextInput` and `SpinInput`
|
||||
(`RemoveInputBorder`). A new owner-drawn control built on a native GTK widget needs the same call.
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ jobs:
|
||||
if: ${{ !cancelled() && (github.event_name != 'schedule' || github.repository == 'OrcaSlicer/OrcaSlicer') }}
|
||||
uses: ./.github/workflows/build_check_cache.yml
|
||||
with:
|
||||
os: ${{ vars.SELF_HOSTED && 'orca-macos-arm64' || 'macos-14' }}
|
||||
os: ${{ vars.SELF_HOSTED && 'orca-macos-arm64' || 'macos-15' }}
|
||||
arch: ${{ matrix.arch }}
|
||||
build-deps-only: ${{ inputs.build-deps-only || false }}
|
||||
force-build: ${{ github.event_name == 'schedule' }}
|
||||
@@ -138,7 +138,7 @@ jobs:
|
||||
if: ${{ !cancelled() && needs.build_macos_arch.result == 'success' && !inputs.build-deps-only && (github.event_name != 'schedule' || github.repository == 'OrcaSlicer/OrcaSlicer') }}
|
||||
uses: ./.github/workflows/build_orca.yml
|
||||
with:
|
||||
os: ${{ vars.SELF_HOSTED && 'orca-macos-arm64' || 'macos-14' }}
|
||||
os: ${{ vars.SELF_HOSTED && 'orca-macos-arm64' || 'macos-15' }}
|
||||
arch: universal
|
||||
macos-combine-only: true
|
||||
secrets: inherit
|
||||
@@ -182,7 +182,7 @@ jobs:
|
||||
if: ${{ !cancelled() && success() }}
|
||||
uses: ./.github/workflows/unit_tests.yml
|
||||
with:
|
||||
os: ${{ vars.SELF_HOSTED && 'orca-macos-arm64' || 'macos-14' }}
|
||||
os: ${{ vars.SELF_HOSTED && 'orca-macos-arm64' || 'macos-15' }}
|
||||
artifact: ${{ github.sha }}-tests-macos-arm64
|
||||
test-dir: build/arm64/tests
|
||||
# Slice a two-colour cube through every shipped printer, and through every
|
||||
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
# Anything that changes how the tree is built belongs in the key, or a job
|
||||
# restores one it cannot use. Linux amd64 passes no arch deliberately, so
|
||||
# 'linux-clang' keeps the cache it already has.
|
||||
cache-os: ${{ runner.os == 'macOS' && format('macos-{0}', inputs.arch) || (runner.os == 'Windows' && format('windows-{0}-{1}', inputs.arch, inputs.compiler) || format('linux-clang{0}', inputs.arch && format('-{0}', inputs.arch) || '')) }}
|
||||
cache-os: ${{ runner.os == 'macOS' && format('{0}-{1}', inputs.os, inputs.arch) || (runner.os == 'Windows' && format('windows-{0}-{1}', inputs.arch, inputs.compiler) || format('linux-clang{0}', inputs.arch && format('-{0}', inputs.arch) || '')) }}
|
||||
# The Windows ARM64 deps build in build-arm64, all others under build;
|
||||
# build_deps.yml and build_orca.yml pass the Windows directory to build_win.bat.
|
||||
dep-folder-name: ${{ runner.os == 'macOS' && format('/{0}', inputs.arch) || (runner.os == 'Windows' && inputs.arch == 'arm64') && '-arm64/OrcaSlicer_dep' || '/OrcaSlicer_dep' }}
|
||||
|
||||
@@ -183,10 +183,12 @@ jobs:
|
||||
- name: Free disk space
|
||||
if: runner.os == 'macOS' && !inputs.macos-combine-only && !vars.SELF_HOSTED
|
||||
run: |
|
||||
df -hI /dev/disk3s1s1
|
||||
sudo find /Applications -maxdepth 1 -type d -name "Xcode_*.app" ! -name "Xcode_15.4.app" -exec rm -rf {} +
|
||||
df -hI /
|
||||
# Keep only the selected Xcode
|
||||
xcode=$(basename "$(cd "$(xcode-select -p)/../.." && pwd -P)")
|
||||
sudo find /Applications -maxdepth 1 -type d -name "Xcode_*.app" ! -name "$xcode" -exec rm -rf {} +
|
||||
sudo rm -rf ~/Library/Developer/CoreSimulator/Caches/*
|
||||
df -hI /dev/disk3s1s1
|
||||
df -hI /
|
||||
|
||||
- name: Build slicer mac
|
||||
if: runner.os == 'macOS' && !inputs.macos-combine-only
|
||||
|
||||
@@ -75,6 +75,19 @@ static FILE *stl_open_count_facets(stl_file *stl, const char *file, unsigned int
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Zero normals and coordinates like 10 or 15 have no byte above 127, so the test above can miss a binary file.
|
||||
// Its size still matches its facet count; text read as that count would need a file of gigabytes.
|
||||
if (stl->stats.type == ascii) {
|
||||
uint32_t header_num_facets;
|
||||
fseek(fp, custom_header_length, SEEK_SET);
|
||||
if (fread(&header_num_facets, sizeof(uint32_t), 1, fp) == 1) {
|
||||
#if BOOST_ENDIAN_BIG_BYTE
|
||||
stl_internal_reverse_quads((char*)&header_num_facets, 4);
|
||||
#endif /* BOOST_ENDIAN_BIG_BYTE */
|
||||
if (header_size + uint64_t(header_num_facets) * SIZEOF_STL_FACET == file_size)
|
||||
stl->stats.type = binary;
|
||||
}
|
||||
}
|
||||
rewind(fp);
|
||||
|
||||
uint32_t num_facets = 0;
|
||||
|
||||
@@ -62,23 +62,6 @@ Clipper2 behaves differently by default, the wrapper adjusts it.
|
||||
clip do not leave slivers.
|
||||
- Open polylines are clipped with the non-zero rule and keep their direction.
|
||||
|
||||
### Tiled booleans
|
||||
|
||||
The sweep slows down with the number of edges crossing a scan line, so a layer
|
||||
cut into thousands of pieces makes every whole-layer boolean expensive.
|
||||
`diff_ex_by_piece()` and `intersection_ex_by_piece()` take a subject of
|
||||
non-overlapping `ExPolygons`, group them into tiles with
|
||||
`ClipperUtils::tile_expolygons()`, and run each tile in parallel against only
|
||||
the clip polygons near it, cut to the tile's box. Below 128 pieces there is a
|
||||
single tile, and they are the plain `diff_ex()` / `intersection_ex()`.
|
||||
|
||||
The result covers the same area as the plain call. Without the safety offset
|
||||
the rings are the same. With it, each tile unites only the clip polygons near
|
||||
it, so a clip edge that the whole-layer union splits where it crosses a distant
|
||||
clip polygon stays whole, and a crossing with the subject can round 1 unit
|
||||
differently. The tiles' results are concatenated in tile order, so the order of
|
||||
the output `ExPolygons` differs from the plain call.
|
||||
|
||||
### Offsets
|
||||
|
||||
- Before offsetting, input vertices closer than
|
||||
|
||||
@@ -2,238 +2,584 @@
|
||||
|
||||
## Purpose and scope
|
||||
|
||||
Precise Seam places the seam where a helper volume intersects the external
|
||||
wall. The user attaches a mesh to an object as a Precise Seam modifier, and on
|
||||
every layer the seam placer reads the modifier's slice to decide where the seam
|
||||
of each external perimeter may, must or must not go. The same mesh keeps
|
||||
working after the model changes, so the seam does not have to be repainted
|
||||
after every design revision, and a swept helper body can guide the seam along
|
||||
any path.
|
||||
Precise Seam lets a helper volume decide where the seam of an object goes. The
|
||||
user attaches a mesh to an object as a Precise Seam modifier. On every layer,
|
||||
the part of the external perimeter that lies inside the modifier's slice
|
||||
determines where the seam must, may or must not be placed. The helper is a
|
||||
persistent model object rather than paint on the surface, so it keeps working
|
||||
when the design changes. A body swept along a path on the surface can guide the
|
||||
seam along any trajectory.
|
||||
|
||||
The modifier is non-printing geometry. It does not take part in slicing, region
|
||||
assignment, filament selection or brim adhesion. It affects only seam
|
||||
placement, which runs during G-code export.
|
||||
The modifier is non-printing geometry. It takes no part in object slicing,
|
||||
region assignment, filament selection or brim adhesion, and it affects only seam
|
||||
placement during G-code export. Objects without Precise Seam volumes follow the
|
||||
regular seam placement unchanged.
|
||||
|
||||
## Volume types and priority
|
||||
Precise Seam does not replace the seam placer. It feeds it: a modifier inserts
|
||||
the points it needs into the perimeter and changes the enforced/blocked type of
|
||||
seam candidates, the same typing mechanism as seam painting, and the configured
|
||||
seam position then chooses among them.
|
||||
|
||||
Precise Seam adds six `ModelVolumeType` values after `SUPPORT_ENFORCER`. The
|
||||
strong types come first and the weak types follow. `is_precise_seam()`,
|
||||
## Modifier types
|
||||
|
||||
Precise Seam adds six `ModelVolumeType` values after `SUPPORT_ENFORCER`, strong
|
||||
types first and weak types after them. `is_precise_seam()`,
|
||||
`is_precise_seam_strong()` and `is_precise_seam_weak()` are range checks that
|
||||
depend on this order.
|
||||
|
||||
| Type | Group | Effect on the perimeter |
|
||||
| Type | Group | Effect on an intersected perimeter |
|
||||
| --- | --- | --- |
|
||||
| `PRECISE_SEAM_CENTER` | strong | seam at the arc-length midpoint of the intersection |
|
||||
| `PRECISE_SEAM_CENTER` | strong | seam at the midpoint, by arc length, of the intersection |
|
||||
| `PRECISE_SEAM_LEFT` | strong | seam at the first point of the intersection |
|
||||
| `PRECISE_SEAM_RIGHT` | strong | seam at the last point of the intersection |
|
||||
| `PRECISE_SEAM_ENFORCED` | weak | intersection marked as enforced |
|
||||
| `PRECISE_SEAM_BLOCKED` | weak | intersection marked as blocked |
|
||||
| `PRECISE_SEAM_NEUTRAL` | weak | intersection reset to neutral |
|
||||
|
||||
A strong modifier fixes one point. A weak modifier only changes the
|
||||
enforced/blocked type of seam candidates, and the configured seam position then
|
||||
chooses among them. First and last are taken along the perimeter made
|
||||
counter-clockwise seen from above. On an outer wall seen from outside, Left is
|
||||
the left end of the intersection. On the wall of a hole seen from inside the
|
||||
hole, the two ends are swapped.
|
||||
A strong modifier fixes a single point. The perimeter gets exactly one enforced
|
||||
seam candidate there, and every other candidate is blocked. A weak modifier
|
||||
retypes, and where needed adds, the candidates inside its intersection, like
|
||||
painting does.
|
||||
|
||||
An **intersection** is a continuous part of the external perimeter's centerline
|
||||
that lies inside the modifier's slice on that layer. It is a portion of the
|
||||
perimeter, never a chord through the object. The centerline lies half an
|
||||
extrusion width inside the model surface and depends on print settings, so a
|
||||
modifier must reach clearly past the surface to cross it unambiguously.
|
||||
|
||||
### Terms
|
||||
|
||||
- **Segment:** an intersection as the code represents it (`PerimeterSegment`).
|
||||
User-facing texts call it an intersection.
|
||||
- **Fragment:** a piece of the perimeter returned by clipping, before it is tied
|
||||
to the source contour.
|
||||
- **Interval:** the bound part of one source edge, given by the edge index and a
|
||||
parameter range on that edge.
|
||||
- **Zone:** a weak segment with its type (Enforced, Blocked or Neutral).
|
||||
- **Boundary:** an end of a zone, inserted into the perimeter polygon.
|
||||
- **Candidate:** a seam candidate of the seam placer, built from the points of
|
||||
the processed perimeter polygon (painted enforcers may add more).
|
||||
|
||||
First and last are taken along the perimeter oriented counter-clockwise as seen
|
||||
from above. On an outer wall seen from outside, Left is therefore the left end
|
||||
of the intersection. On the wall of a hole seen from inside the hole, the two
|
||||
ends are swapped. Mirroring an object does not mirror the mode: perimeters stay
|
||||
counter-clockwise, so Left remains the left end seen from outside, and the seam
|
||||
moves to the other end of the modifier instead of following the mirrored model.
|
||||
|
||||
## Priority
|
||||
|
||||
The order of volumes in the object is the priority order, highest first.
|
||||
`ModelObject::sort_volumes()` keeps every strong modifier before every weak one
|
||||
and preserves the user's order within each group. The object list lets the user
|
||||
drag a modifier only within its own group. A type change that crosses a group
|
||||
boundary moves the volume to the end of its new group, where it has the lowest
|
||||
priority. Strong modifiers are tried in this order, and the first one that
|
||||
yields a seam on a perimeter wins. Weak modifiers are applied from the lowest
|
||||
priority to the highest, so the highest one overwrites any overlapping zone.
|
||||
drag a modifier only within its own group. A type change that crosses the group
|
||||
boundary moves the volume to the end of its new group, with the lowest priority
|
||||
there.
|
||||
|
||||
## Model storage and 3MF compatibility
|
||||
- **Strong:** modifiers are tried in priority order on each perimeter. The first
|
||||
one that yields a usable segment decides the seam. Within that modifier the
|
||||
longest segment wins; lengths are never compared across modifiers. Once a
|
||||
strong point is placed, no later strong modifier and no weak modifier is
|
||||
processed for that perimeter.
|
||||
- **Weak:** every weak modifier applies. They are applied from the lowest
|
||||
priority to the highest, so the highest one overwrites overlapping zones. A
|
||||
Blocked modifier that fully contains a perimeter is the exception: it is
|
||||
skipped there (see [Full containment](#full-containment)).
|
||||
|
||||
Projects must stay readable by earlier releases, and the modifier must not
|
||||
change a print there. Both 3MF writers therefore store a Precise Seam volume as
|
||||
an ordinary parameter modifier: `modifier_part` in the Bambu-format part
|
||||
subtype, and `ParameterModifier` together with the legacy `modifier` flag in
|
||||
the Prusa-format volume metadata. The seam mode is written separately under
|
||||
A strong modifier without a usable segment, even one whose fragments were all
|
||||
discarded, passes the turn to the next one.
|
||||
|
||||
## Data flow
|
||||
|
||||
1. **Invalidation.** `Print::apply()` treats a change of Precise Seam volumes as
|
||||
a change of seam placement and invalidates G-code export; the object is not
|
||||
resliced (see [Print invalidation](#print-invalidation)).
|
||||
2. **Modifier slices.** `SeamPlacer::init()` collects each object's Precise Seam
|
||||
volumes once, slices every volume separately and caches its regions with
|
||||
their bounding boxes.
|
||||
3. **Perimeters.** Seam candidates are gathered in parallel over the layers.
|
||||
For objects with Precise Seam volumes, each external perimeter polygon is
|
||||
normalized and prepared once for all modifiers.
|
||||
4. **Extraction.** For each modifier, the perimeter is clipped against the
|
||||
modifier's regions on that layer. The clipped fragments are bound back to the
|
||||
source edges of the perimeter and assembled into segments.
|
||||
5. **Strong, then weak.** Strong modifiers try to insert one seam point into the
|
||||
perimeter polygon. If none succeeds, weak modifiers insert their zone
|
||||
boundaries and subdivide enforced edges.
|
||||
6. **Candidates.** The seam placer builds candidates from the modified polygon.
|
||||
Painting assigns types first, weak zones overwrite them, and a strong point
|
||||
makes its candidate the only enforced one.
|
||||
7. **Selection and restoration.** The configured seam position chooses the
|
||||
seams and aligns them. Afterwards the exact strong points are restored.
|
||||
8. **Warnings.** After all objects are processed, `SeamPlacer::init()` prepares
|
||||
one combined warning text if any problem was found; G-code export issues it.
|
||||
|
||||
## Modifier slices
|
||||
|
||||
`init_precise_seam_data()` collects the Precise Seam volumes of each object:
|
||||
strong ones in priority order and weak ones in reverse, so that weak zones can
|
||||
be applied with last-write-wins. Each volume is sliced separately with
|
||||
`PrintObject::slice_single_volume_regions()`, at the object's layer heights and
|
||||
with the same centered transformation as the object. The slices keep every
|
||||
region's outer contour together with its holes as an `ExPolygon`. Volumes are
|
||||
not merged, so each keeps its own priority, and a modifier may have several
|
||||
regions on one layer.
|
||||
|
||||
`prepare_modifier_slices()` moves the slices into `ModifierRegionsCache`,
|
||||
pairing each region with the bounding box of its exterior. Empty layers keep
|
||||
their slots, so the cache is indexed by object layer; `Layer::id()` includes raft
|
||||
layers, which are subtracted. The cache is filled before candidates are gathered
|
||||
and is only read afterwards, shared by both modifier kinds and all worker
|
||||
threads without locking.
|
||||
|
||||
## Perimeter preparation
|
||||
|
||||
The seam placer works on external perimeter loops, including the walls of
|
||||
holes. For objects with Precise Seam volumes, consecutive duplicate points and
|
||||
the repeated closing point of each extrusion loop are removed: adjacent
|
||||
extrusion paths share endpoints, and the resulting zero-length edges would
|
||||
prevent point insertion at their junctions. Distinct visits to one point of a
|
||||
self-touching contour are kept. Objects without Precise Seam volumes keep their
|
||||
original points, so ordinary seam candidates are unaffected.
|
||||
|
||||
Each polygon is made counter-clockwise. A single `PreparedPerimeter` is then
|
||||
built for all modifiers of that perimeter. It holds a validity check (at least
|
||||
three points, no consecutive or closing duplicates), the bounding box, and the
|
||||
clipping line: the polygon as an open polyline with its first point repeated at
|
||||
the end. The preparation borrows the polygon and is used only while the polygon
|
||||
is unchanged: strong processing returns immediately after inserting its point,
|
||||
and weak processing collects all segments before it inserts anything. An
|
||||
invalid perimeter receives no Precise Seam processing.
|
||||
|
||||
## Segment extraction
|
||||
|
||||
`extract_perimeter_segments()` turns one modifier's regions on one layer into
|
||||
segments of the perimeter, each with its geometry and its position on the
|
||||
source contour. Both modifier kinds consume these segments; the extractor is
|
||||
told the modifier type so that it prepares only the data that type needs.
|
||||
|
||||
### Clipping
|
||||
|
||||
Regions whose bounding box does not overlap the perimeter's are skipped. The
|
||||
clipping line is intersected with each remaining region by `intersection_pl()`,
|
||||
which clips an open path against an `ExPolygon` with its holes attached, using
|
||||
the nonzero rule. Clipping an open line yields only pieces of the perimeter, so
|
||||
a modifier crossing the whole object produces two separate pieces rather than a
|
||||
chord through the body. Holes in a modifier and several regions of one modifier
|
||||
simply produce more pieces. The line is cut at vertex zero, so a piece crossing
|
||||
that vertex arrives as two fragments. A border that only touches the line can
|
||||
come back as a single point; such fragments carry no coverage and are dropped
|
||||
before binding.
|
||||
|
||||
### Binding fragments to source edges
|
||||
|
||||
Clipper returns coordinates only. Insertion needs the source edge of every
|
||||
point, and coordinates alone are ambiguous where a contour visits the same
|
||||
point twice. Each fragment is therefore bound to the source edges it covers,
|
||||
producing intervals: an edge index with a parameter range on that edge.
|
||||
|
||||
- **Exact path.** For fragments with interior points, the second point is used
|
||||
as an anchor that must equal a source vertex exactly. Clipping keeps the
|
||||
vertices of an open path unchanged, including collinear ones. The following
|
||||
points must match successive source vertices in either direction; later
|
||||
occurrences of the anchor are tried if a sequence does not match. Only the two
|
||||
end cuts are projected onto their edges.
|
||||
- **Projection path.** Two-point fragments, and fragments the exact path cannot
|
||||
match, are bound by projection. The first source edge that holds both points
|
||||
of the first pair, with distinct parameters, establishes the edge and
|
||||
direction. Every following pair must continue on the same edge or cross to the
|
||||
neighboring edge at their actual shared vertex, in the same direction. A pair
|
||||
continuing on the same edge reuses the previous pair's parameter for their
|
||||
shared point, so the two projections of one point cannot differ.
|
||||
- **Failure.** A fragment that cannot be bound continuously is rolled back and
|
||||
discarded. Earlier fragments and other fragments are unaffected. The failure
|
||||
is counted, logged and reported to the user (see
|
||||
[Diagnostics](#diagnostics-and-warnings)).
|
||||
|
||||
Two rare rounding cases are handled only after both paths have failed, so the
|
||||
normal path never pays for them:
|
||||
|
||||
- **Cut beside a vertex.** When a modifier boundary crosses within about one
|
||||
coordinate unit of a source vertex, Clipper can place the cut at the vertex's
|
||||
height but a few units beside it. The end pair then collapses to the vertex's
|
||||
parameter or misses both neighboring edges. An end cut closer than the
|
||||
snapping radius to a vertex of the fragment's own chain is snapped to that
|
||||
vertex: either its neighbor in the fragment (the cut is a rounded copy of it
|
||||
and is dropped) or a vertex that shares a source edge with that neighbor. The
|
||||
neighbor wins whenever it is within the radius. Ends that are themselves source
|
||||
vertices and ambiguous choices are left unchanged. Binding is then retried
|
||||
once with the same strict rules, so a wrong candidate can only fail again.
|
||||
- **Contact.** A fragment that still fails but is shorter than the snapping
|
||||
radius is accepted as a contact and binds nothing. Insertion would collapse it
|
||||
onto one point anyway.
|
||||
|
||||
Both outcomes are recoveries, not failures: they show no user warning but leave
|
||||
a log marker.
|
||||
|
||||
### Assembling segments
|
||||
|
||||
The intervals are sorted by edge and parameter. Intervals on the same occurrence
|
||||
of an edge are united when they overlap or meet, by parameter or at the same
|
||||
integer point; equal coordinates on different edges are never united. A
|
||||
parameter of 1 is stored as parameter 0 of the next edge, so intervals on
|
||||
adjacent edges meet exactly at their shared vertex. Consecutive intervals that
|
||||
meet form one `PerimeterSegment`, and the last segment is joined with the first
|
||||
when they meet at vertex zero, undoing the artificial cut of the clipping line.
|
||||
|
||||
Each segment keeps its polyline, the source edge of every polyline edge, and its
|
||||
begin and end positions on the source contour.
|
||||
|
||||
### Full containment
|
||||
|
||||
A modifier that covers the whole perimeter has no boundaries on it. The policy
|
||||
follows seam painting, where painting a whole perimeter green is a meaningful
|
||||
choice and forbidding the seam all round is not:
|
||||
|
||||
- **Seam Enforced** types the whole perimeter, like a perimeter painted green all
|
||||
round, with subdivision applied as described under [Weak modifiers](#weak-modifiers).
|
||||
- **Seam Neutral** types the whole perimeter Neutral, like an unmarked perimeter,
|
||||
clearing painting and lower zones.
|
||||
- **Seam Blocked** is skipped for the perimeter, with the full-containment
|
||||
warning. The seam cannot avoid the whole perimeter, so the modifier does not
|
||||
override anything below it: lower zones and painting stay in effect.
|
||||
- **Seam Center, Left and Right** are skipped with the same warning: there is no
|
||||
intersection to place the point on.
|
||||
|
||||
Enforced and Neutral take part in the usual priority order (see
|
||||
[Weak modifiers](#weak-modifiers)).
|
||||
|
||||
The perimeter is fully contained when the united intervals cover every source
|
||||
edge from parameter 0 to 1. A modifier boundary that merely touches the
|
||||
perimeter counts as well:
|
||||
|
||||
- At a vertex or on an axis-aligned edge, clipping splits the line exactly at the
|
||||
touch, the pieces meet at one point, and the coverage is complete.
|
||||
- On an inclined edge the touching point is usually not representable on the
|
||||
integer grid. The boundary pokes a few units across and leaves a real gap, so
|
||||
a single segment covers everything except that gap.
|
||||
|
||||
Weak insertion would collapse such a segment's boundaries onto one vertex and
|
||||
turn the intended zone into a single candidate, and strong would put the seam at
|
||||
the touch. A single segment is therefore also full containment in the cases
|
||||
where insertion collapses it, exactly up to edges shorter than 2 µm:
|
||||
|
||||
- the uncovered length from its end to its begin is below 1 µm, or
|
||||
- the gap spans one vertex, or starts at a vertex and ends on the next edge, and
|
||||
both ends lie within 1 µm of the vertex that ends the first gap edge, since
|
||||
each end then snaps onto it from its own edge.
|
||||
|
||||
A cheap filter runs first: both cases bring the segment's ends within 2 µm of
|
||||
each other.
|
||||
|
||||
## Strong modifiers
|
||||
|
||||
For a strong modifier, the extractor prepares each segment's target point
|
||||
before anything is inserted, together with the source edge it lies on:
|
||||
|
||||
- **Left:** the segment's first point.
|
||||
- **Right:** the segment's last point.
|
||||
- **Center:** the point at half the segment's arc length.
|
||||
|
||||
Arc length is the sum of Euclidean edge lengths, not the chord or a vertex count.
|
||||
|
||||
`insert_strong_seam_point()` selects the longest segment of the first modifier
|
||||
that has one. Exactly equal lengths are resolved by the prepared target points:
|
||||
greater bed Y first, then smaller X; a complete tie keeps the first segment.
|
||||
Slice coordinates already include instance rotation and have the bed axes;
|
||||
centering and XY translation do not change this order. Nearly equal lengths are
|
||||
not treated as equal, so exact ties occur mainly on axis-aligned geometry.
|
||||
Geometrically equal segments, such as a symmetric modifier crossing both faces
|
||||
of a thin wall, differ only by rounding noise that varies between layers, so
|
||||
the chosen face may alternate. This is accepted deliberately: such a modifier is
|
||||
ambiguous by itself: more than one segment raises the "multiple intersections"
|
||||
warning. The user should make the modifier cross the perimeter once.
|
||||
|
||||
The selected point is inserted on its source edge. A point within 1 µm of an
|
||||
existing vertex is snapped to that vertex. Helper points are added 1 µm on both
|
||||
sides of it, except on an adjacent edge shorter than 2 µm, which already bounds
|
||||
the distance.
|
||||
|
||||
When the candidates are built, the candidate at the inserted point is the only
|
||||
enforced one and becomes the central enforcer; every other candidate is blocked.
|
||||
Every seam position mode therefore selects it. Alignment and random placement
|
||||
can still move the final position, so after alignment
|
||||
`restore_precise_seam_positions()` writes the exact point and its index back
|
||||
into every perimeter that has a strong seam.
|
||||
|
||||
## Weak modifiers
|
||||
|
||||
`collect_weak_modifier_segments()` extracts the segments of every weak modifier
|
||||
before the polygon is modified, so all positions refer to the same contour. Each
|
||||
segment becomes a zone with a type and two boundaries, kept in application
|
||||
order, lowest priority first. Full containment of an Enforced or Neutral
|
||||
modifier becomes a whole-perimeter zone at its place in that order: it has no
|
||||
boundaries and takes part in no insertion or helper step below. The boundaries
|
||||
carry their positions on the source contour; these remain as provenance after
|
||||
insertion and are not indices into the modified polygon.
|
||||
|
||||
`prepare_weak_modifier_segments()` then changes the polygon:
|
||||
|
||||
1. **Boundary insertion.** Insertion events are sorted by decreasing source edge
|
||||
and parameter, and the polygon is modified from its end towards its start. A
|
||||
pending boundary's source index therefore stays valid. Vertex zero has the
|
||||
canonical position `(0, 0)` and is
|
||||
processed last, and a point on the closing edge is appended rather than
|
||||
inserted at index zero. A boundary within 1 µm of either endpoint of its
|
||||
current edge, an original vertex or a boundary inserted earlier, is snapped to
|
||||
that point, so coincident boundaries share a vertex. A zone narrower than
|
||||
1 µm collapses into a single vertex.
|
||||
2. **Helper points.** A helper point is added 1 µm outside every boundary,
|
||||
unless the edge there is shorter than 2 µm, which already bounds it. The
|
||||
helpers keep the edges at a boundary short, so a seam placed along such an
|
||||
edge stays close to the boundary. Coincident boundaries share their helpers.
|
||||
3. **Enforced subdivision.** Zone types are resolved for the polygon's edges in
|
||||
priority order. The edges of a zone are those from its left boundary up to,
|
||||
but not including, its right boundary; a whole-perimeter zone types every
|
||||
edge. Enforced edges longer than `SeamPlacer::enforcer_oversampling_distance`
|
||||
(0.2 mm) are subdivided into steps of at most that length; shorter edges and
|
||||
existing vertices are kept.
|
||||
The regular seam placer then chooses the seam as for painted seams.
|
||||
|
||||
When candidates are built, painting assigns their types first.
|
||||
`apply_weak_modifiers_to_perimeter()` then overwrites the types of the
|
||||
candidates between the boundaries of each zone, both boundaries included,
|
||||
lowest priority first; a whole-perimeter zone types every candidate. Blocked
|
||||
and Enforced zones therefore take precedence over painting, and Neutral clears
|
||||
painting inside its zone.
|
||||
|
||||
## Numeric tolerances
|
||||
|
||||
Coordinates are integers in scaled units: 1 nm by default, and 10 nm when a bed
|
||||
larger than 2147 mm switches `SCALING_FACTOR`. Both Precise Seam tolerances are
|
||||
deliberately defined in units rather than physical distances. Clipper truncates
|
||||
cuts to whole units at any scale, so the on-edge tolerance must follow the unit; the
|
||||
snapping radius scales with it to keep its margin over single-precision
|
||||
candidate coordinates, which are coarser on large beds. Distances quoted in
|
||||
this document in nanometers and
|
||||
micrometers assume the default unit; on large printers they are ten times
|
||||
larger. The enforced subdivision step is a physical distance and stays 0.2 mm.
|
||||
|
||||
| Value | Role |
|
||||
| --- | --- |
|
||||
| `MACHINE_PRECISION_SQUARED` (2.5 units², about 1.6 nm) | A point lies on an edge if it is this close. It absorbs Clipper's truncation of cuts to whole units (under √2 units from the edge) and never bridges a real gap: a one-unit uncovered gap stays a gap. |
|
||||
| `TOLERANCE_LINEAR` (1000 units, 1 µm) | Insertion snaps points this close to an existing vertex, and helper points are placed this far from boundaries. The same radius bounds the rounding fallback, contacts and the sub-micron full-containment rule, so those decisions match what insertion would produce anyway. |
|
||||
| `enforcer_oversampling_distance` (0.2 mm) | Maximum step of enforced subdivision. |
|
||||
|
||||
Raising the on-edge tolerance would not help with cuts beside a vertex: more
|
||||
points past a vertex would be clamped to its parameter and collapse. Lowering it
|
||||
would reject ordinary rounded cuts. The snapping radius is kept far above
|
||||
clipping precision for robustness: seam candidates hold single-precision
|
||||
coordinates, whose step is about 8 to 15 nm at typical object coordinates
|
||||
(about 0.25 µm 3 m from the object's centre, on large beds only), and
|
||||
weak boundaries and the strong point are located among the candidates by those
|
||||
coordinates, so distinct points must stay clearly distinct. 1 µm is also far
|
||||
below printing precision.
|
||||
|
||||
## Diagnostics and warnings
|
||||
|
||||
One `PreciseSeamWarnings` instance is shared by all objects and layers of a
|
||||
`SeamPlacer::init()` call. After all objects are processed, `SeamPlacer::init()`
|
||||
prepares at most one warning text, available through `precise_seam_warning()`.
|
||||
G-code export issues it as one non-critical warning with the ID
|
||||
`SlicingPreciseSeamWarning`. It is a single line, "Precise Seam: <causes>. Seam
|
||||
placement may differ from expected.", because the export warnings dialog shows
|
||||
only the first line of each warning. Repeated warning events replace the
|
||||
notification instead of appending to it. Except for the "had no effect" cause,
|
||||
the causes name the modifier types involved, as the menu names them, in menu
|
||||
order and each type once, for example "(Seam Left, Seam Enforced)".
|
||||
The causes are:
|
||||
|
||||
- **failed to process some intersections (types):** at least one fragment was
|
||||
discarded by binding. Other segments remain usable.
|
||||
- **multiple intersections with a perimeter, only one was used (types):**
|
||||
a Seam Center, Left or Right modifier had more than one segment on a
|
||||
perimeter (see [Strong modifiers](#strong-modifiers)).
|
||||
- **a perimeter is fully inside a modifier, the modifier was not applied to it
|
||||
(types):** a Seam Center, Left, Right or Blocked modifier was skipped for a
|
||||
perimeter (see [Full containment](#full-containment)).
|
||||
- **modifier "<name>" of "<object>" had no effect on the seam (it might not reach
|
||||
the centerline of the printed perimeter):** a modifier was evaluated on at
|
||||
least one perimeter and never gave a segment, full containment or a discarded
|
||||
fragment. Only the first such modifier in print and volume order is named,
|
||||
followed by "(N in total)" when there are several.
|
||||
|
||||
Only the effect is certain, so the cause is given as a hint. A modifier is
|
||||
evaluated only when its turn comes: on a perimeter where a higher strong
|
||||
modifier placed the seam, lower strong and all weak modifiers are not
|
||||
evaluated. A modifier that was never evaluated is not reported, since nothing
|
||||
is known about it. A point contact gives no segment and does not count as
|
||||
reaching the perimeter.
|
||||
|
||||
The log records the following diagnostic markers:
|
||||
|
||||
- `[PreciseSeamIntersectionFailed]` for a discarded fragment, with object,
|
||||
modifier, layer, height, fragment and failing pair, the failure reason and
|
||||
point counts.
|
||||
- `[PreciseSeamFragmentRecovered]` for a recovery, with `outcome=bound` or
|
||||
`outcome=contact`, the same location fields and the original failure reason.
|
||||
- `[PreciseSeamNoEffect]` for every modifier of the "had no effect" cause, with
|
||||
the object and modifier names. Unlike the user warning, the log lists all of
|
||||
them.
|
||||
|
||||
Failures and recoveries are counted separately. The first 10 of each per
|
||||
`init()` call are logged in detail, in parallel processing order; if a limit is
|
||||
exceeded, one summary marker reports the total and the number omitted.
|
||||
|
||||
## Known limitations
|
||||
|
||||
- **The modifier must reach the perimeter centerline.** Contacts are taken as
|
||||
clipping returns them, without offsets or tangency rules, so boundaries that
|
||||
only graze the centerline are the user's responsibility. Several near-touches
|
||||
on inclined edges can leave several segments separated by gaps of a few units;
|
||||
their zones then cover nearly the whole perimeter instead of being treated as
|
||||
full containment.
|
||||
- **Self-touching perimeters.** Extraction keeps distinct visits of one
|
||||
coordinate apart through its source-edge bindings, but the consumers locate
|
||||
inserted points by coordinates. A weak zone is typed and subdivided from the
|
||||
first vertex with its boundary coordinate, while boundary helpers are added at
|
||||
every such vertex. A strong point marks every candidate at its coordinate as
|
||||
enforced, and the last one is restored after alignment. If a boundary or a
|
||||
strong point falls exactly on a repeated coordinate, a zone may therefore start
|
||||
from another visit, or the seam may start at another visit of the same point.
|
||||
Carrying visit identity through insertion, refinement, candidates and
|
||||
restoration would touch the whole pipeline, so it is not done for this rare
|
||||
geometry. Overlapping source visits are likewise outside the binding contract.
|
||||
|
||||
## Integration with the application
|
||||
|
||||
### Other seam settings
|
||||
|
||||
- Precise Seam takes part only in outer and hole perimeter seam placement. In
|
||||
spiral vase mode the seam placer is not used for perimeters, so the modifiers
|
||||
have no effect.
|
||||
- Scarf seams, the seam gap and wiping start from the chosen point exactly as
|
||||
they would from an ordinary seam.
|
||||
- Seam painting acts only from model parts, the volumes the seam gizmo shows and
|
||||
edits, and from negative volumes. Painting retained on a volume after a change
|
||||
from part to a Precise Seam, ordinary or support modifier is ignored. A type
|
||||
change back to a model part reactivates any retained painting.
|
||||
Negative volumes keep it on purpose: painting a
|
||||
part and turning it into a negative volume is the only way to paint the wall
|
||||
of the hole it cuts. That painting still affects the seam but is invisible in
|
||||
the gizmo and cannot be edited there; this is known technical debt.
|
||||
If painting them is ever made editable, G-code invalidation must track it too:
|
||||
`model_custom_seam_data_changed()` checks model parts only.
|
||||
|
||||
### Model storage and 3MF compatibility
|
||||
|
||||
Projects must stay readable by earlier releases, and a Precise Seam volume must
|
||||
not change a print there. Both 3MF writers therefore store it as an ordinary
|
||||
parameter modifier: `modifier_part` in the Bambu-format part subtype, and
|
||||
`ParameterModifier` together with the legacy `modifier` flag in the
|
||||
Prusa-format volume metadata. The seam mode is written separately under
|
||||
`precise_seam_type`, using the names from `ModelVolume::type_to_string()`
|
||||
(`precise_seam_center` and so on).
|
||||
|
||||
On load, the mode applies after all other volume metadata, regardless of XML
|
||||
key order, and only when the base type is a modifier. Missing or unknown modes
|
||||
leave an ordinary modifier. Seam metadata on any other base type is ignored.
|
||||
Files that stored the seam mode directly as the volume type still load.
|
||||
On load, the mode is applied after all other volume metadata, regardless of XML
|
||||
key order, and only when the base type is a modifier. A missing or unknown mode
|
||||
leaves an ordinary modifier, and seam metadata on any other base type is
|
||||
ignored. Files that stored the seam mode directly as the volume type still load.
|
||||
A project saved again by an earlier release loses the seam mode for good: the
|
||||
volumes stay ordinary modifiers without settings.
|
||||
|
||||
A Precise Seam volume keeps any per-volume settings it had as a part or
|
||||
modifier, but they are inactive and the object list shows no settings item for
|
||||
it. The writers prefix these keys with `precise_seam_config:`, so an earlier
|
||||
reader drops them as unknown options. The volume therefore loads there as a
|
||||
modifier without settings and has no effect on the print. The current reader
|
||||
restores the keys only when the volume ends up as a Precise Seam type, so the
|
||||
settings return when the user changes the type back. Configuration values are
|
||||
XML-escaped in both writers, for every volume type.
|
||||
reader drops them as unknown options and loads a modifier without settings,
|
||||
which has no effect on the print. The current reader restores the keys only when
|
||||
the volume ends up as a Precise Seam type, so the settings return when the user
|
||||
changes the type back.
|
||||
|
||||
## Print invalidation
|
||||
### Print invalidation
|
||||
|
||||
`Print::apply()` compares the Precise Seam volumes of each object by type, ID
|
||||
and transformation. Adding, removing, moving, reordering or retyping one
|
||||
cancels background processing and invalidates only `psGCodeExport`; the sliced
|
||||
layers are kept. `model_volume_list_update_supports_and_seams()` then brings
|
||||
the support and Precise Seam volumes of the print's model copy in line with the
|
||||
new model in one pass. A volume may switch between the two families, since
|
||||
neither affects slicing. A conversion to or from a part or ordinary modifier
|
||||
changes the solid and modifier volume lists and reslices as before.
|
||||
and transformation. Adding, removing, moving, reordering or retyping one cancels
|
||||
background processing and invalidates only `psGCodeExport`; the sliced layers
|
||||
are kept. `model_volume_list_update_supports_and_seams()` then brings the
|
||||
support and Precise Seam volumes of the print's model copy in line with the new
|
||||
model in one pass. A volume may switch between these two families, since neither
|
||||
affects object slicing; such a switch also changes the support volumes, so the
|
||||
support step is invalidated as well.
|
||||
|
||||
## Modifier slices
|
||||
A conversion to or from a part or an ordinary modifier changes the solid and
|
||||
modifier volume lists and reslices the object as before. The volume keeps its
|
||||
ID across the type change, so the region cache treats a former support or
|
||||
Precise Seam volume that became a part or modifier as new, since it was never
|
||||
cached.
|
||||
|
||||
`SeamPlacer::init()` collects the Precise Seam volumes of each object once:
|
||||
strong ones in priority order and weak ones reversed. It slices each volume
|
||||
separately with `PrintObject::slice_single_volume()`, which shares
|
||||
`slice_modifier_volumes()` with support blockers and enforcers but does not
|
||||
merge volumes, so each keeps its own priority. The result is cached per volume
|
||||
and indexed by object layer; `Layer::id()` includes raft layers, which are
|
||||
subtracted. Seam candidates are then gathered in parallel over the layers and
|
||||
read the cache without locking.
|
||||
Removing the last helper of a single-part object reslices it, as removing any
|
||||
last modifier would.
|
||||
|
||||
Objects without Precise Seam volumes follow the unchanged seam placement path.
|
||||
For objects that have them, perimeter extraction also removes consecutive
|
||||
duplicate points and the repeated closing point of each extrusion loop.
|
||||
Zero-length edges at path junctions would otherwise prevent point insertion
|
||||
there. Distinct visits to one point of a self-touching contour are kept.
|
||||
|
||||
## Finding the wall segment
|
||||
|
||||
The seam placer works on the external perimeter loops of each layer, both
|
||||
outer contours and holes, each made counter-clockwise. For every modifier
|
||||
polygon on the layer that overlaps the perimeter's bounding box, the region
|
||||
enclosed by the perimeter is clipped against the modifier polygon. The boundary
|
||||
of each intersection polygon alternates between runs that follow the perimeter
|
||||
and runs that follow the modifier outline. The wall segment is the longest
|
||||
continuous run of intersection vertices that lie on the perimeter, measured in
|
||||
vertices.
|
||||
|
||||
The fast path first finds an intersection vertex that exactly matches a
|
||||
perimeter vertex. It then walks forward and backward, expecting the adjacent
|
||||
perimeter vertex and falling back to projection when Clipper has merged or
|
||||
split collinear edges. A vertex counts as on the perimeter when its projection
|
||||
is within about 1.6 nm, which covers Clipper's rounding. If no vertex matches
|
||||
exactly, or every vertex lies on the perimeter, the general path projects all
|
||||
vertices. When every vertex is on the perimeter, the edge midpoints are checked
|
||||
instead: a modifier chord can join two perimeter vertices directly, and the
|
||||
chords split the vertex ring into runs. If no edge leaves the perimeter, the
|
||||
perimeter lies entirely inside the modifier.
|
||||
|
||||
`Polygon::point_projection()` optionally reports the edge that holds the
|
||||
projection, and every point of the segment keeps the index of its perimeter
|
||||
edge. New points are inserted on that edge. A point within 1 µm of an existing
|
||||
vertex snaps to that vertex instead.
|
||||
|
||||
## Strong modifiers
|
||||
|
||||
For a strong modifier, the target is the first point, the last point or the
|
||||
arc-length midpoint of the segment. The midpoint is projected back onto the
|
||||
original perimeter, because Clipper may have merged several perimeter edges
|
||||
into one segment edge. The target is inserted into the perimeter, and a helper
|
||||
point is inserted 1 µm before and after it. Strong modifiers are tried in
|
||||
priority order, the first valid intersection decides the seam, and weak
|
||||
modifiers are not processed for that perimeter.
|
||||
|
||||
When candidates are built, the inserted point is the only enforced candidate
|
||||
and becomes the central enforcer; every other candidate is blocked. The seam
|
||||
position modes then pick that point: Aligned and Aligned Back prefer the central
|
||||
enforcer, while Back, Random and Nearest rank enforced candidates above blocked
|
||||
ones. Alignment and random placement can still move the final position along an
|
||||
edge. After alignment, `restore_precise_seam_positions()` writes the exact point
|
||||
and its index back into every perimeter that has a strong seam. Inner walls take
|
||||
their seam from the external seam as usual, including staggering.
|
||||
|
||||
## Weak modifiers
|
||||
|
||||
Weak modifiers produce one segment per intersection polygon, so one modifier can
|
||||
mark several zones on one perimeter. All segment boundaries are inserted into
|
||||
the perimeter in order of decreasing arc length. Each insertion then leaves the
|
||||
indices of the pending, shorter ones unchanged; a point on the closing edge is
|
||||
appended rather than inserted at index zero. A helper point is added 1 µm
|
||||
outside each boundary. Random placement picks a position along the edge that
|
||||
follows a candidate. These helpers keep that edge 1 µm long at each boundary, so
|
||||
a zone cannot extend or intrude further than that. Boundaries that coincide
|
||||
share their helper points.
|
||||
|
||||
The zone types are then resolved in priority order, and the edges of enforced
|
||||
zones are subdivided into steps of at most
|
||||
`SeamPlacer::enforcer_oversampling_distance` (0.2 mm). The middle candidate of
|
||||
the longest enforced patch is therefore close to the geometric middle of the
|
||||
zone. That patch is measured in candidates, across the closing edge, regardless
|
||||
of where the contour starts; the same rule applies to painted seams.
|
||||
|
||||
Candidates first receive their type from seam painting. The weak zones then
|
||||
overwrite it, lowest priority first. Blocked and Enforced zones therefore take
|
||||
precedence over painting, and Neutral clears painting inside its zone.
|
||||
|
||||
## Unsupported geometry and warnings
|
||||
|
||||
Some modifier shapes cannot be resolved to one seam or one zone per crossing.
|
||||
They are detected cheaply and reported rather than guessed:
|
||||
|
||||
- A strong modifier that crosses a perimeter in more than one place uses only
|
||||
its first valid segment. The other crossings are ignored.
|
||||
- A modifier that crosses the whole region enclosed by the perimeter is
|
||||
detected when the modifier outline minus that region leaves more than one
|
||||
piece, none of them a hole. Its intersection holds two wall runs, and only
|
||||
one of them is used.
|
||||
- A modifier whose slice has a hole on a layer, found as a clockwise polygon in
|
||||
the flattened slice, is skipped on that layer. The flattened slice no longer
|
||||
records which hole belongs to which contour.
|
||||
- A perimeter that lies entirely inside a modifier is ignored by that modifier.
|
||||
|
||||
The conditions are atomic flags shared by all layers and objects. After all
|
||||
objects are processed, `SeamPlacer::init()` issues at most one non-critical
|
||||
warning with the ID `SlicingPreciseSeamWarning`. The warning is a single line
|
||||
that lists every cause found, because the export warnings dialog shows only the
|
||||
first line of each warning. Repeated warning events replace this notification
|
||||
instead of appending text to it.
|
||||
|
||||
## User interface
|
||||
### User interface
|
||||
|
||||
- *Add Precise Seam* in the object menu creates a Center modifier from a
|
||||
primitive or a loaded mesh. Text and SVG volumes cannot become Precise Seam
|
||||
modifiers: the menu does not offer them, and `ObjectList::set_volume_type()`
|
||||
modifiers: the menu does not offer it, and `ObjectList::set_volume_type()`
|
||||
refuses the change.
|
||||
- *Change Type* has a single *Precise Seam* entry. It converts other volumes to
|
||||
Center and keeps the mode of volumes that are already Precise Seam. The
|
||||
*Precise Seam Type* submenu appears only when every selected item is a
|
||||
Precise Seam volume, including settings rows that resolve to one. It sets the
|
||||
chosen mode on all selected volumes.
|
||||
*Precise Seam Type* submenu appears only when every selected item is a Precise
|
||||
Seam volume, including settings rows that resolve to one, and sets the chosen
|
||||
mode on all of them.
|
||||
- Each mode has its own icon in the object list and its own color in the 3D
|
||||
view, at 60% opacity: warm oranges for the strong modes, and green, red and
|
||||
gray for Enforced, Blocked and Neutral.
|
||||
- Object list drops map visible rows to volume indices while skipping hidden
|
||||
cut connectors, and they refresh the row-to-volume map of the object.
|
||||
- Precise Seam volumes have no filament, block pasting into SLA, and are exposed
|
||||
to Python plugins as `ModelVolumeType` values plus the `is_precise_seam*()`
|
||||
methods.
|
||||
view, at 60% opacity: warm orange, gold and dark orange for Center, Left and
|
||||
Right; green, red and gray for Enforced, Blocked and Neutral. The three strong
|
||||
colors are close shades of one orange because all three mark strong
|
||||
modifiers; the object list icons tell the modes apart.
|
||||
- Precise Seam volumes have no filament and cannot be pasted into SLA objects.
|
||||
Python plugins see them as `ModelVolumeType` values and through the
|
||||
`is_precise_seam*()` methods.
|
||||
|
||||
## Implementation and verification
|
||||
|
||||
- [PreciseSeam.cpp](../../src/libslic3r/GCode/PreciseSeam.cpp) implements segment
|
||||
detection, point insertion, weak-zone resolution and position restoration.
|
||||
[SeamPlacer.cpp](../../src/libslic3r/GCode/SeamPlacer.cpp) integrates it into
|
||||
candidate gathering and issues the warning.
|
||||
- [PreciseSeam.cpp](../../src/libslic3r/GCode/PreciseSeam.cpp) implements the
|
||||
modifier cache, perimeter preparation, segment extraction and binding, strong
|
||||
selection and insertion, weak-zone preparation and application, and position
|
||||
restoration. [PreciseSeam.hpp](../../src/libslic3r/GCode/PreciseSeam.hpp)
|
||||
declares the contracts; [PreciseSeamInternal.hpp](../../src/libslic3r/GCode/PreciseSeamInternal.hpp)
|
||||
exposes the binding internals to tests.
|
||||
- [SeamPlacer.cpp](../../src/libslic3r/GCode/SeamPlacer.cpp) fills the cache,
|
||||
normalizes perimeters, calls both consumers while gathering candidates,
|
||||
restores strong positions after alignment and prepares the warning text, which
|
||||
[GCode.cpp](../../src/libslic3r/GCode.cpp) issues during G-code export.
|
||||
- [Model.hpp](../../src/libslic3r/Model.hpp) defines the types and their order,
|
||||
[PrintApply.cpp](../../src/libslic3r/PrintApply.cpp) handles invalidation, and
|
||||
[PrintObjectSlice.cpp](../../src/libslic3r/PrintObjectSlice.cpp) slices the
|
||||
modifiers. [bbs_3mf.cpp](../../src/libslic3r/Format/bbs_3mf.cpp) and
|
||||
[3mf.cpp](../../src/libslic3r/Format/3mf.cpp) store them.
|
||||
[PrintObjectSlice.cpp](../../src/libslic3r/PrintObjectSlice.cpp) slices single
|
||||
volumes into structured regions. [bbs_3mf.cpp](../../src/libslic3r/Format/bbs_3mf.cpp)
|
||||
and [3mf.cpp](../../src/libslic3r/Format/3mf.cpp) store them.
|
||||
- [GUI_Factories.cpp](../../src/slic3r/GUI/GUI_Factories.cpp) and
|
||||
[GUI_ObjectList.cpp](../../src/slic3r/GUI/GUI_ObjectList.cpp) provide the menus,
|
||||
type changes and ordering.
|
||||
type changes and ordering; [3DScene.cpp](../../src/slic3r/GUI/3DScene.cpp)
|
||||
defines the colors.
|
||||
- [Segment extraction tests](../../tests/libslic3r/test_precise_seam.cpp) cover
|
||||
clipping and binding: holes and components, contour origin and reversal,
|
||||
repeated coordinates, collinear vertices and rounding, rollback and the
|
||||
diagnostic limits, the rounding fallback on synthetic and real Clipper
|
||||
fragments, contacts, and full containment including touches and sub-micron
|
||||
gaps on inclined edges and around vertices.
|
||||
- [Precise Seam tests](../../tests/fff_print/test_precise_seam.cpp) cover the
|
||||
strong positions, including a midpoint on an existing vertex or the closing
|
||||
edge. They also cover shared and coincident weak boundaries, every warning,
|
||||
and the priority order.
|
||||
consumers: strong targets in every mode, including a midpoint on an existing
|
||||
vertex or the closing edge, longest-arc selection and tie order in bed axes,
|
||||
priorities, weak boundaries that coincide or share an edge, enforced
|
||||
subdivision, whole-perimeter weak zones with painting and priorities, weak
|
||||
zones over painting's oversampled candidates, the warning type masks, usage
|
||||
tracking for the "had no effect" warning, volume sorting of strong and weak
|
||||
groups, restoration of strong points after alignment, raft layer indexing and
|
||||
structured slices. End-to-end tests slice a real object with Precise Seam
|
||||
volumes and check the outer wall starts in the exported G-code: every strong
|
||||
mode under several seam positions and with a raft, Enforced and Blocked zones,
|
||||
a modifier with a hole, and the user warning.
|
||||
- [Seam placer tests](../../tests/fff_print/test_seam_placer.cpp) cover
|
||||
enforced-patch selection independent of the contour start, fully painted
|
||||
contours, duplicate removal, and `Print::apply()` synchronization through
|
||||
type changes and restored model snapshots.
|
||||
contours, duplicate removal, and `Print::apply()` synchronization through type
|
||||
changes and restored model snapshots. The duplicate-removal test also checks
|
||||
the "had no effect" warning text prepared by `init()` for a helper that never
|
||||
reaches the loop. Further tests check that adding, moving, retyping or
|
||||
removing a Precise Seam volume invalidates only G-code export, and that seam
|
||||
painting acts only from model parts and negative volumes, including after a
|
||||
type change back to part.
|
||||
- [3MF tests](../../tests/libslic3r/test_precise_seam_3mf.cpp) cover the round
|
||||
trip of every mode and of inactive settings, attribute escaping, and which
|
||||
metadata combinations restore a seam mode.
|
||||
trip of every mode and of inactive settings, attribute escaping, and the
|
||||
metadata combinations that restore a seam mode.
|
||||
[Plugin tests](../../tests/slic3rutils/test_precise_seam_plugin.cpp) cover the
|
||||
Python bindings.
|
||||
|
||||
@@ -22855,3 +22855,28 @@ msgstr ""
|
||||
#: resources/data/hints.ini: [hint:Avoid warping]
|
||||
msgid "Avoid warping\nDid you know that when printing materials that are prone to warping such as ABS, appropriately increasing the heatbed temperature can reduce the probability of warping?"
|
||||
msgstr ""
|
||||
|
||||
#: src/libslic3r/GCode/SeamPlacer.cpp
|
||||
#, possible-boost-format
|
||||
msgid "failed to process some intersections (%1%)"
|
||||
msgstr ""
|
||||
|
||||
#: src/libslic3r/GCode/SeamPlacer.cpp
|
||||
#, possible-boost-format
|
||||
msgid "multiple intersections with a perimeter, only one was used (%1%)"
|
||||
msgstr ""
|
||||
|
||||
#: src/libslic3r/GCode/SeamPlacer.cpp
|
||||
#, possible-boost-format
|
||||
msgid "a perimeter is fully inside a modifier, the modifier was not applied to it (%1%)"
|
||||
msgstr ""
|
||||
|
||||
#: src/libslic3r/GCode/SeamPlacer.cpp
|
||||
#, possible-boost-format
|
||||
msgid "modifier \"%1%\" of \"%2%\" had no effect on the seam (it might not reach the centerline of the printed perimeter)"
|
||||
msgstr ""
|
||||
|
||||
#: src/libslic3r/GCode/SeamPlacer.cpp
|
||||
#, possible-boost-format
|
||||
msgid "modifier \"%1%\" of \"%2%\" (%3% in total) had no effect on the seam (it might not reach the centerline of the printed perimeter)"
|
||||
msgstr ""
|
||||
|
||||
@@ -74,11 +74,8 @@ src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoCut.hpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoText.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoText.hpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp
|
||||
@@ -177,7 +174,6 @@ src/slic3r/GUI/PresetHints.cpp
|
||||
src/slic3r/GUI/ProgressStatusBar.cpp
|
||||
src/slic3r/GUI/PlateSettingsDialog.cpp
|
||||
src/slic3r/GUI/PrivacyUpdateDialog.cpp
|
||||
src/slic3r/GUI/PublishDialog.cpp
|
||||
src/slic3r/GUI/PublishSettingsDialog.cpp
|
||||
src/slic3r/GUI/SavePresetDialog.cpp
|
||||
src/slic3r/GUI/SceneBenchmark.cpp
|
||||
@@ -196,7 +192,6 @@ src/slic3r/GUI/Tab.hpp
|
||||
src/slic3r/GUI/UnsavedChangesDialog.cpp
|
||||
src/slic3r/GUI/Auxiliary.cpp
|
||||
src/slic3r/GUI/UpdateDialogs.cpp
|
||||
src/slic3r/GUI/ObjColorDialog.cpp
|
||||
src/slic3r/GUI/SyncAmsInfoDialog.cpp
|
||||
src/slic3r/GUI/WipeTowerDialog.cpp
|
||||
src/slic3r/GUI/wxExtensions.cpp
|
||||
@@ -258,7 +253,6 @@ src/slic3r/Utils/MKS.cpp
|
||||
src/slic3r/Utils/Moonraker.cpp
|
||||
src/slic3r/Utils/OctoPrint.cpp
|
||||
src/slic3r/Utils/Repetier.cpp
|
||||
src/slic3r/Utils/ProfileDescription.hpp
|
||||
src/slic3r/GUI/SendMultiMachinePage.cpp
|
||||
src/slic3r/GUI/MultiMachinePage.cpp
|
||||
src/slic3r/GUI/MultiMachineManagerPage.cpp
|
||||
|
||||
@@ -27362,17 +27362,30 @@ msgstr ""
|
||||
msgid "Precise Seam"
|
||||
msgstr "Точный шов"
|
||||
|
||||
msgid "multiple intersections with a perimeter detected"
|
||||
msgstr "обнаружены множественные пересечения с периметром"
|
||||
#: src/libslic3r/GCode/SeamPlacer.cpp
|
||||
#, possible-boost-format
|
||||
msgid "failed to process some intersections (%1%)"
|
||||
msgstr "не удалось обработать некоторые пересечения (%1%)"
|
||||
|
||||
msgid "modifier fully crosses the printable perimeter"
|
||||
msgstr "модификатор пересекает печатаемый периметр насквозь"
|
||||
#: src/libslic3r/GCode/SeamPlacer.cpp
|
||||
#, possible-boost-format
|
||||
msgid "multiple intersections with a perimeter, only one was used (%1%)"
|
||||
msgstr "несколько пересечений с периметром, использовано только одно (%1%)"
|
||||
|
||||
msgid "modifier shape is not solid (has holes inside) and was ignored"
|
||||
msgstr "форма модификатора не сплошная (имеет отверстия) и была проигнорирована"
|
||||
#: src/libslic3r/GCode/SeamPlacer.cpp
|
||||
#, possible-boost-format
|
||||
msgid "a perimeter is fully inside a modifier, the modifier was not applied to it (%1%)"
|
||||
msgstr "периметр целиком внутри модификатора, модификатор для него не применён (%1%)"
|
||||
|
||||
msgid "perimeter is fully contained inside modifier and was ignored"
|
||||
msgstr "периметр полностью содержится внутри модификатора и был проигнорирован"
|
||||
#: src/libslic3r/GCode/SeamPlacer.cpp
|
||||
#, possible-boost-format
|
||||
msgid "modifier \"%1%\" of \"%2%\" had no effect on the seam (it might not reach the centerline of the printed perimeter)"
|
||||
msgstr "модификатор «%1%» модели «%2%» не повлиял на шов (возможно, он не достигает осевой линии печатаемого периметра)"
|
||||
|
||||
#: src/libslic3r/GCode/SeamPlacer.cpp
|
||||
#, possible-boost-format
|
||||
msgid "modifier \"%1%\" of \"%2%\" (%3% in total) had no effect on the seam (it might not reach the centerline of the printed perimeter)"
|
||||
msgstr "модификатор «%1%» модели «%2%» (всего: %3%) не повлиял на шов (возможно, он не достигает осевой линии печатаемого периметра)"
|
||||
|
||||
msgid "Seam placement may differ from expected."
|
||||
msgstr "Размещение шва может отличаться от ожидаемого."
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<!-- Рамка -->
|
||||
<!-- Frame -->
|
||||
<path d="M0.5,13.5L0.5,1.5C0.5,0.951,0.951,0.5,1.5,0.5L13.5,0.5C14.049,0.5,14.5,0.951,14.5,1.5L14.5,13.5C14.5,14.049,14.049,14.5,13.5,14.5L1.5,14.5C0.951,14.5,0.5,14.049,0.5,13.5Z" style="fill:none;stroke:#949494;stroke-width:1px"/>
|
||||
|
||||
<!-- Центральные пунктирные линии -->
|
||||
<!-- Dashed seam line, centered -->
|
||||
<rect x="7" y="1" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="7" y="3" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="7" y="5" width="1" height="1" style="fill:#009688"/>
|
||||
@@ -11,9 +11,9 @@
|
||||
<rect x="7" y="11" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="7" y="13" width="1" height="1" style="fill:#009688"/>
|
||||
|
||||
<!-- Правая стрелка -->
|
||||
<path d="M9.5,7.5L12.504,4.504L12.5,10.5L9.5,7.5Z" style="fill:#949494;stroke:#949494;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5"/>
|
||||
<!-- Left arrow -->
|
||||
<path d="M9.5,7.5L12.5,4.5L12.5,10.5Z" style="fill:#949494;stroke:#949494;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5"/>
|
||||
|
||||
<!-- Левая стрелка -->
|
||||
<path d="M5.501928,7.5L2.497928,4.504L2.501928,10.5L5.501928,7.5Z" style="fill:#949494;stroke:#949494;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5"/>
|
||||
<!-- Right arrow -->
|
||||
<path d="M5.5,7.5L2.5,4.5L2.5,10.5Z" style="fill:#949494;stroke:#949494;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.2 KiB |
@@ -1,16 +1,16 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<!-- Рамка -->
|
||||
<!-- Frame -->
|
||||
<path d="M0.5,13.5L0.5,1.5C0.5,0.951,0.951,0.5,1.5,0.5L13.5,0.5C14.049,0.5,14.5,0.951,14.5,1.5L14.5,13.5C14.5,14.049,14.049,14.5,13.5,14.5L1.5,14.5C0.951,14.5,0.5,14.049,0.5,13.5Z" style="fill:none;stroke:#949494;stroke-width:1px"/>
|
||||
|
||||
<!-- Центральные пунктирные линии -->
|
||||
<rect x="7" y="1" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="7" y="3" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="7" y="5" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="7" y="7" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="7" y="9" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="7" y="11" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="7" y="13" width="1" height="1" style="fill:#009688"/>
|
||||
<!-- Dashed seam line, shifted left -->
|
||||
<rect x="3" y="1" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="3" y="3" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="3" y="5" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="3" y="7" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="3" y="9" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="3" y="11" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="3" y="13" width="1" height="1" style="fill:#009688"/>
|
||||
|
||||
<!-- Правая стрелка -->
|
||||
<path d="M9.5,7.5L12.504,4.504L12.5,10.5L9.5,7.5Z" style="fill:#949494;stroke:#949494;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5"/>
|
||||
<!-- Left arrow -->
|
||||
<path d="M5.5,7.5L8.5,4.5L8.5,10.5Z" style="fill:#949494;stroke:#949494;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1018 B |
@@ -1,16 +1,16 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<!-- Рамка -->
|
||||
<!-- Frame -->
|
||||
<path d="M0.5,13.5L0.5,1.5C0.5,0.951,0.951,0.5,1.5,0.5L13.5,0.5C14.049,0.5,14.5,0.951,14.5,1.5L14.5,13.5C14.5,14.049,14.049,14.5,13.5,14.5L1.5,14.5C0.951,14.5,0.5,14.049,0.5,13.5Z" style="fill:none;stroke:#949494;stroke-width:1px"/>
|
||||
|
||||
<!-- Центральные пунктирные линии -->
|
||||
<rect x="7" y="1" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="7" y="3" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="7" y="5" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="7" y="7" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="7" y="9" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="7" y="11" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="7" y="13" width="1" height="1" style="fill:#009688"/>
|
||||
<!-- Dashed seam line, shifted right -->
|
||||
<rect x="11" y="1" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="11" y="3" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="11" y="5" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="11" y="7" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="11" y="9" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="11" y="11" width="1" height="1" style="fill:#009688"/>
|
||||
<rect x="11" y="13" width="1" height="1" style="fill:#009688"/>
|
||||
|
||||
<!-- Левая стрелка -->
|
||||
<path d="M5.501928,7.5L2.497928,4.504L2.501928,10.5L5.501928,7.5Z" style="fill:#949494;stroke:#949494;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5"/>
|
||||
<!-- Right arrow -->
|
||||
<path d="M9.5,7.5L6.5,4.5L6.5,10.5Z" style="fill:#949494;stroke:#949494;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.0 KiB |
@@ -1,4 +0,0 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5.97222 3H4C2.89543 3 2 3.89543 2 5V14C2 15.1046 2.89543 16 4 16H14.4444C15.549 16 16.4444 15.1046 16.4444 14V5C16.4444 3.89543 15.549 3 14.4444 3H12.8333" stroke="white" stroke-linecap="round"/>
|
||||
<path d="M9.93711 2.64645C9.74185 2.45118 9.42527 2.45118 9.23 2.64645L6.04802 5.82843C5.85276 6.02369 5.85276 6.34027 6.04802 6.53553C6.24329 6.7308 6.55987 6.7308 6.75513 6.53553L9.58356 3.70711L12.412 6.53553C12.6072 6.7308 12.9238 6.7308 13.1191 6.53553C13.3144 6.34027 13.3144 6.02369 13.1191 5.82843L9.93711 2.64645ZM9.08356 11.3056C9.08356 11.5817 9.30741 11.8056 9.58356 11.8056C9.8597 11.8056 10.0836 11.5817 10.0836 11.3056H9.08356ZM9.08356 3V11.3056H10.0836V3H9.08356Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 805 B |
@@ -1,10 +0,0 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1_12)">
|
||||
<path d="M18 0H0V18H18V0Z" fill="#262E2F"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1_12">
|
||||
<rect width="18" height="18" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 283 B |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "OrcaFilamentLibrary",
|
||||
"version": "02.04.00.18",
|
||||
"version": "02.04.00.19",
|
||||
"force_update": "0",
|
||||
"description": "Orca Filament Library",
|
||||
"filament_list": [
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"filament_id": "OFvgE0Zh",
|
||||
"instantiation": "false",
|
||||
"fan_cooling_layer_time": [
|
||||
"85"
|
||||
"80"
|
||||
],
|
||||
"fan_min_speed": [
|
||||
"50"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="../../include/global.css" /> <!-- ORCA One for all-->
|
||||
<link rel="stylesheet" type="text/css" href="../css/common.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/theme.css" />
|
||||
<script type="text/javascript" src="../js/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../../include/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../js/json2.js"></script>
|
||||
<script type="text/javascript" src="../../data/text.js"></script>
|
||||
<script type="text/javascript" src="../js/globalapi.js"></script>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="../../include/global.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/common.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/theme.css" />
|
||||
<script type="text/javascript" src="../js/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../../include/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../js/json2.js"></script>
|
||||
<script type="text/javascript" src="../../data/text.js"></script>
|
||||
<script type="text/javascript" src="../js/globalapi.js"></script>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="../css/common.css" />
|
||||
<!-- <link rel="stylesheet" type="text/css" href="23.css" /> -->
|
||||
<link rel="stylesheet" type="text/css" href="../css/theme.css" />
|
||||
<script type="text/javascript" src="../js/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../../include/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../js/json2.js"></script>
|
||||
<script type="text/javascript" src="../../data/text.js"></script>
|
||||
<script type="text/javascript" src="../js/globalapi.js"></script>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="../css/common.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/theme.css" />
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
<script type="text/javascript" src="../js/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../../include/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../js/json2.js"></script>
|
||||
<script type="text/javascript" src="../../data/text.js"></script>
|
||||
<script type="text/javascript" src="../js/globalapi.js"></script>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="../css/common.css" />
|
||||
<link rel="stylesheet" type="text/css" href="load.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/dark.css" />
|
||||
<script type="text/javascript" src="../js/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../../include/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../js/json2.js"></script>
|
||||
<script type="text/javascript" src="../../data/text.js"></script>
|
||||
<script type="text/javascript" src="../js/globalapi.js"></script>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="../css/common.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/dark.css" />
|
||||
<link rel="stylesheet" type="text/css" href="1.css" />
|
||||
<script type="text/javascript" src="../js/jquery-2.1.1.min.js"></script>
|
||||
<script type="text/javascript" src="../../include/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../../data/text.js"></script>
|
||||
<script type="text/javascript" src="../js/globalapi.js"></script>
|
||||
<script type="text/javascript" src="../js/common.js"></script>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="../css/common.css" />
|
||||
<link rel="stylesheet" type="text/css" href="11.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/dark.css" />
|
||||
<script type="text/javascript" src="../js/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../../include/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../js/json2.js"></script>
|
||||
<script type="text/javascript" src="../../data/text.js"></script>
|
||||
<script type="text/javascript" src="../js/globalapi.js"></script>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="21.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/dark.css" />
|
||||
<script type="text/javascript" src="test.js"></script>
|
||||
<script type="text/javascript" src="../js/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../../include/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../js/json2.js"></script>
|
||||
<script type="text/javascript" src="../../data/text.js"></script>
|
||||
<script type="text/javascript" src="../js/globalapi.js"></script>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="22.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/dark.css" />
|
||||
<script type="text/javascript" src="test.js"></script>
|
||||
<script type="text/javascript" src="../js/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../../include/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../js/json2.js"></script>
|
||||
<script type="text/javascript" src="../../data/text.js"></script>
|
||||
<script type="text/javascript" src="../js/globalapi.js"></script>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="../22/common.css" /> <!-- ORCA use common sources for setup guide and standalone dialog -->
|
||||
<link rel="stylesheet" type="text/css" href="23.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/dark.css" />
|
||||
<script type="text/javascript" src="../js/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../../include/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../js/json2.js"></script>
|
||||
<script type="text/javascript" src="../../data/text.js"></script>
|
||||
<script type="text/javascript" src="../js/globalapi.js"></script>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="24.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/dark.css" />
|
||||
<!-- <script type="text/javascript" src="test.js"></script> -->
|
||||
<script type="text/javascript" src="../js/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../../include/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../js/json2.js"></script>
|
||||
<script type="text/javascript" src="../../data/text.js"></script>
|
||||
<script type="text/javascript" src="../js/globalapi.js"></script>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="../css/common.css" />
|
||||
<link rel="stylesheet" type="text/css" href="3.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/dark.css" />
|
||||
<script type="text/javascript" src="../js/jquery-2.1.1.min.js"></script>
|
||||
<script type="text/javascript" src="../../include/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../js/json2.js"></script>
|
||||
<script type="text/javascript" src="../../data/text.js"></script>
|
||||
<script type="text/javascript" src="../js/globalapi.js"></script>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="../../include/global.css" /> <!-- ORCA One for all-->
|
||||
<link rel="stylesheet" type="text/css" href="../css/common.css" />
|
||||
<link rel="stylesheet" type="text/css" href="31.css" />
|
||||
<script type="text/javascript" src="../js/jquery-2.1.1.min.js"></script>
|
||||
<script type="text/javascript" src="../../include/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../js/json2.js"></script>
|
||||
<script type="text/javascript" src="../../data/text.js"></script>
|
||||
<script type="text/javascript" src="../js/globalapi.js"></script>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="../css/common.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/dark.css" />
|
||||
<link rel="stylesheet" type="text/css" href="4orca.css" />
|
||||
<script type="text/javascript" src="../js/jquery-2.1.1.min.js"></script>
|
||||
<script type="text/javascript" src="../../include/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../js/json2.js"></script>
|
||||
<script type="text/javascript" src="../../data/text.js"></script>
|
||||
<script type="text/javascript" src="../js/globalapi.js"></script>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="../css/common.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/dark.css" />
|
||||
<link rel="stylesheet" type="text/css" href="5.css" />
|
||||
<script type="text/javascript" src="../js/jquery-2.1.1.min.js"></script>
|
||||
<script type="text/javascript" src="../../include/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../js/json2.js"></script>
|
||||
<script type="text/javascript" src="../../data/text.js"></script>
|
||||
<script type="text/javascript" src="../js/globalapi.js"></script>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>引导_P1</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../include/global.css" /> <!-- ORCA One for all-->
|
||||
<link rel="stylesheet" type="text/css" href="6.css" />
|
||||
<script type="text/javascript" src="../js/jquery-2.1.1.min.js"></script>
|
||||
<script type="text/javascript" src="../../include/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../js/json2.js"></script>
|
||||
<script type="text/javascript" src="../../data/text.js"></script>
|
||||
<script type="text/javascript" src="../js/globalapi.js"></script>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>Slicer新手引导</title>
|
||||
<link rel="stylesheet" type="text/css" href="./css/common.css" />
|
||||
<link rel="stylesheet" type="text/css" href="./css/home.css" />
|
||||
<script type="text/javascript" src="./js/jquery-2.1.1.min.js"></script>
|
||||
<script type="text/javascript" src="../include/jquery-3.6.0.min.js"></script>
|
||||
</head>
|
||||
<body onLoad="OnInit()">
|
||||
<div id="LoadProgress">
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019 Vladimir Kharlampidi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -1,11 +0,0 @@
|
||||
Swiper
|
||||
==========
|
||||
|
||||
Swiper - is the free and most modern mobile touch slider with hardware accelerated transitions and amazing native behavior. It is intended to be used in mobile websites, mobile web apps, and mobile native/hybrid apps.
|
||||
|
||||
Swiper is not compatible with all platforms, it is a modern touch slider which is focused only on modern apps/platforms to bring the best experience and simplicity.
|
||||
|
||||
# Getting Started
|
||||
* [Getting Started Guide](https://swiperjs.com/get-started/)
|
||||
* [API](https://swiperjs.com/swiper-api/)
|
||||
* [Demos](https://swiperjs.com/demos/)
|
||||
@@ -1,3 +0,0 @@
|
||||
export * from './swiper.module';
|
||||
export * from './swiper.component';
|
||||
export * from './swiper-slide.directive';
|
||||
@@ -1,26 +0,0 @@
|
||||
import { TemplateRef } from '@angular/core';
|
||||
import * as i0 from "@angular/core";
|
||||
export declare class SwiperSlideDirective {
|
||||
template: TemplateRef<any>;
|
||||
virtualIndex: number;
|
||||
class: string;
|
||||
autoplayDelay: string | null;
|
||||
set zoom(val: boolean);
|
||||
get zoom(): boolean;
|
||||
private _zoom;
|
||||
slideIndex: number;
|
||||
get classNames(): string;
|
||||
set classNames(val: string);
|
||||
private _hasClass;
|
||||
slideData: {
|
||||
isActive: boolean;
|
||||
isPrev: boolean;
|
||||
isNext: boolean;
|
||||
isVisible: boolean;
|
||||
isDuplicate: boolean;
|
||||
};
|
||||
private _classNames;
|
||||
constructor(template: TemplateRef<any>);
|
||||
static ɵfac: i0.ɵɵFactoryDeclaration<SwiperSlideDirective, never>;
|
||||
static ɵdir: i0.ɵɵDirectiveDeclaration<SwiperSlideDirective, "ng-template[swiperSlide]", never, { "virtualIndex": "virtualIndex"; "class": "class"; "autoplayDelay": "data-swiper-autoplay"; "zoom": "zoom"; }, {}, never>;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import * as i0 from "@angular/core";
|
||||
import * as i1 from "./swiper.component";
|
||||
import * as i2 from "./swiper-slide.directive";
|
||||
import * as i3 from "@angular/common";
|
||||
export declare class SwiperModule {
|
||||
static ɵfac: i0.ɵɵFactoryDeclaration<SwiperModule, never>;
|
||||
static ɵmod: i0.ɵɵNgModuleDeclaration<SwiperModule, [typeof i1.SwiperComponent, typeof i2.SwiperSlideDirective], [typeof i3.CommonModule], [typeof i1.SwiperComponent, typeof i2.SwiperSlideDirective]>;
|
||||
static ɵinj: i0.ɵɵInjectorDeclaration<SwiperModule>;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
export declare const allowedParams: string[];
|
||||
export declare function getParams(obj?: any): {
|
||||
params: any;
|
||||
passedParams: any;
|
||||
rest: any;
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
export declare const paramsList: string[];
|
||||
@@ -1,6 +0,0 @@
|
||||
export declare function isObject(o: any): boolean;
|
||||
export declare function isShowEl(val: any, obj: any, el: any): boolean;
|
||||
export declare function extend(target: any, src: any): void;
|
||||
export declare function coerceBooleanProperty(value: any): boolean;
|
||||
export declare const ignoreNgOnChanges: string[];
|
||||
export declare function setProperty(val: any, obj?: {}): {} | false;
|
||||
@@ -1,7 +0,0 @@
|
||||
/*
|
||||
* Public API Surface of angular
|
||||
*/
|
||||
export * from './swiper.module';
|
||||
export * from './swiper.component';
|
||||
export * from './swiper-slide.directive';
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9hbmd1bGFyL3NyYy9wdWJsaWMtYXBpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsY0FBYyxpQkFBaUIsQ0FBQztBQUNoQyxjQUFjLG9CQUFvQixDQUFDO0FBQ25DLGNBQWMsMEJBQTBCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogUHVibGljIEFQSSBTdXJmYWNlIG9mIGFuZ3VsYXJcbiAqL1xuZXhwb3J0ICogZnJvbSAnLi9zd2lwZXIubW9kdWxlJztcbmV4cG9ydCAqIGZyb20gJy4vc3dpcGVyLmNvbXBvbmVudCc7XG5leHBvcnQgKiBmcm9tICcuL3N3aXBlci1zbGlkZS5kaXJlY3RpdmUnO1xuIl19
|
||||
@@ -1,60 +0,0 @@
|
||||
import { Directive, Input } from '@angular/core';
|
||||
import { coerceBooleanProperty } from './utils/utils';
|
||||
import * as i0 from "@angular/core";
|
||||
export class SwiperSlideDirective {
|
||||
constructor(template) {
|
||||
this.template = template;
|
||||
this.class = '';
|
||||
this.autoplayDelay = null;
|
||||
this.slideData = {
|
||||
isActive: false,
|
||||
isPrev: false,
|
||||
isNext: false,
|
||||
isVisible: false,
|
||||
isDuplicate: false,
|
||||
};
|
||||
}
|
||||
set zoom(val) {
|
||||
this._zoom = coerceBooleanProperty(val);
|
||||
}
|
||||
get zoom() {
|
||||
return this._zoom;
|
||||
}
|
||||
get classNames() {
|
||||
return this._classNames;
|
||||
}
|
||||
set classNames(val) {
|
||||
if (this._classNames === val) {
|
||||
return;
|
||||
}
|
||||
this._classNames = val;
|
||||
this.slideData = {
|
||||
isActive: this._hasClass(['swiper-slide-active', 'swiper-slide-duplicate-active']),
|
||||
isVisible: this._hasClass(['swiper-slide-visible']),
|
||||
isDuplicate: this._hasClass(['swiper-slide-duplicate']),
|
||||
isPrev: this._hasClass(['swiper-slide-prev', 'swiper-slide-duplicate-prev']),
|
||||
isNext: this._hasClass(['swiper-slide-next', 'swiper-slide-duplicate-next']),
|
||||
};
|
||||
}
|
||||
_hasClass(classNames) {
|
||||
return classNames.some((className) => this._classNames.indexOf(className) >= 0);
|
||||
}
|
||||
}
|
||||
SwiperSlideDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.2", ngImport: i0, type: SwiperSlideDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
|
||||
SwiperSlideDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.2.2", type: SwiperSlideDirective, selector: "ng-template[swiperSlide]", inputs: { virtualIndex: "virtualIndex", class: "class", autoplayDelay: ["data-swiper-autoplay", "autoplayDelay"], zoom: "zoom" }, ngImport: i0 });
|
||||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.2", ngImport: i0, type: SwiperSlideDirective, decorators: [{
|
||||
type: Directive,
|
||||
args: [{
|
||||
selector: 'ng-template[swiperSlide]',
|
||||
}]
|
||||
}], ctorParameters: function () { return [{ type: i0.TemplateRef }]; }, propDecorators: { virtualIndex: [{
|
||||
type: Input
|
||||
}], class: [{
|
||||
type: Input
|
||||
}], autoplayDelay: [{
|
||||
type: Input,
|
||||
args: ['data-swiper-autoplay']
|
||||
}], zoom: [{
|
||||
type: Input
|
||||
}] } });
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3dpcGVyLXNsaWRlLmRpcmVjdGl2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9hbmd1bGFyL3NyYy9zd2lwZXItc2xpZGUuZGlyZWN0aXZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFlLE1BQU0sZUFBZSxDQUFDO0FBQzlELE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLGVBQWUsQ0FBQzs7QUFJdEQsTUFBTSxPQUFPLG9CQUFvQjtJQTBDL0IsWUFBbUIsUUFBMEI7UUFBMUIsYUFBUSxHQUFSLFFBQVEsQ0FBa0I7UUF4Q3BDLFVBQUssR0FBVyxFQUFFLENBQUM7UUFDRyxrQkFBYSxHQUFrQixJQUFJLENBQUM7UUE4Qm5FLGNBQVMsR0FBRztZQUNWLFFBQVEsRUFBRSxLQUFLO1lBQ2YsTUFBTSxFQUFFLEtBQUs7WUFDYixNQUFNLEVBQUUsS0FBSztZQUNiLFNBQVMsRUFBRSxLQUFLO1lBQ2hCLFdBQVcsRUFBRSxLQUFLO1NBQ25CLENBQUM7SUFHOEMsQ0FBQztJQXRDakQsSUFDSSxJQUFJLENBQUMsR0FBWTtRQUNuQixJQUFJLENBQUMsS0FBSyxHQUFHLHFCQUFxQixDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFDRCxJQUFJLElBQUk7UUFDTixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUM7SUFDcEIsQ0FBQztJQUdELElBQUksVUFBVTtRQUNaLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQztJQUMxQixDQUFDO0lBQ0QsSUFBSSxVQUFVLENBQUMsR0FBRztRQUNoQixJQUFJLElBQUksQ0FBQyxXQUFXLEtBQUssR0FBRyxFQUFFO1lBQzVCLE9BQU87U0FDUjtRQUNELElBQUksQ0FBQyxXQUFXLEdBQUcsR0FBRyxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxTQUFTLEdBQUc7WUFDZixRQUFRLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLHFCQUFxQixFQUFFLCtCQUErQixDQUFDLENBQUM7WUFDbEYsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO1lBQ25ELFdBQVcsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsd0JBQXdCLENBQUMsQ0FBQztZQUN2RCxNQUFNLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLG1CQUFtQixFQUFFLDZCQUE2QixDQUFDLENBQUM7WUFDNUUsTUFBTSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxtQkFBbUIsRUFBRSw2QkFBNkIsQ0FBQyxDQUFDO1NBQzdFLENBQUM7SUFDSixDQUFDO0lBRU8sU0FBUyxDQUFDLFVBQW9CO1FBQ3BDLE9BQU8sVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDbEYsQ0FBQzs7aUhBaENVLG9CQUFvQjtxR0FBcEIsb0JBQW9COzJGQUFwQixvQkFBb0I7a0JBSGhDLFNBQVM7bUJBQUM7b0JBQ1QsUUFBUSxFQUFFLDBCQUEwQjtpQkFDckM7a0dBRVUsWUFBWTtzQkFBcEIsS0FBSztnQkFDRyxLQUFLO3NCQUFiLEtBQUs7Z0JBQ3lCLGFBQWE7c0JBQTNDLEtBQUs7dUJBQUMsc0JBQXNCO2dCQUV6QixJQUFJO3NCQURQLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBEaXJlY3RpdmUsIElucHV0LCBUZW1wbGF0ZVJlZiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgY29lcmNlQm9vbGVhblByb3BlcnR5IH0gZnJvbSAnLi91dGlscy91dGlscyc7XG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6ICduZy10ZW1wbGF0ZVtzd2lwZXJTbGlkZV0nLFxufSlcbmV4cG9ydCBjbGFzcyBTd2lwZXJTbGlkZURpcmVjdGl2ZSB7XG4gIEBJbnB1dCgpIHZpcnR1YWxJbmRleDogbnVtYmVyO1xuICBASW5wdXQoKSBjbGFzczogc3RyaW5nID0gJyc7XG4gIEBJbnB1dCgnZGF0YS1zd2lwZXItYXV0b3BsYXknKSBhdXRvcGxheURlbGF5OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgQElucHV0KClcbiAgc2V0IHpvb20odmFsOiBib29sZWFuKSB7XG4gICAgdGhpcy5fem9vbSA9IGNvZXJjZUJvb2xlYW5Qcm9wZXJ0eSh2YWwpO1xuICB9XG4gIGdldCB6b29tKCkge1xuICAgIHJldHVybiB0aGlzLl96b29tO1xuICB9XG4gIHByaXZhdGUgX3pvb206IGJvb2xlYW47XG4gIHNsaWRlSW5kZXg6IG51bWJlcjtcbiAgZ2V0IGNsYXNzTmFtZXMoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2NsYXNzTmFtZXM7XG4gIH1cbiAgc2V0IGNsYXNzTmFtZXModmFsKSB7XG4gICAgaWYgKHRoaXMuX2NsYXNzTmFtZXMgPT09IHZhbCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLl9jbGFzc05hbWVzID0gdmFsO1xuICAgIHRoaXMuc2xpZGVEYXRhID0ge1xuICAgICAgaXNBY3RpdmU6IHRoaXMuX2hhc0NsYXNzKFsnc3dpcGVyLXNsaWRlLWFjdGl2ZScsICdzd2lwZXItc2xpZGUtZHVwbGljYXRlLWFjdGl2ZSddKSxcbiAgICAgIGlzVmlzaWJsZTogdGhpcy5faGFzQ2xhc3MoWydzd2lwZXItc2xpZGUtdmlzaWJsZSddKSxcbiAgICAgIGlzRHVwbGljYXRlOiB0aGlzLl9oYXNDbGFzcyhbJ3N3aXBlci1zbGlkZS1kdXBsaWNhdGUnXSksXG4gICAgICBpc1ByZXY6IHRoaXMuX2hhc0NsYXNzKFsnc3dpcGVyLXNsaWRlLXByZXYnLCAnc3dpcGVyLXNsaWRlLWR1cGxpY2F0ZS1wcmV2J10pLFxuICAgICAgaXNOZXh0OiB0aGlzLl9oYXNDbGFzcyhbJ3N3aXBlci1zbGlkZS1uZXh0JywgJ3N3aXBlci1zbGlkZS1kdXBsaWNhdGUtbmV4dCddKSxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBfaGFzQ2xhc3MoY2xhc3NOYW1lczogc3RyaW5nW10pIHtcbiAgICByZXR1cm4gY2xhc3NOYW1lcy5zb21lKChjbGFzc05hbWUpID0+IHRoaXMuX2NsYXNzTmFtZXMuaW5kZXhPZihjbGFzc05hbWUpID49IDApO1xuICB9XG4gIHNsaWRlRGF0YSA9IHtcbiAgICBpc0FjdGl2ZTogZmFsc2UsXG4gICAgaXNQcmV2OiBmYWxzZSxcbiAgICBpc05leHQ6IGZhbHNlLFxuICAgIGlzVmlzaWJsZTogZmFsc2UsXG4gICAgaXNEdXBsaWNhdGU6IGZhbHNlLFxuICB9O1xuXG4gIHByaXZhdGUgX2NsYXNzTmFtZXM6IHN0cmluZztcbiAgY29uc3RydWN0b3IocHVibGljIHRlbXBsYXRlOiBUZW1wbGF0ZVJlZjxhbnk+KSB7fVxufVxuIl19
|
||||
@@ -1,19 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { SwiperComponent } from './swiper.component';
|
||||
import { SwiperSlideDirective } from './swiper-slide.directive';
|
||||
import * as i0 from "@angular/core";
|
||||
export class SwiperModule {
|
||||
}
|
||||
SwiperModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.2", ngImport: i0, type: SwiperModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
||||
SwiperModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.2", ngImport: i0, type: SwiperModule, declarations: [SwiperComponent, SwiperSlideDirective], imports: [CommonModule], exports: [SwiperComponent, SwiperSlideDirective] });
|
||||
SwiperModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.2", ngImport: i0, type: SwiperModule, imports: [[CommonModule]] });
|
||||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.2", ngImport: i0, type: SwiperModule, decorators: [{
|
||||
type: NgModule,
|
||||
args: [{
|
||||
declarations: [SwiperComponent, SwiperSlideDirective],
|
||||
exports: [SwiperComponent, SwiperSlideDirective],
|
||||
imports: [CommonModule],
|
||||
}]
|
||||
}] });
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3dpcGVyLm1vZHVsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9hbmd1bGFyL3NyYy9zd2lwZXIubW9kdWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNyRCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQzs7QUFNaEUsTUFBTSxPQUFPLFlBQVk7O3lHQUFaLFlBQVk7MEdBQVosWUFBWSxpQkFKUixlQUFlLEVBQUUsb0JBQW9CLGFBRTFDLFlBQVksYUFEWixlQUFlLEVBQUUsb0JBQW9COzBHQUdwQyxZQUFZLFlBRmQsQ0FBQyxZQUFZLENBQUM7MkZBRVosWUFBWTtrQkFMeEIsUUFBUTttQkFBQztvQkFDUixZQUFZLEVBQUUsQ0FBQyxlQUFlLEVBQUUsb0JBQW9CLENBQUM7b0JBQ3JELE9BQU8sRUFBRSxDQUFDLGVBQWUsRUFBRSxvQkFBb0IsQ0FBQztvQkFDaEQsT0FBTyxFQUFFLENBQUMsWUFBWSxDQUFDO2lCQUN4QiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE5nTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgU3dpcGVyQ29tcG9uZW50IH0gZnJvbSAnLi9zd2lwZXIuY29tcG9uZW50JztcbmltcG9ydCB7IFN3aXBlclNsaWRlRGlyZWN0aXZlIH0gZnJvbSAnLi9zd2lwZXItc2xpZGUuZGlyZWN0aXZlJztcbkBOZ01vZHVsZSh7XG4gIGRlY2xhcmF0aW9uczogW1N3aXBlckNvbXBvbmVudCwgU3dpcGVyU2xpZGVEaXJlY3RpdmVdLFxuICBleHBvcnRzOiBbU3dpcGVyQ29tcG9uZW50LCBTd2lwZXJTbGlkZURpcmVjdGl2ZV0sXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGVdLFxufSlcbmV4cG9ydCBjbGFzcyBTd2lwZXJNb2R1bGUge31cbiJdfQ==
|
||||
@@ -1,38 +0,0 @@
|
||||
// eslint-disable-next-line
|
||||
import { isObject, extend } from './utils';
|
||||
import { paramsList } from './params-list';
|
||||
// @ts-ignore
|
||||
import Swiper from 'swiper';
|
||||
export const allowedParams = paramsList.map((key) => key.replace(/_/, ''));
|
||||
export function getParams(obj = {}) {
|
||||
const params = {
|
||||
on: {},
|
||||
};
|
||||
const passedParams = {};
|
||||
extend(params, Swiper.defaults);
|
||||
extend(params, Swiper.extendedDefaults);
|
||||
params._emitClasses = true;
|
||||
const rest = {};
|
||||
Object.keys(obj).forEach((key) => {
|
||||
const _key = key.replace(/^_/, '');
|
||||
if (typeof obj[_key] === 'undefined')
|
||||
return;
|
||||
if (allowedParams.indexOf(_key) >= 0) {
|
||||
if (isObject(obj[_key])) {
|
||||
params[_key] = {};
|
||||
passedParams[_key] = {};
|
||||
extend(params[_key], obj[_key]);
|
||||
extend(passedParams[_key], obj[_key]);
|
||||
}
|
||||
else {
|
||||
params[_key] = obj[_key];
|
||||
passedParams[_key] = obj[_key];
|
||||
}
|
||||
}
|
||||
else {
|
||||
rest[_key] = obj[_key];
|
||||
}
|
||||
});
|
||||
return { params, passedParams, rest };
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0LXBhcmFtcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hbmd1bGFyL3NyYy91dGlscy9nZXQtcGFyYW1zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLDJCQUEyQjtBQUMzQixPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUMzQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLGFBQWE7QUFDYixPQUFPLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFFNUIsTUFBTSxDQUFDLE1BQU0sYUFBYSxHQUFHLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFDM0UsTUFBTSxVQUFVLFNBQVMsQ0FBQyxNQUFXLEVBQUU7SUFDckMsTUFBTSxNQUFNLEdBQVE7UUFDbEIsRUFBRSxFQUFFLEVBQUU7S0FDUCxDQUFDO0lBQ0YsTUFBTSxZQUFZLEdBQVEsRUFBRSxDQUFDO0lBQzdCLE1BQU0sQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ2hDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUM7SUFDeEMsTUFBTSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUM7SUFFM0IsTUFBTSxJQUFJLEdBQVEsRUFBRSxDQUFDO0lBQ3JCLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBVyxFQUFFLEVBQUU7UUFDdkMsTUFBTSxJQUFJLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDbkMsSUFBSSxPQUFPLEdBQUcsQ0FBQyxJQUFJLENBQUMsS0FBSyxXQUFXO1lBQUUsT0FBTztRQUM3QyxJQUFJLGFBQWEsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFO1lBQ3BDLElBQUksUUFBUSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFO2dCQUN2QixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO2dCQUNsQixZQUFZLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO2dCQUN4QixNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO2dCQUNoQyxNQUFNLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO2FBQ3ZDO2lCQUFNO2dCQUNMLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ3pCLFlBQVksQ0FBQyxJQUFJLENBQUMsR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7YUFDaEM7U0FDRjthQUFNO1lBQ0wsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUN4QjtJQUNILENBQUMsQ0FBQyxDQUFDO0lBRUgsT0FBTyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsSUFBSSxFQUFFLENBQUM7QUFDeEMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZVxuaW1wb3J0IHsgaXNPYmplY3QsIGV4dGVuZCB9IGZyb20gJy4vdXRpbHMnO1xuaW1wb3J0IHsgcGFyYW1zTGlzdCB9IGZyb20gJy4vcGFyYW1zLWxpc3QnO1xuLy8gQHRzLWlnbm9yZVxuaW1wb3J0IFN3aXBlciBmcm9tICdzd2lwZXInO1xuXG5leHBvcnQgY29uc3QgYWxsb3dlZFBhcmFtcyA9IHBhcmFtc0xpc3QubWFwKChrZXkpID0+IGtleS5yZXBsYWNlKC9fLywgJycpKTtcbmV4cG9ydCBmdW5jdGlvbiBnZXRQYXJhbXMob2JqOiBhbnkgPSB7fSkge1xuICBjb25zdCBwYXJhbXM6IGFueSA9IHtcbiAgICBvbjoge30sXG4gIH07XG4gIGNvbnN0IHBhc3NlZFBhcmFtczogYW55ID0ge307XG4gIGV4dGVuZChwYXJhbXMsIFN3aXBlci5kZWZhdWx0cyk7XG4gIGV4dGVuZChwYXJhbXMsIFN3aXBlci5leHRlbmRlZERlZmF1bHRzKTtcbiAgcGFyYW1zLl9lbWl0Q2xhc3NlcyA9IHRydWU7XG5cbiAgY29uc3QgcmVzdDogYW55ID0ge307XG4gIE9iamVjdC5rZXlzKG9iaikuZm9yRWFjaCgoa2V5OiBzdHJpbmcpID0+IHtcbiAgICBjb25zdCBfa2V5ID0ga2V5LnJlcGxhY2UoL15fLywgJycpO1xuICAgIGlmICh0eXBlb2Ygb2JqW19rZXldID09PSAndW5kZWZpbmVkJykgcmV0dXJuO1xuICAgIGlmIChhbGxvd2VkUGFyYW1zLmluZGV4T2YoX2tleSkgPj0gMCkge1xuICAgICAgaWYgKGlzT2JqZWN0KG9ialtfa2V5XSkpIHtcbiAgICAgICAgcGFyYW1zW19rZXldID0ge307XG4gICAgICAgIHBhc3NlZFBhcmFtc1tfa2V5XSA9IHt9O1xuICAgICAgICBleHRlbmQocGFyYW1zW19rZXldLCBvYmpbX2tleV0pO1xuICAgICAgICBleHRlbmQocGFzc2VkUGFyYW1zW19rZXldLCBvYmpbX2tleV0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcGFyYW1zW19rZXldID0gb2JqW19rZXldO1xuICAgICAgICBwYXNzZWRQYXJhbXNbX2tleV0gPSBvYmpbX2tleV07XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHJlc3RbX2tleV0gPSBvYmpbX2tleV07XG4gICAgfVxuICB9KTtcblxuICByZXR1cm4geyBwYXJhbXMsIHBhc3NlZFBhcmFtcywgcmVzdCB9O1xufVxuIl19
|
||||
@@ -1,49 +0,0 @@
|
||||
export function isObject(o) {
|
||||
return (typeof o === 'object' &&
|
||||
o !== null &&
|
||||
o.constructor &&
|
||||
Object.prototype.toString.call(o).slice(8, -1) === 'Object');
|
||||
}
|
||||
export function isShowEl(val, obj, el) {
|
||||
return ((coerceBooleanProperty(val) === true && obj && !obj.el) ||
|
||||
!(typeof obj !== 'boolean' &&
|
||||
obj.el !== (el === null || el === void 0 ? void 0 : el.nativeElement) &&
|
||||
(typeof obj.el === 'string' || typeof obj.el === 'object')));
|
||||
}
|
||||
export function extend(target, src) {
|
||||
const noExtend = ['__proto__', 'constructor', 'prototype'];
|
||||
Object.keys(src)
|
||||
.filter((key) => noExtend.indexOf(key) < 0)
|
||||
.forEach((key) => {
|
||||
if (typeof target[key] === 'undefined') {
|
||||
target[key] = src[key];
|
||||
return;
|
||||
}
|
||||
if (target[key] && !src[key]) {
|
||||
return;
|
||||
}
|
||||
if (isObject(src[key]) && isObject(target[key]) && Object.keys(src[key]).length > 0) {
|
||||
if (src[key].__swiper__)
|
||||
target[key] = src[key];
|
||||
else
|
||||
extend(target[key], src[key]);
|
||||
}
|
||||
else {
|
||||
target[key] = src[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
export function coerceBooleanProperty(value) {
|
||||
return value != null && `${value}` !== 'false';
|
||||
}
|
||||
export const ignoreNgOnChanges = ['pagination', 'navigation', 'scrollbar', 'virtual'];
|
||||
export function setProperty(val, obj = {}) {
|
||||
if (isObject(val)) {
|
||||
return val;
|
||||
}
|
||||
if (coerceBooleanProperty(val) === true) {
|
||||
return obj;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYW5ndWxhci9zcmMvdXRpbHMvdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsTUFBTSxVQUFVLFFBQVEsQ0FBQyxDQUFNO0lBQzdCLE9BQU8sQ0FDTCxPQUFPLENBQUMsS0FBSyxRQUFRO1FBQ3JCLENBQUMsS0FBSyxJQUFJO1FBQ1YsQ0FBQyxDQUFDLFdBQVc7UUFDYixNQUFNLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLFFBQVEsQ0FDNUQsQ0FBQztBQUNKLENBQUM7QUFFRCxNQUFNLFVBQVUsUUFBUSxDQUFDLEdBQVEsRUFBRSxHQUFRLEVBQUUsRUFBTztJQUNsRCxPQUFPLENBQ0wsQ0FBQyxxQkFBcUIsQ0FBQyxHQUFHLENBQUMsS0FBSyxJQUFJLElBQUksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN2RCxDQUFDLENBQ0MsT0FBTyxHQUFHLEtBQUssU0FBUztZQUN4QixHQUFHLENBQUMsRUFBRSxNQUFLLEVBQUUsYUFBRixFQUFFLHVCQUFGLEVBQUUsQ0FBRSxhQUFhLENBQUE7WUFDNUIsQ0FBQyxPQUFPLEdBQUcsQ0FBQyxFQUFFLEtBQUssUUFBUSxJQUFJLE9BQU8sR0FBRyxDQUFDLEVBQUUsS0FBSyxRQUFRLENBQUMsQ0FDM0QsQ0FDRixDQUFDO0FBQ0osQ0FBQztBQUVELE1BQU0sVUFBVSxNQUFNLENBQUMsTUFBVyxFQUFFLEdBQVE7SUFDMUMsTUFBTSxRQUFRLEdBQUcsQ0FBQyxXQUFXLEVBQUUsYUFBYSxFQUFFLFdBQVcsQ0FBQyxDQUFDO0lBQzNELE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDO1NBQ2IsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztTQUMxQyxPQUFPLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRTtRQUNmLElBQUksT0FBTyxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssV0FBVyxFQUFFO1lBQ3RDLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDdkIsT0FBTztTQUNSO1FBQ0QsSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUU7WUFDNUIsT0FBTztTQUNSO1FBQ0QsSUFBSSxRQUFRLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksUUFBUSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtZQUNuRixJQUFJLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxVQUFVO2dCQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7O2dCQUMzQyxNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1NBQ3BDO2FBQU07WUFDTCxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1NBQ3hCO0lBQ0gsQ0FBQyxDQUFDLENBQUM7QUFDUCxDQUFDO0FBRUQsTUFBTSxVQUFVLHFCQUFxQixDQUFDLEtBQVU7SUFDOUMsT0FBTyxLQUFLLElBQUksSUFBSSxJQUFJLEdBQUcsS0FBSyxFQUFFLEtBQUssT0FBTyxDQUFDO0FBQ2pELENBQUM7QUFFRCxNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLFlBQVksRUFBRSxZQUFZLEVBQUUsV0FBVyxFQUFFLFNBQVMsQ0FBQyxDQUFDO0FBRXRGLE1BQU0sVUFBVSxXQUFXLENBQUMsR0FBUSxFQUFFLEdBQUcsR0FBRyxFQUFFO0lBQzVDLElBQUksUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFO1FBQ2pCLE9BQU8sR0FBRyxDQUFDO0tBQ1o7SUFFRCxJQUFJLHFCQUFxQixDQUFDLEdBQUcsQ0FBQyxLQUFLLElBQUksRUFBRTtRQUN2QyxPQUFPLEdBQUcsQ0FBQztLQUNaO0lBRUQsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGZ1bmN0aW9uIGlzT2JqZWN0KG86IGFueSk6IGJvb2xlYW4ge1xuICByZXR1cm4gKFxuICAgIHR5cGVvZiBvID09PSAnb2JqZWN0JyAmJlxuICAgIG8gIT09IG51bGwgJiZcbiAgICBvLmNvbnN0cnVjdG9yICYmXG4gICAgT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG8pLnNsaWNlKDgsIC0xKSA9PT0gJ09iamVjdCdcbiAgKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzU2hvd0VsKHZhbDogYW55LCBvYmo6IGFueSwgZWw6IGFueSk6IGJvb2xlYW4ge1xuICByZXR1cm4gKFxuICAgIChjb2VyY2VCb29sZWFuUHJvcGVydHkodmFsKSA9PT0gdHJ1ZSAmJiBvYmogJiYgIW9iai5lbCkgfHxcbiAgICAhKFxuICAgICAgdHlwZW9mIG9iaiAhPT0gJ2Jvb2xlYW4nICYmXG4gICAgICBvYmouZWwgIT09IGVsPy5uYXRpdmVFbGVtZW50ICYmXG4gICAgICAodHlwZW9mIG9iai5lbCA9PT0gJ3N0cmluZycgfHwgdHlwZW9mIG9iai5lbCA9PT0gJ29iamVjdCcpXG4gICAgKVxuICApO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZXh0ZW5kKHRhcmdldDogYW55LCBzcmM6IGFueSkge1xuICBjb25zdCBub0V4dGVuZCA9IFsnX19wcm90b19fJywgJ2NvbnN0cnVjdG9yJywgJ3Byb3RvdHlwZSddO1xuICBPYmplY3Qua2V5cyhzcmMpXG4gICAgLmZpbHRlcigoa2V5KSA9PiBub0V4dGVuZC5pbmRleE9mKGtleSkgPCAwKVxuICAgIC5mb3JFYWNoKChrZXkpID0+IHtcbiAgICAgIGlmICh0eXBlb2YgdGFyZ2V0W2tleV0gPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIHRhcmdldFtrZXldID0gc3JjW2tleV07XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGlmICh0YXJnZXRba2V5XSAmJiAhc3JjW2tleV0pIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgaWYgKGlzT2JqZWN0KHNyY1trZXldKSAmJiBpc09iamVjdCh0YXJnZXRba2V5XSkgJiYgT2JqZWN0LmtleXMoc3JjW2tleV0pLmxlbmd0aCA+IDApIHtcbiAgICAgICAgaWYgKHNyY1trZXldLl9fc3dpcGVyX18pIHRhcmdldFtrZXldID0gc3JjW2tleV07XG4gICAgICAgIGVsc2UgZXh0ZW5kKHRhcmdldFtrZXldLCBzcmNba2V5XSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0YXJnZXRba2V5XSA9IHNyY1trZXldO1xuICAgICAgfVxuICAgIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY29lcmNlQm9vbGVhblByb3BlcnR5KHZhbHVlOiBhbnkpOiBib29sZWFuIHtcbiAgcmV0dXJuIHZhbHVlICE9IG51bGwgJiYgYCR7dmFsdWV9YCAhPT0gJ2ZhbHNlJztcbn1cblxuZXhwb3J0IGNvbnN0IGlnbm9yZU5nT25DaGFuZ2VzID0gWydwYWdpbmF0aW9uJywgJ25hdmlnYXRpb24nLCAnc2Nyb2xsYmFyJywgJ3ZpcnR1YWwnXTtcblxuZXhwb3J0IGZ1bmN0aW9uIHNldFByb3BlcnR5KHZhbDogYW55LCBvYmogPSB7fSk6IHt9IHwgZmFsc2Uge1xuICBpZiAoaXNPYmplY3QodmFsKSkge1xuICAgIHJldHVybiB2YWw7XG4gIH1cblxuICBpZiAoY29lcmNlQm9vbGVhblByb3BlcnR5KHZhbCkgPT09IHRydWUpIHtcbiAgICByZXR1cm4gb2JqO1xuICB9XG5cbiAgcmV0dXJuIGZhbHNlO1xufVxuIl19
|
||||
@@ -1,2 +0,0 @@
|
||||
export * from './angular/src/public-api';
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3dpcGVyLWFuZ3VsYXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc3dpcGVyLWFuZ3VsYXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYywwQkFBMEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCAqIGZyb20gJy4vYW5ndWxhci9zcmMvcHVibGljLWFwaSc7XG4iXX0=
|
||||
@@ -1,5 +0,0 @@
|
||||
/**
|
||||
* Generated bundle index. Do not edit.
|
||||
*/
|
||||
export * from './swiper-angular';
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3dpcGVyX2FuZ3VsYXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc3dpcGVyX2FuZ3VsYXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLGtCQUFrQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBHZW5lcmF0ZWQgYnVuZGxlIGluZGV4LiBEbyBub3QgZWRpdC5cbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL3N3aXBlci1hbmd1bGFyJztcbiJdfQ==
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"name": "swiper_angular",
|
||||
"version": "0.0.1",
|
||||
"private": "true",
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^12.2.0",
|
||||
"@angular/core": "^12.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"main": "bundles/swiper_angular.umd.js",
|
||||
"module": "fesm2015/swiper_angular.js",
|
||||
"es2015": "fesm2015/swiper_angular.js",
|
||||
"esm2015": "esm2015/swiper_angular.js",
|
||||
"fesm2015": "fesm2015/swiper_angular.js",
|
||||
"typings": "swiper_angular.d.ts",
|
||||
"sideEffects": false
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export * from './angular/src/public-api';
|
||||
@@ -1,5 +0,0 @@
|
||||
/**
|
||||
* Generated bundle index. Do not edit.
|
||||
*/
|
||||
/// <amd-module name="swiper_angular" />
|
||||
export * from './swiper-angular';
|
||||
@@ -1,40 +0,0 @@
|
||||
import { getWindow } from 'ssr-window';
|
||||
export default function getBreakpoint(breakpoints, base = 'window', containerEl) {
|
||||
if (!breakpoints || base === 'container' && !containerEl) return undefined;
|
||||
let breakpoint = false;
|
||||
const window = getWindow();
|
||||
const currentHeight = base === 'window' ? window.innerHeight : containerEl.clientHeight;
|
||||
const points = Object.keys(breakpoints).map(point => {
|
||||
if (typeof point === 'string' && point.indexOf('@') === 0) {
|
||||
const minRatio = parseFloat(point.substr(1));
|
||||
const value = currentHeight * minRatio;
|
||||
return {
|
||||
value,
|
||||
point
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
value: point,
|
||||
point
|
||||
};
|
||||
});
|
||||
points.sort((a, b) => parseInt(a.value, 10) - parseInt(b.value, 10));
|
||||
|
||||
for (let i = 0; i < points.length; i += 1) {
|
||||
const {
|
||||
point,
|
||||
value
|
||||
} = points[i];
|
||||
|
||||
if (base === 'window') {
|
||||
if (window.matchMedia(`(min-width: ${value}px)`).matches) {
|
||||
breakpoint = point;
|
||||
}
|
||||
} else if (value <= containerEl.clientWidth) {
|
||||
breakpoint = point;
|
||||
}
|
||||
}
|
||||
|
||||
return breakpoint || 'max';
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import setBreakpoint from './setBreakpoint.js';
|
||||
import getBreakpoint from './getBreakpoint.js';
|
||||
export default {
|
||||
setBreakpoint,
|
||||
getBreakpoint
|
||||
};
|
||||
@@ -1,72 +0,0 @@
|
||||
import { extend } from '../../shared/utils.js';
|
||||
|
||||
const isGridEnabled = (swiper, params) => {
|
||||
return swiper.grid && params.grid && params.grid.rows > 1;
|
||||
};
|
||||
|
||||
export default function setBreakpoint() {
|
||||
const swiper = this;
|
||||
const {
|
||||
activeIndex,
|
||||
initialized,
|
||||
loopedSlides = 0,
|
||||
params,
|
||||
$el
|
||||
} = swiper;
|
||||
const breakpoints = params.breakpoints;
|
||||
if (!breakpoints || breakpoints && Object.keys(breakpoints).length === 0) return; // Get breakpoint for window width and update parameters
|
||||
|
||||
const breakpoint = swiper.getBreakpoint(breakpoints, swiper.params.breakpointsBase, swiper.el);
|
||||
if (!breakpoint || swiper.currentBreakpoint === breakpoint) return;
|
||||
const breakpointOnlyParams = breakpoint in breakpoints ? breakpoints[breakpoint] : undefined;
|
||||
const breakpointParams = breakpointOnlyParams || swiper.originalParams;
|
||||
const wasMultiRow = isGridEnabled(swiper, params);
|
||||
const isMultiRow = isGridEnabled(swiper, breakpointParams);
|
||||
const wasEnabled = params.enabled;
|
||||
|
||||
if (wasMultiRow && !isMultiRow) {
|
||||
$el.removeClass(`${params.containerModifierClass}grid ${params.containerModifierClass}grid-column`);
|
||||
swiper.emitContainerClasses();
|
||||
} else if (!wasMultiRow && isMultiRow) {
|
||||
$el.addClass(`${params.containerModifierClass}grid`);
|
||||
|
||||
if (breakpointParams.grid.fill && breakpointParams.grid.fill === 'column' || !breakpointParams.grid.fill && params.grid.fill === 'column') {
|
||||
$el.addClass(`${params.containerModifierClass}grid-column`);
|
||||
}
|
||||
|
||||
swiper.emitContainerClasses();
|
||||
}
|
||||
|
||||
const directionChanged = breakpointParams.direction && breakpointParams.direction !== params.direction;
|
||||
const needsReLoop = params.loop && (breakpointParams.slidesPerView !== params.slidesPerView || directionChanged);
|
||||
|
||||
if (directionChanged && initialized) {
|
||||
swiper.changeDirection();
|
||||
}
|
||||
|
||||
extend(swiper.params, breakpointParams);
|
||||
const isEnabled = swiper.params.enabled;
|
||||
Object.assign(swiper, {
|
||||
allowTouchMove: swiper.params.allowTouchMove,
|
||||
allowSlideNext: swiper.params.allowSlideNext,
|
||||
allowSlidePrev: swiper.params.allowSlidePrev
|
||||
});
|
||||
|
||||
if (wasEnabled && !isEnabled) {
|
||||
swiper.disable();
|
||||
} else if (!wasEnabled && isEnabled) {
|
||||
swiper.enable();
|
||||
}
|
||||
|
||||
swiper.currentBreakpoint = breakpoint;
|
||||
swiper.emit('_beforeBreakpoint', breakpointParams);
|
||||
|
||||
if (needsReLoop && initialized) {
|
||||
swiper.loopDestroy();
|
||||
swiper.loopCreate();
|
||||
swiper.updateSlides();
|
||||
swiper.slideTo(activeIndex - loopedSlides + swiper.loopedSlides, 0, false);
|
||||
}
|
||||
|
||||
swiper.emit('breakpoint', breakpointParams);
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
function checkOverflow() {
|
||||
const swiper = this;
|
||||
const {
|
||||
isLocked: wasLocked,
|
||||
params
|
||||
} = swiper;
|
||||
const {
|
||||
slidesOffsetBefore
|
||||
} = params;
|
||||
|
||||
if (slidesOffsetBefore) {
|
||||
const lastSlideIndex = swiper.slides.length - 1;
|
||||
const lastSlideRightEdge = swiper.slidesGrid[lastSlideIndex] + swiper.slidesSizesGrid[lastSlideIndex] + slidesOffsetBefore * 2;
|
||||
swiper.isLocked = swiper.size > lastSlideRightEdge;
|
||||
} else {
|
||||
swiper.isLocked = swiper.snapGrid.length === 1;
|
||||
}
|
||||
|
||||
if (params.allowSlideNext === true) {
|
||||
swiper.allowSlideNext = !swiper.isLocked;
|
||||
}
|
||||
|
||||
if (params.allowSlidePrev === true) {
|
||||
swiper.allowSlidePrev = !swiper.isLocked;
|
||||
}
|
||||
|
||||
if (wasLocked && wasLocked !== swiper.isLocked) {
|
||||
swiper.isEnd = false;
|
||||
}
|
||||
|
||||
if (wasLocked !== swiper.isLocked) {
|
||||
swiper.emit(swiper.isLocked ? 'lock' : 'unlock');
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
checkOverflow
|
||||
};
|
||||
@@ -1,52 +0,0 @@
|
||||
function prepareClasses(entries, prefix) {
|
||||
const resultClasses = [];
|
||||
entries.forEach(item => {
|
||||
if (typeof item === 'object') {
|
||||
Object.keys(item).forEach(classNames => {
|
||||
if (item[classNames]) {
|
||||
resultClasses.push(prefix + classNames);
|
||||
}
|
||||
});
|
||||
} else if (typeof item === 'string') {
|
||||
resultClasses.push(prefix + item);
|
||||
}
|
||||
});
|
||||
return resultClasses;
|
||||
}
|
||||
|
||||
export default function addClasses() {
|
||||
const swiper = this;
|
||||
const {
|
||||
classNames,
|
||||
params,
|
||||
rtl,
|
||||
$el,
|
||||
device,
|
||||
support
|
||||
} = swiper; // prettier-ignore
|
||||
|
||||
const suffixes = prepareClasses(['initialized', params.direction, {
|
||||
'pointer-events': !support.touch
|
||||
}, {
|
||||
'free-mode': swiper.params.freeMode && params.freeMode.enabled
|
||||
}, {
|
||||
'autoheight': params.autoHeight
|
||||
}, {
|
||||
'rtl': rtl
|
||||
}, {
|
||||
'grid': params.grid && params.grid.rows > 1
|
||||
}, {
|
||||
'grid-column': params.grid && params.grid.rows > 1 && params.grid.fill === 'column'
|
||||
}, {
|
||||
'android': device.android
|
||||
}, {
|
||||
'ios': device.ios
|
||||
}, {
|
||||
'css-mode': params.cssMode
|
||||
}, {
|
||||
'centered': params.cssMode && params.centeredSlides
|
||||
}], params.containerModifierClass);
|
||||
classNames.push(...suffixes);
|
||||
$el.addClass([...classNames].join(' '));
|
||||
swiper.emitContainerClasses();
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import addClasses from './addClasses.js';
|
||||
import removeClasses from './removeClasses.js';
|
||||
export default {
|
||||
addClasses,
|
||||
removeClasses
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
export default function removeClasses() {
|
||||
const swiper = this;
|
||||
const {
|
||||
$el,
|
||||
classNames
|
||||
} = swiper;
|
||||
$el.removeClass(classNames.join(' '));
|
||||
swiper.emitContainerClasses();
|
||||
}
|
||||
@@ -1,610 +0,0 @@
|
||||
/* eslint no-param-reassign: "off" */
|
||||
import { getDocument } from 'ssr-window';
|
||||
import $ from '../shared/dom.js';
|
||||
import { extend, now, deleteProps } from '../shared/utils.js';
|
||||
import { getSupport } from '../shared/get-support.js';
|
||||
import { getDevice } from '../shared/get-device.js';
|
||||
import { getBrowser } from '../shared/get-browser.js';
|
||||
import Resize from './modules/resize/resize.js';
|
||||
import Observer from './modules/observer/observer.js';
|
||||
import eventsEmitter from './events-emitter.js';
|
||||
import update from './update/index.js';
|
||||
import translate from './translate/index.js';
|
||||
import transition from './transition/index.js';
|
||||
import slide from './slide/index.js';
|
||||
import loop from './loop/index.js';
|
||||
import grabCursor from './grab-cursor/index.js';
|
||||
import events from './events/index.js';
|
||||
import breakpoints from './breakpoints/index.js';
|
||||
import classes from './classes/index.js';
|
||||
import images from './images/index.js';
|
||||
import checkOverflow from './check-overflow/index.js';
|
||||
import defaults from './defaults.js';
|
||||
import moduleExtendParams from './moduleExtendParams.js';
|
||||
const prototypes = {
|
||||
eventsEmitter,
|
||||
update,
|
||||
translate,
|
||||
transition,
|
||||
slide,
|
||||
loop,
|
||||
grabCursor,
|
||||
events,
|
||||
breakpoints,
|
||||
checkOverflow,
|
||||
classes,
|
||||
images
|
||||
};
|
||||
const extendedDefaults = {};
|
||||
|
||||
class Swiper {
|
||||
constructor(...args) {
|
||||
let el;
|
||||
let params;
|
||||
|
||||
if (args.length === 1 && args[0].constructor && Object.prototype.toString.call(args[0]).slice(8, -1) === 'Object') {
|
||||
params = args[0];
|
||||
} else {
|
||||
[el, params] = args;
|
||||
}
|
||||
|
||||
if (!params) params = {};
|
||||
params = extend({}, params);
|
||||
if (el && !params.el) params.el = el;
|
||||
|
||||
if (params.el && $(params.el).length > 1) {
|
||||
const swipers = [];
|
||||
$(params.el).each(containerEl => {
|
||||
const newParams = extend({}, params, {
|
||||
el: containerEl
|
||||
});
|
||||
swipers.push(new Swiper(newParams));
|
||||
});
|
||||
return swipers;
|
||||
} // Swiper Instance
|
||||
|
||||
|
||||
const swiper = this;
|
||||
swiper.__swiper__ = true;
|
||||
swiper.support = getSupport();
|
||||
swiper.device = getDevice({
|
||||
userAgent: params.userAgent
|
||||
});
|
||||
swiper.browser = getBrowser();
|
||||
swiper.eventsListeners = {};
|
||||
swiper.eventsAnyListeners = [];
|
||||
swiper.modules = [...swiper.__modules__];
|
||||
|
||||
if (params.modules && Array.isArray(params.modules)) {
|
||||
swiper.modules.push(...params.modules);
|
||||
}
|
||||
|
||||
const allModulesParams = {};
|
||||
swiper.modules.forEach(mod => {
|
||||
mod({
|
||||
swiper,
|
||||
extendParams: moduleExtendParams(params, allModulesParams),
|
||||
on: swiper.on.bind(swiper),
|
||||
once: swiper.once.bind(swiper),
|
||||
off: swiper.off.bind(swiper),
|
||||
emit: swiper.emit.bind(swiper)
|
||||
});
|
||||
}); // Extend defaults with modules params
|
||||
|
||||
const swiperParams = extend({}, defaults, allModulesParams); // Extend defaults with passed params
|
||||
|
||||
swiper.params = extend({}, swiperParams, extendedDefaults, params);
|
||||
swiper.originalParams = extend({}, swiper.params);
|
||||
swiper.passedParams = extend({}, params); // add event listeners
|
||||
|
||||
if (swiper.params && swiper.params.on) {
|
||||
Object.keys(swiper.params.on).forEach(eventName => {
|
||||
swiper.on(eventName, swiper.params.on[eventName]);
|
||||
});
|
||||
}
|
||||
|
||||
if (swiper.params && swiper.params.onAny) {
|
||||
swiper.onAny(swiper.params.onAny);
|
||||
} // Save Dom lib
|
||||
|
||||
|
||||
swiper.$ = $; // Extend Swiper
|
||||
|
||||
Object.assign(swiper, {
|
||||
enabled: swiper.params.enabled,
|
||||
el,
|
||||
// Classes
|
||||
classNames: [],
|
||||
// Slides
|
||||
slides: $(),
|
||||
slidesGrid: [],
|
||||
snapGrid: [],
|
||||
slidesSizesGrid: [],
|
||||
|
||||
// isDirection
|
||||
isHorizontal() {
|
||||
return swiper.params.direction === 'horizontal';
|
||||
},
|
||||
|
||||
isVertical() {
|
||||
return swiper.params.direction === 'vertical';
|
||||
},
|
||||
|
||||
// Indexes
|
||||
activeIndex: 0,
|
||||
realIndex: 0,
|
||||
//
|
||||
isBeginning: true,
|
||||
isEnd: false,
|
||||
// Props
|
||||
translate: 0,
|
||||
previousTranslate: 0,
|
||||
progress: 0,
|
||||
velocity: 0,
|
||||
animating: false,
|
||||
// Locks
|
||||
allowSlideNext: swiper.params.allowSlideNext,
|
||||
allowSlidePrev: swiper.params.allowSlidePrev,
|
||||
// Touch Events
|
||||
touchEvents: function touchEvents() {
|
||||
const touch = ['touchstart', 'touchmove', 'touchend', 'touchcancel'];
|
||||
const desktop = ['pointerdown', 'pointermove', 'pointerup'];
|
||||
swiper.touchEventsTouch = {
|
||||
start: touch[0],
|
||||
move: touch[1],
|
||||
end: touch[2],
|
||||
cancel: touch[3]
|
||||
};
|
||||
swiper.touchEventsDesktop = {
|
||||
start: desktop[0],
|
||||
move: desktop[1],
|
||||
end: desktop[2]
|
||||
};
|
||||
return swiper.support.touch || !swiper.params.simulateTouch ? swiper.touchEventsTouch : swiper.touchEventsDesktop;
|
||||
}(),
|
||||
touchEventsData: {
|
||||
isTouched: undefined,
|
||||
isMoved: undefined,
|
||||
allowTouchCallbacks: undefined,
|
||||
touchStartTime: undefined,
|
||||
isScrolling: undefined,
|
||||
currentTranslate: undefined,
|
||||
startTranslate: undefined,
|
||||
allowThresholdMove: undefined,
|
||||
// Form elements to match
|
||||
focusableElements: swiper.params.focusableElements,
|
||||
// Last click time
|
||||
lastClickTime: now(),
|
||||
clickTimeout: undefined,
|
||||
// Velocities
|
||||
velocities: [],
|
||||
allowMomentumBounce: undefined,
|
||||
isTouchEvent: undefined,
|
||||
startMoving: undefined
|
||||
},
|
||||
// Clicks
|
||||
allowClick: true,
|
||||
// Touches
|
||||
allowTouchMove: swiper.params.allowTouchMove,
|
||||
touches: {
|
||||
startX: 0,
|
||||
startY: 0,
|
||||
currentX: 0,
|
||||
currentY: 0,
|
||||
diff: 0
|
||||
},
|
||||
// Images
|
||||
imagesToLoad: [],
|
||||
imagesLoaded: 0
|
||||
});
|
||||
swiper.emit('_swiper'); // Init
|
||||
|
||||
if (swiper.params.init) {
|
||||
swiper.init();
|
||||
} // Return app instance
|
||||
|
||||
|
||||
return swiper;
|
||||
}
|
||||
|
||||
enable() {
|
||||
const swiper = this;
|
||||
if (swiper.enabled) return;
|
||||
swiper.enabled = true;
|
||||
|
||||
if (swiper.params.grabCursor) {
|
||||
swiper.setGrabCursor();
|
||||
}
|
||||
|
||||
swiper.emit('enable');
|
||||
}
|
||||
|
||||
disable() {
|
||||
const swiper = this;
|
||||
if (!swiper.enabled) return;
|
||||
swiper.enabled = false;
|
||||
|
||||
if (swiper.params.grabCursor) {
|
||||
swiper.unsetGrabCursor();
|
||||
}
|
||||
|
||||
swiper.emit('disable');
|
||||
}
|
||||
|
||||
setProgress(progress, speed) {
|
||||
const swiper = this;
|
||||
progress = Math.min(Math.max(progress, 0), 1);
|
||||
const min = swiper.minTranslate();
|
||||
const max = swiper.maxTranslate();
|
||||
const current = (max - min) * progress + min;
|
||||
swiper.translateTo(current, typeof speed === 'undefined' ? 0 : speed);
|
||||
swiper.updateActiveIndex();
|
||||
swiper.updateSlidesClasses();
|
||||
}
|
||||
|
||||
emitContainerClasses() {
|
||||
const swiper = this;
|
||||
if (!swiper.params._emitClasses || !swiper.el) return;
|
||||
const cls = swiper.el.className.split(' ').filter(className => {
|
||||
return className.indexOf('swiper') === 0 || className.indexOf(swiper.params.containerModifierClass) === 0;
|
||||
});
|
||||
swiper.emit('_containerClasses', cls.join(' '));
|
||||
}
|
||||
|
||||
getSlideClasses(slideEl) {
|
||||
const swiper = this;
|
||||
return slideEl.className.split(' ').filter(className => {
|
||||
return className.indexOf('swiper-slide') === 0 || className.indexOf(swiper.params.slideClass) === 0;
|
||||
}).join(' ');
|
||||
}
|
||||
|
||||
emitSlidesClasses() {
|
||||
const swiper = this;
|
||||
if (!swiper.params._emitClasses || !swiper.el) return;
|
||||
const updates = [];
|
||||
swiper.slides.each(slideEl => {
|
||||
const classNames = swiper.getSlideClasses(slideEl);
|
||||
updates.push({
|
||||
slideEl,
|
||||
classNames
|
||||
});
|
||||
swiper.emit('_slideClass', slideEl, classNames);
|
||||
});
|
||||
swiper.emit('_slideClasses', updates);
|
||||
}
|
||||
|
||||
slidesPerViewDynamic(view = 'current', exact = false) {
|
||||
const swiper = this;
|
||||
const {
|
||||
params,
|
||||
slides,
|
||||
slidesGrid,
|
||||
slidesSizesGrid,
|
||||
size: swiperSize,
|
||||
activeIndex
|
||||
} = swiper;
|
||||
let spv = 1;
|
||||
|
||||
if (params.centeredSlides) {
|
||||
let slideSize = slides[activeIndex].swiperSlideSize;
|
||||
let breakLoop;
|
||||
|
||||
for (let i = activeIndex + 1; i < slides.length; i += 1) {
|
||||
if (slides[i] && !breakLoop) {
|
||||
slideSize += slides[i].swiperSlideSize;
|
||||
spv += 1;
|
||||
if (slideSize > swiperSize) breakLoop = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = activeIndex - 1; i >= 0; i -= 1) {
|
||||
if (slides[i] && !breakLoop) {
|
||||
slideSize += slides[i].swiperSlideSize;
|
||||
spv += 1;
|
||||
if (slideSize > swiperSize) breakLoop = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// eslint-disable-next-line
|
||||
if (view === 'current') {
|
||||
for (let i = activeIndex + 1; i < slides.length; i += 1) {
|
||||
const slideInView = exact ? slidesGrid[i] + slidesSizesGrid[i] - slidesGrid[activeIndex] < swiperSize : slidesGrid[i] - slidesGrid[activeIndex] < swiperSize;
|
||||
|
||||
if (slideInView) {
|
||||
spv += 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// previous
|
||||
for (let i = activeIndex - 1; i >= 0; i -= 1) {
|
||||
const slideInView = slidesGrid[activeIndex] - slidesGrid[i] < swiperSize;
|
||||
|
||||
if (slideInView) {
|
||||
spv += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return spv;
|
||||
}
|
||||
|
||||
update() {
|
||||
const swiper = this;
|
||||
if (!swiper || swiper.destroyed) return;
|
||||
const {
|
||||
snapGrid,
|
||||
params
|
||||
} = swiper; // Breakpoints
|
||||
|
||||
if (params.breakpoints) {
|
||||
swiper.setBreakpoint();
|
||||
}
|
||||
|
||||
swiper.updateSize();
|
||||
swiper.updateSlides();
|
||||
swiper.updateProgress();
|
||||
swiper.updateSlidesClasses();
|
||||
|
||||
function setTranslate() {
|
||||
const translateValue = swiper.rtlTranslate ? swiper.translate * -1 : swiper.translate;
|
||||
const newTranslate = Math.min(Math.max(translateValue, swiper.maxTranslate()), swiper.minTranslate());
|
||||
swiper.setTranslate(newTranslate);
|
||||
swiper.updateActiveIndex();
|
||||
swiper.updateSlidesClasses();
|
||||
}
|
||||
|
||||
let translated;
|
||||
|
||||
if (swiper.params.freeMode && swiper.params.freeMode.enabled) {
|
||||
setTranslate();
|
||||
|
||||
if (swiper.params.autoHeight) {
|
||||
swiper.updateAutoHeight();
|
||||
}
|
||||
} else {
|
||||
if ((swiper.params.slidesPerView === 'auto' || swiper.params.slidesPerView > 1) && swiper.isEnd && !swiper.params.centeredSlides) {
|
||||
translated = swiper.slideTo(swiper.slides.length - 1, 0, false, true);
|
||||
} else {
|
||||
translated = swiper.slideTo(swiper.activeIndex, 0, false, true);
|
||||
}
|
||||
|
||||
if (!translated) {
|
||||
setTranslate();
|
||||
}
|
||||
}
|
||||
|
||||
if (params.watchOverflow && snapGrid !== swiper.snapGrid) {
|
||||
swiper.checkOverflow();
|
||||
}
|
||||
|
||||
swiper.emit('update');
|
||||
}
|
||||
|
||||
changeDirection(newDirection, needUpdate = true) {
|
||||
const swiper = this;
|
||||
const currentDirection = swiper.params.direction;
|
||||
|
||||
if (!newDirection) {
|
||||
// eslint-disable-next-line
|
||||
newDirection = currentDirection === 'horizontal' ? 'vertical' : 'horizontal';
|
||||
}
|
||||
|
||||
if (newDirection === currentDirection || newDirection !== 'horizontal' && newDirection !== 'vertical') {
|
||||
return swiper;
|
||||
}
|
||||
|
||||
swiper.$el.removeClass(`${swiper.params.containerModifierClass}${currentDirection}`).addClass(`${swiper.params.containerModifierClass}${newDirection}`);
|
||||
swiper.emitContainerClasses();
|
||||
swiper.params.direction = newDirection;
|
||||
swiper.slides.each(slideEl => {
|
||||
if (newDirection === 'vertical') {
|
||||
slideEl.style.width = '';
|
||||
} else {
|
||||
slideEl.style.height = '';
|
||||
}
|
||||
});
|
||||
swiper.emit('changeDirection');
|
||||
if (needUpdate) swiper.update();
|
||||
return swiper;
|
||||
}
|
||||
|
||||
mount(el) {
|
||||
const swiper = this;
|
||||
if (swiper.mounted) return true; // Find el
|
||||
|
||||
const $el = $(el || swiper.params.el);
|
||||
el = $el[0];
|
||||
|
||||
if (!el) {
|
||||
return false;
|
||||
}
|
||||
|
||||
el.swiper = swiper;
|
||||
|
||||
const getWrapperSelector = () => {
|
||||
return `.${(swiper.params.wrapperClass || '').trim().split(' ').join('.')}`;
|
||||
};
|
||||
|
||||
const getWrapper = () => {
|
||||
if (el && el.shadowRoot && el.shadowRoot.querySelector) {
|
||||
const res = $(el.shadowRoot.querySelector(getWrapperSelector())); // Children needs to return slot items
|
||||
|
||||
res.children = options => $el.children(options);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
return $el.children(getWrapperSelector());
|
||||
}; // Find Wrapper
|
||||
|
||||
|
||||
let $wrapperEl = getWrapper();
|
||||
|
||||
if ($wrapperEl.length === 0 && swiper.params.createElements) {
|
||||
const document = getDocument();
|
||||
const wrapper = document.createElement('div');
|
||||
$wrapperEl = $(wrapper);
|
||||
wrapper.className = swiper.params.wrapperClass;
|
||||
$el.append(wrapper);
|
||||
$el.children(`.${swiper.params.slideClass}`).each(slideEl => {
|
||||
$wrapperEl.append(slideEl);
|
||||
});
|
||||
}
|
||||
|
||||
Object.assign(swiper, {
|
||||
$el,
|
||||
el,
|
||||
$wrapperEl,
|
||||
wrapperEl: $wrapperEl[0],
|
||||
mounted: true,
|
||||
// RTL
|
||||
rtl: el.dir.toLowerCase() === 'rtl' || $el.css('direction') === 'rtl',
|
||||
rtlTranslate: swiper.params.direction === 'horizontal' && (el.dir.toLowerCase() === 'rtl' || $el.css('direction') === 'rtl'),
|
||||
wrongRTL: $wrapperEl.css('display') === '-webkit-box'
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
init(el) {
|
||||
const swiper = this;
|
||||
if (swiper.initialized) return swiper;
|
||||
const mounted = swiper.mount(el);
|
||||
if (mounted === false) return swiper;
|
||||
swiper.emit('beforeInit'); // Set breakpoint
|
||||
|
||||
if (swiper.params.breakpoints) {
|
||||
swiper.setBreakpoint();
|
||||
} // Add Classes
|
||||
|
||||
|
||||
swiper.addClasses(); // Create loop
|
||||
|
||||
if (swiper.params.loop) {
|
||||
swiper.loopCreate();
|
||||
} // Update size
|
||||
|
||||
|
||||
swiper.updateSize(); // Update slides
|
||||
|
||||
swiper.updateSlides();
|
||||
|
||||
if (swiper.params.watchOverflow) {
|
||||
swiper.checkOverflow();
|
||||
} // Set Grab Cursor
|
||||
|
||||
|
||||
if (swiper.params.grabCursor && swiper.enabled) {
|
||||
swiper.setGrabCursor();
|
||||
}
|
||||
|
||||
if (swiper.params.preloadImages) {
|
||||
swiper.preloadImages();
|
||||
} // Slide To Initial Slide
|
||||
|
||||
|
||||
if (swiper.params.loop) {
|
||||
swiper.slideTo(swiper.params.initialSlide + swiper.loopedSlides, 0, swiper.params.runCallbacksOnInit, false, true);
|
||||
} else {
|
||||
swiper.slideTo(swiper.params.initialSlide, 0, swiper.params.runCallbacksOnInit, false, true);
|
||||
} // Attach events
|
||||
|
||||
|
||||
swiper.attachEvents(); // Init Flag
|
||||
|
||||
swiper.initialized = true; // Emit
|
||||
|
||||
swiper.emit('init');
|
||||
swiper.emit('afterInit');
|
||||
return swiper;
|
||||
}
|
||||
|
||||
destroy(deleteInstance = true, cleanStyles = true) {
|
||||
const swiper = this;
|
||||
const {
|
||||
params,
|
||||
$el,
|
||||
$wrapperEl,
|
||||
slides
|
||||
} = swiper;
|
||||
|
||||
if (typeof swiper.params === 'undefined' || swiper.destroyed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
swiper.emit('beforeDestroy'); // Init Flag
|
||||
|
||||
swiper.initialized = false; // Detach events
|
||||
|
||||
swiper.detachEvents(); // Destroy loop
|
||||
|
||||
if (params.loop) {
|
||||
swiper.loopDestroy();
|
||||
} // Cleanup styles
|
||||
|
||||
|
||||
if (cleanStyles) {
|
||||
swiper.removeClasses();
|
||||
$el.removeAttr('style');
|
||||
$wrapperEl.removeAttr('style');
|
||||
|
||||
if (slides && slides.length) {
|
||||
slides.removeClass([params.slideVisibleClass, params.slideActiveClass, params.slideNextClass, params.slidePrevClass].join(' ')).removeAttr('style').removeAttr('data-swiper-slide-index');
|
||||
}
|
||||
}
|
||||
|
||||
swiper.emit('destroy'); // Detach emitter events
|
||||
|
||||
Object.keys(swiper.eventsListeners).forEach(eventName => {
|
||||
swiper.off(eventName);
|
||||
});
|
||||
|
||||
if (deleteInstance !== false) {
|
||||
swiper.$el[0].swiper = null;
|
||||
deleteProps(swiper);
|
||||
}
|
||||
|
||||
swiper.destroyed = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
static extendDefaults(newDefaults) {
|
||||
extend(extendedDefaults, newDefaults);
|
||||
}
|
||||
|
||||
static get extendedDefaults() {
|
||||
return extendedDefaults;
|
||||
}
|
||||
|
||||
static get defaults() {
|
||||
return defaults;
|
||||
}
|
||||
|
||||
static installModule(mod) {
|
||||
if (!Swiper.prototype.__modules__) Swiper.prototype.__modules__ = [];
|
||||
const modules = Swiper.prototype.__modules__;
|
||||
|
||||
if (typeof mod === 'function' && modules.indexOf(mod) < 0) {
|
||||
modules.push(mod);
|
||||
}
|
||||
}
|
||||
|
||||
static use(module) {
|
||||
if (Array.isArray(module)) {
|
||||
module.forEach(m => Swiper.installModule(m));
|
||||
return Swiper;
|
||||
}
|
||||
|
||||
Swiper.installModule(module);
|
||||
return Swiper;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Object.keys(prototypes).forEach(prototypeGroup => {
|
||||
Object.keys(prototypes[prototypeGroup]).forEach(protoMethod => {
|
||||
Swiper.prototype[protoMethod] = prototypes[prototypeGroup][protoMethod];
|
||||
});
|
||||
});
|
||||
Swiper.use([Resize, Observer]);
|
||||
export default Swiper;
|
||||
@@ -1,120 +0,0 @@
|
||||
export default {
|
||||
init: true,
|
||||
direction: 'horizontal',
|
||||
touchEventsTarget: 'wrapper',
|
||||
initialSlide: 0,
|
||||
speed: 300,
|
||||
cssMode: false,
|
||||
updateOnWindowResize: true,
|
||||
resizeObserver: true,
|
||||
nested: false,
|
||||
createElements: false,
|
||||
enabled: true,
|
||||
focusableElements: 'input, select, option, textarea, button, video, label',
|
||||
// Overrides
|
||||
width: null,
|
||||
height: null,
|
||||
//
|
||||
preventInteractionOnTransition: false,
|
||||
// ssr
|
||||
userAgent: null,
|
||||
url: null,
|
||||
// To support iOS's swipe-to-go-back gesture (when being used in-app).
|
||||
edgeSwipeDetection: false,
|
||||
edgeSwipeThreshold: 20,
|
||||
// Autoheight
|
||||
autoHeight: false,
|
||||
// Set wrapper width
|
||||
setWrapperSize: false,
|
||||
// Virtual Translate
|
||||
virtualTranslate: false,
|
||||
// Effects
|
||||
effect: 'slide',
|
||||
// 'slide' or 'fade' or 'cube' or 'coverflow' or 'flip'
|
||||
// Breakpoints
|
||||
breakpoints: undefined,
|
||||
breakpointsBase: 'window',
|
||||
// Slides grid
|
||||
spaceBetween: 0,
|
||||
slidesPerView: 1,
|
||||
slidesPerGroup: 1,
|
||||
slidesPerGroupSkip: 0,
|
||||
slidesPerGroupAuto: false,
|
||||
centeredSlides: false,
|
||||
centeredSlidesBounds: false,
|
||||
slidesOffsetBefore: 0,
|
||||
// in px
|
||||
slidesOffsetAfter: 0,
|
||||
// in px
|
||||
normalizeSlideIndex: true,
|
||||
centerInsufficientSlides: false,
|
||||
// Disable swiper and hide navigation when container not overflow
|
||||
watchOverflow: true,
|
||||
// Round length
|
||||
roundLengths: false,
|
||||
// Touches
|
||||
touchRatio: 1,
|
||||
touchAngle: 45,
|
||||
simulateTouch: true,
|
||||
shortSwipes: true,
|
||||
longSwipes: true,
|
||||
longSwipesRatio: 0.5,
|
||||
longSwipesMs: 300,
|
||||
followFinger: true,
|
||||
allowTouchMove: true,
|
||||
threshold: 0,
|
||||
touchMoveStopPropagation: false,
|
||||
touchStartPreventDefault: true,
|
||||
touchStartForcePreventDefault: false,
|
||||
touchReleaseOnEdges: false,
|
||||
// Unique Navigation Elements
|
||||
uniqueNavElements: true,
|
||||
// Resistance
|
||||
resistance: true,
|
||||
resistanceRatio: 0.85,
|
||||
// Progress
|
||||
watchSlidesProgress: false,
|
||||
// Cursor
|
||||
grabCursor: false,
|
||||
// Clicks
|
||||
preventClicks: true,
|
||||
preventClicksPropagation: true,
|
||||
slideToClickedSlide: false,
|
||||
// Images
|
||||
preloadImages: true,
|
||||
updateOnImagesReady: true,
|
||||
// loop
|
||||
loop: false,
|
||||
loopAdditionalSlides: 0,
|
||||
loopedSlides: null,
|
||||
loopFillGroupWithBlank: false,
|
||||
loopPreventsSlide: true,
|
||||
// Swiping/no swiping
|
||||
allowSlidePrev: true,
|
||||
allowSlideNext: true,
|
||||
swipeHandler: null,
|
||||
// '.swipe-handler',
|
||||
noSwiping: true,
|
||||
noSwipingClass: 'swiper-no-swiping',
|
||||
noSwipingSelector: null,
|
||||
// Passive Listeners
|
||||
passiveListeners: true,
|
||||
// NS
|
||||
containerModifierClass: 'swiper-',
|
||||
// NEW
|
||||
slideClass: 'swiper-slide',
|
||||
slideBlankClass: 'swiper-slide-invisible-blank',
|
||||
slideActiveClass: 'swiper-slide-active',
|
||||
slideDuplicateActiveClass: 'swiper-slide-duplicate-active',
|
||||
slideVisibleClass: 'swiper-slide-visible',
|
||||
slideDuplicateClass: 'swiper-slide-duplicate',
|
||||
slideNextClass: 'swiper-slide-next',
|
||||
slideDuplicateNextClass: 'swiper-slide-duplicate-next',
|
||||
slidePrevClass: 'swiper-slide-prev',
|
||||
slideDuplicatePrevClass: 'swiper-slide-duplicate-prev',
|
||||
wrapperClass: 'swiper-wrapper',
|
||||
// Callbacks
|
||||
runCallbacksOnInit: true,
|
||||
// Internals
|
||||
_emitClasses: false
|
||||
};
|
||||
@@ -1,108 +0,0 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
export default {
|
||||
on(events, handler, priority) {
|
||||
const self = this;
|
||||
if (typeof handler !== 'function') return self;
|
||||
const method = priority ? 'unshift' : 'push';
|
||||
events.split(' ').forEach(event => {
|
||||
if (!self.eventsListeners[event]) self.eventsListeners[event] = [];
|
||||
self.eventsListeners[event][method](handler);
|
||||
});
|
||||
return self;
|
||||
},
|
||||
|
||||
once(events, handler, priority) {
|
||||
const self = this;
|
||||
if (typeof handler !== 'function') return self;
|
||||
|
||||
function onceHandler(...args) {
|
||||
self.off(events, onceHandler);
|
||||
|
||||
if (onceHandler.__emitterProxy) {
|
||||
delete onceHandler.__emitterProxy;
|
||||
}
|
||||
|
||||
handler.apply(self, args);
|
||||
}
|
||||
|
||||
onceHandler.__emitterProxy = handler;
|
||||
return self.on(events, onceHandler, priority);
|
||||
},
|
||||
|
||||
onAny(handler, priority) {
|
||||
const self = this;
|
||||
if (typeof handler !== 'function') return self;
|
||||
const method = priority ? 'unshift' : 'push';
|
||||
|
||||
if (self.eventsAnyListeners.indexOf(handler) < 0) {
|
||||
self.eventsAnyListeners[method](handler);
|
||||
}
|
||||
|
||||
return self;
|
||||
},
|
||||
|
||||
offAny(handler) {
|
||||
const self = this;
|
||||
if (!self.eventsAnyListeners) return self;
|
||||
const index = self.eventsAnyListeners.indexOf(handler);
|
||||
|
||||
if (index >= 0) {
|
||||
self.eventsAnyListeners.splice(index, 1);
|
||||
}
|
||||
|
||||
return self;
|
||||
},
|
||||
|
||||
off(events, handler) {
|
||||
const self = this;
|
||||
if (!self.eventsListeners) return self;
|
||||
events.split(' ').forEach(event => {
|
||||
if (typeof handler === 'undefined') {
|
||||
self.eventsListeners[event] = [];
|
||||
} else if (self.eventsListeners[event]) {
|
||||
self.eventsListeners[event].forEach((eventHandler, index) => {
|
||||
if (eventHandler === handler || eventHandler.__emitterProxy && eventHandler.__emitterProxy === handler) {
|
||||
self.eventsListeners[event].splice(index, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return self;
|
||||
},
|
||||
|
||||
emit(...args) {
|
||||
const self = this;
|
||||
if (!self.eventsListeners) return self;
|
||||
let events;
|
||||
let data;
|
||||
let context;
|
||||
|
||||
if (typeof args[0] === 'string' || Array.isArray(args[0])) {
|
||||
events = args[0];
|
||||
data = args.slice(1, args.length);
|
||||
context = self;
|
||||
} else {
|
||||
events = args[0].events;
|
||||
data = args[0].data;
|
||||
context = args[0].context || self;
|
||||
}
|
||||
|
||||
data.unshift(context);
|
||||
const eventsArray = Array.isArray(events) ? events : events.split(' ');
|
||||
eventsArray.forEach(event => {
|
||||
if (self.eventsAnyListeners && self.eventsAnyListeners.length) {
|
||||
self.eventsAnyListeners.forEach(eventHandler => {
|
||||
eventHandler.apply(context, [event, ...data]);
|
||||
});
|
||||
}
|
||||
|
||||
if (self.eventsListeners && self.eventsListeners[event]) {
|
||||
self.eventsListeners[event].forEach(eventHandler => {
|
||||
eventHandler.apply(context, data);
|
||||
});
|
||||
}
|
||||
});
|
||||
return self;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -1,97 +0,0 @@
|
||||
import { getDocument } from 'ssr-window';
|
||||
import onTouchStart from './onTouchStart.js';
|
||||
import onTouchMove from './onTouchMove.js';
|
||||
import onTouchEnd from './onTouchEnd.js';
|
||||
import onResize from './onResize.js';
|
||||
import onClick from './onClick.js';
|
||||
import onScroll from './onScroll.js';
|
||||
let dummyEventAttached = false;
|
||||
|
||||
function dummyEventListener() {}
|
||||
|
||||
const events = (swiper, method) => {
|
||||
const document = getDocument();
|
||||
const {
|
||||
params,
|
||||
touchEvents,
|
||||
el,
|
||||
wrapperEl,
|
||||
device,
|
||||
support
|
||||
} = swiper;
|
||||
const capture = !!params.nested;
|
||||
const domMethod = method === 'on' ? 'addEventListener' : 'removeEventListener';
|
||||
const swiperMethod = method; // Touch Events
|
||||
|
||||
if (!support.touch) {
|
||||
el[domMethod](touchEvents.start, swiper.onTouchStart, false);
|
||||
document[domMethod](touchEvents.move, swiper.onTouchMove, capture);
|
||||
document[domMethod](touchEvents.end, swiper.onTouchEnd, false);
|
||||
} else {
|
||||
const passiveListener = touchEvents.start === 'touchstart' && support.passiveListener && params.passiveListeners ? {
|
||||
passive: true,
|
||||
capture: false
|
||||
} : false;
|
||||
el[domMethod](touchEvents.start, swiper.onTouchStart, passiveListener);
|
||||
el[domMethod](touchEvents.move, swiper.onTouchMove, support.passiveListener ? {
|
||||
passive: false,
|
||||
capture
|
||||
} : capture);
|
||||
el[domMethod](touchEvents.end, swiper.onTouchEnd, passiveListener);
|
||||
|
||||
if (touchEvents.cancel) {
|
||||
el[domMethod](touchEvents.cancel, swiper.onTouchEnd, passiveListener);
|
||||
}
|
||||
} // Prevent Links Clicks
|
||||
|
||||
|
||||
if (params.preventClicks || params.preventClicksPropagation) {
|
||||
el[domMethod]('click', swiper.onClick, true);
|
||||
}
|
||||
|
||||
if (params.cssMode) {
|
||||
wrapperEl[domMethod]('scroll', swiper.onScroll);
|
||||
} // Resize handler
|
||||
|
||||
|
||||
if (params.updateOnWindowResize) {
|
||||
swiper[swiperMethod](device.ios || device.android ? 'resize orientationchange observerUpdate' : 'resize observerUpdate', onResize, true);
|
||||
} else {
|
||||
swiper[swiperMethod]('observerUpdate', onResize, true);
|
||||
}
|
||||
};
|
||||
|
||||
function attachEvents() {
|
||||
const swiper = this;
|
||||
const document = getDocument();
|
||||
const {
|
||||
params,
|
||||
support
|
||||
} = swiper;
|
||||
swiper.onTouchStart = onTouchStart.bind(swiper);
|
||||
swiper.onTouchMove = onTouchMove.bind(swiper);
|
||||
swiper.onTouchEnd = onTouchEnd.bind(swiper);
|
||||
|
||||
if (params.cssMode) {
|
||||
swiper.onScroll = onScroll.bind(swiper);
|
||||
}
|
||||
|
||||
swiper.onClick = onClick.bind(swiper);
|
||||
|
||||
if (support.touch && !dummyEventAttached) {
|
||||
document.addEventListener('touchstart', dummyEventListener);
|
||||
dummyEventAttached = true;
|
||||
}
|
||||
|
||||
events(swiper, 'on');
|
||||
}
|
||||
|
||||
function detachEvents() {
|
||||
const swiper = this;
|
||||
events(swiper, 'off');
|
||||
}
|
||||
|
||||
export default {
|
||||
attachEvents,
|
||||
detachEvents
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
export default function onClick(e) {
|
||||
const swiper = this;
|
||||
if (!swiper.enabled) return;
|
||||
|
||||
if (!swiper.allowClick) {
|
||||
if (swiper.params.preventClicks) e.preventDefault();
|
||||
|
||||
if (swiper.params.preventClicksPropagation && swiper.animating) {
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
export default function onResize() {
|
||||
const swiper = this;
|
||||
const {
|
||||
params,
|
||||
el
|
||||
} = swiper;
|
||||
if (el && el.offsetWidth === 0) return; // Breakpoints
|
||||
|
||||
if (params.breakpoints) {
|
||||
swiper.setBreakpoint();
|
||||
} // Save locks
|
||||
|
||||
|
||||
const {
|
||||
allowSlideNext,
|
||||
allowSlidePrev,
|
||||
snapGrid
|
||||
} = swiper; // Disable locks on resize
|
||||
|
||||
swiper.allowSlideNext = true;
|
||||
swiper.allowSlidePrev = true;
|
||||
swiper.updateSize();
|
||||
swiper.updateSlides();
|
||||
swiper.updateSlidesClasses();
|
||||
|
||||
if ((params.slidesPerView === 'auto' || params.slidesPerView > 1) && swiper.isEnd && !swiper.isBeginning && !swiper.params.centeredSlides) {
|
||||
swiper.slideTo(swiper.slides.length - 1, 0, false, true);
|
||||
} else {
|
||||
swiper.slideTo(swiper.activeIndex, 0, false, true);
|
||||
}
|
||||
|
||||
if (swiper.autoplay && swiper.autoplay.running && swiper.autoplay.paused) {
|
||||
swiper.autoplay.run();
|
||||
} // Return locks after resize
|
||||
|
||||
|
||||
swiper.allowSlidePrev = allowSlidePrev;
|
||||
swiper.allowSlideNext = allowSlideNext;
|
||||
|
||||
if (swiper.params.watchOverflow && snapGrid !== swiper.snapGrid) {
|
||||
swiper.checkOverflow();
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
export default function onScroll() {
|
||||
const swiper = this;
|
||||
const {
|
||||
wrapperEl,
|
||||
rtlTranslate,
|
||||
enabled
|
||||
} = swiper;
|
||||
if (!enabled) return;
|
||||
swiper.previousTranslate = swiper.translate;
|
||||
|
||||
if (swiper.isHorizontal()) {
|
||||
swiper.translate = -wrapperEl.scrollLeft;
|
||||
} else {
|
||||
swiper.translate = -wrapperEl.scrollTop;
|
||||
} // eslint-disable-next-line
|
||||
|
||||
|
||||
if (swiper.translate === -0) swiper.translate = 0;
|
||||
swiper.updateActiveIndex();
|
||||
swiper.updateSlidesClasses();
|
||||
let newProgress;
|
||||
const translatesDiff = swiper.maxTranslate() - swiper.minTranslate();
|
||||
|
||||
if (translatesDiff === 0) {
|
||||
newProgress = 0;
|
||||
} else {
|
||||
newProgress = (swiper.translate - swiper.minTranslate()) / translatesDiff;
|
||||
}
|
||||
|
||||
if (newProgress !== swiper.progress) {
|
||||
swiper.updateProgress(rtlTranslate ? -swiper.translate : swiper.translate);
|
||||
}
|
||||
|
||||
swiper.emit('setTranslate', swiper.translate, false);
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
import { now, nextTick } from '../../shared/utils.js';
|
||||
export default function onTouchEnd(event) {
|
||||
const swiper = this;
|
||||
const data = swiper.touchEventsData;
|
||||
const {
|
||||
params,
|
||||
touches,
|
||||
rtlTranslate: rtl,
|
||||
slidesGrid,
|
||||
enabled
|
||||
} = swiper;
|
||||
if (!enabled) return;
|
||||
let e = event;
|
||||
if (e.originalEvent) e = e.originalEvent;
|
||||
|
||||
if (data.allowTouchCallbacks) {
|
||||
swiper.emit('touchEnd', e);
|
||||
}
|
||||
|
||||
data.allowTouchCallbacks = false;
|
||||
|
||||
if (!data.isTouched) {
|
||||
if (data.isMoved && params.grabCursor) {
|
||||
swiper.setGrabCursor(false);
|
||||
}
|
||||
|
||||
data.isMoved = false;
|
||||
data.startMoving = false;
|
||||
return;
|
||||
} // Return Grab Cursor
|
||||
|
||||
|
||||
if (params.grabCursor && data.isMoved && data.isTouched && (swiper.allowSlideNext === true || swiper.allowSlidePrev === true)) {
|
||||
swiper.setGrabCursor(false);
|
||||
} // Time diff
|
||||
|
||||
|
||||
const touchEndTime = now();
|
||||
const timeDiff = touchEndTime - data.touchStartTime; // Tap, doubleTap, Click
|
||||
|
||||
if (swiper.allowClick) {
|
||||
swiper.updateClickedSlide(e);
|
||||
swiper.emit('tap click', e);
|
||||
|
||||
if (timeDiff < 300 && touchEndTime - data.lastClickTime < 300) {
|
||||
swiper.emit('doubleTap doubleClick', e);
|
||||
}
|
||||
}
|
||||
|
||||
data.lastClickTime = now();
|
||||
nextTick(() => {
|
||||
if (!swiper.destroyed) swiper.allowClick = true;
|
||||
});
|
||||
|
||||
if (!data.isTouched || !data.isMoved || !swiper.swipeDirection || touches.diff === 0 || data.currentTranslate === data.startTranslate) {
|
||||
data.isTouched = false;
|
||||
data.isMoved = false;
|
||||
data.startMoving = false;
|
||||
return;
|
||||
}
|
||||
|
||||
data.isTouched = false;
|
||||
data.isMoved = false;
|
||||
data.startMoving = false;
|
||||
let currentPos;
|
||||
|
||||
if (params.followFinger) {
|
||||
currentPos = rtl ? swiper.translate : -swiper.translate;
|
||||
} else {
|
||||
currentPos = -data.currentTranslate;
|
||||
}
|
||||
|
||||
if (params.cssMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (swiper.params.freeMode && params.freeMode.enabled) {
|
||||
swiper.freeMode.onTouchEnd({
|
||||
currentPos
|
||||
});
|
||||
return;
|
||||
} // Find current slide
|
||||
|
||||
|
||||
let stopIndex = 0;
|
||||
let groupSize = swiper.slidesSizesGrid[0];
|
||||
|
||||
for (let i = 0; i < slidesGrid.length; i += i < params.slidesPerGroupSkip ? 1 : params.slidesPerGroup) {
|
||||
const increment = i < params.slidesPerGroupSkip - 1 ? 1 : params.slidesPerGroup;
|
||||
|
||||
if (typeof slidesGrid[i + increment] !== 'undefined') {
|
||||
if (currentPos >= slidesGrid[i] && currentPos < slidesGrid[i + increment]) {
|
||||
stopIndex = i;
|
||||
groupSize = slidesGrid[i + increment] - slidesGrid[i];
|
||||
}
|
||||
} else if (currentPos >= slidesGrid[i]) {
|
||||
stopIndex = i;
|
||||
groupSize = slidesGrid[slidesGrid.length - 1] - slidesGrid[slidesGrid.length - 2];
|
||||
}
|
||||
} // Find current slide size
|
||||
|
||||
|
||||
const ratio = (currentPos - slidesGrid[stopIndex]) / groupSize;
|
||||
const increment = stopIndex < params.slidesPerGroupSkip - 1 ? 1 : params.slidesPerGroup;
|
||||
|
||||
if (timeDiff > params.longSwipesMs) {
|
||||
// Long touches
|
||||
if (!params.longSwipes) {
|
||||
swiper.slideTo(swiper.activeIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (swiper.swipeDirection === 'next') {
|
||||
if (ratio >= params.longSwipesRatio) swiper.slideTo(stopIndex + increment);else swiper.slideTo(stopIndex);
|
||||
}
|
||||
|
||||
if (swiper.swipeDirection === 'prev') {
|
||||
if (ratio > 1 - params.longSwipesRatio) swiper.slideTo(stopIndex + increment);else swiper.slideTo(stopIndex);
|
||||
}
|
||||
} else {
|
||||
// Short swipes
|
||||
if (!params.shortSwipes) {
|
||||
swiper.slideTo(swiper.activeIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
const isNavButtonTarget = swiper.navigation && (e.target === swiper.navigation.nextEl || e.target === swiper.navigation.prevEl);
|
||||
|
||||
if (!isNavButtonTarget) {
|
||||
if (swiper.swipeDirection === 'next') {
|
||||
swiper.slideTo(stopIndex + increment);
|
||||
}
|
||||
|
||||
if (swiper.swipeDirection === 'prev') {
|
||||
swiper.slideTo(stopIndex);
|
||||
}
|
||||
} else if (e.target === swiper.navigation.nextEl) {
|
||||
swiper.slideTo(stopIndex + increment);
|
||||
} else {
|
||||
swiper.slideTo(stopIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
import { getDocument } from 'ssr-window';
|
||||
import $ from '../../shared/dom.js';
|
||||
import { now } from '../../shared/utils.js';
|
||||
export default function onTouchMove(event) {
|
||||
const document = getDocument();
|
||||
const swiper = this;
|
||||
const data = swiper.touchEventsData;
|
||||
const {
|
||||
params,
|
||||
touches,
|
||||
rtlTranslate: rtl,
|
||||
enabled
|
||||
} = swiper;
|
||||
if (!enabled) return;
|
||||
let e = event;
|
||||
if (e.originalEvent) e = e.originalEvent;
|
||||
|
||||
if (!data.isTouched) {
|
||||
if (data.startMoving && data.isScrolling) {
|
||||
swiper.emit('touchMoveOpposite', e);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.isTouchEvent && e.type !== 'touchmove') return;
|
||||
const targetTouch = e.type === 'touchmove' && e.targetTouches && (e.targetTouches[0] || e.changedTouches[0]);
|
||||
const pageX = e.type === 'touchmove' ? targetTouch.pageX : e.pageX;
|
||||
const pageY = e.type === 'touchmove' ? targetTouch.pageY : e.pageY;
|
||||
|
||||
if (e.preventedByNestedSwiper) {
|
||||
touches.startX = pageX;
|
||||
touches.startY = pageY;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!swiper.allowTouchMove) {
|
||||
// isMoved = true;
|
||||
swiper.allowClick = false;
|
||||
|
||||
if (data.isTouched) {
|
||||
Object.assign(touches, {
|
||||
startX: pageX,
|
||||
startY: pageY,
|
||||
currentX: pageX,
|
||||
currentY: pageY
|
||||
});
|
||||
data.touchStartTime = now();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.isTouchEvent && params.touchReleaseOnEdges && !params.loop) {
|
||||
if (swiper.isVertical()) {
|
||||
// Vertical
|
||||
if (pageY < touches.startY && swiper.translate <= swiper.maxTranslate() || pageY > touches.startY && swiper.translate >= swiper.minTranslate()) {
|
||||
data.isTouched = false;
|
||||
data.isMoved = false;
|
||||
return;
|
||||
}
|
||||
} else if (pageX < touches.startX && swiper.translate <= swiper.maxTranslate() || pageX > touches.startX && swiper.translate >= swiper.minTranslate()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (data.isTouchEvent && document.activeElement) {
|
||||
if (e.target === document.activeElement && $(e.target).is(data.focusableElements)) {
|
||||
data.isMoved = true;
|
||||
swiper.allowClick = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (data.allowTouchCallbacks) {
|
||||
swiper.emit('touchMove', e);
|
||||
}
|
||||
|
||||
if (e.targetTouches && e.targetTouches.length > 1) return;
|
||||
touches.currentX = pageX;
|
||||
touches.currentY = pageY;
|
||||
const diffX = touches.currentX - touches.startX;
|
||||
const diffY = touches.currentY - touches.startY;
|
||||
if (swiper.params.threshold && Math.sqrt(diffX ** 2 + diffY ** 2) < swiper.params.threshold) return;
|
||||
|
||||
if (typeof data.isScrolling === 'undefined') {
|
||||
let touchAngle;
|
||||
|
||||
if (swiper.isHorizontal() && touches.currentY === touches.startY || swiper.isVertical() && touches.currentX === touches.startX) {
|
||||
data.isScrolling = false;
|
||||
} else {
|
||||
// eslint-disable-next-line
|
||||
if (diffX * diffX + diffY * diffY >= 25) {
|
||||
touchAngle = Math.atan2(Math.abs(diffY), Math.abs(diffX)) * 180 / Math.PI;
|
||||
data.isScrolling = swiper.isHorizontal() ? touchAngle > params.touchAngle : 90 - touchAngle > params.touchAngle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data.isScrolling) {
|
||||
swiper.emit('touchMoveOpposite', e);
|
||||
}
|
||||
|
||||
if (typeof data.startMoving === 'undefined') {
|
||||
if (touches.currentX !== touches.startX || touches.currentY !== touches.startY) {
|
||||
data.startMoving = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (data.isScrolling) {
|
||||
data.isTouched = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.startMoving) {
|
||||
return;
|
||||
}
|
||||
|
||||
swiper.allowClick = false;
|
||||
|
||||
if (!params.cssMode && e.cancelable) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
if (params.touchMoveStopPropagation && !params.nested) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
if (!data.isMoved) {
|
||||
if (params.loop && !params.cssMode) {
|
||||
swiper.loopFix();
|
||||
}
|
||||
|
||||
data.startTranslate = swiper.getTranslate();
|
||||
swiper.setTransition(0);
|
||||
|
||||
if (swiper.animating) {
|
||||
swiper.$wrapperEl.trigger('webkitTransitionEnd transitionend');
|
||||
}
|
||||
|
||||
data.allowMomentumBounce = false; // Grab Cursor
|
||||
|
||||
if (params.grabCursor && (swiper.allowSlideNext === true || swiper.allowSlidePrev === true)) {
|
||||
swiper.setGrabCursor(true);
|
||||
}
|
||||
|
||||
swiper.emit('sliderFirstMove', e);
|
||||
}
|
||||
|
||||
swiper.emit('sliderMove', e);
|
||||
data.isMoved = true;
|
||||
let diff = swiper.isHorizontal() ? diffX : diffY;
|
||||
touches.diff = diff;
|
||||
diff *= params.touchRatio;
|
||||
if (rtl) diff = -diff;
|
||||
swiper.swipeDirection = diff > 0 ? 'prev' : 'next';
|
||||
data.currentTranslate = diff + data.startTranslate;
|
||||
let disableParentSwiper = true;
|
||||
let resistanceRatio = params.resistanceRatio;
|
||||
|
||||
if (params.touchReleaseOnEdges) {
|
||||
resistanceRatio = 0;
|
||||
}
|
||||
|
||||
if (diff > 0 && data.currentTranslate > swiper.minTranslate()) {
|
||||
disableParentSwiper = false;
|
||||
if (params.resistance) data.currentTranslate = swiper.minTranslate() - 1 + (-swiper.minTranslate() + data.startTranslate + diff) ** resistanceRatio;
|
||||
} else if (diff < 0 && data.currentTranslate < swiper.maxTranslate()) {
|
||||
disableParentSwiper = false;
|
||||
if (params.resistance) data.currentTranslate = swiper.maxTranslate() + 1 - (swiper.maxTranslate() - data.startTranslate - diff) ** resistanceRatio;
|
||||
}
|
||||
|
||||
if (disableParentSwiper) {
|
||||
e.preventedByNestedSwiper = true;
|
||||
} // Directions locks
|
||||
|
||||
|
||||
if (!swiper.allowSlideNext && swiper.swipeDirection === 'next' && data.currentTranslate < data.startTranslate) {
|
||||
data.currentTranslate = data.startTranslate;
|
||||
}
|
||||
|
||||
if (!swiper.allowSlidePrev && swiper.swipeDirection === 'prev' && data.currentTranslate > data.startTranslate) {
|
||||
data.currentTranslate = data.startTranslate;
|
||||
}
|
||||
|
||||
if (!swiper.allowSlidePrev && !swiper.allowSlideNext) {
|
||||
data.currentTranslate = data.startTranslate;
|
||||
} // Threshold
|
||||
|
||||
|
||||
if (params.threshold > 0) {
|
||||
if (Math.abs(diff) > params.threshold || data.allowThresholdMove) {
|
||||
if (!data.allowThresholdMove) {
|
||||
data.allowThresholdMove = true;
|
||||
touches.startX = touches.currentX;
|
||||
touches.startY = touches.currentY;
|
||||
data.currentTranslate = data.startTranslate;
|
||||
touches.diff = swiper.isHorizontal() ? touches.currentX - touches.startX : touches.currentY - touches.startY;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
data.currentTranslate = data.startTranslate;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!params.followFinger || params.cssMode) return; // Update active index in free mode
|
||||
|
||||
if (params.freeMode && params.freeMode.enabled && swiper.freeMode || params.watchSlidesProgress) {
|
||||
swiper.updateActiveIndex();
|
||||
swiper.updateSlidesClasses();
|
||||
}
|
||||
|
||||
if (swiper.params.freeMode && params.freeMode.enabled && swiper.freeMode) {
|
||||
swiper.freeMode.onTouchMove();
|
||||
} // Update progress
|
||||
|
||||
|
||||
swiper.updateProgress(data.currentTranslate); // Update translate
|
||||
|
||||
swiper.setTranslate(data.currentTranslate);
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
import { getWindow, getDocument } from 'ssr-window';
|
||||
import $ from '../../shared/dom.js';
|
||||
import { now } from '../../shared/utils.js'; // Modified from https://stackoverflow.com/questions/54520554/custom-element-getrootnode-closest-function-crossing-multiple-parent-shadowd
|
||||
|
||||
function closestElement(selector, base = this) {
|
||||
function __closestFrom(el) {
|
||||
if (!el || el === getDocument() || el === getWindow()) return null;
|
||||
if (el.assignedSlot) el = el.assignedSlot;
|
||||
const found = el.closest(selector);
|
||||
return found || __closestFrom(el.getRootNode().host);
|
||||
}
|
||||
|
||||
return __closestFrom(base);
|
||||
}
|
||||
|
||||
export default function onTouchStart(event) {
|
||||
const swiper = this;
|
||||
const document = getDocument();
|
||||
const window = getWindow();
|
||||
const data = swiper.touchEventsData;
|
||||
const {
|
||||
params,
|
||||
touches,
|
||||
enabled
|
||||
} = swiper;
|
||||
if (!enabled) return;
|
||||
|
||||
if (swiper.animating && params.preventInteractionOnTransition) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!swiper.animating && params.cssMode && params.loop) {
|
||||
swiper.loopFix();
|
||||
}
|
||||
|
||||
let e = event;
|
||||
if (e.originalEvent) e = e.originalEvent;
|
||||
let $targetEl = $(e.target);
|
||||
|
||||
if (params.touchEventsTarget === 'wrapper') {
|
||||
if (!$targetEl.closest(swiper.wrapperEl).length) return;
|
||||
}
|
||||
|
||||
data.isTouchEvent = e.type === 'touchstart';
|
||||
if (!data.isTouchEvent && 'which' in e && e.which === 3) return;
|
||||
if (!data.isTouchEvent && 'button' in e && e.button > 0) return;
|
||||
if (data.isTouched && data.isMoved) return; // change target el for shadow root component
|
||||
|
||||
const swipingClassHasValue = !!params.noSwipingClass && params.noSwipingClass !== '';
|
||||
|
||||
if (swipingClassHasValue && e.target && e.target.shadowRoot && event.path && event.path[0]) {
|
||||
$targetEl = $(event.path[0]);
|
||||
}
|
||||
|
||||
const noSwipingSelector = params.noSwipingSelector ? params.noSwipingSelector : `.${params.noSwipingClass}`;
|
||||
const isTargetShadow = !!(e.target && e.target.shadowRoot); // use closestElement for shadow root element to get the actual closest for nested shadow root element
|
||||
|
||||
if (params.noSwiping && (isTargetShadow ? closestElement(noSwipingSelector, e.target) : $targetEl.closest(noSwipingSelector)[0])) {
|
||||
swiper.allowClick = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.swipeHandler) {
|
||||
if (!$targetEl.closest(params.swipeHandler)[0]) return;
|
||||
}
|
||||
|
||||
touches.currentX = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
|
||||
touches.currentY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
|
||||
const startX = touches.currentX;
|
||||
const startY = touches.currentY; // Do NOT start if iOS edge swipe is detected. Otherwise iOS app cannot swipe-to-go-back anymore
|
||||
|
||||
const edgeSwipeDetection = params.edgeSwipeDetection || params.iOSEdgeSwipeDetection;
|
||||
const edgeSwipeThreshold = params.edgeSwipeThreshold || params.iOSEdgeSwipeThreshold;
|
||||
|
||||
if (edgeSwipeDetection && (startX <= edgeSwipeThreshold || startX >= window.innerWidth - edgeSwipeThreshold)) {
|
||||
if (edgeSwipeDetection === 'prevent') {
|
||||
event.preventDefault();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Object.assign(data, {
|
||||
isTouched: true,
|
||||
isMoved: false,
|
||||
allowTouchCallbacks: true,
|
||||
isScrolling: undefined,
|
||||
startMoving: undefined
|
||||
});
|
||||
touches.startX = startX;
|
||||
touches.startY = startY;
|
||||
data.touchStartTime = now();
|
||||
swiper.allowClick = true;
|
||||
swiper.updateSize();
|
||||
swiper.swipeDirection = undefined;
|
||||
if (params.threshold > 0) data.allowThresholdMove = false;
|
||||
|
||||
if (e.type !== 'touchstart') {
|
||||
let preventDefault = true;
|
||||
if ($targetEl.is(data.focusableElements)) preventDefault = false;
|
||||
|
||||
if (document.activeElement && $(document.activeElement).is(data.focusableElements) && document.activeElement !== $targetEl[0]) {
|
||||
document.activeElement.blur();
|
||||
}
|
||||
|
||||
const shouldPreventDefault = preventDefault && swiper.allowTouchMove && params.touchStartPreventDefault;
|
||||
|
||||
if ((params.touchStartForcePreventDefault || shouldPreventDefault) && !$targetEl[0].isContentEditable) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
swiper.emit('touchStart', e);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import setGrabCursor from './setGrabCursor.js';
|
||||
import unsetGrabCursor from './unsetGrabCursor.js';
|
||||
export default {
|
||||
setGrabCursor,
|
||||
unsetGrabCursor
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
export default function setGrabCursor(moving) {
|
||||
const swiper = this;
|
||||
if (swiper.support.touch || !swiper.params.simulateTouch || swiper.params.watchOverflow && swiper.isLocked || swiper.params.cssMode) return;
|
||||
const el = swiper.params.touchEventsTarget === 'container' ? swiper.el : swiper.wrapperEl;
|
||||
el.style.cursor = 'move';
|
||||
el.style.cursor = moving ? '-webkit-grabbing' : '-webkit-grab';
|
||||
el.style.cursor = moving ? '-moz-grabbin' : '-moz-grab';
|
||||
el.style.cursor = moving ? 'grabbing' : 'grab';
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
export default function unsetGrabCursor() {
|
||||
const swiper = this;
|
||||
|
||||
if (swiper.support.touch || swiper.params.watchOverflow && swiper.isLocked || swiper.params.cssMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
swiper[swiper.params.touchEventsTarget === 'container' ? 'el' : 'wrapperEl'].style.cursor = '';
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import loadImage from './loadImage.js';
|
||||
import preloadImages from './preloadImages.js';
|
||||
export default {
|
||||
loadImage,
|
||||
preloadImages
|
||||
};
|
||||
@@ -1,37 +0,0 @@
|
||||
import { getWindow } from 'ssr-window';
|
||||
import $ from '../../shared/dom.js';
|
||||
export default function loadImage(imageEl, src, srcset, sizes, checkForComplete, callback) {
|
||||
const window = getWindow();
|
||||
let image;
|
||||
|
||||
function onReady() {
|
||||
if (callback) callback();
|
||||
}
|
||||
|
||||
const isPicture = $(imageEl).parent('picture')[0];
|
||||
|
||||
if (!isPicture && (!imageEl.complete || !checkForComplete)) {
|
||||
if (src) {
|
||||
image = new window.Image();
|
||||
image.onload = onReady;
|
||||
image.onerror = onReady;
|
||||
|
||||
if (sizes) {
|
||||
image.sizes = sizes;
|
||||
}
|
||||
|
||||
if (srcset) {
|
||||
image.srcset = srcset;
|
||||
}
|
||||
|
||||
if (src) {
|
||||
image.src = src;
|
||||
}
|
||||
} else {
|
||||
onReady();
|
||||
}
|
||||
} else {
|
||||
// image already loaded...
|
||||
onReady();
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
export default function preloadImages() {
|
||||
const swiper = this;
|
||||
swiper.imagesToLoad = swiper.$el.find('img');
|
||||
|
||||
function onReady() {
|
||||
if (typeof swiper === 'undefined' || swiper === null || !swiper || swiper.destroyed) return;
|
||||
if (swiper.imagesLoaded !== undefined) swiper.imagesLoaded += 1;
|
||||
|
||||
if (swiper.imagesLoaded === swiper.imagesToLoad.length) {
|
||||
if (swiper.params.updateOnImagesReady) swiper.update();
|
||||
swiper.emit('imagesReady');
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < swiper.imagesToLoad.length; i += 1) {
|
||||
const imageEl = swiper.imagesToLoad[i];
|
||||
swiper.loadImage(imageEl, imageEl.currentSrc || imageEl.getAttribute('src'), imageEl.srcset || imageEl.getAttribute('srcset'), imageEl.sizes || imageEl.getAttribute('sizes'), true, onReady);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import loopCreate from './loopCreate.js';
|
||||
import loopFix from './loopFix.js';
|
||||
import loopDestroy from './loopDestroy.js';
|
||||
export default {
|
||||
loopCreate,
|
||||
loopFix,
|
||||
loopDestroy
|
||||
};
|
||||
@@ -1,59 +0,0 @@
|
||||
import { getDocument } from 'ssr-window';
|
||||
import $ from '../../shared/dom.js';
|
||||
export default function loopCreate() {
|
||||
const swiper = this;
|
||||
const document = getDocument();
|
||||
const {
|
||||
params,
|
||||
$wrapperEl
|
||||
} = swiper; // Remove duplicated slides
|
||||
|
||||
const $selector = $($wrapperEl.children()[0].parentNode);
|
||||
$selector.children(`.${params.slideClass}.${params.slideDuplicateClass}`).remove();
|
||||
let slides = $selector.children(`.${params.slideClass}`);
|
||||
|
||||
if (params.loopFillGroupWithBlank) {
|
||||
const blankSlidesNum = params.slidesPerGroup - slides.length % params.slidesPerGroup;
|
||||
|
||||
if (blankSlidesNum !== params.slidesPerGroup) {
|
||||
for (let i = 0; i < blankSlidesNum; i += 1) {
|
||||
const blankNode = $(document.createElement('div')).addClass(`${params.slideClass} ${params.slideBlankClass}`);
|
||||
$selector.append(blankNode);
|
||||
}
|
||||
|
||||
slides = $selector.children(`.${params.slideClass}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (params.slidesPerView === 'auto' && !params.loopedSlides) params.loopedSlides = slides.length;
|
||||
swiper.loopedSlides = Math.ceil(parseFloat(params.loopedSlides || params.slidesPerView, 10));
|
||||
swiper.loopedSlides += params.loopAdditionalSlides;
|
||||
|
||||
if (swiper.loopedSlides > slides.length) {
|
||||
swiper.loopedSlides = slides.length;
|
||||
}
|
||||
|
||||
const prependSlides = [];
|
||||
const appendSlides = [];
|
||||
slides.each((el, index) => {
|
||||
const slide = $(el);
|
||||
|
||||
if (index < swiper.loopedSlides) {
|
||||
appendSlides.push(el);
|
||||
}
|
||||
|
||||
if (index < slides.length && index >= slides.length - swiper.loopedSlides) {
|
||||
prependSlides.push(el);
|
||||
}
|
||||
|
||||
slide.attr('data-swiper-slide-index', index);
|
||||
});
|
||||
|
||||
for (let i = 0; i < appendSlides.length; i += 1) {
|
||||
$selector.append($(appendSlides[i].cloneNode(true)).addClass(params.slideDuplicateClass));
|
||||
}
|
||||
|
||||
for (let i = prependSlides.length - 1; i >= 0; i -= 1) {
|
||||
$selector.prepend($(prependSlides[i].cloneNode(true)).addClass(params.slideDuplicateClass));
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
export default function loopDestroy() {
|
||||
const swiper = this;
|
||||
const {
|
||||
$wrapperEl,
|
||||
params,
|
||||
slides
|
||||
} = swiper;
|
||||
$wrapperEl.children(`.${params.slideClass}.${params.slideDuplicateClass},.${params.slideClass}.${params.slideBlankClass}`).remove();
|
||||
slides.removeAttr('data-swiper-slide-index');
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
export default function loopFix() {
|
||||
const swiper = this;
|
||||
swiper.emit('beforeLoopFix');
|
||||
const {
|
||||
activeIndex,
|
||||
slides,
|
||||
loopedSlides,
|
||||
allowSlidePrev,
|
||||
allowSlideNext,
|
||||
snapGrid,
|
||||
rtlTranslate: rtl
|
||||
} = swiper;
|
||||
let newIndex;
|
||||
swiper.allowSlidePrev = true;
|
||||
swiper.allowSlideNext = true;
|
||||
const snapTranslate = -snapGrid[activeIndex];
|
||||
const diff = snapTranslate - swiper.getTranslate(); // Fix For Negative Oversliding
|
||||
|
||||
if (activeIndex < loopedSlides) {
|
||||
newIndex = slides.length - loopedSlides * 3 + activeIndex;
|
||||
newIndex += loopedSlides;
|
||||
const slideChanged = swiper.slideTo(newIndex, 0, false, true);
|
||||
|
||||
if (slideChanged && diff !== 0) {
|
||||
swiper.setTranslate((rtl ? -swiper.translate : swiper.translate) - diff);
|
||||
}
|
||||
} else if (activeIndex >= slides.length - loopedSlides) {
|
||||
// Fix For Positive Oversliding
|
||||
newIndex = -slides.length + activeIndex + loopedSlides;
|
||||
newIndex += loopedSlides;
|
||||
const slideChanged = swiper.slideTo(newIndex, 0, false, true);
|
||||
|
||||
if (slideChanged && diff !== 0) {
|
||||
swiper.setTranslate((rtl ? -swiper.translate : swiper.translate) - diff);
|
||||
}
|
||||
}
|
||||
|
||||
swiper.allowSlidePrev = allowSlidePrev;
|
||||
swiper.allowSlideNext = allowSlideNext;
|
||||
swiper.emit('loopFix');
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import { extend } from '../shared/utils.js';
|
||||
export default function moduleExtendParams(params, allModulesParams) {
|
||||
return function extendParams(obj = {}) {
|
||||
const moduleParamName = Object.keys(obj)[0];
|
||||
const moduleParams = obj[moduleParamName];
|
||||
|
||||
if (typeof moduleParams !== 'object' || moduleParams === null) {
|
||||
extend(allModulesParams, obj);
|
||||
return;
|
||||
}
|
||||
|
||||
if (['navigation', 'pagination', 'scrollbar'].indexOf(moduleParamName) >= 0 && params[moduleParamName] === true) {
|
||||
params[moduleParamName] = {
|
||||
auto: true
|
||||
};
|
||||
}
|
||||
|
||||
if (!(moduleParamName in params && 'enabled' in moduleParams)) {
|
||||
extend(allModulesParams, obj);
|
||||
return;
|
||||
}
|
||||
|
||||
if (params[moduleParamName] === true) {
|
||||
params[moduleParamName] = {
|
||||
enabled: true
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof params[moduleParamName] === 'object' && !('enabled' in params[moduleParamName])) {
|
||||
params[moduleParamName].enabled = true;
|
||||
}
|
||||
|
||||
if (!params[moduleParamName]) params[moduleParamName] = {
|
||||
enabled: false
|
||||
};
|
||||
extend(allModulesParams, obj);
|
||||
};
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
import { getWindow } from 'ssr-window';
|
||||
export default function Observer({
|
||||
swiper,
|
||||
extendParams,
|
||||
on,
|
||||
emit
|
||||
}) {
|
||||
const observers = [];
|
||||
const window = getWindow();
|
||||
|
||||
const attach = (target, options = {}) => {
|
||||
const ObserverFunc = window.MutationObserver || window.WebkitMutationObserver;
|
||||
const observer = new ObserverFunc(mutations => {
|
||||
// The observerUpdate event should only be triggered
|
||||
// once despite the number of mutations. Additional
|
||||
// triggers are redundant and are very costly
|
||||
if (mutations.length === 1) {
|
||||
emit('observerUpdate', mutations[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
const observerUpdate = function observerUpdate() {
|
||||
emit('observerUpdate', mutations[0]);
|
||||
};
|
||||
|
||||
if (window.requestAnimationFrame) {
|
||||
window.requestAnimationFrame(observerUpdate);
|
||||
} else {
|
||||
window.setTimeout(observerUpdate, 0);
|
||||
}
|
||||
});
|
||||
observer.observe(target, {
|
||||
attributes: typeof options.attributes === 'undefined' ? true : options.attributes,
|
||||
childList: typeof options.childList === 'undefined' ? true : options.childList,
|
||||
characterData: typeof options.characterData === 'undefined' ? true : options.characterData
|
||||
});
|
||||
observers.push(observer);
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
if (!swiper.params.observer) return;
|
||||
|
||||
if (swiper.params.observeParents) {
|
||||
const containerParents = swiper.$el.parents();
|
||||
|
||||
for (let i = 0; i < containerParents.length; i += 1) {
|
||||
attach(containerParents[i]);
|
||||
}
|
||||
} // Observe container
|
||||
|
||||
|
||||
attach(swiper.$el[0], {
|
||||
childList: swiper.params.observeSlideChildren
|
||||
}); // Observe wrapper
|
||||
|
||||
attach(swiper.$wrapperEl[0], {
|
||||
attributes: false
|
||||
});
|
||||
};
|
||||
|
||||
const destroy = () => {
|
||||
observers.forEach(observer => {
|
||||
observer.disconnect();
|
||||
});
|
||||
observers.splice(0, observers.length);
|
||||
};
|
||||
|
||||
extendParams({
|
||||
observer: false,
|
||||
observeParents: false,
|
||||
observeSlideChildren: false
|
||||
});
|
||||
on('init', init);
|
||||
on('destroy', destroy);
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
import { getWindow } from 'ssr-window';
|
||||
export default function Resize({
|
||||
swiper,
|
||||
on,
|
||||
emit
|
||||
}) {
|
||||
const window = getWindow();
|
||||
let observer = null;
|
||||
|
||||
const resizeHandler = () => {
|
||||
if (!swiper || swiper.destroyed || !swiper.initialized) return;
|
||||
emit('beforeResize');
|
||||
emit('resize');
|
||||
};
|
||||
|
||||
const createObserver = () => {
|
||||
if (!swiper || swiper.destroyed || !swiper.initialized) return;
|
||||
observer = new ResizeObserver(entries => {
|
||||
const {
|
||||
width,
|
||||
height
|
||||
} = swiper;
|
||||
let newWidth = width;
|
||||
let newHeight = height;
|
||||
entries.forEach(({
|
||||
contentBoxSize,
|
||||
contentRect,
|
||||
target
|
||||
}) => {
|
||||
if (target && target !== swiper.el) return;
|
||||
newWidth = contentRect ? contentRect.width : (contentBoxSize[0] || contentBoxSize).inlineSize;
|
||||
newHeight = contentRect ? contentRect.height : (contentBoxSize[0] || contentBoxSize).blockSize;
|
||||
});
|
||||
|
||||
if (newWidth !== width || newHeight !== height) {
|
||||
resizeHandler();
|
||||
}
|
||||
});
|
||||
observer.observe(swiper.el);
|
||||
};
|
||||
|
||||
const removeObserver = () => {
|
||||
if (observer && observer.unobserve && swiper.el) {
|
||||
observer.unobserve(swiper.el);
|
||||
observer = null;
|
||||
}
|
||||
};
|
||||
|
||||
const orientationChangeHandler = () => {
|
||||
if (!swiper || swiper.destroyed || !swiper.initialized) return;
|
||||
emit('orientationchange');
|
||||
};
|
||||
|
||||
on('init', () => {
|
||||
if (swiper.params.resizeObserver && typeof window.ResizeObserver !== 'undefined') {
|
||||
createObserver();
|
||||
return;
|
||||
}
|
||||
|
||||
window.addEventListener('resize', resizeHandler);
|
||||
window.addEventListener('orientationchange', orientationChangeHandler);
|
||||
});
|
||||
on('destroy', () => {
|
||||
removeObserver();
|
||||
window.removeEventListener('resize', resizeHandler);
|
||||
window.removeEventListener('orientationchange', orientationChangeHandler);
|
||||
});
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import slideTo from './slideTo.js';
|
||||
import slideToLoop from './slideToLoop.js';
|
||||
import slideNext from './slideNext.js';
|
||||
import slidePrev from './slidePrev.js';
|
||||
import slideReset from './slideReset.js';
|
||||
import slideToClosest from './slideToClosest.js';
|
||||
import slideToClickedSlide from './slideToClickedSlide.js';
|
||||
export default {
|
||||
slideTo,
|
||||
slideToLoop,
|
||||
slideNext,
|
||||
slidePrev,
|
||||
slideReset,
|
||||
slideToClosest,
|
||||
slideToClickedSlide
|
||||
};
|
||||
@@ -1,26 +0,0 @@
|
||||
/* eslint no-unused-vars: "off" */
|
||||
export default function slideNext(speed = this.params.speed, runCallbacks = true, internal) {
|
||||
const swiper = this;
|
||||
const {
|
||||
animating,
|
||||
enabled,
|
||||
params
|
||||
} = swiper;
|
||||
if (!enabled) return swiper;
|
||||
let perGroup = params.slidesPerGroup;
|
||||
|
||||
if (params.slidesPerView === 'auto' && params.slidesPerGroup === 1 && params.slidesPerGroupAuto) {
|
||||
perGroup = Math.max(swiper.slidesPerViewDynamic('current', true), 1);
|
||||
}
|
||||
|
||||
const increment = swiper.activeIndex < params.slidesPerGroupSkip ? 1 : perGroup;
|
||||
|
||||
if (params.loop) {
|
||||
if (animating && params.loopPreventsSlide) return false;
|
||||
swiper.loopFix(); // eslint-disable-next-line
|
||||
|
||||
swiper._clientLeft = swiper.$wrapperEl[0].clientLeft;
|
||||
}
|
||||
|
||||
return swiper.slideTo(swiper.activeIndex + increment, speed, runCallbacks, internal);
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/* eslint no-unused-vars: "off" */
|
||||
export default function slidePrev(speed = this.params.speed, runCallbacks = true, internal) {
|
||||
const swiper = this;
|
||||
const {
|
||||
params,
|
||||
animating,
|
||||
snapGrid,
|
||||
slidesGrid,
|
||||
rtlTranslate,
|
||||
enabled
|
||||
} = swiper;
|
||||
if (!enabled) return swiper;
|
||||
|
||||
if (params.loop) {
|
||||
if (animating && params.loopPreventsSlide) return false;
|
||||
swiper.loopFix(); // eslint-disable-next-line
|
||||
|
||||
swiper._clientLeft = swiper.$wrapperEl[0].clientLeft;
|
||||
}
|
||||
|
||||
const translate = rtlTranslate ? swiper.translate : -swiper.translate;
|
||||
|
||||
function normalize(val) {
|
||||
if (val < 0) return -Math.floor(Math.abs(val));
|
||||
return Math.floor(val);
|
||||
}
|
||||
|
||||
const normalizedTranslate = normalize(translate);
|
||||
const normalizedSnapGrid = snapGrid.map(val => normalize(val));
|
||||
let prevSnap = snapGrid[normalizedSnapGrid.indexOf(normalizedTranslate) - 1];
|
||||
|
||||
if (typeof prevSnap === 'undefined' && params.cssMode) {
|
||||
let prevSnapIndex;
|
||||
snapGrid.forEach((snap, snapIndex) => {
|
||||
if (normalizedTranslate >= snap) {
|
||||
// prevSnap = snap;
|
||||
prevSnapIndex = snapIndex;
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof prevSnapIndex !== 'undefined') {
|
||||
prevSnap = snapGrid[prevSnapIndex > 0 ? prevSnapIndex - 1 : prevSnapIndex];
|
||||
}
|
||||
}
|
||||
|
||||
let prevIndex = 0;
|
||||
|
||||
if (typeof prevSnap !== 'undefined') {
|
||||
prevIndex = slidesGrid.indexOf(prevSnap);
|
||||
if (prevIndex < 0) prevIndex = swiper.activeIndex - 1;
|
||||
|
||||
if (params.slidesPerView === 'auto' && params.slidesPerGroup === 1 && params.slidesPerGroupAuto) {
|
||||
prevIndex = prevIndex - swiper.slidesPerViewDynamic('previous', true) + 1;
|
||||
prevIndex = Math.max(prevIndex, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return swiper.slideTo(prevIndex, speed, runCallbacks, internal);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
/* eslint no-unused-vars: "off" */
|
||||
export default function slideReset(speed = this.params.speed, runCallbacks = true, internal) {
|
||||
const swiper = this;
|
||||
return swiper.slideTo(swiper.activeIndex, speed, runCallbacks, internal);
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
import { animateCSSModeScroll } from '../../shared/utils.js';
|
||||
export default function slideTo(index = 0, speed = this.params.speed, runCallbacks = true, internal, initial) {
|
||||
if (typeof index !== 'number' && typeof index !== 'string') {
|
||||
throw new Error(`The 'index' argument cannot have type other than 'number' or 'string'. [${typeof index}] given.`);
|
||||
}
|
||||
|
||||
if (typeof index === 'string') {
|
||||
/**
|
||||
* The `index` argument converted from `string` to `number`.
|
||||
* @type {number}
|
||||
*/
|
||||
const indexAsNumber = parseInt(index, 10);
|
||||
/**
|
||||
* Determines whether the `index` argument is a valid `number`
|
||||
* after being converted from the `string` type.
|
||||
* @type {boolean}
|
||||
*/
|
||||
|
||||
const isValidNumber = isFinite(indexAsNumber);
|
||||
|
||||
if (!isValidNumber) {
|
||||
throw new Error(`The passed-in 'index' (string) couldn't be converted to 'number'. [${index}] given.`);
|
||||
} // Knowing that the converted `index` is a valid number,
|
||||
// we can update the original argument's value.
|
||||
|
||||
|
||||
index = indexAsNumber;
|
||||
}
|
||||
|
||||
const swiper = this;
|
||||
let slideIndex = index;
|
||||
if (slideIndex < 0) slideIndex = 0;
|
||||
const {
|
||||
params,
|
||||
snapGrid,
|
||||
slidesGrid,
|
||||
previousIndex,
|
||||
activeIndex,
|
||||
rtlTranslate: rtl,
|
||||
wrapperEl,
|
||||
enabled
|
||||
} = swiper;
|
||||
|
||||
if (swiper.animating && params.preventInteractionOnTransition || !enabled && !internal && !initial) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const skip = Math.min(swiper.params.slidesPerGroupSkip, slideIndex);
|
||||
let snapIndex = skip + Math.floor((slideIndex - skip) / swiper.params.slidesPerGroup);
|
||||
if (snapIndex >= snapGrid.length) snapIndex = snapGrid.length - 1;
|
||||
|
||||
if ((activeIndex || params.initialSlide || 0) === (previousIndex || 0) && runCallbacks) {
|
||||
swiper.emit('beforeSlideChangeStart');
|
||||
}
|
||||
|
||||
const translate = -snapGrid[snapIndex]; // Update progress
|
||||
|
||||
swiper.updateProgress(translate); // Normalize slideIndex
|
||||
|
||||
if (params.normalizeSlideIndex) {
|
||||
for (let i = 0; i < slidesGrid.length; i += 1) {
|
||||
const normalizedTranslate = -Math.floor(translate * 100);
|
||||
const normalizedGrid = Math.floor(slidesGrid[i] * 100);
|
||||
const normalizedGridNext = Math.floor(slidesGrid[i + 1] * 100);
|
||||
|
||||
if (typeof slidesGrid[i + 1] !== 'undefined') {
|
||||
if (normalizedTranslate >= normalizedGrid && normalizedTranslate < normalizedGridNext - (normalizedGridNext - normalizedGrid) / 2) {
|
||||
slideIndex = i;
|
||||
} else if (normalizedTranslate >= normalizedGrid && normalizedTranslate < normalizedGridNext) {
|
||||
slideIndex = i + 1;
|
||||
}
|
||||
} else if (normalizedTranslate >= normalizedGrid) {
|
||||
slideIndex = i;
|
||||
}
|
||||
}
|
||||
} // Directions locks
|
||||
|
||||
|
||||
if (swiper.initialized && slideIndex !== activeIndex) {
|
||||
if (!swiper.allowSlideNext && translate < swiper.translate && translate < swiper.minTranslate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!swiper.allowSlidePrev && translate > swiper.translate && translate > swiper.maxTranslate()) {
|
||||
if ((activeIndex || 0) !== slideIndex) return false;
|
||||
}
|
||||
}
|
||||
|
||||
let direction;
|
||||
if (slideIndex > activeIndex) direction = 'next';else if (slideIndex < activeIndex) direction = 'prev';else direction = 'reset'; // Update Index
|
||||
|
||||
if (rtl && -translate === swiper.translate || !rtl && translate === swiper.translate) {
|
||||
swiper.updateActiveIndex(slideIndex); // Update Height
|
||||
|
||||
if (params.autoHeight) {
|
||||
swiper.updateAutoHeight();
|
||||
}
|
||||
|
||||
swiper.updateSlidesClasses();
|
||||
|
||||
if (params.effect !== 'slide') {
|
||||
swiper.setTranslate(translate);
|
||||
}
|
||||
|
||||
if (direction !== 'reset') {
|
||||
swiper.transitionStart(runCallbacks, direction);
|
||||
swiper.transitionEnd(runCallbacks, direction);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (params.cssMode) {
|
||||
const isH = swiper.isHorizontal();
|
||||
const t = rtl ? translate : -translate;
|
||||
|
||||
if (speed === 0) {
|
||||
const isVirtual = swiper.virtual && swiper.params.virtual.enabled;
|
||||
|
||||
if (isVirtual) {
|
||||
swiper.wrapperEl.style.scrollSnapType = 'none';
|
||||
swiper._immediateVirtual = true;
|
||||
}
|
||||
|
||||
wrapperEl[isH ? 'scrollLeft' : 'scrollTop'] = t;
|
||||
|
||||
if (isVirtual) {
|
||||
requestAnimationFrame(() => {
|
||||
swiper.wrapperEl.style.scrollSnapType = '';
|
||||
swiper._swiperImmediateVirtual = false;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (!swiper.support.smoothScroll) {
|
||||
animateCSSModeScroll({
|
||||
swiper,
|
||||
targetPosition: t,
|
||||
side: isH ? 'left' : 'top'
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
wrapperEl.scrollTo({
|
||||
[isH ? 'left' : 'top']: t,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (speed === 0) {
|
||||
swiper.setTransition(0);
|
||||
swiper.setTranslate(translate);
|
||||
swiper.updateActiveIndex(slideIndex);
|
||||
swiper.updateSlidesClasses();
|
||||
swiper.emit('beforeTransitionStart', speed, internal);
|
||||
swiper.transitionStart(runCallbacks, direction);
|
||||
swiper.transitionEnd(runCallbacks, direction);
|
||||
} else {
|
||||
swiper.setTransition(speed);
|
||||
swiper.setTranslate(translate);
|
||||
swiper.updateActiveIndex(slideIndex);
|
||||
swiper.updateSlidesClasses();
|
||||
swiper.emit('beforeTransitionStart', speed, internal);
|
||||
swiper.transitionStart(runCallbacks, direction);
|
||||
|
||||
if (!swiper.animating) {
|
||||
swiper.animating = true;
|
||||
|
||||
if (!swiper.onSlideToWrapperTransitionEnd) {
|
||||
swiper.onSlideToWrapperTransitionEnd = function transitionEnd(e) {
|
||||
if (!swiper || swiper.destroyed) return;
|
||||
if (e.target !== this) return;
|
||||
swiper.$wrapperEl[0].removeEventListener('transitionend', swiper.onSlideToWrapperTransitionEnd);
|
||||
swiper.$wrapperEl[0].removeEventListener('webkitTransitionEnd', swiper.onSlideToWrapperTransitionEnd);
|
||||
swiper.onSlideToWrapperTransitionEnd = null;
|
||||
delete swiper.onSlideToWrapperTransitionEnd;
|
||||
swiper.transitionEnd(runCallbacks, direction);
|
||||
};
|
||||
}
|
||||
|
||||
swiper.$wrapperEl[0].addEventListener('transitionend', swiper.onSlideToWrapperTransitionEnd);
|
||||
swiper.$wrapperEl[0].addEventListener('webkitTransitionEnd', swiper.onSlideToWrapperTransitionEnd);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
import $ from '../../shared/dom.js';
|
||||
import { nextTick } from '../../shared/utils.js';
|
||||
export default function slideToClickedSlide() {
|
||||
const swiper = this;
|
||||
const {
|
||||
params,
|
||||
$wrapperEl
|
||||
} = swiper;
|
||||
const slidesPerView = params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : params.slidesPerView;
|
||||
let slideToIndex = swiper.clickedIndex;
|
||||
let realIndex;
|
||||
|
||||
if (params.loop) {
|
||||
if (swiper.animating) return;
|
||||
realIndex = parseInt($(swiper.clickedSlide).attr('data-swiper-slide-index'), 10);
|
||||
|
||||
if (params.centeredSlides) {
|
||||
if (slideToIndex < swiper.loopedSlides - slidesPerView / 2 || slideToIndex > swiper.slides.length - swiper.loopedSlides + slidesPerView / 2) {
|
||||
swiper.loopFix();
|
||||
slideToIndex = $wrapperEl.children(`.${params.slideClass}[data-swiper-slide-index="${realIndex}"]:not(.${params.slideDuplicateClass})`).eq(0).index();
|
||||
nextTick(() => {
|
||||
swiper.slideTo(slideToIndex);
|
||||
});
|
||||
} else {
|
||||
swiper.slideTo(slideToIndex);
|
||||
}
|
||||
} else if (slideToIndex > swiper.slides.length - slidesPerView) {
|
||||
swiper.loopFix();
|
||||
slideToIndex = $wrapperEl.children(`.${params.slideClass}[data-swiper-slide-index="${realIndex}"]:not(.${params.slideDuplicateClass})`).eq(0).index();
|
||||
nextTick(() => {
|
||||
swiper.slideTo(slideToIndex);
|
||||
});
|
||||
} else {
|
||||
swiper.slideTo(slideToIndex);
|
||||
}
|
||||
} else {
|
||||
swiper.slideTo(slideToIndex);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/* eslint no-unused-vars: "off" */
|
||||
export default function slideToClosest(speed = this.params.speed, runCallbacks = true, internal, threshold = 0.5) {
|
||||
const swiper = this;
|
||||
let index = swiper.activeIndex;
|
||||
const skip = Math.min(swiper.params.slidesPerGroupSkip, index);
|
||||
const snapIndex = skip + Math.floor((index - skip) / swiper.params.slidesPerGroup);
|
||||
const translate = swiper.rtlTranslate ? swiper.translate : -swiper.translate;
|
||||
|
||||
if (translate >= swiper.snapGrid[snapIndex]) {
|
||||
// The current translate is on or after the current snap index, so the choice
|
||||
// is between the current index and the one after it.
|
||||
const currentSnap = swiper.snapGrid[snapIndex];
|
||||
const nextSnap = swiper.snapGrid[snapIndex + 1];
|
||||
|
||||
if (translate - currentSnap > (nextSnap - currentSnap) * threshold) {
|
||||
index += swiper.params.slidesPerGroup;
|
||||
}
|
||||
} else {
|
||||
// The current translate is before the current snap index, so the choice
|
||||
// is between the current index and the one before it.
|
||||
const prevSnap = swiper.snapGrid[snapIndex - 1];
|
||||
const currentSnap = swiper.snapGrid[snapIndex];
|
||||
|
||||
if (translate - prevSnap <= (currentSnap - prevSnap) * threshold) {
|
||||
index -= swiper.params.slidesPerGroup;
|
||||
}
|
||||
}
|
||||
|
||||
index = Math.max(index, 0);
|
||||
index = Math.min(index, swiper.slidesGrid.length - 1);
|
||||
return swiper.slideTo(index, speed, runCallbacks, internal);
|
||||
}
|
||||