diff --git a/.gitignore b/.gitignore index 08d024f5e6..ed5c657ad9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,6 @@ *.pyc /build/ -/examples/*.html.png -/examples/example-list.js -/examples/example-list.xml +/examples/ /node_modules/ /dist/ /coverage/ diff --git a/config/examples/example-verbatim.html b/config/examples/example-verbatim.html new file mode 100644 index 0000000000..649a88cea0 --- /dev/null +++ b/config/examples/example-verbatim.html @@ -0,0 +1 @@ +{{{ contents }}} diff --git a/config/examples/example.html b/config/examples/example.html new file mode 100644 index 0000000000..a72220b572 --- /dev/null +++ b/config/examples/example.html @@ -0,0 +1,91 @@ + + + + + + + + + + + {{{ resources }}} + {{{ css_resource }}} + + + {{ title }} + + + + + +
+ + {{{ contents }}} + +
+ +
+

{{ title }}

+

{{ shortdesc }}

+
+ {{{ docs }}} +
+
{{ tags }}
+
+ +
+ +
+
+
+ + + + + + + +
<!DOCTYPE html>
+<html>
+<head>
+<title>{{ title }}</title>
+<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
+<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
+<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ol3/{{ ol_version }}/ol.css" type="text/css">
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ol3/{{ ol_version }}/ol.js"></script>
+{{ resources }}
+{{#if css_inline}}
+<style>
+{{ css_inline }}
+</style>
+{{/if}}
+</head>
+<body>
+<div class="container-fluid">
+
+{{ contents }}
+</div>
+<script>
+{{ js_inline }}
+</script>
+</body>
+</html>
+
+
+ + + + + + + {{{ js_resource }}} + + + diff --git a/examples/readme.md b/config/examples/readme.md similarity index 76% rename from examples/readme.md rename to config/examples/readme.md index bfce29d564..796f500932 100644 --- a/examples/readme.md +++ b/config/examples/readme.md @@ -1,4 +1,4 @@ -# Code examples +This folder contains example templates. These templates are used to build the examples in `examples_src/` folder. The resulting examples are written to the `examples/` folder. Although the main purpose of these examples is to demonstrate how to use the API, they also serve other purposes in the development cycle, and so are not exactly as they would be in normal application code: @@ -13,4 +13,4 @@ To enable this, examples have the following, not needed in application code: * html files load `example-behaviour.js` and some js files define the Map renderer option as `exampleNS.getRendererFromQueryString()`; application code would not need these * in addition, examples use Twitter Bootstrap and jQuery; this is of course not a requirement - you may use whichever presentation/helper libraries you wish -See [Quick Start tutorial](http://openlayers.org/en/master/doc/quickstart.html) for a simple example of how application code would use the library. +At the bottom of each example generated in the `examples/` folder, a modified version of its source code is shown. That modified version can be run standalone and is usually used as starting point for users to extend examples into their own application. diff --git a/examples/accessible.html b/examples/accessible.html deleted file mode 100644 index 71e821d804..0000000000 --- a/examples/accessible.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - Accessibility example - - - - - - -
- -
-
- -
-
-
- -
- -
-

Accessibility example

-

Example of an accessible map.

-
-

This page's map element has its tabindex attribute set to "0", that makes it focusable. To focus the map element you can either navigate to it using the "tab" key or use the skip link. When the map element is focused the + and - keys can be used to zoom in and out and the arrow keys can be used to pan.

-

When clicked the "Zoom in" and "Zoom out" buttons below the map zoom the map in and out, respectively. You can navigate to the buttons using the "tab" key, and press the "enter" key to trigger the zooming action.

-

See the accessible.js source to see how this is done.

-
-
accessibility, tabindex
-
- -
- -
- - - - - - - diff --git a/examples/animation.html b/examples/animation.html deleted file mode 100644 index d072983e10..0000000000 --- a/examples/animation.html +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - Animation example - - - - - -
- -
-
-
-
-
- -
-
- - - - - - - - - -
-
- -
- -
-

Animation example

-

Demonstrates animated pan, zoom, and rotation.

-
-

See the animation.js source to see how this is done.

-
-
animation
-
- -
- -
- - - - - - - diff --git a/examples/arcgis-tiled.html b/examples/arcgis-tiled.html deleted file mode 100644 index d922b78ca3..0000000000 --- a/examples/arcgis-tiled.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - Tiled ArcGIS MapServer example - - - - - -
- -
-
-
-
-
- -
- -
-

Tiled ArcGIS MapServer example

-

Example of a tiled ArcGIS layer.

-
-

See the arcgis-tiled.js source to see how this is done.

-
-
arcgis, tile, tilelayer
-
- -
- -
- - - - - - - diff --git a/examples/attributions.html b/examples/attributions.html deleted file mode 100644 index 1ab192dce4..0000000000 --- a/examples/attributions.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - Attributions example - - - - - -
- -
-
-
-
-
- -
- -
-

Attributions example

-

Example of a attributions visibily change on map resize, to collapse them on small maps.

-
-

See the attributions.js source to see how this is done.

-
-
attributions, openstreetmap
-
- -
- -
- - - - - - - diff --git a/examples/bind-input.html b/examples/bind-input.html deleted file mode 100644 index 341c4ddbc5..0000000000 --- a/examples/bind-input.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - - - - - - - - Bind HTML input example - - - - - -
- -
-
-
-
-
- -
- -
-

Bind HTML input example

-

Demonstrates two-way binding of HTML input elements to OpenLayers objects.

-
-

See the bind-input.js source to see how this is done.

- - -
-
input, bind, openstreetmap
-
- -
- -
- Layer - - - -
- - -
- -
-
-
- View - - - - -
-
-
- -
- -
- - - - - - - diff --git a/examples/bing-maps.html b/examples/bing-maps.html deleted file mode 100644 index a97c1dadcb..0000000000 --- a/examples/bing-maps.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - Bing Maps example - - - - - -
- -
-
-
- - -
-
- -
- -
-

Bing Maps example

-

Example of a Bing Maps layer.

-
-

When the Bing Maps tile service doesn't have tiles for a given resolution and region it returns "placeholder" tiles indicating that. Zoom the map beyond level 19 to see the "placeholder" tiles. If you want OpenLayers to display stretched tiles in place of "placeholder" tiles beyond zoom level 19 then set maxZoom to 19 in the options passed to ol.source.BingMaps.

-

See the bing-maps.js source to see how this is done.

-
-
bing, bing-maps
-
- -
- -
- - - - - - - diff --git a/examples/box-selection.html b/examples/box-selection.html deleted file mode 100644 index 4fd498b1b6..0000000000 --- a/examples/box-selection.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - Box selection example - - - - - -
- -
-
-
-
-
- -
- -
-

Box selection example

-

Using a DragBox interaction to select features.

-
-

This example shows how to use a DragBox interaction to select features. Selected features are added - to the feature overlay of a select interaction (ol.interaction.Select) for highlighting.

-

Use SHIFT+drag to draw boxes.

-

See the box-selection.js source to see how this is done.

-
-
DragBox, feature, selection, box
-
-
-
-   -
-
- -
- -
- - - - - - - diff --git a/examples/brightness-contrast.html b/examples/brightness-contrast.html deleted file mode 100644 index fb499eeba1..0000000000 --- a/examples/brightness-contrast.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - Brightness/contrast example - - - - - - -
- -
-
-
- - - -
- - - -
-
- - - -
-
-
- -
- -
-

Brightness/contrast example

-

Example of brightness/contrast control on the client (WebGL only).

-
-

See the brightness-contrast.js source to see how this is done.

-
-
brightness, contrast, webgl
-
- -
- -
- - - - - - - diff --git a/examples/button-title.html b/examples/button-title.html deleted file mode 100644 index 1247a7accd..0000000000 --- a/examples/button-title.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - ol3 custom tooltips example - - - - - -
- -
-
-
-
-
- -
-
-

Custom tooltips

-

- This example shows how to customize the buttons tooltips with - Bootstrap. -

-
-

- See the button-title.js source to see how this is done. -

-
-
- custom, tooltip -
-
-
-
- - - - - - - - - diff --git a/examples/canvas-tiles.html b/examples/canvas-tiles.html deleted file mode 100644 index 90eb1866ca..0000000000 --- a/examples/canvas-tiles.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - Canvas tiles example - - - - - -
- -
-
-
-
-
- -
- -
-

Canvas tiles example

-

Renders tiles with coordinates for debugging.

-
-

The black grid tiles are generated on the client with an HTML5 canvas. Note that the tile coordinates are ol3 normalized tile coordinates (origin bottom left), not OSM tile coordinates (origin top left).

-

See the canvas-tiles.js source to see how this is done.

-
-
layers, openstreetmap, canvas
-
- -
- -
- - - - - - - diff --git a/examples/center.html b/examples/center.html deleted file mode 100644 index bf56e78d0c..0000000000 --- a/examples/center.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - - - - - - - Advanced View Positioning example - - - - - -
- -
-
-
-
-
-
-
-
-
-
- -
-
- (best fit),
- (respect resolution constraint).
- (nearest),
- (with min resolution),
- -
-
- -
- -
-

Advanced View Positioning example

-

This example demonstrates how a map's view can be - adjusted so a geometry or coordinate is positioned at a specific - pixel location. The map above has top, right, bottom, and left - padding applied inside the viewport. The view's fitGeometry method - is used to fit a geometry in the view with the same padding. The - view's centerOn method is used to position a coordinate (Lausanne) - at a specific pixel location (the center of the black box).

-
-

Use Alt+Shift+drag to rotate the map.

-

See the center.js source to see how this is done.

-
-
center, rotation, openstreetmap
-
- -
- -
- - - - - - - diff --git a/examples/cluster.html b/examples/cluster.html deleted file mode 100644 index 13b29c0249..0000000000 --- a/examples/cluster.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - Clustering example - - - - - -
- -
-
-
-
-
- -
- -
-

Clustering example

-

Example of using ol.Cluster.

-
-

See the cluster.js source to see how this is done.

-
-
cluster vector
-
- -
- -
- - - - - - - diff --git a/examples/custom-controls.html b/examples/custom-controls.html deleted file mode 100644 index 5e5cfb4050..0000000000 --- a/examples/custom-controls.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - ol3 custom controls example - - - - - -
- -
-
-
-
-
- -
-
-

Custom controls

-

This example shows how to create custom controls.

-
-

- This example creates a "rotate to north" button. - See the custom-controls.js - source to see how this is done. -

-
-
- custom, control -
-
-
-
- - - - - - - - diff --git a/examples/d3.html b/examples/d3.html deleted file mode 100644 index aa1825d802..0000000000 --- a/examples/d3.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - d3 integration example - - - - - -
- -
-
-
-
-
- -
- -
-

d3 integration example

-

Example of using ol3 and d3 together.

-
-

The example loads TopoJSON geometries and uses d3 (d3.geo.path) to render these geometries to a canvas element that is then used as the image of an ol3 image layer.

-

See the d3.js source to see how this is done.

-
-
d3
-
- -
- -
- - - - - - - - - diff --git a/examples/device-orientation.html b/examples/device-orientation.html deleted file mode 100644 index 589ddb2623..0000000000 --- a/examples/device-orientation.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - Device-Orientation example - - - - - -
- -
-
-
-
-
- -
- -
-

Device orientation example

- -

α :

-

β :

-

γ :

-

heading :

-

Listen to DeviceOrientation events

-
-

See the device-orientation.js source to see how this is done.

-
-
orientation, openstreetmap
-
- -
- -
- - - - - - - diff --git a/examples/drag-and-drop-image-vector.html b/examples/drag-and-drop-image-vector.html deleted file mode 100644 index 422d31e648..0000000000 --- a/examples/drag-and-drop-image-vector.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - Drag-and-Drop image vector example - - - - - -
- -
-
-
-
-
- -
- -
-

Drag-and-Drop image vector example

-

Example of using the drag-and-drop interaction with a ol.source.ImageVector. Drag and drop GPX, GeoJSON, IGC, KML, or TopoJSON files on to the map. Each file is rendered to an image on the client.

-
-

See the drag-and-drop-image-vector.js source to see how this is done.

-
-
drag-and-drop-image-vector, gpx, geojson, igc, kml, topojson, vector, image
-
-
-
-   -
-
- -
- -
- - - - - - - diff --git a/examples/drag-and-drop.html b/examples/drag-and-drop.html deleted file mode 100644 index eff604f539..0000000000 --- a/examples/drag-and-drop.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - Drag-and-Drop example - - - - - -
- -
-
-
-
-
- -
- -
-

Drag-and-Drop example

-

Example of using the drag-and-drop interaction. Drag and drop GPX, GeoJSON, IGC, KML, or TopoJSON files on to the map. There is no projection transform support, so this will only work with data in EPSG:4326 and EPSG:3857.

-
-

See the drag-and-drop.js source to see how this is done.

-
-
drag-and-drop, gpx, geojson, igc, kml, topojson
-
-
-
-   -
-
- -
- -
- - - - - - - diff --git a/examples/drag-features.html b/examples/drag-features.html deleted file mode 100644 index 109afa0074..0000000000 --- a/examples/drag-features.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - Drag features example - - - - - -
- -
-
-
-
-
- -
- -
-

Drag features example

-

Example of a drag features interaction.

-
-

See the drag-features.js source to see how this is done.

-
-
drag, feature, vector, editing
-
- -
- -
- - - - - - - diff --git a/examples/drag-rotate-and-zoom.html b/examples/drag-rotate-and-zoom.html deleted file mode 100644 index 5dcb3fe950..0000000000 --- a/examples/drag-rotate-and-zoom.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - Drag rotate and zoom example - - - - - -
- -
-
-
-
-
- -
- -
-

Drag rotate and zoom example

-

A single interaction to drag, rotate, and zoom.

-
-

Shift + Drag to rotate and zoom the map around its center.

-

See the drag-rotate-and-zoom.js source to see how this is done.

-
-
drag, rotate, zoom, interaction
-
- -
- -
- - - - - - - diff --git a/examples/draw-and-modify-features.html b/examples/draw-and-modify-features.html deleted file mode 100644 index 277812df9a..0000000000 --- a/examples/draw-and-modify-features.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - Draw and modify features example - - - - - -
- -
-
-
-
-
- -
- -
-

Draw and modify features example

-

Example of using the ol.interaction.Draw interaction together with - the ol.interaction.Modify interaction.

-
- - -
- -
-

See the draw-and-modify-features.js source to see how this is done.

-
-
draw, edit, modify, vector, featureoverlay
-
- -
- -
- - - - - - - diff --git a/examples/draw-features.html b/examples/draw-features.html deleted file mode 100644 index 0cf553fe94..0000000000 --- a/examples/draw-features.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - Draw features example - - - - - -
- -
-
-
-
-
- -
- -
-

Draw features example

-

Example of using the ol.interaction.Draw interaction.

-
- - -
- -
-

See the draw-features.js source to see how this is done.

-
-
draw, edit, vector
-
- -
- -
- - - - - - - diff --git a/examples/dynamic-data.html b/examples/dynamic-data.html deleted file mode 100644 index b7ea32de74..0000000000 --- a/examples/dynamic-data.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - Dynamic data example - - - - - -
- -
-
-
-
-
- -
- -
-

Dynamic data example

-

Example of dynamic data.

-
-

See the dynamic-data.js source to see how this is done.

-
-
dynamic-data
-
- -
- -
- - - - - - - diff --git a/examples/earthquake-clusters.html b/examples/earthquake-clusters.html deleted file mode 100644 index d3f630e066..0000000000 --- a/examples/earthquake-clusters.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - Earthquake Clusters - - - - - - -
- -
-
-
-
-
- -
- -
-

Earthquake Clusters

-

Demonstrates the use of style geometries to render source features of a cluster.

-
-

- This example parses a KML file and renders the features as clusters on a vector layer. The styling in this example is quite involved. Single earthquake locations (rendered as stars) have a size relative to their magnitude. Clusters have an opacity relative to the number of features in the cluster, and a size that represents the extent of the features that make up the cluster. When clicking or hovering on a cluster, the individual features that make up the cluster will be shown. -

-

To achieve this, we make heavy use of style functions and ol.style.Style#geometry. See the earthquake-clusters.js source to see how this is done.

-
-
KML, vector, style, geometry, cluster
-
-
- -
- - - - - - - - diff --git a/examples/epsg-4326.html b/examples/epsg-4326.html deleted file mode 100644 index 8fd47ec4e3..0000000000 --- a/examples/epsg-4326.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - EPSG:4326 example - - - - - -
- -
-
-
-
-
- -
- -
-

EPSG:4326 example

-

Example of a map in EPSG:4326.

-
-

See the epsg-4326.js source to see how this is done.

-
-
epsg4326
-
- -
- -
- - - - - - - diff --git a/examples/export-map.html b/examples/export-map.html deleted file mode 100644 index a0766335d2..0000000000 --- a/examples/export-map.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - Export map example - - - - - -
- -
-
-
- - Export PNG -
-
- -
- -
-

Export map example

-

Example of exporting a map as a PNG image.

-
-

See the export-map.js source to see how this is done.

-
-
export, png, openstreetmap
-
- -
- -
- - - - - - - diff --git a/examples/fractal.html b/examples/fractal.html deleted file mode 100644 index 4904d81d94..0000000000 --- a/examples/fractal.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - Fractal Example - - - - - - -
- -
-
-
-
-
- -
- -
-

Fractal Example

-

Example of a fractal.

- -
-

See the fractal.js source to see how this is done.

-
-
fractal, vector
-
- -
- -
- - - - - - - diff --git a/examples/full-screen-drag-rotate-and-zoom.html b/examples/full-screen-drag-rotate-and-zoom.html deleted file mode 100644 index 3720462e6a..0000000000 --- a/examples/full-screen-drag-rotate-and-zoom.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - Full screen drag rotate and zoom example - - - - - -
- -
-
-
-
-
- -
- -
-

Full screen drag rotate and zoom example

-

Example of drag rotate and zoom control with full screen effect.

-
-

Hold down Shift + drag to rotate and zoom. Click the button in the top right corner to go full screen. Then do the Shift + drag thing again.

-

If there is no button on the map, your browser does not support the Full Screen API.

-

See the full-screen-drag-rotate-and-zoom.js source to see how this is done.

-
-
full-screen, drag, rotate, zoom, bing, bing-maps
-
- -
- -
- - - - - - - diff --git a/examples/full-screen.html b/examples/full-screen.html deleted file mode 100644 index 638be7f120..0000000000 --- a/examples/full-screen.html +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - Full screen control example - - - - - -
- -
-
-
-
-
- -
- -
-

Full screen control example

-

Example of a full screen control.

-
-

Click the control in the top right corner to go full screen. Click it again to exit full screen.

-

If there is no button on the map, your browser does not support the Full Screen API.

-

See the full-screen.js source to see how this is done.

-
-
full-screen, bing, bing-maps
-
- -
- -
- - - - - - - diff --git a/examples/geojson.html b/examples/geojson.html deleted file mode 100644 index 54cc237742..0000000000 --- a/examples/geojson.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - GeoJSON example - - - - - -
- -
-
-
-
-
- -
- -
-

GeoJSON example

-

Example of GeoJSON features.

-
-

See the geojson.js source to see how this is done.

-
-
geojson, vector, openstreetmap
-
- -
- -
- - - - - - - diff --git a/examples/geolocation.html b/examples/geolocation.html deleted file mode 100644 index b6cff8851a..0000000000 --- a/examples/geolocation.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - Geolocation example - - - - - -
- -
-
-
-
-
- -
- -
-

Geolocation example

- -

position accuracy :

-

altitude :

-

altitude accuracy :

-

heading :

-

speed :

- -

Example of a geolocation map.

-
-

See the geolocation.js source to see how this is done.

-
-
geolocation, openstreetmap
-
-
- -
- -
- - - - - - - diff --git a/examples/getfeatureinfo-image.html b/examples/getfeatureinfo-image.html deleted file mode 100644 index bde7a8501d..0000000000 --- a/examples/getfeatureinfo-image.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - GetFeatureInfo example (image layer) - - - - - -
- -
-
-
-
-
- -
- -
-

GetFeatureInfo example (image layer)

-

This example shows how to trigger WMS GetFeatureInfo requests on click for a WMS image layer.

-
-

Additionally map.forEachLayerAtPixel is used to change the mouse - pointer when hovering a non-transparent pixel on the map.

-

See the getfeatureinfo-image.js source to see how this is done.

-
-
getfeatureinfo, forEachLayerAtPixel
-
-
-
-   -
-
- -
- -
- - - - - - - diff --git a/examples/getfeatureinfo-tile.html b/examples/getfeatureinfo-tile.html deleted file mode 100644 index b59b9205ec..0000000000 --- a/examples/getfeatureinfo-tile.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - WMS GetFeatureInfo example (tile layer) - - - - - -
- -
-
-
-
-
- -
- -
-

WMS GetFeatureInfo example (tile layer)

-

This example shows how to trigger WMS GetFeatureInfo requests on click for a WMS tile layer.

-
-

Additionally map.forEachLayerAtPixel is used to change the mouse - pointer when hovering a non-transparent pixel on the map.

-

See the getfeatureinfo-tile.js source to see how this is done.

-
-
getfeatureinfo, forEachLayerAtPixel
-
-
-
-   -
-
- -
- -
- - - - - - - diff --git a/examples/gpx.html b/examples/gpx.html deleted file mode 100644 index 5c35655732..0000000000 --- a/examples/gpx.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - GPX example - - - - - -
- -
-
-
- - Export GPX -
-
-
- -
- -
-

GPX example

-

Example of using the GPX source.

-
-

See the gpx.js source to see how this is done.

-
-
GPX
-
-
-
-   -
-
- -
- -
- - - - - - - diff --git a/examples/graticule.html b/examples/graticule.html deleted file mode 100644 index 89c57be0e5..0000000000 --- a/examples/graticule.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - Graticule example - - - - - -
- -
-
-
-
-
- -
- -
-

Graticule example

-

This example shows how to add a graticule overlay to a map.

-
-

See the graticule.js source to see how this is done.

-
-
graticule
-
- -
- -
- - - - - - - diff --git a/examples/heatmap-earthquakes.html b/examples/heatmap-earthquakes.html deleted file mode 100644 index 79a5e2e59a..0000000000 --- a/examples/heatmap-earthquakes.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - Earthquakes heatmap - - - - - -
- -
-
-
-
-
- -
- -
-

Earthquakes heatmap

-

Demonstrates the use of a heatmap layer.

-
-

- This example parses a KML file and renders the features as a ol.layer.Heatmap layer. -

-

See the heatmap-earthquakes.js source to see how this is done.

-
-
heatmap, kml, vector, style
-
- -
-
- - - - -
-
- -
-
- - - - - - - diff --git a/examples/hue-saturation.html b/examples/hue-saturation.html deleted file mode 100644 index b5f4abc94b..0000000000 --- a/examples/hue-saturation.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - Hue/saturation example - - - - - - -
- -
-
-
- - - -
- - - -
-
- - - -
-
-
- -
- -
-

Hue/saturation example

-

Example of hue/saturation control on the client (WebGL only).

-
-

See the hue-saturation.js source to see how this is done.

-
-
hue, saturation, webgl
-
- -
- -
- - - - - - - diff --git a/examples/icon-sprite-webgl.html b/examples/icon-sprite-webgl.html deleted file mode 100644 index 1d50a55616..0000000000 --- a/examples/icon-sprite-webgl.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - Icon sprites with WebGL example - - - - - -
- -
-
-
-
-
- -
- -
-

Icon sprite with WebGL example

-

Icon sprite with WebGL.

-
-

See the icon-sprite-webgl.js source to see how this is done.

-

In this example a sprite image is used for the icon styles. Using a sprite is required to get good performance with WebGL.

-
-
webgl, icon, sprite, vector, point
-
-
-
-   -
-
- -
- -
- - - - - - - - diff --git a/examples/icon.html b/examples/icon.html deleted file mode 100644 index 6b1ddaeae0..0000000000 --- a/examples/icon.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - Vector Icon Example - - - - - - -
- -
-
-
- -
-
-
- -
- -
-

Icon example

-

Example using an icon to symbolize a point.

-
-

See the icon.js source to see how this is done.

-
-
vector, style, icon, marker, popup
-
- -
- -
- - - - - - - - diff --git a/examples/igc.html b/examples/igc.html deleted file mode 100644 index 78e6b5c88e..0000000000 --- a/examples/igc.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - IGC example - - - - - -
- -
-
-
-
-
- -
- -
-

IGC example

-

Example of tracks recorded from multiple paraglider flights on the same day, read from an IGC file.

-
-

The five tracks contain a total of 49,707 unique coordinates. Zoom in to see more detail. The background layer is from OpenCycleMap.

-

See the igc.js source to see how this is done.

-
- -
complex-geometry, closest-feature, igc, opencyclemap
-
-
-
-   -
-
- -
- -
- - - - - - - diff --git a/examples/image-filter.html b/examples/image-filter.html deleted file mode 100644 index 1b0b2fede3..0000000000 --- a/examples/image-filter.html +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - Image Filter Example - - - - - -
- -
-
-
-
-
- -
- -
-

Image filter example

-

Apply a filter to imagery

- -
-

- Layer rendering can be manipulated in precompose and postcompose event listeners. - These listeners get an event with a reference to the Canvas rendering context. - In this example, the postcompose listener applies a filter to the image data. -

-

See the image-filter.js source for details on how this is done.

-
-
filter, image manipulation
-
- -
- -
- - - - - - - diff --git a/examples/image-load-events.html b/examples/image-load-events.html deleted file mode 100644 index a979d70284..0000000000 --- a/examples/image-load-events.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - - Image load events example - - - - - - -
- -
-
-
-
-
-
- -
- -
-

Image load events example

-

Example using image load events.

-
-

- Image sources fire events related to image loading. You can - listen for imageloadstart, imageloadend, - and imageloaderror type events to monitor image loading - progress. This example registers listeners for these events and - renders an image loading progress bar at the bottom of the map. -

-

- See the image-load-events.js source - for more detail on how this is done. -

-
-
image, events, loading
-
- -
- -
- - - - - - - diff --git a/examples/image-vector-layer.html b/examples/image-vector-layer.html deleted file mode 100644 index 2de416994b..0000000000 --- a/examples/image-vector-layer.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - Image vector layer example - - - - - -
- -
-
-
-
-
- -
- -
-

Image vector example

-

Example of an image vector layer.

-
-

This example uses a ol.source.ImageVector source. That source gets vector features from the - ol.source.Vector it's configured with, and draw these features to an HTML5 canvas element that - is then used as the image of an image layer.

-

See the image-vector-layer.js source to see how this is done.

-
-
vector, image
-
-
-
-   -
-
- -
- -
- - - - - - - diff --git a/examples/kml-earthquakes.html b/examples/kml-earthquakes.html deleted file mode 100644 index 7352359da7..0000000000 --- a/examples/kml-earthquakes.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - Earthquakes in KML - - - - - - -
- -
-
-
-
-
- -
- -
-

Earthquakes in KML

-

Demonstrates the use of a Shape symbolizer to render earthquake locations.

-
-

- This example parses a KML file and renders the features as a vector layer. The layer is given a style that renders earthquake locations with a size relative to their magnitude. -

-

See the kml-earthquakes.js source to see how this is done.

-
-
KML, vector, style, tooltip
-
-
- -
- - - - - - - - diff --git a/examples/kml-timezones.html b/examples/kml-timezones.html deleted file mode 100644 index 564c648e7a..0000000000 --- a/examples/kml-timezones.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - Timezones in KML - - - - - - -
- -
-
-
-
-
- -
- -
-

Timezones in KML

-

Demonstrates rendering timezones from KML.

-
-

This example parses a KML file and renders the features as a vector layer. The layer is given a ol.style.Style that fills timezones yellow with an opacity calculated based on the current offset to local noon.

-

See the kml-timezones.js source to see how this is done.

-
-
KML, vector, style
-
-
- -
- - - - - - - - diff --git a/examples/kml.html b/examples/kml.html deleted file mode 100644 index 7a10f71e23..0000000000 --- a/examples/kml.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - KML example - - - - - -
- -
-
-
- - Export KML -
-
- -
- -
-

KML example

-

Example of using the KML source.

-
-

See the kml.js source to see how this is done.

-
-
KML
-
-
-
-   -
-
- -
- -
- - - - - - - diff --git a/examples/layer-clipping-webgl.html b/examples/layer-clipping-webgl.html deleted file mode 100644 index f28de14ec2..0000000000 --- a/examples/layer-clipping-webgl.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - Layer WebGL clipping example - - - - - -
- -
-
-
-
-
- - - -
- -
-

Layer WebGL clipping example

-

Layer WebGL clipping example.

-
-

This example shows how to use the precompose and postcompose rendering hooks to clip layers using WebGL.

-

See the layer-clipping-webgl.js source to see how this is done.

-
-
clipping, webgl, openstreetmap
-
- -
- -
- - - - - - - diff --git a/examples/layer-clipping.html b/examples/layer-clipping.html deleted file mode 100644 index 8b70917bd1..0000000000 --- a/examples/layer-clipping.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - Layer clipping example - - - - - -
- -
-
-
-
-
- -
- -
-

Layer clipping example

-

Layer clipping example.

-
-

See the layer-clipping.js source to see how this is done.

-
-
clipping, openstreetmap
-
- -
- -
- - - - - - - diff --git a/examples/layer-extent.html b/examples/layer-extent.html deleted file mode 100644 index 95bc7d041c..0000000000 --- a/examples/layer-extent.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - Limited Layer Extent - - - - - -
- -
-
-
-
-
- -
- -
-

Limited layer extent

-

Restricting layer rendering to a limited extent.

-
-

- This example uses the layer.setExtent() method to - modify the extent of the overlay layer. Use the controls below - to limit rendering based on an extent. -

-

-

- - - - - -
-

-

- See the layer-extent.js - source for details on how this is done. -

-
-
extent, tilejson
-
- -
- -
- - - - - - - diff --git a/examples/layer-group.html b/examples/layer-group.html deleted file mode 100644 index a86f9dc072..0000000000 --- a/examples/layer-group.html +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - Layer group example - - - - - -
- -
-
-
- -

Layer group example

-

Example of a map with layer group.

-
-

See the layer-group.js source to see how this is done.

-
-
tilejson, input, bind, group, layergroup
-
- -
-
Click on layer nodes below to change their properties.
-
    -
  • OpenAerial layer -
    - - - - - - - - - - - -
    -
  • -
  • Layer group -
    - - - - - - - - - - - -
    -
      -
    • Food insecurity layer -
      - - - - - - - - - - - -
      -
    • -
    • World borders layer -
      - - - - - - - - - - - -
      -
    • -
    -
  • -
- -
- -
- - - - - - - diff --git a/examples/layer-spy.html b/examples/layer-spy.html deleted file mode 100644 index 1eb895c269..0000000000 --- a/examples/layer-spy.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - Layer Spy Example - - - - - -
- -
-
-
-
-
- -
- -
-

Layer spy example

-

View a portion of one layer over another

-
-

- Layer rendering can be manipulated in precompose and postcompose event listeners. - These listeners get an event with a reference to the Canvas rendering context. - In this example, the precompose listener sets a clipping mask around the most - recent mouse position, giving you a spyglass effect for viewing one layer over another. -

-

- Move around the map to see the effect. Use the ↑ up and ↓ down arrow keys to adjust the spyglass size. -

-

See the layer-spy.js source to see how this is done.

-
-
spy, image manipulation
-
- -
- -
- - - - - - - diff --git a/examples/layer-swipe.html b/examples/layer-swipe.html deleted file mode 100644 index 15e34dc16e..0000000000 --- a/examples/layer-swipe.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - Layer Swipe example - - - - - -
- -
-
-
- -
-
- -
- -
-

Layer Swipe example

-

Example of a Layer swipe map.

-
-

See the layer-swipe.js source to see how this is done.

-
-
swipe, openstreetmap
-
- -
- -
- - - - - - - diff --git a/examples/lazy-source.html b/examples/lazy-source.html deleted file mode 100644 index ce57a051d5..0000000000 --- a/examples/lazy-source.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - Lazy Source - - - - - - -
- -
-
-
-
-
- -
- -
-

Lazy source example

-

Example of setting a layer source after construction.

-
-

- Typically, the source for a layer is provided to the layer constructor. - If you need to set a layer source after construction, this can be - done with the layer.setSource() method. -

-

- The layer in the map above is constructed with no source. Use the - links below to set/unset the layer source. A layer is not rendered - until its source is set. -

-

- - -

-

See the lazy-source.js source for details on how this is done.

-
-
source
-
- -
- -
- - - - - - - diff --git a/examples/line-arrows.html b/examples/line-arrows.html deleted file mode 100644 index 6338653387..0000000000 --- a/examples/line-arrows.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - LineString arrows example - - - - - -
- -
-
-
-
-
- -
- -
-

LineString arrows example

-

Example of drawing arrows for each line string segment.

-
-

See the line-arrows.js source to see how this is done.

-
-
draw, vector, arrow
-
- -
- -
- - - - - - - diff --git a/examples/localized-openstreetmap.html b/examples/localized-openstreetmap.html deleted file mode 100644 index aeecd23e99..0000000000 --- a/examples/localized-openstreetmap.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - Localized OpenStreetMap example - - - - - -
- -
-
-
-
-
- -
- -
-

Localized OpenStreetMap example

-

Example of a localized OpenStreetMap map with a custom tile server and a custom attribution.

-
-

The base layer is OpenCycleMap with an overlay from OpenSeaMap. The OpenSeaMap tile server does not support CORS headers.

-

See the localized-openstreetmap.js source to see how this is done.

-
-
cors, localized-openstreetmap, openseamap, openstreetmap
-
- -
- -
- - - - - - - diff --git a/examples/mapguide-untiled.html b/examples/mapguide-untiled.html deleted file mode 100644 index 3a3af560aa..0000000000 --- a/examples/mapguide-untiled.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - MapGuide untiled example - - - - - -
- -
-
-
-
-
- -
- -
-

MapGuide untiled example

-

Example of a untiled MapGuide map.

-
-

See the mapguide-untiled.js source to see how this is done.

-
-
mapguide
-
- -
- -
- - - - - - - diff --git a/examples/mapquest.html b/examples/mapquest.html deleted file mode 100644 index c9ef06a26f..0000000000 --- a/examples/mapquest.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - MapQuest example - - - - - -
- -
-
-
- -
-
- -
- -
-

MapQuest example

-

Example of a MapQuest map.

-
-

See the mapquest.js source to see how this is done.

-
-
mapquest
-
- -
- -
- - - - - - - diff --git a/examples/measure.html b/examples/measure.html deleted file mode 100644 index 0341173c75..0000000000 --- a/examples/measure.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - Measure example - - - - - - -
- -
-
-
-
-
- -
- -
-

Measure example

-

Example of using the - ol.interaction.Draw interaction for creating simple - measuring application.

-
- - - -
- -
-

NOTE: If use geodesic measures is not checked, measure is done in simple way on projected plane. Earth - curvature is not taken into account

-

See the measure.js source to see how this is done.

-
-
draw, edit, measure, vector
-
- -
- -
- - - - - - - diff --git a/examples/min-max-resolution.html b/examples/min-max-resolution.html deleted file mode 100644 index 0f79406311..0000000000 --- a/examples/min-max-resolution.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - Min/max resolution example - - - - - -
- -
-
-
-
-
- -
- -
-

Min/max resolution example

-

Show/hide layers depending on current view resolution.

-
-

- Zoom in twice: the MapBox layer should hide whereas the OSM layer should be shown. -

-

- If you continue to zoom in, you'll see the OSM layer also disappear. -

-

- The rendering of the layers are here controlled using minResolution and maxResolution options. -

-

See the min-max-resolution.js source to see how this is done.

-
-
minResolution, maxResolution, resolution
-
- -
- -
- - - - - - - diff --git a/examples/modify-features.html b/examples/modify-features.html deleted file mode 100644 index 1a569054d8..0000000000 --- a/examples/modify-features.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - Modify features example - - - - - -
- -
-
-
-
-
- -
- -
-

Modify features example

-

Editing features with the modify interaction.

-
-

This example demonstrates how the modify and select interactions can be used together. Zoom in to an area of interest and select a feature for editing. Then drag points around to modify the feature. You can preserve topology by selecting multiple features before editing (Shift+click to select multiple features).

-

See the modify-features.js source to see how this is done.

-
-
modify, edit, vector
-
- -
- -
- - - - - - - diff --git a/examples/modify-test.html b/examples/modify-test.html deleted file mode 100644 index c4b3b61012..0000000000 --- a/examples/modify-test.html +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - Modify features test - - - - - - -
- -
-
-
-
-
- -
- -
-

Modify features test

-

Example for testing feature modification.

-
-

See the modify-test.js source to see how this is done.

-
-
modify, edit, vector
-
- -
- -
- - - - - - - diff --git a/examples/mouse-position.html b/examples/mouse-position.html deleted file mode 100644 index de9b13e996..0000000000 --- a/examples/mouse-position.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - Mouse position example - - - - - -
- -
-
-
-
-
- -
-
-

Mouse position example

-

Example of a mouse position control, outside the map.

-
-

See the mouse-position.js source to see how this is done.

-
-
mouse-position, openstreetmap
-
- - - - -
-
-
 
-
- -
- - - - - - - diff --git a/examples/moveend.html b/examples/moveend.html deleted file mode 100644 index f88b248974..0000000000 --- a/examples/moveend.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - Moveend Example - - - - - -
-
-
-
-
-
- -
-
-

Move end example

-

Use of the moveend event.

-
-

In this example, a listener is registered for the map's moveend event. Whenever this listener is called, it updates the inputs below with the map extent in decimal degrees.

-

See the moveend.js source for details on how this is done.

-
-
moveend, map, event
- - - - -
- -
- -
- - - - - - - diff --git a/examples/navigation-controls.html b/examples/navigation-controls.html deleted file mode 100644 index f4d3ba0a85..0000000000 --- a/examples/navigation-controls.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - Navigation controls example - - - - - -
- -
-
-
-
-
- -
- -
-

Navigation controls example

-

Shows how to add navigation controls.

- The following navigation controls are added to the map: -
    -
  • ol.control.Zoom (added by default)
  • -
  • ol.control.ZoomToExtent
  • -
-
-

See the navigation-controls.js source to see how this is done.

-
-
control, navigation, extent
-
- -
- -
- - - - - - - diff --git a/examples/overlay.html b/examples/overlay.html deleted file mode 100644 index c3351e0d22..0000000000 --- a/examples/overlay.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - Overlay example - - - - - -
- -
-
-
-
-
- -
- -
-

Overlay example

-

Demonstrates overlays.

-
-

The popups are created using - Popovers from Bootstrap.

-

See the overlay.js source to see how this is done.

-
-
overlay, popup, bootstrap, popover, mapquest, openaerial
-
- -
- -
- -
- - Vienna -
- - -
- - - - - - - - diff --git a/examples/overviewmap-custom.html b/examples/overviewmap-custom.html deleted file mode 100644 index d00be1357d..0000000000 --- a/examples/overviewmap-custom.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - ol3 OverviewMap control with advanced customization example - - - - - -
-

OverviewMap control, advanced

-
- -
-

Example of OverviewMap control with advanced customization.

-
-

See the overviewmap-custom.js source to see how this is done.

-

This example demonstrates how you can customize the overviewmap control using its supported options as well as defining custom CSS. You can also rotate the map using the shift key to see how the overview map reacts.

-
-
overview, overviewmap
-
-
- - - - - - - diff --git a/examples/overviewmap.html b/examples/overviewmap.html deleted file mode 100644 index ca0a0da1a4..0000000000 --- a/examples/overviewmap.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - ol3 OverviewMap control example - - - - - -
-

OverviewMap control

-
- -
-

Example of OverviewMap control.

-
-

See the overviewmap.js source to see how this is done.

-
-
overview, overviewmap
-
-
- - - - - - - diff --git a/examples/polygon-styles.html b/examples/polygon-styles.html deleted file mode 100644 index 5464d2f097..0000000000 --- a/examples/polygon-styles.html +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - Custom styles for polygons - - - - - - -
- -
-
-
-
-
- -
- -
-

Custom styles for polygons

-

Showing the vertices of a polygon with a custom style geometry.

-
-

See the polygon-styles.js source to see how this is done.

-
-
polygon, vector, style, GeometryFunction
-
- -
- -
- - - - - - - diff --git a/examples/popup.html b/examples/popup.html deleted file mode 100644 index 272fa75009..0000000000 --- a/examples/popup.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - Popup example - - - - - -
- -
-
-
- -
-
-
- -
- -
-

Popup example

-

Uses an overlay to create a popup.

-
-

- Click on the map to get a popup. The popup is composed of a few basic elements: a container, a close button, and a place for the content. To anchor the popup to the map, an ol.Overlay is created with the popup container. A listener is registered for the map's click event to display the popup, and another listener is set as the click handler for the close button to hide the popup. -

-

- See the popup.js source to see how this is done. -

-
-
overlay, popup, mapquest, openaerial
-
- -
- -
- - - - - - - diff --git a/examples/preload.html b/examples/preload.html deleted file mode 100644 index b45933d6da..0000000000 --- a/examples/preload.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - Preload example - - - - - -
- -
-
-
-
-
-
-
-
- -
- -
-

Preload example

-

Example of tile preloading.

-
-

The map on the left preloads low resolution tiles. The map on the right does not use any preloading. Try zooming out and panning to see the difference.

-

See the preload.js source to see how this is done.

-
-
preload, bing
-
- -
- -
- - - - - - - diff --git a/examples/regularshape.html b/examples/regularshape.html deleted file mode 100644 index 2b1ecfcc34..0000000000 --- a/examples/regularshape.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - Regular Shape example - - - - - -
- -
-
-
-
-
- -
- -
-

Regular Shape example

-

Example of some Regular Shape styles.

-
-

See the regularshape.js source to see how this is done.

-
-
vector, symbol, regularshape, style, square, cross, star, triangle, x
-
- -
- -
- - - - - - - diff --git a/examples/rotation.html b/examples/rotation.html deleted file mode 100644 index b6e94d986e..0000000000 --- a/examples/rotation.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - Rotation example - - - - - -
- -
-
-
-
-
- -
- -
-

Rotation example

-

Example of a rotated map.

-
-

Use Alt+Shift+drag to rotate the map.

-

See the rotation.js source to see how this is done.

-
-
rotation, openstreetmap
-
- -
- -
- - - - - - - diff --git a/examples/scale-line.html b/examples/scale-line.html deleted file mode 100644 index 2151535a52..0000000000 --- a/examples/scale-line.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - Scale line example - - - - - -
- -
-
-
- -
-
- -
- -
-

Scale line example

-

Example of a scale line.

-
-

See the scale-line.js source to see how this is done.

-
-
scale-line, openstreetmap
-
- -
- -
- - - - - - - diff --git a/examples/select-features.html b/examples/select-features.html deleted file mode 100644 index 353183ecef..0000000000 --- a/examples/select-features.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - Select features example - - - - - -
- -
-
-
-
-
- -
- -
-

Select features example

-

Example of using the Select interaction. Choose between Single-click, Click and Hover as the event type for selection in the combobox below. When using Single-click or Click you can hold do Shift key to toggle the feature in the selection.

-

Note: when Single-click is used double-clicks won't select features. This in contrast to Click, where a double-click will both select the feature and zoom the map (because of the DoubleClickZoom interaction). Note that Single-click is less responsive than Click because of the delay it uses to detect double-clicks.

-

In this example, a listener is registered for the Select interaction's select event in order to update the selection status below. -

- - -  0 selected features -
-
-

See the select-features.js source to see how this is done.

-
-
select, vector
-
- -
- -
- - - - - - - diff --git a/examples/semi-transparent-layer.html b/examples/semi-transparent-layer.html deleted file mode 100644 index 24f7302eca..0000000000 --- a/examples/semi-transparent-layer.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - Semi-transparent layer example - - - - - -
- -
-
-
-
-
- -
- -
-

Semi-transparent layer example

-

Example of a map with a semi-transparent layer.

-
-

See the semi-transparent-layer.js source to see how this is done.

-
-
transparent, mapquest, tilejson
-
- -
- -
- - - - - - - diff --git a/examples/side-by-side.html b/examples/side-by-side.html deleted file mode 100644 index 67bb0f8cfd..0000000000 --- a/examples/side-by-side.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - Side-by-side example - - - - - -
- -
-
-

Canvas

-
-
-
-

WebGL

-
- -
-
-

DOM

-
-
-
- -
- -
-

Side-by-side example

-

The three maps, one WebGL, one Canvas, one DOM, share the same center, resolution, rotation and layers.

-
-

See the side-by-side.js source to see how this is done.

-
-
side-by-side, canvas, webgl, dom, canvas, sync, object
-
- -
- -
- - - - - - - diff --git a/examples/simple.html b/examples/simple.html deleted file mode 100644 index 4f760282af..0000000000 --- a/examples/simple.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - Simple example - - - - - -
- -
-
-
-
-
- -
- -
-

Simple example

-

Example of a simple map.

-
-

See the simple.js source to see how this is done.

-
-
simple, openstreetmap
-
- -
- -
- - - - - - - diff --git a/examples/snap.html b/examples/snap.html deleted file mode 100644 index b30424fabf..0000000000 --- a/examples/snap.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - Snap example - - - - - -
- -
-
-
-
-
- -
- -
-

Snap interaction example

-

Example of using the snap interaction together with - draw and modify interactions. The snap interaction must be added - last, as it needs to be the first to handle the - pointermove event.

-
-
- -
-
- -
-
- - -
-
- -
-

See the snap.js source to see how this is done.

-
-
draw, edit, modify, vector, featureoverlay, snap
-
- -
- -
- - - - - - - diff --git a/examples/sphere-mollweide.html b/examples/sphere-mollweide.html deleted file mode 100644 index 9493769cea..0000000000 --- a/examples/sphere-mollweide.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - Sphere Mollweide example - - - - - -
- -
-
-
-
-
- -
- -
-

Sphere Mollweide example

-

Example of a Sphere Mollweide map with a Graticule component.

-
-

See the sphere-mollweide.js source to see how this is done.

-
-
graticule, Mollweide, projection, proj4js
-
- -
- -
- - - - - - - - diff --git a/examples/stamen.html b/examples/stamen.html deleted file mode 100644 index 4663db3467..0000000000 --- a/examples/stamen.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - Stamen example - - - - - -
- -
-
-
-
-
- -
- -
-

Stamen example

-

Example of a Stamen tile source. Two layers are composed: the watercolor base layer with the terrain labels.

-
-

See the stamen.js source to see how this is done.

-
-
stamen, watercolor, terrain-labels, two-layers
-
- -
- -
- - - - - - - diff --git a/examples/static-image.html b/examples/static-image.html deleted file mode 100644 index 4e761dc286..0000000000 --- a/examples/static-image.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - Static image example - - - - - -
- -
-
-
-
-
- -
- -
-

Static image example

-

Example of a static image layer.

-
-

- This example uses a static image - as a layer source. The map view is configured with a custom - projection that translates image coordinates directly into map - coordinates. -

-

- See the static-image.js source - for details on how this is done. -

-
-
static image, xkcd
-
- -
- -
- - - - - - - diff --git a/examples/symbol-atlas-webgl.html b/examples/symbol-atlas-webgl.html deleted file mode 100644 index 666bc43ab5..0000000000 --- a/examples/symbol-atlas-webgl.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - Symbols with WebGL example - - - - - -
- -
-
-
-
-
- -
- -
-

Symbols with WebGL example

-

Using symbols in an atlas with WebGL.

-
-

When using symbol styles with WebGL, OpenLayers would render the symbol - on a temporary image and would create a WebGL texture for each image. For a - better performance, it is recommended to use atlas images (similar to - image sprites with CSS), so that the number of textures is reduced. OpenLayers - provides an AtlasManager, which when passed to the constructor - of a symbol style, will create atlases for the symbols.

-

See the symbol-atlas-webgl.js source to see how this is done.

-
-
webgl, symbol, atlas, vector, point
-
- -
- -
- - - - - - - - diff --git a/examples/synthetic-lines.html b/examples/synthetic-lines.html deleted file mode 100644 index 64f497f935..0000000000 --- a/examples/synthetic-lines.html +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - - - Synthetic lines example - - - - - -
- -
-
-
-
-
- -
- -
-

Synthetic lines example

-

Synthetic lines example.

-
-

See the synthetic-lines.js source to see how this is done.

-

Performance results:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Device/Browser200 lines500 lines1000 lines2000 lines5000 lines10000 lines20000 lines
Mac Book Air / Chrome 33 canary60 fps60 fps60 fps60 fps60 fps60 fps60 fps
Mac Book Air / FireFox 2560 fps60 fps60 fps60 fps60 fps22 fps6 fps
Mac Book Air / Safari 760 fps60 fps60 fps40 fps10 fpsN/AN/A
iPhone 4S / iOS 7 / Safari60 fps33 fps15 fps5 fpsN/AN/AN/A
- -
-
vector
-
- -
- -
- - - - - - - - diff --git a/examples/synthetic-points.html b/examples/synthetic-points.html deleted file mode 100644 index 45cd56ddb6..0000000000 --- a/examples/synthetic-points.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - Synthetic points example - - - - - -
- -
-
-
-
-
- -
- -
-

Synthetic points example

-

Synthetic points example.

-
-

See the synthetic-points.js source to see how this is done.

-
-
vector
-
- -
- -
- - - - - - - - diff --git a/examples/teleport.html b/examples/teleport.html deleted file mode 100644 index c501ff48a7..0000000000 --- a/examples/teleport.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - Teleport example - - - - - -
- -
-
-
-
-
-
-
-
- -
-
- Teleport -
-
- -
- -
-

Teleport example

-

Example of moving a map from one target to another.

-
-

Click on the Teleport button below the map to move the map from one target to another.

-

See the teleport.js source to see how this is done.

-
-
teleport, openstreetmap
-
- -
- -
- - - - - - - diff --git a/examples/tile-load-events.html b/examples/tile-load-events.html deleted file mode 100644 index 883e42ec6d..0000000000 --- a/examples/tile-load-events.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - - Tile load events example - - - - - - -
- -
-
-
-
-
-
- -
- -
-

Tile load events example

-

Example using tile load events.

-
-

- Image tile sources fire events related to tile loading. You can - listen for tileloadstart, tileloadend, - and tileloaderror type events to monitor tile loading - progress. This example registers listeners for these events and - renders a tile loading progress bar at the bottom of the map. -

-

- See the tile-load-events.js source - for more detail on how this is done. -

-
-
tile, events, loading
-
- -
- -
- - - - - - - diff --git a/examples/tile-vector.html b/examples/tile-vector.html deleted file mode 100644 index 192e786cfd..0000000000 --- a/examples/tile-vector.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - Tile vector example - - - - - - -
- -
-
-
-
-
- -
- -
-

Tile vector example

-

Example of vector tiles from openstreetmap.us.

-
-

See the tile-vector.js source to see how this is done.

-
-
- Warning Map is becoming unresponsive with too many layers. -
-
- Layers - - - - -
-
tile-vector, openstreetmap
-
- -
- -
- - - - - - - diff --git a/examples/tilejson.html b/examples/tilejson.html deleted file mode 100644 index 8a5e94a092..0000000000 --- a/examples/tilejson.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - TileJSON example - - - - - -
- -
-
-
-
-
- -
- -
-

TileJSON example

-

Example of a TileJSON layer.

-
-

See the tilejson.js source to see how this is done.

-
-
tilejson
-
- -
- -
- - - - - - - diff --git a/examples/tileutfgrid.html b/examples/tileutfgrid.html deleted file mode 100644 index 23c39c577c..0000000000 --- a/examples/tileutfgrid.html +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - TileUTFGrid example - - - - - -
- -
-
-
-
-
- -
- -
-

TileUTFGrid example

-

This example shows how to read data from a TileUTFGrid layer.

-

Point to a country to see its name and flag.

-
-

Tiles made with TileMill. Hosting on MapBox.com or with open-source TileServer.

-

See the tileutfgrid.js source to see how this is done.

-
-
utfgrid, tileutfgrid, tilejson
-
- -
- -
- -
- -
-
 
- -
-
- - - - - - - diff --git a/examples/tissot.html b/examples/tissot.html deleted file mode 100644 index 8d77e8253a..0000000000 --- a/examples/tissot.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - Tissot indicatrix example - - - - - -
- -
-
-

EPSG:4326

-
-
-
-

EPSG:3857

-
-
-
- -
- -
-

Tissot indicatrix example

-

Example of Tissot indicatrix maps. The map on the left is an EPSG:4326 map. The one on the right is EPSG:3857.

-
-

See the tissot.js source to see how this is done.

-
-
tissot, circle
-
- -
- -
- - - - - - - diff --git a/examples/topojson.html b/examples/topojson.html deleted file mode 100644 index 031bc17d32..0000000000 --- a/examples/topojson.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - TopoJSON Example - - - - - -
- -
-
-
-
-
- -
- -
-

TopoJSON example

-

Demonstrates rendering of features from a TopoJSON topology.

-
-

See the topojson.js source to see how this is done.

-
-
vector, topojson, style
-
-
 
- -
- -
- - - - - - - diff --git a/examples/vector-labels.html b/examples/vector-labels.html deleted file mode 100644 index 9d316e64c1..0000000000 --- a/examples/vector-labels.html +++ /dev/null @@ -1,361 +0,0 @@ - - - - - - - - - - - - Vector labels example - - - - - -
- -
-
-
-
-
- -
- -

Points

-
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
-
- -
- -

Lines

-
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
-
- -
- -

Polygons

-
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
-
- -
- -
- -
-

Vector labels example

-

Example of GeoJSON features with labels.

-
-

See the vector-labels.js source to see how this is done.

-

Note: The 'Text/Wrap' option is currently not working properly. This is because ol3 uses Canvas's strokeText and fillText functions that do not support text wrapping.

-
-
geojson, vector, openstreetmap, label
-
- -
- - -
- - - - - - - diff --git a/examples/vector-layer.html b/examples/vector-layer.html deleted file mode 100644 index 3589342a69..0000000000 --- a/examples/vector-layer.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - Vector layer example - - - - - -
- -
-
-
-
-
- -
- -
-

Vector layer example

-

Example of a countries vector layer with country information on hover and country labels at higher zoom levels.

-
-

See the vector-layer.js source to see how this is done.

-
-
vector, geojson, style, feature overlay
-
-
-
-   -
-
- -
- -
- - - - - - - diff --git a/examples/vector-osm.html b/examples/vector-osm.html deleted file mode 100644 index b505c591a4..0000000000 --- a/examples/vector-osm.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - OSM XML example - - - - - -
- -
-
-
-
-
- -
- -
-

OSM XML example

-

Example of using the OSM XML source. Vector data is loaded dynamically from a server using a tiling strategy.

-
-

See the vector-osm.js source to see how this is done.

-
-
vector, osm, xml, loading, server
-
-
-
-   -
-
- -
- -
- - - - - - - diff --git a/examples/vector-wfs.html b/examples/vector-wfs.html deleted file mode 100644 index e038956163..0000000000 --- a/examples/vector-wfs.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - WFS example - - - - - -
- -
-
-
-
-
- -
- -
-

WFS example

-

Example of using WFS with a BBOX strategy.

-
-

See the vector-wfs.js source to see how this is done.

-
-
vector, WFS, bbox, loading, server
-
-
- -
- - - - - - - diff --git a/examples/wkt.html b/examples/wkt.html deleted file mode 100644 index a00a58f843..0000000000 --- a/examples/wkt.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - WKT example - - - - - -
- -
-
-
-
-
- -
- -
-

WKT example

-

Example of using the WKT parser.

-
-

See the wkt.js source to see how this is done.

-
-
WKT Well Known Text
-
-
- -
- - - - - - - diff --git a/examples/wms-capabilities.html b/examples/wms-capabilities.html deleted file mode 100644 index c0c70a11f7..0000000000 --- a/examples/wms-capabilities.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - WMS GetCapabilities parsing example - - - - - -
- -
- -
-

WMS GetCapabilities parsing example

-

Example of parsing a WMS GetCapabilities response.

-
-

See the wms-capabilities.js source to see how this is done.

-
-
wms, capabilities, getcapabilities
-
- -
-

-        
- -
- -
- - - - - - - diff --git a/examples/wms-custom-proj.html b/examples/wms-custom-proj.html deleted file mode 100644 index f87405a33e..0000000000 --- a/examples/wms-custom-proj.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - Tiled WMS with custom projection example - - - - - -
- -
-
-
-
-
- -
- -
-

Tiled WMS with custom projection example

-

Example of two tiled WMS layers (Pixelmap 1:1'000'000 and national parks) using the projection EPSG:21781.

-
-

See the wms-custom-proj.js source to see how this is done.

-
-
wms, tile, tilelayer, projection
-
- -
- -
- - - - - - diff --git a/examples/wms-image-custom-proj.html b/examples/wms-image-custom-proj.html deleted file mode 100644 index 59af93e1a1..0000000000 --- a/examples/wms-image-custom-proj.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - Single image WMS with Proj4js projection example - - - - - -
- -
-
-
-
-
- -
- -
-

Single image WMS with Proj4js projection example

-

Example of two single image WMS layers.

-
-

Pixelmap 1:1'000'000 with National Parks overlay using the projection EPSG:21781.

-

See the wms-image-custom-proj.js source to see how this is done.

-
-
wms, single image, proj4js, projection
-
- -
- -
- - - - - - - - - diff --git a/examples/wms-image.html b/examples/wms-image.html deleted file mode 100644 index d8a4a0adf3..0000000000 --- a/examples/wms-image.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - Single image WMS example - - - - - -
- -
-
-
-
-
- -
- -
-

Single image WMS example

-

Example of a single image WMS layer.

-
-

See the wms-image.js source to see how this is done.

-
-
wms, image
-
- -
- -
- - - - - - - diff --git a/examples/wms-no-proj.html b/examples/wms-no-proj.html deleted file mode 100644 index acd45d3e9b..0000000000 --- a/examples/wms-no-proj.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - WMS without client projection example - - - - - -
- -
-
-
-
-
- -
- -
-

WMS without client projection example

-

Example of two WMS layers using the projection EPSG:21781, which is unknown to the client.

-
-

See the wms-no-proj.js source to see how this is done.

-
-
wms, projection
-
- -
- -
- - - - - - - diff --git a/examples/wms-tiled-wrap-180.html b/examples/wms-tiled-wrap-180.html deleted file mode 100644 index 01aeb64c69..0000000000 --- a/examples/wms-tiled-wrap-180.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - Tiled WMS wrap 180° meridian example - - - - - -
- -
-
-
-
-
- -
- -
-

Tiled WMS wrap 180° meridian example

-

Example of a tiled WMS layer that wraps across the 180° meridian.

-
-

See the wms-tiled-wrap-180.js source to see how this is done.

-
-
wms, tile, dateline, wrap, 180
-
- -
- -
- - - - - - - diff --git a/examples/wms-tiled.html b/examples/wms-tiled.html deleted file mode 100644 index d16ccb70e5..0000000000 --- a/examples/wms-tiled.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - Tiled WMS example - - - - - -
- -
-
-
-
-
- -
- -
-

Tiled WMS example

-

Example of a tiled WMS layer.

-
-

See the wms-tiled.js source to see how this is done.

-
-
wms, tile, tilelayer
-
- -
- -
- - - - - - - diff --git a/examples/wmts-capabilities.html b/examples/wmts-capabilities.html deleted file mode 100644 index 1a37d7784c..0000000000 --- a/examples/wmts-capabilities.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - WMTS GetCapabilities parsing example - - - - - -
- -
- -
-

WMTS GetCapabilities parsing example

-

Example of parsing a WMTS GetCapabilities response.

-
-

See the wmts-capabilities.js source to see how this is done.

-
-
wmts, capabilities, getcapabilities
-
- -
-

-        
- -
- -
- - - - - - - diff --git a/examples/wmts-hidpi.html b/examples/wmts-hidpi.html deleted file mode 100644 index 8deed62a4b..0000000000 --- a/examples/wmts-hidpi.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - WMTS HiDPI example - - - - - - -
- -
-
-
-
-
- -
- -
-

WMTS HiDPI example

-

Example of a WMTS based HiDPI layer.

-
-

See the wmts-hidpi.js source to see how this is done.

-
-
hidpi, retina, wmts
-
- -
- -
- - - - - - - diff --git a/examples/wmts-layer-from-capabilities.html b/examples/wmts-layer-from-capabilities.html deleted file mode 100644 index 4918488e4c..0000000000 --- a/examples/wmts-layer-from-capabilities.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - WMTS Layer example from capabilities - - - - - -
- -
-
-
-
-
- -
- -
-

WMTS Capabilities example

-

Example of a WMTS source created from a WMTS capabilities document.

-
-

See the wmts-layer-from-capabilities.js source to see how this is done.

-
-
wmts, capabilities, getcapabilities
-
- -
- -
- - - - - - - diff --git a/examples/wmts.html b/examples/wmts.html deleted file mode 100644 index 4b48f24f16..0000000000 --- a/examples/wmts.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - WMTS example - - - - - -
- -
-
-
-
-
- -
- -
-

WMTS example

-

Example of a WMTS source.

-
-

See the wmts.js source to see how this is done.

-
-
wmts
-
- -
- -
- - - - - - - diff --git a/examples/xyz-esri-4326-512.html b/examples/xyz-esri-4326-512.html deleted file mode 100644 index 584d04608e..0000000000 --- a/examples/xyz-esri-4326-512.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - XYZ Esri EPSG:4326 tileSize 512 example - - - - - -
- -
-
-
-
-
- -
- -
-

XYZ Esri EPSG:4326 tileSize 512 example

-

Example of a XYZ source in EPSG:4326 using Esri 512x512 tiles.

-
-

See the xyz-esri-4326-512.js source for details on how this is done.

-
-
xyz, esri, tilesize, custom projection
-
- -
- -
- - - - - - - diff --git a/examples/xyz-esri.html b/examples/xyz-esri.html deleted file mode 100644 index 31f21a082a..0000000000 --- a/examples/xyz-esri.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - XYZ Esri example - - - - - -
- -
-
-
-
-
- -
- -
-

XYZ Esri example

-

Example of a XYZ source using Esri tiles.

-
-

See the xyz-esri.js source for details on how this is done.

-
-
xyz, esri
-
- -
- -
- - - - - - - diff --git a/examples/xyz-retina.html b/examples/xyz-retina.html deleted file mode 100644 index acc25a45b8..0000000000 --- a/examples/xyz-retina.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - XYZ Retina tiles example - - - - - -
- -
-
-
-
-
- -
- -
-

XYZ with Retina tiles example

-

Example of Retina / HiDPI mercator tiles (512x512px) available as XYZ.

-
-

The ol.source.XYZ must contain tilePixelRatio parameter. The tiles were prepared from a GeoTIFF file with MapTiler.

-

See the xyz-retina.js source for details on how this is done.

-
-
retina, hidpi, xyz, maptiler, @2x, devicePixelRatio
-
- -
- -
- - - - - - - diff --git a/examples/xyz.html b/examples/xyz.html deleted file mode 100644 index ed08aeec4c..0000000000 --- a/examples/xyz.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - XYZ example - - - - - -
- -
-
-
-
-
- -
- -
-

XYZ example

-

Example of a XYZ source.

-
-

See the xyz.js source for details on how this is done.

-
-
xyz
-
- -
- -
- - - - - - - diff --git a/examples/zoom-constrained.html b/examples/zoom-constrained.html deleted file mode 100644 index e1ccbab1e3..0000000000 --- a/examples/zoom-constrained.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - Zoom Constrained Example - - - - - -
- -
-
-
-
-
- -
- -
-

Zoom constrained example

-

Example of a zoom constrained view.

-
-

This map has a view that is constrained between zoom levels 9 and 13. This is done using the minZoom and maxZoom view options.

-

See the zoom-constrained.js source for details.

-
-
bing, zoom, minZoom, maxZoom
-
- -
- -
- - - - - - - diff --git a/examples/zoomify.html b/examples/zoomify.html deleted file mode 100644 index f6be63b091..0000000000 --- a/examples/zoomify.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - Zoomify example - - - - - -
- -
-
-
-
-
- -
- -
-

Zoomify example

-

Example of a Zoomify source.

-
-

See the zoomify.js source to see how this is done.

-
-
zoomify
-
- -
- -
- - - - - - - diff --git a/examples/zoomslider.html b/examples/zoomslider.html deleted file mode 100644 index f5da737e26..0000000000 --- a/examples/zoomslider.html +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - Zoom slider example - - - - - -
- -
-
-

Default style

-
-
-
-

Placed between zoom controls

-
-
-
-

Horizontal and completely re-styled

-
-
-
- -
- -
-

ZoomSlider control

-

Example of various ZoomSlider controls.

-
-

- See the zoomslider.js - source to see how this is done. -

-
-
- zoom, zoomslider, slider, style, styling, css, control -
-
-
-
- - - - - - - - diff --git a/examples/Jugl.js b/examples_src/Jugl.js similarity index 100% rename from examples/Jugl.js rename to examples_src/Jugl.js diff --git a/examples_src/accessible.css b/examples_src/accessible.css new file mode 100644 index 0000000000..0b1c657b51 --- /dev/null +++ b/examples_src/accessible.css @@ -0,0 +1,16 @@ +a.skiplink { + position: absolute; + clip: rect(1px, 1px, 1px, 1px); + padding: 0; + border: 0; + height: 1px; + width: 1px; + overflow: hidden; +} +a.skiplink:focus { + clip: auto; + height: auto; + width: auto; + background-color: #fff; + padding: 0.3em; +} diff --git a/examples_src/accessible.html b/examples_src/accessible.html new file mode 100644 index 0000000000..7e73c824f9 --- /dev/null +++ b/examples_src/accessible.html @@ -0,0 +1,15 @@ +--- +template: "example.html" +title: "Accessibility example" +shortdesc: "Example of an accessible map." +docs: > +

This page's map element has its tabindex attribute set to "0", that makes it focusable. To focus the map element you can either navigate to it using the "tab" key or use the skip link. When the map element is focused the + and - keys can be used to zoom in and out and the arrow keys can be used to pan.

+

When clicked the "Zoom in" and "Zoom out" buttons below the map zoom the map in and out, respectively. You can navigate to the buttons using the "tab" key, and press the "enter" key to trigger the zooming action.

+tags: "accessibility, tabindex" +--- +
+
+ +
+
+
diff --git a/examples/accessible.js b/examples_src/accessible.js similarity index 100% rename from examples/accessible.js rename to examples_src/accessible.js diff --git a/examples_src/animation.html b/examples_src/animation.html new file mode 100644 index 0000000000..aebcde69d6 --- /dev/null +++ b/examples_src/animation.html @@ -0,0 +1,27 @@ +--- +template: "example.html" +title: "Animation example" +shortdesc: "Demonstrates animated pan, zoom, and rotation." +docs: > + This example shows how to use the beforeRender function on the Map to run one + or more animations. +tags: "animation" +--- +
+
+
+
+
+
+
+ + + + + + + + + +
+
diff --git a/examples/animation.js b/examples_src/animation.js similarity index 100% rename from examples/animation.js rename to examples_src/animation.js diff --git a/examples_src/arcgis-tiled.html b/examples_src/arcgis-tiled.html new file mode 100644 index 0000000000..0cf5c660cd --- /dev/null +++ b/examples_src/arcgis-tiled.html @@ -0,0 +1,16 @@ +--- +template: "example.html" +title: "Tiled ArcGIS MapServer example" +shortdesc: "Example of a tiled ArcGIS layer." +docs: > + This example shows how to use an ArcGIS REST MapService as tiles. + This source type supports Map and Image Services. For cached ArcGIS + services, better performance is available by using + ol.source.XYZ instead. +tags: arcgis, tile, tilelayer" +--- +
+
+
+
+
diff --git a/examples/arcgis-tiled.js b/examples_src/arcgis-tiled.js similarity index 100% rename from examples/arcgis-tiled.js rename to examples_src/arcgis-tiled.js diff --git a/examples_src/attributions.html b/examples_src/attributions.html new file mode 100644 index 0000000000..d268129d88 --- /dev/null +++ b/examples_src/attributions.html @@ -0,0 +1,15 @@ +--- +template: "example.html" +title: "Attributions example" +shortdesc: "Example of a attributions visibily change on map resize, to collapse them on small maps." +docs: > + When the map gets too small because of a resize, the attribution will be collapsed. + This is because the collapsible option is set to true if the width + of the map gets smaller than 600 pixels. +tags: "attributions, openstreetmap" +--- +
+
+
+
+
diff --git a/examples/attributions.js b/examples_src/attributions.js similarity index 100% rename from examples/attributions.js rename to examples_src/attributions.js diff --git a/examples_src/bind-input.html b/examples_src/bind-input.html new file mode 100644 index 0000000000..cfec65e20c --- /dev/null +++ b/examples_src/bind-input.html @@ -0,0 +1,51 @@ +--- +template: "example.html" +title: "Bind HTML input example" +shortdesc: "Demonstrates two-way binding of HTML input elements to OpenLayers objects." +docs: > + + +tags: "custom, control" +--- +
+
+
+
+
+
+
+
+ Layer + + + +
+ +
+
+
+
+
+ View + + + + +
+
+
\ No newline at end of file diff --git a/examples/bind-input.js b/examples_src/bind-input.js similarity index 100% rename from examples/bind-input.js rename to examples_src/bind-input.js diff --git a/examples_src/bing-maps.html b/examples_src/bing-maps.html new file mode 100644 index 0000000000..c8fb02ddb4 --- /dev/null +++ b/examples_src/bing-maps.html @@ -0,0 +1,20 @@ +--- +template: "example.html" +title: "Bing Maps example" +shortdesc: "Example of a Bing Maps layer." +docs: > +

When the Bing Maps tile service doesn't have tiles for a given resolution and region it returns "placeholder" tiles indicating that. Zoom the map beyond level 19 to see the "placeholder" tiles. If you want OpenLayers to display stretched tiles in place of "placeholder" tiles beyond zoom level 19 then set maxZoom to 19 in the options passed to ol.source.BingMaps.

+tags: "bing, bing-maps" +--- +
+
+
+ +
+
\ No newline at end of file diff --git a/examples/bing-maps.js b/examples_src/bing-maps.js similarity index 100% rename from examples/bing-maps.js rename to examples_src/bing-maps.js diff --git a/examples_src/box-selection.html b/examples_src/box-selection.html new file mode 100644 index 0000000000..b727d9b35a --- /dev/null +++ b/examples_src/box-selection.html @@ -0,0 +1,20 @@ +--- +template: "example.html" +title: "Box selection example" +shortdesc: "Using a DragBox interaction to select features." +docs: > +

This example shows how to use a DragBox interaction to select features. Selected features are added + to the feature overlay of a select interaction (ol.interaction.Select) for highlighting.

+

Use SHIFT+drag to draw boxes.

+tags: "DragBox, feature, selection, box" +--- +
+
+
+
+
+
+   +
+
+
diff --git a/examples/box-selection.js b/examples_src/box-selection.js similarity index 100% rename from examples/box-selection.js rename to examples_src/box-selection.js diff --git a/examples_src/brightness-contrast.css b/examples_src/brightness-contrast.css new file mode 100644 index 0000000000..273b443f89 --- /dev/null +++ b/examples_src/brightness-contrast.css @@ -0,0 +1,7 @@ +#reset-brightness { + min-width: 138px; +} +#reset-contrast { + min-width: 120px; +} + diff --git a/examples_src/brightness-contrast.html b/examples_src/brightness-contrast.html new file mode 100644 index 0000000000..7744f3320e --- /dev/null +++ b/examples_src/brightness-contrast.html @@ -0,0 +1,27 @@ +--- +template: "example.html" +title: "Brightness/contrast example" +shortdesc: "Example of brightness/contrast control on the client (WebGL only)." +docs: > + This example shows how to control brightness/contrast on the client, + the example is limited to WebGL. +tags: "brightness, contrast, webgl" +--- +
+
+
+ +
+ + + +
+
+ + + +
+
+
diff --git a/examples/brightness-contrast.js b/examples_src/brightness-contrast.js similarity index 100% rename from examples/brightness-contrast.js rename to examples_src/brightness-contrast.js diff --git a/examples_src/button-title.css b/examples_src/button-title.css new file mode 100644 index 0000000000..c1f2f96c9e --- /dev/null +++ b/examples_src/button-title.css @@ -0,0 +1,4 @@ +.tooltip-inner { + white-space: nowrap; +} + diff --git a/examples_src/button-title.html b/examples_src/button-title.html new file mode 100644 index 0000000000..c932530b5c --- /dev/null +++ b/examples_src/button-title.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Custom tooltips example" +shortdesc: "This example shows how to customize the buttons tooltips with Bootstrap." +docs: > + This example shows how to customize the buttons tooltips with Bootstrap. +tags: "custom, tooltip" +--- +
+
+
+
+
diff --git a/examples/button-title.js b/examples_src/button-title.js similarity index 100% rename from examples/button-title.js rename to examples_src/button-title.js diff --git a/examples_src/canvas-tiles.html b/examples_src/canvas-tiles.html new file mode 100644 index 0000000000..d4b051c9c0 --- /dev/null +++ b/examples_src/canvas-tiles.html @@ -0,0 +1,14 @@ +--- +template: "example.html" +title: "Canvas tiles example" +shortdesc: "Renders tiles with coordinates for debugging." +docs: > +

The black grid tiles are generated on the client with an HTML5 canvas. Note that the tile coordinates are ol3 normalized tile coordinates (origin bottom left), not + OSM tile coordinates (origin top left).

+tags: "layers, openstreetmap, canvas" +--- +
+
+
+
+
diff --git a/examples/canvas-tiles.js b/examples_src/canvas-tiles.js similarity index 100% rename from examples/canvas-tiles.js rename to examples_src/canvas-tiles.js diff --git a/examples_src/center.css b/examples_src/center.css new file mode 100644 index 0000000000..3f96011ab0 --- /dev/null +++ b/examples_src/center.css @@ -0,0 +1,56 @@ +.mapcontainer { + position: relative; + margin-bottom: 20px; +} +.map { + width: 1000px; + height: 600px; +} +div.ol-zoom { + top: 178px; + left: 158px; +} +div.ol-attribution { + bottom: 30px; + right: 50px; +} +.padding-top { + position: absolute; + top: 0; + left: 0px; + width: 1000px; + height: 170px; + background: rgba(255, 255, 255, 0.5); +} +.padding-left { + position: absolute; + top: 170px; + left: 0; + width: 150px; + height: 400px; + background: rgba(255, 255, 255, 0.5); +} +.padding-right { + position: absolute; + top: 170px; + left: 950px; + width: 50px; + height: 400px; + background: rgba(255, 255, 255, 0.5); +} +.padding-bottom { + position: absolute; + top: 570px; + left: 0px; + width: 1000px; + height: 30px; + background: rgba(255, 255, 255, 0.5); +} +.center { + position: absolute; + border: solid 1px black; + top: 490px; + left: 560px; + width: 20px; + height: 20px; +} diff --git a/examples_src/center.html b/examples_src/center.html new file mode 100644 index 0000000000..f97b0577b6 --- /dev/null +++ b/examples_src/center.html @@ -0,0 +1,34 @@ +--- +template: "example.html" +title: "Advanced View Positioning example" +shortdesc: "This example demonstrates how a map's view can be adjusted so a geometry or coordinate is positioned at a specific pixel location." +docs: > + This example demonstrates how a map's view can be + adjusted so a geometry or coordinate is positioned at a specific + pixel location. The map above has top, right, bottom, and left + padding applied inside the viewport. The view's fitGeometry method + is used to fit a geometry in the view with the same padding. The + view's centerOn method is used to position a coordinate (Lausanne) + at a specific pixel location (the center of the black box). +

Use Alt+Shift+drag to rotate the map.

+tags: "center, rotation, openstreetmap" +--- +
+
+
+
+
+
+
+
+
+
+
+
+ (best fit),
+ (respect resolution constraint).
+ (nearest),
+ (with min resolution),
+ +
+
diff --git a/examples/center.js b/examples_src/center.js similarity index 100% rename from examples/center.js rename to examples_src/center.js diff --git a/examples_src/cluster.html b/examples_src/cluster.html new file mode 100644 index 0000000000..50a1ad3f48 --- /dev/null +++ b/examples_src/cluster.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Clustering example" +shortdesc: "Example of using ol.source.Cluster." +docs: > + This example shows how to do clustering on point features. +tags: "cluster, vector" +--- +
+
+
+
+
diff --git a/examples/cluster.js b/examples_src/cluster.js similarity index 100% rename from examples/cluster.js rename to examples_src/cluster.js diff --git a/examples_src/custom-controls.css b/examples_src/custom-controls.css new file mode 100644 index 0000000000..0742513f03 --- /dev/null +++ b/examples_src/custom-controls.css @@ -0,0 +1,7 @@ +.rotate-north { + top: 65px; + left: .5em; +} +.ol-touch .rotate-north { + top: 80px; +} diff --git a/examples_src/custom-controls.html b/examples_src/custom-controls.html new file mode 100644 index 0000000000..5bb376751c --- /dev/null +++ b/examples_src/custom-controls.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Custom control example" +shortdesc: "Shows how to create custom controls." +docs: > + This example creates a "rotate to north" button. +tags: "custom, control" +--- +
+
+
+
+
diff --git a/examples/custom-controls.js b/examples_src/custom-controls.js similarity index 100% rename from examples/custom-controls.js rename to examples_src/custom-controls.js diff --git a/examples_src/d3.html b/examples_src/d3.html new file mode 100644 index 0000000000..41499bf376 --- /dev/null +++ b/examples_src/d3.html @@ -0,0 +1,14 @@ +--- +template: "example.html" +title: "d3 integration example" +shortdesc: "Example of using ol3 and d3 together." +docs: > +

The example loads TopoJSON geometries and uses d3 (d3.geo.path) to render these geometries to a canvas element that is then used as the image of an ol3 image layer.

+tags: "d3" +resources: "http://d3js.org/d3.v3.min.js,http://d3js.org/topojson.v1.min.js" +--- +
+
+
+
+
diff --git a/examples/d3.js b/examples_src/d3.js similarity index 100% rename from examples/d3.js rename to examples_src/d3.js diff --git a/examples/data/Butterfly.png b/examples_src/data/Butterfly.png similarity index 100% rename from examples/data/Butterfly.png rename to examples_src/data/Butterfly.png diff --git a/examples/data/IGNWMTSCapabilities.xml b/examples_src/data/IGNWMTSCapabilities.xml similarity index 100% rename from examples/data/IGNWMTSCapabilities.xml rename to examples_src/data/IGNWMTSCapabilities.xml diff --git a/examples/data/WMTSCapabilities.xml b/examples_src/data/WMTSCapabilities.xml similarity index 100% rename from examples/data/WMTSCapabilities.xml rename to examples_src/data/WMTSCapabilities.xml diff --git a/examples/data/arrow.png b/examples_src/data/arrow.png similarity index 100% rename from examples/data/arrow.png rename to examples_src/data/arrow.png diff --git a/examples/data/geojson/countries-110m.geojson b/examples_src/data/geojson/countries-110m.geojson similarity index 100% rename from examples/data/geojson/countries-110m.geojson rename to examples_src/data/geojson/countries-110m.geojson diff --git a/examples/data/geojson/countries.geojson b/examples_src/data/geojson/countries.geojson similarity index 100% rename from examples/data/geojson/countries.geojson rename to examples_src/data/geojson/countries.geojson diff --git a/examples/data/geojson/line-samples.geojson b/examples_src/data/geojson/line-samples.geojson similarity index 100% rename from examples/data/geojson/line-samples.geojson rename to examples_src/data/geojson/line-samples.geojson diff --git a/examples/data/geojson/point-samples.geojson b/examples_src/data/geojson/point-samples.geojson similarity index 100% rename from examples/data/geojson/point-samples.geojson rename to examples_src/data/geojson/point-samples.geojson diff --git a/examples/data/geojson/polygon-samples.geojson b/examples_src/data/geojson/polygon-samples.geojson similarity index 100% rename from examples/data/geojson/polygon-samples.geojson rename to examples_src/data/geojson/polygon-samples.geojson diff --git a/examples/data/geojson/switzerland.geojson b/examples_src/data/geojson/switzerland.geojson similarity index 100% rename from examples/data/geojson/switzerland.geojson rename to examples_src/data/geojson/switzerland.geojson diff --git a/examples/data/geolocation-orientation.json b/examples_src/data/geolocation-orientation.json similarity index 100% rename from examples/data/geolocation-orientation.json rename to examples_src/data/geolocation-orientation.json diff --git a/examples/data/geolocation_marker.png b/examples_src/data/geolocation_marker.png similarity index 100% rename from examples/data/geolocation_marker.png rename to examples_src/data/geolocation_marker.png diff --git a/examples/data/geolocation_marker_heading.png b/examples_src/data/geolocation_marker_heading.png similarity index 100% rename from examples/data/geolocation_marker_heading.png rename to examples_src/data/geolocation_marker_heading.png diff --git a/examples/data/gml/topp-states-wfs.xml b/examples_src/data/gml/topp-states-wfs.xml similarity index 100% rename from examples/data/gml/topp-states-wfs.xml rename to examples_src/data/gml/topp-states-wfs.xml diff --git a/examples/data/gpx/fells_loop.gpx b/examples_src/data/gpx/fells_loop.gpx similarity index 100% rename from examples/data/gpx/fells_loop.gpx rename to examples_src/data/gpx/fells_loop.gpx diff --git a/examples/data/icon.png b/examples_src/data/icon.png similarity index 100% rename from examples/data/icon.png rename to examples_src/data/icon.png diff --git a/examples/data/igc/Clement-Latour.igc b/examples_src/data/igc/Clement-Latour.igc similarity index 100% rename from examples/data/igc/Clement-Latour.igc rename to examples_src/data/igc/Clement-Latour.igc diff --git a/examples/data/igc/Damien-de-Baenst.igc b/examples_src/data/igc/Damien-de-Baenst.igc similarity index 100% rename from examples/data/igc/Damien-de-Baenst.igc rename to examples_src/data/igc/Damien-de-Baenst.igc diff --git a/examples/data/igc/Sylvain-Dhonneur.igc b/examples_src/data/igc/Sylvain-Dhonneur.igc similarity index 100% rename from examples/data/igc/Sylvain-Dhonneur.igc rename to examples_src/data/igc/Sylvain-Dhonneur.igc diff --git a/examples/data/igc/Tom-Payne.igc b/examples_src/data/igc/Tom-Payne.igc similarity index 100% rename from examples/data/igc/Tom-Payne.igc rename to examples_src/data/igc/Tom-Payne.igc diff --git a/examples/data/igc/Ulrich-Prinz.igc b/examples_src/data/igc/Ulrich-Prinz.igc similarity index 100% rename from examples/data/igc/Ulrich-Prinz.igc rename to examples_src/data/igc/Ulrich-Prinz.igc diff --git a/examples/data/kml/2012-02-10.kml b/examples_src/data/kml/2012-02-10.kml similarity index 100% rename from examples/data/kml/2012-02-10.kml rename to examples_src/data/kml/2012-02-10.kml diff --git a/examples/data/kml/2012_Earthquakes_Mag5.kml b/examples_src/data/kml/2012_Earthquakes_Mag5.kml similarity index 100% rename from examples/data/kml/2012_Earthquakes_Mag5.kml rename to examples_src/data/kml/2012_Earthquakes_Mag5.kml diff --git a/examples/data/kml/timezones.kml b/examples_src/data/kml/timezones.kml similarity index 100% rename from examples/data/kml/timezones.kml rename to examples_src/data/kml/timezones.kml diff --git a/examples/data/ogcsample.xml b/examples_src/data/ogcsample.xml similarity index 100% rename from examples/data/ogcsample.xml rename to examples_src/data/ogcsample.xml diff --git a/examples/data/sld/countries.sld b/examples_src/data/sld/countries.sld similarity index 100% rename from examples/data/sld/countries.sld rename to examples_src/data/sld/countries.sld diff --git a/examples/data/topojson/us.json b/examples_src/data/topojson/us.json similarity index 100% rename from examples/data/topojson/us.json rename to examples_src/data/topojson/us.json diff --git a/examples/data/topojson/world-110m.json b/examples_src/data/topojson/world-110m.json similarity index 100% rename from examples/data/topojson/world-110m.json rename to examples_src/data/topojson/world-110m.json diff --git a/examples_src/device-orientation.html b/examples_src/device-orientation.html new file mode 100644 index 0000000000..418d25cca1 --- /dev/null +++ b/examples_src/device-orientation.html @@ -0,0 +1,23 @@ +--- +template: "example.html" +title: "Device-Orientation example" +shortdesc: "Listen to DeviceOrientation events." +docs: > + This example shows how to track changes in device orientation. +tags: "orientation, openstreetmap" +--- +
+
+
+
+

Device orientation example

+ +

α :

+

β :

+

γ :

+

heading :

+
+
+
diff --git a/examples/device-orientation.js b/examples_src/device-orientation.js similarity index 100% rename from examples/device-orientation.js rename to examples_src/device-orientation.js diff --git a/examples_src/drag-and-drop-image-vector.html b/examples_src/drag-and-drop-image-vector.html new file mode 100644 index 0000000000..83879d4747 --- /dev/null +++ b/examples_src/drag-and-drop-image-vector.html @@ -0,0 +1,19 @@ +--- +template: "example.html" +title: "Drag-and-Drop image vector example" +shortdesc: "Example of using the drag-and-drop interaction with a ol.source.ImageVector. Drag and drop GPX, GeoJSON, IGC, KML, or TopoJSON files on to the map. Each file is rendered to an image on the client." +docs: > + Example of using the drag-and-drop interaction with a ol.source.ImageVector. Drag and drop GPX, GeoJSON, IGC, KML, or TopoJSON files on to the map. Each file is rendered to + an image on the client. +tags: "drag-and-drop-image-vector, gpx, geojson, igc, kml, topojson, vector, image" +--- +
+
+
+
+
+   +
+
+
+
diff --git a/examples/drag-and-drop-image-vector.js b/examples_src/drag-and-drop-image-vector.js similarity index 100% rename from examples/drag-and-drop-image-vector.js rename to examples_src/drag-and-drop-image-vector.js diff --git a/examples_src/drag-and-drop.html b/examples_src/drag-and-drop.html new file mode 100644 index 0000000000..fd8f2b9f5e --- /dev/null +++ b/examples_src/drag-and-drop.html @@ -0,0 +1,19 @@ +--- +template: "example.html" +title: "Drag-and-Drop example" +shortdesc: "Example of using the drag-and-drop interaction. Drag and drop GPX, GeoJSON, IGC, KML, or TopoJSON files on to the map. There is no projection transform support, so this will only work with data in EPSG:4326 and EPSG:3857." +docs: > + Example of using the drag-and-drop interaction. Drag and drop GPX, GeoJSON, IGC, KML, or TopoJSON files on to the map. There is no projection transform support, so this will + only work with data in EPSG:4326 and EPSG:3857. +tags: "drag-and-drop, gpx, geojson, igc, kml, topojson" +--- +
+
+
+
+
+   +
+
+
+
diff --git a/examples/drag-and-drop.js b/examples_src/drag-and-drop.js similarity index 100% rename from examples/drag-and-drop.js rename to examples_src/drag-and-drop.js diff --git a/examples_src/drag-features.html b/examples_src/drag-features.html new file mode 100644 index 0000000000..d3d9aa0d8a --- /dev/null +++ b/examples_src/drag-features.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Drag features example" +shortdesc: "Example of a drag features interaction." +docs: > + The drag features interaction can be used to drag features to a new position. +tags: "drag, feature, vector, editing" +--- +
+
+
+
+
diff --git a/examples/drag-features.js b/examples_src/drag-features.js similarity index 100% rename from examples/drag-features.js rename to examples_src/drag-features.js diff --git a/examples_src/drag-rotate-and-zoom.html b/examples_src/drag-rotate-and-zoom.html new file mode 100644 index 0000000000..07928c1c7b --- /dev/null +++ b/examples_src/drag-rotate-and-zoom.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Drag rotate and zoom example" +shortdesc: "A single interaction to drag, rotate, and zoom." +docs: > +

Shift + Drag to rotate and zoom the map around its center.

+tags: "drag, rotate, zoom, interaction" +--- +
+
+
+
+
diff --git a/examples/drag-rotate-and-zoom.js b/examples_src/drag-rotate-and-zoom.js similarity index 100% rename from examples/drag-rotate-and-zoom.js rename to examples_src/drag-rotate-and-zoom.js diff --git a/examples_src/draw-and-modify-features.html b/examples_src/draw-and-modify-features.html new file mode 100644 index 0000000000..b0030d6f5f --- /dev/null +++ b/examples_src/draw-and-modify-features.html @@ -0,0 +1,21 @@ +--- +template: "example.html" +title: "Draw and modify features example" +shortdesc: "Example of using the ol.interaction.Draw interaction together with the ol.interaction.Modify interaction." +docs: > + Example of using the ol.interaction.Draw interaction together with the ol.interaction.Modify interaction. +tags: "draw, edit, modify, vector, featureoverlay" +--- +
+
+
+
+
+ + +
+
diff --git a/examples/draw-and-modify-features.js b/examples_src/draw-and-modify-features.js similarity index 100% rename from examples/draw-and-modify-features.js rename to examples_src/draw-and-modify-features.js diff --git a/examples_src/draw-features.html b/examples_src/draw-features.html new file mode 100644 index 0000000000..2f00e27698 --- /dev/null +++ b/examples_src/draw-features.html @@ -0,0 +1,23 @@ +--- +template: "example.html" +title: "Draw features example" +shortdesc: "Example of using the ol.interaction.Draw interaction." +docs: > + Example of using the ol.interaction.Draw interaction. +tags: "draw, edit, vector" +--- +
+
+
+
+ + +
+
+
diff --git a/examples/draw-features.js b/examples_src/draw-features.js similarity index 100% rename from examples/draw-features.js rename to examples_src/draw-features.js diff --git a/examples_src/dynamic-data.html b/examples_src/dynamic-data.html new file mode 100644 index 0000000000..39cddfd3ee --- /dev/null +++ b/examples_src/dynamic-data.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Dynamic data example" +shortdesc: "Example of dynamic data." +docs: > + Example of dynamic data. +tags: "dynamic-data" +--- +
+
+
+
+
diff --git a/examples/dynamic-data.js b/examples_src/dynamic-data.js similarity index 100% rename from examples/dynamic-data.js rename to examples_src/dynamic-data.js diff --git a/examples_src/earthquake-clusters.css b/examples_src/earthquake-clusters.css new file mode 100644 index 0000000000..a73813d649 --- /dev/null +++ b/examples_src/earthquake-clusters.css @@ -0,0 +1,19 @@ +#map { + position: relative; +} +#info { + position: absolute; + height: 1px; + width: 1px; + z-index: 100; +} +.tooltip.in { + opacity: 1; + filter: alpha(opacity=100); +} +.tooltip.top .tooltip-arrow { + border-top-color: white; +} +.tooltip-inner { + border: 2px solid white; +} diff --git a/examples_src/earthquake-clusters.html b/examples_src/earthquake-clusters.html new file mode 100644 index 0000000000..f8f414cc35 --- /dev/null +++ b/examples_src/earthquake-clusters.html @@ -0,0 +1,16 @@ +--- +template: "example.html" +title: "Earthquake Clusters" +shortdesc: "Demonstrates the use of style geometries to render source features of a cluster." +docs: > +

This example parses a KML file and renders the features as clusters on a vector layer. The styling in this example is quite involved. Single earthquake locations + (rendered as stars) have a size relative to their magnitude. Clusters have an opacity relative to the number of features in the cluster, and a size that represents + the extent of the features that make up the cluster. When clicking or hovering on a cluster, the individual features that make up the cluster will be shown.

+

To achieve this, we make heavy use of style functions and ol.style.Style#geometry.

+tags: "KML, vector, style, geometry, cluster" +--- +
+
+
+
+
diff --git a/examples/earthquake-clusters.js b/examples_src/earthquake-clusters.js similarity index 100% rename from examples/earthquake-clusters.js rename to examples_src/earthquake-clusters.js diff --git a/examples_src/epsg-4326.html b/examples_src/epsg-4326.html new file mode 100644 index 0000000000..13650d1d91 --- /dev/null +++ b/examples_src/epsg-4326.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "EPSG:4326 example" +shortdesc: "Example of a map in EPSG:4326." +docs: > + This example shows how to create a map in EPSG:4326. +tags: "epsg4326" +--- +
+
+
+
+
diff --git a/examples/epsg-4326.js b/examples_src/epsg-4326.js similarity index 100% rename from examples/epsg-4326.js rename to examples_src/epsg-4326.js diff --git a/examples_src/export-map.html b/examples_src/export-map.html new file mode 100644 index 0000000000..fe23c0884e --- /dev/null +++ b/examples_src/export-map.html @@ -0,0 +1,18 @@ +--- +template: "example.html" +title: "Export map example" +shortdesc: "Example of exporting a map as a PNG image." +docs: > + Example of exporting a map as a PNG image. +tags: "export, png, openstreetmap" +--- +
+
+
+ + Export PNG +
+
diff --git a/examples/export-map.js b/examples_src/export-map.js similarity index 100% rename from examples/export-map.js rename to examples_src/export-map.js diff --git a/examples_src/fractal.css b/examples_src/fractal.css new file mode 100644 index 0000000000..3137217cf6 --- /dev/null +++ b/examples_src/fractal.css @@ -0,0 +1,6 @@ +.map { + background: whitesmoke; +} +#depth { + width: 100px; +} diff --git a/examples_src/fractal.html b/examples_src/fractal.html new file mode 100644 index 0000000000..2d624cf154 --- /dev/null +++ b/examples_src/fractal.html @@ -0,0 +1,18 @@ +--- +template: "example.html" +title: "Fractal Example" +shortdesc: "Example of a fractal." +docs: > + Example of a fractal. +tags: "fractal, vector" +--- +
+
+
+ +
+
diff --git a/examples/fractal.js b/examples_src/fractal.js similarity index 100% rename from examples/fractal.js rename to examples_src/fractal.js diff --git a/examples_src/full-screen-drag-rotate-and-zoom.css b/examples_src/full-screen-drag-rotate-and-zoom.css new file mode 100644 index 0000000000..510e73ea40 --- /dev/null +++ b/examples_src/full-screen-drag-rotate-and-zoom.css @@ -0,0 +1,13 @@ +.map:-moz-full-screen { + height: 100%; +} +.map:-webkit-full-screen { + height: 100%; +} +.map:fullscreen { + height: 100%; +} +/* position the rotate control lower than usual */ +.ol-rotate { + top: 3em; +} diff --git a/examples_src/full-screen-drag-rotate-and-zoom.html b/examples_src/full-screen-drag-rotate-and-zoom.html new file mode 100644 index 0000000000..e6e93999e0 --- /dev/null +++ b/examples_src/full-screen-drag-rotate-and-zoom.html @@ -0,0 +1,14 @@ +--- +template: "example.html" +title: "Full screen drag rotate and zoom example" +shortdesc: "Example of drag rotate and zoom control with full screen effect." +docs: > +

Hold down Shift + drag to rotate and zoom. Click the button in the top right corner to go full screen. Then do the Shift + drag thing again.

+

If there is no button on the map, your browser does not support the Full Screen API.

+tags: "full-screen, drag, rotate, zoom, bing, bing-maps" +--- +
+
+
+
+
diff --git a/examples/full-screen-drag-rotate-and-zoom.js b/examples_src/full-screen-drag-rotate-and-zoom.js similarity index 100% rename from examples/full-screen-drag-rotate-and-zoom.js rename to examples_src/full-screen-drag-rotate-and-zoom.js diff --git a/examples_src/full-screen.css b/examples_src/full-screen.css new file mode 100644 index 0000000000..8b28c0651c --- /dev/null +++ b/examples_src/full-screen.css @@ -0,0 +1,15 @@ +.map:-moz-full-screen { + height: 100%; +} +.map:-webkit-full-screen { + height: 100%; +} +.map:-ms-fullscreen { + height: 100%; +} +.map:fullscreen { + height: 100%; +} +.ol-rotate { + top: 3em; +} diff --git a/examples_src/full-screen.html b/examples_src/full-screen.html new file mode 100644 index 0000000000..176c83b491 --- /dev/null +++ b/examples_src/full-screen.html @@ -0,0 +1,14 @@ +--- +template: "example.html" +title: "Full screen control example" +shortdesc: "Example of a full screen control." +docs: > +

Click the control in the top right corner to go full screen. Click it again to exit full screen.

+

If there is no button on the map, your browser does not support the Full Screen API.

+tags: "full-screen, bing, bing-maps" +--- +
+
+
+
+
diff --git a/examples/full-screen.js b/examples_src/full-screen.js similarity index 100% rename from examples/full-screen.js rename to examples_src/full-screen.js diff --git a/examples_src/geojson.html b/examples_src/geojson.html new file mode 100644 index 0000000000..a064983427 --- /dev/null +++ b/examples_src/geojson.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "GeoJSON example" +shortdesc: "Example of GeoJSON features." +docs: > + Example of GeoJSON features. +tags: "geojson, vector, openstreetmap" +--- +
+
+
+
+
diff --git a/examples/geojson.js b/examples_src/geojson.js similarity index 100% rename from examples/geojson.js rename to examples_src/geojson.js diff --git a/examples/geolocation-orientation.html b/examples_src/geolocation-orientation.html similarity index 97% rename from examples/geolocation-orientation.html rename to examples_src/geolocation-orientation.html index 5dd4fe3f61..a65ee833bd 100644 --- a/examples/geolocation-orientation.html +++ b/examples_src/geolocation-orientation.html @@ -1,3 +1,6 @@ +--- +template: "example-verbatim.html" +--- diff --git a/examples/geolocation-orientation.js b/examples_src/geolocation-orientation.js similarity index 100% rename from examples/geolocation-orientation.js rename to examples_src/geolocation-orientation.js diff --git a/examples_src/geolocation.html b/examples_src/geolocation.html new file mode 100644 index 0000000000..0d6b207818 --- /dev/null +++ b/examples_src/geolocation.html @@ -0,0 +1,24 @@ +--- +template: "example.html" +title: "Geolocation example" +shortdesc: "Example of a geolocation map." +docs: > + Example of a geolocation map. +tags: "geolocation, openstreetmap" +--- +
+
+
+
+ +
+ +

position accuracy :

+

altitude :

+

altitude accuracy :

+

heading :

+

speed :

+
+
diff --git a/examples/geolocation.js b/examples_src/geolocation.js similarity index 100% rename from examples/geolocation.js rename to examples_src/geolocation.js diff --git a/examples_src/getfeatureinfo-image.html b/examples_src/getfeatureinfo-image.html new file mode 100644 index 0000000000..d44b7f7a7a --- /dev/null +++ b/examples_src/getfeatureinfo-image.html @@ -0,0 +1,18 @@ +--- +template: "example.html" +title: "GetFeatureInfo example (image layer)" +shortdesc: "This example shows how to trigger WMS GetFeatureInfo requests on click for a WMS image layer." +docs: > +

Additionally map.forEachLayerAtPixel is used to change the mouse pointer when hovering a non-transparent pixel on the map.

+tags: "getfeatureinfo, forEachLayerAtPixel" +--- +
+
+
+
+
+   +
+
+
+
diff --git a/examples/getfeatureinfo-image.js b/examples_src/getfeatureinfo-image.js similarity index 100% rename from examples/getfeatureinfo-image.js rename to examples_src/getfeatureinfo-image.js diff --git a/examples_src/getfeatureinfo-tile.html b/examples_src/getfeatureinfo-tile.html new file mode 100644 index 0000000000..7743beef4d --- /dev/null +++ b/examples_src/getfeatureinfo-tile.html @@ -0,0 +1,18 @@ +--- +template: "example.html" +title: "WMS GetFeatureInfo example (tile layer)" +shortdesc: "This example shows how to trigger WMS GetFeatureInfo requests on click for a WMS tile layer." +docs: > +

Additionally map.forEachLayerAtPixel is used to change the mouse pointer when hovering a non-transparent pixel on the map.

+tags: "getfeatureinfo, forEachLayerAtPixel" +--- +
+
+
+
+
+   +
+
+
+
diff --git a/examples/getfeatureinfo-tile.js b/examples_src/getfeatureinfo-tile.js similarity index 100% rename from examples/getfeatureinfo-tile.js rename to examples_src/getfeatureinfo-tile.js diff --git a/examples_src/gpx.html b/examples_src/gpx.html new file mode 100644 index 0000000000..38729dad13 --- /dev/null +++ b/examples_src/gpx.html @@ -0,0 +1,25 @@ +--- +template: "example.html" +title: "GPX example" +shortdesc: "Example of using the GPX source." +docs: > + Example of using the GPX source. +tags: "GPX" +--- +
+
+
+
+
+   +
+
+ + Export GPX +
+
+
+ \ No newline at end of file diff --git a/examples/gpx.js b/examples_src/gpx.js similarity index 100% rename from examples/gpx.js rename to examples_src/gpx.js diff --git a/examples_src/graticule.html b/examples_src/graticule.html new file mode 100644 index 0000000000..3e89dfba2c --- /dev/null +++ b/examples_src/graticule.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Graticule example" +shortdesc: "This example shows how to add a graticule overlay to a map." +docs: > + This example shows how to add a graticule overlay to a map. +tags: "graticule" +--- +
+
+
+
+
diff --git a/examples/graticule.js b/examples_src/graticule.js similarity index 100% rename from examples/graticule.js rename to examples_src/graticule.js diff --git a/examples_src/heatmap-earthquakes.html b/examples_src/heatmap-earthquakes.html new file mode 100644 index 0000000000..473d128ca8 --- /dev/null +++ b/examples_src/heatmap-earthquakes.html @@ -0,0 +1,21 @@ +--- +template: "example.html" +title: "Earthquakes heatmap" +shortdesc: "Demonstrates the use of a heatmap layer." +docs: > + This example parses a KML file and renders the features as a ol.layer.Heatmap layer. +tags: "heatmap, kml, vector, style" +--- +
+
+
+
+
+
+ + + + +
+
+
diff --git a/examples/heatmap-earthquakes.js b/examples_src/heatmap-earthquakes.js similarity index 100% rename from examples/heatmap-earthquakes.js rename to examples_src/heatmap-earthquakes.js diff --git a/examples_src/hue-saturation.css b/examples_src/hue-saturation.css new file mode 100644 index 0000000000..59a9ea8a69 --- /dev/null +++ b/examples_src/hue-saturation.css @@ -0,0 +1,6 @@ +#reset-hue { + min-width: 90px; +} +#reset-saturation { + min-width: 124px; +} diff --git a/examples_src/hue-saturation.html b/examples_src/hue-saturation.html new file mode 100644 index 0000000000..72b8075e37 --- /dev/null +++ b/examples_src/hue-saturation.html @@ -0,0 +1,26 @@ +--- +template: "example.html" +title: "Hue/saturation example" +shortdesc: "Example of hue/saturation control on the client (WebGL only)." +docs: > + Example of hue/saturation control on the client (WebGL only). +tags: "custom, control" +--- +
+
+
+ +
+ + + +
+
+ + + +
+
+
diff --git a/examples/hue-saturation.js b/examples_src/hue-saturation.js similarity index 100% rename from examples/hue-saturation.js rename to examples_src/hue-saturation.js diff --git a/examples_src/icon-sprite-webgl.html b/examples_src/icon-sprite-webgl.html new file mode 100644 index 0000000000..f44a060ad3 --- /dev/null +++ b/examples_src/icon-sprite-webgl.html @@ -0,0 +1,18 @@ +--- +template: "example.html" +title: "Icon sprites with WebGL example" +shortdesc: "Icon sprite with WebGL" +docs: > +

In this example a sprite image is used for the icon styles. Using a sprite is required to get good performance with WebGL.

+tags: "webgl, icon, sprite, vector, point" +--- +
+
+
+
+
+   +
+
+
+
diff --git a/examples/icon-sprite-webgl.js b/examples_src/icon-sprite-webgl.js similarity index 100% rename from examples/icon-sprite-webgl.js rename to examples_src/icon-sprite-webgl.js diff --git a/examples_src/icon.css b/examples_src/icon.css new file mode 100644 index 0000000000..3881884e22 --- /dev/null +++ b/examples_src/icon.css @@ -0,0 +1,6 @@ +#map { + position: relative; +} +#popup { + padding-bottom: 45px; +} \ No newline at end of file diff --git a/examples_src/icon.html b/examples_src/icon.html new file mode 100644 index 0000000000..8fa391abf8 --- /dev/null +++ b/examples_src/icon.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Vector Icon Example" +shortdesc: "Example using an icon to symbolize a point." +docs: > + Example using an icon to symbolize a point. +tags: "vector, style, icon, marker, popup" +--- +
+
+
+
+
diff --git a/examples/icon.js b/examples_src/icon.js similarity index 100% rename from examples/icon.js rename to examples_src/icon.js diff --git a/examples_src/igc.html b/examples_src/igc.html new file mode 100644 index 0000000000..cffea1281d --- /dev/null +++ b/examples_src/igc.html @@ -0,0 +1,19 @@ +--- +template: "example.html" +title: "IGC example" +shortdesc: "Example of tracks recorded from multiple paraglider flights on the same day, read from an IGC file." +docs: > +

The five tracks contain a total of 49,707 unique coordinates. Zoom in to see more detail. The background layer is from OpenCycleMap.

+tags: "complex-geometry, closest-feature, igc, opencyclemap" +--- +
+
+
+ +
+
+   +
+
+
+
diff --git a/examples/igc.js b/examples_src/igc.js similarity index 100% rename from examples/igc.js rename to examples_src/igc.js diff --git a/examples_src/image-filter.html b/examples_src/image-filter.html new file mode 100644 index 0000000000..c16e35a811 --- /dev/null +++ b/examples_src/image-filter.html @@ -0,0 +1,24 @@ +--- +template: "example.html" +title: "Image Filter Example" +shortdesc: "Apply a filter to imagery" +docs: > +

Layer rendering can be manipulated in precompose and postcompose event listeners. + These listeners get an event with a reference to the Canvas rendering context. + In this example, the postcompose listener applies a filter to the image data.

+tags: "filter, image manipulation" +--- +
+
+
+
+
+ diff --git a/examples/image-filter.js b/examples_src/image-filter.js similarity index 100% rename from examples/image-filter.js rename to examples_src/image-filter.js diff --git a/examples_src/image-load-events.css b/examples_src/image-load-events.css new file mode 100644 index 0000000000..0bd164d656 --- /dev/null +++ b/examples_src/image-load-events.css @@ -0,0 +1,15 @@ +.map { + background: #E0ECED; +} +.wrapper { + position: relative; +} +#progress { + position: absolute; + bottom: 0; + left: 0; + height: 2px; + background: rgba(0, 60, 136, 0.4); + width: 0; + transition: width 250ms; +} \ No newline at end of file diff --git a/examples_src/image-load-events.html b/examples_src/image-load-events.html new file mode 100644 index 0000000000..37125d3c73 --- /dev/null +++ b/examples_src/image-load-events.html @@ -0,0 +1,18 @@ +--- +template: "example.html" +title: "Image load events example" +shortdesc: "Example using image load events." +docs: > +

Image sources fire events related to image loading. You can + listen for imageloadstart, imageloadend, + and imageloaderror type events to monitor image loading + progress. This example registers listeners for these events and + renders an image loading progress bar at the bottom of the map.

+tags: "image, events, loading" +--- +
+
+
+
+
+
diff --git a/examples/image-load-events.js b/examples_src/image-load-events.js similarity index 100% rename from examples/image-load-events.js rename to examples_src/image-load-events.js diff --git a/examples_src/image-vector-layer.html b/examples_src/image-vector-layer.html new file mode 100644 index 0000000000..f9eb402a97 --- /dev/null +++ b/examples_src/image-vector-layer.html @@ -0,0 +1,20 @@ +--- +template: "example.html" +title: "Image vector layer example" +shortdesc: "Example of an image vector layer." +docs: > +

This example uses a ol.source.ImageVector source. That source gets vector features from the + ol.source.Vector it's configured with, and draw these features to an HTML5 canvas element that + is then used as the image of an image layer.

+tags: "vector, image" +--- +
+
+
+
+
+   +
+
+
+
diff --git a/examples/image-vector-layer.js b/examples_src/image-vector-layer.js similarity index 100% rename from examples/image-vector-layer.js rename to examples_src/image-vector-layer.js diff --git a/examples/index.html b/examples_src/index.html similarity index 100% rename from examples/index.html rename to examples_src/index.html diff --git a/examples_src/kml-earthquakes.css b/examples_src/kml-earthquakes.css new file mode 100644 index 0000000000..a73813d649 --- /dev/null +++ b/examples_src/kml-earthquakes.css @@ -0,0 +1,19 @@ +#map { + position: relative; +} +#info { + position: absolute; + height: 1px; + width: 1px; + z-index: 100; +} +.tooltip.in { + opacity: 1; + filter: alpha(opacity=100); +} +.tooltip.top .tooltip-arrow { + border-top-color: white; +} +.tooltip-inner { + border: 2px solid white; +} diff --git a/examples_src/kml-earthquakes.html b/examples_src/kml-earthquakes.html new file mode 100644 index 0000000000..407be33860 --- /dev/null +++ b/examples_src/kml-earthquakes.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Earthquakes in KML" +shortdesc: "Demonstrates the use of a Shape symbolizer to render earthquake locations." +docs: > + This example parses a KML file and renders the features as a vector layer. The layer is given a style that renders earthquake locations with a size relative to their magnitude. +tags: "KML, vector, style, tooltip" +--- +
+
+
+
+
\ No newline at end of file diff --git a/examples/kml-earthquakes.js b/examples_src/kml-earthquakes.js similarity index 100% rename from examples/kml-earthquakes.js rename to examples_src/kml-earthquakes.js diff --git a/examples_src/kml-timezones.css b/examples_src/kml-timezones.css new file mode 100644 index 0000000000..bdd40f44a4 --- /dev/null +++ b/examples_src/kml-timezones.css @@ -0,0 +1,9 @@ +#map { + position: relative; +} +#info { + position: absolute; + height: 1px; + width: 1px; + z-index: 100; +} diff --git a/examples_src/kml-timezones.html b/examples_src/kml-timezones.html new file mode 100644 index 0000000000..3c9a4b1635 --- /dev/null +++ b/examples_src/kml-timezones.html @@ -0,0 +1,14 @@ +--- +template: "example.html" +title: "Timezones in KML" +shortdesc: "Demonstrates rendering timezones from KML." +docs: > + This example parses a KML file and renders the features as a vector layer. The layer is given a ol.style.Style that fills timezones + yellow with an opacity calculated based on the current offset to local noon. +tags: "KML, vector, style" +--- +
+
+
+
+
diff --git a/examples/kml-timezones.js b/examples_src/kml-timezones.js similarity index 100% rename from examples/kml-timezones.js rename to examples_src/kml-timezones.js diff --git a/examples_src/kml.html b/examples_src/kml.html new file mode 100644 index 0000000000..bb9726a57b --- /dev/null +++ b/examples_src/kml.html @@ -0,0 +1,23 @@ +--- +template: "example.html" +title: "KML example" +shortdesc: "Example of using the KML source." +docs: > + Example of using the KML source. +tags: "KML" +--- +
+
+
+
+
+   +
+
+ + Export KML +
+
diff --git a/examples/kml.js b/examples_src/kml.js similarity index 100% rename from examples/kml.js rename to examples_src/kml.js diff --git a/examples_src/layer-clipping-webgl.html b/examples_src/layer-clipping-webgl.html new file mode 100644 index 0000000000..5a76fac0f7 --- /dev/null +++ b/examples_src/layer-clipping-webgl.html @@ -0,0 +1,16 @@ +--- +template: "example.html" +title: "Layer WebGL clipping example" +shortdesc: "Layer WebGL clipping example." +docs: > + This example shows how to use the precompose and postcompose rendering hooks to clip layers using WebGL. +tags: "clipping, webgl, openstreetmap" +--- +
+
+
+
+
+ diff --git a/examples/layer-clipping-webgl.js b/examples_src/layer-clipping-webgl.js similarity index 100% rename from examples/layer-clipping-webgl.js rename to examples_src/layer-clipping-webgl.js diff --git a/examples_src/layer-clipping.html b/examples_src/layer-clipping.html new file mode 100644 index 0000000000..31c0724a18 --- /dev/null +++ b/examples_src/layer-clipping.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Layer clipping example" +shortdesc: "Layer clipping example" +docs: > + Layer clipping example +tags: "clipping, openstreetmap" +--- +
+
+
+
+
diff --git a/examples/layer-clipping.js b/examples_src/layer-clipping.js similarity index 100% rename from examples/layer-clipping.js rename to examples_src/layer-clipping.js diff --git a/examples_src/layer-extent.html b/examples_src/layer-extent.html new file mode 100644 index 0000000000..7aaa2d3b1f --- /dev/null +++ b/examples_src/layer-extent.html @@ -0,0 +1,22 @@ +--- +template: "example.html" +title: "Limited Layer Extent" +shortdesc: "Restricting layer rendering to a limited extent." +docs: > + This example uses the layer.setExtent() method to + modify the extent of the overlay layer. Use the controls below + to limit rendering based on an extent. +tags: "extent, tilejson" +--- +
+
+
+
+
+
+ + + + + +
diff --git a/examples/layer-extent.js b/examples_src/layer-extent.js similarity index 100% rename from examples/layer-extent.js rename to examples_src/layer-extent.js diff --git a/examples_src/layer-group.css b/examples_src/layer-group.css new file mode 100644 index 0000000000..31cb3e6cf1 --- /dev/null +++ b/examples_src/layer-group.css @@ -0,0 +1,3 @@ +#layertree li > span { + cursor: pointer; +} \ No newline at end of file diff --git a/examples_src/layer-group.html b/examples_src/layer-group.html new file mode 100644 index 0000000000..b0f34534a5 --- /dev/null +++ b/examples_src/layer-group.html @@ -0,0 +1,88 @@ +--- +template: "example.html" +title: "Layer group example" +shortdesc: "Example of a map with layer group." +docs: > + Example of a map with layer group. +tags: "tilejson, input, bind, group, layergroup" +--- +
+
+
+
+
+
Click on layer nodes below to change their properties.
+ +
+
diff --git a/examples/layer-group.js b/examples_src/layer-group.js similarity index 100% rename from examples/layer-group.js rename to examples_src/layer-group.js diff --git a/examples_src/layer-spy.html b/examples_src/layer-spy.html new file mode 100644 index 0000000000..4cdfa1b3ec --- /dev/null +++ b/examples_src/layer-spy.html @@ -0,0 +1,17 @@ +--- +template: "example.html" +title: "Layer Spy Example" +shortdesc: "View a portion of one layer over another" +docs: > +

Layer rendering can be manipulated in precompose and postcompose event listeners. + These listeners get an event with a reference to the Canvas rendering context. + In this example, the precompose listener sets a clipping mask around the most + recent mouse position, giving you a spyglass effect for viewing one layer over another.

+

Move around the map to see the effect. Use the ↑ up and ↓ down arrow keys to adjust the spyglass size.

+tags: "spy, image manipulation" +--- +
+
+
+
+
diff --git a/examples/layer-spy.js b/examples_src/layer-spy.js similarity index 100% rename from examples/layer-spy.js rename to examples_src/layer-spy.js diff --git a/examples_src/layer-swipe.html b/examples_src/layer-swipe.html new file mode 100644 index 0000000000..f704b6cfb0 --- /dev/null +++ b/examples_src/layer-swipe.html @@ -0,0 +1,14 @@ +--- +template: "example.html" +title: "Layer Swipe example" +shortdesc: "Example of a Layer swipe map." +docs: > + Example of a Layer swipe map. +tags: "swipe, openstreetmap" +--- +
+
+
+ +
+
\ No newline at end of file diff --git a/examples/layer-swipe.js b/examples_src/layer-swipe.js similarity index 100% rename from examples/layer-swipe.js rename to examples_src/layer-swipe.js diff --git a/examples_src/lazy-source.css b/examples_src/lazy-source.css new file mode 100644 index 0000000000..1803215980 --- /dev/null +++ b/examples_src/lazy-source.css @@ -0,0 +1,6 @@ + button.code { + font-family: Monaco,Menlo,Consolas,"Courier New",monospace; + font-size: 12px; + padding: 5px; + margin: 0 5px; + } \ No newline at end of file diff --git a/examples_src/lazy-source.html b/examples_src/lazy-source.html new file mode 100644 index 0000000000..f8e80b744d --- /dev/null +++ b/examples_src/lazy-source.html @@ -0,0 +1,20 @@ +--- +template: "example.html" +title: "Lazy Source" +shortdesc: "Example of setting a layer source after construction." +docs: > +

Typically, the source for a layer is provided to the layer constructor. + If you need to set a layer source after construction, this can be + done with the layer.setSource() method.

+

The layer in the map above is constructed with no source. Use the + links below to set/unset the layer source. A layer is not rendered + until its source is set.

+tags: "source" +--- +
+
+
+
+
+ + \ No newline at end of file diff --git a/examples/lazy-source.js b/examples_src/lazy-source.js similarity index 100% rename from examples/lazy-source.js rename to examples_src/lazy-source.js diff --git a/examples_src/line-arrows.html b/examples_src/line-arrows.html new file mode 100644 index 0000000000..8e5f65d47d --- /dev/null +++ b/examples_src/line-arrows.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "LineString arrows example" +shortdesc: "Example of drawing arrows for each line string segment." +docs: > + Example of drawing arrows for each line string segment. +tags: "draw, vector, arrow" +--- +
+
+
+
+
diff --git a/examples/line-arrows.js b/examples_src/line-arrows.js similarity index 100% rename from examples/line-arrows.js rename to examples_src/line-arrows.js diff --git a/examples_src/localized-openstreetmap.html b/examples_src/localized-openstreetmap.html new file mode 100644 index 0000000000..9f2ba9145e --- /dev/null +++ b/examples_src/localized-openstreetmap.html @@ -0,0 +1,14 @@ +--- +template: "example.html" +title: "Localized OpenStreetMap example" +shortdesc: "Example of a localized OpenStreetMap map with a custom tile server and a custom attribution." +docs: > +

The base layer is OpenCycleMap with an overlay from OpenSeaMap. The OpenSeaMap tile server + does not support CORS headers.

+tags: "cors, localized-openstreetmap, openseamap, openstreetmap" +--- +
+
+
+
+
diff --git a/examples/localized-openstreetmap.js b/examples_src/localized-openstreetmap.js similarity index 100% rename from examples/localized-openstreetmap.js rename to examples_src/localized-openstreetmap.js diff --git a/examples_src/mapguide-untiled.html b/examples_src/mapguide-untiled.html new file mode 100644 index 0000000000..31a2d5d810 --- /dev/null +++ b/examples_src/mapguide-untiled.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "MapGuide untiled example" +shortdesc: "Example of a untiled MapGuide map." +docs: > + Example of a untiled MapGuide map. +tags: "mapguide" +--- +
+
+
+
+
diff --git a/examples/mapguide-untiled.js b/examples_src/mapguide-untiled.js similarity index 100% rename from examples/mapguide-untiled.js rename to examples_src/mapguide-untiled.js diff --git a/examples_src/mapquest.html b/examples_src/mapquest.html new file mode 100644 index 0000000000..fad64c1621 --- /dev/null +++ b/examples_src/mapquest.html @@ -0,0 +1,18 @@ +--- +template: "example.html" +title: "MapQuest example" +shortdesc: "Example of a MapQuest map.Shows how to create custom controls." +docs: > + Example of a MapQuest map. +tags: "mapquest" +--- +
+
+
+ +
+
\ No newline at end of file diff --git a/examples/mapquest.js b/examples_src/mapquest.js similarity index 100% rename from examples/mapquest.js rename to examples_src/mapquest.js diff --git a/examples_src/measure.css b/examples_src/measure.css new file mode 100644 index 0000000000..9d0a6a317f --- /dev/null +++ b/examples_src/measure.css @@ -0,0 +1,32 @@ +.tooltip { + position: relative; + background: rgba(0, 0, 0, 0.5); + border-radius: 4px; + color: white; + padding: 4px 8px; + opacity: 0.7; + white-space: nowrap; +} +.tooltip-measure { + opacity: 1; + font-weight: bold; +} +.tooltip-static { + background-color: #ffcc33; + color: black; + border: 1px solid white; +} +.tooltip-measure:before, +.tooltip-static:before { + border-top: 6px solid rgba(0, 0, 0, 0.5); + border-right: 6px solid transparent; + border-left: 6px solid transparent; + content: ""; + position: absolute; + bottom: -6px; + margin-left: -7px; + left: 50%; +} +.tooltip-static:before { + border-top-color: #ffcc33; +} \ No newline at end of file diff --git a/examples_src/measure.html b/examples_src/measure.html new file mode 100644 index 0000000000..d4e665967a --- /dev/null +++ b/examples_src/measure.html @@ -0,0 +1,21 @@ +--- +template: "example.html" +title: "Measure example" +shortdesc: "Example of using the ol.interaction.Draw interaction for creating simple measuring application." +docs: > +

NOTE: If use geodesic measures is not checked, measure is done in simple way on projected plane. Earth curvature is not taken into account

+tags: "draw, edit, measure, vector" +--- +
+
+
+
+
+
+ + + +
\ No newline at end of file diff --git a/examples/measure.js b/examples_src/measure.js similarity index 100% rename from examples/measure.js rename to examples_src/measure.js diff --git a/examples_src/min-max-resolution.html b/examples_src/min-max-resolution.html new file mode 100644 index 0000000000..42d8ea4c66 --- /dev/null +++ b/examples_src/min-max-resolution.html @@ -0,0 +1,15 @@ +--- +template: "example.html" +title: "Min/max resolution example" +shortdesc: "Show/hide layers depending on current view resolution." +docs: > +

Zoom in twice: the MapBox layer should hide whereas the OSM layer should be shown.

+

If you continue to zoom in, you'll see the OSM layer also disappear.

+

The rendering of the layers are here controlled using minResolution and maxResolution options.

+tags: "minResolution, maxResolution, resolution" +--- +
+
+
+
+
diff --git a/examples/min-max-resolution.js b/examples_src/min-max-resolution.js similarity index 100% rename from examples/min-max-resolution.js rename to examples_src/min-max-resolution.js diff --git a/examples/mobile-full-screen.html b/examples_src/mobile-full-screen.html similarity index 96% rename from examples/mobile-full-screen.html rename to examples_src/mobile-full-screen.html index 1afd9087f0..65c51ce89e 100644 --- a/examples/mobile-full-screen.html +++ b/examples_src/mobile-full-screen.html @@ -1,3 +1,6 @@ +--- +template: "example-verbatim.html" +--- diff --git a/examples/mobile-full-screen.js b/examples_src/mobile-full-screen.js similarity index 100% rename from examples/mobile-full-screen.js rename to examples_src/mobile-full-screen.js diff --git a/examples_src/modify-features.html b/examples_src/modify-features.html new file mode 100644 index 0000000000..b2f5687374 --- /dev/null +++ b/examples_src/modify-features.html @@ -0,0 +1,14 @@ +--- +template: "example.html" +title: "Modify features example" +shortdesc: "Editing features with the modify interaction." +docs: > +

This example demonstrates how the modify and select interactions can be used together. Zoom in to an area of interest and select a feature for editing. + Then drag points around to modify the feature. You can preserve topology by selecting multiple features before editing (Shift+click to select multiple features).

+tags: "modify, edit, vector" +--- +
+
+
+
+
diff --git a/examples/modify-features.js b/examples_src/modify-features.js similarity index 100% rename from examples/modify-features.js rename to examples_src/modify-features.js diff --git a/examples_src/modify-test.css b/examples_src/modify-test.css new file mode 100644 index 0000000000..f9028c9f45 --- /dev/null +++ b/examples_src/modify-test.css @@ -0,0 +1,3 @@ +.map { + background: grey; +} diff --git a/examples_src/modify-test.html b/examples_src/modify-test.html new file mode 100644 index 0000000000..db700fd411 --- /dev/null +++ b/examples_src/modify-test.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Modify features test" +shortdesc: "Example for testing feature modification." +docs: > + Example for testing feature modification. +tags: "modify, edit, vector" +--- +
+
+
+
+
diff --git a/examples/modify-test.js b/examples_src/modify-test.js similarity index 100% rename from examples/modify-test.js rename to examples_src/modify-test.js diff --git a/examples_src/mouse-position.html b/examples_src/mouse-position.html new file mode 100644 index 0000000000..ec3da34342 --- /dev/null +++ b/examples_src/mouse-position.html @@ -0,0 +1,25 @@ +--- +template: "example.html" +title: "Mouse position example" +shortdesc: "Example of a mouse position control, outside the map." +docs: > + Example of a mouse position control, outside the map. +tags: "mouse-position, openstreetmap" +--- +
+
+
+
+
+
+
+ + + + +
+
+
 
\ No newline at end of file diff --git a/examples/mouse-position.js b/examples_src/mouse-position.js similarity index 100% rename from examples/mouse-position.js rename to examples_src/mouse-position.js diff --git a/examples_src/moveend.html b/examples_src/moveend.html new file mode 100644 index 0000000000..0010925bf1 --- /dev/null +++ b/examples_src/moveend.html @@ -0,0 +1,17 @@ +--- +template: "example.html" +title: "Moveend Example" +shortdesc: "Use of the moveend event." +docs: > +

In this example, a listener is registered for the map's moveend event. Whenever this listener is called, it updates the inputs below with the map extent in decimal degrees.

+tags: "moveend, map, event" +--- +
+
+
+
+
+ + + + diff --git a/examples/moveend.js b/examples_src/moveend.js similarity index 100% rename from examples/moveend.js rename to examples_src/moveend.js diff --git a/examples_src/navigation-controls.html b/examples_src/navigation-controls.html new file mode 100644 index 0000000000..95bb614445 --- /dev/null +++ b/examples_src/navigation-controls.html @@ -0,0 +1,19 @@ +--- +template: "example.html" +title: "Navigation controls example" +shortdesc: "Shows how to add navigation controls." +docs: > +

This example shows how to use the beforeRender function on the Map to run one + or more animations.

+

The following navigation controls are added to the map:

+ +tags: "control, navigation, extent" +--- +
+
+
+
+
diff --git a/examples/navigation-controls.js b/examples_src/navigation-controls.js similarity index 100% rename from examples/navigation-controls.js rename to examples_src/navigation-controls.js diff --git a/examples_src/overlay.css b/examples_src/overlay.css new file mode 100644 index 0000000000..7b813f5ba9 --- /dev/null +++ b/examples_src/overlay.css @@ -0,0 +1,18 @@ +#marker { + width: 20px; + height: 20px; + border: 1px solid #088; + border-radius: 10px; + background-color: #0FF; + opacity: 0.5; +} +#vienna { + text-decoration: none; + color: white; + font-size: 11pt; + font-weight: bold; + text-shadow: black 0.1em 0.1em 0.2em; +} +.popover-content { + min-width: 180px; +} diff --git a/examples_src/overlay.html b/examples_src/overlay.html new file mode 100644 index 0000000000..4dfda85731 --- /dev/null +++ b/examples_src/overlay.html @@ -0,0 +1,21 @@ +--- +template: "example.html" +title: "Overlay example" +shortdesc: "Demonstrates overlays." +docs: > +

The popups are created using Popovers from Bootstrap.

+tags: "overlay, popup, bootstrap, popover, mapquest, openaerial" +resources: overlay.css +--- +
+
+
+
+
+
+ + Vienna +
+ + +
diff --git a/examples/overlay.js b/examples_src/overlay.js similarity index 100% rename from examples/overlay.js rename to examples_src/overlay.js diff --git a/examples_src/overviewmap-custom.css b/examples_src/overviewmap-custom.css new file mode 100644 index 0000000000..2a5d5bf07b --- /dev/null +++ b/examples_src/overviewmap-custom.css @@ -0,0 +1,32 @@ +.ol-custom-overviewmap, +.ol-custom-overviewmap.ol-uncollapsible { + bottom: auto; + left: auto; + right: 0; + top: 0; +} + +.ol-custom-overviewmap:not(.ol-collapsed) { + border: 1px solid black; +} + +.ol-custom-overviewmap .ol-overviewmap-map { + border: none; + width: 300px; +} + +.ol-custom-overviewmap .ol-overviewmap-box { + border: 2px solid red; +} + +.ol-custom-overviewmap:not(.ol-collapsed) button{ + bottom: auto; + left: auto; + right: 1px; + top: 1px; +} + +.ol-rotate { + top: 170px; + right: 0; +} diff --git a/examples_src/overviewmap-custom.html b/examples_src/overviewmap-custom.html new file mode 100644 index 0000000000..684697018f --- /dev/null +++ b/examples_src/overviewmap-custom.html @@ -0,0 +1,14 @@ +--- +template: "example.html" +title: "OverviewMap control example advanced" +shortdesc: "Example of OverviewMap control with advanced customization." +docs: > +

This example demonstrates how you can customize the overviewmap control using its supported options as well as defining custom CSS. You can also rotate the map using the shift key to see how the overview map reacts.

+tags: "overview, overviewmap" +resources: overviewmap-custom.css +--- +
+
+
+
+
diff --git a/examples/overviewmap-custom.js b/examples_src/overviewmap-custom.js similarity index 100% rename from examples/overviewmap-custom.js rename to examples_src/overviewmap-custom.js diff --git a/examples_src/overviewmap.html b/examples_src/overviewmap.html new file mode 100644 index 0000000000..7a2c2d9965 --- /dev/null +++ b/examples_src/overviewmap.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "OverviewMap control example" +shortdesc: "Example of OverviewMap control." +docs: > + This example demonstrates the use of the OverviewMap control. +tags: "overview, overviewmap" +--- +
+
+
+
+
diff --git a/examples/overviewmap.js b/examples_src/overviewmap.js similarity index 100% rename from examples/overviewmap.js rename to examples_src/overviewmap.js diff --git a/examples_src/polygon-styles.css b/examples_src/polygon-styles.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples_src/polygon-styles.html b/examples_src/polygon-styles.html new file mode 100644 index 0000000000..d425638295 --- /dev/null +++ b/examples_src/polygon-styles.html @@ -0,0 +1,16 @@ +--- +template: "example.html" +title: "Custom styles for polygons" +shortdesc: "Showing the vertices of a polygon with a custom style geometry." +docs: > + In this example two different styles are created for the polygons: + * The first style is for the polygons themselves. + * The second style is to draw the vertices of the polygons. +tags: "polygon, vector, style, GeometryFunction" +resources: polygon-styles.css +--- +
+
+
+
+
diff --git a/examples/polygon-styles.js b/examples_src/polygon-styles.js similarity index 100% rename from examples/polygon-styles.js rename to examples_src/polygon-styles.js diff --git a/examples_src/popup.css b/examples_src/popup.css new file mode 100644 index 0000000000..ddcde8dc4e --- /dev/null +++ b/examples_src/popup.css @@ -0,0 +1,41 @@ +.ol-popup { + position: absolute; + background-color: white; + -webkit-filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2)); + filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2)); + padding: 15px; + border-radius: 10px; + border: 1px solid #cccccc; + bottom: 12px; + left: -50px; +} +.ol-popup:after, .ol-popup:before { + top: 100%; + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; +} +.ol-popup:after { + border-top-color: white; + border-width: 10px; + left: 48px; + margin-left: -10px; +} +.ol-popup:before { + border-top-color: #cccccc; + border-width: 11px; + left: 48px; + margin-left: -11px; +} +.ol-popup-closer { + text-decoration: none; + position: absolute; + top: 2px; + right: 8px; +} +.ol-popup-closer:after { + content: "✖"; +} diff --git a/examples_src/popup.html b/examples_src/popup.html new file mode 100644 index 0000000000..31074d70d9 --- /dev/null +++ b/examples_src/popup.html @@ -0,0 +1,20 @@ +--- +template: "example.html" +title: "Popup example" +shortdesc: "Uses an overlay to create a popup." +docs: > +

+ Click on the map to get a popup. The popup is composed of a few basic elements: a container, a close button, and a place for the content. To anchor the popup to the map, an ol.Overlay is created with the popup container. A listener is registered for the map's click event to display the popup, and another listener is set as the click handler for the close button to hide the popup. +

+tags: "overlay, popup, mapquest, openaerial" +resources: popup.css +--- +
+
+
+ +
+
diff --git a/examples/popup.js b/examples_src/popup.js similarity index 100% rename from examples/popup.js rename to examples_src/popup.js diff --git a/examples_src/preload.html b/examples_src/preload.html new file mode 100644 index 0000000000..5f303faf6b --- /dev/null +++ b/examples_src/preload.html @@ -0,0 +1,17 @@ +--- +template: "example.html" +title: "Preload example" +shortdesc: "Example of tile preloading." +docs: > +

The map on the left preloads low resolution tiles. The map on the right does not use any preloading. Try zooming out and panning to see the difference.

+tags: "preload, bing" +--- +
+
+
+
+
+
+
+
+ diff --git a/examples/preload.js b/examples_src/preload.js similarity index 100% rename from examples/preload.js rename to examples_src/preload.js diff --git a/examples_src/readme.md b/examples_src/readme.md new file mode 100644 index 0000000000..dc3ab3f354 --- /dev/null +++ b/examples_src/readme.md @@ -0,0 +1,10 @@ +# Code examples + +The `.html` files in this folder are built by applying the templates in the `config/examples/` folder. Examples have [YAML front-matter](http://www.metalsmith.io) headers with the following properties: + +* template: The template from the `config/examples/` directory to use for this example +* title: The title of the example +* shortdesc: A short description for the example index +* docs: Documentation of the example. Can be markdown. +* tags: Tags for the example index +* resources: Additional js or css resources required by the example. This is a comma separated list of URLs. diff --git a/examples_src/regularshape.html b/examples_src/regularshape.html new file mode 100644 index 0000000000..3f764a91b1 --- /dev/null +++ b/examples_src/regularshape.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Regular Shape example" +shortdesc: "Example of some Regular Shape styles." +docs: > + +tags: "vector, symbol, regularshape, style, square, cross, star, triangle, x" +--- +
+
+
+
+
diff --git a/examples/regularshape.js b/examples_src/regularshape.js similarity index 100% rename from examples/regularshape.js rename to examples_src/regularshape.js diff --git a/examples_src/rotation.html b/examples_src/rotation.html new file mode 100644 index 0000000000..9b8f79c3f9 --- /dev/null +++ b/examples_src/rotation.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Rotation example" +shortdesc: "Example of a rotated map." +docs: > +

Use Alt+Shift+drag to rotate the map.

+tags: "rotation, openstreetmap" +--- +
+
+
+
+
diff --git a/examples/rotation.js b/examples_src/rotation.js similarity index 100% rename from examples/rotation.js rename to examples_src/rotation.js diff --git a/examples_src/scale-line.html b/examples_src/scale-line.html new file mode 100644 index 0000000000..049f00df67 --- /dev/null +++ b/examples_src/scale-line.html @@ -0,0 +1,20 @@ +--- +template: "example.html" +title: "Scale line example" +shortdesc: "Example of a scale line." +docs: > + +tags: "scale-line, openstreetmap" +--- +
+
+
+ +
+
diff --git a/examples/scale-line.js b/examples_src/scale-line.js similarity index 100% rename from examples/scale-line.js rename to examples_src/scale-line.js diff --git a/examples_src/select-features.html b/examples_src/select-features.html new file mode 100644 index 0000000000..7370a9a83c --- /dev/null +++ b/examples_src/select-features.html @@ -0,0 +1,25 @@ +--- +template: "example.html" +title: "Select features example" +shortdesc: "Example of using the Select interaction." +docs: > + Choose between Single-click, Click and Hover as the event type for selection in the combobox below. When using Single-click or Click you can hold do Shift key to toggle the feature in the selection.

+

Note: when Single-click is used double-clicks won't select features. This in contrast to Click, where a double-click will both select the feature and zoom the map (because of the DoubleClickZoom interaction). Note that Single-click is less responsive than Click because of the delay it uses to detect double-clicks.

+

In this example, a listener is registered for the Select interaction's select event in order to update the selection status below. +

+ + +  0 selected features +
+tags: "select, vector" +--- +
+
+
+
+
diff --git a/examples/select-features.js b/examples_src/select-features.js similarity index 100% rename from examples/select-features.js rename to examples_src/select-features.js diff --git a/examples_src/semi-transparent-layer.html b/examples_src/semi-transparent-layer.html new file mode 100644 index 0000000000..e4c173aa49 --- /dev/null +++ b/examples_src/semi-transparent-layer.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Semi-transparent layer example" +shortdesc: "Example of a map with a semi-transparent layer." +docs: > + This example will display a tiled MaxBox layer semi-transparently over a MapQuest background. +tags: "transparent, mapquest, tilejson" +--- +
+
+
+
+
diff --git a/examples/semi-transparent-layer.js b/examples_src/semi-transparent-layer.js similarity index 100% rename from examples/semi-transparent-layer.js rename to examples_src/semi-transparent-layer.js diff --git a/examples_src/side-by-side.html b/examples_src/side-by-side.html new file mode 100644 index 0000000000..4649b85808 --- /dev/null +++ b/examples_src/side-by-side.html @@ -0,0 +1,25 @@ +--- +template: "example.html" +title: "Side-by-side example" +shortdesc: "The three maps, one WebGL, one Canvas, one DOM, share the same center, resolution, rotation and layers." +docs: > + The three maps, one WebGL, one Canvas, one DOM, share the same center, resolution, rotation and layers. +tags: "side-by-side, canvas, webgl, dom, canvas, sync, object" +--- +
+
+

Canvas

+
+
+
+

WebGL

+
+ +
+
+

DOM

+
+
+
diff --git a/examples/side-by-side.js b/examples_src/side-by-side.js similarity index 100% rename from examples/side-by-side.js rename to examples_src/side-by-side.js diff --git a/examples_src/simple.html b/examples_src/simple.html new file mode 100644 index 0000000000..b9abd1fd95 --- /dev/null +++ b/examples_src/simple.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Simple example" +shortdesc: "Example of a simple map." +docs: > + A simple map with customized Attribution control. +tags: "simple, openstreetmap, attribution" +--- +
+
+
+
+
diff --git a/examples/simple.js b/examples_src/simple.js similarity index 100% rename from examples/simple.js rename to examples_src/simple.js diff --git a/examples_src/snap.html b/examples_src/snap.html new file mode 100644 index 0000000000..69a2eb211c --- /dev/null +++ b/examples_src/snap.html @@ -0,0 +1,38 @@ +--- +template: "example.html" +title: "Snap interaction example" +shortdesc: "Example of using the snap interaction together with draw and modify interactions." +docs: > + Example of using the snap interaction together with + draw and modify interactions. The snap interaction must be added + last, as it needs to be the first to handle the + pointermove event.

+
+
+ +
+
+ +
+
+ + +
+
+tags: "draw, edit, modify, vector, featureoverlay, snap" +--- +
+
+
+
+
diff --git a/examples/snap.js b/examples_src/snap.js similarity index 100% rename from examples/snap.js rename to examples_src/snap.js diff --git a/examples_src/sphere-mollweide.html b/examples_src/sphere-mollweide.html new file mode 100644 index 0000000000..e10e22637a --- /dev/null +++ b/examples_src/sphere-mollweide.html @@ -0,0 +1,14 @@ +--- +template: "example.html" +title: "Sphere Mollweide example" +shortdesc: "Example of a Sphere Mollweide map with a Graticule component." +docs: > + Example of a Sphere Mollweide map with a Graticule component. +tags: "graticule, Mollweide, projection, proj4js" +resources: http://cdnjs.cloudflare.com/ajax/libs/proj4js/2.2.1/proj4.js +--- +
+
+
+
+
diff --git a/examples/sphere-mollweide.js b/examples_src/sphere-mollweide.js similarity index 100% rename from examples/sphere-mollweide.js rename to examples_src/sphere-mollweide.js diff --git a/examples_src/stamen.html b/examples_src/stamen.html new file mode 100644 index 0000000000..df1deac087 --- /dev/null +++ b/examples_src/stamen.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Stamen example" +shortdesc: "Example of a Stamen tile source." +docs: > + Two layers are composed: the watercolor base layer with the terrain labels. +tags: "stamen, watercolor, terrain-labels, two-layers" +--- +
+
+
+
+
diff --git a/examples/stamen.js b/examples_src/stamen.js similarity index 100% rename from examples/stamen.js rename to examples_src/stamen.js diff --git a/examples_src/static-image.html b/examples_src/static-image.html new file mode 100644 index 0000000000..4224fa096e --- /dev/null +++ b/examples_src/static-image.html @@ -0,0 +1,18 @@ +--- +template: "example.html" +title: "Static image example" +shortdesc: "Example of a static image layer." +docs: > +

+ This example uses a static image + as a layer source. The map view is configured with a custom + projection that translates image coordinates directly into map + coordinates. +

+tags: "static image, xkcd" +--- +
+
+
+
+
diff --git a/examples/static-image.js b/examples_src/static-image.js similarity index 100% rename from examples/static-image.js rename to examples_src/static-image.js diff --git a/examples_src/symbol-atlas-webgl.html b/examples_src/symbol-atlas-webgl.html new file mode 100644 index 0000000000..d8d3bde07b --- /dev/null +++ b/examples_src/symbol-atlas-webgl.html @@ -0,0 +1,18 @@ +--- +template: "example.html" +title: "Symbols with WebGL example" +shortdesc: "Using symbols in an atlas with WebGL." +docs: > +

When using symbol styles with WebGL, OpenLayers would render the symbol + on a temporary image and would create a WebGL texture for each image. For a + better performance, it is recommended to use atlas images (similar to + image sprites with CSS), so that the number of textures is reduced. OpenLayers + provides an AtlasManager, which when passed to the constructor + of a symbol style, will create atlases for the symbols.

+tags: "webgl, symbol, atlas, vector, point" +--- +
+
+
+
+
diff --git a/examples/symbol-atlas-webgl.js b/examples_src/symbol-atlas-webgl.js similarity index 100% rename from examples/symbol-atlas-webgl.js rename to examples_src/symbol-atlas-webgl.js diff --git a/examples_src/synthetic-lines.html b/examples_src/synthetic-lines.html new file mode 100644 index 0000000000..e1ef27fa30 --- /dev/null +++ b/examples_src/synthetic-lines.html @@ -0,0 +1,69 @@ +--- +template: "example.html" +title: "Synthetic lines example" +shortdesc: "Synthetic lines example." +docs: > +

Performance results:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Device/Browser200 lines500 lines1000 lines2000 lines5000 lines10000 lines20000 lines
Mac Book Air / Chrome 33 canary60 fps60 fps60 fps60 fps60 fps60 fps60 fps
Mac Book Air / FireFox 2560 fps60 fps60 fps60 fps60 fps22 fps6 fps
Mac Book Air / Safari 760 fps60 fps60 fps40 fps10 fpsN/AN/A
iPhone 4S / iOS 7 / Safari60 fps33 fps15 fps5 fpsN/AN/AN/A
+tags: "vector" +--- +
+
+
+
+
diff --git a/examples/synthetic-lines.js b/examples_src/synthetic-lines.js similarity index 100% rename from examples/synthetic-lines.js rename to examples_src/synthetic-lines.js diff --git a/examples_src/synthetic-points.html b/examples_src/synthetic-points.html new file mode 100644 index 0000000000..a9a59b513f --- /dev/null +++ b/examples_src/synthetic-points.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Synthetic points example" +shortdesc: "Synthetic points example." +docs: > + +tags: "vector" +--- +
+
+
+
+
diff --git a/examples/synthetic-points.js b/examples_src/synthetic-points.js similarity index 100% rename from examples/synthetic-points.js rename to examples_src/synthetic-points.js diff --git a/examples_src/teleport.html b/examples_src/teleport.html new file mode 100644 index 0000000000..aa43a0bd14 --- /dev/null +++ b/examples_src/teleport.html @@ -0,0 +1,21 @@ +--- +template: "example.html" +title: "Teleport example" +shortdesc: "Example of moving a map from one target to another." +docs: > +

Click on the Teleport button below the map to move the map from one target to another.

+tags: "teleport, openstreetmap" +--- +
+
+
+
+
+
+
+
+
+
+ Teleport +
+
diff --git a/examples/teleport.js b/examples_src/teleport.js similarity index 100% rename from examples/teleport.js rename to examples_src/teleport.js diff --git a/examples_src/tile-load-events.css b/examples_src/tile-load-events.css new file mode 100644 index 0000000000..0bd164d656 --- /dev/null +++ b/examples_src/tile-load-events.css @@ -0,0 +1,15 @@ +.map { + background: #E0ECED; +} +.wrapper { + position: relative; +} +#progress { + position: absolute; + bottom: 0; + left: 0; + height: 2px; + background: rgba(0, 60, 136, 0.4); + width: 0; + transition: width 250ms; +} \ No newline at end of file diff --git a/examples_src/tile-load-events.html b/examples_src/tile-load-events.html new file mode 100644 index 0000000000..75d512d4dd --- /dev/null +++ b/examples_src/tile-load-events.html @@ -0,0 +1,19 @@ +--- +template: "example.html" +title: "Tile load events example" +shortdesc: "Example using tile load events." +docs: > + Image tile sources fire events related to tile loading. You can + listen for tileloadstart, tileloadend, + and tileloaderror type events to monitor tile loading + progress. This example registers listeners for these events and + renders a tile loading progress bar at the bottom of the map.

+ This example creates a "rotate to north" button. +tags: "tile, events, loading" +--- +
+
+
+
+
+
\ No newline at end of file diff --git a/examples/tile-load-events.js b/examples_src/tile-load-events.js similarity index 100% rename from examples/tile-load-events.js rename to examples_src/tile-load-events.js diff --git a/examples_src/tile-vector.css b/examples_src/tile-vector.css new file mode 100644 index 0000000000..e038ad375e --- /dev/null +++ b/examples_src/tile-vector.css @@ -0,0 +1,4 @@ + #map { + max-width: 600px; + margin: 0 auto; + } \ No newline at end of file diff --git a/examples_src/tile-vector.html b/examples_src/tile-vector.html new file mode 100644 index 0000000000..cdee5d09d4 --- /dev/null +++ b/examples_src/tile-vector.html @@ -0,0 +1,23 @@ +--- +template: "example.html" +title: "Tile vector example" +shortdesc: "Example of vector tiles from openstreetmap.us." +docs: > + Example of vector tiles from openstreetmap.us. +tags: "custom, control" +--- +
+
+
+
+
+
+ Warning Map is becoming unresponsive with too many layers. +
+
+ Layers + + + + +
\ No newline at end of file diff --git a/examples/tile-vector.js b/examples_src/tile-vector.js similarity index 100% rename from examples/tile-vector.js rename to examples_src/tile-vector.js diff --git a/examples_src/tilejson.html b/examples_src/tilejson.html new file mode 100644 index 0000000000..e11a22f833 --- /dev/null +++ b/examples_src/tilejson.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "TileJSON example" +shortdesc: "Example of a TileJSON layer." +docs: > + Example of a TileJSON layer. +tags: "tilejson" +--- +
+
+
+
+
diff --git a/examples/tilejson.js b/examples_src/tilejson.js similarity index 100% rename from examples/tilejson.js rename to examples_src/tilejson.js diff --git a/examples_src/tileutfgrid.css b/examples_src/tileutfgrid.css new file mode 100644 index 0000000000..b45853acf6 --- /dev/null +++ b/examples_src/tileutfgrid.css @@ -0,0 +1,6 @@ +#country-name { + color: black; + font-size: 12pt; + font-weight: bold; + text-shadow: white 0.1em 0.1em 0.2em; +} diff --git a/examples_src/tileutfgrid.html b/examples_src/tileutfgrid.html new file mode 100644 index 0000000000..668fd27c33 --- /dev/null +++ b/examples_src/tileutfgrid.html @@ -0,0 +1,22 @@ +--- +template: "example.html" +title: "TileUTFGrid example" +shortdesc: "This example shows how to read data from a TileUTFGrid layer." +docs: > +

Point to a country to see its name and flag.

+ Tiles made with [TileMill](http://tilemill.com). Hosting on MapBox.com or with open-source [TileServer](https://github.com/klokantech/tileserver-php/). +tags: "utfgrid, tileutfgrid, tilejson" +--- +
+
+
+
+
+ +
+ +
+
 
+ +
+
diff --git a/examples/tileutfgrid.js b/examples_src/tileutfgrid.js similarity index 100% rename from examples/tileutfgrid.js rename to examples_src/tileutfgrid.js diff --git a/examples_src/tissot.html b/examples_src/tissot.html new file mode 100644 index 0000000000..4bab02205e --- /dev/null +++ b/examples_src/tissot.html @@ -0,0 +1,18 @@ +--- +template: "example.html" +title: "Tissot indicatrix example" +shortdesc: "Draw Tissot's indicatrices on maps." +docs: > + Example of [Tissot indicatrix](http://en.wikipedia.org/wiki/Tissot's_indicatrix) maps. The map on the left is an EPSG:4326 map. The one on the right is EPSG:3857. +tags: "tissot, circle" +--- +
+
+

EPSG:4326

+
+
+
+

EPSG:3857

+
+
+
diff --git a/examples/tissot.js b/examples_src/tissot.js similarity index 100% rename from examples/tissot.js rename to examples_src/tissot.js diff --git a/examples_src/topojson.html b/examples_src/topojson.html new file mode 100644 index 0000000000..86be09dcab --- /dev/null +++ b/examples_src/topojson.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "TopoJSON example" +shortdesc: "Demonstrates rendering of features from a TopoJSON topology." +docs: > + This example uses a vector layer with a `ol.source.TopoJSON` for rendering features from [TopoJSON](https://github.com/mbostock/topojson/wiki). +tags: "topojson, vector, style" +--- +
+
+
+
+
diff --git a/examples/topojson.js b/examples_src/topojson.js similarity index 100% rename from examples/topojson.js rename to examples_src/topojson.js diff --git a/examples_src/vector-labels.css b/examples_src/vector-labels.css new file mode 100644 index 0000000000..8009acb0f2 --- /dev/null +++ b/examples_src/vector-labels.css @@ -0,0 +1,37 @@ +h2 { + font-size: 1.5em; + line-height: 15px; +} + +.scale-cnt { + margin: 5px; +} + +.edit-form-ctn { +} + +.edit-form { + float: left; + margin: 5px; + width: 230px; + padding: 4px; + border: 1px solid black; +} + +.edit-form input[type="button"] { + float: right; +} + +.edit-form-elem label { + display: block; + float: left; + width: 85px; +} + +.edit-form-elem input[type="text"] { + width: 60px; +} + +.edit-form-elem select { + width: 130px; +} diff --git a/examples_src/vector-labels.html b/examples_src/vector-labels.html new file mode 100644 index 0000000000..1dfaadbbf1 --- /dev/null +++ b/examples_src/vector-labels.html @@ -0,0 +1,280 @@ +--- +template: "example.html" +title: "Vector labels example" +shortdesc: "Example of GeoJSON features with labels." +docs: > + **Note:** The 'Text/Wrap' option is currently not working properly. This is because ol3 uses Canvas's strokeText and fillText functions that do not support text wrapping. +tags: "geojson, vector, openstreetmap, label" +--- +
+
+
+
+
+ +
+ +

Points

+
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+
+ +
+ +

Lines

+
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+
+ +
+ +

Polygons

+
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+
diff --git a/examples/vector-labels.js b/examples_src/vector-labels.js similarity index 100% rename from examples/vector-labels.js rename to examples_src/vector-labels.js diff --git a/examples_src/vector-layer.html b/examples_src/vector-layer.html new file mode 100644 index 0000000000..d98c05e545 --- /dev/null +++ b/examples_src/vector-layer.html @@ -0,0 +1,22 @@ +--- +template: "example.html" +title: "Vector layer example" +shortdesc: "Example of a countries vector layer with country information." +docs: > + The countries are loaded from a GeoJSON file. Information about countries is shown on hover and click. Zoom in a few times to see country name labels. +tags: "vector, osm, xml, loading, server" +--- +
+
+
+
+
+ +
+
+
+
+   +
+
+
diff --git a/examples/vector-layer.js b/examples_src/vector-layer.js similarity index 100% rename from examples/vector-layer.js rename to examples_src/vector-layer.js diff --git a/examples_src/vector-osm.html b/examples_src/vector-osm.html new file mode 100644 index 0000000000..5bc7310a05 --- /dev/null +++ b/examples_src/vector-osm.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "OSM XML example" +shortdesc: "Example of using the OSM XML source." +docs: > + OSM XML vector data is loaded dynamically from a server using a tiling strategy. +tags: "vector, osm, xml, loading, server" +--- +
+
+
+
+
diff --git a/examples/vector-osm.js b/examples_src/vector-osm.js similarity index 100% rename from examples/vector-osm.js rename to examples_src/vector-osm.js diff --git a/examples_src/vector-wfs.html b/examples_src/vector-wfs.html new file mode 100644 index 0000000000..df0d5b43f8 --- /dev/null +++ b/examples_src/vector-wfs.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "WFS example" +shortdesc: "Example of using WFS with a BBOX strategy." +docs: > + This example loads new features from GeoServer WFS when the view extent changes. +tags: "vector, WFS, bbox, loading, server" +--- +
+
+
+
+
diff --git a/examples/vector-wfs.js b/examples_src/vector-wfs.js similarity index 100% rename from examples/vector-wfs.js rename to examples_src/vector-wfs.js diff --git a/examples_src/wkt.html b/examples_src/wkt.html new file mode 100644 index 0000000000..11bfc16f69 --- /dev/null +++ b/examples_src/wkt.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "WKT example" +shortdesc: "Example of using the WKT parser." +docs: > + Create features from geometries in WKT (Well Known Text) format. +tags: "wkt, well known text" +--- +
+
+
+
+
diff --git a/examples/wkt.js b/examples_src/wkt.js similarity index 100% rename from examples/wkt.js rename to examples_src/wkt.js diff --git a/examples_src/wms-capabilities.css b/examples_src/wms-capabilities.css new file mode 100644 index 0000000000..78cbe01578 --- /dev/null +++ b/examples_src/wms-capabilities.css @@ -0,0 +1,4 @@ +.log-container { + height: 400px; + overflow: scroll; +} diff --git a/examples_src/wms-capabilities.html b/examples_src/wms-capabilities.html new file mode 100644 index 0000000000..6bc4772fba --- /dev/null +++ b/examples_src/wms-capabilities.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "WMS GetCapabilities parsing example" +shortdesc: "Example of parsing a WMS GetCapabilities response." +docs: > + This example shows the contents of the result object from parsing a WMS capabilities response. +tags: "wms, capabilities, getcapabilities" +--- +
+
+
+
+
diff --git a/examples/wms-capabilities.js b/examples_src/wms-capabilities.js similarity index 100% rename from examples/wms-capabilities.js rename to examples_src/wms-capabilities.js diff --git a/examples_src/wms-custom-proj.html b/examples_src/wms-custom-proj.html new file mode 100644 index 0000000000..72b00eebfb --- /dev/null +++ b/examples_src/wms-custom-proj.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Tiled WMS with custom projection example" +shortdesc: "Example of using custom coordinate transform functions." +docs: > + With `ol.proj.addCoordinateTransforms()`, custom coordinate transform functions can be added to configured projections. +tags: "wms, tile, tilelayer, projection" +--- +
+
+
+
+
diff --git a/examples/wms-custom-proj.js b/examples_src/wms-custom-proj.js similarity index 100% rename from examples/wms-custom-proj.js rename to examples_src/wms-custom-proj.js diff --git a/examples_src/wms-image-custom-proj.html b/examples_src/wms-image-custom-proj.html new file mode 100644 index 0000000000..d7858ba8ab --- /dev/null +++ b/examples_src/wms-image-custom-proj.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Single image WMS with Proj4js projection example" +shortdesc: "Example of integrating Proj4js for coordinate transforms." +docs: > + With transparent [Proj4js](http://proj4js.org/) integration, OpenLayers can transform coordinates between arbitrary projections. +tags: "wms, single image, proj4js, projection" +--- +
+
+
+
+
diff --git a/examples/wms-image-custom-proj.js b/examples_src/wms-image-custom-proj.js similarity index 100% rename from examples/wms-image-custom-proj.js rename to examples_src/wms-image-custom-proj.js diff --git a/examples_src/wms-image.html b/examples_src/wms-image.html new file mode 100644 index 0000000000..0ae047a1bd --- /dev/null +++ b/examples_src/wms-image.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Single image WMS example" +shortdesc: "Example of a single image WMS layer." +docs: > + WMS can be used as an Image layer, as shown here, or as a Tile layer, as shown in the [Tiled WMS example](wms-tiled.html) example. Tiles can be cached, so the browser will not re-fetch data for areas that were viewed already. But there may be problems with repeated labels for WMS servers that are not aware of tiles, in which case single image WMS will produce better cartography. +tags: "wms, image" +--- +
+
+
+
+
diff --git a/examples/wms-image.js b/examples_src/wms-image.js similarity index 100% rename from examples/wms-image.js rename to examples_src/wms-image.js diff --git a/examples_src/wms-no-proj.html b/examples_src/wms-no-proj.html new file mode 100644 index 0000000000..9f9844df44 --- /dev/null +++ b/examples_src/wms-no-proj.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "WMS without client projection example" +shortdesc: "Example of two WMS layers using the projection EPSG:21781, which is unknown to the client." +docs: > + As long as no coordinate transformations are required, OpenLayers 3 works fine with projections that are only configured with a `code` and `units`. +tags: "wms, projection" +--- +
+
+
+
+
diff --git a/examples/wms-no-proj.js b/examples_src/wms-no-proj.js similarity index 100% rename from examples/wms-no-proj.js rename to examples_src/wms-no-proj.js diff --git a/examples_src/wms-tiled-wrap-180.html b/examples_src/wms-tiled-wrap-180.html new file mode 100644 index 0000000000..cd24112994 --- /dev/null +++ b/examples_src/wms-tiled-wrap-180.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Tiled WMS wrap 180° meridian example" +shortdesc: "Example of a tiled WMS layer that wraps across the 180° meridian." +docs: > + The `wrapX` option is set to `true` here so tiles will be wrapped around the x-axis. +tags: "wms, tile, dateline, wrap, 180" +--- +
+
+
+
+
diff --git a/examples/wms-tiled-wrap-180.js b/examples_src/wms-tiled-wrap-180.js similarity index 100% rename from examples/wms-tiled-wrap-180.js rename to examples_src/wms-tiled-wrap-180.js diff --git a/examples_src/wms-tiled.html b/examples_src/wms-tiled.html new file mode 100644 index 0000000000..7b48807d52 --- /dev/null +++ b/examples_src/wms-tiled.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Tiled WMS example" +shortdesc: "Example of a tiled WMS layer." +docs: > + WMS can be used as a Tile layer, as shown here, or as an Image layer, as shown in the [Single Image WMS example](wms-image.html) example. Tiles can be cached, so the browser will not re-fetch data for areas that were viewed already. But there may be problems with repeated labels for WMS servers that are not aware of tiles, in which case single image WMS will produce better cartography. +tags: "wms, tile, tilelayer" +--- +
+
+
+
+
diff --git a/examples/wms-tiled.js b/examples_src/wms-tiled.js similarity index 100% rename from examples/wms-tiled.js rename to examples_src/wms-tiled.js diff --git a/examples_src/wmts-capabilities.css b/examples_src/wmts-capabilities.css new file mode 100644 index 0000000000..78cbe01578 --- /dev/null +++ b/examples_src/wmts-capabilities.css @@ -0,0 +1,4 @@ +.log-container { + height: 400px; + overflow: scroll; +} diff --git a/examples_src/wmts-capabilities.html b/examples_src/wmts-capabilities.html new file mode 100644 index 0000000000..dd13f220f5 --- /dev/null +++ b/examples_src/wmts-capabilities.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "WMTS GetCapabilities parsing example" +shortdesc: "Example of parsing a WMTS GetCapabilities response." +docs: > + This example shows the contents of the result object from parsing a WMTS capabilities response. +tags: "wmts, capabilities, getcapabilities" +--- +
+
+
+
+
diff --git a/examples/wmts-capabilities.js b/examples_src/wmts-capabilities.js similarity index 100% rename from examples/wmts-capabilities.js rename to examples_src/wmts-capabilities.js diff --git a/examples_src/wmts-hidpi.css b/examples_src/wmts-hidpi.css new file mode 100644 index 0000000000..825625b824 --- /dev/null +++ b/examples_src/wmts-hidpi.css @@ -0,0 +1,3 @@ +.map { + background: white; +} diff --git a/examples_src/wmts-hidpi.html b/examples_src/wmts-hidpi.html new file mode 100644 index 0000000000..9677d896c5 --- /dev/null +++ b/examples_src/wmts-hidpi.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "WMTS HiDPI example" +shortdesc: "Example of a WMTS based HiDPI layer." +docs: > + The WMTS source has a `tilePixelRatio` option. A HiDPI capable WMTS could provide tiles with 512x512 pixel tiles, but use them in a 256x256 pixel tile grid. In this case `tilePixelRatio` needs to be set to `2`. +tags: "hidpi, retina, wmts" +--- +
+
+
+
+
diff --git a/examples/wmts-hidpi.js b/examples_src/wmts-hidpi.js similarity index 100% rename from examples/wmts-hidpi.js rename to examples_src/wmts-hidpi.js diff --git a/examples_src/wmts-layer-from-capabilities.html b/examples_src/wmts-layer-from-capabilities.html new file mode 100644 index 0000000000..f1a57fd9ac --- /dev/null +++ b/examples_src/wmts-layer-from-capabilities.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "WMTS Layer from capabilities example" +shortdesc: "Example of a WMTS source created from a WMTS capabilities document." +docs: > + This example shows how to create the configuration for accessing a WMTS from a GetCapabilities response.. The [WMTS example](wmts.html) shows how to create the configuration manually. +tags: "wmts, capabilities, getcapabilities" +--- +
+
+
+
+
diff --git a/examples/wmts-layer-from-capabilities.js b/examples_src/wmts-layer-from-capabilities.js similarity index 100% rename from examples/wmts-layer-from-capabilities.js rename to examples_src/wmts-layer-from-capabilities.js diff --git a/examples_src/wmts.html b/examples_src/wmts.html new file mode 100644 index 0000000000..71fb109621 --- /dev/null +++ b/examples_src/wmts.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "WMTS example" +shortdesc: "Example of a WMTS source." +docs: > + This example shows how to manually create the configuration for accessing a WMTS. The [WMTS Layer from capabilities example](wmts-layer-from-capabilities.html) shows how to create the configuration from a GetCapabilities response. +tags: "wmts" +--- +
+
+
+
+
diff --git a/examples/wmts.js b/examples_src/wmts.js similarity index 100% rename from examples/wmts.js rename to examples_src/wmts.js diff --git a/examples_src/xyz-esri-4326-512.html b/examples_src/xyz-esri-4326-512.html new file mode 100644 index 0000000000..cea1e526cf --- /dev/null +++ b/examples_src/xyz-esri-4326-512.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "XYZ Esri EPSG:4326 tileSize 512 example" +shortdesc: "Example of a XYZ source in EPSG:4326 using Esri 512x512 tiles." +docs: > + ArcGIS REST tile services with custom tile sizes (here: 512x512 pixels) and projection (here: EPSG:4326) are supported by `ol.source.XYZ`. A custom tile grid and tile url function are required. +tags: "xyz, esri, tilesize, custom projection" +--- +
+
+
+
+
diff --git a/examples/xyz-esri-4326-512.js b/examples_src/xyz-esri-4326-512.js similarity index 100% rename from examples/xyz-esri-4326-512.js rename to examples_src/xyz-esri-4326-512.js diff --git a/examples_src/xyz-esri.html b/examples_src/xyz-esri.html new file mode 100644 index 0000000000..e290eeaba2 --- /dev/null +++ b/examples_src/xyz-esri.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "XYZ Esri example" +shortdesc: "Example of a XYZ source using Esri tiles." +docs: > + ArcGIS REST tile services are supported by `ol.source.XYZ`. +tags: "xyz, esri, arcgis rest" +--- +
+
+
+
+
diff --git a/examples/xyz-esri.js b/examples_src/xyz-esri.js similarity index 100% rename from examples/xyz-esri.js rename to examples_src/xyz-esri.js diff --git a/examples_src/xyz-retina.html b/examples_src/xyz-retina.html new file mode 100644 index 0000000000..0743c5a733 --- /dev/null +++ b/examples_src/xyz-retina.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "XYZ Retina tiles example" +shortdesc: "Example of Retina / HiDPI mercator tiles (512x512px) available as XYZ." +docs: > + The ol.source.XYZ must contain `tilePixelRatio` parameter. The tiles were prepared from a GeoTIFF file with [MapTiler](http://www.maptiler.com/). +tags: "retina, hidpi, xyz, maptiler, @2x, devicePixelRatio" +--- +
+
+
+
+
diff --git a/examples/xyz-retina.js b/examples_src/xyz-retina.js similarity index 100% rename from examples/xyz-retina.js rename to examples_src/xyz-retina.js diff --git a/examples_src/xyz.html b/examples_src/xyz.html new file mode 100644 index 0000000000..3c0a0b2a8c --- /dev/null +++ b/examples_src/xyz.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "XYZ Example" +shortdesc: "Example of a XYZ source." +docs: > + The XYZ source is used for tile data that is accessed through URLs that include a zoom level and tile grid x/y coordinates. +tags: "xyz" +--- +
+
+
+
+
diff --git a/examples/xyz.js b/examples_src/xyz.js similarity index 100% rename from examples/xyz.js rename to examples_src/xyz.js diff --git a/examples_src/zoom-constrained.html b/examples_src/zoom-constrained.html new file mode 100644 index 0000000000..4978953530 --- /dev/null +++ b/examples_src/zoom-constrained.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Zoom Constrained Example" +shortdesc: "Example of a zoom constrained view." +docs: > + This map has a view that is constrained between zoom levels 9 and 13. This is done using the `minZoom` and `maxZoom` view options. +tags: "bing, zoom, minZoom, maxZoom" +--- +
+
+
+
+
diff --git a/examples/zoom-constrained.js b/examples_src/zoom-constrained.js similarity index 100% rename from examples/zoom-constrained.js rename to examples_src/zoom-constrained.js diff --git a/examples_src/zoomify.html b/examples_src/zoomify.html new file mode 100644 index 0000000000..b8b77fad86 --- /dev/null +++ b/examples_src/zoomify.html @@ -0,0 +1,13 @@ +--- +template: "example.html" +title: "Zoomify example" +shortdesc: "Example of a Zoomify source." +docs: > + Zoomify is a format for deep-zooming into high resolution images. This example shows how to use the Zoomify source with a pixel projection. +tags: "zoomify, deep zoom, pixel, projection" +--- +
+
+
+
+
diff --git a/examples/zoomify.js b/examples_src/zoomify.js similarity index 100% rename from examples/zoomify.js rename to examples_src/zoomify.js diff --git a/examples_src/zoomslider.css b/examples_src/zoomslider.css new file mode 100644 index 0000000000..91eaa3c2b5 --- /dev/null +++ b/examples_src/zoomslider.css @@ -0,0 +1,60 @@ +/** + * The zoomslider in the second map shall be placed between the zoom-in and + * zoom-out buttons. + */ +#map2 .ol-zoom .ol-zoom-out { + margin-top: 204px; +} +#map2 .ol-zoomslider { + background-color: transparent; + top: 2.3em; +} + +#map2 .ol-touch .ol-zoom .ol-zoom-out { + margin-top: 212px; +} +#map2 .ol-touch .ol-zoomslider { + top: 2.75em; +} + +#map2 .ol-zoom-in.ol-has-tooltip:hover [role=tooltip], +#map2 .ol-zoom-in.ol-has-tooltip:focus [role=tooltip] { + top: 3px; +} + +#map2 .ol-zoom-out.ol-has-tooltip:hover [role=tooltip], +#map2 .ol-zoom-out.ol-has-tooltip:focus [role=tooltip] { + top: 232px; +} + +/** + * The zoomslider in the third map shall be horizontal, placed in the top-right + * corner, smaller and orange. + */ +#map3 .ol-zoomslider { + top: 8px; + left: auto; + right: 8px; + background-color: rgba(255,69,0,0.2); + width: 200px; + height: 15px; + padding: 0; + box-shadow: 0 0 5px rgb(255,69,0); + border-radius: 20px; +} + +#map3 .ol-zoomslider:hover { + background-color: rgba(255,69,0,0.3); +} + +#map3 .ol-zoomslider-thumb { + height: 15px; + width: 15px; + margin: 0; + filter: none; + background-color: rgba(255,69,0,0.6); + border-radius: 20px; +} +#map3 a.ol-zoomslider-handle:hover { + background-color: rgba(255,69,0,0.7); +} diff --git a/examples_src/zoomslider.html b/examples_src/zoomslider.html new file mode 100644 index 0000000000..24b0c4f0a7 --- /dev/null +++ b/examples_src/zoomslider.html @@ -0,0 +1,22 @@ +--- +template: "example.html" +title: "Zoom slider example" +shortdesc: "Example of various ZoomSlider controls." +docs: > + This example shows how to add a zoom slider to a map and how to customize it. +tags: "zoom, zoomslider, slider, style, styling, css, control" +--- +
+
+

Default style

+
+
+
+

Placed between zoom controls

+
+
+
+

Horizontal and completely re-styled

+
+
+
diff --git a/examples/zoomslider.js b/examples_src/zoomslider.js similarity index 100% rename from examples/zoomslider.js rename to examples_src/zoomslider.js diff --git a/package.json b/package.json index 961eba0072..b3ad9bb5b2 100644 --- a/package.json +++ b/package.json @@ -30,8 +30,12 @@ "fs-extra": "0.12.0", "glob": "5.0.3", "graceful-fs": "3.0.2", + "handlebars": "3.0.1", "htmlparser2": "3.7.3", "jsdoc": "3.3.0-alpha9", + "marked": "0.3.3", + "metalsmith": "1.5.0", + "metalsmith-templates": "0.7.0", "nomnom": "1.8.0", "rbush": "1.3.5", "temp": "0.8.1", diff --git a/resources/example-behaviour.js b/resources/example-behaviour.js index 161f51d790..6fefba2de7 100644 --- a/resources/example-behaviour.js +++ b/resources/example-behaviour.js @@ -1,4 +1,15 @@ ;(function() { + var copyButton = document.getElementById('copy-button'); + if (copyButton) { + var data = document.getElementById('example-source').textContent; + new ZeroClipboard(copyButton).on('copy', function(event) { + event.clipboardData.setData({ + 'text/plain': data, + 'text/html': data + }); + }); + } + if (window.location.host === 'localhost:3000') { return; } diff --git a/resources/layout.css b/resources/layout.css index f4d25d5391..c05e5c19a7 100644 --- a/resources/layout.css +++ b/resources/layout.css @@ -15,7 +15,7 @@ body { font-family: 'Lucida Grande',Verdana,Geneva,Lucida,Arial,Helvetica,sans-serif; } -#tags { +#tags, #shortdesc, .hidden { display: none; } diff --git a/resources/prism/prism.css b/resources/prism/prism.css new file mode 100644 index 0000000000..e643c21e06 --- /dev/null +++ b/resources/prism/prism.css @@ -0,0 +1,137 @@ +/* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ + +code[class*="language-"], +pre[class*="language-"] { + color: black; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + direction: ltr; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, +code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*="language-"]::selection, pre[class*="language-"] ::selection, +code[class*="language-"]::selection, code[class*="language-"] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + code[class*="language-"], + pre[class*="language-"] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; +} + +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: .1em; + border-radius: .3em; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.namespace { + opacity: .7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #a67f59; + background: hsla(0, 0%, 100%, .5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function { + color: #DD4A68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + diff --git a/resources/prism/prism.min.js b/resources/prism/prism.min.js new file mode 100644 index 0000000000..21ea6df0f1 --- /dev/null +++ b/resources/prism/prism.min.js @@ -0,0 +1,6 @@ +/* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript */ +self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{};var Prism=function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={util:{encode:function(e){return e instanceof n?new n(e.type,t.util.encode(e.content),e.alias):"Array"===t.util.type(e)?e.map(t.util.encode):e.replace(/&/g,"&").replace(/e.length)break e;if(!(d instanceof a)){u.lastIndex=0;var m=u.exec(d);if(m){c&&(f=m[1].length);var y=m.index-1+f,m=m[0].slice(f),v=m.length,k=y+v,b=d.slice(0,y+1),w=d.slice(k+1),N=[p,1];b&&N.push(b);var O=new a(l,g?t.tokenize(m,g):m,h);N.push(O),w&&N.push(w),Array.prototype.splice.apply(r,N)}}}}}return r},hooks:{all:{},add:function(e,n){var a=t.hooks.all;a[e]=a[e]||[],a[e].push(n)},run:function(e,n){var a=t.hooks.all[e];if(a&&a.length)for(var r,i=0;r=a[i++];)r(n)}}},n=t.Token=function(e,t,n){this.type=e,this.content=t,this.alias=n};if(n.stringify=function(e,a,r){if("string"==typeof e)return e;if("Array"===t.util.type(e))return e.map(function(t){return n.stringify(t,a,e)}).join("");var i={type:e.type,content:n.stringify(e.content,a,r),tag:"span",classes:["token",e.type],attributes:{},language:a,parent:r};if("comment"==i.type&&(i.attributes.spellcheck="true"),e.alias){var l="Array"===t.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(i.classes,l)}t.hooks.run("wrap",i);var s="";for(var o in i.attributes)s+=o+'="'+(i.attributes[o]||"")+'"';return"<"+i.tag+' class="'+i.classes.join(" ")+'" '+s+">"+i.content+""},!self.document)return self.addEventListener?(self.addEventListener("message",function(e){var n=JSON.parse(e.data),a=n.language,r=n.code;self.postMessage(JSON.stringify(t.util.encode(t.tokenize(r,t.languages[a])))),self.close()},!1),self.Prism):self.Prism;var a=document.getElementsByTagName("script");return a=a[a.length-1],a&&(t.filename=a.src,document.addEventListener&&!a.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)),self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism);; +Prism.languages.markup={comment://,prolog:/<\?.+?\?>/,doctype://,cdata://i,tag:{pattern:/<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|[^\s'">=]+))?\s*)*\/?>/i,inside:{tag:{pattern:/^<\/?[\w:-]+/i,inside:{punctuation:/^<\/?/,namespace:/^[\w-]+?:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/=|>|"/}},punctuation:/\/?>/,"attr-name":{pattern:/[\w:-]+/,inside:{namespace:/^[\w-]+?:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.hooks.add("wrap",function(t){"entity"===t.type&&(t.attributes.title=t.content.replace(/&/,"&"))});; +Prism.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{punctuation:/[;:]/}},url:/url\((?:(["'])(\\\n|\\?.)*?\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*(?=\s*\{)/,string:/("|')(\\\n|\\?.)*?\1/,property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,punctuation:/[\{\};:]/,"function":/[-a-z0-9]+(?=\()/i},Prism.languages.markup&&(Prism.languages.insertBefore("markup","tag",{style:{pattern:/[\w\W]*?<\/style>/i,inside:{tag:{pattern:/|<\/style>/i,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.css},alias:"language-css"}}),Prism.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|').*?\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:Prism.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:Prism.languages.css}},alias:"language-css"}},Prism.languages.markup.tag));; +Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.+/,lookbehind:!0}],string:/("|')(\\\n|\\?.)*?\1/,"class-name":{pattern:/((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(true|false)\b/,"function":{pattern:/[a-z0-9_]+\(/i,inside:{punctuation:/\(/}},number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/,operator:/[-+]{1,2}|!|<=?|>=?|={1,3}|&{1,2}|\|?\||\?|\*|\/|~|\^|%/,ignore:/&(lt|gt|amp);/i,punctuation:/[{}[\];(),.:]/};; +Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|function|get|if|implements|import|in|instanceof|interface|let|new|null|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|-?Infinity)\b/,"function":/(?!\d)[a-z0-9_$]+(?=\()/i}),Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/[\w\W]*?<\/script>/i,inside:{tag:{pattern:/|<\/script>/i,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript},alias:"language-javascript"}});; diff --git a/resources/zeroclipboard/.jshintrc b/resources/zeroclipboard/.jshintrc new file mode 100644 index 0000000000..15359aa1a5 --- /dev/null +++ b/resources/zeroclipboard/.jshintrc @@ -0,0 +1,70 @@ +{ + /* Enforcing options */ + "bitwise": true, + "camelcase": true, + "curly": true, + "eqeqeq": true, + "es3": true, + "es5": false, + "forin": true, + "freeze": true, + "immed": true, + "indent": 2, + "latedef": true, + "newcap": true, + "noarg": true, + "noempty": true, + "nonbsp": true, + "nonew": true, + "plusplus": false, + "quotmark": "double", + "undef": true, + "unused": true, + "strict": true, + "trailing": true, + "maxparams": 4, + "maxdepth": 5, + "maxstatements": false, + "maxlen": false, /* IDEAL: 120? */ + + + /* Relaxing options */ + "asi": false, + "boss": false, + "debug": false, + "eqnull": true, + "esnext": false, + "evil": false, + "expr": false, + "funcscope": false, + "gcl": false, + "globalstrict": false, + "iterator": false, + "lastsemic": false, + "laxbreak": false, + "laxcomma": false, + "loopfunc": false, + "maxerr": 50, + "moz": false, + "multistr": false, + "notypeof": false, + "proto": false, + "scripturl": false, + "smarttabs": false, + "shadow": false, + "sub": false, + "supernew": false, + "validthis": false, + "noyield": false, + + /* Environments */ + "browser": true, + + /* Global variables */ + "globals": { + /* AMD */ + "define": false, + /* CommonJS */ + "module": false + } +} \ No newline at end of file diff --git a/resources/zeroclipboard/ZeroClipboard.Core.js b/resources/zeroclipboard/ZeroClipboard.Core.js new file mode 100644 index 0000000000..b58b14675b --- /dev/null +++ b/resources/zeroclipboard/ZeroClipboard.Core.js @@ -0,0 +1,2017 @@ +/*! + * ZeroClipboard + * The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface. + * Copyright (c) 2009-2014 Jon Rohan, James M. Greene + * Licensed MIT + * http://zeroclipboard.org/ + * v2.2.0 + */ +(function(window, undefined) { + "use strict"; + /** + * Store references to critically important global functions that may be + * overridden on certain web pages. + */ + var _window = window, _document = _window.document, _navigator = _window.navigator, _setTimeout = _window.setTimeout, _clearTimeout = _window.clearTimeout, _setInterval = _window.setInterval, _clearInterval = _window.clearInterval, _getComputedStyle = _window.getComputedStyle, _encodeURIComponent = _window.encodeURIComponent, _ActiveXObject = _window.ActiveXObject, _Error = _window.Error, _parseInt = _window.Number.parseInt || _window.parseInt, _parseFloat = _window.Number.parseFloat || _window.parseFloat, _isNaN = _window.Number.isNaN || _window.isNaN, _now = _window.Date.now, _keys = _window.Object.keys, _defineProperty = _window.Object.defineProperty, _hasOwn = _window.Object.prototype.hasOwnProperty, _slice = _window.Array.prototype.slice, _unwrap = function() { + var unwrapper = function(el) { + return el; + }; + if (typeof _window.wrap === "function" && typeof _window.unwrap === "function") { + try { + var div = _document.createElement("div"); + var unwrappedDiv = _window.unwrap(div); + if (div.nodeType === 1 && unwrappedDiv && unwrappedDiv.nodeType === 1) { + unwrapper = _window.unwrap; + } + } catch (e) {} + } + return unwrapper; + }(); + /** + * Convert an `arguments` object into an Array. + * + * @returns The arguments as an Array + * @private + */ + var _args = function(argumentsObj) { + return _slice.call(argumentsObj, 0); + }; + /** + * Shallow-copy the owned, enumerable properties of one object over to another, similar to jQuery's `$.extend`. + * + * @returns The target object, augmented + * @private + */ + var _extend = function() { + var i, len, arg, prop, src, copy, args = _args(arguments), target = args[0] || {}; + for (i = 1, len = args.length; i < len; i++) { + if ((arg = args[i]) != null) { + for (prop in arg) { + if (_hasOwn.call(arg, prop)) { + src = target[prop]; + copy = arg[prop]; + if (target !== copy && copy !== undefined) { + target[prop] = copy; + } + } + } + } + } + return target; + }; + /** + * Return a deep copy of the source object or array. + * + * @returns Object or Array + * @private + */ + var _deepCopy = function(source) { + var copy, i, len, prop; + if (typeof source !== "object" || source == null || typeof source.nodeType === "number") { + copy = source; + } else if (typeof source.length === "number") { + copy = []; + for (i = 0, len = source.length; i < len; i++) { + if (_hasOwn.call(source, i)) { + copy[i] = _deepCopy(source[i]); + } + } + } else { + copy = {}; + for (prop in source) { + if (_hasOwn.call(source, prop)) { + copy[prop] = _deepCopy(source[prop]); + } + } + } + return copy; + }; + /** + * Makes a shallow copy of `obj` (like `_extend`) but filters its properties based on a list of `keys` to keep. + * The inverse of `_omit`, mostly. The big difference is that these properties do NOT need to be enumerable to + * be kept. + * + * @returns A new filtered object. + * @private + */ + var _pick = function(obj, keys) { + var newObj = {}; + for (var i = 0, len = keys.length; i < len; i++) { + if (keys[i] in obj) { + newObj[keys[i]] = obj[keys[i]]; + } + } + return newObj; + }; + /** + * Makes a shallow copy of `obj` (like `_extend`) but filters its properties based on a list of `keys` to omit. + * The inverse of `_pick`. + * + * @returns A new filtered object. + * @private + */ + var _omit = function(obj, keys) { + var newObj = {}; + for (var prop in obj) { + if (keys.indexOf(prop) === -1) { + newObj[prop] = obj[prop]; + } + } + return newObj; + }; + /** + * Remove all owned, enumerable properties from an object. + * + * @returns The original object without its owned, enumerable properties. + * @private + */ + var _deleteOwnProperties = function(obj) { + if (obj) { + for (var prop in obj) { + if (_hasOwn.call(obj, prop)) { + delete obj[prop]; + } + } + } + return obj; + }; + /** + * Determine if an element is contained within another element. + * + * @returns Boolean + * @private + */ + var _containedBy = function(el, ancestorEl) { + if (el && el.nodeType === 1 && el.ownerDocument && ancestorEl && (ancestorEl.nodeType === 1 && ancestorEl.ownerDocument && ancestorEl.ownerDocument === el.ownerDocument || ancestorEl.nodeType === 9 && !ancestorEl.ownerDocument && ancestorEl === el.ownerDocument)) { + do { + if (el === ancestorEl) { + return true; + } + el = el.parentNode; + } while (el); + } + return false; + }; + /** + * Get the URL path's parent directory. + * + * @returns String or `undefined` + * @private + */ + var _getDirPathOfUrl = function(url) { + var dir; + if (typeof url === "string" && url) { + dir = url.split("#")[0].split("?")[0]; + dir = url.slice(0, url.lastIndexOf("/") + 1); + } + return dir; + }; + /** + * Get the current script's URL by throwing an `Error` and analyzing it. + * + * @returns String or `undefined` + * @private + */ + var _getCurrentScriptUrlFromErrorStack = function(stack) { + var url, matches; + if (typeof stack === "string" && stack) { + matches = stack.match(/^(?:|[^:@]*@|.+\)@(?=http[s]?|file)|.+?\s+(?: at |@)(?:[^:\(]+ )*[\(]?)((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/); + if (matches && matches[1]) { + url = matches[1]; + } else { + matches = stack.match(/\)@((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/); + if (matches && matches[1]) { + url = matches[1]; + } + } + } + return url; + }; + /** + * Get the current script's URL by throwing an `Error` and analyzing it. + * + * @returns String or `undefined` + * @private + */ + var _getCurrentScriptUrlFromError = function() { + var url, err; + try { + throw new _Error(); + } catch (e) { + err = e; + } + if (err) { + url = err.sourceURL || err.fileName || _getCurrentScriptUrlFromErrorStack(err.stack); + } + return url; + }; + /** + * Get the current script's URL. + * + * @returns String or `undefined` + * @private + */ + var _getCurrentScriptUrl = function() { + var jsPath, scripts, i; + if (_document.currentScript && (jsPath = _document.currentScript.src)) { + return jsPath; + } + scripts = _document.getElementsByTagName("script"); + if (scripts.length === 1) { + return scripts[0].src || undefined; + } + if ("readyState" in scripts[0]) { + for (i = scripts.length; i--; ) { + if (scripts[i].readyState === "interactive" && (jsPath = scripts[i].src)) { + return jsPath; + } + } + } + if (_document.readyState === "loading" && (jsPath = scripts[scripts.length - 1].src)) { + return jsPath; + } + if (jsPath = _getCurrentScriptUrlFromError()) { + return jsPath; + } + return undefined; + }; + /** + * Get the unanimous parent directory of ALL script tags. + * If any script tags are either (a) inline or (b) from differing parent + * directories, this method must return `undefined`. + * + * @returns String or `undefined` + * @private + */ + var _getUnanimousScriptParentDir = function() { + var i, jsDir, jsPath, scripts = _document.getElementsByTagName("script"); + for (i = scripts.length; i--; ) { + if (!(jsPath = scripts[i].src)) { + jsDir = null; + break; + } + jsPath = _getDirPathOfUrl(jsPath); + if (jsDir == null) { + jsDir = jsPath; + } else if (jsDir !== jsPath) { + jsDir = null; + break; + } + } + return jsDir || undefined; + }; + /** + * Get the presumed location of the "ZeroClipboard.swf" file, based on the location + * of the executing JavaScript file (e.g. "ZeroClipboard.js", etc.). + * + * @returns String + * @private + */ + var _getDefaultSwfPath = function() { + var jsDir = _getDirPathOfUrl(_getCurrentScriptUrl()) || _getUnanimousScriptParentDir() || ""; + return jsDir + "ZeroClipboard.swf"; + }; + /** + * Keep track of if the page is framed (in an `iframe`). This can never change. + * @private + */ + var _pageIsFramed = function() { + return window.opener == null && (!!window.top && window != window.top || !!window.parent && window != window.parent); + }(); + /** + * Keep track of the state of the Flash object. + * @private + */ + var _flashState = { + bridge: null, + version: "0.0.0", + pluginType: "unknown", + disabled: null, + outdated: null, + sandboxed: null, + unavailable: null, + degraded: null, + deactivated: null, + overdue: null, + ready: null + }; + /** + * The minimum Flash Player version required to use ZeroClipboard completely. + * @readonly + * @private + */ + var _minimumFlashVersion = "11.0.0"; + /** + * The ZeroClipboard library version number, as reported by Flash, at the time the SWF was compiled. + */ + var _zcSwfVersion; + /** + * Keep track of all event listener registrations. + * @private + */ + var _handlers = {}; + /** + * Keep track of the currently activated element. + * @private + */ + var _currentElement; + /** + * Keep track of the element that was activated when a `copy` process started. + * @private + */ + var _copyTarget; + /** + * Keep track of data for the pending clipboard transaction. + * @private + */ + var _clipData = {}; + /** + * Keep track of data formats for the pending clipboard transaction. + * @private + */ + var _clipDataFormatMap = null; + /** + * Keep track of the Flash availability check timeout. + * @private + */ + var _flashCheckTimeout = 0; + /** + * Keep track of SWF network errors interval polling. + * @private + */ + var _swfFallbackCheckInterval = 0; + /** + * The `message` store for events + * @private + */ + var _eventMessages = { + ready: "Flash communication is established", + error: { + "flash-disabled": "Flash is disabled or not installed. May also be attempting to run Flash in a sandboxed iframe, which is impossible.", + "flash-outdated": "Flash is too outdated to support ZeroClipboard", + "flash-sandboxed": "Attempting to run Flash in a sandboxed iframe, which is impossible", + "flash-unavailable": "Flash is unable to communicate bidirectionally with JavaScript", + "flash-degraded": "Flash is unable to preserve data fidelity when communicating with JavaScript", + "flash-deactivated": "Flash is too outdated for your browser and/or is configured as click-to-activate.\nThis may also mean that the ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity.\nMay also be attempting to run Flash in a sandboxed iframe, which is impossible.", + "flash-overdue": "Flash communication was established but NOT within the acceptable time limit", + "version-mismatch": "ZeroClipboard JS version number does not match ZeroClipboard SWF version number", + "clipboard-error": "At least one error was thrown while ZeroClipboard was attempting to inject your data into the clipboard", + "config-mismatch": "ZeroClipboard configuration does not match Flash's reality", + "swf-not-found": "The ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity" + } + }; + /** + * The `name`s of `error` events that can only occur is Flash has at least + * been able to load the SWF successfully. + * @private + */ + var _errorsThatOnlyOccurAfterFlashLoads = [ "flash-unavailable", "flash-degraded", "flash-overdue", "version-mismatch", "config-mismatch", "clipboard-error" ]; + /** + * The `name`s of `error` events that should likely result in the `_flashState` + * variable's property values being updated. + * @private + */ + var _flashStateErrorNames = [ "flash-disabled", "flash-outdated", "flash-sandboxed", "flash-unavailable", "flash-degraded", "flash-deactivated", "flash-overdue" ]; + /** + * A RegExp to match the `name` property of `error` events related to Flash. + * @private + */ + var _flashStateErrorNameMatchingRegex = new RegExp("^flash-(" + _flashStateErrorNames.map(function(errorName) { + return errorName.replace(/^flash-/, ""); + }).join("|") + ")$"); + /** + * A RegExp to match the `name` property of `error` events related to Flash, + * which is enabled. + * @private + */ + var _flashStateEnabledErrorNameMatchingRegex = new RegExp("^flash-(" + _flashStateErrorNames.slice(1).map(function(errorName) { + return errorName.replace(/^flash-/, ""); + }).join("|") + ")$"); + /** + * ZeroClipboard configuration defaults for the Core module. + * @private + */ + var _globalConfig = { + swfPath: _getDefaultSwfPath(), + trustedDomains: window.location.host ? [ window.location.host ] : [], + cacheBust: true, + forceEnhancedClipboard: false, + flashLoadTimeout: 3e4, + autoActivate: true, + bubbleEvents: true, + containerId: "global-zeroclipboard-html-bridge", + containerClass: "global-zeroclipboard-container", + swfObjectId: "global-zeroclipboard-flash-bridge", + hoverClass: "zeroclipboard-is-hover", + activeClass: "zeroclipboard-is-active", + forceHandCursor: false, + title: null, + zIndex: 999999999 + }; + /** + * The underlying implementation of `ZeroClipboard.config`. + * @private + */ + var _config = function(options) { + if (typeof options === "object" && options !== null) { + for (var prop in options) { + if (_hasOwn.call(options, prop)) { + if (/^(?:forceHandCursor|title|zIndex|bubbleEvents)$/.test(prop)) { + _globalConfig[prop] = options[prop]; + } else if (_flashState.bridge == null) { + if (prop === "containerId" || prop === "swfObjectId") { + if (_isValidHtml4Id(options[prop])) { + _globalConfig[prop] = options[prop]; + } else { + throw new Error("The specified `" + prop + "` value is not valid as an HTML4 Element ID"); + } + } else { + _globalConfig[prop] = options[prop]; + } + } + } + } + } + if (typeof options === "string" && options) { + if (_hasOwn.call(_globalConfig, options)) { + return _globalConfig[options]; + } + return; + } + return _deepCopy(_globalConfig); + }; + /** + * The underlying implementation of `ZeroClipboard.state`. + * @private + */ + var _state = function() { + _detectSandbox(); + return { + browser: _pick(_navigator, [ "userAgent", "platform", "appName" ]), + flash: _omit(_flashState, [ "bridge" ]), + zeroclipboard: { + version: ZeroClipboard.version, + config: ZeroClipboard.config() + } + }; + }; + /** + * The underlying implementation of `ZeroClipboard.isFlashUnusable`. + * @private + */ + var _isFlashUnusable = function() { + return !!(_flashState.disabled || _flashState.outdated || _flashState.sandboxed || _flashState.unavailable || _flashState.degraded || _flashState.deactivated); + }; + /** + * The underlying implementation of `ZeroClipboard.on`. + * @private + */ + var _on = function(eventType, listener) { + var i, len, events, added = {}; + if (typeof eventType === "string" && eventType) { + events = eventType.toLowerCase().split(/\s+/); + } else if (typeof eventType === "object" && eventType && typeof listener === "undefined") { + for (i in eventType) { + if (_hasOwn.call(eventType, i) && typeof i === "string" && i && typeof eventType[i] === "function") { + ZeroClipboard.on(i, eventType[i]); + } + } + } + if (events && events.length) { + for (i = 0, len = events.length; i < len; i++) { + eventType = events[i].replace(/^on/, ""); + added[eventType] = true; + if (!_handlers[eventType]) { + _handlers[eventType] = []; + } + _handlers[eventType].push(listener); + } + if (added.ready && _flashState.ready) { + ZeroClipboard.emit({ + type: "ready" + }); + } + if (added.error) { + for (i = 0, len = _flashStateErrorNames.length; i < len; i++) { + if (_flashState[_flashStateErrorNames[i].replace(/^flash-/, "")] === true) { + ZeroClipboard.emit({ + type: "error", + name: _flashStateErrorNames[i] + }); + break; + } + } + if (_zcSwfVersion !== undefined && ZeroClipboard.version !== _zcSwfVersion) { + ZeroClipboard.emit({ + type: "error", + name: "version-mismatch", + jsVersion: ZeroClipboard.version, + swfVersion: _zcSwfVersion + }); + } + } + } + return ZeroClipboard; + }; + /** + * The underlying implementation of `ZeroClipboard.off`. + * @private + */ + var _off = function(eventType, listener) { + var i, len, foundIndex, events, perEventHandlers; + if (arguments.length === 0) { + events = _keys(_handlers); + } else if (typeof eventType === "string" && eventType) { + events = eventType.split(/\s+/); + } else if (typeof eventType === "object" && eventType && typeof listener === "undefined") { + for (i in eventType) { + if (_hasOwn.call(eventType, i) && typeof i === "string" && i && typeof eventType[i] === "function") { + ZeroClipboard.off(i, eventType[i]); + } + } + } + if (events && events.length) { + for (i = 0, len = events.length; i < len; i++) { + eventType = events[i].toLowerCase().replace(/^on/, ""); + perEventHandlers = _handlers[eventType]; + if (perEventHandlers && perEventHandlers.length) { + if (listener) { + foundIndex = perEventHandlers.indexOf(listener); + while (foundIndex !== -1) { + perEventHandlers.splice(foundIndex, 1); + foundIndex = perEventHandlers.indexOf(listener, foundIndex); + } + } else { + perEventHandlers.length = 0; + } + } + } + } + return ZeroClipboard; + }; + /** + * The underlying implementation of `ZeroClipboard.handlers`. + * @private + */ + var _listeners = function(eventType) { + var copy; + if (typeof eventType === "string" && eventType) { + copy = _deepCopy(_handlers[eventType]) || null; + } else { + copy = _deepCopy(_handlers); + } + return copy; + }; + /** + * The underlying implementation of `ZeroClipboard.emit`. + * @private + */ + var _emit = function(event) { + var eventCopy, returnVal, tmp; + event = _createEvent(event); + if (!event) { + return; + } + if (_preprocessEvent(event)) { + return; + } + if (event.type === "ready" && _flashState.overdue === true) { + return ZeroClipboard.emit({ + type: "error", + name: "flash-overdue" + }); + } + eventCopy = _extend({}, event); + _dispatchCallbacks.call(this, eventCopy); + if (event.type === "copy") { + tmp = _mapClipDataToFlash(_clipData); + returnVal = tmp.data; + _clipDataFormatMap = tmp.formatMap; + } + return returnVal; + }; + /** + * The underlying implementation of `ZeroClipboard.create`. + * @private + */ + var _create = function() { + var previousState = _flashState.sandboxed; + _detectSandbox(); + if (typeof _flashState.ready !== "boolean") { + _flashState.ready = false; + } + if (_flashState.sandboxed !== previousState && _flashState.sandboxed === true) { + _flashState.ready = false; + ZeroClipboard.emit({ + type: "error", + name: "flash-sandboxed" + }); + } else if (!ZeroClipboard.isFlashUnusable() && _flashState.bridge === null) { + var maxWait = _globalConfig.flashLoadTimeout; + if (typeof maxWait === "number" && maxWait >= 0) { + _flashCheckTimeout = _setTimeout(function() { + if (typeof _flashState.deactivated !== "boolean") { + _flashState.deactivated = true; + } + if (_flashState.deactivated === true) { + ZeroClipboard.emit({ + type: "error", + name: "flash-deactivated" + }); + } + }, maxWait); + } + _flashState.overdue = false; + _embedSwf(); + } + }; + /** + * The underlying implementation of `ZeroClipboard.destroy`. + * @private + */ + var _destroy = function() { + ZeroClipboard.clearData(); + ZeroClipboard.blur(); + ZeroClipboard.emit("destroy"); + _unembedSwf(); + ZeroClipboard.off(); + }; + /** + * The underlying implementation of `ZeroClipboard.setData`. + * @private + */ + var _setData = function(format, data) { + var dataObj; + if (typeof format === "object" && format && typeof data === "undefined") { + dataObj = format; + ZeroClipboard.clearData(); + } else if (typeof format === "string" && format) { + dataObj = {}; + dataObj[format] = data; + } else { + return; + } + for (var dataFormat in dataObj) { + if (typeof dataFormat === "string" && dataFormat && _hasOwn.call(dataObj, dataFormat) && typeof dataObj[dataFormat] === "string" && dataObj[dataFormat]) { + _clipData[dataFormat] = dataObj[dataFormat]; + } + } + }; + /** + * The underlying implementation of `ZeroClipboard.clearData`. + * @private + */ + var _clearData = function(format) { + if (typeof format === "undefined") { + _deleteOwnProperties(_clipData); + _clipDataFormatMap = null; + } else if (typeof format === "string" && _hasOwn.call(_clipData, format)) { + delete _clipData[format]; + } + }; + /** + * The underlying implementation of `ZeroClipboard.getData`. + * @private + */ + var _getData = function(format) { + if (typeof format === "undefined") { + return _deepCopy(_clipData); + } else if (typeof format === "string" && _hasOwn.call(_clipData, format)) { + return _clipData[format]; + } + }; + /** + * The underlying implementation of `ZeroClipboard.focus`/`ZeroClipboard.activate`. + * @private + */ + var _focus = function(element) { + if (!(element && element.nodeType === 1)) { + return; + } + if (_currentElement) { + _removeClass(_currentElement, _globalConfig.activeClass); + if (_currentElement !== element) { + _removeClass(_currentElement, _globalConfig.hoverClass); + } + } + _currentElement = element; + _addClass(element, _globalConfig.hoverClass); + var newTitle = element.getAttribute("title") || _globalConfig.title; + if (typeof newTitle === "string" && newTitle) { + var htmlBridge = _getHtmlBridge(_flashState.bridge); + if (htmlBridge) { + htmlBridge.setAttribute("title", newTitle); + } + } + var useHandCursor = _globalConfig.forceHandCursor === true || _getStyle(element, "cursor") === "pointer"; + _setHandCursor(useHandCursor); + _reposition(); + }; + /** + * The underlying implementation of `ZeroClipboard.blur`/`ZeroClipboard.deactivate`. + * @private + */ + var _blur = function() { + var htmlBridge = _getHtmlBridge(_flashState.bridge); + if (htmlBridge) { + htmlBridge.removeAttribute("title"); + htmlBridge.style.left = "0px"; + htmlBridge.style.top = "-9999px"; + htmlBridge.style.width = "1px"; + htmlBridge.style.height = "1px"; + } + if (_currentElement) { + _removeClass(_currentElement, _globalConfig.hoverClass); + _removeClass(_currentElement, _globalConfig.activeClass); + _currentElement = null; + } + }; + /** + * The underlying implementation of `ZeroClipboard.activeElement`. + * @private + */ + var _activeElement = function() { + return _currentElement || null; + }; + /** + * Check if a value is a valid HTML4 `ID` or `Name` token. + * @private + */ + var _isValidHtml4Id = function(id) { + return typeof id === "string" && id && /^[A-Za-z][A-Za-z0-9_:\-\.]*$/.test(id); + }; + /** + * Create or update an `event` object, based on the `eventType`. + * @private + */ + var _createEvent = function(event) { + var eventType; + if (typeof event === "string" && event) { + eventType = event; + event = {}; + } else if (typeof event === "object" && event && typeof event.type === "string" && event.type) { + eventType = event.type; + } + if (!eventType) { + return; + } + eventType = eventType.toLowerCase(); + if (!event.target && (/^(copy|aftercopy|_click)$/.test(eventType) || eventType === "error" && event.name === "clipboard-error")) { + event.target = _copyTarget; + } + _extend(event, { + type: eventType, + target: event.target || _currentElement || null, + relatedTarget: event.relatedTarget || null, + currentTarget: _flashState && _flashState.bridge || null, + timeStamp: event.timeStamp || _now() || null + }); + var msg = _eventMessages[event.type]; + if (event.type === "error" && event.name && msg) { + msg = msg[event.name]; + } + if (msg) { + event.message = msg; + } + if (event.type === "ready") { + _extend(event, { + target: null, + version: _flashState.version + }); + } + if (event.type === "error") { + if (_flashStateErrorNameMatchingRegex.test(event.name)) { + _extend(event, { + target: null, + minimumVersion: _minimumFlashVersion + }); + } + if (_flashStateEnabledErrorNameMatchingRegex.test(event.name)) { + _extend(event, { + version: _flashState.version + }); + } + } + if (event.type === "copy") { + event.clipboardData = { + setData: ZeroClipboard.setData, + clearData: ZeroClipboard.clearData + }; + } + if (event.type === "aftercopy") { + event = _mapClipResultsFromFlash(event, _clipDataFormatMap); + } + if (event.target && !event.relatedTarget) { + event.relatedTarget = _getRelatedTarget(event.target); + } + return _addMouseData(event); + }; + /** + * Get a relatedTarget from the target's `data-clipboard-target` attribute + * @private + */ + var _getRelatedTarget = function(targetEl) { + var relatedTargetId = targetEl && targetEl.getAttribute && targetEl.getAttribute("data-clipboard-target"); + return relatedTargetId ? _document.getElementById(relatedTargetId) : null; + }; + /** + * Add element and position data to `MouseEvent` instances + * @private + */ + var _addMouseData = function(event) { + if (event && /^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) { + var srcElement = event.target; + var fromElement = event.type === "_mouseover" && event.relatedTarget ? event.relatedTarget : undefined; + var toElement = event.type === "_mouseout" && event.relatedTarget ? event.relatedTarget : undefined; + var pos = _getElementPosition(srcElement); + var screenLeft = _window.screenLeft || _window.screenX || 0; + var screenTop = _window.screenTop || _window.screenY || 0; + var scrollLeft = _document.body.scrollLeft + _document.documentElement.scrollLeft; + var scrollTop = _document.body.scrollTop + _document.documentElement.scrollTop; + var pageX = pos.left + (typeof event._stageX === "number" ? event._stageX : 0); + var pageY = pos.top + (typeof event._stageY === "number" ? event._stageY : 0); + var clientX = pageX - scrollLeft; + var clientY = pageY - scrollTop; + var screenX = screenLeft + clientX; + var screenY = screenTop + clientY; + var moveX = typeof event.movementX === "number" ? event.movementX : 0; + var moveY = typeof event.movementY === "number" ? event.movementY : 0; + delete event._stageX; + delete event._stageY; + _extend(event, { + srcElement: srcElement, + fromElement: fromElement, + toElement: toElement, + screenX: screenX, + screenY: screenY, + pageX: pageX, + pageY: pageY, + clientX: clientX, + clientY: clientY, + x: clientX, + y: clientY, + movementX: moveX, + movementY: moveY, + offsetX: 0, + offsetY: 0, + layerX: 0, + layerY: 0 + }); + } + return event; + }; + /** + * Determine if an event's registered handlers should be execute synchronously or asynchronously. + * + * @returns {boolean} + * @private + */ + var _shouldPerformAsync = function(event) { + var eventType = event && typeof event.type === "string" && event.type || ""; + return !/^(?:(?:before)?copy|destroy)$/.test(eventType); + }; + /** + * Control if a callback should be executed asynchronously or not. + * + * @returns `undefined` + * @private + */ + var _dispatchCallback = function(func, context, args, async) { + if (async) { + _setTimeout(function() { + func.apply(context, args); + }, 0); + } else { + func.apply(context, args); + } + }; + /** + * Handle the actual dispatching of events to client instances. + * + * @returns `undefined` + * @private + */ + var _dispatchCallbacks = function(event) { + if (!(typeof event === "object" && event && event.type)) { + return; + } + var async = _shouldPerformAsync(event); + var wildcardTypeHandlers = _handlers["*"] || []; + var specificTypeHandlers = _handlers[event.type] || []; + var handlers = wildcardTypeHandlers.concat(specificTypeHandlers); + if (handlers && handlers.length) { + var i, len, func, context, eventCopy, originalContext = this; + for (i = 0, len = handlers.length; i < len; i++) { + func = handlers[i]; + context = originalContext; + if (typeof func === "string" && typeof _window[func] === "function") { + func = _window[func]; + } + if (typeof func === "object" && func && typeof func.handleEvent === "function") { + context = func; + func = func.handleEvent; + } + if (typeof func === "function") { + eventCopy = _extend({}, event); + _dispatchCallback(func, context, [ eventCopy ], async); + } + } + } + return this; + }; + /** + * Check an `error` event's `name` property to see if Flash has + * already loaded, which rules out possible `iframe` sandboxing. + * @private + */ + var _getSandboxStatusFromErrorEvent = function(event) { + var isSandboxed = null; + if (_pageIsFramed === false || event && event.type === "error" && event.name && _errorsThatOnlyOccurAfterFlashLoads.indexOf(event.name) !== -1) { + isSandboxed = false; + } + return isSandboxed; + }; + /** + * Preprocess any special behaviors, reactions, or state changes after receiving this event. + * Executes only once per event emitted, NOT once per client. + * @private + */ + var _preprocessEvent = function(event) { + var element = event.target || _currentElement || null; + var sourceIsSwf = event._source === "swf"; + delete event._source; + switch (event.type) { + case "error": + var isSandboxed = event.name === "flash-sandboxed" || _getSandboxStatusFromErrorEvent(event); + if (typeof isSandboxed === "boolean") { + _flashState.sandboxed = isSandboxed; + } + if (_flashStateErrorNames.indexOf(event.name) !== -1) { + _extend(_flashState, { + disabled: event.name === "flash-disabled", + outdated: event.name === "flash-outdated", + unavailable: event.name === "flash-unavailable", + degraded: event.name === "flash-degraded", + deactivated: event.name === "flash-deactivated", + overdue: event.name === "flash-overdue", + ready: false + }); + } else if (event.name === "version-mismatch") { + _zcSwfVersion = event.swfVersion; + _extend(_flashState, { + disabled: false, + outdated: false, + unavailable: false, + degraded: false, + deactivated: false, + overdue: false, + ready: false + }); + } + _clearTimeoutsAndPolling(); + break; + + case "ready": + _zcSwfVersion = event.swfVersion; + var wasDeactivated = _flashState.deactivated === true; + _extend(_flashState, { + disabled: false, + outdated: false, + sandboxed: false, + unavailable: false, + degraded: false, + deactivated: false, + overdue: wasDeactivated, + ready: !wasDeactivated + }); + _clearTimeoutsAndPolling(); + break; + + case "beforecopy": + _copyTarget = element; + break; + + case "copy": + var textContent, htmlContent, targetEl = event.relatedTarget; + if (!(_clipData["text/html"] || _clipData["text/plain"]) && targetEl && (htmlContent = targetEl.value || targetEl.outerHTML || targetEl.innerHTML) && (textContent = targetEl.value || targetEl.textContent || targetEl.innerText)) { + event.clipboardData.clearData(); + event.clipboardData.setData("text/plain", textContent); + if (htmlContent !== textContent) { + event.clipboardData.setData("text/html", htmlContent); + } + } else if (!_clipData["text/plain"] && event.target && (textContent = event.target.getAttribute("data-clipboard-text"))) { + event.clipboardData.clearData(); + event.clipboardData.setData("text/plain", textContent); + } + break; + + case "aftercopy": + _queueEmitClipboardErrors(event); + ZeroClipboard.clearData(); + if (element && element !== _safeActiveElement() && element.focus) { + element.focus(); + } + break; + + case "_mouseover": + ZeroClipboard.focus(element); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) { + _fireMouseEvent(_extend({}, event, { + type: "mouseenter", + bubbles: false, + cancelable: false + })); + } + _fireMouseEvent(_extend({}, event, { + type: "mouseover" + })); + } + break; + + case "_mouseout": + ZeroClipboard.blur(); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) { + _fireMouseEvent(_extend({}, event, { + type: "mouseleave", + bubbles: false, + cancelable: false + })); + } + _fireMouseEvent(_extend({}, event, { + type: "mouseout" + })); + } + break; + + case "_mousedown": + _addClass(element, _globalConfig.activeClass); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; + + case "_mouseup": + _removeClass(element, _globalConfig.activeClass); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; + + case "_click": + _copyTarget = null; + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; + + case "_mousemove": + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; + } + if (/^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) { + return true; + } + }; + /** + * Check an "aftercopy" event for clipboard errors and emit a corresponding "error" event. + * @private + */ + var _queueEmitClipboardErrors = function(aftercopyEvent) { + if (aftercopyEvent.errors && aftercopyEvent.errors.length > 0) { + var errorEvent = _deepCopy(aftercopyEvent); + _extend(errorEvent, { + type: "error", + name: "clipboard-error" + }); + delete errorEvent.success; + _setTimeout(function() { + ZeroClipboard.emit(errorEvent); + }, 0); + } + }; + /** + * Dispatch a synthetic MouseEvent. + * + * @returns `undefined` + * @private + */ + var _fireMouseEvent = function(event) { + if (!(event && typeof event.type === "string" && event)) { + return; + } + var e, target = event.target || null, doc = target && target.ownerDocument || _document, defaults = { + view: doc.defaultView || _window, + canBubble: true, + cancelable: true, + detail: event.type === "click" ? 1 : 0, + button: typeof event.which === "number" ? event.which - 1 : typeof event.button === "number" ? event.button : doc.createEvent ? 0 : 1 + }, args = _extend(defaults, event); + if (!target) { + return; + } + if (doc.createEvent && target.dispatchEvent) { + args = [ args.type, args.canBubble, args.cancelable, args.view, args.detail, args.screenX, args.screenY, args.clientX, args.clientY, args.ctrlKey, args.altKey, args.shiftKey, args.metaKey, args.button, args.relatedTarget ]; + e = doc.createEvent("MouseEvents"); + if (e.initMouseEvent) { + e.initMouseEvent.apply(e, args); + e._source = "js"; + target.dispatchEvent(e); + } + } + }; + /** + * Continuously poll the DOM until either: + * (a) the fallback content becomes visible, or + * (b) we receive an event from SWF (handled elsewhere) + * + * IMPORTANT: + * This is NOT a necessary check but it can result in significantly faster + * detection of bad `swfPath` configuration and/or network/server issues [in + * supported browsers] than waiting for the entire `flashLoadTimeout` duration + * to elapse before detecting that the SWF cannot be loaded. The detection + * duration can be anywhere from 10-30 times faster [in supported browsers] by + * using this approach. + * + * @returns `undefined` + * @private + */ + var _watchForSwfFallbackContent = function() { + var maxWait = _globalConfig.flashLoadTimeout; + if (typeof maxWait === "number" && maxWait >= 0) { + var pollWait = Math.min(1e3, maxWait / 10); + var fallbackContentId = _globalConfig.swfObjectId + "_fallbackContent"; + _swfFallbackCheckInterval = _setInterval(function() { + var el = _document.getElementById(fallbackContentId); + if (_isElementVisible(el)) { + _clearTimeoutsAndPolling(); + _flashState.deactivated = null; + ZeroClipboard.emit({ + type: "error", + name: "swf-not-found" + }); + } + }, pollWait); + } + }; + /** + * Create the HTML bridge element to embed the Flash object into. + * @private + */ + var _createHtmlBridge = function() { + var container = _document.createElement("div"); + container.id = _globalConfig.containerId; + container.className = _globalConfig.containerClass; + container.style.position = "absolute"; + container.style.left = "0px"; + container.style.top = "-9999px"; + container.style.width = "1px"; + container.style.height = "1px"; + container.style.zIndex = "" + _getSafeZIndex(_globalConfig.zIndex); + return container; + }; + /** + * Get the HTML element container that wraps the Flash bridge object/element. + * @private + */ + var _getHtmlBridge = function(flashBridge) { + var htmlBridge = flashBridge && flashBridge.parentNode; + while (htmlBridge && htmlBridge.nodeName === "OBJECT" && htmlBridge.parentNode) { + htmlBridge = htmlBridge.parentNode; + } + return htmlBridge || null; + }; + /** + * Create the SWF object. + * + * @returns The SWF object reference. + * @private + */ + var _embedSwf = function() { + var len, flashBridge = _flashState.bridge, container = _getHtmlBridge(flashBridge); + if (!flashBridge) { + var allowScriptAccess = _determineScriptAccess(_window.location.host, _globalConfig); + var allowNetworking = allowScriptAccess === "never" ? "none" : "all"; + var flashvars = _vars(_extend({ + jsVersion: ZeroClipboard.version + }, _globalConfig)); + var swfUrl = _globalConfig.swfPath + _cacheBust(_globalConfig.swfPath, _globalConfig); + container = _createHtmlBridge(); + var divToBeReplaced = _document.createElement("div"); + container.appendChild(divToBeReplaced); + _document.body.appendChild(container); + var tmpDiv = _document.createElement("div"); + var usingActiveX = _flashState.pluginType === "activex"; + tmpDiv.innerHTML = '" + (usingActiveX ? '' : "") + '' + '' + '' + '' + '' + '
 
' + "
"; + flashBridge = tmpDiv.firstChild; + tmpDiv = null; + _unwrap(flashBridge).ZeroClipboard = ZeroClipboard; + container.replaceChild(flashBridge, divToBeReplaced); + _watchForSwfFallbackContent(); + } + if (!flashBridge) { + flashBridge = _document[_globalConfig.swfObjectId]; + if (flashBridge && (len = flashBridge.length)) { + flashBridge = flashBridge[len - 1]; + } + if (!flashBridge && container) { + flashBridge = container.firstChild; + } + } + _flashState.bridge = flashBridge || null; + return flashBridge; + }; + /** + * Destroy the SWF object. + * @private + */ + var _unembedSwf = function() { + var flashBridge = _flashState.bridge; + if (flashBridge) { + var htmlBridge = _getHtmlBridge(flashBridge); + if (htmlBridge) { + if (_flashState.pluginType === "activex" && "readyState" in flashBridge) { + flashBridge.style.display = "none"; + (function removeSwfFromIE() { + if (flashBridge.readyState === 4) { + for (var prop in flashBridge) { + if (typeof flashBridge[prop] === "function") { + flashBridge[prop] = null; + } + } + if (flashBridge.parentNode) { + flashBridge.parentNode.removeChild(flashBridge); + } + if (htmlBridge.parentNode) { + htmlBridge.parentNode.removeChild(htmlBridge); + } + } else { + _setTimeout(removeSwfFromIE, 10); + } + })(); + } else { + if (flashBridge.parentNode) { + flashBridge.parentNode.removeChild(flashBridge); + } + if (htmlBridge.parentNode) { + htmlBridge.parentNode.removeChild(htmlBridge); + } + } + } + _clearTimeoutsAndPolling(); + _flashState.ready = null; + _flashState.bridge = null; + _flashState.deactivated = null; + _zcSwfVersion = undefined; + } + }; + /** + * Map the data format names of the "clipData" to Flash-friendly names. + * + * @returns A new transformed object. + * @private + */ + var _mapClipDataToFlash = function(clipData) { + var newClipData = {}, formatMap = {}; + if (!(typeof clipData === "object" && clipData)) { + return; + } + for (var dataFormat in clipData) { + if (dataFormat && _hasOwn.call(clipData, dataFormat) && typeof clipData[dataFormat] === "string" && clipData[dataFormat]) { + switch (dataFormat.toLowerCase()) { + case "text/plain": + case "text": + case "air:text": + case "flash:text": + newClipData.text = clipData[dataFormat]; + formatMap.text = dataFormat; + break; + + case "text/html": + case "html": + case "air:html": + case "flash:html": + newClipData.html = clipData[dataFormat]; + formatMap.html = dataFormat; + break; + + case "application/rtf": + case "text/rtf": + case "rtf": + case "richtext": + case "air:rtf": + case "flash:rtf": + newClipData.rtf = clipData[dataFormat]; + formatMap.rtf = dataFormat; + break; + + default: + break; + } + } + } + return { + data: newClipData, + formatMap: formatMap + }; + }; + /** + * Map the data format names from Flash-friendly names back to their original "clipData" names (via a format mapping). + * + * @returns A new transformed object. + * @private + */ + var _mapClipResultsFromFlash = function(clipResults, formatMap) { + if (!(typeof clipResults === "object" && clipResults && typeof formatMap === "object" && formatMap)) { + return clipResults; + } + var newResults = {}; + for (var prop in clipResults) { + if (_hasOwn.call(clipResults, prop)) { + if (prop === "errors") { + newResults[prop] = clipResults[prop] ? clipResults[prop].slice() : []; + for (var i = 0, len = newResults[prop].length; i < len; i++) { + newResults[prop][i].format = formatMap[newResults[prop][i].format]; + } + } else if (prop !== "success" && prop !== "data") { + newResults[prop] = clipResults[prop]; + } else { + newResults[prop] = {}; + var tmpHash = clipResults[prop]; + for (var dataFormat in tmpHash) { + if (dataFormat && _hasOwn.call(tmpHash, dataFormat) && _hasOwn.call(formatMap, dataFormat)) { + newResults[prop][formatMap[dataFormat]] = tmpHash[dataFormat]; + } + } + } + } + } + return newResults; + }; + /** + * Will look at a path, and will create a "?noCache={time}" or "&noCache={time}" + * query param string to return. Does NOT append that string to the original path. + * This is useful because ExternalInterface often breaks when a Flash SWF is cached. + * + * @returns The `noCache` query param with necessary "?"/"&" prefix. + * @private + */ + var _cacheBust = function(path, options) { + var cacheBust = options == null || options && options.cacheBust === true; + if (cacheBust) { + return (path.indexOf("?") === -1 ? "?" : "&") + "noCache=" + _now(); + } else { + return ""; + } + }; + /** + * Creates a query string for the FlashVars param. + * Does NOT include the cache-busting query param. + * + * @returns FlashVars query string + * @private + */ + var _vars = function(options) { + var i, len, domain, domains, str = "", trustedOriginsExpanded = []; + if (options.trustedDomains) { + if (typeof options.trustedDomains === "string") { + domains = [ options.trustedDomains ]; + } else if (typeof options.trustedDomains === "object" && "length" in options.trustedDomains) { + domains = options.trustedDomains; + } + } + if (domains && domains.length) { + for (i = 0, len = domains.length; i < len; i++) { + if (_hasOwn.call(domains, i) && domains[i] && typeof domains[i] === "string") { + domain = _extractDomain(domains[i]); + if (!domain) { + continue; + } + if (domain === "*") { + trustedOriginsExpanded.length = 0; + trustedOriginsExpanded.push(domain); + break; + } + trustedOriginsExpanded.push.apply(trustedOriginsExpanded, [ domain, "//" + domain, _window.location.protocol + "//" + domain ]); + } + } + } + if (trustedOriginsExpanded.length) { + str += "trustedOrigins=" + _encodeURIComponent(trustedOriginsExpanded.join(",")); + } + if (options.forceEnhancedClipboard === true) { + str += (str ? "&" : "") + "forceEnhancedClipboard=true"; + } + if (typeof options.swfObjectId === "string" && options.swfObjectId) { + str += (str ? "&" : "") + "swfObjectId=" + _encodeURIComponent(options.swfObjectId); + } + if (typeof options.jsVersion === "string" && options.jsVersion) { + str += (str ? "&" : "") + "jsVersion=" + _encodeURIComponent(options.jsVersion); + } + return str; + }; + /** + * Extract the domain (e.g. "github.com") from an origin (e.g. "https://github.com") or + * URL (e.g. "https://github.com/zeroclipboard/zeroclipboard/"). + * + * @returns the domain + * @private + */ + var _extractDomain = function(originOrUrl) { + if (originOrUrl == null || originOrUrl === "") { + return null; + } + originOrUrl = originOrUrl.replace(/^\s+|\s+$/g, ""); + if (originOrUrl === "") { + return null; + } + var protocolIndex = originOrUrl.indexOf("//"); + originOrUrl = protocolIndex === -1 ? originOrUrl : originOrUrl.slice(protocolIndex + 2); + var pathIndex = originOrUrl.indexOf("/"); + originOrUrl = pathIndex === -1 ? originOrUrl : protocolIndex === -1 || pathIndex === 0 ? null : originOrUrl.slice(0, pathIndex); + if (originOrUrl && originOrUrl.slice(-4).toLowerCase() === ".swf") { + return null; + } + return originOrUrl || null; + }; + /** + * Set `allowScriptAccess` based on `trustedDomains` and `window.location.host` vs. `swfPath`. + * + * @returns The appropriate script access level. + * @private + */ + var _determineScriptAccess = function() { + var _extractAllDomains = function(origins) { + var i, len, tmp, resultsArray = []; + if (typeof origins === "string") { + origins = [ origins ]; + } + if (!(typeof origins === "object" && origins && typeof origins.length === "number")) { + return resultsArray; + } + for (i = 0, len = origins.length; i < len; i++) { + if (_hasOwn.call(origins, i) && (tmp = _extractDomain(origins[i]))) { + if (tmp === "*") { + resultsArray.length = 0; + resultsArray.push("*"); + break; + } + if (resultsArray.indexOf(tmp) === -1) { + resultsArray.push(tmp); + } + } + } + return resultsArray; + }; + return function(currentDomain, configOptions) { + var swfDomain = _extractDomain(configOptions.swfPath); + if (swfDomain === null) { + swfDomain = currentDomain; + } + var trustedDomains = _extractAllDomains(configOptions.trustedDomains); + var len = trustedDomains.length; + if (len > 0) { + if (len === 1 && trustedDomains[0] === "*") { + return "always"; + } + if (trustedDomains.indexOf(currentDomain) !== -1) { + if (len === 1 && currentDomain === swfDomain) { + return "sameDomain"; + } + return "always"; + } + } + return "never"; + }; + }(); + /** + * Get the currently active/focused DOM element. + * + * @returns the currently active/focused element, or `null` + * @private + */ + var _safeActiveElement = function() { + try { + return _document.activeElement; + } catch (err) { + return null; + } + }; + /** + * Add a class to an element, if it doesn't already have it. + * + * @returns The element, with its new class added. + * @private + */ + var _addClass = function(element, value) { + var c, cl, className, classNames = []; + if (typeof value === "string" && value) { + classNames = value.split(/\s+/); + } + if (element && element.nodeType === 1 && classNames.length > 0) { + if (element.classList) { + for (c = 0, cl = classNames.length; c < cl; c++) { + element.classList.add(classNames[c]); + } + } else if (element.hasOwnProperty("className")) { + className = " " + element.className + " "; + for (c = 0, cl = classNames.length; c < cl; c++) { + if (className.indexOf(" " + classNames[c] + " ") === -1) { + className += classNames[c] + " "; + } + } + element.className = className.replace(/^\s+|\s+$/g, ""); + } + } + return element; + }; + /** + * Remove a class from an element, if it has it. + * + * @returns The element, with its class removed. + * @private + */ + var _removeClass = function(element, value) { + var c, cl, className, classNames = []; + if (typeof value === "string" && value) { + classNames = value.split(/\s+/); + } + if (element && element.nodeType === 1 && classNames.length > 0) { + if (element.classList && element.classList.length > 0) { + for (c = 0, cl = classNames.length; c < cl; c++) { + element.classList.remove(classNames[c]); + } + } else if (element.className) { + className = (" " + element.className + " ").replace(/[\r\n\t]/g, " "); + for (c = 0, cl = classNames.length; c < cl; c++) { + className = className.replace(" " + classNames[c] + " ", " "); + } + element.className = className.replace(/^\s+|\s+$/g, ""); + } + } + return element; + }; + /** + * Attempt to interpret the element's CSS styling. If `prop` is `"cursor"`, + * then we assume that it should be a hand ("pointer") cursor if the element + * is an anchor element ("a" tag). + * + * @returns The computed style property. + * @private + */ + var _getStyle = function(el, prop) { + var value = _getComputedStyle(el, null).getPropertyValue(prop); + if (prop === "cursor") { + if (!value || value === "auto") { + if (el.nodeName === "A") { + return "pointer"; + } + } + } + return value; + }; + /** + * Get the absolutely positioned coordinates of a DOM element. + * + * @returns Object containing the element's position, width, and height. + * @private + */ + var _getElementPosition = function(el) { + var pos = { + left: 0, + top: 0, + width: 0, + height: 0 + }; + if (el.getBoundingClientRect) { + var elRect = el.getBoundingClientRect(); + var pageXOffset = _window.pageXOffset; + var pageYOffset = _window.pageYOffset; + var leftBorderWidth = _document.documentElement.clientLeft || 0; + var topBorderWidth = _document.documentElement.clientTop || 0; + var leftBodyOffset = 0; + var topBodyOffset = 0; + if (_getStyle(_document.body, "position") === "relative") { + var bodyRect = _document.body.getBoundingClientRect(); + var htmlRect = _document.documentElement.getBoundingClientRect(); + leftBodyOffset = bodyRect.left - htmlRect.left || 0; + topBodyOffset = bodyRect.top - htmlRect.top || 0; + } + pos.left = elRect.left + pageXOffset - leftBorderWidth - leftBodyOffset; + pos.top = elRect.top + pageYOffset - topBorderWidth - topBodyOffset; + pos.width = "width" in elRect ? elRect.width : elRect.right - elRect.left; + pos.height = "height" in elRect ? elRect.height : elRect.bottom - elRect.top; + } + return pos; + }; + /** + * Determine is an element is visible somewhere within the document (page). + * + * @returns Boolean + * @private + */ + var _isElementVisible = function(el) { + if (!el) { + return false; + } + var styles = _getComputedStyle(el, null); + var hasCssHeight = _parseFloat(styles.height) > 0; + var hasCssWidth = _parseFloat(styles.width) > 0; + var hasCssTop = _parseFloat(styles.top) >= 0; + var hasCssLeft = _parseFloat(styles.left) >= 0; + var cssKnows = hasCssHeight && hasCssWidth && hasCssTop && hasCssLeft; + var rect = cssKnows ? null : _getElementPosition(el); + var isVisible = styles.display !== "none" && styles.visibility !== "collapse" && (cssKnows || !!rect && (hasCssHeight || rect.height > 0) && (hasCssWidth || rect.width > 0) && (hasCssTop || rect.top >= 0) && (hasCssLeft || rect.left >= 0)); + return isVisible; + }; + /** + * Clear all existing timeouts and interval polling delegates. + * + * @returns `undefined` + * @private + */ + var _clearTimeoutsAndPolling = function() { + _clearTimeout(_flashCheckTimeout); + _flashCheckTimeout = 0; + _clearInterval(_swfFallbackCheckInterval); + _swfFallbackCheckInterval = 0; + }; + /** + * Reposition the Flash object to cover the currently activated element. + * + * @returns `undefined` + * @private + */ + var _reposition = function() { + var htmlBridge; + if (_currentElement && (htmlBridge = _getHtmlBridge(_flashState.bridge))) { + var pos = _getElementPosition(_currentElement); + _extend(htmlBridge.style, { + width: pos.width + "px", + height: pos.height + "px", + top: pos.top + "px", + left: pos.left + "px", + zIndex: "" + _getSafeZIndex(_globalConfig.zIndex) + }); + } + }; + /** + * Sends a signal to the Flash object to display the hand cursor if `true`. + * + * @returns `undefined` + * @private + */ + var _setHandCursor = function(enabled) { + if (_flashState.ready === true) { + if (_flashState.bridge && typeof _flashState.bridge.setHandCursor === "function") { + _flashState.bridge.setHandCursor(enabled); + } else { + _flashState.ready = false; + } + } + }; + /** + * Get a safe value for `zIndex` + * + * @returns an integer, or "auto" + * @private + */ + var _getSafeZIndex = function(val) { + if (/^(?:auto|inherit)$/.test(val)) { + return val; + } + var zIndex; + if (typeof val === "number" && !_isNaN(val)) { + zIndex = val; + } else if (typeof val === "string") { + zIndex = _getSafeZIndex(_parseInt(val, 10)); + } + return typeof zIndex === "number" ? zIndex : "auto"; + }; + /** + * Attempt to detect if ZeroClipboard is executing inside of a sandboxed iframe. + * If it is, Flash Player cannot be used, so ZeroClipboard is dead in the water. + * + * @see {@link http://lists.w3.org/Archives/Public/public-whatwg-archive/2014Dec/0002.html} + * @see {@link https://github.com/zeroclipboard/zeroclipboard/issues/511} + * @see {@link http://zeroclipboard.org/test-iframes.html} + * + * @returns `true` (is sandboxed), `false` (is not sandboxed), or `null` (uncertain) + * @private + */ + var _detectSandbox = function(doNotReassessFlashSupport) { + var effectiveScriptOrigin, frame, frameError, previousState = _flashState.sandboxed, isSandboxed = null; + doNotReassessFlashSupport = doNotReassessFlashSupport === true; + if (_pageIsFramed === false) { + isSandboxed = false; + } else { + try { + frame = window.frameElement || null; + } catch (e) { + frameError = { + name: e.name, + message: e.message + }; + } + if (frame && frame.nodeType === 1 && frame.nodeName === "IFRAME") { + try { + isSandboxed = frame.hasAttribute("sandbox"); + } catch (e) { + isSandboxed = null; + } + } else { + try { + effectiveScriptOrigin = document.domain || null; + } catch (e) { + effectiveScriptOrigin = null; + } + if (effectiveScriptOrigin === null || frameError && frameError.name === "SecurityError" && /(^|[\s\(\[@])sandbox(es|ed|ing|[\s\.,!\)\]@]|$)/.test(frameError.message.toLowerCase())) { + isSandboxed = true; + } + } + } + _flashState.sandboxed = isSandboxed; + if (previousState !== isSandboxed && !doNotReassessFlashSupport) { + _detectFlashSupport(_ActiveXObject); + } + return isSandboxed; + }; + /** + * Detect the Flash Player status, version, and plugin type. + * + * @see {@link https://code.google.com/p/doctype-mirror/wiki/ArticleDetectFlash#The_code} + * @see {@link http://stackoverflow.com/questions/12866060/detecting-pepper-ppapi-flash-with-javascript} + * + * @returns `undefined` + * @private + */ + var _detectFlashSupport = function(ActiveXObject) { + var plugin, ax, mimeType, hasFlash = false, isActiveX = false, isPPAPI = false, flashVersion = ""; + /** + * Derived from Apple's suggested sniffer. + * @param {String} desc e.g. "Shockwave Flash 7.0 r61" + * @returns {String} "7.0.61" + * @private + */ + function parseFlashVersion(desc) { + var matches = desc.match(/[\d]+/g); + matches.length = 3; + return matches.join("."); + } + function isPepperFlash(flashPlayerFileName) { + return !!flashPlayerFileName && (flashPlayerFileName = flashPlayerFileName.toLowerCase()) && (/^(pepflashplayer\.dll|libpepflashplayer\.so|pepperflashplayer\.plugin)$/.test(flashPlayerFileName) || flashPlayerFileName.slice(-13) === "chrome.plugin"); + } + function inspectPlugin(plugin) { + if (plugin) { + hasFlash = true; + if (plugin.version) { + flashVersion = parseFlashVersion(plugin.version); + } + if (!flashVersion && plugin.description) { + flashVersion = parseFlashVersion(plugin.description); + } + if (plugin.filename) { + isPPAPI = isPepperFlash(plugin.filename); + } + } + } + if (_navigator.plugins && _navigator.plugins.length) { + plugin = _navigator.plugins["Shockwave Flash"]; + inspectPlugin(plugin); + if (_navigator.plugins["Shockwave Flash 2.0"]) { + hasFlash = true; + flashVersion = "2.0.0.11"; + } + } else if (_navigator.mimeTypes && _navigator.mimeTypes.length) { + mimeType = _navigator.mimeTypes["application/x-shockwave-flash"]; + plugin = mimeType && mimeType.enabledPlugin; + inspectPlugin(plugin); + } else if (typeof ActiveXObject !== "undefined") { + isActiveX = true; + try { + ax = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); + hasFlash = true; + flashVersion = parseFlashVersion(ax.GetVariable("$version")); + } catch (e1) { + try { + ax = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); + hasFlash = true; + flashVersion = "6.0.21"; + } catch (e2) { + try { + ax = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); + hasFlash = true; + flashVersion = parseFlashVersion(ax.GetVariable("$version")); + } catch (e3) { + isActiveX = false; + } + } + } + } + _flashState.disabled = hasFlash !== true; + _flashState.outdated = flashVersion && _parseFloat(flashVersion) < _parseFloat(_minimumFlashVersion); + _flashState.version = flashVersion || "0.0.0"; + _flashState.pluginType = isPPAPI ? "pepper" : isActiveX ? "activex" : hasFlash ? "netscape" : "unknown"; + }; + /** + * Invoke the Flash detection algorithms immediately upon inclusion so we're not waiting later. + */ + _detectFlashSupport(_ActiveXObject); + /** + * Always assess the `sandboxed` state of the page at important Flash-related moments. + */ + _detectSandbox(true); + /** + * A shell constructor for `ZeroClipboard` client instances. + * + * @constructor + */ + var ZeroClipboard = function() { + if (!(this instanceof ZeroClipboard)) { + return new ZeroClipboard(); + } + if (typeof ZeroClipboard._createClient === "function") { + ZeroClipboard._createClient.apply(this, _args(arguments)); + } + }; + /** + * The ZeroClipboard library's version number. + * + * @static + * @readonly + * @property {string} + */ + _defineProperty(ZeroClipboard, "version", { + value: "2.2.0", + writable: false, + configurable: true, + enumerable: true + }); + /** + * Update or get a copy of the ZeroClipboard global configuration. + * Returns a copy of the current/updated configuration. + * + * @returns Object + * @static + */ + ZeroClipboard.config = function() { + return _config.apply(this, _args(arguments)); + }; + /** + * Diagnostic method that describes the state of the browser, Flash Player, and ZeroClipboard. + * + * @returns Object + * @static + */ + ZeroClipboard.state = function() { + return _state.apply(this, _args(arguments)); + }; + /** + * Check if Flash is unusable for any reason: disabled, outdated, deactivated, etc. + * + * @returns Boolean + * @static + */ + ZeroClipboard.isFlashUnusable = function() { + return _isFlashUnusable.apply(this, _args(arguments)); + }; + /** + * Register an event listener. + * + * @returns `ZeroClipboard` + * @static + */ + ZeroClipboard.on = function() { + return _on.apply(this, _args(arguments)); + }; + /** + * Unregister an event listener. + * If no `listener` function/object is provided, it will unregister all listeners for the provided `eventType`. + * If no `eventType` is provided, it will unregister all listeners for every event type. + * + * @returns `ZeroClipboard` + * @static + */ + ZeroClipboard.off = function() { + return _off.apply(this, _args(arguments)); + }; + /** + * Retrieve event listeners for an `eventType`. + * If no `eventType` is provided, it will retrieve all listeners for every event type. + * + * @returns array of listeners for the `eventType`; if no `eventType`, then a map/hash object of listeners for all event types; or `null` + */ + ZeroClipboard.handlers = function() { + return _listeners.apply(this, _args(arguments)); + }; + /** + * Event emission receiver from the Flash object, forwarding to any registered JavaScript event listeners. + * + * @returns For the "copy" event, returns the Flash-friendly "clipData" object; otherwise `undefined`. + * @static + */ + ZeroClipboard.emit = function() { + return _emit.apply(this, _args(arguments)); + }; + /** + * Create and embed the Flash object. + * + * @returns The Flash object + * @static + */ + ZeroClipboard.create = function() { + return _create.apply(this, _args(arguments)); + }; + /** + * Self-destruct and clean up everything, including the embedded Flash object. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.destroy = function() { + return _destroy.apply(this, _args(arguments)); + }; + /** + * Set the pending data for clipboard injection. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.setData = function() { + return _setData.apply(this, _args(arguments)); + }; + /** + * Clear the pending data for clipboard injection. + * If no `format` is provided, all pending data formats will be cleared. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.clearData = function() { + return _clearData.apply(this, _args(arguments)); + }; + /** + * Get a copy of the pending data for clipboard injection. + * If no `format` is provided, a copy of ALL pending data formats will be returned. + * + * @returns `String` or `Object` + * @static + */ + ZeroClipboard.getData = function() { + return _getData.apply(this, _args(arguments)); + }; + /** + * Sets the current HTML object that the Flash object should overlay. This will put the global + * Flash object on top of the current element; depending on the setup, this may also set the + * pending clipboard text data as well as the Flash object's wrapping element's title attribute + * based on the underlying HTML element and ZeroClipboard configuration. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.focus = ZeroClipboard.activate = function() { + return _focus.apply(this, _args(arguments)); + }; + /** + * Un-overlays the Flash object. This will put the global Flash object off-screen; depending on + * the setup, this may also unset the Flash object's wrapping element's title attribute based on + * the underlying HTML element and ZeroClipboard configuration. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.blur = ZeroClipboard.deactivate = function() { + return _blur.apply(this, _args(arguments)); + }; + /** + * Returns the currently focused/"activated" HTML element that the Flash object is wrapping. + * + * @returns `HTMLElement` or `null` + * @static + */ + ZeroClipboard.activeElement = function() { + return _activeElement.apply(this, _args(arguments)); + }; + if (typeof define === "function" && define.amd) { + define(function() { + return ZeroClipboard; + }); + } else if (typeof module === "object" && module && typeof module.exports === "object" && module.exports) { + module.exports = ZeroClipboard; + } else { + window.ZeroClipboard = ZeroClipboard; + } +})(function() { + return this || window; +}()); \ No newline at end of file diff --git a/resources/zeroclipboard/ZeroClipboard.Core.min.js b/resources/zeroclipboard/ZeroClipboard.Core.min.js new file mode 100644 index 0000000000..01efd47115 --- /dev/null +++ b/resources/zeroclipboard/ZeroClipboard.Core.min.js @@ -0,0 +1,10 @@ +/*! + * ZeroClipboard + * The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface. + * Copyright (c) 2009-2014 Jon Rohan, James M. Greene + * Licensed MIT + * http://zeroclipboard.org/ + * v2.2.0 + */ +!function(a,b){"use strict";var c,d,e,f=a,g=f.document,h=f.navigator,i=f.setTimeout,j=f.clearTimeout,k=f.setInterval,l=f.clearInterval,m=f.getComputedStyle,n=f.encodeURIComponent,o=f.ActiveXObject,p=f.Error,q=f.Number.parseInt||f.parseInt,r=f.Number.parseFloat||f.parseFloat,s=f.Number.isNaN||f.isNaN,t=f.Date.now,u=f.Object.keys,v=f.Object.defineProperty,w=f.Object.prototype.hasOwnProperty,x=f.Array.prototype.slice,y=function(){var a=function(a){return a};if("function"==typeof f.wrap&&"function"==typeof f.unwrap)try{var b=g.createElement("div"),c=f.unwrap(b);1===b.nodeType&&c&&1===c.nodeType&&(a=f.unwrap)}catch(d){}return a}(),z=function(a){return x.call(a,0)},A=function(){var a,c,d,e,f,g,h=z(arguments),i=h[0]||{};for(a=1,c=h.length;c>a;a++)if(null!=(d=h[a]))for(e in d)w.call(d,e)&&(f=i[e],g=d[e],i!==g&&g!==b&&(i[e]=g));return i},B=function(a){var b,c,d,e;if("object"!=typeof a||null==a||"number"==typeof a.nodeType)b=a;else if("number"==typeof a.length)for(b=[],c=0,d=a.length;d>c;c++)w.call(a,c)&&(b[c]=B(a[c]));else{b={};for(e in a)w.call(a,e)&&(b[e]=B(a[e]))}return b},C=function(a,b){for(var c={},d=0,e=b.length;e>d;d++)b[d]in a&&(c[b[d]]=a[b[d]]);return c},D=function(a,b){var c={};for(var d in a)-1===b.indexOf(d)&&(c[d]=a[d]);return c},E=function(a){if(a)for(var b in a)w.call(a,b)&&delete a[b];return a},F=function(a,b){if(a&&1===a.nodeType&&a.ownerDocument&&b&&(1===b.nodeType&&b.ownerDocument&&b.ownerDocument===a.ownerDocument||9===b.nodeType&&!b.ownerDocument&&b===a.ownerDocument))do{if(a===b)return!0;a=a.parentNode}while(a);return!1},G=function(a){var b;return"string"==typeof a&&a&&(b=a.split("#")[0].split("?")[0],b=a.slice(0,a.lastIndexOf("/")+1)),b},H=function(a){var b,c;return"string"==typeof a&&a&&(c=a.match(/^(?:|[^:@]*@|.+\)@(?=http[s]?|file)|.+?\s+(?: at |@)(?:[^:\(]+ )*[\(]?)((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/),c&&c[1]?b=c[1]:(c=a.match(/\)@((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/),c&&c[1]&&(b=c[1]))),b},I=function(){var a,b;try{throw new p}catch(c){b=c}return b&&(a=b.sourceURL||b.fileName||H(b.stack)),a},J=function(){var a,c,d;if(g.currentScript&&(a=g.currentScript.src))return a;if(c=g.getElementsByTagName("script"),1===c.length)return c[0].src||b;if("readyState"in c[0])for(d=c.length;d--;)if("interactive"===c[d].readyState&&(a=c[d].src))return a;return"loading"===g.readyState&&(a=c[c.length-1].src)?a:(a=I())?a:b},K=function(){var a,c,d,e=g.getElementsByTagName("script");for(a=e.length;a--;){if(!(d=e[a].src)){c=null;break}if(d=G(d),null==c)c=d;else if(c!==d){c=null;break}}return c||b},L=function(){var a=G(J())||K()||"";return a+"ZeroClipboard.swf"},M=function(){return null==a.opener&&(!!a.top&&a!=a.top||!!a.parent&&a!=a.parent)}(),N={bridge:null,version:"0.0.0",pluginType:"unknown",disabled:null,outdated:null,sandboxed:null,unavailable:null,degraded:null,deactivated:null,overdue:null,ready:null},O="11.0.0",P={},Q={},R=null,S=0,T=0,U={ready:"Flash communication is established",error:{"flash-disabled":"Flash is disabled or not installed. May also be attempting to run Flash in a sandboxed iframe, which is impossible.","flash-outdated":"Flash is too outdated to support ZeroClipboard","flash-sandboxed":"Attempting to run Flash in a sandboxed iframe, which is impossible","flash-unavailable":"Flash is unable to communicate bidirectionally with JavaScript","flash-degraded":"Flash is unable to preserve data fidelity when communicating with JavaScript","flash-deactivated":"Flash is too outdated for your browser and/or is configured as click-to-activate.\nThis may also mean that the ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity.\nMay also be attempting to run Flash in a sandboxed iframe, which is impossible.","flash-overdue":"Flash communication was established but NOT within the acceptable time limit","version-mismatch":"ZeroClipboard JS version number does not match ZeroClipboard SWF version number","clipboard-error":"At least one error was thrown while ZeroClipboard was attempting to inject your data into the clipboard","config-mismatch":"ZeroClipboard configuration does not match Flash's reality","swf-not-found":"The ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity"}},V=["flash-unavailable","flash-degraded","flash-overdue","version-mismatch","config-mismatch","clipboard-error"],W=["flash-disabled","flash-outdated","flash-sandboxed","flash-unavailable","flash-degraded","flash-deactivated","flash-overdue"],X=new RegExp("^flash-("+W.map(function(a){return a.replace(/^flash-/,"")}).join("|")+")$"),Y=new RegExp("^flash-("+W.slice(1).map(function(a){return a.replace(/^flash-/,"")}).join("|")+")$"),Z={swfPath:L(),trustedDomains:a.location.host?[a.location.host]:[],cacheBust:!0,forceEnhancedClipboard:!1,flashLoadTimeout:3e4,autoActivate:!0,bubbleEvents:!0,containerId:"global-zeroclipboard-html-bridge",containerClass:"global-zeroclipboard-container",swfObjectId:"global-zeroclipboard-flash-bridge",hoverClass:"zeroclipboard-is-hover",activeClass:"zeroclipboard-is-active",forceHandCursor:!1,title:null,zIndex:999999999},$=function(a){if("object"==typeof a&&null!==a)for(var b in a)if(w.call(a,b))if(/^(?:forceHandCursor|title|zIndex|bubbleEvents)$/.test(b))Z[b]=a[b];else if(null==N.bridge)if("containerId"===b||"swfObjectId"===b){if(!nb(a[b]))throw new Error("The specified `"+b+"` value is not valid as an HTML4 Element ID");Z[b]=a[b]}else Z[b]=a[b];{if("string"!=typeof a||!a)return B(Z);if(w.call(Z,a))return Z[a]}},_=function(){return Tb(),{browser:C(h,["userAgent","platform","appName"]),flash:D(N,["bridge"]),zeroclipboard:{version:Vb.version,config:Vb.config()}}},ab=function(){return!!(N.disabled||N.outdated||N.sandboxed||N.unavailable||N.degraded||N.deactivated)},bb=function(a,d){var e,f,g,h={};if("string"==typeof a&&a)g=a.toLowerCase().split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof d)for(e in a)w.call(a,e)&&"string"==typeof e&&e&&"function"==typeof a[e]&&Vb.on(e,a[e]);if(g&&g.length){for(e=0,f=g.length;f>e;e++)a=g[e].replace(/^on/,""),h[a]=!0,P[a]||(P[a]=[]),P[a].push(d);if(h.ready&&N.ready&&Vb.emit({type:"ready"}),h.error){for(e=0,f=W.length;f>e;e++)if(N[W[e].replace(/^flash-/,"")]===!0){Vb.emit({type:"error",name:W[e]});break}c!==b&&Vb.version!==c&&Vb.emit({type:"error",name:"version-mismatch",jsVersion:Vb.version,swfVersion:c})}}return Vb},cb=function(a,b){var c,d,e,f,g;if(0===arguments.length)f=u(P);else if("string"==typeof a&&a)f=a.split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof b)for(c in a)w.call(a,c)&&"string"==typeof c&&c&&"function"==typeof a[c]&&Vb.off(c,a[c]);if(f&&f.length)for(c=0,d=f.length;d>c;c++)if(a=f[c].toLowerCase().replace(/^on/,""),g=P[a],g&&g.length)if(b)for(e=g.indexOf(b);-1!==e;)g.splice(e,1),e=g.indexOf(b,e);else g.length=0;return Vb},db=function(a){var b;return b="string"==typeof a&&a?B(P[a])||null:B(P)},eb=function(a){var b,c,d;return a=ob(a),a&&!vb(a)?"ready"===a.type&&N.overdue===!0?Vb.emit({type:"error",name:"flash-overdue"}):(b=A({},a),tb.call(this,b),"copy"===a.type&&(d=Db(Q),c=d.data,R=d.formatMap),c):void 0},fb=function(){var a=N.sandboxed;if(Tb(),"boolean"!=typeof N.ready&&(N.ready=!1),N.sandboxed!==a&&N.sandboxed===!0)N.ready=!1,Vb.emit({type:"error",name:"flash-sandboxed"});else if(!Vb.isFlashUnusable()&&null===N.bridge){var b=Z.flashLoadTimeout;"number"==typeof b&&b>=0&&(S=i(function(){"boolean"!=typeof N.deactivated&&(N.deactivated=!0),N.deactivated===!0&&Vb.emit({type:"error",name:"flash-deactivated"})},b)),N.overdue=!1,Bb()}},gb=function(){Vb.clearData(),Vb.blur(),Vb.emit("destroy"),Cb(),Vb.off()},hb=function(a,b){var c;if("object"==typeof a&&a&&"undefined"==typeof b)c=a,Vb.clearData();else{if("string"!=typeof a||!a)return;c={},c[a]=b}for(var d in c)"string"==typeof d&&d&&w.call(c,d)&&"string"==typeof c[d]&&c[d]&&(Q[d]=c[d])},ib=function(a){"undefined"==typeof a?(E(Q),R=null):"string"==typeof a&&w.call(Q,a)&&delete Q[a]},jb=function(a){return"undefined"==typeof a?B(Q):"string"==typeof a&&w.call(Q,a)?Q[a]:void 0},kb=function(a){if(a&&1===a.nodeType){d&&(Lb(d,Z.activeClass),d!==a&&Lb(d,Z.hoverClass)),d=a,Kb(a,Z.hoverClass);var b=a.getAttribute("title")||Z.title;if("string"==typeof b&&b){var c=Ab(N.bridge);c&&c.setAttribute("title",b)}var e=Z.forceHandCursor===!0||"pointer"===Mb(a,"cursor");Rb(e),Qb()}},lb=function(){var a=Ab(N.bridge);a&&(a.removeAttribute("title"),a.style.left="0px",a.style.top="-9999px",a.style.width="1px",a.style.height="1px"),d&&(Lb(d,Z.hoverClass),Lb(d,Z.activeClass),d=null)},mb=function(){return d||null},nb=function(a){return"string"==typeof a&&a&&/^[A-Za-z][A-Za-z0-9_:\-\.]*$/.test(a)},ob=function(a){var b;if("string"==typeof a&&a?(b=a,a={}):"object"==typeof a&&a&&"string"==typeof a.type&&a.type&&(b=a.type),b){b=b.toLowerCase(),!a.target&&(/^(copy|aftercopy|_click)$/.test(b)||"error"===b&&"clipboard-error"===a.name)&&(a.target=e),A(a,{type:b,target:a.target||d||null,relatedTarget:a.relatedTarget||null,currentTarget:N&&N.bridge||null,timeStamp:a.timeStamp||t()||null});var c=U[a.type];return"error"===a.type&&a.name&&c&&(c=c[a.name]),c&&(a.message=c),"ready"===a.type&&A(a,{target:null,version:N.version}),"error"===a.type&&(X.test(a.name)&&A(a,{target:null,minimumVersion:O}),Y.test(a.name)&&A(a,{version:N.version})),"copy"===a.type&&(a.clipboardData={setData:Vb.setData,clearData:Vb.clearData}),"aftercopy"===a.type&&(a=Eb(a,R)),a.target&&!a.relatedTarget&&(a.relatedTarget=pb(a.target)),qb(a)}},pb=function(a){var b=a&&a.getAttribute&&a.getAttribute("data-clipboard-target");return b?g.getElementById(b):null},qb=function(a){if(a&&/^_(?:click|mouse(?:over|out|down|up|move))$/.test(a.type)){var c=a.target,d="_mouseover"===a.type&&a.relatedTarget?a.relatedTarget:b,e="_mouseout"===a.type&&a.relatedTarget?a.relatedTarget:b,h=Nb(c),i=f.screenLeft||f.screenX||0,j=f.screenTop||f.screenY||0,k=g.body.scrollLeft+g.documentElement.scrollLeft,l=g.body.scrollTop+g.documentElement.scrollTop,m=h.left+("number"==typeof a._stageX?a._stageX:0),n=h.top+("number"==typeof a._stageY?a._stageY:0),o=m-k,p=n-l,q=i+o,r=j+p,s="number"==typeof a.movementX?a.movementX:0,t="number"==typeof a.movementY?a.movementY:0;delete a._stageX,delete a._stageY,A(a,{srcElement:c,fromElement:d,toElement:e,screenX:q,screenY:r,pageX:m,pageY:n,clientX:o,clientY:p,x:o,y:p,movementX:s,movementY:t,offsetX:0,offsetY:0,layerX:0,layerY:0})}return a},rb=function(a){var b=a&&"string"==typeof a.type&&a.type||"";return!/^(?:(?:before)?copy|destroy)$/.test(b)},sb=function(a,b,c,d){d?i(function(){a.apply(b,c)},0):a.apply(b,c)},tb=function(a){if("object"==typeof a&&a&&a.type){var b=rb(a),c=P["*"]||[],d=P[a.type]||[],e=c.concat(d);if(e&&e.length){var g,h,i,j,k,l=this;for(g=0,h=e.length;h>g;g++)i=e[g],j=l,"string"==typeof i&&"function"==typeof f[i]&&(i=f[i]),"object"==typeof i&&i&&"function"==typeof i.handleEvent&&(j=i,i=i.handleEvent),"function"==typeof i&&(k=A({},a),sb(i,j,[k],b))}return this}},ub=function(a){var b=null;return(M===!1||a&&"error"===a.type&&a.name&&-1!==V.indexOf(a.name))&&(b=!1),b},vb=function(a){var b=a.target||d||null,f="swf"===a._source;switch(delete a._source,a.type){case"error":var g="flash-sandboxed"===a.name||ub(a);"boolean"==typeof g&&(N.sandboxed=g),-1!==W.indexOf(a.name)?A(N,{disabled:"flash-disabled"===a.name,outdated:"flash-outdated"===a.name,unavailable:"flash-unavailable"===a.name,degraded:"flash-degraded"===a.name,deactivated:"flash-deactivated"===a.name,overdue:"flash-overdue"===a.name,ready:!1}):"version-mismatch"===a.name&&(c=a.swfVersion,A(N,{disabled:!1,outdated:!1,unavailable:!1,degraded:!1,deactivated:!1,overdue:!1,ready:!1})),Pb();break;case"ready":c=a.swfVersion;var h=N.deactivated===!0;A(N,{disabled:!1,outdated:!1,sandboxed:!1,unavailable:!1,degraded:!1,deactivated:!1,overdue:h,ready:!h}),Pb();break;case"beforecopy":e=b;break;case"copy":var i,j,k=a.relatedTarget;!Q["text/html"]&&!Q["text/plain"]&&k&&(j=k.value||k.outerHTML||k.innerHTML)&&(i=k.value||k.textContent||k.innerText)?(a.clipboardData.clearData(),a.clipboardData.setData("text/plain",i),j!==i&&a.clipboardData.setData("text/html",j)):!Q["text/plain"]&&a.target&&(i=a.target.getAttribute("data-clipboard-text"))&&(a.clipboardData.clearData(),a.clipboardData.setData("text/plain",i));break;case"aftercopy":wb(a),Vb.clearData(),b&&b!==Jb()&&b.focus&&b.focus();break;case"_mouseover":Vb.focus(b),Z.bubbleEvents===!0&&f&&(b&&b!==a.relatedTarget&&!F(a.relatedTarget,b)&&xb(A({},a,{type:"mouseenter",bubbles:!1,cancelable:!1})),xb(A({},a,{type:"mouseover"})));break;case"_mouseout":Vb.blur(),Z.bubbleEvents===!0&&f&&(b&&b!==a.relatedTarget&&!F(a.relatedTarget,b)&&xb(A({},a,{type:"mouseleave",bubbles:!1,cancelable:!1})),xb(A({},a,{type:"mouseout"})));break;case"_mousedown":Kb(b,Z.activeClass),Z.bubbleEvents===!0&&f&&xb(A({},a,{type:a.type.slice(1)}));break;case"_mouseup":Lb(b,Z.activeClass),Z.bubbleEvents===!0&&f&&xb(A({},a,{type:a.type.slice(1)}));break;case"_click":e=null,Z.bubbleEvents===!0&&f&&xb(A({},a,{type:a.type.slice(1)}));break;case"_mousemove":Z.bubbleEvents===!0&&f&&xb(A({},a,{type:a.type.slice(1)}))}return/^_(?:click|mouse(?:over|out|down|up|move))$/.test(a.type)?!0:void 0},wb=function(a){if(a.errors&&a.errors.length>0){var b=B(a);A(b,{type:"error",name:"clipboard-error"}),delete b.success,i(function(){Vb.emit(b)},0)}},xb=function(a){if(a&&"string"==typeof a.type&&a){var b,c=a.target||null,d=c&&c.ownerDocument||g,e={view:d.defaultView||f,canBubble:!0,cancelable:!0,detail:"click"===a.type?1:0,button:"number"==typeof a.which?a.which-1:"number"==typeof a.button?a.button:d.createEvent?0:1},h=A(e,a);c&&d.createEvent&&c.dispatchEvent&&(h=[h.type,h.canBubble,h.cancelable,h.view,h.detail,h.screenX,h.screenY,h.clientX,h.clientY,h.ctrlKey,h.altKey,h.shiftKey,h.metaKey,h.button,h.relatedTarget],b=d.createEvent("MouseEvents"),b.initMouseEvent&&(b.initMouseEvent.apply(b,h),b._source="js",c.dispatchEvent(b)))}},yb=function(){var a=Z.flashLoadTimeout;if("number"==typeof a&&a>=0){var b=Math.min(1e3,a/10),c=Z.swfObjectId+"_fallbackContent";T=k(function(){var a=g.getElementById(c);Ob(a)&&(Pb(),N.deactivated=null,Vb.emit({type:"error",name:"swf-not-found"}))},b)}},zb=function(){var a=g.createElement("div");return a.id=Z.containerId,a.className=Z.containerClass,a.style.position="absolute",a.style.left="0px",a.style.top="-9999px",a.style.width="1px",a.style.height="1px",a.style.zIndex=""+Sb(Z.zIndex),a},Ab=function(a){for(var b=a&&a.parentNode;b&&"OBJECT"===b.nodeName&&b.parentNode;)b=b.parentNode;return b||null},Bb=function(){var a,b=N.bridge,c=Ab(b);if(!b){var d=Ib(f.location.host,Z),e="never"===d?"none":"all",h=Gb(A({jsVersion:Vb.version},Z)),i=Z.swfPath+Fb(Z.swfPath,Z);c=zb();var j=g.createElement("div");c.appendChild(j),g.body.appendChild(c);var k=g.createElement("div"),l="activex"===N.pluginType;k.innerHTML='"+(l?'':"")+'
 
',b=k.firstChild,k=null,y(b).ZeroClipboard=Vb,c.replaceChild(b,j),yb()}return b||(b=g[Z.swfObjectId],b&&(a=b.length)&&(b=b[a-1]),!b&&c&&(b=c.firstChild)),N.bridge=b||null,b},Cb=function(){var a=N.bridge;if(a){var d=Ab(a);d&&("activex"===N.pluginType&&"readyState"in a?(a.style.display="none",function e(){if(4===a.readyState){for(var b in a)"function"==typeof a[b]&&(a[b]=null);a.parentNode&&a.parentNode.removeChild(a),d.parentNode&&d.parentNode.removeChild(d)}else i(e,10)}()):(a.parentNode&&a.parentNode.removeChild(a),d.parentNode&&d.parentNode.removeChild(d))),Pb(),N.ready=null,N.bridge=null,N.deactivated=null,c=b}},Db=function(a){var b={},c={};if("object"==typeof a&&a){for(var d in a)if(d&&w.call(a,d)&&"string"==typeof a[d]&&a[d])switch(d.toLowerCase()){case"text/plain":case"text":case"air:text":case"flash:text":b.text=a[d],c.text=d;break;case"text/html":case"html":case"air:html":case"flash:html":b.html=a[d],c.html=d;break;case"application/rtf":case"text/rtf":case"rtf":case"richtext":case"air:rtf":case"flash:rtf":b.rtf=a[d],c.rtf=d}return{data:b,formatMap:c}}},Eb=function(a,b){if("object"!=typeof a||!a||"object"!=typeof b||!b)return a;var c={};for(var d in a)if(w.call(a,d))if("errors"===d){c[d]=a[d]?a[d].slice():[];for(var e=0,f=c[d].length;f>e;e++)c[d][e].format=b[c[d][e].format]}else if("success"!==d&&"data"!==d)c[d]=a[d];else{c[d]={};var g=a[d];for(var h in g)h&&w.call(g,h)&&w.call(b,h)&&(c[d][b[h]]=g[h])}return c},Fb=function(a,b){var c=null==b||b&&b.cacheBust===!0;return c?(-1===a.indexOf("?")?"?":"&")+"noCache="+t():""},Gb=function(a){var b,c,d,e,g="",h=[];if(a.trustedDomains&&("string"==typeof a.trustedDomains?e=[a.trustedDomains]:"object"==typeof a.trustedDomains&&"length"in a.trustedDomains&&(e=a.trustedDomains)),e&&e.length)for(b=0,c=e.length;c>b;b++)if(w.call(e,b)&&e[b]&&"string"==typeof e[b]){if(d=Hb(e[b]),!d)continue;if("*"===d){h.length=0,h.push(d);break}h.push.apply(h,[d,"//"+d,f.location.protocol+"//"+d])}return h.length&&(g+="trustedOrigins="+n(h.join(","))),a.forceEnhancedClipboard===!0&&(g+=(g?"&":"")+"forceEnhancedClipboard=true"),"string"==typeof a.swfObjectId&&a.swfObjectId&&(g+=(g?"&":"")+"swfObjectId="+n(a.swfObjectId)),"string"==typeof a.jsVersion&&a.jsVersion&&(g+=(g?"&":"")+"jsVersion="+n(a.jsVersion)),g},Hb=function(a){if(null==a||""===a)return null;if(a=a.replace(/^\s+|\s+$/g,""),""===a)return null;var b=a.indexOf("//");a=-1===b?a:a.slice(b+2);var c=a.indexOf("/");return a=-1===c?a:-1===b||0===c?null:a.slice(0,c),a&&".swf"===a.slice(-4).toLowerCase()?null:a||null},Ib=function(){var a=function(a){var b,c,d,e=[];if("string"==typeof a&&(a=[a]),"object"!=typeof a||!a||"number"!=typeof a.length)return e;for(b=0,c=a.length;c>b;b++)if(w.call(a,b)&&(d=Hb(a[b]))){if("*"===d){e.length=0,e.push("*");break}-1===e.indexOf(d)&&e.push(d)}return e};return function(b,c){var d=Hb(c.swfPath);null===d&&(d=b);var e=a(c.trustedDomains),f=e.length;if(f>0){if(1===f&&"*"===e[0])return"always";if(-1!==e.indexOf(b))return 1===f&&b===d?"sameDomain":"always"}return"never"}}(),Jb=function(){try{return g.activeElement}catch(a){return null}},Kb=function(a,b){var c,d,e,f=[];if("string"==typeof b&&b&&(f=b.split(/\s+/)),a&&1===a.nodeType&&f.length>0)if(a.classList)for(c=0,d=f.length;d>c;c++)a.classList.add(f[c]);else if(a.hasOwnProperty("className")){for(e=" "+a.className+" ",c=0,d=f.length;d>c;c++)-1===e.indexOf(" "+f[c]+" ")&&(e+=f[c]+" ");a.className=e.replace(/^\s+|\s+$/g,"")}return a},Lb=function(a,b){var c,d,e,f=[];if("string"==typeof b&&b&&(f=b.split(/\s+/)),a&&1===a.nodeType&&f.length>0)if(a.classList&&a.classList.length>0)for(c=0,d=f.length;d>c;c++)a.classList.remove(f[c]);else if(a.className){for(e=(" "+a.className+" ").replace(/[\r\n\t]/g," "),c=0,d=f.length;d>c;c++)e=e.replace(" "+f[c]+" "," ");a.className=e.replace(/^\s+|\s+$/g,"")}return a},Mb=function(a,b){var c=m(a,null).getPropertyValue(b);return"cursor"!==b||c&&"auto"!==c||"A"!==a.nodeName?c:"pointer"},Nb=function(a){var b={left:0,top:0,width:0,height:0};if(a.getBoundingClientRect){var c=a.getBoundingClientRect(),d=f.pageXOffset,e=f.pageYOffset,h=g.documentElement.clientLeft||0,i=g.documentElement.clientTop||0,j=0,k=0;if("relative"===Mb(g.body,"position")){var l=g.body.getBoundingClientRect(),m=g.documentElement.getBoundingClientRect();j=l.left-m.left||0,k=l.top-m.top||0}b.left=c.left+d-h-j,b.top=c.top+e-i-k,b.width="width"in c?c.width:c.right-c.left,b.height="height"in c?c.height:c.bottom-c.top}return b},Ob=function(a){if(!a)return!1;var b=m(a,null),c=r(b.height)>0,d=r(b.width)>0,e=r(b.top)>=0,f=r(b.left)>=0,g=c&&d&&e&&f,h=g?null:Nb(a),i="none"!==b.display&&"collapse"!==b.visibility&&(g||!!h&&(c||h.height>0)&&(d||h.width>0)&&(e||h.top>=0)&&(f||h.left>=0));return i},Pb=function(){j(S),S=0,l(T),T=0},Qb=function(){var a;if(d&&(a=Ab(N.bridge))){var b=Nb(d);A(a.style,{width:b.width+"px",height:b.height+"px",top:b.top+"px",left:b.left+"px",zIndex:""+Sb(Z.zIndex)})}},Rb=function(a){N.ready===!0&&(N.bridge&&"function"==typeof N.bridge.setHandCursor?N.bridge.setHandCursor(a):N.ready=!1)},Sb=function(a){if(/^(?:auto|inherit)$/.test(a))return a;var b;return"number"!=typeof a||s(a)?"string"==typeof a&&(b=Sb(q(a,10))):b=a,"number"==typeof b?b:"auto"},Tb=function(b){var c,d,e,f=N.sandboxed,g=null;if(b=b===!0,M===!1)g=!1;else{try{d=a.frameElement||null}catch(h){e={name:h.name,message:h.message}}if(d&&1===d.nodeType&&"IFRAME"===d.nodeName)try{g=d.hasAttribute("sandbox")}catch(h){g=null}else{try{c=document.domain||null}catch(h){c=null}(null===c||e&&"SecurityError"===e.name&&/(^|[\s\(\[@])sandbox(es|ed|ing|[\s\.,!\)\]@]|$)/.test(e.message.toLowerCase()))&&(g=!0)}}return N.sandboxed=g,f===g||b||Ub(o),g},Ub=function(a){function b(a){var b=a.match(/[\d]+/g);return b.length=3,b.join(".")}function c(a){return!!a&&(a=a.toLowerCase())&&(/^(pepflashplayer\.dll|libpepflashplayer\.so|pepperflashplayer\.plugin)$/.test(a)||"chrome.plugin"===a.slice(-13))}function d(a){a&&(i=!0,a.version&&(l=b(a.version)),!l&&a.description&&(l=b(a.description)),a.filename&&(k=c(a.filename)))}var e,f,g,i=!1,j=!1,k=!1,l="";if(h.plugins&&h.plugins.length)e=h.plugins["Shockwave Flash"],d(e),h.plugins["Shockwave Flash 2.0"]&&(i=!0,l="2.0.0.11");else if(h.mimeTypes&&h.mimeTypes.length)g=h.mimeTypes["application/x-shockwave-flash"],e=g&&g.enabledPlugin,d(e);else if("undefined"!=typeof a){j=!0;try{f=new a("ShockwaveFlash.ShockwaveFlash.7"),i=!0,l=b(f.GetVariable("$version"))}catch(m){try{f=new a("ShockwaveFlash.ShockwaveFlash.6"),i=!0,l="6.0.21"}catch(n){try{f=new a("ShockwaveFlash.ShockwaveFlash"),i=!0,l=b(f.GetVariable("$version"))}catch(o){j=!1}}}}N.disabled=i!==!0,N.outdated=l&&r(l)= 0) {\n _flashCheckTimeout = _setTimeout(function() {\n if (typeof _flashState.deactivated !== \"boolean\") {\n _flashState.deactivated = true;\n }\n if (_flashState.deactivated === true) {\n ZeroClipboard.emit({\n type: \"error\",\n name: \"flash-deactivated\"\n });\n }\n }, maxWait);\n }\n _flashState.overdue = false;\n _embedSwf();\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.destroy`.\n * @private\n */\n var _destroy = function() {\n ZeroClipboard.clearData();\n ZeroClipboard.blur();\n ZeroClipboard.emit(\"destroy\");\n _unembedSwf();\n ZeroClipboard.off();\n };\n /**\n * The underlying implementation of `ZeroClipboard.setData`.\n * @private\n */\n var _setData = function(format, data) {\n var dataObj;\n if (typeof format === \"object\" && format && typeof data === \"undefined\") {\n dataObj = format;\n ZeroClipboard.clearData();\n } else if (typeof format === \"string\" && format) {\n dataObj = {};\n dataObj[format] = data;\n } else {\n return;\n }\n for (var dataFormat in dataObj) {\n if (typeof dataFormat === \"string\" && dataFormat && _hasOwn.call(dataObj, dataFormat) && typeof dataObj[dataFormat] === \"string\" && dataObj[dataFormat]) {\n _clipData[dataFormat] = dataObj[dataFormat];\n }\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.clearData`.\n * @private\n */\n var _clearData = function(format) {\n if (typeof format === \"undefined\") {\n _deleteOwnProperties(_clipData);\n _clipDataFormatMap = null;\n } else if (typeof format === \"string\" && _hasOwn.call(_clipData, format)) {\n delete _clipData[format];\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.getData`.\n * @private\n */\n var _getData = function(format) {\n if (typeof format === \"undefined\") {\n return _deepCopy(_clipData);\n } else if (typeof format === \"string\" && _hasOwn.call(_clipData, format)) {\n return _clipData[format];\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.focus`/`ZeroClipboard.activate`.\n * @private\n */\n var _focus = function(element) {\n if (!(element && element.nodeType === 1)) {\n return;\n }\n if (_currentElement) {\n _removeClass(_currentElement, _globalConfig.activeClass);\n if (_currentElement !== element) {\n _removeClass(_currentElement, _globalConfig.hoverClass);\n }\n }\n _currentElement = element;\n _addClass(element, _globalConfig.hoverClass);\n var newTitle = element.getAttribute(\"title\") || _globalConfig.title;\n if (typeof newTitle === \"string\" && newTitle) {\n var htmlBridge = _getHtmlBridge(_flashState.bridge);\n if (htmlBridge) {\n htmlBridge.setAttribute(\"title\", newTitle);\n }\n }\n var useHandCursor = _globalConfig.forceHandCursor === true || _getStyle(element, \"cursor\") === \"pointer\";\n _setHandCursor(useHandCursor);\n _reposition();\n };\n /**\n * The underlying implementation of `ZeroClipboard.blur`/`ZeroClipboard.deactivate`.\n * @private\n */\n var _blur = function() {\n var htmlBridge = _getHtmlBridge(_flashState.bridge);\n if (htmlBridge) {\n htmlBridge.removeAttribute(\"title\");\n htmlBridge.style.left = \"0px\";\n htmlBridge.style.top = \"-9999px\";\n htmlBridge.style.width = \"1px\";\n htmlBridge.style.height = \"1px\";\n }\n if (_currentElement) {\n _removeClass(_currentElement, _globalConfig.hoverClass);\n _removeClass(_currentElement, _globalConfig.activeClass);\n _currentElement = null;\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.activeElement`.\n * @private\n */\n var _activeElement = function() {\n return _currentElement || null;\n };\n /**\n * Check if a value is a valid HTML4 `ID` or `Name` token.\n * @private\n */\n var _isValidHtml4Id = function(id) {\n return typeof id === \"string\" && id && /^[A-Za-z][A-Za-z0-9_:\\-\\.]*$/.test(id);\n };\n /**\n * Create or update an `event` object, based on the `eventType`.\n * @private\n */\n var _createEvent = function(event) {\n var eventType;\n if (typeof event === \"string\" && event) {\n eventType = event;\n event = {};\n } else if (typeof event === \"object\" && event && typeof event.type === \"string\" && event.type) {\n eventType = event.type;\n }\n if (!eventType) {\n return;\n }\n eventType = eventType.toLowerCase();\n if (!event.target && (/^(copy|aftercopy|_click)$/.test(eventType) || eventType === \"error\" && event.name === \"clipboard-error\")) {\n event.target = _copyTarget;\n }\n _extend(event, {\n type: eventType,\n target: event.target || _currentElement || null,\n relatedTarget: event.relatedTarget || null,\n currentTarget: _flashState && _flashState.bridge || null,\n timeStamp: event.timeStamp || _now() || null\n });\n var msg = _eventMessages[event.type];\n if (event.type === \"error\" && event.name && msg) {\n msg = msg[event.name];\n }\n if (msg) {\n event.message = msg;\n }\n if (event.type === \"ready\") {\n _extend(event, {\n target: null,\n version: _flashState.version\n });\n }\n if (event.type === \"error\") {\n if (_flashStateErrorNameMatchingRegex.test(event.name)) {\n _extend(event, {\n target: null,\n minimumVersion: _minimumFlashVersion\n });\n }\n if (_flashStateEnabledErrorNameMatchingRegex.test(event.name)) {\n _extend(event, {\n version: _flashState.version\n });\n }\n }\n if (event.type === \"copy\") {\n event.clipboardData = {\n setData: ZeroClipboard.setData,\n clearData: ZeroClipboard.clearData\n };\n }\n if (event.type === \"aftercopy\") {\n event = _mapClipResultsFromFlash(event, _clipDataFormatMap);\n }\n if (event.target && !event.relatedTarget) {\n event.relatedTarget = _getRelatedTarget(event.target);\n }\n return _addMouseData(event);\n };\n /**\n * Get a relatedTarget from the target's `data-clipboard-target` attribute\n * @private\n */\n var _getRelatedTarget = function(targetEl) {\n var relatedTargetId = targetEl && targetEl.getAttribute && targetEl.getAttribute(\"data-clipboard-target\");\n return relatedTargetId ? _document.getElementById(relatedTargetId) : null;\n };\n /**\n * Add element and position data to `MouseEvent` instances\n * @private\n */\n var _addMouseData = function(event) {\n if (event && /^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) {\n var srcElement = event.target;\n var fromElement = event.type === \"_mouseover\" && event.relatedTarget ? event.relatedTarget : undefined;\n var toElement = event.type === \"_mouseout\" && event.relatedTarget ? event.relatedTarget : undefined;\n var pos = _getElementPosition(srcElement);\n var screenLeft = _window.screenLeft || _window.screenX || 0;\n var screenTop = _window.screenTop || _window.screenY || 0;\n var scrollLeft = _document.body.scrollLeft + _document.documentElement.scrollLeft;\n var scrollTop = _document.body.scrollTop + _document.documentElement.scrollTop;\n var pageX = pos.left + (typeof event._stageX === \"number\" ? event._stageX : 0);\n var pageY = pos.top + (typeof event._stageY === \"number\" ? event._stageY : 0);\n var clientX = pageX - scrollLeft;\n var clientY = pageY - scrollTop;\n var screenX = screenLeft + clientX;\n var screenY = screenTop + clientY;\n var moveX = typeof event.movementX === \"number\" ? event.movementX : 0;\n var moveY = typeof event.movementY === \"number\" ? event.movementY : 0;\n delete event._stageX;\n delete event._stageY;\n _extend(event, {\n srcElement: srcElement,\n fromElement: fromElement,\n toElement: toElement,\n screenX: screenX,\n screenY: screenY,\n pageX: pageX,\n pageY: pageY,\n clientX: clientX,\n clientY: clientY,\n x: clientX,\n y: clientY,\n movementX: moveX,\n movementY: moveY,\n offsetX: 0,\n offsetY: 0,\n layerX: 0,\n layerY: 0\n });\n }\n return event;\n };\n /**\n * Determine if an event's registered handlers should be execute synchronously or asynchronously.\n *\n * @returns {boolean}\n * @private\n */\n var _shouldPerformAsync = function(event) {\n var eventType = event && typeof event.type === \"string\" && event.type || \"\";\n return !/^(?:(?:before)?copy|destroy)$/.test(eventType);\n };\n /**\n * Control if a callback should be executed asynchronously or not.\n *\n * @returns `undefined`\n * @private\n */\n var _dispatchCallback = function(func, context, args, async) {\n if (async) {\n _setTimeout(function() {\n func.apply(context, args);\n }, 0);\n } else {\n func.apply(context, args);\n }\n };\n /**\n * Handle the actual dispatching of events to client instances.\n *\n * @returns `undefined`\n * @private\n */\n var _dispatchCallbacks = function(event) {\n if (!(typeof event === \"object\" && event && event.type)) {\n return;\n }\n var async = _shouldPerformAsync(event);\n var wildcardTypeHandlers = _handlers[\"*\"] || [];\n var specificTypeHandlers = _handlers[event.type] || [];\n var handlers = wildcardTypeHandlers.concat(specificTypeHandlers);\n if (handlers && handlers.length) {\n var i, len, func, context, eventCopy, originalContext = this;\n for (i = 0, len = handlers.length; i < len; i++) {\n func = handlers[i];\n context = originalContext;\n if (typeof func === \"string\" && typeof _window[func] === \"function\") {\n func = _window[func];\n }\n if (typeof func === \"object\" && func && typeof func.handleEvent === \"function\") {\n context = func;\n func = func.handleEvent;\n }\n if (typeof func === \"function\") {\n eventCopy = _extend({}, event);\n _dispatchCallback(func, context, [ eventCopy ], async);\n }\n }\n }\n return this;\n };\n /**\n * Check an `error` event's `name` property to see if Flash has\n * already loaded, which rules out possible `iframe` sandboxing.\n * @private\n */\n var _getSandboxStatusFromErrorEvent = function(event) {\n var isSandboxed = null;\n if (_pageIsFramed === false || event && event.type === \"error\" && event.name && _errorsThatOnlyOccurAfterFlashLoads.indexOf(event.name) !== -1) {\n isSandboxed = false;\n }\n return isSandboxed;\n };\n /**\n * Preprocess any special behaviors, reactions, or state changes after receiving this event.\n * Executes only once per event emitted, NOT once per client.\n * @private\n */\n var _preprocessEvent = function(event) {\n var element = event.target || _currentElement || null;\n var sourceIsSwf = event._source === \"swf\";\n delete event._source;\n switch (event.type) {\n case \"error\":\n var isSandboxed = event.name === \"flash-sandboxed\" || _getSandboxStatusFromErrorEvent(event);\n if (typeof isSandboxed === \"boolean\") {\n _flashState.sandboxed = isSandboxed;\n }\n if (_flashStateErrorNames.indexOf(event.name) !== -1) {\n _extend(_flashState, {\n disabled: event.name === \"flash-disabled\",\n outdated: event.name === \"flash-outdated\",\n unavailable: event.name === \"flash-unavailable\",\n degraded: event.name === \"flash-degraded\",\n deactivated: event.name === \"flash-deactivated\",\n overdue: event.name === \"flash-overdue\",\n ready: false\n });\n } else if (event.name === \"version-mismatch\") {\n _zcSwfVersion = event.swfVersion;\n _extend(_flashState, {\n disabled: false,\n outdated: false,\n unavailable: false,\n degraded: false,\n deactivated: false,\n overdue: false,\n ready: false\n });\n }\n _clearTimeoutsAndPolling();\n break;\n\n case \"ready\":\n _zcSwfVersion = event.swfVersion;\n var wasDeactivated = _flashState.deactivated === true;\n _extend(_flashState, {\n disabled: false,\n outdated: false,\n sandboxed: false,\n unavailable: false,\n degraded: false,\n deactivated: false,\n overdue: wasDeactivated,\n ready: !wasDeactivated\n });\n _clearTimeoutsAndPolling();\n break;\n\n case \"beforecopy\":\n _copyTarget = element;\n break;\n\n case \"copy\":\n var textContent, htmlContent, targetEl = event.relatedTarget;\n if (!(_clipData[\"text/html\"] || _clipData[\"text/plain\"]) && targetEl && (htmlContent = targetEl.value || targetEl.outerHTML || targetEl.innerHTML) && (textContent = targetEl.value || targetEl.textContent || targetEl.innerText)) {\n event.clipboardData.clearData();\n event.clipboardData.setData(\"text/plain\", textContent);\n if (htmlContent !== textContent) {\n event.clipboardData.setData(\"text/html\", htmlContent);\n }\n } else if (!_clipData[\"text/plain\"] && event.target && (textContent = event.target.getAttribute(\"data-clipboard-text\"))) {\n event.clipboardData.clearData();\n event.clipboardData.setData(\"text/plain\", textContent);\n }\n break;\n\n case \"aftercopy\":\n _queueEmitClipboardErrors(event);\n ZeroClipboard.clearData();\n if (element && element !== _safeActiveElement() && element.focus) {\n element.focus();\n }\n break;\n\n case \"_mouseover\":\n ZeroClipboard.focus(element);\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) {\n _fireMouseEvent(_extend({}, event, {\n type: \"mouseenter\",\n bubbles: false,\n cancelable: false\n }));\n }\n _fireMouseEvent(_extend({}, event, {\n type: \"mouseover\"\n }));\n }\n break;\n\n case \"_mouseout\":\n ZeroClipboard.blur();\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) {\n _fireMouseEvent(_extend({}, event, {\n type: \"mouseleave\",\n bubbles: false,\n cancelable: false\n }));\n }\n _fireMouseEvent(_extend({}, event, {\n type: \"mouseout\"\n }));\n }\n break;\n\n case \"_mousedown\":\n _addClass(element, _globalConfig.activeClass);\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n _fireMouseEvent(_extend({}, event, {\n type: event.type.slice(1)\n }));\n }\n break;\n\n case \"_mouseup\":\n _removeClass(element, _globalConfig.activeClass);\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n _fireMouseEvent(_extend({}, event, {\n type: event.type.slice(1)\n }));\n }\n break;\n\n case \"_click\":\n _copyTarget = null;\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n _fireMouseEvent(_extend({}, event, {\n type: event.type.slice(1)\n }));\n }\n break;\n\n case \"_mousemove\":\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n _fireMouseEvent(_extend({}, event, {\n type: event.type.slice(1)\n }));\n }\n break;\n }\n if (/^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) {\n return true;\n }\n };\n /**\n * Check an \"aftercopy\" event for clipboard errors and emit a corresponding \"error\" event.\n * @private\n */\n var _queueEmitClipboardErrors = function(aftercopyEvent) {\n if (aftercopyEvent.errors && aftercopyEvent.errors.length > 0) {\n var errorEvent = _deepCopy(aftercopyEvent);\n _extend(errorEvent, {\n type: \"error\",\n name: \"clipboard-error\"\n });\n delete errorEvent.success;\n _setTimeout(function() {\n ZeroClipboard.emit(errorEvent);\n }, 0);\n }\n };\n /**\n * Dispatch a synthetic MouseEvent.\n *\n * @returns `undefined`\n * @private\n */\n var _fireMouseEvent = function(event) {\n if (!(event && typeof event.type === \"string\" && event)) {\n return;\n }\n var e, target = event.target || null, doc = target && target.ownerDocument || _document, defaults = {\n view: doc.defaultView || _window,\n canBubble: true,\n cancelable: true,\n detail: event.type === \"click\" ? 1 : 0,\n button: typeof event.which === \"number\" ? event.which - 1 : typeof event.button === \"number\" ? event.button : doc.createEvent ? 0 : 1\n }, args = _extend(defaults, event);\n if (!target) {\n return;\n }\n if (doc.createEvent && target.dispatchEvent) {\n args = [ args.type, args.canBubble, args.cancelable, args.view, args.detail, args.screenX, args.screenY, args.clientX, args.clientY, args.ctrlKey, args.altKey, args.shiftKey, args.metaKey, args.button, args.relatedTarget ];\n e = doc.createEvent(\"MouseEvents\");\n if (e.initMouseEvent) {\n e.initMouseEvent.apply(e, args);\n e._source = \"js\";\n target.dispatchEvent(e);\n }\n }\n };\n /**\n * Continuously poll the DOM until either:\n * (a) the fallback content becomes visible, or\n * (b) we receive an event from SWF (handled elsewhere)\n *\n * IMPORTANT:\n * This is NOT a necessary check but it can result in significantly faster\n * detection of bad `swfPath` configuration and/or network/server issues [in\n * supported browsers] than waiting for the entire `flashLoadTimeout` duration\n * to elapse before detecting that the SWF cannot be loaded. The detection\n * duration can be anywhere from 10-30 times faster [in supported browsers] by\n * using this approach.\n *\n * @returns `undefined`\n * @private\n */\n var _watchForSwfFallbackContent = function() {\n var maxWait = _globalConfig.flashLoadTimeout;\n if (typeof maxWait === \"number\" && maxWait >= 0) {\n var pollWait = Math.min(1e3, maxWait / 10);\n var fallbackContentId = _globalConfig.swfObjectId + \"_fallbackContent\";\n _swfFallbackCheckInterval = _setInterval(function() {\n var el = _document.getElementById(fallbackContentId);\n if (_isElementVisible(el)) {\n _clearTimeoutsAndPolling();\n _flashState.deactivated = null;\n ZeroClipboard.emit({\n type: \"error\",\n name: \"swf-not-found\"\n });\n }\n }, pollWait);\n }\n };\n /**\n * Create the HTML bridge element to embed the Flash object into.\n * @private\n */\n var _createHtmlBridge = function() {\n var container = _document.createElement(\"div\");\n container.id = _globalConfig.containerId;\n container.className = _globalConfig.containerClass;\n container.style.position = \"absolute\";\n container.style.left = \"0px\";\n container.style.top = \"-9999px\";\n container.style.width = \"1px\";\n container.style.height = \"1px\";\n container.style.zIndex = \"\" + _getSafeZIndex(_globalConfig.zIndex);\n return container;\n };\n /**\n * Get the HTML element container that wraps the Flash bridge object/element.\n * @private\n */\n var _getHtmlBridge = function(flashBridge) {\n var htmlBridge = flashBridge && flashBridge.parentNode;\n while (htmlBridge && htmlBridge.nodeName === \"OBJECT\" && htmlBridge.parentNode) {\n htmlBridge = htmlBridge.parentNode;\n }\n return htmlBridge || null;\n };\n /**\n * Create the SWF object.\n *\n * @returns The SWF object reference.\n * @private\n */\n var _embedSwf = function() {\n var len, flashBridge = _flashState.bridge, container = _getHtmlBridge(flashBridge);\n if (!flashBridge) {\n var allowScriptAccess = _determineScriptAccess(_window.location.host, _globalConfig);\n var allowNetworking = allowScriptAccess === \"never\" ? \"none\" : \"all\";\n var flashvars = _vars(_extend({\n jsVersion: ZeroClipboard.version\n }, _globalConfig));\n var swfUrl = _globalConfig.swfPath + _cacheBust(_globalConfig.swfPath, _globalConfig);\n container = _createHtmlBridge();\n var divToBeReplaced = _document.createElement(\"div\");\n container.appendChild(divToBeReplaced);\n _document.body.appendChild(container);\n var tmpDiv = _document.createElement(\"div\");\n var usingActiveX = _flashState.pluginType === \"activex\";\n tmpDiv.innerHTML = '\" + (usingActiveX ? '' : \"\") + '' + '' + '' + '' + '' + '
 
' + \"
\";\n flashBridge = tmpDiv.firstChild;\n tmpDiv = null;\n _unwrap(flashBridge).ZeroClipboard = ZeroClipboard;\n container.replaceChild(flashBridge, divToBeReplaced);\n _watchForSwfFallbackContent();\n }\n if (!flashBridge) {\n flashBridge = _document[_globalConfig.swfObjectId];\n if (flashBridge && (len = flashBridge.length)) {\n flashBridge = flashBridge[len - 1];\n }\n if (!flashBridge && container) {\n flashBridge = container.firstChild;\n }\n }\n _flashState.bridge = flashBridge || null;\n return flashBridge;\n };\n /**\n * Destroy the SWF object.\n * @private\n */\n var _unembedSwf = function() {\n var flashBridge = _flashState.bridge;\n if (flashBridge) {\n var htmlBridge = _getHtmlBridge(flashBridge);\n if (htmlBridge) {\n if (_flashState.pluginType === \"activex\" && \"readyState\" in flashBridge) {\n flashBridge.style.display = \"none\";\n (function removeSwfFromIE() {\n if (flashBridge.readyState === 4) {\n for (var prop in flashBridge) {\n if (typeof flashBridge[prop] === \"function\") {\n flashBridge[prop] = null;\n }\n }\n if (flashBridge.parentNode) {\n flashBridge.parentNode.removeChild(flashBridge);\n }\n if (htmlBridge.parentNode) {\n htmlBridge.parentNode.removeChild(htmlBridge);\n }\n } else {\n _setTimeout(removeSwfFromIE, 10);\n }\n })();\n } else {\n if (flashBridge.parentNode) {\n flashBridge.parentNode.removeChild(flashBridge);\n }\n if (htmlBridge.parentNode) {\n htmlBridge.parentNode.removeChild(htmlBridge);\n }\n }\n }\n _clearTimeoutsAndPolling();\n _flashState.ready = null;\n _flashState.bridge = null;\n _flashState.deactivated = null;\n _zcSwfVersion = undefined;\n }\n };\n /**\n * Map the data format names of the \"clipData\" to Flash-friendly names.\n *\n * @returns A new transformed object.\n * @private\n */\n var _mapClipDataToFlash = function(clipData) {\n var newClipData = {}, formatMap = {};\n if (!(typeof clipData === \"object\" && clipData)) {\n return;\n }\n for (var dataFormat in clipData) {\n if (dataFormat && _hasOwn.call(clipData, dataFormat) && typeof clipData[dataFormat] === \"string\" && clipData[dataFormat]) {\n switch (dataFormat.toLowerCase()) {\n case \"text/plain\":\n case \"text\":\n case \"air:text\":\n case \"flash:text\":\n newClipData.text = clipData[dataFormat];\n formatMap.text = dataFormat;\n break;\n\n case \"text/html\":\n case \"html\":\n case \"air:html\":\n case \"flash:html\":\n newClipData.html = clipData[dataFormat];\n formatMap.html = dataFormat;\n break;\n\n case \"application/rtf\":\n case \"text/rtf\":\n case \"rtf\":\n case \"richtext\":\n case \"air:rtf\":\n case \"flash:rtf\":\n newClipData.rtf = clipData[dataFormat];\n formatMap.rtf = dataFormat;\n break;\n\n default:\n break;\n }\n }\n }\n return {\n data: newClipData,\n formatMap: formatMap\n };\n };\n /**\n * Map the data format names from Flash-friendly names back to their original \"clipData\" names (via a format mapping).\n *\n * @returns A new transformed object.\n * @private\n */\n var _mapClipResultsFromFlash = function(clipResults, formatMap) {\n if (!(typeof clipResults === \"object\" && clipResults && typeof formatMap === \"object\" && formatMap)) {\n return clipResults;\n }\n var newResults = {};\n for (var prop in clipResults) {\n if (_hasOwn.call(clipResults, prop)) {\n if (prop === \"errors\") {\n newResults[prop] = clipResults[prop] ? clipResults[prop].slice() : [];\n for (var i = 0, len = newResults[prop].length; i < len; i++) {\n newResults[prop][i].format = formatMap[newResults[prop][i].format];\n }\n } else if (prop !== \"success\" && prop !== \"data\") {\n newResults[prop] = clipResults[prop];\n } else {\n newResults[prop] = {};\n var tmpHash = clipResults[prop];\n for (var dataFormat in tmpHash) {\n if (dataFormat && _hasOwn.call(tmpHash, dataFormat) && _hasOwn.call(formatMap, dataFormat)) {\n newResults[prop][formatMap[dataFormat]] = tmpHash[dataFormat];\n }\n }\n }\n }\n }\n return newResults;\n };\n /**\n * Will look at a path, and will create a \"?noCache={time}\" or \"&noCache={time}\"\n * query param string to return. Does NOT append that string to the original path.\n * This is useful because ExternalInterface often breaks when a Flash SWF is cached.\n *\n * @returns The `noCache` query param with necessary \"?\"/\"&\" prefix.\n * @private\n */\n var _cacheBust = function(path, options) {\n var cacheBust = options == null || options && options.cacheBust === true;\n if (cacheBust) {\n return (path.indexOf(\"?\") === -1 ? \"?\" : \"&\") + \"noCache=\" + _now();\n } else {\n return \"\";\n }\n };\n /**\n * Creates a query string for the FlashVars param.\n * Does NOT include the cache-busting query param.\n *\n * @returns FlashVars query string\n * @private\n */\n var _vars = function(options) {\n var i, len, domain, domains, str = \"\", trustedOriginsExpanded = [];\n if (options.trustedDomains) {\n if (typeof options.trustedDomains === \"string\") {\n domains = [ options.trustedDomains ];\n } else if (typeof options.trustedDomains === \"object\" && \"length\" in options.trustedDomains) {\n domains = options.trustedDomains;\n }\n }\n if (domains && domains.length) {\n for (i = 0, len = domains.length; i < len; i++) {\n if (_hasOwn.call(domains, i) && domains[i] && typeof domains[i] === \"string\") {\n domain = _extractDomain(domains[i]);\n if (!domain) {\n continue;\n }\n if (domain === \"*\") {\n trustedOriginsExpanded.length = 0;\n trustedOriginsExpanded.push(domain);\n break;\n }\n trustedOriginsExpanded.push.apply(trustedOriginsExpanded, [ domain, \"//\" + domain, _window.location.protocol + \"//\" + domain ]);\n }\n }\n }\n if (trustedOriginsExpanded.length) {\n str += \"trustedOrigins=\" + _encodeURIComponent(trustedOriginsExpanded.join(\",\"));\n }\n if (options.forceEnhancedClipboard === true) {\n str += (str ? \"&\" : \"\") + \"forceEnhancedClipboard=true\";\n }\n if (typeof options.swfObjectId === \"string\" && options.swfObjectId) {\n str += (str ? \"&\" : \"\") + \"swfObjectId=\" + _encodeURIComponent(options.swfObjectId);\n }\n if (typeof options.jsVersion === \"string\" && options.jsVersion) {\n str += (str ? \"&\" : \"\") + \"jsVersion=\" + _encodeURIComponent(options.jsVersion);\n }\n return str;\n };\n /**\n * Extract the domain (e.g. \"github.com\") from an origin (e.g. \"https://github.com\") or\n * URL (e.g. \"https://github.com/zeroclipboard/zeroclipboard/\").\n *\n * @returns the domain\n * @private\n */\n var _extractDomain = function(originOrUrl) {\n if (originOrUrl == null || originOrUrl === \"\") {\n return null;\n }\n originOrUrl = originOrUrl.replace(/^\\s+|\\s+$/g, \"\");\n if (originOrUrl === \"\") {\n return null;\n }\n var protocolIndex = originOrUrl.indexOf(\"//\");\n originOrUrl = protocolIndex === -1 ? originOrUrl : originOrUrl.slice(protocolIndex + 2);\n var pathIndex = originOrUrl.indexOf(\"/\");\n originOrUrl = pathIndex === -1 ? originOrUrl : protocolIndex === -1 || pathIndex === 0 ? null : originOrUrl.slice(0, pathIndex);\n if (originOrUrl && originOrUrl.slice(-4).toLowerCase() === \".swf\") {\n return null;\n }\n return originOrUrl || null;\n };\n /**\n * Set `allowScriptAccess` based on `trustedDomains` and `window.location.host` vs. `swfPath`.\n *\n * @returns The appropriate script access level.\n * @private\n */\n var _determineScriptAccess = function() {\n var _extractAllDomains = function(origins) {\n var i, len, tmp, resultsArray = [];\n if (typeof origins === \"string\") {\n origins = [ origins ];\n }\n if (!(typeof origins === \"object\" && origins && typeof origins.length === \"number\")) {\n return resultsArray;\n }\n for (i = 0, len = origins.length; i < len; i++) {\n if (_hasOwn.call(origins, i) && (tmp = _extractDomain(origins[i]))) {\n if (tmp === \"*\") {\n resultsArray.length = 0;\n resultsArray.push(\"*\");\n break;\n }\n if (resultsArray.indexOf(tmp) === -1) {\n resultsArray.push(tmp);\n }\n }\n }\n return resultsArray;\n };\n return function(currentDomain, configOptions) {\n var swfDomain = _extractDomain(configOptions.swfPath);\n if (swfDomain === null) {\n swfDomain = currentDomain;\n }\n var trustedDomains = _extractAllDomains(configOptions.trustedDomains);\n var len = trustedDomains.length;\n if (len > 0) {\n if (len === 1 && trustedDomains[0] === \"*\") {\n return \"always\";\n }\n if (trustedDomains.indexOf(currentDomain) !== -1) {\n if (len === 1 && currentDomain === swfDomain) {\n return \"sameDomain\";\n }\n return \"always\";\n }\n }\n return \"never\";\n };\n }();\n /**\n * Get the currently active/focused DOM element.\n *\n * @returns the currently active/focused element, or `null`\n * @private\n */\n var _safeActiveElement = function() {\n try {\n return _document.activeElement;\n } catch (err) {\n return null;\n }\n };\n /**\n * Add a class to an element, if it doesn't already have it.\n *\n * @returns The element, with its new class added.\n * @private\n */\n var _addClass = function(element, value) {\n var c, cl, className, classNames = [];\n if (typeof value === \"string\" && value) {\n classNames = value.split(/\\s+/);\n }\n if (element && element.nodeType === 1 && classNames.length > 0) {\n if (element.classList) {\n for (c = 0, cl = classNames.length; c < cl; c++) {\n element.classList.add(classNames[c]);\n }\n } else if (element.hasOwnProperty(\"className\")) {\n className = \" \" + element.className + \" \";\n for (c = 0, cl = classNames.length; c < cl; c++) {\n if (className.indexOf(\" \" + classNames[c] + \" \") === -1) {\n className += classNames[c] + \" \";\n }\n }\n element.className = className.replace(/^\\s+|\\s+$/g, \"\");\n }\n }\n return element;\n };\n /**\n * Remove a class from an element, if it has it.\n *\n * @returns The element, with its class removed.\n * @private\n */\n var _removeClass = function(element, value) {\n var c, cl, className, classNames = [];\n if (typeof value === \"string\" && value) {\n classNames = value.split(/\\s+/);\n }\n if (element && element.nodeType === 1 && classNames.length > 0) {\n if (element.classList && element.classList.length > 0) {\n for (c = 0, cl = classNames.length; c < cl; c++) {\n element.classList.remove(classNames[c]);\n }\n } else if (element.className) {\n className = (\" \" + element.className + \" \").replace(/[\\r\\n\\t]/g, \" \");\n for (c = 0, cl = classNames.length; c < cl; c++) {\n className = className.replace(\" \" + classNames[c] + \" \", \" \");\n }\n element.className = className.replace(/^\\s+|\\s+$/g, \"\");\n }\n }\n return element;\n };\n /**\n * Attempt to interpret the element's CSS styling. If `prop` is `\"cursor\"`,\n * then we assume that it should be a hand (\"pointer\") cursor if the element\n * is an anchor element (\"a\" tag).\n *\n * @returns The computed style property.\n * @private\n */\n var _getStyle = function(el, prop) {\n var value = _getComputedStyle(el, null).getPropertyValue(prop);\n if (prop === \"cursor\") {\n if (!value || value === \"auto\") {\n if (el.nodeName === \"A\") {\n return \"pointer\";\n }\n }\n }\n return value;\n };\n /**\n * Get the absolutely positioned coordinates of a DOM element.\n *\n * @returns Object containing the element's position, width, and height.\n * @private\n */\n var _getElementPosition = function(el) {\n var pos = {\n left: 0,\n top: 0,\n width: 0,\n height: 0\n };\n if (el.getBoundingClientRect) {\n var elRect = el.getBoundingClientRect();\n var pageXOffset = _window.pageXOffset;\n var pageYOffset = _window.pageYOffset;\n var leftBorderWidth = _document.documentElement.clientLeft || 0;\n var topBorderWidth = _document.documentElement.clientTop || 0;\n var leftBodyOffset = 0;\n var topBodyOffset = 0;\n if (_getStyle(_document.body, \"position\") === \"relative\") {\n var bodyRect = _document.body.getBoundingClientRect();\n var htmlRect = _document.documentElement.getBoundingClientRect();\n leftBodyOffset = bodyRect.left - htmlRect.left || 0;\n topBodyOffset = bodyRect.top - htmlRect.top || 0;\n }\n pos.left = elRect.left + pageXOffset - leftBorderWidth - leftBodyOffset;\n pos.top = elRect.top + pageYOffset - topBorderWidth - topBodyOffset;\n pos.width = \"width\" in elRect ? elRect.width : elRect.right - elRect.left;\n pos.height = \"height\" in elRect ? elRect.height : elRect.bottom - elRect.top;\n }\n return pos;\n };\n /**\n * Determine is an element is visible somewhere within the document (page).\n *\n * @returns Boolean\n * @private\n */\n var _isElementVisible = function(el) {\n if (!el) {\n return false;\n }\n var styles = _getComputedStyle(el, null);\n var hasCssHeight = _parseFloat(styles.height) > 0;\n var hasCssWidth = _parseFloat(styles.width) > 0;\n var hasCssTop = _parseFloat(styles.top) >= 0;\n var hasCssLeft = _parseFloat(styles.left) >= 0;\n var cssKnows = hasCssHeight && hasCssWidth && hasCssTop && hasCssLeft;\n var rect = cssKnows ? null : _getElementPosition(el);\n var isVisible = styles.display !== \"none\" && styles.visibility !== \"collapse\" && (cssKnows || !!rect && (hasCssHeight || rect.height > 0) && (hasCssWidth || rect.width > 0) && (hasCssTop || rect.top >= 0) && (hasCssLeft || rect.left >= 0));\n return isVisible;\n };\n /**\n * Clear all existing timeouts and interval polling delegates.\n *\n * @returns `undefined`\n * @private\n */\n var _clearTimeoutsAndPolling = function() {\n _clearTimeout(_flashCheckTimeout);\n _flashCheckTimeout = 0;\n _clearInterval(_swfFallbackCheckInterval);\n _swfFallbackCheckInterval = 0;\n };\n /**\n * Reposition the Flash object to cover the currently activated element.\n *\n * @returns `undefined`\n * @private\n */\n var _reposition = function() {\n var htmlBridge;\n if (_currentElement && (htmlBridge = _getHtmlBridge(_flashState.bridge))) {\n var pos = _getElementPosition(_currentElement);\n _extend(htmlBridge.style, {\n width: pos.width + \"px\",\n height: pos.height + \"px\",\n top: pos.top + \"px\",\n left: pos.left + \"px\",\n zIndex: \"\" + _getSafeZIndex(_globalConfig.zIndex)\n });\n }\n };\n /**\n * Sends a signal to the Flash object to display the hand cursor if `true`.\n *\n * @returns `undefined`\n * @private\n */\n var _setHandCursor = function(enabled) {\n if (_flashState.ready === true) {\n if (_flashState.bridge && typeof _flashState.bridge.setHandCursor === \"function\") {\n _flashState.bridge.setHandCursor(enabled);\n } else {\n _flashState.ready = false;\n }\n }\n };\n /**\n * Get a safe value for `zIndex`\n *\n * @returns an integer, or \"auto\"\n * @private\n */\n var _getSafeZIndex = function(val) {\n if (/^(?:auto|inherit)$/.test(val)) {\n return val;\n }\n var zIndex;\n if (typeof val === \"number\" && !_isNaN(val)) {\n zIndex = val;\n } else if (typeof val === \"string\") {\n zIndex = _getSafeZIndex(_parseInt(val, 10));\n }\n return typeof zIndex === \"number\" ? zIndex : \"auto\";\n };\n /**\n * Attempt to detect if ZeroClipboard is executing inside of a sandboxed iframe.\n * If it is, Flash Player cannot be used, so ZeroClipboard is dead in the water.\n *\n * @see {@link http://lists.w3.org/Archives/Public/public-whatwg-archive/2014Dec/0002.html}\n * @see {@link https://github.com/zeroclipboard/zeroclipboard/issues/511}\n * @see {@link http://zeroclipboard.org/test-iframes.html}\n *\n * @returns `true` (is sandboxed), `false` (is not sandboxed), or `null` (uncertain) \n * @private\n */\n var _detectSandbox = function(doNotReassessFlashSupport) {\n var effectiveScriptOrigin, frame, frameError, previousState = _flashState.sandboxed, isSandboxed = null;\n doNotReassessFlashSupport = doNotReassessFlashSupport === true;\n if (_pageIsFramed === false) {\n isSandboxed = false;\n } else {\n try {\n frame = window.frameElement || null;\n } catch (e) {\n frameError = {\n name: e.name,\n message: e.message\n };\n }\n if (frame && frame.nodeType === 1 && frame.nodeName === \"IFRAME\") {\n try {\n isSandboxed = frame.hasAttribute(\"sandbox\");\n } catch (e) {\n isSandboxed = null;\n }\n } else {\n try {\n effectiveScriptOrigin = document.domain || null;\n } catch (e) {\n effectiveScriptOrigin = null;\n }\n if (effectiveScriptOrigin === null || frameError && frameError.name === \"SecurityError\" && /(^|[\\s\\(\\[@])sandbox(es|ed|ing|[\\s\\.,!\\)\\]@]|$)/.test(frameError.message.toLowerCase())) {\n isSandboxed = true;\n }\n }\n }\n _flashState.sandboxed = isSandboxed;\n if (previousState !== isSandboxed && !doNotReassessFlashSupport) {\n _detectFlashSupport(_ActiveXObject);\n }\n return isSandboxed;\n };\n /**\n * Detect the Flash Player status, version, and plugin type.\n *\n * @see {@link https://code.google.com/p/doctype-mirror/wiki/ArticleDetectFlash#The_code}\n * @see {@link http://stackoverflow.com/questions/12866060/detecting-pepper-ppapi-flash-with-javascript}\n *\n * @returns `undefined`\n * @private\n */\n var _detectFlashSupport = function(ActiveXObject) {\n var plugin, ax, mimeType, hasFlash = false, isActiveX = false, isPPAPI = false, flashVersion = \"\";\n /**\n * Derived from Apple's suggested sniffer.\n * @param {String} desc e.g. \"Shockwave Flash 7.0 r61\"\n * @returns {String} \"7.0.61\"\n * @private\n */\n function parseFlashVersion(desc) {\n var matches = desc.match(/[\\d]+/g);\n matches.length = 3;\n return matches.join(\".\");\n }\n function isPepperFlash(flashPlayerFileName) {\n return !!flashPlayerFileName && (flashPlayerFileName = flashPlayerFileName.toLowerCase()) && (/^(pepflashplayer\\.dll|libpepflashplayer\\.so|pepperflashplayer\\.plugin)$/.test(flashPlayerFileName) || flashPlayerFileName.slice(-13) === \"chrome.plugin\");\n }\n function inspectPlugin(plugin) {\n if (plugin) {\n hasFlash = true;\n if (plugin.version) {\n flashVersion = parseFlashVersion(plugin.version);\n }\n if (!flashVersion && plugin.description) {\n flashVersion = parseFlashVersion(plugin.description);\n }\n if (plugin.filename) {\n isPPAPI = isPepperFlash(plugin.filename);\n }\n }\n }\n if (_navigator.plugins && _navigator.plugins.length) {\n plugin = _navigator.plugins[\"Shockwave Flash\"];\n inspectPlugin(plugin);\n if (_navigator.plugins[\"Shockwave Flash 2.0\"]) {\n hasFlash = true;\n flashVersion = \"2.0.0.11\";\n }\n } else if (_navigator.mimeTypes && _navigator.mimeTypes.length) {\n mimeType = _navigator.mimeTypes[\"application/x-shockwave-flash\"];\n plugin = mimeType && mimeType.enabledPlugin;\n inspectPlugin(plugin);\n } else if (typeof ActiveXObject !== \"undefined\") {\n isActiveX = true;\n try {\n ax = new ActiveXObject(\"ShockwaveFlash.ShockwaveFlash.7\");\n hasFlash = true;\n flashVersion = parseFlashVersion(ax.GetVariable(\"$version\"));\n } catch (e1) {\n try {\n ax = new ActiveXObject(\"ShockwaveFlash.ShockwaveFlash.6\");\n hasFlash = true;\n flashVersion = \"6.0.21\";\n } catch (e2) {\n try {\n ax = new ActiveXObject(\"ShockwaveFlash.ShockwaveFlash\");\n hasFlash = true;\n flashVersion = parseFlashVersion(ax.GetVariable(\"$version\"));\n } catch (e3) {\n isActiveX = false;\n }\n }\n }\n }\n _flashState.disabled = hasFlash !== true;\n _flashState.outdated = flashVersion && _parseFloat(flashVersion) < _parseFloat(_minimumFlashVersion);\n _flashState.version = flashVersion || \"0.0.0\";\n _flashState.pluginType = isPPAPI ? \"pepper\" : isActiveX ? \"activex\" : hasFlash ? \"netscape\" : \"unknown\";\n };\n /**\n * Invoke the Flash detection algorithms immediately upon inclusion so we're not waiting later.\n */\n _detectFlashSupport(_ActiveXObject);\n /**\n * Always assess the `sandboxed` state of the page at important Flash-related moments.\n */\n _detectSandbox(true);\n /**\n * A shell constructor for `ZeroClipboard` client instances.\n *\n * @constructor\n */\n var ZeroClipboard = function() {\n if (!(this instanceof ZeroClipboard)) {\n return new ZeroClipboard();\n }\n if (typeof ZeroClipboard._createClient === \"function\") {\n ZeroClipboard._createClient.apply(this, _args(arguments));\n }\n };\n /**\n * The ZeroClipboard library's version number.\n *\n * @static\n * @readonly\n * @property {string}\n */\n _defineProperty(ZeroClipboard, \"version\", {\n value: \"2.2.0\",\n writable: false,\n configurable: true,\n enumerable: true\n });\n /**\n * Update or get a copy of the ZeroClipboard global configuration.\n * Returns a copy of the current/updated configuration.\n *\n * @returns Object\n * @static\n */\n ZeroClipboard.config = function() {\n return _config.apply(this, _args(arguments));\n };\n /**\n * Diagnostic method that describes the state of the browser, Flash Player, and ZeroClipboard.\n *\n * @returns Object\n * @static\n */\n ZeroClipboard.state = function() {\n return _state.apply(this, _args(arguments));\n };\n /**\n * Check if Flash is unusable for any reason: disabled, outdated, deactivated, etc.\n *\n * @returns Boolean\n * @static\n */\n ZeroClipboard.isFlashUnusable = function() {\n return _isFlashUnusable.apply(this, _args(arguments));\n };\n /**\n * Register an event listener.\n *\n * @returns `ZeroClipboard`\n * @static\n */\n ZeroClipboard.on = function() {\n return _on.apply(this, _args(arguments));\n };\n /**\n * Unregister an event listener.\n * If no `listener` function/object is provided, it will unregister all listeners for the provided `eventType`.\n * If no `eventType` is provided, it will unregister all listeners for every event type.\n *\n * @returns `ZeroClipboard`\n * @static\n */\n ZeroClipboard.off = function() {\n return _off.apply(this, _args(arguments));\n };\n /**\n * Retrieve event listeners for an `eventType`.\n * If no `eventType` is provided, it will retrieve all listeners for every event type.\n *\n * @returns array of listeners for the `eventType`; if no `eventType`, then a map/hash object of listeners for all event types; or `null`\n */\n ZeroClipboard.handlers = function() {\n return _listeners.apply(this, _args(arguments));\n };\n /**\n * Event emission receiver from the Flash object, forwarding to any registered JavaScript event listeners.\n *\n * @returns For the \"copy\" event, returns the Flash-friendly \"clipData\" object; otherwise `undefined`.\n * @static\n */\n ZeroClipboard.emit = function() {\n return _emit.apply(this, _args(arguments));\n };\n /**\n * Create and embed the Flash object.\n *\n * @returns The Flash object\n * @static\n */\n ZeroClipboard.create = function() {\n return _create.apply(this, _args(arguments));\n };\n /**\n * Self-destruct and clean up everything, including the embedded Flash object.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.destroy = function() {\n return _destroy.apply(this, _args(arguments));\n };\n /**\n * Set the pending data for clipboard injection.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.setData = function() {\n return _setData.apply(this, _args(arguments));\n };\n /**\n * Clear the pending data for clipboard injection.\n * If no `format` is provided, all pending data formats will be cleared.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.clearData = function() {\n return _clearData.apply(this, _args(arguments));\n };\n /**\n * Get a copy of the pending data for clipboard injection.\n * If no `format` is provided, a copy of ALL pending data formats will be returned.\n *\n * @returns `String` or `Object`\n * @static\n */\n ZeroClipboard.getData = function() {\n return _getData.apply(this, _args(arguments));\n };\n /**\n * Sets the current HTML object that the Flash object should overlay. This will put the global\n * Flash object on top of the current element; depending on the setup, this may also set the\n * pending clipboard text data as well as the Flash object's wrapping element's title attribute\n * based on the underlying HTML element and ZeroClipboard configuration.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.focus = ZeroClipboard.activate = function() {\n return _focus.apply(this, _args(arguments));\n };\n /**\n * Un-overlays the Flash object. This will put the global Flash object off-screen; depending on\n * the setup, this may also unset the Flash object's wrapping element's title attribute based on\n * the underlying HTML element and ZeroClipboard configuration.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.blur = ZeroClipboard.deactivate = function() {\n return _blur.apply(this, _args(arguments));\n };\n /**\n * Returns the currently focused/\"activated\" HTML element that the Flash object is wrapping.\n *\n * @returns `HTMLElement` or `null`\n * @static\n */\n ZeroClipboard.activeElement = function() {\n return _activeElement.apply(this, _args(arguments));\n };\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return ZeroClipboard;\n });\n } else if (typeof module === \"object\" && module && typeof module.exports === \"object\" && module.exports) {\n module.exports = ZeroClipboard;\n } else {\n window.ZeroClipboard = ZeroClipboard;\n }\n})(function() {\n return this || window;\n}());"]} \ No newline at end of file diff --git a/resources/zeroclipboard/ZeroClipboard.js b/resources/zeroclipboard/ZeroClipboard.js new file mode 100644 index 0000000000..6e20b5910f --- /dev/null +++ b/resources/zeroclipboard/ZeroClipboard.js @@ -0,0 +1,2581 @@ +/*! + * ZeroClipboard + * The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface. + * Copyright (c) 2009-2014 Jon Rohan, James M. Greene + * Licensed MIT + * http://zeroclipboard.org/ + * v2.2.0 + */ +(function(window, undefined) { + "use strict"; + /** + * Store references to critically important global functions that may be + * overridden on certain web pages. + */ + var _window = window, _document = _window.document, _navigator = _window.navigator, _setTimeout = _window.setTimeout, _clearTimeout = _window.clearTimeout, _setInterval = _window.setInterval, _clearInterval = _window.clearInterval, _getComputedStyle = _window.getComputedStyle, _encodeURIComponent = _window.encodeURIComponent, _ActiveXObject = _window.ActiveXObject, _Error = _window.Error, _parseInt = _window.Number.parseInt || _window.parseInt, _parseFloat = _window.Number.parseFloat || _window.parseFloat, _isNaN = _window.Number.isNaN || _window.isNaN, _now = _window.Date.now, _keys = _window.Object.keys, _defineProperty = _window.Object.defineProperty, _hasOwn = _window.Object.prototype.hasOwnProperty, _slice = _window.Array.prototype.slice, _unwrap = function() { + var unwrapper = function(el) { + return el; + }; + if (typeof _window.wrap === "function" && typeof _window.unwrap === "function") { + try { + var div = _document.createElement("div"); + var unwrappedDiv = _window.unwrap(div); + if (div.nodeType === 1 && unwrappedDiv && unwrappedDiv.nodeType === 1) { + unwrapper = _window.unwrap; + } + } catch (e) {} + } + return unwrapper; + }(); + /** + * Convert an `arguments` object into an Array. + * + * @returns The arguments as an Array + * @private + */ + var _args = function(argumentsObj) { + return _slice.call(argumentsObj, 0); + }; + /** + * Shallow-copy the owned, enumerable properties of one object over to another, similar to jQuery's `$.extend`. + * + * @returns The target object, augmented + * @private + */ + var _extend = function() { + var i, len, arg, prop, src, copy, args = _args(arguments), target = args[0] || {}; + for (i = 1, len = args.length; i < len; i++) { + if ((arg = args[i]) != null) { + for (prop in arg) { + if (_hasOwn.call(arg, prop)) { + src = target[prop]; + copy = arg[prop]; + if (target !== copy && copy !== undefined) { + target[prop] = copy; + } + } + } + } + } + return target; + }; + /** + * Return a deep copy of the source object or array. + * + * @returns Object or Array + * @private + */ + var _deepCopy = function(source) { + var copy, i, len, prop; + if (typeof source !== "object" || source == null || typeof source.nodeType === "number") { + copy = source; + } else if (typeof source.length === "number") { + copy = []; + for (i = 0, len = source.length; i < len; i++) { + if (_hasOwn.call(source, i)) { + copy[i] = _deepCopy(source[i]); + } + } + } else { + copy = {}; + for (prop in source) { + if (_hasOwn.call(source, prop)) { + copy[prop] = _deepCopy(source[prop]); + } + } + } + return copy; + }; + /** + * Makes a shallow copy of `obj` (like `_extend`) but filters its properties based on a list of `keys` to keep. + * The inverse of `_omit`, mostly. The big difference is that these properties do NOT need to be enumerable to + * be kept. + * + * @returns A new filtered object. + * @private + */ + var _pick = function(obj, keys) { + var newObj = {}; + for (var i = 0, len = keys.length; i < len; i++) { + if (keys[i] in obj) { + newObj[keys[i]] = obj[keys[i]]; + } + } + return newObj; + }; + /** + * Makes a shallow copy of `obj` (like `_extend`) but filters its properties based on a list of `keys` to omit. + * The inverse of `_pick`. + * + * @returns A new filtered object. + * @private + */ + var _omit = function(obj, keys) { + var newObj = {}; + for (var prop in obj) { + if (keys.indexOf(prop) === -1) { + newObj[prop] = obj[prop]; + } + } + return newObj; + }; + /** + * Remove all owned, enumerable properties from an object. + * + * @returns The original object without its owned, enumerable properties. + * @private + */ + var _deleteOwnProperties = function(obj) { + if (obj) { + for (var prop in obj) { + if (_hasOwn.call(obj, prop)) { + delete obj[prop]; + } + } + } + return obj; + }; + /** + * Determine if an element is contained within another element. + * + * @returns Boolean + * @private + */ + var _containedBy = function(el, ancestorEl) { + if (el && el.nodeType === 1 && el.ownerDocument && ancestorEl && (ancestorEl.nodeType === 1 && ancestorEl.ownerDocument && ancestorEl.ownerDocument === el.ownerDocument || ancestorEl.nodeType === 9 && !ancestorEl.ownerDocument && ancestorEl === el.ownerDocument)) { + do { + if (el === ancestorEl) { + return true; + } + el = el.parentNode; + } while (el); + } + return false; + }; + /** + * Get the URL path's parent directory. + * + * @returns String or `undefined` + * @private + */ + var _getDirPathOfUrl = function(url) { + var dir; + if (typeof url === "string" && url) { + dir = url.split("#")[0].split("?")[0]; + dir = url.slice(0, url.lastIndexOf("/") + 1); + } + return dir; + }; + /** + * Get the current script's URL by throwing an `Error` and analyzing it. + * + * @returns String or `undefined` + * @private + */ + var _getCurrentScriptUrlFromErrorStack = function(stack) { + var url, matches; + if (typeof stack === "string" && stack) { + matches = stack.match(/^(?:|[^:@]*@|.+\)@(?=http[s]?|file)|.+?\s+(?: at |@)(?:[^:\(]+ )*[\(]?)((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/); + if (matches && matches[1]) { + url = matches[1]; + } else { + matches = stack.match(/\)@((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/); + if (matches && matches[1]) { + url = matches[1]; + } + } + } + return url; + }; + /** + * Get the current script's URL by throwing an `Error` and analyzing it. + * + * @returns String or `undefined` + * @private + */ + var _getCurrentScriptUrlFromError = function() { + var url, err; + try { + throw new _Error(); + } catch (e) { + err = e; + } + if (err) { + url = err.sourceURL || err.fileName || _getCurrentScriptUrlFromErrorStack(err.stack); + } + return url; + }; + /** + * Get the current script's URL. + * + * @returns String or `undefined` + * @private + */ + var _getCurrentScriptUrl = function() { + var jsPath, scripts, i; + if (_document.currentScript && (jsPath = _document.currentScript.src)) { + return jsPath; + } + scripts = _document.getElementsByTagName("script"); + if (scripts.length === 1) { + return scripts[0].src || undefined; + } + if ("readyState" in scripts[0]) { + for (i = scripts.length; i--; ) { + if (scripts[i].readyState === "interactive" && (jsPath = scripts[i].src)) { + return jsPath; + } + } + } + if (_document.readyState === "loading" && (jsPath = scripts[scripts.length - 1].src)) { + return jsPath; + } + if (jsPath = _getCurrentScriptUrlFromError()) { + return jsPath; + } + return undefined; + }; + /** + * Get the unanimous parent directory of ALL script tags. + * If any script tags are either (a) inline or (b) from differing parent + * directories, this method must return `undefined`. + * + * @returns String or `undefined` + * @private + */ + var _getUnanimousScriptParentDir = function() { + var i, jsDir, jsPath, scripts = _document.getElementsByTagName("script"); + for (i = scripts.length; i--; ) { + if (!(jsPath = scripts[i].src)) { + jsDir = null; + break; + } + jsPath = _getDirPathOfUrl(jsPath); + if (jsDir == null) { + jsDir = jsPath; + } else if (jsDir !== jsPath) { + jsDir = null; + break; + } + } + return jsDir || undefined; + }; + /** + * Get the presumed location of the "ZeroClipboard.swf" file, based on the location + * of the executing JavaScript file (e.g. "ZeroClipboard.js", etc.). + * + * @returns String + * @private + */ + var _getDefaultSwfPath = function() { + var jsDir = _getDirPathOfUrl(_getCurrentScriptUrl()) || _getUnanimousScriptParentDir() || ""; + return jsDir + "ZeroClipboard.swf"; + }; + /** + * Keep track of if the page is framed (in an `iframe`). This can never change. + * @private + */ + var _pageIsFramed = function() { + return window.opener == null && (!!window.top && window != window.top || !!window.parent && window != window.parent); + }(); + /** + * Keep track of the state of the Flash object. + * @private + */ + var _flashState = { + bridge: null, + version: "0.0.0", + pluginType: "unknown", + disabled: null, + outdated: null, + sandboxed: null, + unavailable: null, + degraded: null, + deactivated: null, + overdue: null, + ready: null + }; + /** + * The minimum Flash Player version required to use ZeroClipboard completely. + * @readonly + * @private + */ + var _minimumFlashVersion = "11.0.0"; + /** + * The ZeroClipboard library version number, as reported by Flash, at the time the SWF was compiled. + */ + var _zcSwfVersion; + /** + * Keep track of all event listener registrations. + * @private + */ + var _handlers = {}; + /** + * Keep track of the currently activated element. + * @private + */ + var _currentElement; + /** + * Keep track of the element that was activated when a `copy` process started. + * @private + */ + var _copyTarget; + /** + * Keep track of data for the pending clipboard transaction. + * @private + */ + var _clipData = {}; + /** + * Keep track of data formats for the pending clipboard transaction. + * @private + */ + var _clipDataFormatMap = null; + /** + * Keep track of the Flash availability check timeout. + * @private + */ + var _flashCheckTimeout = 0; + /** + * Keep track of SWF network errors interval polling. + * @private + */ + var _swfFallbackCheckInterval = 0; + /** + * The `message` store for events + * @private + */ + var _eventMessages = { + ready: "Flash communication is established", + error: { + "flash-disabled": "Flash is disabled or not installed. May also be attempting to run Flash in a sandboxed iframe, which is impossible.", + "flash-outdated": "Flash is too outdated to support ZeroClipboard", + "flash-sandboxed": "Attempting to run Flash in a sandboxed iframe, which is impossible", + "flash-unavailable": "Flash is unable to communicate bidirectionally with JavaScript", + "flash-degraded": "Flash is unable to preserve data fidelity when communicating with JavaScript", + "flash-deactivated": "Flash is too outdated for your browser and/or is configured as click-to-activate.\nThis may also mean that the ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity.\nMay also be attempting to run Flash in a sandboxed iframe, which is impossible.", + "flash-overdue": "Flash communication was established but NOT within the acceptable time limit", + "version-mismatch": "ZeroClipboard JS version number does not match ZeroClipboard SWF version number", + "clipboard-error": "At least one error was thrown while ZeroClipboard was attempting to inject your data into the clipboard", + "config-mismatch": "ZeroClipboard configuration does not match Flash's reality", + "swf-not-found": "The ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity" + } + }; + /** + * The `name`s of `error` events that can only occur is Flash has at least + * been able to load the SWF successfully. + * @private + */ + var _errorsThatOnlyOccurAfterFlashLoads = [ "flash-unavailable", "flash-degraded", "flash-overdue", "version-mismatch", "config-mismatch", "clipboard-error" ]; + /** + * The `name`s of `error` events that should likely result in the `_flashState` + * variable's property values being updated. + * @private + */ + var _flashStateErrorNames = [ "flash-disabled", "flash-outdated", "flash-sandboxed", "flash-unavailable", "flash-degraded", "flash-deactivated", "flash-overdue" ]; + /** + * A RegExp to match the `name` property of `error` events related to Flash. + * @private + */ + var _flashStateErrorNameMatchingRegex = new RegExp("^flash-(" + _flashStateErrorNames.map(function(errorName) { + return errorName.replace(/^flash-/, ""); + }).join("|") + ")$"); + /** + * A RegExp to match the `name` property of `error` events related to Flash, + * which is enabled. + * @private + */ + var _flashStateEnabledErrorNameMatchingRegex = new RegExp("^flash-(" + _flashStateErrorNames.slice(1).map(function(errorName) { + return errorName.replace(/^flash-/, ""); + }).join("|") + ")$"); + /** + * ZeroClipboard configuration defaults for the Core module. + * @private + */ + var _globalConfig = { + swfPath: _getDefaultSwfPath(), + trustedDomains: window.location.host ? [ window.location.host ] : [], + cacheBust: true, + forceEnhancedClipboard: false, + flashLoadTimeout: 3e4, + autoActivate: true, + bubbleEvents: true, + containerId: "global-zeroclipboard-html-bridge", + containerClass: "global-zeroclipboard-container", + swfObjectId: "global-zeroclipboard-flash-bridge", + hoverClass: "zeroclipboard-is-hover", + activeClass: "zeroclipboard-is-active", + forceHandCursor: false, + title: null, + zIndex: 999999999 + }; + /** + * The underlying implementation of `ZeroClipboard.config`. + * @private + */ + var _config = function(options) { + if (typeof options === "object" && options !== null) { + for (var prop in options) { + if (_hasOwn.call(options, prop)) { + if (/^(?:forceHandCursor|title|zIndex|bubbleEvents)$/.test(prop)) { + _globalConfig[prop] = options[prop]; + } else if (_flashState.bridge == null) { + if (prop === "containerId" || prop === "swfObjectId") { + if (_isValidHtml4Id(options[prop])) { + _globalConfig[prop] = options[prop]; + } else { + throw new Error("The specified `" + prop + "` value is not valid as an HTML4 Element ID"); + } + } else { + _globalConfig[prop] = options[prop]; + } + } + } + } + } + if (typeof options === "string" && options) { + if (_hasOwn.call(_globalConfig, options)) { + return _globalConfig[options]; + } + return; + } + return _deepCopy(_globalConfig); + }; + /** + * The underlying implementation of `ZeroClipboard.state`. + * @private + */ + var _state = function() { + _detectSandbox(); + return { + browser: _pick(_navigator, [ "userAgent", "platform", "appName" ]), + flash: _omit(_flashState, [ "bridge" ]), + zeroclipboard: { + version: ZeroClipboard.version, + config: ZeroClipboard.config() + } + }; + }; + /** + * The underlying implementation of `ZeroClipboard.isFlashUnusable`. + * @private + */ + var _isFlashUnusable = function() { + return !!(_flashState.disabled || _flashState.outdated || _flashState.sandboxed || _flashState.unavailable || _flashState.degraded || _flashState.deactivated); + }; + /** + * The underlying implementation of `ZeroClipboard.on`. + * @private + */ + var _on = function(eventType, listener) { + var i, len, events, added = {}; + if (typeof eventType === "string" && eventType) { + events = eventType.toLowerCase().split(/\s+/); + } else if (typeof eventType === "object" && eventType && typeof listener === "undefined") { + for (i in eventType) { + if (_hasOwn.call(eventType, i) && typeof i === "string" && i && typeof eventType[i] === "function") { + ZeroClipboard.on(i, eventType[i]); + } + } + } + if (events && events.length) { + for (i = 0, len = events.length; i < len; i++) { + eventType = events[i].replace(/^on/, ""); + added[eventType] = true; + if (!_handlers[eventType]) { + _handlers[eventType] = []; + } + _handlers[eventType].push(listener); + } + if (added.ready && _flashState.ready) { + ZeroClipboard.emit({ + type: "ready" + }); + } + if (added.error) { + for (i = 0, len = _flashStateErrorNames.length; i < len; i++) { + if (_flashState[_flashStateErrorNames[i].replace(/^flash-/, "")] === true) { + ZeroClipboard.emit({ + type: "error", + name: _flashStateErrorNames[i] + }); + break; + } + } + if (_zcSwfVersion !== undefined && ZeroClipboard.version !== _zcSwfVersion) { + ZeroClipboard.emit({ + type: "error", + name: "version-mismatch", + jsVersion: ZeroClipboard.version, + swfVersion: _zcSwfVersion + }); + } + } + } + return ZeroClipboard; + }; + /** + * The underlying implementation of `ZeroClipboard.off`. + * @private + */ + var _off = function(eventType, listener) { + var i, len, foundIndex, events, perEventHandlers; + if (arguments.length === 0) { + events = _keys(_handlers); + } else if (typeof eventType === "string" && eventType) { + events = eventType.split(/\s+/); + } else if (typeof eventType === "object" && eventType && typeof listener === "undefined") { + for (i in eventType) { + if (_hasOwn.call(eventType, i) && typeof i === "string" && i && typeof eventType[i] === "function") { + ZeroClipboard.off(i, eventType[i]); + } + } + } + if (events && events.length) { + for (i = 0, len = events.length; i < len; i++) { + eventType = events[i].toLowerCase().replace(/^on/, ""); + perEventHandlers = _handlers[eventType]; + if (perEventHandlers && perEventHandlers.length) { + if (listener) { + foundIndex = perEventHandlers.indexOf(listener); + while (foundIndex !== -1) { + perEventHandlers.splice(foundIndex, 1); + foundIndex = perEventHandlers.indexOf(listener, foundIndex); + } + } else { + perEventHandlers.length = 0; + } + } + } + } + return ZeroClipboard; + }; + /** + * The underlying implementation of `ZeroClipboard.handlers`. + * @private + */ + var _listeners = function(eventType) { + var copy; + if (typeof eventType === "string" && eventType) { + copy = _deepCopy(_handlers[eventType]) || null; + } else { + copy = _deepCopy(_handlers); + } + return copy; + }; + /** + * The underlying implementation of `ZeroClipboard.emit`. + * @private + */ + var _emit = function(event) { + var eventCopy, returnVal, tmp; + event = _createEvent(event); + if (!event) { + return; + } + if (_preprocessEvent(event)) { + return; + } + if (event.type === "ready" && _flashState.overdue === true) { + return ZeroClipboard.emit({ + type: "error", + name: "flash-overdue" + }); + } + eventCopy = _extend({}, event); + _dispatchCallbacks.call(this, eventCopy); + if (event.type === "copy") { + tmp = _mapClipDataToFlash(_clipData); + returnVal = tmp.data; + _clipDataFormatMap = tmp.formatMap; + } + return returnVal; + }; + /** + * The underlying implementation of `ZeroClipboard.create`. + * @private + */ + var _create = function() { + var previousState = _flashState.sandboxed; + _detectSandbox(); + if (typeof _flashState.ready !== "boolean") { + _flashState.ready = false; + } + if (_flashState.sandboxed !== previousState && _flashState.sandboxed === true) { + _flashState.ready = false; + ZeroClipboard.emit({ + type: "error", + name: "flash-sandboxed" + }); + } else if (!ZeroClipboard.isFlashUnusable() && _flashState.bridge === null) { + var maxWait = _globalConfig.flashLoadTimeout; + if (typeof maxWait === "number" && maxWait >= 0) { + _flashCheckTimeout = _setTimeout(function() { + if (typeof _flashState.deactivated !== "boolean") { + _flashState.deactivated = true; + } + if (_flashState.deactivated === true) { + ZeroClipboard.emit({ + type: "error", + name: "flash-deactivated" + }); + } + }, maxWait); + } + _flashState.overdue = false; + _embedSwf(); + } + }; + /** + * The underlying implementation of `ZeroClipboard.destroy`. + * @private + */ + var _destroy = function() { + ZeroClipboard.clearData(); + ZeroClipboard.blur(); + ZeroClipboard.emit("destroy"); + _unembedSwf(); + ZeroClipboard.off(); + }; + /** + * The underlying implementation of `ZeroClipboard.setData`. + * @private + */ + var _setData = function(format, data) { + var dataObj; + if (typeof format === "object" && format && typeof data === "undefined") { + dataObj = format; + ZeroClipboard.clearData(); + } else if (typeof format === "string" && format) { + dataObj = {}; + dataObj[format] = data; + } else { + return; + } + for (var dataFormat in dataObj) { + if (typeof dataFormat === "string" && dataFormat && _hasOwn.call(dataObj, dataFormat) && typeof dataObj[dataFormat] === "string" && dataObj[dataFormat]) { + _clipData[dataFormat] = dataObj[dataFormat]; + } + } + }; + /** + * The underlying implementation of `ZeroClipboard.clearData`. + * @private + */ + var _clearData = function(format) { + if (typeof format === "undefined") { + _deleteOwnProperties(_clipData); + _clipDataFormatMap = null; + } else if (typeof format === "string" && _hasOwn.call(_clipData, format)) { + delete _clipData[format]; + } + }; + /** + * The underlying implementation of `ZeroClipboard.getData`. + * @private + */ + var _getData = function(format) { + if (typeof format === "undefined") { + return _deepCopy(_clipData); + } else if (typeof format === "string" && _hasOwn.call(_clipData, format)) { + return _clipData[format]; + } + }; + /** + * The underlying implementation of `ZeroClipboard.focus`/`ZeroClipboard.activate`. + * @private + */ + var _focus = function(element) { + if (!(element && element.nodeType === 1)) { + return; + } + if (_currentElement) { + _removeClass(_currentElement, _globalConfig.activeClass); + if (_currentElement !== element) { + _removeClass(_currentElement, _globalConfig.hoverClass); + } + } + _currentElement = element; + _addClass(element, _globalConfig.hoverClass); + var newTitle = element.getAttribute("title") || _globalConfig.title; + if (typeof newTitle === "string" && newTitle) { + var htmlBridge = _getHtmlBridge(_flashState.bridge); + if (htmlBridge) { + htmlBridge.setAttribute("title", newTitle); + } + } + var useHandCursor = _globalConfig.forceHandCursor === true || _getStyle(element, "cursor") === "pointer"; + _setHandCursor(useHandCursor); + _reposition(); + }; + /** + * The underlying implementation of `ZeroClipboard.blur`/`ZeroClipboard.deactivate`. + * @private + */ + var _blur = function() { + var htmlBridge = _getHtmlBridge(_flashState.bridge); + if (htmlBridge) { + htmlBridge.removeAttribute("title"); + htmlBridge.style.left = "0px"; + htmlBridge.style.top = "-9999px"; + htmlBridge.style.width = "1px"; + htmlBridge.style.height = "1px"; + } + if (_currentElement) { + _removeClass(_currentElement, _globalConfig.hoverClass); + _removeClass(_currentElement, _globalConfig.activeClass); + _currentElement = null; + } + }; + /** + * The underlying implementation of `ZeroClipboard.activeElement`. + * @private + */ + var _activeElement = function() { + return _currentElement || null; + }; + /** + * Check if a value is a valid HTML4 `ID` or `Name` token. + * @private + */ + var _isValidHtml4Id = function(id) { + return typeof id === "string" && id && /^[A-Za-z][A-Za-z0-9_:\-\.]*$/.test(id); + }; + /** + * Create or update an `event` object, based on the `eventType`. + * @private + */ + var _createEvent = function(event) { + var eventType; + if (typeof event === "string" && event) { + eventType = event; + event = {}; + } else if (typeof event === "object" && event && typeof event.type === "string" && event.type) { + eventType = event.type; + } + if (!eventType) { + return; + } + eventType = eventType.toLowerCase(); + if (!event.target && (/^(copy|aftercopy|_click)$/.test(eventType) || eventType === "error" && event.name === "clipboard-error")) { + event.target = _copyTarget; + } + _extend(event, { + type: eventType, + target: event.target || _currentElement || null, + relatedTarget: event.relatedTarget || null, + currentTarget: _flashState && _flashState.bridge || null, + timeStamp: event.timeStamp || _now() || null + }); + var msg = _eventMessages[event.type]; + if (event.type === "error" && event.name && msg) { + msg = msg[event.name]; + } + if (msg) { + event.message = msg; + } + if (event.type === "ready") { + _extend(event, { + target: null, + version: _flashState.version + }); + } + if (event.type === "error") { + if (_flashStateErrorNameMatchingRegex.test(event.name)) { + _extend(event, { + target: null, + minimumVersion: _minimumFlashVersion + }); + } + if (_flashStateEnabledErrorNameMatchingRegex.test(event.name)) { + _extend(event, { + version: _flashState.version + }); + } + } + if (event.type === "copy") { + event.clipboardData = { + setData: ZeroClipboard.setData, + clearData: ZeroClipboard.clearData + }; + } + if (event.type === "aftercopy") { + event = _mapClipResultsFromFlash(event, _clipDataFormatMap); + } + if (event.target && !event.relatedTarget) { + event.relatedTarget = _getRelatedTarget(event.target); + } + return _addMouseData(event); + }; + /** + * Get a relatedTarget from the target's `data-clipboard-target` attribute + * @private + */ + var _getRelatedTarget = function(targetEl) { + var relatedTargetId = targetEl && targetEl.getAttribute && targetEl.getAttribute("data-clipboard-target"); + return relatedTargetId ? _document.getElementById(relatedTargetId) : null; + }; + /** + * Add element and position data to `MouseEvent` instances + * @private + */ + var _addMouseData = function(event) { + if (event && /^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) { + var srcElement = event.target; + var fromElement = event.type === "_mouseover" && event.relatedTarget ? event.relatedTarget : undefined; + var toElement = event.type === "_mouseout" && event.relatedTarget ? event.relatedTarget : undefined; + var pos = _getElementPosition(srcElement); + var screenLeft = _window.screenLeft || _window.screenX || 0; + var screenTop = _window.screenTop || _window.screenY || 0; + var scrollLeft = _document.body.scrollLeft + _document.documentElement.scrollLeft; + var scrollTop = _document.body.scrollTop + _document.documentElement.scrollTop; + var pageX = pos.left + (typeof event._stageX === "number" ? event._stageX : 0); + var pageY = pos.top + (typeof event._stageY === "number" ? event._stageY : 0); + var clientX = pageX - scrollLeft; + var clientY = pageY - scrollTop; + var screenX = screenLeft + clientX; + var screenY = screenTop + clientY; + var moveX = typeof event.movementX === "number" ? event.movementX : 0; + var moveY = typeof event.movementY === "number" ? event.movementY : 0; + delete event._stageX; + delete event._stageY; + _extend(event, { + srcElement: srcElement, + fromElement: fromElement, + toElement: toElement, + screenX: screenX, + screenY: screenY, + pageX: pageX, + pageY: pageY, + clientX: clientX, + clientY: clientY, + x: clientX, + y: clientY, + movementX: moveX, + movementY: moveY, + offsetX: 0, + offsetY: 0, + layerX: 0, + layerY: 0 + }); + } + return event; + }; + /** + * Determine if an event's registered handlers should be execute synchronously or asynchronously. + * + * @returns {boolean} + * @private + */ + var _shouldPerformAsync = function(event) { + var eventType = event && typeof event.type === "string" && event.type || ""; + return !/^(?:(?:before)?copy|destroy)$/.test(eventType); + }; + /** + * Control if a callback should be executed asynchronously or not. + * + * @returns `undefined` + * @private + */ + var _dispatchCallback = function(func, context, args, async) { + if (async) { + _setTimeout(function() { + func.apply(context, args); + }, 0); + } else { + func.apply(context, args); + } + }; + /** + * Handle the actual dispatching of events to client instances. + * + * @returns `undefined` + * @private + */ + var _dispatchCallbacks = function(event) { + if (!(typeof event === "object" && event && event.type)) { + return; + } + var async = _shouldPerformAsync(event); + var wildcardTypeHandlers = _handlers["*"] || []; + var specificTypeHandlers = _handlers[event.type] || []; + var handlers = wildcardTypeHandlers.concat(specificTypeHandlers); + if (handlers && handlers.length) { + var i, len, func, context, eventCopy, originalContext = this; + for (i = 0, len = handlers.length; i < len; i++) { + func = handlers[i]; + context = originalContext; + if (typeof func === "string" && typeof _window[func] === "function") { + func = _window[func]; + } + if (typeof func === "object" && func && typeof func.handleEvent === "function") { + context = func; + func = func.handleEvent; + } + if (typeof func === "function") { + eventCopy = _extend({}, event); + _dispatchCallback(func, context, [ eventCopy ], async); + } + } + } + return this; + }; + /** + * Check an `error` event's `name` property to see if Flash has + * already loaded, which rules out possible `iframe` sandboxing. + * @private + */ + var _getSandboxStatusFromErrorEvent = function(event) { + var isSandboxed = null; + if (_pageIsFramed === false || event && event.type === "error" && event.name && _errorsThatOnlyOccurAfterFlashLoads.indexOf(event.name) !== -1) { + isSandboxed = false; + } + return isSandboxed; + }; + /** + * Preprocess any special behaviors, reactions, or state changes after receiving this event. + * Executes only once per event emitted, NOT once per client. + * @private + */ + var _preprocessEvent = function(event) { + var element = event.target || _currentElement || null; + var sourceIsSwf = event._source === "swf"; + delete event._source; + switch (event.type) { + case "error": + var isSandboxed = event.name === "flash-sandboxed" || _getSandboxStatusFromErrorEvent(event); + if (typeof isSandboxed === "boolean") { + _flashState.sandboxed = isSandboxed; + } + if (_flashStateErrorNames.indexOf(event.name) !== -1) { + _extend(_flashState, { + disabled: event.name === "flash-disabled", + outdated: event.name === "flash-outdated", + unavailable: event.name === "flash-unavailable", + degraded: event.name === "flash-degraded", + deactivated: event.name === "flash-deactivated", + overdue: event.name === "flash-overdue", + ready: false + }); + } else if (event.name === "version-mismatch") { + _zcSwfVersion = event.swfVersion; + _extend(_flashState, { + disabled: false, + outdated: false, + unavailable: false, + degraded: false, + deactivated: false, + overdue: false, + ready: false + }); + } + _clearTimeoutsAndPolling(); + break; + + case "ready": + _zcSwfVersion = event.swfVersion; + var wasDeactivated = _flashState.deactivated === true; + _extend(_flashState, { + disabled: false, + outdated: false, + sandboxed: false, + unavailable: false, + degraded: false, + deactivated: false, + overdue: wasDeactivated, + ready: !wasDeactivated + }); + _clearTimeoutsAndPolling(); + break; + + case "beforecopy": + _copyTarget = element; + break; + + case "copy": + var textContent, htmlContent, targetEl = event.relatedTarget; + if (!(_clipData["text/html"] || _clipData["text/plain"]) && targetEl && (htmlContent = targetEl.value || targetEl.outerHTML || targetEl.innerHTML) && (textContent = targetEl.value || targetEl.textContent || targetEl.innerText)) { + event.clipboardData.clearData(); + event.clipboardData.setData("text/plain", textContent); + if (htmlContent !== textContent) { + event.clipboardData.setData("text/html", htmlContent); + } + } else if (!_clipData["text/plain"] && event.target && (textContent = event.target.getAttribute("data-clipboard-text"))) { + event.clipboardData.clearData(); + event.clipboardData.setData("text/plain", textContent); + } + break; + + case "aftercopy": + _queueEmitClipboardErrors(event); + ZeroClipboard.clearData(); + if (element && element !== _safeActiveElement() && element.focus) { + element.focus(); + } + break; + + case "_mouseover": + ZeroClipboard.focus(element); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) { + _fireMouseEvent(_extend({}, event, { + type: "mouseenter", + bubbles: false, + cancelable: false + })); + } + _fireMouseEvent(_extend({}, event, { + type: "mouseover" + })); + } + break; + + case "_mouseout": + ZeroClipboard.blur(); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) { + _fireMouseEvent(_extend({}, event, { + type: "mouseleave", + bubbles: false, + cancelable: false + })); + } + _fireMouseEvent(_extend({}, event, { + type: "mouseout" + })); + } + break; + + case "_mousedown": + _addClass(element, _globalConfig.activeClass); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; + + case "_mouseup": + _removeClass(element, _globalConfig.activeClass); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; + + case "_click": + _copyTarget = null; + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; + + case "_mousemove": + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; + } + if (/^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) { + return true; + } + }; + /** + * Check an "aftercopy" event for clipboard errors and emit a corresponding "error" event. + * @private + */ + var _queueEmitClipboardErrors = function(aftercopyEvent) { + if (aftercopyEvent.errors && aftercopyEvent.errors.length > 0) { + var errorEvent = _deepCopy(aftercopyEvent); + _extend(errorEvent, { + type: "error", + name: "clipboard-error" + }); + delete errorEvent.success; + _setTimeout(function() { + ZeroClipboard.emit(errorEvent); + }, 0); + } + }; + /** + * Dispatch a synthetic MouseEvent. + * + * @returns `undefined` + * @private + */ + var _fireMouseEvent = function(event) { + if (!(event && typeof event.type === "string" && event)) { + return; + } + var e, target = event.target || null, doc = target && target.ownerDocument || _document, defaults = { + view: doc.defaultView || _window, + canBubble: true, + cancelable: true, + detail: event.type === "click" ? 1 : 0, + button: typeof event.which === "number" ? event.which - 1 : typeof event.button === "number" ? event.button : doc.createEvent ? 0 : 1 + }, args = _extend(defaults, event); + if (!target) { + return; + } + if (doc.createEvent && target.dispatchEvent) { + args = [ args.type, args.canBubble, args.cancelable, args.view, args.detail, args.screenX, args.screenY, args.clientX, args.clientY, args.ctrlKey, args.altKey, args.shiftKey, args.metaKey, args.button, args.relatedTarget ]; + e = doc.createEvent("MouseEvents"); + if (e.initMouseEvent) { + e.initMouseEvent.apply(e, args); + e._source = "js"; + target.dispatchEvent(e); + } + } + }; + /** + * Continuously poll the DOM until either: + * (a) the fallback content becomes visible, or + * (b) we receive an event from SWF (handled elsewhere) + * + * IMPORTANT: + * This is NOT a necessary check but it can result in significantly faster + * detection of bad `swfPath` configuration and/or network/server issues [in + * supported browsers] than waiting for the entire `flashLoadTimeout` duration + * to elapse before detecting that the SWF cannot be loaded. The detection + * duration can be anywhere from 10-30 times faster [in supported browsers] by + * using this approach. + * + * @returns `undefined` + * @private + */ + var _watchForSwfFallbackContent = function() { + var maxWait = _globalConfig.flashLoadTimeout; + if (typeof maxWait === "number" && maxWait >= 0) { + var pollWait = Math.min(1e3, maxWait / 10); + var fallbackContentId = _globalConfig.swfObjectId + "_fallbackContent"; + _swfFallbackCheckInterval = _setInterval(function() { + var el = _document.getElementById(fallbackContentId); + if (_isElementVisible(el)) { + _clearTimeoutsAndPolling(); + _flashState.deactivated = null; + ZeroClipboard.emit({ + type: "error", + name: "swf-not-found" + }); + } + }, pollWait); + } + }; + /** + * Create the HTML bridge element to embed the Flash object into. + * @private + */ + var _createHtmlBridge = function() { + var container = _document.createElement("div"); + container.id = _globalConfig.containerId; + container.className = _globalConfig.containerClass; + container.style.position = "absolute"; + container.style.left = "0px"; + container.style.top = "-9999px"; + container.style.width = "1px"; + container.style.height = "1px"; + container.style.zIndex = "" + _getSafeZIndex(_globalConfig.zIndex); + return container; + }; + /** + * Get the HTML element container that wraps the Flash bridge object/element. + * @private + */ + var _getHtmlBridge = function(flashBridge) { + var htmlBridge = flashBridge && flashBridge.parentNode; + while (htmlBridge && htmlBridge.nodeName === "OBJECT" && htmlBridge.parentNode) { + htmlBridge = htmlBridge.parentNode; + } + return htmlBridge || null; + }; + /** + * Create the SWF object. + * + * @returns The SWF object reference. + * @private + */ + var _embedSwf = function() { + var len, flashBridge = _flashState.bridge, container = _getHtmlBridge(flashBridge); + if (!flashBridge) { + var allowScriptAccess = _determineScriptAccess(_window.location.host, _globalConfig); + var allowNetworking = allowScriptAccess === "never" ? "none" : "all"; + var flashvars = _vars(_extend({ + jsVersion: ZeroClipboard.version + }, _globalConfig)); + var swfUrl = _globalConfig.swfPath + _cacheBust(_globalConfig.swfPath, _globalConfig); + container = _createHtmlBridge(); + var divToBeReplaced = _document.createElement("div"); + container.appendChild(divToBeReplaced); + _document.body.appendChild(container); + var tmpDiv = _document.createElement("div"); + var usingActiveX = _flashState.pluginType === "activex"; + tmpDiv.innerHTML = '" + (usingActiveX ? '' : "") + '' + '' + '' + '' + '' + '
 
' + "
"; + flashBridge = tmpDiv.firstChild; + tmpDiv = null; + _unwrap(flashBridge).ZeroClipboard = ZeroClipboard; + container.replaceChild(flashBridge, divToBeReplaced); + _watchForSwfFallbackContent(); + } + if (!flashBridge) { + flashBridge = _document[_globalConfig.swfObjectId]; + if (flashBridge && (len = flashBridge.length)) { + flashBridge = flashBridge[len - 1]; + } + if (!flashBridge && container) { + flashBridge = container.firstChild; + } + } + _flashState.bridge = flashBridge || null; + return flashBridge; + }; + /** + * Destroy the SWF object. + * @private + */ + var _unembedSwf = function() { + var flashBridge = _flashState.bridge; + if (flashBridge) { + var htmlBridge = _getHtmlBridge(flashBridge); + if (htmlBridge) { + if (_flashState.pluginType === "activex" && "readyState" in flashBridge) { + flashBridge.style.display = "none"; + (function removeSwfFromIE() { + if (flashBridge.readyState === 4) { + for (var prop in flashBridge) { + if (typeof flashBridge[prop] === "function") { + flashBridge[prop] = null; + } + } + if (flashBridge.parentNode) { + flashBridge.parentNode.removeChild(flashBridge); + } + if (htmlBridge.parentNode) { + htmlBridge.parentNode.removeChild(htmlBridge); + } + } else { + _setTimeout(removeSwfFromIE, 10); + } + })(); + } else { + if (flashBridge.parentNode) { + flashBridge.parentNode.removeChild(flashBridge); + } + if (htmlBridge.parentNode) { + htmlBridge.parentNode.removeChild(htmlBridge); + } + } + } + _clearTimeoutsAndPolling(); + _flashState.ready = null; + _flashState.bridge = null; + _flashState.deactivated = null; + _zcSwfVersion = undefined; + } + }; + /** + * Map the data format names of the "clipData" to Flash-friendly names. + * + * @returns A new transformed object. + * @private + */ + var _mapClipDataToFlash = function(clipData) { + var newClipData = {}, formatMap = {}; + if (!(typeof clipData === "object" && clipData)) { + return; + } + for (var dataFormat in clipData) { + if (dataFormat && _hasOwn.call(clipData, dataFormat) && typeof clipData[dataFormat] === "string" && clipData[dataFormat]) { + switch (dataFormat.toLowerCase()) { + case "text/plain": + case "text": + case "air:text": + case "flash:text": + newClipData.text = clipData[dataFormat]; + formatMap.text = dataFormat; + break; + + case "text/html": + case "html": + case "air:html": + case "flash:html": + newClipData.html = clipData[dataFormat]; + formatMap.html = dataFormat; + break; + + case "application/rtf": + case "text/rtf": + case "rtf": + case "richtext": + case "air:rtf": + case "flash:rtf": + newClipData.rtf = clipData[dataFormat]; + formatMap.rtf = dataFormat; + break; + + default: + break; + } + } + } + return { + data: newClipData, + formatMap: formatMap + }; + }; + /** + * Map the data format names from Flash-friendly names back to their original "clipData" names (via a format mapping). + * + * @returns A new transformed object. + * @private + */ + var _mapClipResultsFromFlash = function(clipResults, formatMap) { + if (!(typeof clipResults === "object" && clipResults && typeof formatMap === "object" && formatMap)) { + return clipResults; + } + var newResults = {}; + for (var prop in clipResults) { + if (_hasOwn.call(clipResults, prop)) { + if (prop === "errors") { + newResults[prop] = clipResults[prop] ? clipResults[prop].slice() : []; + for (var i = 0, len = newResults[prop].length; i < len; i++) { + newResults[prop][i].format = formatMap[newResults[prop][i].format]; + } + } else if (prop !== "success" && prop !== "data") { + newResults[prop] = clipResults[prop]; + } else { + newResults[prop] = {}; + var tmpHash = clipResults[prop]; + for (var dataFormat in tmpHash) { + if (dataFormat && _hasOwn.call(tmpHash, dataFormat) && _hasOwn.call(formatMap, dataFormat)) { + newResults[prop][formatMap[dataFormat]] = tmpHash[dataFormat]; + } + } + } + } + } + return newResults; + }; + /** + * Will look at a path, and will create a "?noCache={time}" or "&noCache={time}" + * query param string to return. Does NOT append that string to the original path. + * This is useful because ExternalInterface often breaks when a Flash SWF is cached. + * + * @returns The `noCache` query param with necessary "?"/"&" prefix. + * @private + */ + var _cacheBust = function(path, options) { + var cacheBust = options == null || options && options.cacheBust === true; + if (cacheBust) { + return (path.indexOf("?") === -1 ? "?" : "&") + "noCache=" + _now(); + } else { + return ""; + } + }; + /** + * Creates a query string for the FlashVars param. + * Does NOT include the cache-busting query param. + * + * @returns FlashVars query string + * @private + */ + var _vars = function(options) { + var i, len, domain, domains, str = "", trustedOriginsExpanded = []; + if (options.trustedDomains) { + if (typeof options.trustedDomains === "string") { + domains = [ options.trustedDomains ]; + } else if (typeof options.trustedDomains === "object" && "length" in options.trustedDomains) { + domains = options.trustedDomains; + } + } + if (domains && domains.length) { + for (i = 0, len = domains.length; i < len; i++) { + if (_hasOwn.call(domains, i) && domains[i] && typeof domains[i] === "string") { + domain = _extractDomain(domains[i]); + if (!domain) { + continue; + } + if (domain === "*") { + trustedOriginsExpanded.length = 0; + trustedOriginsExpanded.push(domain); + break; + } + trustedOriginsExpanded.push.apply(trustedOriginsExpanded, [ domain, "//" + domain, _window.location.protocol + "//" + domain ]); + } + } + } + if (trustedOriginsExpanded.length) { + str += "trustedOrigins=" + _encodeURIComponent(trustedOriginsExpanded.join(",")); + } + if (options.forceEnhancedClipboard === true) { + str += (str ? "&" : "") + "forceEnhancedClipboard=true"; + } + if (typeof options.swfObjectId === "string" && options.swfObjectId) { + str += (str ? "&" : "") + "swfObjectId=" + _encodeURIComponent(options.swfObjectId); + } + if (typeof options.jsVersion === "string" && options.jsVersion) { + str += (str ? "&" : "") + "jsVersion=" + _encodeURIComponent(options.jsVersion); + } + return str; + }; + /** + * Extract the domain (e.g. "github.com") from an origin (e.g. "https://github.com") or + * URL (e.g. "https://github.com/zeroclipboard/zeroclipboard/"). + * + * @returns the domain + * @private + */ + var _extractDomain = function(originOrUrl) { + if (originOrUrl == null || originOrUrl === "") { + return null; + } + originOrUrl = originOrUrl.replace(/^\s+|\s+$/g, ""); + if (originOrUrl === "") { + return null; + } + var protocolIndex = originOrUrl.indexOf("//"); + originOrUrl = protocolIndex === -1 ? originOrUrl : originOrUrl.slice(protocolIndex + 2); + var pathIndex = originOrUrl.indexOf("/"); + originOrUrl = pathIndex === -1 ? originOrUrl : protocolIndex === -1 || pathIndex === 0 ? null : originOrUrl.slice(0, pathIndex); + if (originOrUrl && originOrUrl.slice(-4).toLowerCase() === ".swf") { + return null; + } + return originOrUrl || null; + }; + /** + * Set `allowScriptAccess` based on `trustedDomains` and `window.location.host` vs. `swfPath`. + * + * @returns The appropriate script access level. + * @private + */ + var _determineScriptAccess = function() { + var _extractAllDomains = function(origins) { + var i, len, tmp, resultsArray = []; + if (typeof origins === "string") { + origins = [ origins ]; + } + if (!(typeof origins === "object" && origins && typeof origins.length === "number")) { + return resultsArray; + } + for (i = 0, len = origins.length; i < len; i++) { + if (_hasOwn.call(origins, i) && (tmp = _extractDomain(origins[i]))) { + if (tmp === "*") { + resultsArray.length = 0; + resultsArray.push("*"); + break; + } + if (resultsArray.indexOf(tmp) === -1) { + resultsArray.push(tmp); + } + } + } + return resultsArray; + }; + return function(currentDomain, configOptions) { + var swfDomain = _extractDomain(configOptions.swfPath); + if (swfDomain === null) { + swfDomain = currentDomain; + } + var trustedDomains = _extractAllDomains(configOptions.trustedDomains); + var len = trustedDomains.length; + if (len > 0) { + if (len === 1 && trustedDomains[0] === "*") { + return "always"; + } + if (trustedDomains.indexOf(currentDomain) !== -1) { + if (len === 1 && currentDomain === swfDomain) { + return "sameDomain"; + } + return "always"; + } + } + return "never"; + }; + }(); + /** + * Get the currently active/focused DOM element. + * + * @returns the currently active/focused element, or `null` + * @private + */ + var _safeActiveElement = function() { + try { + return _document.activeElement; + } catch (err) { + return null; + } + }; + /** + * Add a class to an element, if it doesn't already have it. + * + * @returns The element, with its new class added. + * @private + */ + var _addClass = function(element, value) { + var c, cl, className, classNames = []; + if (typeof value === "string" && value) { + classNames = value.split(/\s+/); + } + if (element && element.nodeType === 1 && classNames.length > 0) { + if (element.classList) { + for (c = 0, cl = classNames.length; c < cl; c++) { + element.classList.add(classNames[c]); + } + } else if (element.hasOwnProperty("className")) { + className = " " + element.className + " "; + for (c = 0, cl = classNames.length; c < cl; c++) { + if (className.indexOf(" " + classNames[c] + " ") === -1) { + className += classNames[c] + " "; + } + } + element.className = className.replace(/^\s+|\s+$/g, ""); + } + } + return element; + }; + /** + * Remove a class from an element, if it has it. + * + * @returns The element, with its class removed. + * @private + */ + var _removeClass = function(element, value) { + var c, cl, className, classNames = []; + if (typeof value === "string" && value) { + classNames = value.split(/\s+/); + } + if (element && element.nodeType === 1 && classNames.length > 0) { + if (element.classList && element.classList.length > 0) { + for (c = 0, cl = classNames.length; c < cl; c++) { + element.classList.remove(classNames[c]); + } + } else if (element.className) { + className = (" " + element.className + " ").replace(/[\r\n\t]/g, " "); + for (c = 0, cl = classNames.length; c < cl; c++) { + className = className.replace(" " + classNames[c] + " ", " "); + } + element.className = className.replace(/^\s+|\s+$/g, ""); + } + } + return element; + }; + /** + * Attempt to interpret the element's CSS styling. If `prop` is `"cursor"`, + * then we assume that it should be a hand ("pointer") cursor if the element + * is an anchor element ("a" tag). + * + * @returns The computed style property. + * @private + */ + var _getStyle = function(el, prop) { + var value = _getComputedStyle(el, null).getPropertyValue(prop); + if (prop === "cursor") { + if (!value || value === "auto") { + if (el.nodeName === "A") { + return "pointer"; + } + } + } + return value; + }; + /** + * Get the absolutely positioned coordinates of a DOM element. + * + * @returns Object containing the element's position, width, and height. + * @private + */ + var _getElementPosition = function(el) { + var pos = { + left: 0, + top: 0, + width: 0, + height: 0 + }; + if (el.getBoundingClientRect) { + var elRect = el.getBoundingClientRect(); + var pageXOffset = _window.pageXOffset; + var pageYOffset = _window.pageYOffset; + var leftBorderWidth = _document.documentElement.clientLeft || 0; + var topBorderWidth = _document.documentElement.clientTop || 0; + var leftBodyOffset = 0; + var topBodyOffset = 0; + if (_getStyle(_document.body, "position") === "relative") { + var bodyRect = _document.body.getBoundingClientRect(); + var htmlRect = _document.documentElement.getBoundingClientRect(); + leftBodyOffset = bodyRect.left - htmlRect.left || 0; + topBodyOffset = bodyRect.top - htmlRect.top || 0; + } + pos.left = elRect.left + pageXOffset - leftBorderWidth - leftBodyOffset; + pos.top = elRect.top + pageYOffset - topBorderWidth - topBodyOffset; + pos.width = "width" in elRect ? elRect.width : elRect.right - elRect.left; + pos.height = "height" in elRect ? elRect.height : elRect.bottom - elRect.top; + } + return pos; + }; + /** + * Determine is an element is visible somewhere within the document (page). + * + * @returns Boolean + * @private + */ + var _isElementVisible = function(el) { + if (!el) { + return false; + } + var styles = _getComputedStyle(el, null); + var hasCssHeight = _parseFloat(styles.height) > 0; + var hasCssWidth = _parseFloat(styles.width) > 0; + var hasCssTop = _parseFloat(styles.top) >= 0; + var hasCssLeft = _parseFloat(styles.left) >= 0; + var cssKnows = hasCssHeight && hasCssWidth && hasCssTop && hasCssLeft; + var rect = cssKnows ? null : _getElementPosition(el); + var isVisible = styles.display !== "none" && styles.visibility !== "collapse" && (cssKnows || !!rect && (hasCssHeight || rect.height > 0) && (hasCssWidth || rect.width > 0) && (hasCssTop || rect.top >= 0) && (hasCssLeft || rect.left >= 0)); + return isVisible; + }; + /** + * Clear all existing timeouts and interval polling delegates. + * + * @returns `undefined` + * @private + */ + var _clearTimeoutsAndPolling = function() { + _clearTimeout(_flashCheckTimeout); + _flashCheckTimeout = 0; + _clearInterval(_swfFallbackCheckInterval); + _swfFallbackCheckInterval = 0; + }; + /** + * Reposition the Flash object to cover the currently activated element. + * + * @returns `undefined` + * @private + */ + var _reposition = function() { + var htmlBridge; + if (_currentElement && (htmlBridge = _getHtmlBridge(_flashState.bridge))) { + var pos = _getElementPosition(_currentElement); + _extend(htmlBridge.style, { + width: pos.width + "px", + height: pos.height + "px", + top: pos.top + "px", + left: pos.left + "px", + zIndex: "" + _getSafeZIndex(_globalConfig.zIndex) + }); + } + }; + /** + * Sends a signal to the Flash object to display the hand cursor if `true`. + * + * @returns `undefined` + * @private + */ + var _setHandCursor = function(enabled) { + if (_flashState.ready === true) { + if (_flashState.bridge && typeof _flashState.bridge.setHandCursor === "function") { + _flashState.bridge.setHandCursor(enabled); + } else { + _flashState.ready = false; + } + } + }; + /** + * Get a safe value for `zIndex` + * + * @returns an integer, or "auto" + * @private + */ + var _getSafeZIndex = function(val) { + if (/^(?:auto|inherit)$/.test(val)) { + return val; + } + var zIndex; + if (typeof val === "number" && !_isNaN(val)) { + zIndex = val; + } else if (typeof val === "string") { + zIndex = _getSafeZIndex(_parseInt(val, 10)); + } + return typeof zIndex === "number" ? zIndex : "auto"; + }; + /** + * Attempt to detect if ZeroClipboard is executing inside of a sandboxed iframe. + * If it is, Flash Player cannot be used, so ZeroClipboard is dead in the water. + * + * @see {@link http://lists.w3.org/Archives/Public/public-whatwg-archive/2014Dec/0002.html} + * @see {@link https://github.com/zeroclipboard/zeroclipboard/issues/511} + * @see {@link http://zeroclipboard.org/test-iframes.html} + * + * @returns `true` (is sandboxed), `false` (is not sandboxed), or `null` (uncertain) + * @private + */ + var _detectSandbox = function(doNotReassessFlashSupport) { + var effectiveScriptOrigin, frame, frameError, previousState = _flashState.sandboxed, isSandboxed = null; + doNotReassessFlashSupport = doNotReassessFlashSupport === true; + if (_pageIsFramed === false) { + isSandboxed = false; + } else { + try { + frame = window.frameElement || null; + } catch (e) { + frameError = { + name: e.name, + message: e.message + }; + } + if (frame && frame.nodeType === 1 && frame.nodeName === "IFRAME") { + try { + isSandboxed = frame.hasAttribute("sandbox"); + } catch (e) { + isSandboxed = null; + } + } else { + try { + effectiveScriptOrigin = document.domain || null; + } catch (e) { + effectiveScriptOrigin = null; + } + if (effectiveScriptOrigin === null || frameError && frameError.name === "SecurityError" && /(^|[\s\(\[@])sandbox(es|ed|ing|[\s\.,!\)\]@]|$)/.test(frameError.message.toLowerCase())) { + isSandboxed = true; + } + } + } + _flashState.sandboxed = isSandboxed; + if (previousState !== isSandboxed && !doNotReassessFlashSupport) { + _detectFlashSupport(_ActiveXObject); + } + return isSandboxed; + }; + /** + * Detect the Flash Player status, version, and plugin type. + * + * @see {@link https://code.google.com/p/doctype-mirror/wiki/ArticleDetectFlash#The_code} + * @see {@link http://stackoverflow.com/questions/12866060/detecting-pepper-ppapi-flash-with-javascript} + * + * @returns `undefined` + * @private + */ + var _detectFlashSupport = function(ActiveXObject) { + var plugin, ax, mimeType, hasFlash = false, isActiveX = false, isPPAPI = false, flashVersion = ""; + /** + * Derived from Apple's suggested sniffer. + * @param {String} desc e.g. "Shockwave Flash 7.0 r61" + * @returns {String} "7.0.61" + * @private + */ + function parseFlashVersion(desc) { + var matches = desc.match(/[\d]+/g); + matches.length = 3; + return matches.join("."); + } + function isPepperFlash(flashPlayerFileName) { + return !!flashPlayerFileName && (flashPlayerFileName = flashPlayerFileName.toLowerCase()) && (/^(pepflashplayer\.dll|libpepflashplayer\.so|pepperflashplayer\.plugin)$/.test(flashPlayerFileName) || flashPlayerFileName.slice(-13) === "chrome.plugin"); + } + function inspectPlugin(plugin) { + if (plugin) { + hasFlash = true; + if (plugin.version) { + flashVersion = parseFlashVersion(plugin.version); + } + if (!flashVersion && plugin.description) { + flashVersion = parseFlashVersion(plugin.description); + } + if (plugin.filename) { + isPPAPI = isPepperFlash(plugin.filename); + } + } + } + if (_navigator.plugins && _navigator.plugins.length) { + plugin = _navigator.plugins["Shockwave Flash"]; + inspectPlugin(plugin); + if (_navigator.plugins["Shockwave Flash 2.0"]) { + hasFlash = true; + flashVersion = "2.0.0.11"; + } + } else if (_navigator.mimeTypes && _navigator.mimeTypes.length) { + mimeType = _navigator.mimeTypes["application/x-shockwave-flash"]; + plugin = mimeType && mimeType.enabledPlugin; + inspectPlugin(plugin); + } else if (typeof ActiveXObject !== "undefined") { + isActiveX = true; + try { + ax = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); + hasFlash = true; + flashVersion = parseFlashVersion(ax.GetVariable("$version")); + } catch (e1) { + try { + ax = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); + hasFlash = true; + flashVersion = "6.0.21"; + } catch (e2) { + try { + ax = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); + hasFlash = true; + flashVersion = parseFlashVersion(ax.GetVariable("$version")); + } catch (e3) { + isActiveX = false; + } + } + } + } + _flashState.disabled = hasFlash !== true; + _flashState.outdated = flashVersion && _parseFloat(flashVersion) < _parseFloat(_minimumFlashVersion); + _flashState.version = flashVersion || "0.0.0"; + _flashState.pluginType = isPPAPI ? "pepper" : isActiveX ? "activex" : hasFlash ? "netscape" : "unknown"; + }; + /** + * Invoke the Flash detection algorithms immediately upon inclusion so we're not waiting later. + */ + _detectFlashSupport(_ActiveXObject); + /** + * Always assess the `sandboxed` state of the page at important Flash-related moments. + */ + _detectSandbox(true); + /** + * A shell constructor for `ZeroClipboard` client instances. + * + * @constructor + */ + var ZeroClipboard = function() { + if (!(this instanceof ZeroClipboard)) { + return new ZeroClipboard(); + } + if (typeof ZeroClipboard._createClient === "function") { + ZeroClipboard._createClient.apply(this, _args(arguments)); + } + }; + /** + * The ZeroClipboard library's version number. + * + * @static + * @readonly + * @property {string} + */ + _defineProperty(ZeroClipboard, "version", { + value: "2.2.0", + writable: false, + configurable: true, + enumerable: true + }); + /** + * Update or get a copy of the ZeroClipboard global configuration. + * Returns a copy of the current/updated configuration. + * + * @returns Object + * @static + */ + ZeroClipboard.config = function() { + return _config.apply(this, _args(arguments)); + }; + /** + * Diagnostic method that describes the state of the browser, Flash Player, and ZeroClipboard. + * + * @returns Object + * @static + */ + ZeroClipboard.state = function() { + return _state.apply(this, _args(arguments)); + }; + /** + * Check if Flash is unusable for any reason: disabled, outdated, deactivated, etc. + * + * @returns Boolean + * @static + */ + ZeroClipboard.isFlashUnusable = function() { + return _isFlashUnusable.apply(this, _args(arguments)); + }; + /** + * Register an event listener. + * + * @returns `ZeroClipboard` + * @static + */ + ZeroClipboard.on = function() { + return _on.apply(this, _args(arguments)); + }; + /** + * Unregister an event listener. + * If no `listener` function/object is provided, it will unregister all listeners for the provided `eventType`. + * If no `eventType` is provided, it will unregister all listeners for every event type. + * + * @returns `ZeroClipboard` + * @static + */ + ZeroClipboard.off = function() { + return _off.apply(this, _args(arguments)); + }; + /** + * Retrieve event listeners for an `eventType`. + * If no `eventType` is provided, it will retrieve all listeners for every event type. + * + * @returns array of listeners for the `eventType`; if no `eventType`, then a map/hash object of listeners for all event types; or `null` + */ + ZeroClipboard.handlers = function() { + return _listeners.apply(this, _args(arguments)); + }; + /** + * Event emission receiver from the Flash object, forwarding to any registered JavaScript event listeners. + * + * @returns For the "copy" event, returns the Flash-friendly "clipData" object; otherwise `undefined`. + * @static + */ + ZeroClipboard.emit = function() { + return _emit.apply(this, _args(arguments)); + }; + /** + * Create and embed the Flash object. + * + * @returns The Flash object + * @static + */ + ZeroClipboard.create = function() { + return _create.apply(this, _args(arguments)); + }; + /** + * Self-destruct and clean up everything, including the embedded Flash object. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.destroy = function() { + return _destroy.apply(this, _args(arguments)); + }; + /** + * Set the pending data for clipboard injection. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.setData = function() { + return _setData.apply(this, _args(arguments)); + }; + /** + * Clear the pending data for clipboard injection. + * If no `format` is provided, all pending data formats will be cleared. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.clearData = function() { + return _clearData.apply(this, _args(arguments)); + }; + /** + * Get a copy of the pending data for clipboard injection. + * If no `format` is provided, a copy of ALL pending data formats will be returned. + * + * @returns `String` or `Object` + * @static + */ + ZeroClipboard.getData = function() { + return _getData.apply(this, _args(arguments)); + }; + /** + * Sets the current HTML object that the Flash object should overlay. This will put the global + * Flash object on top of the current element; depending on the setup, this may also set the + * pending clipboard text data as well as the Flash object's wrapping element's title attribute + * based on the underlying HTML element and ZeroClipboard configuration. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.focus = ZeroClipboard.activate = function() { + return _focus.apply(this, _args(arguments)); + }; + /** + * Un-overlays the Flash object. This will put the global Flash object off-screen; depending on + * the setup, this may also unset the Flash object's wrapping element's title attribute based on + * the underlying HTML element and ZeroClipboard configuration. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.blur = ZeroClipboard.deactivate = function() { + return _blur.apply(this, _args(arguments)); + }; + /** + * Returns the currently focused/"activated" HTML element that the Flash object is wrapping. + * + * @returns `HTMLElement` or `null` + * @static + */ + ZeroClipboard.activeElement = function() { + return _activeElement.apply(this, _args(arguments)); + }; + /** + * Keep track of the ZeroClipboard client instance counter. + */ + var _clientIdCounter = 0; + /** + * Keep track of the state of the client instances. + * + * Entry structure: + * _clientMeta[client.id] = { + * instance: client, + * elements: [], + * handlers: {} + * }; + */ + var _clientMeta = {}; + /** + * Keep track of the ZeroClipboard clipped elements counter. + */ + var _elementIdCounter = 0; + /** + * Keep track of the state of the clipped element relationships to clients. + * + * Entry structure: + * _elementMeta[element.zcClippingId] = [client1.id, client2.id]; + */ + var _elementMeta = {}; + /** + * Keep track of the state of the mouse event handlers for clipped elements. + * + * Entry structure: + * _mouseHandlers[element.zcClippingId] = { + * mouseover: function(event) {}, + * mouseout: function(event) {}, + * mouseenter: function(event) {}, + * mouseleave: function(event) {}, + * mousemove: function(event) {} + * }; + */ + var _mouseHandlers = {}; + /** + * Extending the ZeroClipboard configuration defaults for the Client module. + */ + _extend(_globalConfig, { + autoActivate: true + }); + /** + * The real constructor for `ZeroClipboard` client instances. + * @private + */ + var _clientConstructor = function(elements) { + var client = this; + client.id = "" + _clientIdCounter++; + _clientMeta[client.id] = { + instance: client, + elements: [], + handlers: {} + }; + if (elements) { + client.clip(elements); + } + ZeroClipboard.on("*", function(event) { + return client.emit(event); + }); + ZeroClipboard.on("destroy", function() { + client.destroy(); + }); + ZeroClipboard.create(); + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.on`. + * @private + */ + var _clientOn = function(eventType, listener) { + var i, len, events, added = {}, meta = _clientMeta[this.id], handlers = meta && meta.handlers; + if (!meta) { + throw new Error("Attempted to add new listener(s) to a destroyed ZeroClipboard client instance"); + } + if (typeof eventType === "string" && eventType) { + events = eventType.toLowerCase().split(/\s+/); + } else if (typeof eventType === "object" && eventType && typeof listener === "undefined") { + for (i in eventType) { + if (_hasOwn.call(eventType, i) && typeof i === "string" && i && typeof eventType[i] === "function") { + this.on(i, eventType[i]); + } + } + } + if (events && events.length) { + for (i = 0, len = events.length; i < len; i++) { + eventType = events[i].replace(/^on/, ""); + added[eventType] = true; + if (!handlers[eventType]) { + handlers[eventType] = []; + } + handlers[eventType].push(listener); + } + if (added.ready && _flashState.ready) { + this.emit({ + type: "ready", + client: this + }); + } + if (added.error) { + for (i = 0, len = _flashStateErrorNames.length; i < len; i++) { + if (_flashState[_flashStateErrorNames[i].replace(/^flash-/, "")]) { + this.emit({ + type: "error", + name: _flashStateErrorNames[i], + client: this + }); + break; + } + } + if (_zcSwfVersion !== undefined && ZeroClipboard.version !== _zcSwfVersion) { + this.emit({ + type: "error", + name: "version-mismatch", + jsVersion: ZeroClipboard.version, + swfVersion: _zcSwfVersion + }); + } + } + } + return this; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.off`. + * @private + */ + var _clientOff = function(eventType, listener) { + var i, len, foundIndex, events, perEventHandlers, meta = _clientMeta[this.id], handlers = meta && meta.handlers; + if (!handlers) { + return this; + } + if (arguments.length === 0) { + events = _keys(handlers); + } else if (typeof eventType === "string" && eventType) { + events = eventType.split(/\s+/); + } else if (typeof eventType === "object" && eventType && typeof listener === "undefined") { + for (i in eventType) { + if (_hasOwn.call(eventType, i) && typeof i === "string" && i && typeof eventType[i] === "function") { + this.off(i, eventType[i]); + } + } + } + if (events && events.length) { + for (i = 0, len = events.length; i < len; i++) { + eventType = events[i].toLowerCase().replace(/^on/, ""); + perEventHandlers = handlers[eventType]; + if (perEventHandlers && perEventHandlers.length) { + if (listener) { + foundIndex = perEventHandlers.indexOf(listener); + while (foundIndex !== -1) { + perEventHandlers.splice(foundIndex, 1); + foundIndex = perEventHandlers.indexOf(listener, foundIndex); + } + } else { + perEventHandlers.length = 0; + } + } + } + } + return this; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.handlers`. + * @private + */ + var _clientListeners = function(eventType) { + var copy = null, handlers = _clientMeta[this.id] && _clientMeta[this.id].handlers; + if (handlers) { + if (typeof eventType === "string" && eventType) { + copy = handlers[eventType] ? handlers[eventType].slice(0) : []; + } else { + copy = _deepCopy(handlers); + } + } + return copy; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.emit`. + * @private + */ + var _clientEmit = function(event) { + if (_clientShouldEmit.call(this, event)) { + if (typeof event === "object" && event && typeof event.type === "string" && event.type) { + event = _extend({}, event); + } + var eventCopy = _extend({}, _createEvent(event), { + client: this + }); + _clientDispatchCallbacks.call(this, eventCopy); + } + return this; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.clip`. + * @private + */ + var _clientClip = function(elements) { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to clip element(s) to a destroyed ZeroClipboard client instance"); + } + elements = _prepClip(elements); + for (var i = 0; i < elements.length; i++) { + if (_hasOwn.call(elements, i) && elements[i] && elements[i].nodeType === 1) { + if (!elements[i].zcClippingId) { + elements[i].zcClippingId = "zcClippingId_" + _elementIdCounter++; + _elementMeta[elements[i].zcClippingId] = [ this.id ]; + if (_globalConfig.autoActivate === true) { + _addMouseHandlers(elements[i]); + } + } else if (_elementMeta[elements[i].zcClippingId].indexOf(this.id) === -1) { + _elementMeta[elements[i].zcClippingId].push(this.id); + } + var clippedElements = _clientMeta[this.id] && _clientMeta[this.id].elements; + if (clippedElements.indexOf(elements[i]) === -1) { + clippedElements.push(elements[i]); + } + } + } + return this; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.unclip`. + * @private + */ + var _clientUnclip = function(elements) { + var meta = _clientMeta[this.id]; + if (!meta) { + return this; + } + var clippedElements = meta.elements; + var arrayIndex; + if (typeof elements === "undefined") { + elements = clippedElements.slice(0); + } else { + elements = _prepClip(elements); + } + for (var i = elements.length; i--; ) { + if (_hasOwn.call(elements, i) && elements[i] && elements[i].nodeType === 1) { + arrayIndex = 0; + while ((arrayIndex = clippedElements.indexOf(elements[i], arrayIndex)) !== -1) { + clippedElements.splice(arrayIndex, 1); + } + var clientIds = _elementMeta[elements[i].zcClippingId]; + if (clientIds) { + arrayIndex = 0; + while ((arrayIndex = clientIds.indexOf(this.id, arrayIndex)) !== -1) { + clientIds.splice(arrayIndex, 1); + } + if (clientIds.length === 0) { + if (_globalConfig.autoActivate === true) { + _removeMouseHandlers(elements[i]); + } + delete elements[i].zcClippingId; + } + } + } + } + return this; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.elements`. + * @private + */ + var _clientElements = function() { + var meta = _clientMeta[this.id]; + return meta && meta.elements ? meta.elements.slice(0) : []; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.destroy`. + * @private + */ + var _clientDestroy = function() { + if (!_clientMeta[this.id]) { + return; + } + this.unclip(); + this.off(); + delete _clientMeta[this.id]; + }; + /** + * Inspect an Event to see if the Client (`this`) should honor it for emission. + * @private + */ + var _clientShouldEmit = function(event) { + if (!(event && event.type)) { + return false; + } + if (event.client && event.client !== this) { + return false; + } + var meta = _clientMeta[this.id]; + var clippedEls = meta && meta.elements; + var hasClippedEls = !!clippedEls && clippedEls.length > 0; + var goodTarget = !event.target || hasClippedEls && clippedEls.indexOf(event.target) !== -1; + var goodRelTarget = event.relatedTarget && hasClippedEls && clippedEls.indexOf(event.relatedTarget) !== -1; + var goodClient = event.client && event.client === this; + if (!meta || !(goodTarget || goodRelTarget || goodClient)) { + return false; + } + return true; + }; + /** + * Handle the actual dispatching of events to a client instance. + * + * @returns `undefined` + * @private + */ + var _clientDispatchCallbacks = function(event) { + var meta = _clientMeta[this.id]; + if (!(typeof event === "object" && event && event.type && meta)) { + return; + } + var async = _shouldPerformAsync(event); + var wildcardTypeHandlers = meta && meta.handlers["*"] || []; + var specificTypeHandlers = meta && meta.handlers[event.type] || []; + var handlers = wildcardTypeHandlers.concat(specificTypeHandlers); + if (handlers && handlers.length) { + var i, len, func, context, eventCopy, originalContext = this; + for (i = 0, len = handlers.length; i < len; i++) { + func = handlers[i]; + context = originalContext; + if (typeof func === "string" && typeof _window[func] === "function") { + func = _window[func]; + } + if (typeof func === "object" && func && typeof func.handleEvent === "function") { + context = func; + func = func.handleEvent; + } + if (typeof func === "function") { + eventCopy = _extend({}, event); + _dispatchCallback(func, context, [ eventCopy ], async); + } + } + } + }; + /** + * Prepares the elements for clipping/unclipping. + * + * @returns An Array of elements. + * @private + */ + var _prepClip = function(elements) { + if (typeof elements === "string") { + elements = []; + } + return typeof elements.length !== "number" ? [ elements ] : elements; + }; + /** + * Add a `mouseover` handler function for a clipped element. + * + * @returns `undefined` + * @private + */ + var _addMouseHandlers = function(element) { + if (!(element && element.nodeType === 1)) { + return; + } + var _suppressMouseEvents = function(event) { + if (!(event || (event = _window.event))) { + return; + } + if (event._source !== "js") { + event.stopImmediatePropagation(); + event.preventDefault(); + } + delete event._source; + }; + var _elementMouseOver = function(event) { + if (!(event || (event = _window.event))) { + return; + } + _suppressMouseEvents(event); + ZeroClipboard.focus(element); + }; + element.addEventListener("mouseover", _elementMouseOver, false); + element.addEventListener("mouseout", _suppressMouseEvents, false); + element.addEventListener("mouseenter", _suppressMouseEvents, false); + element.addEventListener("mouseleave", _suppressMouseEvents, false); + element.addEventListener("mousemove", _suppressMouseEvents, false); + _mouseHandlers[element.zcClippingId] = { + mouseover: _elementMouseOver, + mouseout: _suppressMouseEvents, + mouseenter: _suppressMouseEvents, + mouseleave: _suppressMouseEvents, + mousemove: _suppressMouseEvents + }; + }; + /** + * Remove a `mouseover` handler function for a clipped element. + * + * @returns `undefined` + * @private + */ + var _removeMouseHandlers = function(element) { + if (!(element && element.nodeType === 1)) { + return; + } + var mouseHandlers = _mouseHandlers[element.zcClippingId]; + if (!(typeof mouseHandlers === "object" && mouseHandlers)) { + return; + } + var key, val, mouseEvents = [ "move", "leave", "enter", "out", "over" ]; + for (var i = 0, len = mouseEvents.length; i < len; i++) { + key = "mouse" + mouseEvents[i]; + val = mouseHandlers[key]; + if (typeof val === "function") { + element.removeEventListener(key, val, false); + } + } + delete _mouseHandlers[element.zcClippingId]; + }; + /** + * Creates a new ZeroClipboard client instance. + * Optionally, auto-`clip` an element or collection of elements. + * + * @constructor + */ + ZeroClipboard._createClient = function() { + _clientConstructor.apply(this, _args(arguments)); + }; + /** + * Register an event listener to the client. + * + * @returns `this` + */ + ZeroClipboard.prototype.on = function() { + return _clientOn.apply(this, _args(arguments)); + }; + /** + * Unregister an event handler from the client. + * If no `listener` function/object is provided, it will unregister all handlers for the provided `eventType`. + * If no `eventType` is provided, it will unregister all handlers for every event type. + * + * @returns `this` + */ + ZeroClipboard.prototype.off = function() { + return _clientOff.apply(this, _args(arguments)); + }; + /** + * Retrieve event listeners for an `eventType` from the client. + * If no `eventType` is provided, it will retrieve all listeners for every event type. + * + * @returns array of listeners for the `eventType`; if no `eventType`, then a map/hash object of listeners for all event types; or `null` + */ + ZeroClipboard.prototype.handlers = function() { + return _clientListeners.apply(this, _args(arguments)); + }; + /** + * Event emission receiver from the Flash object for this client's registered JavaScript event listeners. + * + * @returns For the "copy" event, returns the Flash-friendly "clipData" object; otherwise `undefined`. + */ + ZeroClipboard.prototype.emit = function() { + return _clientEmit.apply(this, _args(arguments)); + }; + /** + * Register clipboard actions for new element(s) to the client. + * + * @returns `this` + */ + ZeroClipboard.prototype.clip = function() { + return _clientClip.apply(this, _args(arguments)); + }; + /** + * Unregister the clipboard actions of previously registered element(s) on the page. + * If no elements are provided, ALL registered elements will be unregistered. + * + * @returns `this` + */ + ZeroClipboard.prototype.unclip = function() { + return _clientUnclip.apply(this, _args(arguments)); + }; + /** + * Get all of the elements to which this client is clipped. + * + * @returns array of clipped elements + */ + ZeroClipboard.prototype.elements = function() { + return _clientElements.apply(this, _args(arguments)); + }; + /** + * Self-destruct and clean up everything for a single client. + * This will NOT destroy the embedded Flash object. + * + * @returns `undefined` + */ + ZeroClipboard.prototype.destroy = function() { + return _clientDestroy.apply(this, _args(arguments)); + }; + /** + * Stores the pending plain text to inject into the clipboard. + * + * @returns `this` + */ + ZeroClipboard.prototype.setText = function(text) { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance"); + } + ZeroClipboard.setData("text/plain", text); + return this; + }; + /** + * Stores the pending HTML text to inject into the clipboard. + * + * @returns `this` + */ + ZeroClipboard.prototype.setHtml = function(html) { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance"); + } + ZeroClipboard.setData("text/html", html); + return this; + }; + /** + * Stores the pending rich text (RTF) to inject into the clipboard. + * + * @returns `this` + */ + ZeroClipboard.prototype.setRichText = function(richText) { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance"); + } + ZeroClipboard.setData("application/rtf", richText); + return this; + }; + /** + * Stores the pending data to inject into the clipboard. + * + * @returns `this` + */ + ZeroClipboard.prototype.setData = function() { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance"); + } + ZeroClipboard.setData.apply(this, _args(arguments)); + return this; + }; + /** + * Clears the pending data to inject into the clipboard. + * If no `format` is provided, all pending data formats will be cleared. + * + * @returns `this` + */ + ZeroClipboard.prototype.clearData = function() { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to clear pending clipboard data from a destroyed ZeroClipboard client instance"); + } + ZeroClipboard.clearData.apply(this, _args(arguments)); + return this; + }; + /** + * Gets a copy of the pending data to inject into the clipboard. + * If no `format` is provided, a copy of ALL pending data formats will be returned. + * + * @returns `String` or `Object` + */ + ZeroClipboard.prototype.getData = function() { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to get pending clipboard data from a destroyed ZeroClipboard client instance"); + } + return ZeroClipboard.getData.apply(this, _args(arguments)); + }; + if (typeof define === "function" && define.amd) { + define(function() { + return ZeroClipboard; + }); + } else if (typeof module === "object" && module && typeof module.exports === "object" && module.exports) { + module.exports = ZeroClipboard; + } else { + window.ZeroClipboard = ZeroClipboard; + } +})(function() { + return this || window; +}()); \ No newline at end of file diff --git a/resources/zeroclipboard/ZeroClipboard.min.js b/resources/zeroclipboard/ZeroClipboard.min.js new file mode 100644 index 0000000000..6ecd08854a --- /dev/null +++ b/resources/zeroclipboard/ZeroClipboard.min.js @@ -0,0 +1,10 @@ +/*! + * ZeroClipboard + * The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface. + * Copyright (c) 2009-2014 Jon Rohan, James M. Greene + * Licensed MIT + * http://zeroclipboard.org/ + * v2.2.0 + */ +!function(a,b){"use strict";var c,d,e,f=a,g=f.document,h=f.navigator,i=f.setTimeout,j=f.clearTimeout,k=f.setInterval,l=f.clearInterval,m=f.getComputedStyle,n=f.encodeURIComponent,o=f.ActiveXObject,p=f.Error,q=f.Number.parseInt||f.parseInt,r=f.Number.parseFloat||f.parseFloat,s=f.Number.isNaN||f.isNaN,t=f.Date.now,u=f.Object.keys,v=f.Object.defineProperty,w=f.Object.prototype.hasOwnProperty,x=f.Array.prototype.slice,y=function(){var a=function(a){return a};if("function"==typeof f.wrap&&"function"==typeof f.unwrap)try{var b=g.createElement("div"),c=f.unwrap(b);1===b.nodeType&&c&&1===c.nodeType&&(a=f.unwrap)}catch(d){}return a}(),z=function(a){return x.call(a,0)},A=function(){var a,c,d,e,f,g,h=z(arguments),i=h[0]||{};for(a=1,c=h.length;c>a;a++)if(null!=(d=h[a]))for(e in d)w.call(d,e)&&(f=i[e],g=d[e],i!==g&&g!==b&&(i[e]=g));return i},B=function(a){var b,c,d,e;if("object"!=typeof a||null==a||"number"==typeof a.nodeType)b=a;else if("number"==typeof a.length)for(b=[],c=0,d=a.length;d>c;c++)w.call(a,c)&&(b[c]=B(a[c]));else{b={};for(e in a)w.call(a,e)&&(b[e]=B(a[e]))}return b},C=function(a,b){for(var c={},d=0,e=b.length;e>d;d++)b[d]in a&&(c[b[d]]=a[b[d]]);return c},D=function(a,b){var c={};for(var d in a)-1===b.indexOf(d)&&(c[d]=a[d]);return c},E=function(a){if(a)for(var b in a)w.call(a,b)&&delete a[b];return a},F=function(a,b){if(a&&1===a.nodeType&&a.ownerDocument&&b&&(1===b.nodeType&&b.ownerDocument&&b.ownerDocument===a.ownerDocument||9===b.nodeType&&!b.ownerDocument&&b===a.ownerDocument))do{if(a===b)return!0;a=a.parentNode}while(a);return!1},G=function(a){var b;return"string"==typeof a&&a&&(b=a.split("#")[0].split("?")[0],b=a.slice(0,a.lastIndexOf("/")+1)),b},H=function(a){var b,c;return"string"==typeof a&&a&&(c=a.match(/^(?:|[^:@]*@|.+\)@(?=http[s]?|file)|.+?\s+(?: at |@)(?:[^:\(]+ )*[\(]?)((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/),c&&c[1]?b=c[1]:(c=a.match(/\)@((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/),c&&c[1]&&(b=c[1]))),b},I=function(){var a,b;try{throw new p}catch(c){b=c}return b&&(a=b.sourceURL||b.fileName||H(b.stack)),a},J=function(){var a,c,d;if(g.currentScript&&(a=g.currentScript.src))return a;if(c=g.getElementsByTagName("script"),1===c.length)return c[0].src||b;if("readyState"in c[0])for(d=c.length;d--;)if("interactive"===c[d].readyState&&(a=c[d].src))return a;return"loading"===g.readyState&&(a=c[c.length-1].src)?a:(a=I())?a:b},K=function(){var a,c,d,e=g.getElementsByTagName("script");for(a=e.length;a--;){if(!(d=e[a].src)){c=null;break}if(d=G(d),null==c)c=d;else if(c!==d){c=null;break}}return c||b},L=function(){var a=G(J())||K()||"";return a+"ZeroClipboard.swf"},M=function(){return null==a.opener&&(!!a.top&&a!=a.top||!!a.parent&&a!=a.parent)}(),N={bridge:null,version:"0.0.0",pluginType:"unknown",disabled:null,outdated:null,sandboxed:null,unavailable:null,degraded:null,deactivated:null,overdue:null,ready:null},O="11.0.0",P={},Q={},R=null,S=0,T=0,U={ready:"Flash communication is established",error:{"flash-disabled":"Flash is disabled or not installed. May also be attempting to run Flash in a sandboxed iframe, which is impossible.","flash-outdated":"Flash is too outdated to support ZeroClipboard","flash-sandboxed":"Attempting to run Flash in a sandboxed iframe, which is impossible","flash-unavailable":"Flash is unable to communicate bidirectionally with JavaScript","flash-degraded":"Flash is unable to preserve data fidelity when communicating with JavaScript","flash-deactivated":"Flash is too outdated for your browser and/or is configured as click-to-activate.\nThis may also mean that the ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity.\nMay also be attempting to run Flash in a sandboxed iframe, which is impossible.","flash-overdue":"Flash communication was established but NOT within the acceptable time limit","version-mismatch":"ZeroClipboard JS version number does not match ZeroClipboard SWF version number","clipboard-error":"At least one error was thrown while ZeroClipboard was attempting to inject your data into the clipboard","config-mismatch":"ZeroClipboard configuration does not match Flash's reality","swf-not-found":"The ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity"}},V=["flash-unavailable","flash-degraded","flash-overdue","version-mismatch","config-mismatch","clipboard-error"],W=["flash-disabled","flash-outdated","flash-sandboxed","flash-unavailable","flash-degraded","flash-deactivated","flash-overdue"],X=new RegExp("^flash-("+W.map(function(a){return a.replace(/^flash-/,"")}).join("|")+")$"),Y=new RegExp("^flash-("+W.slice(1).map(function(a){return a.replace(/^flash-/,"")}).join("|")+")$"),Z={swfPath:L(),trustedDomains:a.location.host?[a.location.host]:[],cacheBust:!0,forceEnhancedClipboard:!1,flashLoadTimeout:3e4,autoActivate:!0,bubbleEvents:!0,containerId:"global-zeroclipboard-html-bridge",containerClass:"global-zeroclipboard-container",swfObjectId:"global-zeroclipboard-flash-bridge",hoverClass:"zeroclipboard-is-hover",activeClass:"zeroclipboard-is-active",forceHandCursor:!1,title:null,zIndex:999999999},$=function(a){if("object"==typeof a&&null!==a)for(var b in a)if(w.call(a,b))if(/^(?:forceHandCursor|title|zIndex|bubbleEvents)$/.test(b))Z[b]=a[b];else if(null==N.bridge)if("containerId"===b||"swfObjectId"===b){if(!nb(a[b]))throw new Error("The specified `"+b+"` value is not valid as an HTML4 Element ID");Z[b]=a[b]}else Z[b]=a[b];{if("string"!=typeof a||!a)return B(Z);if(w.call(Z,a))return Z[a]}},_=function(){return Tb(),{browser:C(h,["userAgent","platform","appName"]),flash:D(N,["bridge"]),zeroclipboard:{version:Vb.version,config:Vb.config()}}},ab=function(){return!!(N.disabled||N.outdated||N.sandboxed||N.unavailable||N.degraded||N.deactivated)},bb=function(a,d){var e,f,g,h={};if("string"==typeof a&&a)g=a.toLowerCase().split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof d)for(e in a)w.call(a,e)&&"string"==typeof e&&e&&"function"==typeof a[e]&&Vb.on(e,a[e]);if(g&&g.length){for(e=0,f=g.length;f>e;e++)a=g[e].replace(/^on/,""),h[a]=!0,P[a]||(P[a]=[]),P[a].push(d);if(h.ready&&N.ready&&Vb.emit({type:"ready"}),h.error){for(e=0,f=W.length;f>e;e++)if(N[W[e].replace(/^flash-/,"")]===!0){Vb.emit({type:"error",name:W[e]});break}c!==b&&Vb.version!==c&&Vb.emit({type:"error",name:"version-mismatch",jsVersion:Vb.version,swfVersion:c})}}return Vb},cb=function(a,b){var c,d,e,f,g;if(0===arguments.length)f=u(P);else if("string"==typeof a&&a)f=a.split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof b)for(c in a)w.call(a,c)&&"string"==typeof c&&c&&"function"==typeof a[c]&&Vb.off(c,a[c]);if(f&&f.length)for(c=0,d=f.length;d>c;c++)if(a=f[c].toLowerCase().replace(/^on/,""),g=P[a],g&&g.length)if(b)for(e=g.indexOf(b);-1!==e;)g.splice(e,1),e=g.indexOf(b,e);else g.length=0;return Vb},db=function(a){var b;return b="string"==typeof a&&a?B(P[a])||null:B(P)},eb=function(a){var b,c,d;return a=ob(a),a&&!vb(a)?"ready"===a.type&&N.overdue===!0?Vb.emit({type:"error",name:"flash-overdue"}):(b=A({},a),tb.call(this,b),"copy"===a.type&&(d=Db(Q),c=d.data,R=d.formatMap),c):void 0},fb=function(){var a=N.sandboxed;if(Tb(),"boolean"!=typeof N.ready&&(N.ready=!1),N.sandboxed!==a&&N.sandboxed===!0)N.ready=!1,Vb.emit({type:"error",name:"flash-sandboxed"});else if(!Vb.isFlashUnusable()&&null===N.bridge){var b=Z.flashLoadTimeout;"number"==typeof b&&b>=0&&(S=i(function(){"boolean"!=typeof N.deactivated&&(N.deactivated=!0),N.deactivated===!0&&Vb.emit({type:"error",name:"flash-deactivated"})},b)),N.overdue=!1,Bb()}},gb=function(){Vb.clearData(),Vb.blur(),Vb.emit("destroy"),Cb(),Vb.off()},hb=function(a,b){var c;if("object"==typeof a&&a&&"undefined"==typeof b)c=a,Vb.clearData();else{if("string"!=typeof a||!a)return;c={},c[a]=b}for(var d in c)"string"==typeof d&&d&&w.call(c,d)&&"string"==typeof c[d]&&c[d]&&(Q[d]=c[d])},ib=function(a){"undefined"==typeof a?(E(Q),R=null):"string"==typeof a&&w.call(Q,a)&&delete Q[a]},jb=function(a){return"undefined"==typeof a?B(Q):"string"==typeof a&&w.call(Q,a)?Q[a]:void 0},kb=function(a){if(a&&1===a.nodeType){d&&(Lb(d,Z.activeClass),d!==a&&Lb(d,Z.hoverClass)),d=a,Kb(a,Z.hoverClass);var b=a.getAttribute("title")||Z.title;if("string"==typeof b&&b){var c=Ab(N.bridge);c&&c.setAttribute("title",b)}var e=Z.forceHandCursor===!0||"pointer"===Mb(a,"cursor");Rb(e),Qb()}},lb=function(){var a=Ab(N.bridge);a&&(a.removeAttribute("title"),a.style.left="0px",a.style.top="-9999px",a.style.width="1px",a.style.height="1px"),d&&(Lb(d,Z.hoverClass),Lb(d,Z.activeClass),d=null)},mb=function(){return d||null},nb=function(a){return"string"==typeof a&&a&&/^[A-Za-z][A-Za-z0-9_:\-\.]*$/.test(a)},ob=function(a){var b;if("string"==typeof a&&a?(b=a,a={}):"object"==typeof a&&a&&"string"==typeof a.type&&a.type&&(b=a.type),b){b=b.toLowerCase(),!a.target&&(/^(copy|aftercopy|_click)$/.test(b)||"error"===b&&"clipboard-error"===a.name)&&(a.target=e),A(a,{type:b,target:a.target||d||null,relatedTarget:a.relatedTarget||null,currentTarget:N&&N.bridge||null,timeStamp:a.timeStamp||t()||null});var c=U[a.type];return"error"===a.type&&a.name&&c&&(c=c[a.name]),c&&(a.message=c),"ready"===a.type&&A(a,{target:null,version:N.version}),"error"===a.type&&(X.test(a.name)&&A(a,{target:null,minimumVersion:O}),Y.test(a.name)&&A(a,{version:N.version})),"copy"===a.type&&(a.clipboardData={setData:Vb.setData,clearData:Vb.clearData}),"aftercopy"===a.type&&(a=Eb(a,R)),a.target&&!a.relatedTarget&&(a.relatedTarget=pb(a.target)),qb(a)}},pb=function(a){var b=a&&a.getAttribute&&a.getAttribute("data-clipboard-target");return b?g.getElementById(b):null},qb=function(a){if(a&&/^_(?:click|mouse(?:over|out|down|up|move))$/.test(a.type)){var c=a.target,d="_mouseover"===a.type&&a.relatedTarget?a.relatedTarget:b,e="_mouseout"===a.type&&a.relatedTarget?a.relatedTarget:b,h=Nb(c),i=f.screenLeft||f.screenX||0,j=f.screenTop||f.screenY||0,k=g.body.scrollLeft+g.documentElement.scrollLeft,l=g.body.scrollTop+g.documentElement.scrollTop,m=h.left+("number"==typeof a._stageX?a._stageX:0),n=h.top+("number"==typeof a._stageY?a._stageY:0),o=m-k,p=n-l,q=i+o,r=j+p,s="number"==typeof a.movementX?a.movementX:0,t="number"==typeof a.movementY?a.movementY:0;delete a._stageX,delete a._stageY,A(a,{srcElement:c,fromElement:d,toElement:e,screenX:q,screenY:r,pageX:m,pageY:n,clientX:o,clientY:p,x:o,y:p,movementX:s,movementY:t,offsetX:0,offsetY:0,layerX:0,layerY:0})}return a},rb=function(a){var b=a&&"string"==typeof a.type&&a.type||"";return!/^(?:(?:before)?copy|destroy)$/.test(b)},sb=function(a,b,c,d){d?i(function(){a.apply(b,c)},0):a.apply(b,c)},tb=function(a){if("object"==typeof a&&a&&a.type){var b=rb(a),c=P["*"]||[],d=P[a.type]||[],e=c.concat(d);if(e&&e.length){var g,h,i,j,k,l=this;for(g=0,h=e.length;h>g;g++)i=e[g],j=l,"string"==typeof i&&"function"==typeof f[i]&&(i=f[i]),"object"==typeof i&&i&&"function"==typeof i.handleEvent&&(j=i,i=i.handleEvent),"function"==typeof i&&(k=A({},a),sb(i,j,[k],b))}return this}},ub=function(a){var b=null;return(M===!1||a&&"error"===a.type&&a.name&&-1!==V.indexOf(a.name))&&(b=!1),b},vb=function(a){var b=a.target||d||null,f="swf"===a._source;switch(delete a._source,a.type){case"error":var g="flash-sandboxed"===a.name||ub(a);"boolean"==typeof g&&(N.sandboxed=g),-1!==W.indexOf(a.name)?A(N,{disabled:"flash-disabled"===a.name,outdated:"flash-outdated"===a.name,unavailable:"flash-unavailable"===a.name,degraded:"flash-degraded"===a.name,deactivated:"flash-deactivated"===a.name,overdue:"flash-overdue"===a.name,ready:!1}):"version-mismatch"===a.name&&(c=a.swfVersion,A(N,{disabled:!1,outdated:!1,unavailable:!1,degraded:!1,deactivated:!1,overdue:!1,ready:!1})),Pb();break;case"ready":c=a.swfVersion;var h=N.deactivated===!0;A(N,{disabled:!1,outdated:!1,sandboxed:!1,unavailable:!1,degraded:!1,deactivated:!1,overdue:h,ready:!h}),Pb();break;case"beforecopy":e=b;break;case"copy":var i,j,k=a.relatedTarget;!Q["text/html"]&&!Q["text/plain"]&&k&&(j=k.value||k.outerHTML||k.innerHTML)&&(i=k.value||k.textContent||k.innerText)?(a.clipboardData.clearData(),a.clipboardData.setData("text/plain",i),j!==i&&a.clipboardData.setData("text/html",j)):!Q["text/plain"]&&a.target&&(i=a.target.getAttribute("data-clipboard-text"))&&(a.clipboardData.clearData(),a.clipboardData.setData("text/plain",i));break;case"aftercopy":wb(a),Vb.clearData(),b&&b!==Jb()&&b.focus&&b.focus();break;case"_mouseover":Vb.focus(b),Z.bubbleEvents===!0&&f&&(b&&b!==a.relatedTarget&&!F(a.relatedTarget,b)&&xb(A({},a,{type:"mouseenter",bubbles:!1,cancelable:!1})),xb(A({},a,{type:"mouseover"})));break;case"_mouseout":Vb.blur(),Z.bubbleEvents===!0&&f&&(b&&b!==a.relatedTarget&&!F(a.relatedTarget,b)&&xb(A({},a,{type:"mouseleave",bubbles:!1,cancelable:!1})),xb(A({},a,{type:"mouseout"})));break;case"_mousedown":Kb(b,Z.activeClass),Z.bubbleEvents===!0&&f&&xb(A({},a,{type:a.type.slice(1)}));break;case"_mouseup":Lb(b,Z.activeClass),Z.bubbleEvents===!0&&f&&xb(A({},a,{type:a.type.slice(1)}));break;case"_click":e=null,Z.bubbleEvents===!0&&f&&xb(A({},a,{type:a.type.slice(1)}));break;case"_mousemove":Z.bubbleEvents===!0&&f&&xb(A({},a,{type:a.type.slice(1)}))}return/^_(?:click|mouse(?:over|out|down|up|move))$/.test(a.type)?!0:void 0},wb=function(a){if(a.errors&&a.errors.length>0){var b=B(a);A(b,{type:"error",name:"clipboard-error"}),delete b.success,i(function(){Vb.emit(b)},0)}},xb=function(a){if(a&&"string"==typeof a.type&&a){var b,c=a.target||null,d=c&&c.ownerDocument||g,e={view:d.defaultView||f,canBubble:!0,cancelable:!0,detail:"click"===a.type?1:0,button:"number"==typeof a.which?a.which-1:"number"==typeof a.button?a.button:d.createEvent?0:1},h=A(e,a);c&&d.createEvent&&c.dispatchEvent&&(h=[h.type,h.canBubble,h.cancelable,h.view,h.detail,h.screenX,h.screenY,h.clientX,h.clientY,h.ctrlKey,h.altKey,h.shiftKey,h.metaKey,h.button,h.relatedTarget],b=d.createEvent("MouseEvents"),b.initMouseEvent&&(b.initMouseEvent.apply(b,h),b._source="js",c.dispatchEvent(b)))}},yb=function(){var a=Z.flashLoadTimeout;if("number"==typeof a&&a>=0){var b=Math.min(1e3,a/10),c=Z.swfObjectId+"_fallbackContent";T=k(function(){var a=g.getElementById(c);Ob(a)&&(Pb(),N.deactivated=null,Vb.emit({type:"error",name:"swf-not-found"}))},b)}},zb=function(){var a=g.createElement("div");return a.id=Z.containerId,a.className=Z.containerClass,a.style.position="absolute",a.style.left="0px",a.style.top="-9999px",a.style.width="1px",a.style.height="1px",a.style.zIndex=""+Sb(Z.zIndex),a},Ab=function(a){for(var b=a&&a.parentNode;b&&"OBJECT"===b.nodeName&&b.parentNode;)b=b.parentNode;return b||null},Bb=function(){var a,b=N.bridge,c=Ab(b);if(!b){var d=Ib(f.location.host,Z),e="never"===d?"none":"all",h=Gb(A({jsVersion:Vb.version},Z)),i=Z.swfPath+Fb(Z.swfPath,Z);c=zb();var j=g.createElement("div");c.appendChild(j),g.body.appendChild(c);var k=g.createElement("div"),l="activex"===N.pluginType;k.innerHTML='"+(l?'':"")+'
 
',b=k.firstChild,k=null,y(b).ZeroClipboard=Vb,c.replaceChild(b,j),yb()}return b||(b=g[Z.swfObjectId],b&&(a=b.length)&&(b=b[a-1]),!b&&c&&(b=c.firstChild)),N.bridge=b||null,b},Cb=function(){var a=N.bridge;if(a){var d=Ab(a);d&&("activex"===N.pluginType&&"readyState"in a?(a.style.display="none",function e(){if(4===a.readyState){for(var b in a)"function"==typeof a[b]&&(a[b]=null);a.parentNode&&a.parentNode.removeChild(a),d.parentNode&&d.parentNode.removeChild(d)}else i(e,10)}()):(a.parentNode&&a.parentNode.removeChild(a),d.parentNode&&d.parentNode.removeChild(d))),Pb(),N.ready=null,N.bridge=null,N.deactivated=null,c=b}},Db=function(a){var b={},c={};if("object"==typeof a&&a){for(var d in a)if(d&&w.call(a,d)&&"string"==typeof a[d]&&a[d])switch(d.toLowerCase()){case"text/plain":case"text":case"air:text":case"flash:text":b.text=a[d],c.text=d;break;case"text/html":case"html":case"air:html":case"flash:html":b.html=a[d],c.html=d;break;case"application/rtf":case"text/rtf":case"rtf":case"richtext":case"air:rtf":case"flash:rtf":b.rtf=a[d],c.rtf=d}return{data:b,formatMap:c}}},Eb=function(a,b){if("object"!=typeof a||!a||"object"!=typeof b||!b)return a;var c={};for(var d in a)if(w.call(a,d))if("errors"===d){c[d]=a[d]?a[d].slice():[];for(var e=0,f=c[d].length;f>e;e++)c[d][e].format=b[c[d][e].format]}else if("success"!==d&&"data"!==d)c[d]=a[d];else{c[d]={};var g=a[d];for(var h in g)h&&w.call(g,h)&&w.call(b,h)&&(c[d][b[h]]=g[h])}return c},Fb=function(a,b){var c=null==b||b&&b.cacheBust===!0;return c?(-1===a.indexOf("?")?"?":"&")+"noCache="+t():""},Gb=function(a){var b,c,d,e,g="",h=[];if(a.trustedDomains&&("string"==typeof a.trustedDomains?e=[a.trustedDomains]:"object"==typeof a.trustedDomains&&"length"in a.trustedDomains&&(e=a.trustedDomains)),e&&e.length)for(b=0,c=e.length;c>b;b++)if(w.call(e,b)&&e[b]&&"string"==typeof e[b]){if(d=Hb(e[b]),!d)continue;if("*"===d){h.length=0,h.push(d);break}h.push.apply(h,[d,"//"+d,f.location.protocol+"//"+d])}return h.length&&(g+="trustedOrigins="+n(h.join(","))),a.forceEnhancedClipboard===!0&&(g+=(g?"&":"")+"forceEnhancedClipboard=true"),"string"==typeof a.swfObjectId&&a.swfObjectId&&(g+=(g?"&":"")+"swfObjectId="+n(a.swfObjectId)),"string"==typeof a.jsVersion&&a.jsVersion&&(g+=(g?"&":"")+"jsVersion="+n(a.jsVersion)),g},Hb=function(a){if(null==a||""===a)return null;if(a=a.replace(/^\s+|\s+$/g,""),""===a)return null;var b=a.indexOf("//");a=-1===b?a:a.slice(b+2);var c=a.indexOf("/");return a=-1===c?a:-1===b||0===c?null:a.slice(0,c),a&&".swf"===a.slice(-4).toLowerCase()?null:a||null},Ib=function(){var a=function(a){var b,c,d,e=[];if("string"==typeof a&&(a=[a]),"object"!=typeof a||!a||"number"!=typeof a.length)return e;for(b=0,c=a.length;c>b;b++)if(w.call(a,b)&&(d=Hb(a[b]))){if("*"===d){e.length=0,e.push("*");break}-1===e.indexOf(d)&&e.push(d)}return e};return function(b,c){var d=Hb(c.swfPath);null===d&&(d=b);var e=a(c.trustedDomains),f=e.length;if(f>0){if(1===f&&"*"===e[0])return"always";if(-1!==e.indexOf(b))return 1===f&&b===d?"sameDomain":"always"}return"never"}}(),Jb=function(){try{return g.activeElement}catch(a){return null}},Kb=function(a,b){var c,d,e,f=[];if("string"==typeof b&&b&&(f=b.split(/\s+/)),a&&1===a.nodeType&&f.length>0)if(a.classList)for(c=0,d=f.length;d>c;c++)a.classList.add(f[c]);else if(a.hasOwnProperty("className")){for(e=" "+a.className+" ",c=0,d=f.length;d>c;c++)-1===e.indexOf(" "+f[c]+" ")&&(e+=f[c]+" ");a.className=e.replace(/^\s+|\s+$/g,"")}return a},Lb=function(a,b){var c,d,e,f=[];if("string"==typeof b&&b&&(f=b.split(/\s+/)),a&&1===a.nodeType&&f.length>0)if(a.classList&&a.classList.length>0)for(c=0,d=f.length;d>c;c++)a.classList.remove(f[c]);else if(a.className){for(e=(" "+a.className+" ").replace(/[\r\n\t]/g," "),c=0,d=f.length;d>c;c++)e=e.replace(" "+f[c]+" "," ");a.className=e.replace(/^\s+|\s+$/g,"")}return a},Mb=function(a,b){var c=m(a,null).getPropertyValue(b);return"cursor"!==b||c&&"auto"!==c||"A"!==a.nodeName?c:"pointer"},Nb=function(a){var b={left:0,top:0,width:0,height:0};if(a.getBoundingClientRect){var c=a.getBoundingClientRect(),d=f.pageXOffset,e=f.pageYOffset,h=g.documentElement.clientLeft||0,i=g.documentElement.clientTop||0,j=0,k=0;if("relative"===Mb(g.body,"position")){var l=g.body.getBoundingClientRect(),m=g.documentElement.getBoundingClientRect();j=l.left-m.left||0,k=l.top-m.top||0}b.left=c.left+d-h-j,b.top=c.top+e-i-k,b.width="width"in c?c.width:c.right-c.left,b.height="height"in c?c.height:c.bottom-c.top}return b},Ob=function(a){if(!a)return!1;var b=m(a,null),c=r(b.height)>0,d=r(b.width)>0,e=r(b.top)>=0,f=r(b.left)>=0,g=c&&d&&e&&f,h=g?null:Nb(a),i="none"!==b.display&&"collapse"!==b.visibility&&(g||!!h&&(c||h.height>0)&&(d||h.width>0)&&(e||h.top>=0)&&(f||h.left>=0));return i},Pb=function(){j(S),S=0,l(T),T=0},Qb=function(){var a;if(d&&(a=Ab(N.bridge))){var b=Nb(d);A(a.style,{width:b.width+"px",height:b.height+"px",top:b.top+"px",left:b.left+"px",zIndex:""+Sb(Z.zIndex)})}},Rb=function(a){N.ready===!0&&(N.bridge&&"function"==typeof N.bridge.setHandCursor?N.bridge.setHandCursor(a):N.ready=!1)},Sb=function(a){if(/^(?:auto|inherit)$/.test(a))return a;var b;return"number"!=typeof a||s(a)?"string"==typeof a&&(b=Sb(q(a,10))):b=a,"number"==typeof b?b:"auto"},Tb=function(b){var c,d,e,f=N.sandboxed,g=null;if(b=b===!0,M===!1)g=!1;else{try{d=a.frameElement||null}catch(h){e={name:h.name,message:h.message}}if(d&&1===d.nodeType&&"IFRAME"===d.nodeName)try{g=d.hasAttribute("sandbox")}catch(h){g=null}else{try{c=document.domain||null}catch(h){c=null}(null===c||e&&"SecurityError"===e.name&&/(^|[\s\(\[@])sandbox(es|ed|ing|[\s\.,!\)\]@]|$)/.test(e.message.toLowerCase()))&&(g=!0)}}return N.sandboxed=g,f===g||b||Ub(o),g},Ub=function(a){function b(a){var b=a.match(/[\d]+/g);return b.length=3,b.join(".")}function c(a){return!!a&&(a=a.toLowerCase())&&(/^(pepflashplayer\.dll|libpepflashplayer\.so|pepperflashplayer\.plugin)$/.test(a)||"chrome.plugin"===a.slice(-13))}function d(a){a&&(i=!0,a.version&&(l=b(a.version)),!l&&a.description&&(l=b(a.description)),a.filename&&(k=c(a.filename)))}var e,f,g,i=!1,j=!1,k=!1,l="";if(h.plugins&&h.plugins.length)e=h.plugins["Shockwave Flash"],d(e),h.plugins["Shockwave Flash 2.0"]&&(i=!0,l="2.0.0.11");else if(h.mimeTypes&&h.mimeTypes.length)g=h.mimeTypes["application/x-shockwave-flash"],e=g&&g.enabledPlugin,d(e);else if("undefined"!=typeof a){j=!0;try{f=new a("ShockwaveFlash.ShockwaveFlash.7"),i=!0,l=b(f.GetVariable("$version"))}catch(m){try{f=new a("ShockwaveFlash.ShockwaveFlash.6"),i=!0,l="6.0.21"}catch(n){try{f=new a("ShockwaveFlash.ShockwaveFlash"),i=!0,l=b(f.GetVariable("$version"))}catch(o){j=!1}}}}N.disabled=i!==!0,N.outdated=l&&r(l)e;e++)a=g[e].replace(/^on/,""),h[a]=!0,j[a]||(j[a]=[]),j[a].push(d);if(h.ready&&N.ready&&this.emit({type:"ready",client:this}),h.error){for(e=0,f=W.length;f>e;e++)if(N[W[e].replace(/^flash-/,"")]){this.emit({type:"error",name:W[e],client:this});break}c!==b&&Vb.version!==c&&this.emit({type:"error",name:"version-mismatch",jsVersion:Vb.version,swfVersion:c})}}return this},bc=function(a,b){var c,d,e,f,g,h=Xb[this.id],i=h&&h.handlers;if(!i)return this;if(0===arguments.length)f=u(i);else if("string"==typeof a&&a)f=a.split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof b)for(c in a)w.call(a,c)&&"string"==typeof c&&c&&"function"==typeof a[c]&&this.off(c,a[c]);if(f&&f.length)for(c=0,d=f.length;d>c;c++)if(a=f[c].toLowerCase().replace(/^on/,""),g=i[a],g&&g.length)if(b)for(e=g.indexOf(b);-1!==e;)g.splice(e,1),e=g.indexOf(b,e);else g.length=0;return this},cc=function(a){var b=null,c=Xb[this.id]&&Xb[this.id].handlers;return c&&(b="string"==typeof a&&a?c[a]?c[a].slice(0):[]:B(c)),b},dc=function(a){if(ic.call(this,a)){"object"==typeof a&&a&&"string"==typeof a.type&&a.type&&(a=A({},a));var b=A({},ob(a),{client:this});jc.call(this,b)}return this},ec=function(a){if(!Xb[this.id])throw new Error("Attempted to clip element(s) to a destroyed ZeroClipboard client instance");a=kc(a);for(var b=0;b0,e=!a.target||d&&-1!==c.indexOf(a.target),f=a.relatedTarget&&d&&-1!==c.indexOf(a.relatedTarget),g=a.client&&a.client===this;return b&&(e||f||g)?!0:!1},jc=function(a){var b=Xb[this.id];if("object"==typeof a&&a&&a.type&&b){var c=rb(a),d=b&&b.handlers["*"]||[],e=b&&b.handlers[a.type]||[],g=d.concat(e);if(g&&g.length){var h,i,j,k,l,m=this;for(h=0,i=g.length;i>h;h++)j=g[h],k=m,"string"==typeof j&&"function"==typeof f[j]&&(j=f[j]),"object"==typeof j&&j&&"function"==typeof j.handleEvent&&(k=j,j=j.handleEvent),"function"==typeof j&&(l=A({},a),sb(j,k,[l],c))}}},kc=function(a){return"string"==typeof a&&(a=[]),"number"!=typeof a.length?[a]:a},lc=function(a){if(a&&1===a.nodeType){var b=function(a){(a||(a=f.event))&&("js"!==a._source&&(a.stopImmediatePropagation(),a.preventDefault()),delete a._source)},c=function(c){(c||(c=f.event))&&(b(c),Vb.focus(a))};a.addEventListener("mouseover",c,!1),a.addEventListener("mouseout",b,!1),a.addEventListener("mouseenter",b,!1),a.addEventListener("mouseleave",b,!1),a.addEventListener("mousemove",b,!1),$b[a.zcClippingId]={mouseover:c,mouseout:b,mouseenter:b,mouseleave:b,mousemove:b}}},mc=function(a){if(a&&1===a.nodeType){var b=$b[a.zcClippingId];if("object"==typeof b&&b){for(var c,d,e=["move","leave","enter","out","over"],f=0,g=e.length;g>f;f++)c="mouse"+e[f],d=b[c],"function"==typeof d&&a.removeEventListener(c,d,!1);delete $b[a.zcClippingId]}}};Vb._createClient=function(){_b.apply(this,z(arguments))},Vb.prototype.on=function(){return ac.apply(this,z(arguments))},Vb.prototype.off=function(){return bc.apply(this,z(arguments))},Vb.prototype.handlers=function(){return cc.apply(this,z(arguments))},Vb.prototype.emit=function(){return dc.apply(this,z(arguments))},Vb.prototype.clip=function(){return ec.apply(this,z(arguments))},Vb.prototype.unclip=function(){return fc.apply(this,z(arguments))},Vb.prototype.elements=function(){return gc.apply(this,z(arguments))},Vb.prototype.destroy=function(){return hc.apply(this,z(arguments))},Vb.prototype.setText=function(a){if(!Xb[this.id])throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");return Vb.setData("text/plain",a),this},Vb.prototype.setHtml=function(a){if(!Xb[this.id])throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");return Vb.setData("text/html",a),this},Vb.prototype.setRichText=function(a){if(!Xb[this.id])throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");return Vb.setData("application/rtf",a),this},Vb.prototype.setData=function(){if(!Xb[this.id])throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");return Vb.setData.apply(this,z(arguments)),this},Vb.prototype.clearData=function(){if(!Xb[this.id])throw new Error("Attempted to clear pending clipboard data from a destroyed ZeroClipboard client instance");return Vb.clearData.apply(this,z(arguments)),this},Vb.prototype.getData=function(){if(!Xb[this.id])throw new Error("Attempted to get pending clipboard data from a destroyed ZeroClipboard client instance");return Vb.getData.apply(this,z(arguments))},"function"==typeof define&&define.amd?define(function(){return Vb}):"object"==typeof module&&module&&"object"==typeof module.exports&&module.exports?module.exports=Vb:a.ZeroClipboard=Vb}(function(){return this||window}()); +//# sourceMappingURL=ZeroClipboard.min.map \ No newline at end of file diff --git a/resources/zeroclipboard/ZeroClipboard.min.map b/resources/zeroclipboard/ZeroClipboard.min.map new file mode 100644 index 0000000000..8d7dc47ac1 --- /dev/null +++ b/resources/zeroclipboard/ZeroClipboard.min.map @@ -0,0 +1 @@ +{"version":3,"file":"ZeroClipboard.min.js","sources":["ZeroClipboard.js"],"names":["window","undefined","_zcSwfVersion","_currentElement","_copyTarget","_window","_document","document","_navigator","navigator","_setTimeout","setTimeout","_clearTimeout","clearTimeout","_setInterval","setInterval","_clearInterval","clearInterval","_getComputedStyle","getComputedStyle","_encodeURIComponent","encodeURIComponent","_ActiveXObject","ActiveXObject","_Error","Error","_parseInt","Number","parseInt","_parseFloat","parseFloat","_isNaN","isNaN","_now","Date","now","_keys","Object","keys","_defineProperty","defineProperty","_hasOwn","prototype","hasOwnProperty","_slice","Array","slice","_unwrap","unwrapper","el","wrap","unwrap","div","createElement","unwrappedDiv","nodeType","e","_args","argumentsObj","call","_extend","i","len","arg","prop","src","copy","args","arguments","target","length","_deepCopy","source","_pick","obj","newObj","_omit","indexOf","_deleteOwnProperties","_containedBy","ancestorEl","ownerDocument","parentNode","_getDirPathOfUrl","url","dir","split","lastIndexOf","_getCurrentScriptUrlFromErrorStack","stack","matches","match","_getCurrentScriptUrlFromError","err","sourceURL","fileName","_getCurrentScriptUrl","jsPath","scripts","currentScript","getElementsByTagName","readyState","_getUnanimousScriptParentDir","jsDir","_getDefaultSwfPath","_pageIsFramed","opener","top","parent","_flashState","bridge","version","pluginType","disabled","outdated","sandboxed","unavailable","degraded","deactivated","overdue","ready","_minimumFlashVersion","_handlers","_clipData","_clipDataFormatMap","_flashCheckTimeout","_swfFallbackCheckInterval","_eventMessages","error","flash-disabled","flash-outdated","flash-sandboxed","flash-unavailable","flash-degraded","flash-deactivated","flash-overdue","version-mismatch","clipboard-error","config-mismatch","swf-not-found","_errorsThatOnlyOccurAfterFlashLoads","_flashStateErrorNames","_flashStateErrorNameMatchingRegex","RegExp","map","errorName","replace","join","_flashStateEnabledErrorNameMatchingRegex","_globalConfig","swfPath","trustedDomains","location","host","cacheBust","forceEnhancedClipboard","flashLoadTimeout","autoActivate","bubbleEvents","containerId","containerClass","swfObjectId","hoverClass","activeClass","forceHandCursor","title","zIndex","_config","options","test","_isValidHtml4Id","_state","_detectSandbox","browser","flash","zeroclipboard","ZeroClipboard","config","_isFlashUnusable","_on","eventType","listener","events","added","toLowerCase","on","push","emit","type","name","jsVersion","swfVersion","_off","foundIndex","perEventHandlers","off","splice","_listeners","_emit","event","eventCopy","returnVal","tmp","_createEvent","_preprocessEvent","_dispatchCallbacks","this","_mapClipDataToFlash","data","formatMap","_create","previousState","isFlashUnusable","maxWait","_embedSwf","_destroy","clearData","blur","_unembedSwf","_setData","format","dataObj","dataFormat","_clearData","_getData","_focus","element","_removeClass","_addClass","newTitle","getAttribute","htmlBridge","_getHtmlBridge","setAttribute","useHandCursor","_getStyle","_setHandCursor","_reposition","_blur","removeAttribute","style","left","width","height","_activeElement","id","relatedTarget","currentTarget","timeStamp","msg","message","minimumVersion","clipboardData","setData","_mapClipResultsFromFlash","_getRelatedTarget","_addMouseData","targetEl","relatedTargetId","getElementById","srcElement","fromElement","toElement","pos","_getElementPosition","screenLeft","screenX","screenTop","screenY","scrollLeft","body","documentElement","scrollTop","pageX","_stageX","pageY","_stageY","clientX","clientY","moveX","movementX","moveY","movementY","x","y","offsetX","offsetY","layerX","layerY","_shouldPerformAsync","_dispatchCallback","func","context","async","apply","wildcardTypeHandlers","specificTypeHandlers","handlers","concat","originalContext","handleEvent","_getSandboxStatusFromErrorEvent","isSandboxed","sourceIsSwf","_source","_clearTimeoutsAndPolling","wasDeactivated","textContent","htmlContent","value","outerHTML","innerHTML","innerText","_queueEmitClipboardErrors","_safeActiveElement","focus","_fireMouseEvent","bubbles","cancelable","aftercopyEvent","errors","errorEvent","success","doc","defaults","view","defaultView","canBubble","detail","button","which","createEvent","dispatchEvent","ctrlKey","altKey","shiftKey","metaKey","initMouseEvent","_watchForSwfFallbackContent","pollWait","Math","min","fallbackContentId","_isElementVisible","_createHtmlBridge","container","className","position","_getSafeZIndex","flashBridge","nodeName","allowScriptAccess","_determineScriptAccess","allowNetworking","flashvars","_vars","swfUrl","_cacheBust","divToBeReplaced","appendChild","tmpDiv","usingActiveX","firstChild","replaceChild","display","removeSwfFromIE","removeChild","clipData","newClipData","text","html","rtf","clipResults","newResults","tmpHash","path","domain","domains","str","trustedOriginsExpanded","_extractDomain","protocol","originOrUrl","protocolIndex","pathIndex","_extractAllDomains","origins","resultsArray","currentDomain","configOptions","swfDomain","activeElement","c","cl","classNames","classList","add","remove","getPropertyValue","getBoundingClientRect","elRect","pageXOffset","pageYOffset","leftBorderWidth","clientLeft","topBorderWidth","clientTop","leftBodyOffset","topBodyOffset","bodyRect","htmlRect","right","bottom","styles","hasCssHeight","hasCssWidth","hasCssTop","hasCssLeft","cssKnows","rect","isVisible","visibility","enabled","setHandCursor","val","doNotReassessFlashSupport","effectiveScriptOrigin","frame","frameError","frameElement","hasAttribute","_detectFlashSupport","parseFlashVersion","desc","isPepperFlash","flashPlayerFileName","inspectPlugin","plugin","hasFlash","flashVersion","description","filename","isPPAPI","ax","mimeType","isActiveX","plugins","mimeTypes","enabledPlugin","GetVariable","e1","e2","e3","_createClient","writable","configurable","enumerable","state","create","destroy","getData","activate","deactivate","_clientIdCounter","_clientMeta","_elementIdCounter","_elementMeta","_mouseHandlers","_clientConstructor","elements","client","instance","clip","_clientOn","meta","_clientOff","_clientListeners","_clientEmit","_clientShouldEmit","_clientDispatchCallbacks","_clientClip","_prepClip","zcClippingId","_addMouseHandlers","clippedElements","_clientUnclip","arrayIndex","clientIds","_removeMouseHandlers","_clientElements","_clientDestroy","unclip","clippedEls","hasClippedEls","goodTarget","goodRelTarget","goodClient","_suppressMouseEvents","stopImmediatePropagation","preventDefault","_elementMouseOver","addEventListener","mouseover","mouseout","mouseenter","mouseleave","mousemove","mouseHandlers","key","mouseEvents","removeEventListener","setText","setHtml","setRichText","richText","define","amd","module","exports"],"mappings":"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","sourcesContent":["/*!\n * ZeroClipboard\n * The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface.\n * Copyright (c) 2009-2014 Jon Rohan, James M. Greene\n * Licensed MIT\n * http://zeroclipboard.org/\n * v2.2.0\n */\n(function(window, undefined) {\n \"use strict\";\n /**\n * Store references to critically important global functions that may be\n * overridden on certain web pages.\n */\n var _window = window, _document = _window.document, _navigator = _window.navigator, _setTimeout = _window.setTimeout, _clearTimeout = _window.clearTimeout, _setInterval = _window.setInterval, _clearInterval = _window.clearInterval, _getComputedStyle = _window.getComputedStyle, _encodeURIComponent = _window.encodeURIComponent, _ActiveXObject = _window.ActiveXObject, _Error = _window.Error, _parseInt = _window.Number.parseInt || _window.parseInt, _parseFloat = _window.Number.parseFloat || _window.parseFloat, _isNaN = _window.Number.isNaN || _window.isNaN, _now = _window.Date.now, _keys = _window.Object.keys, _defineProperty = _window.Object.defineProperty, _hasOwn = _window.Object.prototype.hasOwnProperty, _slice = _window.Array.prototype.slice, _unwrap = function() {\n var unwrapper = function(el) {\n return el;\n };\n if (typeof _window.wrap === \"function\" && typeof _window.unwrap === \"function\") {\n try {\n var div = _document.createElement(\"div\");\n var unwrappedDiv = _window.unwrap(div);\n if (div.nodeType === 1 && unwrappedDiv && unwrappedDiv.nodeType === 1) {\n unwrapper = _window.unwrap;\n }\n } catch (e) {}\n }\n return unwrapper;\n }();\n /**\n * Convert an `arguments` object into an Array.\n *\n * @returns The arguments as an Array\n * @private\n */\n var _args = function(argumentsObj) {\n return _slice.call(argumentsObj, 0);\n };\n /**\n * Shallow-copy the owned, enumerable properties of one object over to another, similar to jQuery's `$.extend`.\n *\n * @returns The target object, augmented\n * @private\n */\n var _extend = function() {\n var i, len, arg, prop, src, copy, args = _args(arguments), target = args[0] || {};\n for (i = 1, len = args.length; i < len; i++) {\n if ((arg = args[i]) != null) {\n for (prop in arg) {\n if (_hasOwn.call(arg, prop)) {\n src = target[prop];\n copy = arg[prop];\n if (target !== copy && copy !== undefined) {\n target[prop] = copy;\n }\n }\n }\n }\n }\n return target;\n };\n /**\n * Return a deep copy of the source object or array.\n *\n * @returns Object or Array\n * @private\n */\n var _deepCopy = function(source) {\n var copy, i, len, prop;\n if (typeof source !== \"object\" || source == null || typeof source.nodeType === \"number\") {\n copy = source;\n } else if (typeof source.length === \"number\") {\n copy = [];\n for (i = 0, len = source.length; i < len; i++) {\n if (_hasOwn.call(source, i)) {\n copy[i] = _deepCopy(source[i]);\n }\n }\n } else {\n copy = {};\n for (prop in source) {\n if (_hasOwn.call(source, prop)) {\n copy[prop] = _deepCopy(source[prop]);\n }\n }\n }\n return copy;\n };\n /**\n * Makes a shallow copy of `obj` (like `_extend`) but filters its properties based on a list of `keys` to keep.\n * The inverse of `_omit`, mostly. The big difference is that these properties do NOT need to be enumerable to\n * be kept.\n *\n * @returns A new filtered object.\n * @private\n */\n var _pick = function(obj, keys) {\n var newObj = {};\n for (var i = 0, len = keys.length; i < len; i++) {\n if (keys[i] in obj) {\n newObj[keys[i]] = obj[keys[i]];\n }\n }\n return newObj;\n };\n /**\n * Makes a shallow copy of `obj` (like `_extend`) but filters its properties based on a list of `keys` to omit.\n * The inverse of `_pick`.\n *\n * @returns A new filtered object.\n * @private\n */\n var _omit = function(obj, keys) {\n var newObj = {};\n for (var prop in obj) {\n if (keys.indexOf(prop) === -1) {\n newObj[prop] = obj[prop];\n }\n }\n return newObj;\n };\n /**\n * Remove all owned, enumerable properties from an object.\n *\n * @returns The original object without its owned, enumerable properties.\n * @private\n */\n var _deleteOwnProperties = function(obj) {\n if (obj) {\n for (var prop in obj) {\n if (_hasOwn.call(obj, prop)) {\n delete obj[prop];\n }\n }\n }\n return obj;\n };\n /**\n * Determine if an element is contained within another element.\n *\n * @returns Boolean\n * @private\n */\n var _containedBy = function(el, ancestorEl) {\n if (el && el.nodeType === 1 && el.ownerDocument && ancestorEl && (ancestorEl.nodeType === 1 && ancestorEl.ownerDocument && ancestorEl.ownerDocument === el.ownerDocument || ancestorEl.nodeType === 9 && !ancestorEl.ownerDocument && ancestorEl === el.ownerDocument)) {\n do {\n if (el === ancestorEl) {\n return true;\n }\n el = el.parentNode;\n } while (el);\n }\n return false;\n };\n /**\n * Get the URL path's parent directory.\n *\n * @returns String or `undefined`\n * @private\n */\n var _getDirPathOfUrl = function(url) {\n var dir;\n if (typeof url === \"string\" && url) {\n dir = url.split(\"#\")[0].split(\"?\")[0];\n dir = url.slice(0, url.lastIndexOf(\"/\") + 1);\n }\n return dir;\n };\n /**\n * Get the current script's URL by throwing an `Error` and analyzing it.\n *\n * @returns String or `undefined`\n * @private\n */\n var _getCurrentScriptUrlFromErrorStack = function(stack) {\n var url, matches;\n if (typeof stack === \"string\" && stack) {\n matches = stack.match(/^(?:|[^:@]*@|.+\\)@(?=http[s]?|file)|.+?\\s+(?: at |@)(?:[^:\\(]+ )*[\\(]?)((?:http[s]?|file):\\/\\/[\\/]?.+?\\/[^:\\)]*?)(?::\\d+)(?::\\d+)?/);\n if (matches && matches[1]) {\n url = matches[1];\n } else {\n matches = stack.match(/\\)@((?:http[s]?|file):\\/\\/[\\/]?.+?\\/[^:\\)]*?)(?::\\d+)(?::\\d+)?/);\n if (matches && matches[1]) {\n url = matches[1];\n }\n }\n }\n return url;\n };\n /**\n * Get the current script's URL by throwing an `Error` and analyzing it.\n *\n * @returns String or `undefined`\n * @private\n */\n var _getCurrentScriptUrlFromError = function() {\n var url, err;\n try {\n throw new _Error();\n } catch (e) {\n err = e;\n }\n if (err) {\n url = err.sourceURL || err.fileName || _getCurrentScriptUrlFromErrorStack(err.stack);\n }\n return url;\n };\n /**\n * Get the current script's URL.\n *\n * @returns String or `undefined`\n * @private\n */\n var _getCurrentScriptUrl = function() {\n var jsPath, scripts, i;\n if (_document.currentScript && (jsPath = _document.currentScript.src)) {\n return jsPath;\n }\n scripts = _document.getElementsByTagName(\"script\");\n if (scripts.length === 1) {\n return scripts[0].src || undefined;\n }\n if (\"readyState\" in scripts[0]) {\n for (i = scripts.length; i--; ) {\n if (scripts[i].readyState === \"interactive\" && (jsPath = scripts[i].src)) {\n return jsPath;\n }\n }\n }\n if (_document.readyState === \"loading\" && (jsPath = scripts[scripts.length - 1].src)) {\n return jsPath;\n }\n if (jsPath = _getCurrentScriptUrlFromError()) {\n return jsPath;\n }\n return undefined;\n };\n /**\n * Get the unanimous parent directory of ALL script tags.\n * If any script tags are either (a) inline or (b) from differing parent\n * directories, this method must return `undefined`.\n *\n * @returns String or `undefined`\n * @private\n */\n var _getUnanimousScriptParentDir = function() {\n var i, jsDir, jsPath, scripts = _document.getElementsByTagName(\"script\");\n for (i = scripts.length; i--; ) {\n if (!(jsPath = scripts[i].src)) {\n jsDir = null;\n break;\n }\n jsPath = _getDirPathOfUrl(jsPath);\n if (jsDir == null) {\n jsDir = jsPath;\n } else if (jsDir !== jsPath) {\n jsDir = null;\n break;\n }\n }\n return jsDir || undefined;\n };\n /**\n * Get the presumed location of the \"ZeroClipboard.swf\" file, based on the location\n * of the executing JavaScript file (e.g. \"ZeroClipboard.js\", etc.).\n *\n * @returns String\n * @private\n */\n var _getDefaultSwfPath = function() {\n var jsDir = _getDirPathOfUrl(_getCurrentScriptUrl()) || _getUnanimousScriptParentDir() || \"\";\n return jsDir + \"ZeroClipboard.swf\";\n };\n /**\n * Keep track of if the page is framed (in an `iframe`). This can never change.\n * @private\n */\n var _pageIsFramed = function() {\n return window.opener == null && (!!window.top && window != window.top || !!window.parent && window != window.parent);\n }();\n /**\n * Keep track of the state of the Flash object.\n * @private\n */\n var _flashState = {\n bridge: null,\n version: \"0.0.0\",\n pluginType: \"unknown\",\n disabled: null,\n outdated: null,\n sandboxed: null,\n unavailable: null,\n degraded: null,\n deactivated: null,\n overdue: null,\n ready: null\n };\n /**\n * The minimum Flash Player version required to use ZeroClipboard completely.\n * @readonly\n * @private\n */\n var _minimumFlashVersion = \"11.0.0\";\n /**\n * The ZeroClipboard library version number, as reported by Flash, at the time the SWF was compiled.\n */\n var _zcSwfVersion;\n /**\n * Keep track of all event listener registrations.\n * @private\n */\n var _handlers = {};\n /**\n * Keep track of the currently activated element.\n * @private\n */\n var _currentElement;\n /**\n * Keep track of the element that was activated when a `copy` process started.\n * @private\n */\n var _copyTarget;\n /**\n * Keep track of data for the pending clipboard transaction.\n * @private\n */\n var _clipData = {};\n /**\n * Keep track of data formats for the pending clipboard transaction.\n * @private\n */\n var _clipDataFormatMap = null;\n /**\n * Keep track of the Flash availability check timeout.\n * @private\n */\n var _flashCheckTimeout = 0;\n /**\n * Keep track of SWF network errors interval polling.\n * @private\n */\n var _swfFallbackCheckInterval = 0;\n /**\n * The `message` store for events\n * @private\n */\n var _eventMessages = {\n ready: \"Flash communication is established\",\n error: {\n \"flash-disabled\": \"Flash is disabled or not installed. May also be attempting to run Flash in a sandboxed iframe, which is impossible.\",\n \"flash-outdated\": \"Flash is too outdated to support ZeroClipboard\",\n \"flash-sandboxed\": \"Attempting to run Flash in a sandboxed iframe, which is impossible\",\n \"flash-unavailable\": \"Flash is unable to communicate bidirectionally with JavaScript\",\n \"flash-degraded\": \"Flash is unable to preserve data fidelity when communicating with JavaScript\",\n \"flash-deactivated\": \"Flash is too outdated for your browser and/or is configured as click-to-activate.\\nThis may also mean that the ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity.\\nMay also be attempting to run Flash in a sandboxed iframe, which is impossible.\",\n \"flash-overdue\": \"Flash communication was established but NOT within the acceptable time limit\",\n \"version-mismatch\": \"ZeroClipboard JS version number does not match ZeroClipboard SWF version number\",\n \"clipboard-error\": \"At least one error was thrown while ZeroClipboard was attempting to inject your data into the clipboard\",\n \"config-mismatch\": \"ZeroClipboard configuration does not match Flash's reality\",\n \"swf-not-found\": \"The ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity\"\n }\n };\n /**\n * The `name`s of `error` events that can only occur is Flash has at least\n * been able to load the SWF successfully.\n * @private\n */\n var _errorsThatOnlyOccurAfterFlashLoads = [ \"flash-unavailable\", \"flash-degraded\", \"flash-overdue\", \"version-mismatch\", \"config-mismatch\", \"clipboard-error\" ];\n /**\n * The `name`s of `error` events that should likely result in the `_flashState`\n * variable's property values being updated.\n * @private\n */\n var _flashStateErrorNames = [ \"flash-disabled\", \"flash-outdated\", \"flash-sandboxed\", \"flash-unavailable\", \"flash-degraded\", \"flash-deactivated\", \"flash-overdue\" ];\n /**\n * A RegExp to match the `name` property of `error` events related to Flash.\n * @private\n */\n var _flashStateErrorNameMatchingRegex = new RegExp(\"^flash-(\" + _flashStateErrorNames.map(function(errorName) {\n return errorName.replace(/^flash-/, \"\");\n }).join(\"|\") + \")$\");\n /**\n * A RegExp to match the `name` property of `error` events related to Flash,\n * which is enabled.\n * @private\n */\n var _flashStateEnabledErrorNameMatchingRegex = new RegExp(\"^flash-(\" + _flashStateErrorNames.slice(1).map(function(errorName) {\n return errorName.replace(/^flash-/, \"\");\n }).join(\"|\") + \")$\");\n /**\n * ZeroClipboard configuration defaults for the Core module.\n * @private\n */\n var _globalConfig = {\n swfPath: _getDefaultSwfPath(),\n trustedDomains: window.location.host ? [ window.location.host ] : [],\n cacheBust: true,\n forceEnhancedClipboard: false,\n flashLoadTimeout: 3e4,\n autoActivate: true,\n bubbleEvents: true,\n containerId: \"global-zeroclipboard-html-bridge\",\n containerClass: \"global-zeroclipboard-container\",\n swfObjectId: \"global-zeroclipboard-flash-bridge\",\n hoverClass: \"zeroclipboard-is-hover\",\n activeClass: \"zeroclipboard-is-active\",\n forceHandCursor: false,\n title: null,\n zIndex: 999999999\n };\n /**\n * The underlying implementation of `ZeroClipboard.config`.\n * @private\n */\n var _config = function(options) {\n if (typeof options === \"object\" && options !== null) {\n for (var prop in options) {\n if (_hasOwn.call(options, prop)) {\n if (/^(?:forceHandCursor|title|zIndex|bubbleEvents)$/.test(prop)) {\n _globalConfig[prop] = options[prop];\n } else if (_flashState.bridge == null) {\n if (prop === \"containerId\" || prop === \"swfObjectId\") {\n if (_isValidHtml4Id(options[prop])) {\n _globalConfig[prop] = options[prop];\n } else {\n throw new Error(\"The specified `\" + prop + \"` value is not valid as an HTML4 Element ID\");\n }\n } else {\n _globalConfig[prop] = options[prop];\n }\n }\n }\n }\n }\n if (typeof options === \"string\" && options) {\n if (_hasOwn.call(_globalConfig, options)) {\n return _globalConfig[options];\n }\n return;\n }\n return _deepCopy(_globalConfig);\n };\n /**\n * The underlying implementation of `ZeroClipboard.state`.\n * @private\n */\n var _state = function() {\n _detectSandbox();\n return {\n browser: _pick(_navigator, [ \"userAgent\", \"platform\", \"appName\" ]),\n flash: _omit(_flashState, [ \"bridge\" ]),\n zeroclipboard: {\n version: ZeroClipboard.version,\n config: ZeroClipboard.config()\n }\n };\n };\n /**\n * The underlying implementation of `ZeroClipboard.isFlashUnusable`.\n * @private\n */\n var _isFlashUnusable = function() {\n return !!(_flashState.disabled || _flashState.outdated || _flashState.sandboxed || _flashState.unavailable || _flashState.degraded || _flashState.deactivated);\n };\n /**\n * The underlying implementation of `ZeroClipboard.on`.\n * @private\n */\n var _on = function(eventType, listener) {\n var i, len, events, added = {};\n if (typeof eventType === \"string\" && eventType) {\n events = eventType.toLowerCase().split(/\\s+/);\n } else if (typeof eventType === \"object\" && eventType && typeof listener === \"undefined\") {\n for (i in eventType) {\n if (_hasOwn.call(eventType, i) && typeof i === \"string\" && i && typeof eventType[i] === \"function\") {\n ZeroClipboard.on(i, eventType[i]);\n }\n }\n }\n if (events && events.length) {\n for (i = 0, len = events.length; i < len; i++) {\n eventType = events[i].replace(/^on/, \"\");\n added[eventType] = true;\n if (!_handlers[eventType]) {\n _handlers[eventType] = [];\n }\n _handlers[eventType].push(listener);\n }\n if (added.ready && _flashState.ready) {\n ZeroClipboard.emit({\n type: \"ready\"\n });\n }\n if (added.error) {\n for (i = 0, len = _flashStateErrorNames.length; i < len; i++) {\n if (_flashState[_flashStateErrorNames[i].replace(/^flash-/, \"\")] === true) {\n ZeroClipboard.emit({\n type: \"error\",\n name: _flashStateErrorNames[i]\n });\n break;\n }\n }\n if (_zcSwfVersion !== undefined && ZeroClipboard.version !== _zcSwfVersion) {\n ZeroClipboard.emit({\n type: \"error\",\n name: \"version-mismatch\",\n jsVersion: ZeroClipboard.version,\n swfVersion: _zcSwfVersion\n });\n }\n }\n }\n return ZeroClipboard;\n };\n /**\n * The underlying implementation of `ZeroClipboard.off`.\n * @private\n */\n var _off = function(eventType, listener) {\n var i, len, foundIndex, events, perEventHandlers;\n if (arguments.length === 0) {\n events = _keys(_handlers);\n } else if (typeof eventType === \"string\" && eventType) {\n events = eventType.split(/\\s+/);\n } else if (typeof eventType === \"object\" && eventType && typeof listener === \"undefined\") {\n for (i in eventType) {\n if (_hasOwn.call(eventType, i) && typeof i === \"string\" && i && typeof eventType[i] === \"function\") {\n ZeroClipboard.off(i, eventType[i]);\n }\n }\n }\n if (events && events.length) {\n for (i = 0, len = events.length; i < len; i++) {\n eventType = events[i].toLowerCase().replace(/^on/, \"\");\n perEventHandlers = _handlers[eventType];\n if (perEventHandlers && perEventHandlers.length) {\n if (listener) {\n foundIndex = perEventHandlers.indexOf(listener);\n while (foundIndex !== -1) {\n perEventHandlers.splice(foundIndex, 1);\n foundIndex = perEventHandlers.indexOf(listener, foundIndex);\n }\n } else {\n perEventHandlers.length = 0;\n }\n }\n }\n }\n return ZeroClipboard;\n };\n /**\n * The underlying implementation of `ZeroClipboard.handlers`.\n * @private\n */\n var _listeners = function(eventType) {\n var copy;\n if (typeof eventType === \"string\" && eventType) {\n copy = _deepCopy(_handlers[eventType]) || null;\n } else {\n copy = _deepCopy(_handlers);\n }\n return copy;\n };\n /**\n * The underlying implementation of `ZeroClipboard.emit`.\n * @private\n */\n var _emit = function(event) {\n var eventCopy, returnVal, tmp;\n event = _createEvent(event);\n if (!event) {\n return;\n }\n if (_preprocessEvent(event)) {\n return;\n }\n if (event.type === \"ready\" && _flashState.overdue === true) {\n return ZeroClipboard.emit({\n type: \"error\",\n name: \"flash-overdue\"\n });\n }\n eventCopy = _extend({}, event);\n _dispatchCallbacks.call(this, eventCopy);\n if (event.type === \"copy\") {\n tmp = _mapClipDataToFlash(_clipData);\n returnVal = tmp.data;\n _clipDataFormatMap = tmp.formatMap;\n }\n return returnVal;\n };\n /**\n * The underlying implementation of `ZeroClipboard.create`.\n * @private\n */\n var _create = function() {\n var previousState = _flashState.sandboxed;\n _detectSandbox();\n if (typeof _flashState.ready !== \"boolean\") {\n _flashState.ready = false;\n }\n if (_flashState.sandboxed !== previousState && _flashState.sandboxed === true) {\n _flashState.ready = false;\n ZeroClipboard.emit({\n type: \"error\",\n name: \"flash-sandboxed\"\n });\n } else if (!ZeroClipboard.isFlashUnusable() && _flashState.bridge === null) {\n var maxWait = _globalConfig.flashLoadTimeout;\n if (typeof maxWait === \"number\" && maxWait >= 0) {\n _flashCheckTimeout = _setTimeout(function() {\n if (typeof _flashState.deactivated !== \"boolean\") {\n _flashState.deactivated = true;\n }\n if (_flashState.deactivated === true) {\n ZeroClipboard.emit({\n type: \"error\",\n name: \"flash-deactivated\"\n });\n }\n }, maxWait);\n }\n _flashState.overdue = false;\n _embedSwf();\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.destroy`.\n * @private\n */\n var _destroy = function() {\n ZeroClipboard.clearData();\n ZeroClipboard.blur();\n ZeroClipboard.emit(\"destroy\");\n _unembedSwf();\n ZeroClipboard.off();\n };\n /**\n * The underlying implementation of `ZeroClipboard.setData`.\n * @private\n */\n var _setData = function(format, data) {\n var dataObj;\n if (typeof format === \"object\" && format && typeof data === \"undefined\") {\n dataObj = format;\n ZeroClipboard.clearData();\n } else if (typeof format === \"string\" && format) {\n dataObj = {};\n dataObj[format] = data;\n } else {\n return;\n }\n for (var dataFormat in dataObj) {\n if (typeof dataFormat === \"string\" && dataFormat && _hasOwn.call(dataObj, dataFormat) && typeof dataObj[dataFormat] === \"string\" && dataObj[dataFormat]) {\n _clipData[dataFormat] = dataObj[dataFormat];\n }\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.clearData`.\n * @private\n */\n var _clearData = function(format) {\n if (typeof format === \"undefined\") {\n _deleteOwnProperties(_clipData);\n _clipDataFormatMap = null;\n } else if (typeof format === \"string\" && _hasOwn.call(_clipData, format)) {\n delete _clipData[format];\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.getData`.\n * @private\n */\n var _getData = function(format) {\n if (typeof format === \"undefined\") {\n return _deepCopy(_clipData);\n } else if (typeof format === \"string\" && _hasOwn.call(_clipData, format)) {\n return _clipData[format];\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.focus`/`ZeroClipboard.activate`.\n * @private\n */\n var _focus = function(element) {\n if (!(element && element.nodeType === 1)) {\n return;\n }\n if (_currentElement) {\n _removeClass(_currentElement, _globalConfig.activeClass);\n if (_currentElement !== element) {\n _removeClass(_currentElement, _globalConfig.hoverClass);\n }\n }\n _currentElement = element;\n _addClass(element, _globalConfig.hoverClass);\n var newTitle = element.getAttribute(\"title\") || _globalConfig.title;\n if (typeof newTitle === \"string\" && newTitle) {\n var htmlBridge = _getHtmlBridge(_flashState.bridge);\n if (htmlBridge) {\n htmlBridge.setAttribute(\"title\", newTitle);\n }\n }\n var useHandCursor = _globalConfig.forceHandCursor === true || _getStyle(element, \"cursor\") === \"pointer\";\n _setHandCursor(useHandCursor);\n _reposition();\n };\n /**\n * The underlying implementation of `ZeroClipboard.blur`/`ZeroClipboard.deactivate`.\n * @private\n */\n var _blur = function() {\n var htmlBridge = _getHtmlBridge(_flashState.bridge);\n if (htmlBridge) {\n htmlBridge.removeAttribute(\"title\");\n htmlBridge.style.left = \"0px\";\n htmlBridge.style.top = \"-9999px\";\n htmlBridge.style.width = \"1px\";\n htmlBridge.style.height = \"1px\";\n }\n if (_currentElement) {\n _removeClass(_currentElement, _globalConfig.hoverClass);\n _removeClass(_currentElement, _globalConfig.activeClass);\n _currentElement = null;\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.activeElement`.\n * @private\n */\n var _activeElement = function() {\n return _currentElement || null;\n };\n /**\n * Check if a value is a valid HTML4 `ID` or `Name` token.\n * @private\n */\n var _isValidHtml4Id = function(id) {\n return typeof id === \"string\" && id && /^[A-Za-z][A-Za-z0-9_:\\-\\.]*$/.test(id);\n };\n /**\n * Create or update an `event` object, based on the `eventType`.\n * @private\n */\n var _createEvent = function(event) {\n var eventType;\n if (typeof event === \"string\" && event) {\n eventType = event;\n event = {};\n } else if (typeof event === \"object\" && event && typeof event.type === \"string\" && event.type) {\n eventType = event.type;\n }\n if (!eventType) {\n return;\n }\n eventType = eventType.toLowerCase();\n if (!event.target && (/^(copy|aftercopy|_click)$/.test(eventType) || eventType === \"error\" && event.name === \"clipboard-error\")) {\n event.target = _copyTarget;\n }\n _extend(event, {\n type: eventType,\n target: event.target || _currentElement || null,\n relatedTarget: event.relatedTarget || null,\n currentTarget: _flashState && _flashState.bridge || null,\n timeStamp: event.timeStamp || _now() || null\n });\n var msg = _eventMessages[event.type];\n if (event.type === \"error\" && event.name && msg) {\n msg = msg[event.name];\n }\n if (msg) {\n event.message = msg;\n }\n if (event.type === \"ready\") {\n _extend(event, {\n target: null,\n version: _flashState.version\n });\n }\n if (event.type === \"error\") {\n if (_flashStateErrorNameMatchingRegex.test(event.name)) {\n _extend(event, {\n target: null,\n minimumVersion: _minimumFlashVersion\n });\n }\n if (_flashStateEnabledErrorNameMatchingRegex.test(event.name)) {\n _extend(event, {\n version: _flashState.version\n });\n }\n }\n if (event.type === \"copy\") {\n event.clipboardData = {\n setData: ZeroClipboard.setData,\n clearData: ZeroClipboard.clearData\n };\n }\n if (event.type === \"aftercopy\") {\n event = _mapClipResultsFromFlash(event, _clipDataFormatMap);\n }\n if (event.target && !event.relatedTarget) {\n event.relatedTarget = _getRelatedTarget(event.target);\n }\n return _addMouseData(event);\n };\n /**\n * Get a relatedTarget from the target's `data-clipboard-target` attribute\n * @private\n */\n var _getRelatedTarget = function(targetEl) {\n var relatedTargetId = targetEl && targetEl.getAttribute && targetEl.getAttribute(\"data-clipboard-target\");\n return relatedTargetId ? _document.getElementById(relatedTargetId) : null;\n };\n /**\n * Add element and position data to `MouseEvent` instances\n * @private\n */\n var _addMouseData = function(event) {\n if (event && /^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) {\n var srcElement = event.target;\n var fromElement = event.type === \"_mouseover\" && event.relatedTarget ? event.relatedTarget : undefined;\n var toElement = event.type === \"_mouseout\" && event.relatedTarget ? event.relatedTarget : undefined;\n var pos = _getElementPosition(srcElement);\n var screenLeft = _window.screenLeft || _window.screenX || 0;\n var screenTop = _window.screenTop || _window.screenY || 0;\n var scrollLeft = _document.body.scrollLeft + _document.documentElement.scrollLeft;\n var scrollTop = _document.body.scrollTop + _document.documentElement.scrollTop;\n var pageX = pos.left + (typeof event._stageX === \"number\" ? event._stageX : 0);\n var pageY = pos.top + (typeof event._stageY === \"number\" ? event._stageY : 0);\n var clientX = pageX - scrollLeft;\n var clientY = pageY - scrollTop;\n var screenX = screenLeft + clientX;\n var screenY = screenTop + clientY;\n var moveX = typeof event.movementX === \"number\" ? event.movementX : 0;\n var moveY = typeof event.movementY === \"number\" ? event.movementY : 0;\n delete event._stageX;\n delete event._stageY;\n _extend(event, {\n srcElement: srcElement,\n fromElement: fromElement,\n toElement: toElement,\n screenX: screenX,\n screenY: screenY,\n pageX: pageX,\n pageY: pageY,\n clientX: clientX,\n clientY: clientY,\n x: clientX,\n y: clientY,\n movementX: moveX,\n movementY: moveY,\n offsetX: 0,\n offsetY: 0,\n layerX: 0,\n layerY: 0\n });\n }\n return event;\n };\n /**\n * Determine if an event's registered handlers should be execute synchronously or asynchronously.\n *\n * @returns {boolean}\n * @private\n */\n var _shouldPerformAsync = function(event) {\n var eventType = event && typeof event.type === \"string\" && event.type || \"\";\n return !/^(?:(?:before)?copy|destroy)$/.test(eventType);\n };\n /**\n * Control if a callback should be executed asynchronously or not.\n *\n * @returns `undefined`\n * @private\n */\n var _dispatchCallback = function(func, context, args, async) {\n if (async) {\n _setTimeout(function() {\n func.apply(context, args);\n }, 0);\n } else {\n func.apply(context, args);\n }\n };\n /**\n * Handle the actual dispatching of events to client instances.\n *\n * @returns `undefined`\n * @private\n */\n var _dispatchCallbacks = function(event) {\n if (!(typeof event === \"object\" && event && event.type)) {\n return;\n }\n var async = _shouldPerformAsync(event);\n var wildcardTypeHandlers = _handlers[\"*\"] || [];\n var specificTypeHandlers = _handlers[event.type] || [];\n var handlers = wildcardTypeHandlers.concat(specificTypeHandlers);\n if (handlers && handlers.length) {\n var i, len, func, context, eventCopy, originalContext = this;\n for (i = 0, len = handlers.length; i < len; i++) {\n func = handlers[i];\n context = originalContext;\n if (typeof func === \"string\" && typeof _window[func] === \"function\") {\n func = _window[func];\n }\n if (typeof func === \"object\" && func && typeof func.handleEvent === \"function\") {\n context = func;\n func = func.handleEvent;\n }\n if (typeof func === \"function\") {\n eventCopy = _extend({}, event);\n _dispatchCallback(func, context, [ eventCopy ], async);\n }\n }\n }\n return this;\n };\n /**\n * Check an `error` event's `name` property to see if Flash has\n * already loaded, which rules out possible `iframe` sandboxing.\n * @private\n */\n var _getSandboxStatusFromErrorEvent = function(event) {\n var isSandboxed = null;\n if (_pageIsFramed === false || event && event.type === \"error\" && event.name && _errorsThatOnlyOccurAfterFlashLoads.indexOf(event.name) !== -1) {\n isSandboxed = false;\n }\n return isSandboxed;\n };\n /**\n * Preprocess any special behaviors, reactions, or state changes after receiving this event.\n * Executes only once per event emitted, NOT once per client.\n * @private\n */\n var _preprocessEvent = function(event) {\n var element = event.target || _currentElement || null;\n var sourceIsSwf = event._source === \"swf\";\n delete event._source;\n switch (event.type) {\n case \"error\":\n var isSandboxed = event.name === \"flash-sandboxed\" || _getSandboxStatusFromErrorEvent(event);\n if (typeof isSandboxed === \"boolean\") {\n _flashState.sandboxed = isSandboxed;\n }\n if (_flashStateErrorNames.indexOf(event.name) !== -1) {\n _extend(_flashState, {\n disabled: event.name === \"flash-disabled\",\n outdated: event.name === \"flash-outdated\",\n unavailable: event.name === \"flash-unavailable\",\n degraded: event.name === \"flash-degraded\",\n deactivated: event.name === \"flash-deactivated\",\n overdue: event.name === \"flash-overdue\",\n ready: false\n });\n } else if (event.name === \"version-mismatch\") {\n _zcSwfVersion = event.swfVersion;\n _extend(_flashState, {\n disabled: false,\n outdated: false,\n unavailable: false,\n degraded: false,\n deactivated: false,\n overdue: false,\n ready: false\n });\n }\n _clearTimeoutsAndPolling();\n break;\n\n case \"ready\":\n _zcSwfVersion = event.swfVersion;\n var wasDeactivated = _flashState.deactivated === true;\n _extend(_flashState, {\n disabled: false,\n outdated: false,\n sandboxed: false,\n unavailable: false,\n degraded: false,\n deactivated: false,\n overdue: wasDeactivated,\n ready: !wasDeactivated\n });\n _clearTimeoutsAndPolling();\n break;\n\n case \"beforecopy\":\n _copyTarget = element;\n break;\n\n case \"copy\":\n var textContent, htmlContent, targetEl = event.relatedTarget;\n if (!(_clipData[\"text/html\"] || _clipData[\"text/plain\"]) && targetEl && (htmlContent = targetEl.value || targetEl.outerHTML || targetEl.innerHTML) && (textContent = targetEl.value || targetEl.textContent || targetEl.innerText)) {\n event.clipboardData.clearData();\n event.clipboardData.setData(\"text/plain\", textContent);\n if (htmlContent !== textContent) {\n event.clipboardData.setData(\"text/html\", htmlContent);\n }\n } else if (!_clipData[\"text/plain\"] && event.target && (textContent = event.target.getAttribute(\"data-clipboard-text\"))) {\n event.clipboardData.clearData();\n event.clipboardData.setData(\"text/plain\", textContent);\n }\n break;\n\n case \"aftercopy\":\n _queueEmitClipboardErrors(event);\n ZeroClipboard.clearData();\n if (element && element !== _safeActiveElement() && element.focus) {\n element.focus();\n }\n break;\n\n case \"_mouseover\":\n ZeroClipboard.focus(element);\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) {\n _fireMouseEvent(_extend({}, event, {\n type: \"mouseenter\",\n bubbles: false,\n cancelable: false\n }));\n }\n _fireMouseEvent(_extend({}, event, {\n type: \"mouseover\"\n }));\n }\n break;\n\n case \"_mouseout\":\n ZeroClipboard.blur();\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) {\n _fireMouseEvent(_extend({}, event, {\n type: \"mouseleave\",\n bubbles: false,\n cancelable: false\n }));\n }\n _fireMouseEvent(_extend({}, event, {\n type: \"mouseout\"\n }));\n }\n break;\n\n case \"_mousedown\":\n _addClass(element, _globalConfig.activeClass);\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n _fireMouseEvent(_extend({}, event, {\n type: event.type.slice(1)\n }));\n }\n break;\n\n case \"_mouseup\":\n _removeClass(element, _globalConfig.activeClass);\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n _fireMouseEvent(_extend({}, event, {\n type: event.type.slice(1)\n }));\n }\n break;\n\n case \"_click\":\n _copyTarget = null;\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n _fireMouseEvent(_extend({}, event, {\n type: event.type.slice(1)\n }));\n }\n break;\n\n case \"_mousemove\":\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n _fireMouseEvent(_extend({}, event, {\n type: event.type.slice(1)\n }));\n }\n break;\n }\n if (/^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) {\n return true;\n }\n };\n /**\n * Check an \"aftercopy\" event for clipboard errors and emit a corresponding \"error\" event.\n * @private\n */\n var _queueEmitClipboardErrors = function(aftercopyEvent) {\n if (aftercopyEvent.errors && aftercopyEvent.errors.length > 0) {\n var errorEvent = _deepCopy(aftercopyEvent);\n _extend(errorEvent, {\n type: \"error\",\n name: \"clipboard-error\"\n });\n delete errorEvent.success;\n _setTimeout(function() {\n ZeroClipboard.emit(errorEvent);\n }, 0);\n }\n };\n /**\n * Dispatch a synthetic MouseEvent.\n *\n * @returns `undefined`\n * @private\n */\n var _fireMouseEvent = function(event) {\n if (!(event && typeof event.type === \"string\" && event)) {\n return;\n }\n var e, target = event.target || null, doc = target && target.ownerDocument || _document, defaults = {\n view: doc.defaultView || _window,\n canBubble: true,\n cancelable: true,\n detail: event.type === \"click\" ? 1 : 0,\n button: typeof event.which === \"number\" ? event.which - 1 : typeof event.button === \"number\" ? event.button : doc.createEvent ? 0 : 1\n }, args = _extend(defaults, event);\n if (!target) {\n return;\n }\n if (doc.createEvent && target.dispatchEvent) {\n args = [ args.type, args.canBubble, args.cancelable, args.view, args.detail, args.screenX, args.screenY, args.clientX, args.clientY, args.ctrlKey, args.altKey, args.shiftKey, args.metaKey, args.button, args.relatedTarget ];\n e = doc.createEvent(\"MouseEvents\");\n if (e.initMouseEvent) {\n e.initMouseEvent.apply(e, args);\n e._source = \"js\";\n target.dispatchEvent(e);\n }\n }\n };\n /**\n * Continuously poll the DOM until either:\n * (a) the fallback content becomes visible, or\n * (b) we receive an event from SWF (handled elsewhere)\n *\n * IMPORTANT:\n * This is NOT a necessary check but it can result in significantly faster\n * detection of bad `swfPath` configuration and/or network/server issues [in\n * supported browsers] than waiting for the entire `flashLoadTimeout` duration\n * to elapse before detecting that the SWF cannot be loaded. The detection\n * duration can be anywhere from 10-30 times faster [in supported browsers] by\n * using this approach.\n *\n * @returns `undefined`\n * @private\n */\n var _watchForSwfFallbackContent = function() {\n var maxWait = _globalConfig.flashLoadTimeout;\n if (typeof maxWait === \"number\" && maxWait >= 0) {\n var pollWait = Math.min(1e3, maxWait / 10);\n var fallbackContentId = _globalConfig.swfObjectId + \"_fallbackContent\";\n _swfFallbackCheckInterval = _setInterval(function() {\n var el = _document.getElementById(fallbackContentId);\n if (_isElementVisible(el)) {\n _clearTimeoutsAndPolling();\n _flashState.deactivated = null;\n ZeroClipboard.emit({\n type: \"error\",\n name: \"swf-not-found\"\n });\n }\n }, pollWait);\n }\n };\n /**\n * Create the HTML bridge element to embed the Flash object into.\n * @private\n */\n var _createHtmlBridge = function() {\n var container = _document.createElement(\"div\");\n container.id = _globalConfig.containerId;\n container.className = _globalConfig.containerClass;\n container.style.position = \"absolute\";\n container.style.left = \"0px\";\n container.style.top = \"-9999px\";\n container.style.width = \"1px\";\n container.style.height = \"1px\";\n container.style.zIndex = \"\" + _getSafeZIndex(_globalConfig.zIndex);\n return container;\n };\n /**\n * Get the HTML element container that wraps the Flash bridge object/element.\n * @private\n */\n var _getHtmlBridge = function(flashBridge) {\n var htmlBridge = flashBridge && flashBridge.parentNode;\n while (htmlBridge && htmlBridge.nodeName === \"OBJECT\" && htmlBridge.parentNode) {\n htmlBridge = htmlBridge.parentNode;\n }\n return htmlBridge || null;\n };\n /**\n * Create the SWF object.\n *\n * @returns The SWF object reference.\n * @private\n */\n var _embedSwf = function() {\n var len, flashBridge = _flashState.bridge, container = _getHtmlBridge(flashBridge);\n if (!flashBridge) {\n var allowScriptAccess = _determineScriptAccess(_window.location.host, _globalConfig);\n var allowNetworking = allowScriptAccess === \"never\" ? \"none\" : \"all\";\n var flashvars = _vars(_extend({\n jsVersion: ZeroClipboard.version\n }, _globalConfig));\n var swfUrl = _globalConfig.swfPath + _cacheBust(_globalConfig.swfPath, _globalConfig);\n container = _createHtmlBridge();\n var divToBeReplaced = _document.createElement(\"div\");\n container.appendChild(divToBeReplaced);\n _document.body.appendChild(container);\n var tmpDiv = _document.createElement(\"div\");\n var usingActiveX = _flashState.pluginType === \"activex\";\n tmpDiv.innerHTML = '\" + (usingActiveX ? '' : \"\") + '' + '' + '' + '' + '' + '
 
' + \"
\";\n flashBridge = tmpDiv.firstChild;\n tmpDiv = null;\n _unwrap(flashBridge).ZeroClipboard = ZeroClipboard;\n container.replaceChild(flashBridge, divToBeReplaced);\n _watchForSwfFallbackContent();\n }\n if (!flashBridge) {\n flashBridge = _document[_globalConfig.swfObjectId];\n if (flashBridge && (len = flashBridge.length)) {\n flashBridge = flashBridge[len - 1];\n }\n if (!flashBridge && container) {\n flashBridge = container.firstChild;\n }\n }\n _flashState.bridge = flashBridge || null;\n return flashBridge;\n };\n /**\n * Destroy the SWF object.\n * @private\n */\n var _unembedSwf = function() {\n var flashBridge = _flashState.bridge;\n if (flashBridge) {\n var htmlBridge = _getHtmlBridge(flashBridge);\n if (htmlBridge) {\n if (_flashState.pluginType === \"activex\" && \"readyState\" in flashBridge) {\n flashBridge.style.display = \"none\";\n (function removeSwfFromIE() {\n if (flashBridge.readyState === 4) {\n for (var prop in flashBridge) {\n if (typeof flashBridge[prop] === \"function\") {\n flashBridge[prop] = null;\n }\n }\n if (flashBridge.parentNode) {\n flashBridge.parentNode.removeChild(flashBridge);\n }\n if (htmlBridge.parentNode) {\n htmlBridge.parentNode.removeChild(htmlBridge);\n }\n } else {\n _setTimeout(removeSwfFromIE, 10);\n }\n })();\n } else {\n if (flashBridge.parentNode) {\n flashBridge.parentNode.removeChild(flashBridge);\n }\n if (htmlBridge.parentNode) {\n htmlBridge.parentNode.removeChild(htmlBridge);\n }\n }\n }\n _clearTimeoutsAndPolling();\n _flashState.ready = null;\n _flashState.bridge = null;\n _flashState.deactivated = null;\n _zcSwfVersion = undefined;\n }\n };\n /**\n * Map the data format names of the \"clipData\" to Flash-friendly names.\n *\n * @returns A new transformed object.\n * @private\n */\n var _mapClipDataToFlash = function(clipData) {\n var newClipData = {}, formatMap = {};\n if (!(typeof clipData === \"object\" && clipData)) {\n return;\n }\n for (var dataFormat in clipData) {\n if (dataFormat && _hasOwn.call(clipData, dataFormat) && typeof clipData[dataFormat] === \"string\" && clipData[dataFormat]) {\n switch (dataFormat.toLowerCase()) {\n case \"text/plain\":\n case \"text\":\n case \"air:text\":\n case \"flash:text\":\n newClipData.text = clipData[dataFormat];\n formatMap.text = dataFormat;\n break;\n\n case \"text/html\":\n case \"html\":\n case \"air:html\":\n case \"flash:html\":\n newClipData.html = clipData[dataFormat];\n formatMap.html = dataFormat;\n break;\n\n case \"application/rtf\":\n case \"text/rtf\":\n case \"rtf\":\n case \"richtext\":\n case \"air:rtf\":\n case \"flash:rtf\":\n newClipData.rtf = clipData[dataFormat];\n formatMap.rtf = dataFormat;\n break;\n\n default:\n break;\n }\n }\n }\n return {\n data: newClipData,\n formatMap: formatMap\n };\n };\n /**\n * Map the data format names from Flash-friendly names back to their original \"clipData\" names (via a format mapping).\n *\n * @returns A new transformed object.\n * @private\n */\n var _mapClipResultsFromFlash = function(clipResults, formatMap) {\n if (!(typeof clipResults === \"object\" && clipResults && typeof formatMap === \"object\" && formatMap)) {\n return clipResults;\n }\n var newResults = {};\n for (var prop in clipResults) {\n if (_hasOwn.call(clipResults, prop)) {\n if (prop === \"errors\") {\n newResults[prop] = clipResults[prop] ? clipResults[prop].slice() : [];\n for (var i = 0, len = newResults[prop].length; i < len; i++) {\n newResults[prop][i].format = formatMap[newResults[prop][i].format];\n }\n } else if (prop !== \"success\" && prop !== \"data\") {\n newResults[prop] = clipResults[prop];\n } else {\n newResults[prop] = {};\n var tmpHash = clipResults[prop];\n for (var dataFormat in tmpHash) {\n if (dataFormat && _hasOwn.call(tmpHash, dataFormat) && _hasOwn.call(formatMap, dataFormat)) {\n newResults[prop][formatMap[dataFormat]] = tmpHash[dataFormat];\n }\n }\n }\n }\n }\n return newResults;\n };\n /**\n * Will look at a path, and will create a \"?noCache={time}\" or \"&noCache={time}\"\n * query param string to return. Does NOT append that string to the original path.\n * This is useful because ExternalInterface often breaks when a Flash SWF is cached.\n *\n * @returns The `noCache` query param with necessary \"?\"/\"&\" prefix.\n * @private\n */\n var _cacheBust = function(path, options) {\n var cacheBust = options == null || options && options.cacheBust === true;\n if (cacheBust) {\n return (path.indexOf(\"?\") === -1 ? \"?\" : \"&\") + \"noCache=\" + _now();\n } else {\n return \"\";\n }\n };\n /**\n * Creates a query string for the FlashVars param.\n * Does NOT include the cache-busting query param.\n *\n * @returns FlashVars query string\n * @private\n */\n var _vars = function(options) {\n var i, len, domain, domains, str = \"\", trustedOriginsExpanded = [];\n if (options.trustedDomains) {\n if (typeof options.trustedDomains === \"string\") {\n domains = [ options.trustedDomains ];\n } else if (typeof options.trustedDomains === \"object\" && \"length\" in options.trustedDomains) {\n domains = options.trustedDomains;\n }\n }\n if (domains && domains.length) {\n for (i = 0, len = domains.length; i < len; i++) {\n if (_hasOwn.call(domains, i) && domains[i] && typeof domains[i] === \"string\") {\n domain = _extractDomain(domains[i]);\n if (!domain) {\n continue;\n }\n if (domain === \"*\") {\n trustedOriginsExpanded.length = 0;\n trustedOriginsExpanded.push(domain);\n break;\n }\n trustedOriginsExpanded.push.apply(trustedOriginsExpanded, [ domain, \"//\" + domain, _window.location.protocol + \"//\" + domain ]);\n }\n }\n }\n if (trustedOriginsExpanded.length) {\n str += \"trustedOrigins=\" + _encodeURIComponent(trustedOriginsExpanded.join(\",\"));\n }\n if (options.forceEnhancedClipboard === true) {\n str += (str ? \"&\" : \"\") + \"forceEnhancedClipboard=true\";\n }\n if (typeof options.swfObjectId === \"string\" && options.swfObjectId) {\n str += (str ? \"&\" : \"\") + \"swfObjectId=\" + _encodeURIComponent(options.swfObjectId);\n }\n if (typeof options.jsVersion === \"string\" && options.jsVersion) {\n str += (str ? \"&\" : \"\") + \"jsVersion=\" + _encodeURIComponent(options.jsVersion);\n }\n return str;\n };\n /**\n * Extract the domain (e.g. \"github.com\") from an origin (e.g. \"https://github.com\") or\n * URL (e.g. \"https://github.com/zeroclipboard/zeroclipboard/\").\n *\n * @returns the domain\n * @private\n */\n var _extractDomain = function(originOrUrl) {\n if (originOrUrl == null || originOrUrl === \"\") {\n return null;\n }\n originOrUrl = originOrUrl.replace(/^\\s+|\\s+$/g, \"\");\n if (originOrUrl === \"\") {\n return null;\n }\n var protocolIndex = originOrUrl.indexOf(\"//\");\n originOrUrl = protocolIndex === -1 ? originOrUrl : originOrUrl.slice(protocolIndex + 2);\n var pathIndex = originOrUrl.indexOf(\"/\");\n originOrUrl = pathIndex === -1 ? originOrUrl : protocolIndex === -1 || pathIndex === 0 ? null : originOrUrl.slice(0, pathIndex);\n if (originOrUrl && originOrUrl.slice(-4).toLowerCase() === \".swf\") {\n return null;\n }\n return originOrUrl || null;\n };\n /**\n * Set `allowScriptAccess` based on `trustedDomains` and `window.location.host` vs. `swfPath`.\n *\n * @returns The appropriate script access level.\n * @private\n */\n var _determineScriptAccess = function() {\n var _extractAllDomains = function(origins) {\n var i, len, tmp, resultsArray = [];\n if (typeof origins === \"string\") {\n origins = [ origins ];\n }\n if (!(typeof origins === \"object\" && origins && typeof origins.length === \"number\")) {\n return resultsArray;\n }\n for (i = 0, len = origins.length; i < len; i++) {\n if (_hasOwn.call(origins, i) && (tmp = _extractDomain(origins[i]))) {\n if (tmp === \"*\") {\n resultsArray.length = 0;\n resultsArray.push(\"*\");\n break;\n }\n if (resultsArray.indexOf(tmp) === -1) {\n resultsArray.push(tmp);\n }\n }\n }\n return resultsArray;\n };\n return function(currentDomain, configOptions) {\n var swfDomain = _extractDomain(configOptions.swfPath);\n if (swfDomain === null) {\n swfDomain = currentDomain;\n }\n var trustedDomains = _extractAllDomains(configOptions.trustedDomains);\n var len = trustedDomains.length;\n if (len > 0) {\n if (len === 1 && trustedDomains[0] === \"*\") {\n return \"always\";\n }\n if (trustedDomains.indexOf(currentDomain) !== -1) {\n if (len === 1 && currentDomain === swfDomain) {\n return \"sameDomain\";\n }\n return \"always\";\n }\n }\n return \"never\";\n };\n }();\n /**\n * Get the currently active/focused DOM element.\n *\n * @returns the currently active/focused element, or `null`\n * @private\n */\n var _safeActiveElement = function() {\n try {\n return _document.activeElement;\n } catch (err) {\n return null;\n }\n };\n /**\n * Add a class to an element, if it doesn't already have it.\n *\n * @returns The element, with its new class added.\n * @private\n */\n var _addClass = function(element, value) {\n var c, cl, className, classNames = [];\n if (typeof value === \"string\" && value) {\n classNames = value.split(/\\s+/);\n }\n if (element && element.nodeType === 1 && classNames.length > 0) {\n if (element.classList) {\n for (c = 0, cl = classNames.length; c < cl; c++) {\n element.classList.add(classNames[c]);\n }\n } else if (element.hasOwnProperty(\"className\")) {\n className = \" \" + element.className + \" \";\n for (c = 0, cl = classNames.length; c < cl; c++) {\n if (className.indexOf(\" \" + classNames[c] + \" \") === -1) {\n className += classNames[c] + \" \";\n }\n }\n element.className = className.replace(/^\\s+|\\s+$/g, \"\");\n }\n }\n return element;\n };\n /**\n * Remove a class from an element, if it has it.\n *\n * @returns The element, with its class removed.\n * @private\n */\n var _removeClass = function(element, value) {\n var c, cl, className, classNames = [];\n if (typeof value === \"string\" && value) {\n classNames = value.split(/\\s+/);\n }\n if (element && element.nodeType === 1 && classNames.length > 0) {\n if (element.classList && element.classList.length > 0) {\n for (c = 0, cl = classNames.length; c < cl; c++) {\n element.classList.remove(classNames[c]);\n }\n } else if (element.className) {\n className = (\" \" + element.className + \" \").replace(/[\\r\\n\\t]/g, \" \");\n for (c = 0, cl = classNames.length; c < cl; c++) {\n className = className.replace(\" \" + classNames[c] + \" \", \" \");\n }\n element.className = className.replace(/^\\s+|\\s+$/g, \"\");\n }\n }\n return element;\n };\n /**\n * Attempt to interpret the element's CSS styling. If `prop` is `\"cursor\"`,\n * then we assume that it should be a hand (\"pointer\") cursor if the element\n * is an anchor element (\"a\" tag).\n *\n * @returns The computed style property.\n * @private\n */\n var _getStyle = function(el, prop) {\n var value = _getComputedStyle(el, null).getPropertyValue(prop);\n if (prop === \"cursor\") {\n if (!value || value === \"auto\") {\n if (el.nodeName === \"A\") {\n return \"pointer\";\n }\n }\n }\n return value;\n };\n /**\n * Get the absolutely positioned coordinates of a DOM element.\n *\n * @returns Object containing the element's position, width, and height.\n * @private\n */\n var _getElementPosition = function(el) {\n var pos = {\n left: 0,\n top: 0,\n width: 0,\n height: 0\n };\n if (el.getBoundingClientRect) {\n var elRect = el.getBoundingClientRect();\n var pageXOffset = _window.pageXOffset;\n var pageYOffset = _window.pageYOffset;\n var leftBorderWidth = _document.documentElement.clientLeft || 0;\n var topBorderWidth = _document.documentElement.clientTop || 0;\n var leftBodyOffset = 0;\n var topBodyOffset = 0;\n if (_getStyle(_document.body, \"position\") === \"relative\") {\n var bodyRect = _document.body.getBoundingClientRect();\n var htmlRect = _document.documentElement.getBoundingClientRect();\n leftBodyOffset = bodyRect.left - htmlRect.left || 0;\n topBodyOffset = bodyRect.top - htmlRect.top || 0;\n }\n pos.left = elRect.left + pageXOffset - leftBorderWidth - leftBodyOffset;\n pos.top = elRect.top + pageYOffset - topBorderWidth - topBodyOffset;\n pos.width = \"width\" in elRect ? elRect.width : elRect.right - elRect.left;\n pos.height = \"height\" in elRect ? elRect.height : elRect.bottom - elRect.top;\n }\n return pos;\n };\n /**\n * Determine is an element is visible somewhere within the document (page).\n *\n * @returns Boolean\n * @private\n */\n var _isElementVisible = function(el) {\n if (!el) {\n return false;\n }\n var styles = _getComputedStyle(el, null);\n var hasCssHeight = _parseFloat(styles.height) > 0;\n var hasCssWidth = _parseFloat(styles.width) > 0;\n var hasCssTop = _parseFloat(styles.top) >= 0;\n var hasCssLeft = _parseFloat(styles.left) >= 0;\n var cssKnows = hasCssHeight && hasCssWidth && hasCssTop && hasCssLeft;\n var rect = cssKnows ? null : _getElementPosition(el);\n var isVisible = styles.display !== \"none\" && styles.visibility !== \"collapse\" && (cssKnows || !!rect && (hasCssHeight || rect.height > 0) && (hasCssWidth || rect.width > 0) && (hasCssTop || rect.top >= 0) && (hasCssLeft || rect.left >= 0));\n return isVisible;\n };\n /**\n * Clear all existing timeouts and interval polling delegates.\n *\n * @returns `undefined`\n * @private\n */\n var _clearTimeoutsAndPolling = function() {\n _clearTimeout(_flashCheckTimeout);\n _flashCheckTimeout = 0;\n _clearInterval(_swfFallbackCheckInterval);\n _swfFallbackCheckInterval = 0;\n };\n /**\n * Reposition the Flash object to cover the currently activated element.\n *\n * @returns `undefined`\n * @private\n */\n var _reposition = function() {\n var htmlBridge;\n if (_currentElement && (htmlBridge = _getHtmlBridge(_flashState.bridge))) {\n var pos = _getElementPosition(_currentElement);\n _extend(htmlBridge.style, {\n width: pos.width + \"px\",\n height: pos.height + \"px\",\n top: pos.top + \"px\",\n left: pos.left + \"px\",\n zIndex: \"\" + _getSafeZIndex(_globalConfig.zIndex)\n });\n }\n };\n /**\n * Sends a signal to the Flash object to display the hand cursor if `true`.\n *\n * @returns `undefined`\n * @private\n */\n var _setHandCursor = function(enabled) {\n if (_flashState.ready === true) {\n if (_flashState.bridge && typeof _flashState.bridge.setHandCursor === \"function\") {\n _flashState.bridge.setHandCursor(enabled);\n } else {\n _flashState.ready = false;\n }\n }\n };\n /**\n * Get a safe value for `zIndex`\n *\n * @returns an integer, or \"auto\"\n * @private\n */\n var _getSafeZIndex = function(val) {\n if (/^(?:auto|inherit)$/.test(val)) {\n return val;\n }\n var zIndex;\n if (typeof val === \"number\" && !_isNaN(val)) {\n zIndex = val;\n } else if (typeof val === \"string\") {\n zIndex = _getSafeZIndex(_parseInt(val, 10));\n }\n return typeof zIndex === \"number\" ? zIndex : \"auto\";\n };\n /**\n * Attempt to detect if ZeroClipboard is executing inside of a sandboxed iframe.\n * If it is, Flash Player cannot be used, so ZeroClipboard is dead in the water.\n *\n * @see {@link http://lists.w3.org/Archives/Public/public-whatwg-archive/2014Dec/0002.html}\n * @see {@link https://github.com/zeroclipboard/zeroclipboard/issues/511}\n * @see {@link http://zeroclipboard.org/test-iframes.html}\n *\n * @returns `true` (is sandboxed), `false` (is not sandboxed), or `null` (uncertain) \n * @private\n */\n var _detectSandbox = function(doNotReassessFlashSupport) {\n var effectiveScriptOrigin, frame, frameError, previousState = _flashState.sandboxed, isSandboxed = null;\n doNotReassessFlashSupport = doNotReassessFlashSupport === true;\n if (_pageIsFramed === false) {\n isSandboxed = false;\n } else {\n try {\n frame = window.frameElement || null;\n } catch (e) {\n frameError = {\n name: e.name,\n message: e.message\n };\n }\n if (frame && frame.nodeType === 1 && frame.nodeName === \"IFRAME\") {\n try {\n isSandboxed = frame.hasAttribute(\"sandbox\");\n } catch (e) {\n isSandboxed = null;\n }\n } else {\n try {\n effectiveScriptOrigin = document.domain || null;\n } catch (e) {\n effectiveScriptOrigin = null;\n }\n if (effectiveScriptOrigin === null || frameError && frameError.name === \"SecurityError\" && /(^|[\\s\\(\\[@])sandbox(es|ed|ing|[\\s\\.,!\\)\\]@]|$)/.test(frameError.message.toLowerCase())) {\n isSandboxed = true;\n }\n }\n }\n _flashState.sandboxed = isSandboxed;\n if (previousState !== isSandboxed && !doNotReassessFlashSupport) {\n _detectFlashSupport(_ActiveXObject);\n }\n return isSandboxed;\n };\n /**\n * Detect the Flash Player status, version, and plugin type.\n *\n * @see {@link https://code.google.com/p/doctype-mirror/wiki/ArticleDetectFlash#The_code}\n * @see {@link http://stackoverflow.com/questions/12866060/detecting-pepper-ppapi-flash-with-javascript}\n *\n * @returns `undefined`\n * @private\n */\n var _detectFlashSupport = function(ActiveXObject) {\n var plugin, ax, mimeType, hasFlash = false, isActiveX = false, isPPAPI = false, flashVersion = \"\";\n /**\n * Derived from Apple's suggested sniffer.\n * @param {String} desc e.g. \"Shockwave Flash 7.0 r61\"\n * @returns {String} \"7.0.61\"\n * @private\n */\n function parseFlashVersion(desc) {\n var matches = desc.match(/[\\d]+/g);\n matches.length = 3;\n return matches.join(\".\");\n }\n function isPepperFlash(flashPlayerFileName) {\n return !!flashPlayerFileName && (flashPlayerFileName = flashPlayerFileName.toLowerCase()) && (/^(pepflashplayer\\.dll|libpepflashplayer\\.so|pepperflashplayer\\.plugin)$/.test(flashPlayerFileName) || flashPlayerFileName.slice(-13) === \"chrome.plugin\");\n }\n function inspectPlugin(plugin) {\n if (plugin) {\n hasFlash = true;\n if (plugin.version) {\n flashVersion = parseFlashVersion(plugin.version);\n }\n if (!flashVersion && plugin.description) {\n flashVersion = parseFlashVersion(plugin.description);\n }\n if (plugin.filename) {\n isPPAPI = isPepperFlash(plugin.filename);\n }\n }\n }\n if (_navigator.plugins && _navigator.plugins.length) {\n plugin = _navigator.plugins[\"Shockwave Flash\"];\n inspectPlugin(plugin);\n if (_navigator.plugins[\"Shockwave Flash 2.0\"]) {\n hasFlash = true;\n flashVersion = \"2.0.0.11\";\n }\n } else if (_navigator.mimeTypes && _navigator.mimeTypes.length) {\n mimeType = _navigator.mimeTypes[\"application/x-shockwave-flash\"];\n plugin = mimeType && mimeType.enabledPlugin;\n inspectPlugin(plugin);\n } else if (typeof ActiveXObject !== \"undefined\") {\n isActiveX = true;\n try {\n ax = new ActiveXObject(\"ShockwaveFlash.ShockwaveFlash.7\");\n hasFlash = true;\n flashVersion = parseFlashVersion(ax.GetVariable(\"$version\"));\n } catch (e1) {\n try {\n ax = new ActiveXObject(\"ShockwaveFlash.ShockwaveFlash.6\");\n hasFlash = true;\n flashVersion = \"6.0.21\";\n } catch (e2) {\n try {\n ax = new ActiveXObject(\"ShockwaveFlash.ShockwaveFlash\");\n hasFlash = true;\n flashVersion = parseFlashVersion(ax.GetVariable(\"$version\"));\n } catch (e3) {\n isActiveX = false;\n }\n }\n }\n }\n _flashState.disabled = hasFlash !== true;\n _flashState.outdated = flashVersion && _parseFloat(flashVersion) < _parseFloat(_minimumFlashVersion);\n _flashState.version = flashVersion || \"0.0.0\";\n _flashState.pluginType = isPPAPI ? \"pepper\" : isActiveX ? \"activex\" : hasFlash ? \"netscape\" : \"unknown\";\n };\n /**\n * Invoke the Flash detection algorithms immediately upon inclusion so we're not waiting later.\n */\n _detectFlashSupport(_ActiveXObject);\n /**\n * Always assess the `sandboxed` state of the page at important Flash-related moments.\n */\n _detectSandbox(true);\n /**\n * A shell constructor for `ZeroClipboard` client instances.\n *\n * @constructor\n */\n var ZeroClipboard = function() {\n if (!(this instanceof ZeroClipboard)) {\n return new ZeroClipboard();\n }\n if (typeof ZeroClipboard._createClient === \"function\") {\n ZeroClipboard._createClient.apply(this, _args(arguments));\n }\n };\n /**\n * The ZeroClipboard library's version number.\n *\n * @static\n * @readonly\n * @property {string}\n */\n _defineProperty(ZeroClipboard, \"version\", {\n value: \"2.2.0\",\n writable: false,\n configurable: true,\n enumerable: true\n });\n /**\n * Update or get a copy of the ZeroClipboard global configuration.\n * Returns a copy of the current/updated configuration.\n *\n * @returns Object\n * @static\n */\n ZeroClipboard.config = function() {\n return _config.apply(this, _args(arguments));\n };\n /**\n * Diagnostic method that describes the state of the browser, Flash Player, and ZeroClipboard.\n *\n * @returns Object\n * @static\n */\n ZeroClipboard.state = function() {\n return _state.apply(this, _args(arguments));\n };\n /**\n * Check if Flash is unusable for any reason: disabled, outdated, deactivated, etc.\n *\n * @returns Boolean\n * @static\n */\n ZeroClipboard.isFlashUnusable = function() {\n return _isFlashUnusable.apply(this, _args(arguments));\n };\n /**\n * Register an event listener.\n *\n * @returns `ZeroClipboard`\n * @static\n */\n ZeroClipboard.on = function() {\n return _on.apply(this, _args(arguments));\n };\n /**\n * Unregister an event listener.\n * If no `listener` function/object is provided, it will unregister all listeners for the provided `eventType`.\n * If no `eventType` is provided, it will unregister all listeners for every event type.\n *\n * @returns `ZeroClipboard`\n * @static\n */\n ZeroClipboard.off = function() {\n return _off.apply(this, _args(arguments));\n };\n /**\n * Retrieve event listeners for an `eventType`.\n * If no `eventType` is provided, it will retrieve all listeners for every event type.\n *\n * @returns array of listeners for the `eventType`; if no `eventType`, then a map/hash object of listeners for all event types; or `null`\n */\n ZeroClipboard.handlers = function() {\n return _listeners.apply(this, _args(arguments));\n };\n /**\n * Event emission receiver from the Flash object, forwarding to any registered JavaScript event listeners.\n *\n * @returns For the \"copy\" event, returns the Flash-friendly \"clipData\" object; otherwise `undefined`.\n * @static\n */\n ZeroClipboard.emit = function() {\n return _emit.apply(this, _args(arguments));\n };\n /**\n * Create and embed the Flash object.\n *\n * @returns The Flash object\n * @static\n */\n ZeroClipboard.create = function() {\n return _create.apply(this, _args(arguments));\n };\n /**\n * Self-destruct and clean up everything, including the embedded Flash object.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.destroy = function() {\n return _destroy.apply(this, _args(arguments));\n };\n /**\n * Set the pending data for clipboard injection.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.setData = function() {\n return _setData.apply(this, _args(arguments));\n };\n /**\n * Clear the pending data for clipboard injection.\n * If no `format` is provided, all pending data formats will be cleared.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.clearData = function() {\n return _clearData.apply(this, _args(arguments));\n };\n /**\n * Get a copy of the pending data for clipboard injection.\n * If no `format` is provided, a copy of ALL pending data formats will be returned.\n *\n * @returns `String` or `Object`\n * @static\n */\n ZeroClipboard.getData = function() {\n return _getData.apply(this, _args(arguments));\n };\n /**\n * Sets the current HTML object that the Flash object should overlay. This will put the global\n * Flash object on top of the current element; depending on the setup, this may also set the\n * pending clipboard text data as well as the Flash object's wrapping element's title attribute\n * based on the underlying HTML element and ZeroClipboard configuration.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.focus = ZeroClipboard.activate = function() {\n return _focus.apply(this, _args(arguments));\n };\n /**\n * Un-overlays the Flash object. This will put the global Flash object off-screen; depending on\n * the setup, this may also unset the Flash object's wrapping element's title attribute based on\n * the underlying HTML element and ZeroClipboard configuration.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.blur = ZeroClipboard.deactivate = function() {\n return _blur.apply(this, _args(arguments));\n };\n /**\n * Returns the currently focused/\"activated\" HTML element that the Flash object is wrapping.\n *\n * @returns `HTMLElement` or `null`\n * @static\n */\n ZeroClipboard.activeElement = function() {\n return _activeElement.apply(this, _args(arguments));\n };\n /**\n * Keep track of the ZeroClipboard client instance counter.\n */\n var _clientIdCounter = 0;\n /**\n * Keep track of the state of the client instances.\n *\n * Entry structure:\n * _clientMeta[client.id] = {\n * instance: client,\n * elements: [],\n * handlers: {}\n * };\n */\n var _clientMeta = {};\n /**\n * Keep track of the ZeroClipboard clipped elements counter.\n */\n var _elementIdCounter = 0;\n /**\n * Keep track of the state of the clipped element relationships to clients.\n *\n * Entry structure:\n * _elementMeta[element.zcClippingId] = [client1.id, client2.id];\n */\n var _elementMeta = {};\n /**\n * Keep track of the state of the mouse event handlers for clipped elements.\n *\n * Entry structure:\n * _mouseHandlers[element.zcClippingId] = {\n * mouseover: function(event) {},\n * mouseout: function(event) {},\n * mouseenter: function(event) {},\n * mouseleave: function(event) {},\n * mousemove: function(event) {}\n * };\n */\n var _mouseHandlers = {};\n /**\n * Extending the ZeroClipboard configuration defaults for the Client module.\n */\n _extend(_globalConfig, {\n autoActivate: true\n });\n /**\n * The real constructor for `ZeroClipboard` client instances.\n * @private\n */\n var _clientConstructor = function(elements) {\n var client = this;\n client.id = \"\" + _clientIdCounter++;\n _clientMeta[client.id] = {\n instance: client,\n elements: [],\n handlers: {}\n };\n if (elements) {\n client.clip(elements);\n }\n ZeroClipboard.on(\"*\", function(event) {\n return client.emit(event);\n });\n ZeroClipboard.on(\"destroy\", function() {\n client.destroy();\n });\n ZeroClipboard.create();\n };\n /**\n * The underlying implementation of `ZeroClipboard.Client.prototype.on`.\n * @private\n */\n var _clientOn = function(eventType, listener) {\n var i, len, events, added = {}, meta = _clientMeta[this.id], handlers = meta && meta.handlers;\n if (!meta) {\n throw new Error(\"Attempted to add new listener(s) to a destroyed ZeroClipboard client instance\");\n }\n if (typeof eventType === \"string\" && eventType) {\n events = eventType.toLowerCase().split(/\\s+/);\n } else if (typeof eventType === \"object\" && eventType && typeof listener === \"undefined\") {\n for (i in eventType) {\n if (_hasOwn.call(eventType, i) && typeof i === \"string\" && i && typeof eventType[i] === \"function\") {\n this.on(i, eventType[i]);\n }\n }\n }\n if (events && events.length) {\n for (i = 0, len = events.length; i < len; i++) {\n eventType = events[i].replace(/^on/, \"\");\n added[eventType] = true;\n if (!handlers[eventType]) {\n handlers[eventType] = [];\n }\n handlers[eventType].push(listener);\n }\n if (added.ready && _flashState.ready) {\n this.emit({\n type: \"ready\",\n client: this\n });\n }\n if (added.error) {\n for (i = 0, len = _flashStateErrorNames.length; i < len; i++) {\n if (_flashState[_flashStateErrorNames[i].replace(/^flash-/, \"\")]) {\n this.emit({\n type: \"error\",\n name: _flashStateErrorNames[i],\n client: this\n });\n break;\n }\n }\n if (_zcSwfVersion !== undefined && ZeroClipboard.version !== _zcSwfVersion) {\n this.emit({\n type: \"error\",\n name: \"version-mismatch\",\n jsVersion: ZeroClipboard.version,\n swfVersion: _zcSwfVersion\n });\n }\n }\n }\n return this;\n };\n /**\n * The underlying implementation of `ZeroClipboard.Client.prototype.off`.\n * @private\n */\n var _clientOff = function(eventType, listener) {\n var i, len, foundIndex, events, perEventHandlers, meta = _clientMeta[this.id], handlers = meta && meta.handlers;\n if (!handlers) {\n return this;\n }\n if (arguments.length === 0) {\n events = _keys(handlers);\n } else if (typeof eventType === \"string\" && eventType) {\n events = eventType.split(/\\s+/);\n } else if (typeof eventType === \"object\" && eventType && typeof listener === \"undefined\") {\n for (i in eventType) {\n if (_hasOwn.call(eventType, i) && typeof i === \"string\" && i && typeof eventType[i] === \"function\") {\n this.off(i, eventType[i]);\n }\n }\n }\n if (events && events.length) {\n for (i = 0, len = events.length; i < len; i++) {\n eventType = events[i].toLowerCase().replace(/^on/, \"\");\n perEventHandlers = handlers[eventType];\n if (perEventHandlers && perEventHandlers.length) {\n if (listener) {\n foundIndex = perEventHandlers.indexOf(listener);\n while (foundIndex !== -1) {\n perEventHandlers.splice(foundIndex, 1);\n foundIndex = perEventHandlers.indexOf(listener, foundIndex);\n }\n } else {\n perEventHandlers.length = 0;\n }\n }\n }\n }\n return this;\n };\n /**\n * The underlying implementation of `ZeroClipboard.Client.prototype.handlers`.\n * @private\n */\n var _clientListeners = function(eventType) {\n var copy = null, handlers = _clientMeta[this.id] && _clientMeta[this.id].handlers;\n if (handlers) {\n if (typeof eventType === \"string\" && eventType) {\n copy = handlers[eventType] ? handlers[eventType].slice(0) : [];\n } else {\n copy = _deepCopy(handlers);\n }\n }\n return copy;\n };\n /**\n * The underlying implementation of `ZeroClipboard.Client.prototype.emit`.\n * @private\n */\n var _clientEmit = function(event) {\n if (_clientShouldEmit.call(this, event)) {\n if (typeof event === \"object\" && event && typeof event.type === \"string\" && event.type) {\n event = _extend({}, event);\n }\n var eventCopy = _extend({}, _createEvent(event), {\n client: this\n });\n _clientDispatchCallbacks.call(this, eventCopy);\n }\n return this;\n };\n /**\n * The underlying implementation of `ZeroClipboard.Client.prototype.clip`.\n * @private\n */\n var _clientClip = function(elements) {\n if (!_clientMeta[this.id]) {\n throw new Error(\"Attempted to clip element(s) to a destroyed ZeroClipboard client instance\");\n }\n elements = _prepClip(elements);\n for (var i = 0; i < elements.length; i++) {\n if (_hasOwn.call(elements, i) && elements[i] && elements[i].nodeType === 1) {\n if (!elements[i].zcClippingId) {\n elements[i].zcClippingId = \"zcClippingId_\" + _elementIdCounter++;\n _elementMeta[elements[i].zcClippingId] = [ this.id ];\n if (_globalConfig.autoActivate === true) {\n _addMouseHandlers(elements[i]);\n }\n } else if (_elementMeta[elements[i].zcClippingId].indexOf(this.id) === -1) {\n _elementMeta[elements[i].zcClippingId].push(this.id);\n }\n var clippedElements = _clientMeta[this.id] && _clientMeta[this.id].elements;\n if (clippedElements.indexOf(elements[i]) === -1) {\n clippedElements.push(elements[i]);\n }\n }\n }\n return this;\n };\n /**\n * The underlying implementation of `ZeroClipboard.Client.prototype.unclip`.\n * @private\n */\n var _clientUnclip = function(elements) {\n var meta = _clientMeta[this.id];\n if (!meta) {\n return this;\n }\n var clippedElements = meta.elements;\n var arrayIndex;\n if (typeof elements === \"undefined\") {\n elements = clippedElements.slice(0);\n } else {\n elements = _prepClip(elements);\n }\n for (var i = elements.length; i--; ) {\n if (_hasOwn.call(elements, i) && elements[i] && elements[i].nodeType === 1) {\n arrayIndex = 0;\n while ((arrayIndex = clippedElements.indexOf(elements[i], arrayIndex)) !== -1) {\n clippedElements.splice(arrayIndex, 1);\n }\n var clientIds = _elementMeta[elements[i].zcClippingId];\n if (clientIds) {\n arrayIndex = 0;\n while ((arrayIndex = clientIds.indexOf(this.id, arrayIndex)) !== -1) {\n clientIds.splice(arrayIndex, 1);\n }\n if (clientIds.length === 0) {\n if (_globalConfig.autoActivate === true) {\n _removeMouseHandlers(elements[i]);\n }\n delete elements[i].zcClippingId;\n }\n }\n }\n }\n return this;\n };\n /**\n * The underlying implementation of `ZeroClipboard.Client.prototype.elements`.\n * @private\n */\n var _clientElements = function() {\n var meta = _clientMeta[this.id];\n return meta && meta.elements ? meta.elements.slice(0) : [];\n };\n /**\n * The underlying implementation of `ZeroClipboard.Client.prototype.destroy`.\n * @private\n */\n var _clientDestroy = function() {\n if (!_clientMeta[this.id]) {\n return;\n }\n this.unclip();\n this.off();\n delete _clientMeta[this.id];\n };\n /**\n * Inspect an Event to see if the Client (`this`) should honor it for emission.\n * @private\n */\n var _clientShouldEmit = function(event) {\n if (!(event && event.type)) {\n return false;\n }\n if (event.client && event.client !== this) {\n return false;\n }\n var meta = _clientMeta[this.id];\n var clippedEls = meta && meta.elements;\n var hasClippedEls = !!clippedEls && clippedEls.length > 0;\n var goodTarget = !event.target || hasClippedEls && clippedEls.indexOf(event.target) !== -1;\n var goodRelTarget = event.relatedTarget && hasClippedEls && clippedEls.indexOf(event.relatedTarget) !== -1;\n var goodClient = event.client && event.client === this;\n if (!meta || !(goodTarget || goodRelTarget || goodClient)) {\n return false;\n }\n return true;\n };\n /**\n * Handle the actual dispatching of events to a client instance.\n *\n * @returns `undefined`\n * @private\n */\n var _clientDispatchCallbacks = function(event) {\n var meta = _clientMeta[this.id];\n if (!(typeof event === \"object\" && event && event.type && meta)) {\n return;\n }\n var async = _shouldPerformAsync(event);\n var wildcardTypeHandlers = meta && meta.handlers[\"*\"] || [];\n var specificTypeHandlers = meta && meta.handlers[event.type] || [];\n var handlers = wildcardTypeHandlers.concat(specificTypeHandlers);\n if (handlers && handlers.length) {\n var i, len, func, context, eventCopy, originalContext = this;\n for (i = 0, len = handlers.length; i < len; i++) {\n func = handlers[i];\n context = originalContext;\n if (typeof func === \"string\" && typeof _window[func] === \"function\") {\n func = _window[func];\n }\n if (typeof func === \"object\" && func && typeof func.handleEvent === \"function\") {\n context = func;\n func = func.handleEvent;\n }\n if (typeof func === \"function\") {\n eventCopy = _extend({}, event);\n _dispatchCallback(func, context, [ eventCopy ], async);\n }\n }\n }\n };\n /**\n * Prepares the elements for clipping/unclipping.\n *\n * @returns An Array of elements.\n * @private\n */\n var _prepClip = function(elements) {\n if (typeof elements === \"string\") {\n elements = [];\n }\n return typeof elements.length !== \"number\" ? [ elements ] : elements;\n };\n /**\n * Add a `mouseover` handler function for a clipped element.\n *\n * @returns `undefined`\n * @private\n */\n var _addMouseHandlers = function(element) {\n if (!(element && element.nodeType === 1)) {\n return;\n }\n var _suppressMouseEvents = function(event) {\n if (!(event || (event = _window.event))) {\n return;\n }\n if (event._source !== \"js\") {\n event.stopImmediatePropagation();\n event.preventDefault();\n }\n delete event._source;\n };\n var _elementMouseOver = function(event) {\n if (!(event || (event = _window.event))) {\n return;\n }\n _suppressMouseEvents(event);\n ZeroClipboard.focus(element);\n };\n element.addEventListener(\"mouseover\", _elementMouseOver, false);\n element.addEventListener(\"mouseout\", _suppressMouseEvents, false);\n element.addEventListener(\"mouseenter\", _suppressMouseEvents, false);\n element.addEventListener(\"mouseleave\", _suppressMouseEvents, false);\n element.addEventListener(\"mousemove\", _suppressMouseEvents, false);\n _mouseHandlers[element.zcClippingId] = {\n mouseover: _elementMouseOver,\n mouseout: _suppressMouseEvents,\n mouseenter: _suppressMouseEvents,\n mouseleave: _suppressMouseEvents,\n mousemove: _suppressMouseEvents\n };\n };\n /**\n * Remove a `mouseover` handler function for a clipped element.\n *\n * @returns `undefined`\n * @private\n */\n var _removeMouseHandlers = function(element) {\n if (!(element && element.nodeType === 1)) {\n return;\n }\n var mouseHandlers = _mouseHandlers[element.zcClippingId];\n if (!(typeof mouseHandlers === \"object\" && mouseHandlers)) {\n return;\n }\n var key, val, mouseEvents = [ \"move\", \"leave\", \"enter\", \"out\", \"over\" ];\n for (var i = 0, len = mouseEvents.length; i < len; i++) {\n key = \"mouse\" + mouseEvents[i];\n val = mouseHandlers[key];\n if (typeof val === \"function\") {\n element.removeEventListener(key, val, false);\n }\n }\n delete _mouseHandlers[element.zcClippingId];\n };\n /**\n * Creates a new ZeroClipboard client instance.\n * Optionally, auto-`clip` an element or collection of elements.\n *\n * @constructor\n */\n ZeroClipboard._createClient = function() {\n _clientConstructor.apply(this, _args(arguments));\n };\n /**\n * Register an event listener to the client.\n *\n * @returns `this`\n */\n ZeroClipboard.prototype.on = function() {\n return _clientOn.apply(this, _args(arguments));\n };\n /**\n * Unregister an event handler from the client.\n * If no `listener` function/object is provided, it will unregister all handlers for the provided `eventType`.\n * If no `eventType` is provided, it will unregister all handlers for every event type.\n *\n * @returns `this`\n */\n ZeroClipboard.prototype.off = function() {\n return _clientOff.apply(this, _args(arguments));\n };\n /**\n * Retrieve event listeners for an `eventType` from the client.\n * If no `eventType` is provided, it will retrieve all listeners for every event type.\n *\n * @returns array of listeners for the `eventType`; if no `eventType`, then a map/hash object of listeners for all event types; or `null`\n */\n ZeroClipboard.prototype.handlers = function() {\n return _clientListeners.apply(this, _args(arguments));\n };\n /**\n * Event emission receiver from the Flash object for this client's registered JavaScript event listeners.\n *\n * @returns For the \"copy\" event, returns the Flash-friendly \"clipData\" object; otherwise `undefined`.\n */\n ZeroClipboard.prototype.emit = function() {\n return _clientEmit.apply(this, _args(arguments));\n };\n /**\n * Register clipboard actions for new element(s) to the client.\n *\n * @returns `this`\n */\n ZeroClipboard.prototype.clip = function() {\n return _clientClip.apply(this, _args(arguments));\n };\n /**\n * Unregister the clipboard actions of previously registered element(s) on the page.\n * If no elements are provided, ALL registered elements will be unregistered.\n *\n * @returns `this`\n */\n ZeroClipboard.prototype.unclip = function() {\n return _clientUnclip.apply(this, _args(arguments));\n };\n /**\n * Get all of the elements to which this client is clipped.\n *\n * @returns array of clipped elements\n */\n ZeroClipboard.prototype.elements = function() {\n return _clientElements.apply(this, _args(arguments));\n };\n /**\n * Self-destruct and clean up everything for a single client.\n * This will NOT destroy the embedded Flash object.\n *\n * @returns `undefined`\n */\n ZeroClipboard.prototype.destroy = function() {\n return _clientDestroy.apply(this, _args(arguments));\n };\n /**\n * Stores the pending plain text to inject into the clipboard.\n *\n * @returns `this`\n */\n ZeroClipboard.prototype.setText = function(text) {\n if (!_clientMeta[this.id]) {\n throw new Error(\"Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance\");\n }\n ZeroClipboard.setData(\"text/plain\", text);\n return this;\n };\n /**\n * Stores the pending HTML text to inject into the clipboard.\n *\n * @returns `this`\n */\n ZeroClipboard.prototype.setHtml = function(html) {\n if (!_clientMeta[this.id]) {\n throw new Error(\"Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance\");\n }\n ZeroClipboard.setData(\"text/html\", html);\n return this;\n };\n /**\n * Stores the pending rich text (RTF) to inject into the clipboard.\n *\n * @returns `this`\n */\n ZeroClipboard.prototype.setRichText = function(richText) {\n if (!_clientMeta[this.id]) {\n throw new Error(\"Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance\");\n }\n ZeroClipboard.setData(\"application/rtf\", richText);\n return this;\n };\n /**\n * Stores the pending data to inject into the clipboard.\n *\n * @returns `this`\n */\n ZeroClipboard.prototype.setData = function() {\n if (!_clientMeta[this.id]) {\n throw new Error(\"Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance\");\n }\n ZeroClipboard.setData.apply(this, _args(arguments));\n return this;\n };\n /**\n * Clears the pending data to inject into the clipboard.\n * If no `format` is provided, all pending data formats will be cleared.\n *\n * @returns `this`\n */\n ZeroClipboard.prototype.clearData = function() {\n if (!_clientMeta[this.id]) {\n throw new Error(\"Attempted to clear pending clipboard data from a destroyed ZeroClipboard client instance\");\n }\n ZeroClipboard.clearData.apply(this, _args(arguments));\n return this;\n };\n /**\n * Gets a copy of the pending data to inject into the clipboard.\n * If no `format` is provided, a copy of ALL pending data formats will be returned.\n *\n * @returns `String` or `Object`\n */\n ZeroClipboard.prototype.getData = function() {\n if (!_clientMeta[this.id]) {\n throw new Error(\"Attempted to get pending clipboard data from a destroyed ZeroClipboard client instance\");\n }\n return ZeroClipboard.getData.apply(this, _args(arguments));\n };\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return ZeroClipboard;\n });\n } else if (typeof module === \"object\" && module && typeof module.exports === \"object\" && module.exports) {\n module.exports = ZeroClipboard;\n } else {\n window.ZeroClipboard = ZeroClipboard;\n }\n})(function() {\n return this || window;\n}());"]} \ No newline at end of file diff --git a/resources/zeroclipboard/ZeroClipboard.swf b/resources/zeroclipboard/ZeroClipboard.swf new file mode 100644 index 0000000000..8bad6a3e34 Binary files /dev/null and b/resources/zeroclipboard/ZeroClipboard.swf differ diff --git a/tasks/build-examples.js b/tasks/build-examples.js new file mode 100644 index 0000000000..412324a0e3 --- /dev/null +++ b/tasks/build-examples.js @@ -0,0 +1,92 @@ +/*global Buffer */ + +var Metalsmith = require('metalsmith'); +var templates = require('metalsmith-templates'); +var marked = require('marked'); +var fs = require('fs'); +var pjson = require('../package.json'); + +var fileRegEx = /([^\/^\.]*)\.html$/; +var cleanupJSRegEx = /.*(goog\.require(.*);|.*renderer: exampleNS\..*,?)[\n]*/g; +var isCssRegEx = /\.css$/; +var isJsRegEx = /\.js$/; + +function main(callback) { + + function build(files) { + var file, match, str; + for (var f in files) { + file = files[f]; + match = f.match(fileRegEx); + if (match) { + if (file.template) { + if (file.docs) { + file.docs = marked(file.docs); + } + if (file.contents) { + str = marked(file.contents.toString()); + file.contents = new Buffer(str); + } + file.ol_version = pjson.version; + file.js_resource = ''; + var js = fs.readFileSync(__dirname + '/../examples_src/' + + match[1] + '.js', 'utf8'); + file.js_inline = js.replace(cleanupJSRegEx, ''); + var cssFile = __dirname + '/../examples_src/' + match[1] + '.css'; + if (fs.existsSync(cssFile)) { + file.css_resource = ''; + file.css_inline = fs.readFileSync(cssFile, 'utf-8'); + } + if (file.resources) { + var resources = file.resources.split(','); + var resource; + for (var i = resources.length - 1; i >= 0; --i) { + resource = resources[i]; + if (isJsRegEx.test(resource)) { + resources[i] = ''; + } else if (isCssRegEx.test(resource)) { + resources[i] = ''; + } else { + callback(new Error(f + ': Invalid value for "resource": ' + + resource + ' is no .js or .css.')); + } + file.resources = resources.join('\n'); + } + } + } else if (f !== 'index.html'){ + callback(new Error(f + ': Invalid YAML front-matter.')); + } + } + } + } + + + new Metalsmith('.') + .source('examples_src') + .destination('examples') + .use(build) + .use(templates({ + engine: 'handlebars', + directory: 'config/examples' + })) + .build(function(err) { + callback(err); + }); +} + + +if (require.main === module) { + main(function(err) { + if (err) { + process.stderr.write(err.message + '\n'); + process.exit(1); + } else { + process.exit(0); + } + }); +} + +module.exports = main; diff --git a/tasks/parse-examples.js b/tasks/parse-examples.js index 8315da6716..a99eea4d83 100644 --- a/tasks/parse-examples.js +++ b/tasks/parse-examples.js @@ -4,6 +4,7 @@ var path = require('path'); var async = require('async'); var Parser = require('htmlparser2').Parser; +var buildExamples = require('./build-examples'); var exampleDir = path.join(__dirname, '..', 'examples'); @@ -141,6 +142,7 @@ function writeExampleList(exampleInfos, callback) { */ function main(callback) { async.waterfall([ + buildExamples, listExamples, parseExamples, writeExampleList diff --git a/tasks/readme.md b/tasks/readme.md index a08a958770..6bfc5507d8 100644 --- a/tasks/readme.md +++ b/tasks/readme.md @@ -111,6 +111,9 @@ Called internally to parse the library for annotations and write out a `build/in Called after install to generate an example index. After new examples are added, run `node tasks/parse-examples.js` to regenerate the example index. +## `build-examples.js` + +Called internally by `parse-examples.js` to build the examples from templates. ## `serve.js`