Update v1.0.6
This commit is contained in:
4
public/filemanager/scripts/zeroclipboard/.gitignore
vendored
Normal file
4
public/filemanager/scripts/zeroclipboard/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
coverage
|
||||
npm-debug.log
|
||||
bin/*
|
62
public/filemanager/scripts/zeroclipboard/.jshintrc
Normal file
62
public/filemanager/scripts/zeroclipboard/.jshintrc
Normal file
@@ -0,0 +1,62 @@
|
||||
{
|
||||
/* Enforcing options */
|
||||
"bitwise": true,
|
||||
"camelcase": true,
|
||||
"curly": true,
|
||||
"eqeqeq": true,
|
||||
"es3": true,
|
||||
"es5": false,
|
||||
"forin": true,
|
||||
"freeze": true,
|
||||
"immed": true,
|
||||
"indent": 2,
|
||||
"latedef": false, /* IDEAL: `true` */
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"noempty": true,
|
||||
"nonbsp": true,
|
||||
"nonew": true,
|
||||
"plusplus": false,
|
||||
"quotmark": "double",
|
||||
"undef": false, /* IDEAL: `true` */
|
||||
"unused": false, /* IDEAL: `true` */
|
||||
"strict": false, /* IDEAL: `true` */
|
||||
"trailing": true,
|
||||
"maxparams": 4,
|
||||
"maxdepth": 5,
|
||||
"maxstatements": 25,
|
||||
"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
|
||||
}
|
3
public/filemanager/scripts/zeroclipboard/.npmignore
Normal file
3
public/filemanager/scripts/zeroclipboard/.npmignore
Normal file
@@ -0,0 +1,3 @@
|
||||
docs/
|
||||
test/
|
||||
.DS_Store
|
3
public/filemanager/scripts/zeroclipboard/.spmignore
Normal file
3
public/filemanager/scripts/zeroclipboard/.spmignore
Normal file
@@ -0,0 +1,3 @@
|
||||
docs
|
||||
src
|
||||
test
|
5
public/filemanager/scripts/zeroclipboard/.travis.yml
Normal file
5
public/filemanager/scripts/zeroclipboard/.travis.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.10"
|
||||
before_script:
|
||||
- npm install -g grunt-cli
|
29
public/filemanager/scripts/zeroclipboard/CONTRIBUTING.md
Normal file
29
public/filemanager/scripts/zeroclipboard/CONTRIBUTING.md
Normal file
@@ -0,0 +1,29 @@
|
||||
Contributing
|
||||
==============
|
||||
|
||||
If you find an issue, submitting a pull request is always better than a bug report! Please fork and submit your code fixes.
|
||||
|
||||
If you want to build some new features, we have a [roadmap.md](docs/roadmap.md) of features we want. You can add features you want there, or just code the feature and send a pull request.
|
||||
|
||||
### Cloning
|
||||
|
||||
```sh
|
||||
$ git clone https://github.com/zeroclipboard/zeroclipboard.git
|
||||
$ cd zeroclipboard/
|
||||
$ npm install -g grunt-cli
|
||||
$ npm install
|
||||
$ grunt
|
||||
```
|
||||
|
||||
### Developing
|
||||
|
||||
```sh
|
||||
$ npm install
|
||||
$ grunt
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
```sh
|
||||
$ grunt test
|
||||
```
|
332
public/filemanager/scripts/zeroclipboard/Gruntfile.js
vendored
Normal file
332
public/filemanager/scripts/zeroclipboard/Gruntfile.js
vendored
Normal file
@@ -0,0 +1,332 @@
|
||||
/*jshint -W106 */
|
||||
/*jshint node:true, maxstatements: false, maxlen: false */
|
||||
|
||||
var os = require("os");
|
||||
var path = require("path");
|
||||
var loadGruntTasks = require("load-grunt-tasks");
|
||||
|
||||
module.exports = function(grunt) {
|
||||
"use strict";
|
||||
|
||||
// Load necessary tasks
|
||||
loadGruntTasks(grunt);
|
||||
|
||||
|
||||
// Metadata
|
||||
var pkg = grunt.file.readJSON("package.json");
|
||||
|
||||
// Make a temp dir for Flash compilation
|
||||
var tmpDir = os.tmpdir ? os.tmpdir() : os.tmpDir();
|
||||
var flashTmpDir = path.join(tmpDir, "zcflash");
|
||||
|
||||
// Shared configuration
|
||||
var localPort = 7320; // "ZERO"
|
||||
|
||||
// Project configuration.
|
||||
var config = {
|
||||
// Task configuration
|
||||
jshint: {
|
||||
options: {
|
||||
jshintrc: true
|
||||
},
|
||||
gruntfile: ["Gruntfile.js"],
|
||||
component: ["index.js"],
|
||||
js: ["src/js/**/*.js", "!src/js/start.js", "!src/js/end.js"],
|
||||
test: ["test/**/*.js"],
|
||||
dist: ["dist/*.js", "!dist/*.min.js"]
|
||||
},
|
||||
flexpmd: {
|
||||
flash: {
|
||||
src: [flashTmpDir]
|
||||
}
|
||||
},
|
||||
clean: {
|
||||
dist: ["ZeroClipboard.*", "dist/ZeroClipboard.*"],
|
||||
flash: {
|
||||
options: {
|
||||
// Force is required when trying to clean outside of the project dir
|
||||
force: true
|
||||
},
|
||||
src: [flashTmpDir]
|
||||
},
|
||||
meta: ["bower.json", "composer.json", "LICENSE"],
|
||||
coveralls: ["tmp/", "coverage/"]
|
||||
},
|
||||
concat: {
|
||||
options: {
|
||||
stripBanners: false,
|
||||
process: {
|
||||
data: pkg
|
||||
}
|
||||
},
|
||||
core: {
|
||||
src: [
|
||||
"src/meta/source-banner.tmpl",
|
||||
"src/js/start.js",
|
||||
"src/js/shared/state.js",
|
||||
"src/js/shared/private.js",
|
||||
"src/js/core/state.js",
|
||||
"src/js/core/private.js",
|
||||
"src/js/core/api.js",
|
||||
"src/js/end.js"
|
||||
],
|
||||
dest: "dist/ZeroClipboard.Core.js"
|
||||
},
|
||||
client: {
|
||||
src: [
|
||||
"src/meta/source-banner.tmpl",
|
||||
"src/js/start.js",
|
||||
"src/js/shared/state.js",
|
||||
"src/js/shared/private.js",
|
||||
"src/js/core/state.js",
|
||||
"src/js/core/private.js",
|
||||
"src/js/core/api.js",
|
||||
"src/js/client/state.js",
|
||||
"src/js/client/private.js",
|
||||
"src/js/client/api.js",
|
||||
"src/js/end.js"
|
||||
],
|
||||
dest: "dist/ZeroClipboard.js"
|
||||
},
|
||||
flash: {
|
||||
files: [
|
||||
{
|
||||
src: [
|
||||
"src/meta/source-banner.tmpl",
|
||||
"src/flash/ZeroClipboard.as"
|
||||
],
|
||||
dest: path.join(flashTmpDir, "ZeroClipboard.as")
|
||||
},
|
||||
{
|
||||
src: [
|
||||
"src/meta/source-banner.tmpl",
|
||||
"src/flash/ClipboardInjector.as"
|
||||
],
|
||||
dest: path.join(flashTmpDir, "ClipboardInjector.as")
|
||||
},
|
||||
{
|
||||
src: [
|
||||
"src/meta/source-banner.tmpl",
|
||||
"src/flash/JsProxy.as"
|
||||
],
|
||||
dest: path.join(flashTmpDir, "JsProxy.as")
|
||||
},
|
||||
{
|
||||
src: [
|
||||
"src/meta/source-banner.tmpl",
|
||||
"src/flash/XssUtils.as"
|
||||
],
|
||||
dest: path.join(flashTmpDir, "XssUtils.as")
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
uglify: {
|
||||
options: {
|
||||
report: "min"
|
||||
},
|
||||
js: {
|
||||
options: {
|
||||
preserveComments: function(node, comment) {
|
||||
return comment &&
|
||||
comment.type === "comment2" &&
|
||||
/^(!|\*|\*!)\r?\n/.test(comment.value);
|
||||
},
|
||||
beautify: {
|
||||
beautify: true,
|
||||
// `indent_level` requires jshint -W106
|
||||
indent_level: 2
|
||||
},
|
||||
mangle: false,
|
||||
compress: false
|
||||
},
|
||||
files: [
|
||||
{
|
||||
src: ["<%= concat.core.dest %>"],
|
||||
dest: "<%= concat.core.dest %>"
|
||||
},
|
||||
{
|
||||
src: ["<%= concat.client.dest %>"],
|
||||
dest: "<%= concat.client.dest %>"
|
||||
}
|
||||
]
|
||||
},
|
||||
minjs: {
|
||||
options: {
|
||||
preserveComments: function(node, comment) {
|
||||
return comment &&
|
||||
comment.type === "comment2" &&
|
||||
/^(!|\*!)\r?\n/.test(comment.value);
|
||||
},
|
||||
sourceMap: true,
|
||||
sourceMapName: function(dest) {
|
||||
return dest.replace(".min.js", ".min.map");
|
||||
},
|
||||
// Bundles the contents of "`src`" into the "`dest`.map" source map file. This way,
|
||||
// consumers only need to host the "*.min.js" and "*.min.map" files rather than
|
||||
// needing to host all three files: "*.js", "*.min.js", and "*.min.map".
|
||||
sourceMapIncludeSources: true
|
||||
},
|
||||
files: [
|
||||
{
|
||||
src: ["<%= concat.core.dest %>"],
|
||||
dest: "dist/ZeroClipboard.Core.min.js"
|
||||
},
|
||||
{
|
||||
src: ["<%= concat.client.dest %>"],
|
||||
dest: "dist/ZeroClipboard.min.js"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
mxmlc: {
|
||||
options: {
|
||||
rawConfig: "-target-player=11.0.0 -static-link-runtime-shared-libraries=true"
|
||||
},
|
||||
swf: {
|
||||
files: {
|
||||
"dist/ZeroClipboard.swf": ["<%= concat.flash.files[0].dest %>"]
|
||||
}
|
||||
}
|
||||
},
|
||||
template: {
|
||||
options: {
|
||||
data: pkg
|
||||
},
|
||||
bower: {
|
||||
files: {
|
||||
"bower.json": ["src/meta/bower.json.tmpl"]
|
||||
}
|
||||
},
|
||||
composer: {
|
||||
files: {
|
||||
"composer.json": ["src/meta/composer.json.tmpl"]
|
||||
}
|
||||
},
|
||||
LICENSE: {
|
||||
files: {
|
||||
"LICENSE": ["src/meta/LICENSE.tmpl"]
|
||||
}
|
||||
}
|
||||
},
|
||||
chmod: {
|
||||
options: {
|
||||
mode: "444"
|
||||
},
|
||||
dist: ["dist/ZeroClipboard.*"],
|
||||
meta: ["bower.json", "composer.json", "LICENSE"]
|
||||
},
|
||||
connect: {
|
||||
server: {
|
||||
options: {
|
||||
port: localPort
|
||||
}
|
||||
}
|
||||
},
|
||||
qunit: {
|
||||
file: [
|
||||
"test/shared/private.tests.js.html",
|
||||
"test/core/private.tests.js.html",
|
||||
"test/core/api.tests.js.html",
|
||||
"test/client/private.tests.js.html",
|
||||
"test/client/api.tests.js.html",
|
||||
"test/built/ZeroClipboard.Core.tests.js.html",
|
||||
"test/built/ZeroClipboard.tests.js.html"
|
||||
//"test/**/*.tests.js.html"
|
||||
],
|
||||
http: {
|
||||
options: {
|
||||
urls:
|
||||
grunt.file.expand([
|
||||
"test/shared/private.tests.js.html",
|
||||
"test/core/private.tests.js.html",
|
||||
"test/core/api.tests.js.html",
|
||||
"test/client/private.tests.js.html",
|
||||
"test/client/api.tests.js.html",
|
||||
"test/built/ZeroClipboard.Core.tests.js.html",
|
||||
"test/built/ZeroClipboard.tests.js.html"
|
||||
//"test/**/*.tests.js.html"
|
||||
]).map(function(testPage) {
|
||||
return "http://localhost:" + localPort + "/" + testPage + "?noglobals=true";
|
||||
})
|
||||
}
|
||||
},
|
||||
coveralls: {
|
||||
options: {
|
||||
"--web-security": false,
|
||||
timeout: 10000,
|
||||
coverage: {
|
||||
baseUrl: ".",
|
||||
src: [
|
||||
"src/js/**/*.js",
|
||||
"!src/js/start.js",
|
||||
"!src/js/end.js",
|
||||
"dist/*.js",
|
||||
"!dist/*.min.js"
|
||||
],
|
||||
instrumentedFiles: "tmp",
|
||||
htmlReport: "coverage/html",
|
||||
lcovReport: "coverage/lcov",
|
||||
statementsThresholdPct: 60.0,
|
||||
disposeCollector: true
|
||||
},
|
||||
urls:
|
||||
grunt.file.expand([
|
||||
"test/shared/private.tests.js.html",
|
||||
"test/core/private.tests.js.html",
|
||||
"test/core/api.tests.js.html",
|
||||
"test/client/private.tests.js.html",
|
||||
"test/client/api.tests.js.html",
|
||||
"test/built/ZeroClipboard.Core.tests.js.html",
|
||||
"test/built/ZeroClipboard.tests.js.html"
|
||||
//"test/**/*.tests.js.html"
|
||||
]).map(function(testPage) {
|
||||
return "http://localhost:" + localPort + "/" + testPage + "?noglobals=true";
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
coveralls: {
|
||||
options: {
|
||||
force: true
|
||||
},
|
||||
all: {
|
||||
src: "<%= qunit.coveralls.options.coverage.lcovReport %>/lcov.info"
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
options: {
|
||||
spawn: false
|
||||
},
|
||||
gruntfile: {
|
||||
files: "<%= jshint.Gruntfile %>",
|
||||
tasks: ["jshint:Gruntfile"]
|
||||
},
|
||||
js: {
|
||||
files: "<%= jshint.js %>",
|
||||
tasks: ["jshint:js", "unittest"]
|
||||
},
|
||||
test: {
|
||||
files: "<%= jshint.test %>",
|
||||
tasks: ["jshint:test", "unittest"]
|
||||
}
|
||||
}
|
||||
};
|
||||
grunt.initConfig(config);
|
||||
|
||||
|
||||
// Task aliases and chains
|
||||
grunt.registerTask("jshint-prebuild", ["jshint:gruntfile", "jshint:component", "jshint:js", "jshint:test"]);
|
||||
grunt.registerTask("prep-flash", ["clean:flash", "concat:flash"]);
|
||||
grunt.registerTask("validate", ["jshint-prebuild", "prep-flash", "flexpmd"]);
|
||||
grunt.registerTask("build", ["clean", "concat", "jshint:dist", "uglify", "mxmlc", "template", "chmod"]);
|
||||
grunt.registerTask("build-travis", ["clean", "concat", "jshint:dist", "mxmlc", "chmod:dist"]);
|
||||
grunt.registerTask("test", ["connect", "qunit:file", "qunit:http"]);
|
||||
|
||||
// Default task
|
||||
grunt.registerTask("default", ["validate", "build", "test"]);
|
||||
|
||||
// Travis CI task
|
||||
grunt.registerTask("travis", ["validate", "build-travis", "test", "qunit:coveralls", "coveralls"]);
|
||||
|
||||
};
|
8
public/filemanager/scripts/zeroclipboard/LICENSE
Normal file
8
public/filemanager/scripts/zeroclipboard/LICENSE
Normal file
@@ -0,0 +1,8 @@
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2014 Jon Rohan, James M. Greene
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
91
public/filemanager/scripts/zeroclipboard/README.md
Normal file
91
public/filemanager/scripts/zeroclipboard/README.md
Normal file
@@ -0,0 +1,91 @@
|
||||
### WARNING
|
||||
**This `master` branch contains the `v2.x` codebase for ZeroClipboard! For the `v1.x` codebase, see the [`1.x-master`](https://github.com/zeroclipboard/zeroclipboard/tree/1.x-master) branch instead.**
|
||||
|
||||
|
||||
# ZeroClipboard
|
||||
[](https://github.com/zeroclipboard/zeroclipboard) [](https://travis-ci.org/zeroclipboard/zeroclipboard) [](https://coveralls.io/r/zeroclipboard/zeroclipboard?branch=master) [](https://david-dm.org/zeroclipboard/zeroclipboard) [](https://david-dm.org/zeroclipboard/zeroclipboard#info=devDependencies)
|
||||
|
||||
The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible [Adobe Flash](http://en.wikipedia.org/wiki/Adobe_Flash) movie and a [JavaScript](http://en.wikipedia.org/wiki/JavaScript) interface. The "Zero" signifies that the library is invisible and the user interface is left entirely up to you.
|
||||
|
||||
This is achieved by automatically floating the invisible movie on top of a [DOM](http://en.wikipedia.org/wiki/Document_Object_Model) element of your choice. Standard mouse events are even propagated out to your DOM element, so you can still have rollover and mousedown effects.
|
||||
|
||||
|
||||
## Limitations
|
||||
|
||||
### User Interaction Required
|
||||
|
||||
Due to browser and Flash security restrictions, this clipboard injection can _**ONLY**_ occur when
|
||||
the user clicks on the invisible Flash movie. A simulated `click` event from JavaScript will not
|
||||
suffice as this would enable [clipboard poisoning](http://www.computerworld.com/s/article/9117268/Adobe_patches_Flash_clickjacking_and_clipboard_poisoning_bugs).
|
||||
|
||||
### Other Limitations
|
||||
|
||||
For a complete list of limitations, see [docs/instructions.md#limitations](docs/instructions.md#limitations).
|
||||
|
||||
|
||||
## Simple Example
|
||||
|
||||
```html
|
||||
<html>
|
||||
<body>
|
||||
<button id="copy-button" data-clipboard-text="Copy Me!" title="Click to copy me.">Copy to Clipboard</button>
|
||||
<script src="ZeroClipboard.js"></script>
|
||||
<script src="main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```js
|
||||
// main.js
|
||||
var client = new ZeroClipboard( document.getElementById("copy-button") );
|
||||
|
||||
client.on( "ready", function( readyEvent ) {
|
||||
// alert( "ZeroClipboard SWF is ready!" );
|
||||
|
||||
client.on( "aftercopy", function( event ) {
|
||||
// `this` === `client`
|
||||
// `event.target` === the element that was clicked
|
||||
event.target.style.display = "none";
|
||||
alert("Copied text to clipboard: " + event.data["text/plain"] );
|
||||
} );
|
||||
} );
|
||||
```
|
||||
|
||||
See [docs/instructions.md](docs/instructions.md) for more advanced options in using the library on your site.
|
||||
See [docs/api/ZeroClipboard.md](docs/api/ZeroClipboard.md) for the complete API documentation.
|
||||
|
||||
Here is a working [test page](http://zeroclipboard.org/#demo) where you can try out ZeroClipboard in your browser.
|
||||
|
||||
|
||||
## Testing ZeroClipboard Locally
|
||||
|
||||
To test the page [demo page](http://zeroclipboard.org/#demo) locally, clone the [website repo](https://github.com/zeroclipboard/zeroclipboard.org).
|
||||
|
||||
|
||||
## Support
|
||||
|
||||
This library is fully compatible with Flash Player 11.0.0 and above, which requires
|
||||
that the clipboard copy operation be initiated by a user click event inside the
|
||||
Flash movie. This is achieved by automatically floating the invisible movie on top
|
||||
of a [DOM](http://en.wikipedia.org/wiki/Document_Object_Model) element of your
|
||||
choice. Standard mouse events are even propagated out to your DOM element, so you
|
||||
can still have rollover and mousedown effects with just a _little_ extra effort.
|
||||
|
||||
ZeroClipboard `v2.x` is expected to work in IE9+ and all of the evergreen browsers.
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
see [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||
|
||||
|
||||
## Releases
|
||||
|
||||
Starting with version [1.1.7](https://github.com/zeroclipboard/zeroclipboard/releases/tag/v1.1.7), ZeroClipboard uses [semantic versioning](http://semver.org/).
|
||||
|
||||
see [releases](https://github.com/zeroclipboard/zeroclipboard/releases)
|
||||
|
||||
|
||||
## Roadmap
|
||||
|
||||
see [roadmap.md](docs/roadmap.md)
|
17
public/filemanager/scripts/zeroclipboard/bower.json
Normal file
17
public/filemanager/scripts/zeroclipboard/bower.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "zeroclipboard",
|
||||
"description": "The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface.",
|
||||
"version": "2.1.6",
|
||||
"main": ["./dist/ZeroClipboard.js", "./dist/ZeroClipboard.swf"],
|
||||
"keywords": ["flash","clipboard","copy","cut","paste","zclip","clip","clippy"],
|
||||
"license": "https://github.com/zeroclipboard/zeroclipboard/blob/master/LICENSE",
|
||||
"authors": [{"name":"Jon Rohan","url":"http://jonrohan.me/"},{"name":"James M. Greene","email":"james.m.greene@gmail.com","url":"http://jamesgreene.net/"}],
|
||||
"homepage": "http://zeroclipboard.org/",
|
||||
"repository": {"type":"git","url":"https://github.com/zeroclipboard/zeroclipboard.git"},
|
||||
"location": "git://github.com/zeroclipboard/zeroclipboard.git",
|
||||
"ignore": [
|
||||
"*",
|
||||
"!/bower.json",
|
||||
"!/dist/**"
|
||||
]
|
||||
}
|
14
public/filemanager/scripts/zeroclipboard/composer.json
Normal file
14
public/filemanager/scripts/zeroclipboard/composer.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "zeroclipboard/zeroclipboard",
|
||||
"description": "The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface.",
|
||||
"version": "2.1.6",
|
||||
"type": "library",
|
||||
"keywords": ["flash","clipboard","copy","cut","paste","zclip","clip","clippy"],
|
||||
"license": "MIT",
|
||||
"authors": [{"name":"Jon Rohan","homepage":"http://jonrohan.me/","role":"Developer"},{"name":"James M. Greene","email":"james.m.greene@gmail.com","homepage":"http://jamesgreene.net/","role":"Developer"}],
|
||||
"homepage": "http://zeroclipboard.org/",
|
||||
"support": {
|
||||
"source": "https://github.com/zeroclipboard/zeroclipboard.git",
|
||||
"issues": "https://github.com/zeroclipboard/zeroclipboard/issues"
|
||||
}
|
||||
}
|
18
public/filemanager/scripts/zeroclipboard/copy.js
vendored
Normal file
18
public/filemanager/scripts/zeroclipboard/copy.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
ZeroClipboard.config( { swfPath: './scripts/zeroclipboard/dist/ZeroClipboard.swf' } );
|
||||
|
||||
var client = new ZeroClipboard( document.getElementById("copy-button") );
|
||||
|
||||
client.on( "ready", function( readyEvent ) {
|
||||
// alert( "ZeroClipboard SWF is ready!" );
|
||||
|
||||
client.on( "aftercopy", function( event ) {
|
||||
// `this` === `client`
|
||||
// `event.target` === the element that was clicked
|
||||
// event.target.style.display = "none";
|
||||
//alert("Copied text to clipboard: " + event.data["text/plain"] );
|
||||
} );
|
||||
} );
|
||||
|
||||
});
|
70
public/filemanager/scripts/zeroclipboard/dist/.jshintrc
vendored
Normal file
70
public/filemanager/scripts/zeroclipboard/dist/.jshintrc
vendored
Normal file
@@ -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
|
||||
}
|
||||
}
|
1788
public/filemanager/scripts/zeroclipboard/dist/ZeroClipboard.Core.js
vendored
Normal file
1788
public/filemanager/scripts/zeroclipboard/dist/ZeroClipboard.Core.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
10
public/filemanager/scripts/zeroclipboard/dist/ZeroClipboard.Core.min.js
vendored
Normal file
10
public/filemanager/scripts/zeroclipboard/dist/ZeroClipboard.Core.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/filemanager/scripts/zeroclipboard/dist/ZeroClipboard.Core.min.map
vendored
Normal file
1
public/filemanager/scripts/zeroclipboard/dist/ZeroClipboard.Core.min.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2314
public/filemanager/scripts/zeroclipboard/dist/ZeroClipboard.js
vendored
Normal file
2314
public/filemanager/scripts/zeroclipboard/dist/ZeroClipboard.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
10
public/filemanager/scripts/zeroclipboard/dist/ZeroClipboard.min.js
vendored
Normal file
10
public/filemanager/scripts/zeroclipboard/dist/ZeroClipboard.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/filemanager/scripts/zeroclipboard/dist/ZeroClipboard.min.map
vendored
Normal file
1
public/filemanager/scripts/zeroclipboard/dist/ZeroClipboard.min.map
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
public/filemanager/scripts/zeroclipboard/dist/ZeroClipboard.swf
vendored
Normal file
BIN
public/filemanager/scripts/zeroclipboard/dist/ZeroClipboard.swf
vendored
Normal file
Binary file not shown.
@@ -0,0 +1,716 @@
|
||||
# ZeroClipboard.Core API
|
||||
|
||||
This documents details the **ZeroClipboard.Core** API, including various types of properties, methods, and events. **ZeroClipboard.Core** is primarily intended for use in wrapping ZeroClipboard in 3rd party plugins, e.g. [jquery.zeroclipboard](https://github.com/zeroclipboard/jquery.zeroclipboard).
|
||||
|
||||
|
||||
## Static
|
||||
|
||||
### Static Properties
|
||||
|
||||
#### `ZeroClipboard.version`
|
||||
|
||||
_[`String`]_ The version of the ZeroClipboard library being used, e.g. `"2.0.0"`.
|
||||
|
||||
|
||||
### Static Methods
|
||||
|
||||
#### `ZeroClipboard.config(...)`
|
||||
|
||||
```js
|
||||
var config = ZeroClipboard.config();
|
||||
```
|
||||
|
||||
_[`Object`]_ Get a copy of the active configuration for ZeroClipboard.
|
||||
|
||||
|
||||
```js
|
||||
var swfPath = ZeroClipboard.config("swfPath");
|
||||
```
|
||||
|
||||
_[`*`]_ Get a copy of the actively configured value for this configuration property for ZeroClipboard.
|
||||
|
||||
|
||||
```js
|
||||
var config = ZeroClipboard.config({
|
||||
forceHandCursor: true
|
||||
});
|
||||
```
|
||||
|
||||
_[`Object`]_ Set the active configuration for ZeroClipboard. Returns a copy of the updated active configuration. For complete details about what can be configured, see [**Configuration Options** below](#configuration-options).
|
||||
|
||||
|
||||
#### `ZeroClipboard.create()`
|
||||
_[`undefined`]_ Create the Flash bridge SWF object.
|
||||
|
||||
|
||||
#### `ZeroClipboard.destroy()`
|
||||
_[`undefined`]_ Emit the [`"destroy"`](#destroy) event, remove all event handlers, and destroy the Flash bridge.
|
||||
|
||||
|
||||
#### `ZeroClipboard.setData(...)`
|
||||
|
||||
```js
|
||||
ZeroClipboard.setData("text/plain", "Blah");
|
||||
```
|
||||
|
||||
_[`undefined`]_ Set the pending `data` of type `format` for clipboard injection.
|
||||
|
||||
```js
|
||||
ZeroClipboard.setData({
|
||||
"text/plain": "Blah",
|
||||
"text/html": "<b>Blah</b>"
|
||||
});
|
||||
```
|
||||
|
||||
_[`undefined`]_ Set the pending `data` of various formats for clipboard injection.
|
||||
|
||||
|
||||
#### `ZeroClipboard.clearData(...)`
|
||||
|
||||
```js
|
||||
ZeroClipboard.clearData("text/plain");
|
||||
```
|
||||
|
||||
_[`undefined`]_ Clear the pending data of type `format` for clipboard injection.
|
||||
|
||||
```js
|
||||
ZeroClipboard.clearData();
|
||||
```
|
||||
|
||||
_[`undefined`]_ Clear the pending data of ALL formats for clipboard injection.
|
||||
|
||||
|
||||
#### `ZeroClipboard.getData(...)`
|
||||
|
||||
```js
|
||||
var text = ZeroClipboard.getData("text/plain");
|
||||
```
|
||||
|
||||
_[`String`]_ Get the pending data of type `format` for clipboard injection.
|
||||
|
||||
```js
|
||||
var dataObj = ZeroClipboard.getData();
|
||||
```
|
||||
|
||||
_[`Object`]_ Get a copy of the pending data of ALL formats for clipboard injection.
|
||||
|
||||
|
||||
#### `ZeroClipboard.focus(...)`
|
||||
#### `ZeroClipboard.activate(...)`
|
||||
|
||||
```js
|
||||
ZeroClipboard.focus(document.getElementById("d_clip_button"));
|
||||
```
|
||||
|
||||
_[`undefined`]_ Focus/"activate" the provided element by moving the Flash SWF object in front of it. **NOTE:** The preferred method to use is `focus` but the alias `activate` is available for backward compatibility's sake.
|
||||
|
||||
|
||||
#### `ZeroClipboard.blur()`
|
||||
#### `ZeroClipboard.deactivate()`
|
||||
|
||||
_[`undefined`]_ Blur/"deactivate" the currently focused/"activated" element, moving the Flash SWF object off the screen. **NOTE:** The preferred method to use is `blur` but the alias `deactivate` is available for backward compatibility's sake.
|
||||
|
||||
|
||||
#### `ZeroClipboard.activeElement()`
|
||||
|
||||
```js
|
||||
var el = document.getElementById("d_clip_button");
|
||||
ZeroClipboard.focus(el);
|
||||
var activeEl = ZeroClipboard.activeElement(); // activeEl === el
|
||||
```
|
||||
|
||||
_[`HTMLElement` or `null`]_ Return the currently "activated" element that the Flash SWF object is in front of it.
|
||||
|
||||
|
||||
#### `ZeroClipboard.state()`
|
||||
|
||||
_[`Object`]_ Diagnostic method that describes the state of the browser, Flash Player, and ZeroClipboard.
|
||||
|
||||
|
||||
#### `ZeroClipboard.isFlashUnavailable()`
|
||||
|
||||
_[`Boolean`]_ Indicates if Flash Player is **definitely** unusable (disabled, outdated, unavailable, or deactivated). _**IMPORTANT:**_ This method should be considered private.
|
||||
|
||||
|
||||
#### `ZeroClipboard.on(...)`
|
||||
|
||||
```js
|
||||
var listenerFn = function(e) { var ZeroClipboard = this; /* ... */ };
|
||||
ZeroClipboard.on("ready", listenerFn);
|
||||
|
||||
var listenerObj = {
|
||||
handleEvent: function(e) { var listenerObj = this; /* ... */ }
|
||||
};
|
||||
ZeroClipboard.on("error", listenerObj);
|
||||
```
|
||||
|
||||
_[`undefined`]_ Add a `listener` function/object for an `eventType`.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("ready error", function(e) { /* ... */ });
|
||||
```
|
||||
|
||||
_[`undefined`]_ Add a `listener` function/object for multiple `eventType`s.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on({
|
||||
"ready": function(e) { /* ... */ },
|
||||
"error": function(e) { /* ... */ }
|
||||
});
|
||||
```
|
||||
|
||||
_[`undefined`]_ Add a set of `eventType` to `listener` function/object mappings.
|
||||
|
||||
|
||||
#### `ZeroClipboard.off(...)`
|
||||
|
||||
```js
|
||||
ZeroClipboard.off("ready", listenerFn);
|
||||
ZeroClipboard.off("error", listenerObj);
|
||||
```
|
||||
|
||||
_[`undefined`]_ Remove a `listener` function/object for an `eventType`.
|
||||
|
||||
```js
|
||||
ZeroClipboard.off("ready error", listenerFn);
|
||||
```
|
||||
|
||||
_[`undefined`]_ Remove a `listener` function/object for multiple `eventType`s.
|
||||
|
||||
```js
|
||||
ZeroClipboard.off({
|
||||
"ready": readyListenerFn,
|
||||
"error": errorListenerFn
|
||||
});
|
||||
```
|
||||
|
||||
_[`undefined`]_ Remove a set of `eventType` to `listener` function/object mappings.
|
||||
|
||||
```js
|
||||
ZeroClipboard.off("ready");
|
||||
```
|
||||
|
||||
_[`undefined`]_ Remove ALL listener functions/objects for an `eventType`.
|
||||
|
||||
```js
|
||||
ZeroClipboard.off();
|
||||
```
|
||||
|
||||
_[`undefined`]_ Remove ALL listener functions/objects for ALL registered event types.
|
||||
|
||||
|
||||
#### `ZeroClipboard.emit(...)`
|
||||
|
||||
```js
|
||||
ZeroClipboard.emit("ready");
|
||||
ZeroClipboard.emit({
|
||||
type: "error",
|
||||
name: "flash-disabled"
|
||||
});
|
||||
|
||||
var pendingCopyData = ZeroClipboard.emit("copy");
|
||||
```
|
||||
|
||||
_[`undefined`, or a Flash-friendly data Object for the `"copy"` event]_ Dispatch an event to all
|
||||
registered listeners. The emission of some types of events will result in side effects.
|
||||
|
||||
|
||||
#### `ZeroClipboard.handlers()`
|
||||
|
||||
```js
|
||||
var listeners = ZeroClipboard.handlers("ready");
|
||||
```
|
||||
|
||||
_[`Array`]_ Retrieves a copy of the registered listener functions/objects for the given `eventType`.
|
||||
|
||||
|
||||
```js
|
||||
var listeners = ZeroClipboard.handlers();
|
||||
```
|
||||
|
||||
_[`Object`]_ Retrieves a copy of the map of registered listener functions/objects for ALL event types.
|
||||
|
||||
|
||||
|
||||
### Static Events
|
||||
|
||||
#### `"ready"`
|
||||
|
||||
The `ready` event is fired when the Flash SWF completes loading and is ready for action. Please
|
||||
note that you need to set most configuration options [with [`ZeroClipboard.config(...)`](#zeroclipboardconfig)]
|
||||
before `ZeroClipboard.create()` is invoked.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("ready", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "ready",
|
||||
message: "Flash communication is established",
|
||||
target: null,
|
||||
relatedTarget: null,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
version: "11.2.202",
|
||||
timeStamp: Date.now()
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
#### `"beforecopy"`
|
||||
|
||||
On `click`, the Flash object will fire off a `beforecopy` event. This event is generally only
|
||||
used for "UI prepartion" if you want to alter anything before the `copy` event fires.
|
||||
|
||||
**IMPORTANT:** Handlers of this event are expected to operate synchronously if they intend to be
|
||||
finished before the "copy" event is triggered.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("beforecopy", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "beforecopy",
|
||||
target: currentlyActivatedElementOrNull,
|
||||
relatedTarget: dataClipboardElementTargetOfCurrentlyActivatedElementOrNull,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
timeStamp: Date.now()
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
#### `"copy"`
|
||||
|
||||
On `click` (and after the `beforecopy` event), the Flash object will fire off a `copy` event. If
|
||||
the HTML object has `data-clipboard-text` or `data-clipboard-target`, then ZeroClipboard will take
|
||||
care of getting an initial set of data. It will then invoke any `copy` event handlers, in which you
|
||||
can call `event.clipboardData.setData` to set the text, which will complete the loop.
|
||||
|
||||
**IMPORTANT:** If a handler of this event intends to modify the pending data for clipboard
|
||||
injection, it _MUST_ operate synchronously in order to maintain the temporarily elevated
|
||||
permissions granted by the user's `click` event. The most common "gotcha" for this restriction is
|
||||
if someone wants to make an asynchronous XMLHttpRequest in response to the `copy` event to get the
|
||||
data to inject — this won't work; make it a _synchronous_ XMLHttpRequest instead, or do the
|
||||
work in advance before the `copy` event is fired.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("copy", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "copy",
|
||||
target: currentlyActivatedElementOrNull,
|
||||
relatedTarget: dataClipboardElementTargetOfCurrentlyActivatedElementOrNull,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
timeStamp: Date.now(),
|
||||
clipboardData: {
|
||||
setData: ZeroClipboard.setData,
|
||||
clearData: ZeroClipboard.clearData
|
||||
}
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
#### `"aftercopy"`
|
||||
|
||||
The `aftercopy` event is fired when the text is copied [or failed to copy] to the clipboard.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("aftercopy", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "aftercopy",
|
||||
target: currentlyActivatedElementOrNull,
|
||||
relatedTarget: dataClipboardElementTargetOfCurrentlyActivatedElementOrNull,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
timeStamp: Date.now(),
|
||||
success: {
|
||||
"text/plain": true,
|
||||
"text/html": true,
|
||||
"application/rtf": false
|
||||
},
|
||||
data: {
|
||||
"text/plain": "Blah",
|
||||
"text/html": "<b>Blah</b>",
|
||||
"application/rtf": "{\\rtf1\\ansi\n{\\b Blah}}"
|
||||
}
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
#### `"destroy"`
|
||||
|
||||
The `destroy` event is fired when `ZeroClipboard.destroy()` is invoked.
|
||||
|
||||
**IMPORTANT:** Handlers of this event are expected to operate synchronously if they intend to be
|
||||
finished before the destruction is complete.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("destroy", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "destroy",
|
||||
target: null,
|
||||
relatedTarget: null,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
timeStamp: Date.now(),
|
||||
success: {
|
||||
"text/plain": true,
|
||||
"text/html": true,
|
||||
"application/rtf": false
|
||||
},
|
||||
data: {
|
||||
"text/plain": "Blah",
|
||||
"text/html": "<b>Blah</b>",
|
||||
"application/rtf": "{\\rtf1\\ansi\n{\\b Blah}}"
|
||||
}
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
#### `"error"`
|
||||
|
||||
The `error` event is fired under a number of conditions, which will be detailed as sub-sections below.
|
||||
|
||||
Some consumers may not consider all `error` types to be critical, and thus ZeroClipboard does not take it upon
|
||||
itself to implode by calling `ZeroClipboard.destroy()` under error conditions. However, many consumers may
|
||||
want to do just that.
|
||||
|
||||
|
||||
##### `error[name = "flash-disabled"]`
|
||||
|
||||
This type of `error` event fires when Flash Player is either not installed or not enabled in the browser.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("error", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "error",
|
||||
name: "flash-disabled",
|
||||
messsage: "Flash is disabled or not installed",
|
||||
target: null,
|
||||
relatedTarget: null,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
timeStamp: Date.now(),
|
||||
minimumVersion: "11.0.0"
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
##### `error[name = "flash-outdated"]`
|
||||
|
||||
This type of `error` event fires when Flash Player is installed in the browser but the version is too old
|
||||
for ZeroClipboard. ZeroClipboard requires Flash Player 11.0.0 or above.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("error", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "error",
|
||||
name: "flash-outdated",
|
||||
messsage: "Flash is too outdated to support ZeroClipboard",
|
||||
target: null,
|
||||
relatedTarget: null,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
timeStamp: Date.now(),
|
||||
minimumVersion: "11.0.0",
|
||||
version: "10.3.183"
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
##### `error[name = "flash-unavailable"]`
|
||||
|
||||
This type of `error` event fires when the browser's installation of Flash Player cannot communicate bidirectionally with JavaScript.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("error", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "error",
|
||||
name: "flash-unavailable",
|
||||
messsage: "Flash is unable to communicate bidirectionally with JavaScript",
|
||||
target: null,
|
||||
relatedTarget: null,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
timeStamp: Date.now(),
|
||||
minimumVersion: "11.0.0",
|
||||
version: "11.2.202"
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
##### `error[name = "flash-deactivated"]`
|
||||
|
||||
This type of `error` event fires when the browser's installation of Flash Player is either too old
|
||||
for the browser [but _not_ too old for ZeroClipboard] or if Flash objects are configured as
|
||||
click-to-play and the user does not authorize it within `_globalConfig.flashLoadTimeout`
|
||||
milliseconds or does not authorize it at all.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("error", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "error",
|
||||
name: "flash-deactivated",
|
||||
messsage: "Flash is too outdated for your browser and/or is configured as click-to-activate",
|
||||
target: null,
|
||||
relatedTarget: null,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
timeStamp: Date.now(),
|
||||
minimumVersion: "11.0.0",
|
||||
version: "11.2.202"
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
##### `error[name = "flash-overdue"]`
|
||||
|
||||
This type of `error` event fires when the SWF loads successfully but takes longer than
|
||||
`_globalConfig.flashLoadTimeout` milliseconds to do so. This would likely be caused by
|
||||
one of the following situations:
|
||||
1. Too short of a `_globalConfig.flashLoadTimeout` duration configured
|
||||
2. Network latency
|
||||
3. The user's installation of Flash is configured as click-to-play but then authorized
|
||||
by the user too late such that the SWF does not finish loading before the timeout
|
||||
period has expired (or it may have expired before they authorized it at all).
|
||||
|
||||
The appropriate response to this event is left up to the consumer. For instance, if they
|
||||
chose to invoke `ZeroClipboard.destroy()` in response to the earlier
|
||||
`error[name = "flash-deactivated"]` event but then receive this `error[name = "flash-overdue"]`
|
||||
event, they may choose to "restart" their process and construct new ZeroClipboard client instances,
|
||||
or they may choose to just log the error to their server so they can consider increasing the
|
||||
allowed timeout duration in the future.
|
||||
|
||||
This may be especially important for SPA or PJAX-based applications to consider as their users
|
||||
may remain on a single page for an extended period of time during which they _possibly_ could
|
||||
have enjoyed an improved experience if ZeroClipboard had been "restarted" after an initial hiccup.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("error", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "error",
|
||||
name: "flash-overdue",
|
||||
messsage: "Flash communication was established but NOT within the acceptable time limit",
|
||||
target: null,
|
||||
relatedTarget: null,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
timeStamp: Date.now(),
|
||||
minimumVersion: "11.0.0",
|
||||
version: "11.2.202"
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Configuration Options
|
||||
|
||||
These are default values for the global configurations options. You should generally update these _before_ you create your clients.
|
||||
|
||||
```js
|
||||
var _globalConfig = {
|
||||
|
||||
// SWF URL, relative to the page. Default value will be "ZeroClipboard.swf"
|
||||
// under the same path as the ZeroClipboard JS file.
|
||||
swfPath: _swfPath,
|
||||
|
||||
// SWF inbound scripting policy: page domains that the SWF should trust.
|
||||
// (single string, or array of strings)
|
||||
trustedDomains: window.location.host ? [window.location.host] : [],
|
||||
|
||||
// Include a "noCache" query parameter on requests for the SWF.
|
||||
cacheBust: true,
|
||||
|
||||
// Enable use of the fancy "Desktop" clipboard, even on Linux where it is
|
||||
// known to suck.
|
||||
forceEnhancedClipboard: false,
|
||||
|
||||
// How many milliseconds to wait for the Flash SWF to load and respond before assuming that
|
||||
// Flash is deactivated (e.g. click-to-play) in the user's browser. If you don't care about
|
||||
// how long it takes to load the SWF, you can set this to `null`.
|
||||
flashLoadTimeout: 30000,
|
||||
|
||||
// Setting this to `false` would allow users to handle calling `ZeroClipboard.focus(...);`
|
||||
// themselves instead of relying on our per-element `mouseover` handler.
|
||||
autoActivate: true,
|
||||
|
||||
// Bubble synthetic events in JavaScript after they are received by the Flash object.
|
||||
bubbleEvents: true,
|
||||
|
||||
// Sets the ID of the `div` encapsulating the Flash object.
|
||||
// Value is validated against the [HTML4 spec for `ID` tokens][valid_ids].
|
||||
containerId: "global-zeroclipboard-html-bridge",
|
||||
|
||||
// Sets the class of the `div` encapsulating the Flash object.
|
||||
containerClass: "global-zeroclipboard-container",
|
||||
|
||||
// Sets the ID and name of the Flash `object` element.
|
||||
// Value is validated against the [HTML4 spec for `ID` and `Name` tokens][valid_ids].
|
||||
swfObjectId: "global-zeroclipboard-flash-bridge",
|
||||
|
||||
// The class used to indicate that a clipped element is being hovered over.
|
||||
hoverClass: "zeroclipboard-is-hover",
|
||||
|
||||
// The class used to indicate that a clipped element is active (is being clicked).
|
||||
activeClass: "zeroclipboard-is-active",
|
||||
|
||||
|
||||
|
||||
// Forcibly set the hand cursor ("pointer") for all clipped elements.
|
||||
// IMPORTANT: This configuration value CAN be modified while a SWF is actively embedded.
|
||||
forceHandCursor: false,
|
||||
|
||||
// Sets the title of the `div` encapsulating the Flash object.
|
||||
// IMPORTANT: This configuration value CAN be modified while a SWF is actively embedded.
|
||||
title: null,
|
||||
|
||||
// The z-index used by the Flash object.
|
||||
// Max value (32-bit): 2147483647.
|
||||
// IMPORTANT: This configuration value CAN be modified while a SWF is actively embedded.
|
||||
zIndex: 999999999
|
||||
|
||||
};
|
||||
```
|
||||
|
||||
You can override the defaults by making calls like `ZeroClipboard.config({ swfPath: "new/path" });`
|
||||
before you create any clients.
|
||||
|
||||
|
||||
### SWF Inbound Scripting Access: The `trustedDomains` option
|
||||
|
||||
This allows other SWF files and HTML pages from the allowed domains to access/call publicly
|
||||
exposed ActionScript code, e.g. functions shared via `ExternalInterface.addCallback`. In other
|
||||
words, it controls the SWF inbound scripting access.
|
||||
|
||||
If your ZeroClipboard SWF is served from a different origin/domain than your page, you need to tell
|
||||
the SWF that it's OK to trust your page. The default value of `[window.location.host]` is almost
|
||||
_**always**_ what you will want unless you specifically want the SWF to communicate with pages from
|
||||
other domains (e.g. in `iframe`s or child windows).
|
||||
|
||||
For more information about trusted domains, consult the [_official Flash documentation for `flash.system.Security.allowDomain(...)`_](http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/system/Security.html#allowDomain\(\)).
|
||||
|
||||
|
||||
### SWF Outbound Scripting Access
|
||||
|
||||
The `allowScriptAccess` parameter (for Flash embedding markup) allows the SWF file to access/call
|
||||
JavaScript/HTML functionality of HTML pages on allowed domains, e.g. invoking functions via
|
||||
`ExternalInterface.call`. In other words, it controls the SWF outbound scripting access.
|
||||
|
||||
As of version `v2.0.0-alpha.2`, the `allowScriptAccess` configuration option no longer exists. The
|
||||
appropriate value will be determined immediately before the Flash object is embedded on the page.
|
||||
The value is based on a relationship between the current domain (`window.location.host`) and the
|
||||
value of the `trustedDomains` configuration option.
|
||||
|
||||
For more information about `allowScriptAccess`, consult the [_official Flash documentation_](http://helpx.adobe.com/flash/kb/control-access-scripts-host-web.html).
|
||||
|
||||
|
||||
### Cross-Protocol Limitations
|
||||
|
||||
ZeroClipboard was intentionally configured to _not_ allow the SWF to be served from a secure domain (HTTPS) but scripted by an insecure domain (HTTP).
|
||||
|
||||
If you find yourself in this situation (as in [Issue #170](https://github.com/zeroclipboard/zeroclipboard/issues/170)), please consider the following options:
|
||||
1. Serve the SWF over HTTP instead of HTTPS. If the page's protocol can vary (e.g. authorized/unauthorized, staging/production, etc.), you should include add the SWF with a relative protocol (`//s3.amazonaws.com/blah/ZeroClipboard.swf`) instead of an absolute protocol (`https://s3.amazonaws.com/blah/ZeroClipboard.swf`).
|
||||
2. Serve the page over HTTPS instead of HTTP. If the page's protocol can vary, see the note on the previous option (1).
|
||||
3. Update ZeroClipboard's ActionScript codebase to call the [`allowInsecureDomain`](http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/system/Security.html#allowInsecureDomain\(\)) method, then recompile the SWF with your custom changes.
|
||||
|
||||
|
||||
### `file://` Protocol Limitations
|
||||
|
||||
If you want to host a page locally on the `file://` protocol, you must specifically configure
|
||||
ZeroClipboard to trust ALL domains for SWF interaction via a wildcard. This configuration must be
|
||||
set _before_ creating ZeroClipboard client instances as a typical consumer, or before calling
|
||||
`ZeroClipboard.create()` in a 3rd party wrapper:
|
||||
|
||||
```js
|
||||
ZeroClipboard.config({ trustedDomains: ["*"] });
|
||||
```
|
||||
|
||||
This wildcard configuration should _**NOT**_ be used in environments hosted over HTTP/HTTPS.
|
||||
|
||||
|
||||
## Extending `ZeroClipboard`
|
||||
|
||||
For developers who want to wrap ZeroClipboard into a 3rd party plugin
|
||||
(e.g. [jquery.zeroclipboard](https://github.com/zeroclipboard/jquery.zeroclipboard)), here
|
||||
are the important extension points:
|
||||
|
||||
|
||||
### Constructor
|
||||
|
||||
Although the root `ZeroClipboard` function itself is actually a constructor, it also contains a
|
||||
particular hook that checks for the existence of a `ZeroClipboard._createClient` static function
|
||||
and invokes it with `this` (the freshly created `ZeroClipboard` instance) as the context and passes
|
||||
along all provided arguments to the constructor function, e.g.:
|
||||
|
||||
```js
|
||||
var counterId = 0;
|
||||
ZeroClipboard._createClient = function(elements, otherStuff, etc) {
|
||||
this.id = "" + (counterId++);
|
||||
/* ... */
|
||||
};
|
||||
|
||||
var $elementsToOperateOn = $(".clip_button");
|
||||
|
||||
var client = new ZeroClipboard($elementsToOperateOn);
|
||||
```
|
||||
|
||||
|
||||
### Prototype Chain
|
||||
|
||||
Using the `ZeroClipboard` constructor will allow you to also extend the underlying prototype with
|
||||
new instance-based methods, e.g.:
|
||||
|
||||
```js
|
||||
ZeroClipboard.prototype.clientEmitOrSomeOtherOperationToInvoke = function(e) {
|
||||
e.client = this;
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
### Eventing
|
||||
|
||||
Most clients will want to listen for some or all of the `ZeroClipboard.Core` events, and some
|
||||
clients will even want to regurgitate the same events to their own client-based listeners. To
|
||||
make the latter easier, `ZeroClipboard.Core` will also allow you to add a listener to an
|
||||
`eventType` of `"*"`, e.g.:
|
||||
|
||||
```js
|
||||
ZeroClipboard._createClient = function() {
|
||||
var client = this;
|
||||
ZeroClipboard.on("*", function(e) {
|
||||
client.clientEmitOrSomeOtherOperationToInvoke(e);
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
### Static Extension
|
||||
|
||||
The `ZeroClipboard.Core` API is composed of static methods stored as properties of the
|
||||
root `ZeroClipboard` function. As such, additional static methods can be added as desired, if there
|
||||
is any actual benefit to doing so, e.g.:
|
||||
|
||||
```js
|
||||
ZeroClipboard.log = function() {
|
||||
if (typeof console !== "undefined" && console.log) {
|
||||
console.log.apply(console, Array.prototype.slice.call(arguments, 0));
|
||||
}
|
||||
};
|
||||
```
|
@@ -0,0 +1,892 @@
|
||||
# ZeroClipboard API
|
||||
|
||||
This documents details the ZeroClipboard API, including various types of properties, methods, and events.
|
||||
|
||||
|
||||
## Static
|
||||
|
||||
### Static Properties
|
||||
|
||||
#### `ZeroClipboard.version`
|
||||
|
||||
_[`String`]_ The version of the ZeroClipboard library being used, e.g. `"2.0.0"`.
|
||||
|
||||
|
||||
### Static Methods
|
||||
|
||||
#### `ZeroClipboard.config(...)`
|
||||
|
||||
```js
|
||||
var config = ZeroClipboard.config();
|
||||
```
|
||||
|
||||
_[`Object`]_ Get a copy of the active configuration for ZeroClipboard.
|
||||
|
||||
|
||||
```js
|
||||
var swfPath = ZeroClipboard.config("swfPath");
|
||||
```
|
||||
|
||||
_[`*`]_ Get a copy of the actively configured value for this configuration property for ZeroClipboard.
|
||||
|
||||
|
||||
```js
|
||||
var config = ZeroClipboard.config({
|
||||
forceHandCursor: true
|
||||
});
|
||||
```
|
||||
|
||||
_[`Object`]_ Set the active configuration for ZeroClipboard. Returns a copy of the updated active configuration. For complete details about what can be configured, see [**Configuration Options** below](#configuration-options).
|
||||
|
||||
|
||||
#### `ZeroClipboard.create()`
|
||||
_[`undefined`]_ Create the Flash bridge SWF object. _**IMPORTANT:**_ This method should be considered private.
|
||||
|
||||
|
||||
#### `ZeroClipboard.destroy()`
|
||||
_[`undefined`]_ Emit the [`"destroy"`](#destroy) event, remove all event handlers, and destroy the Flash bridge.
|
||||
|
||||
|
||||
#### `ZeroClipboard.setData(...)`
|
||||
|
||||
```js
|
||||
ZeroClipboard.setData("text/plain", "Blah");
|
||||
```
|
||||
|
||||
_[`undefined`]_ Set the pending `data` of type `format` for clipboard injection.
|
||||
|
||||
```js
|
||||
ZeroClipboard.setData({
|
||||
"text/plain": "Blah",
|
||||
"text/html": "<b>Blah</b>"
|
||||
});
|
||||
```
|
||||
|
||||
_[`undefined`]_ Set the pending `data` of various formats for clipboard injection.
|
||||
|
||||
|
||||
#### `ZeroClipboard.clearData(...)`
|
||||
|
||||
```js
|
||||
ZeroClipboard.clearData("text/plain");
|
||||
```
|
||||
|
||||
_[`undefined`]_ Clear the pending data of type `format` for clipboard injection.
|
||||
|
||||
```js
|
||||
ZeroClipboard.clearData();
|
||||
```
|
||||
|
||||
_[`undefined`]_ Clear the pending data of ALL formats for clipboard injection.
|
||||
|
||||
|
||||
#### `ZeroClipboard.getData(...)`
|
||||
|
||||
```js
|
||||
var text = ZeroClipboard.getData("text/plain");
|
||||
```
|
||||
|
||||
_[`String`]_ Get the pending data of type `format` for clipboard injection.
|
||||
|
||||
```js
|
||||
var dataObj = ZeroClipboard.getData();
|
||||
```
|
||||
|
||||
_[`Object`]_ Get a copy of the pending data of ALL formats for clipboard injection.
|
||||
|
||||
|
||||
#### `ZeroClipboard.focus(...)`
|
||||
#### `ZeroClipboard.activate(...)`
|
||||
|
||||
```js
|
||||
ZeroClipboard.focus(document.getElementById("d_clip_button"));
|
||||
```
|
||||
|
||||
_[`undefined`]_ Focus/"activate" the provided element by moving the Flash SWF object in front of it. **NOTE:** The preferred method to use is `focus` but the alias `activate` is available for backward compatibility's sake.
|
||||
|
||||
|
||||
#### `ZeroClipboard.blur()`
|
||||
#### `ZeroClipboard.deactivate()`
|
||||
|
||||
_[`undefined`]_ Blur/"deactivate" the currently focused/"activated" element, moving the Flash SWF object off the screen. **NOTE:** The preferred method to use is `blur` but the alias `deactivate` is available for backward compatibility's sake.
|
||||
|
||||
|
||||
#### `ZeroClipboard.activeElement()`
|
||||
|
||||
```js
|
||||
var el = document.getElementById("d_clip_button");
|
||||
ZeroClipboard.focus(el);
|
||||
var activeEl = ZeroClipboard.activeElement(); // activeEl === el
|
||||
```
|
||||
|
||||
_[`HTMLElement` or `null`]_ Return the currently "activated" element that the Flash SWF object is in front of it.
|
||||
|
||||
|
||||
#### `ZeroClipboard.state()`
|
||||
|
||||
_[`Object`]_ Diagnostic method that describes the state of the browser, Flash Player, and ZeroClipboard.
|
||||
|
||||
|
||||
#### `ZeroClipboard.isFlashUnavailable()`
|
||||
|
||||
_[`Boolean`]_ Indicates if Flash Player is **definitely** unusable (disabled, outdated, unavailable, or deactivated). _**IMPORTANT:**_ This method should be considered private.
|
||||
|
||||
|
||||
#### `ZeroClipboard.on(...)`
|
||||
|
||||
```js
|
||||
var listenerFn = function(e) { var ZeroClipboard = this; /* ... */ };
|
||||
ZeroClipboard.on("ready", listenerFn);
|
||||
|
||||
var listenerObj = {
|
||||
handleEvent: function(e) { var listenerObj = this; /* ... */ }
|
||||
};
|
||||
ZeroClipboard.on("error", listenerObj);
|
||||
```
|
||||
|
||||
_[`undefined`]_ Add a `listener` function/object for an `eventType`.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("ready error", function(e) { /* ... */ });
|
||||
```
|
||||
|
||||
_[`undefined`]_ Add a `listener` function/object for multiple `eventType`s.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on({
|
||||
"ready": function(e) { /* ... */ },
|
||||
"error": function(e) { /* ... */ }
|
||||
});
|
||||
```
|
||||
|
||||
_[`undefined`]_ Add a set of `eventType` to `listener` function/object mappings.
|
||||
|
||||
|
||||
#### `ZeroClipboard.off(...)`
|
||||
|
||||
```js
|
||||
ZeroClipboard.off("ready", listenerFn);
|
||||
ZeroClipboard.off("error", listenerObj);
|
||||
```
|
||||
|
||||
_[`undefined`]_ Remove a `listener` function/object for an `eventType`.
|
||||
|
||||
```js
|
||||
ZeroClipboard.off("ready error", listenerFn);
|
||||
```
|
||||
|
||||
_[`undefined`]_ Remove a `listener` function/object for multiple `eventType`s.
|
||||
|
||||
```js
|
||||
ZeroClipboard.off({
|
||||
"ready": readyListenerFn,
|
||||
"error": errorListenerFn
|
||||
});
|
||||
```
|
||||
|
||||
_[`undefined`]_ Remove a set of `eventType` to `listener` function/object mappings.
|
||||
|
||||
```js
|
||||
ZeroClipboard.off("ready");
|
||||
```
|
||||
|
||||
_[`undefined`]_ Remove ALL listener functions/objects for an `eventType`.
|
||||
|
||||
```js
|
||||
ZeroClipboard.off();
|
||||
```
|
||||
|
||||
_[`undefined`]_ Remove ALL listener functions/objects for ALL registered event types.
|
||||
|
||||
|
||||
#### `ZeroClipboard.emit(...)`
|
||||
|
||||
```js
|
||||
ZeroClipboard.emit("ready");
|
||||
ZeroClipboard.emit({
|
||||
type: "error",
|
||||
name: "flash-disabled"
|
||||
});
|
||||
|
||||
var pendingCopyData = ZeroClipboard.emit("copy");
|
||||
```
|
||||
|
||||
_[`undefined`, or a Flash-friendly data `Object` for the `"copy"` event]_ Dispatch an event to all
|
||||
registered listeners. The emission of some types of events will result in side effects.
|
||||
|
||||
|
||||
#### `ZeroClipboard.handlers(...)`
|
||||
|
||||
```js
|
||||
var listeners = ZeroClipboard.handlers("ready");
|
||||
```
|
||||
|
||||
_[`Array`]_ Retrieves a copy of the registered listener functions/objects for the given `eventType`.
|
||||
|
||||
|
||||
```js
|
||||
var listeners = ZeroClipboard.handlers();
|
||||
```
|
||||
|
||||
_[`Object`]_ Retrieves a copy of the map of registered listener functions/objects for ALL event types.
|
||||
|
||||
|
||||
|
||||
### Static Events
|
||||
|
||||
#### `"ready"`
|
||||
|
||||
The `ready` event is fired when the Flash SWF completes loading and is ready for action. Please
|
||||
note that you need to set most configuration options [with [`ZeroClipboard.config(...)`](#zeroclipboardconfig)]
|
||||
before `ZeroClipboard.create()` is invoked.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("ready", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "ready",
|
||||
message: "Flash communication is established",
|
||||
target: null,
|
||||
relatedTarget: null,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
version: "11.2.202",
|
||||
timeStamp: Date.now()
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
#### `"beforecopy"`
|
||||
|
||||
On `click`, the Flash object will fire off a `beforecopy` event. This event is generally only
|
||||
used for "UI prepartion" if you want to alter anything before the `copy` event fires.
|
||||
|
||||
**IMPORTANT:** Handlers of this event are expected to operate synchronously if they intend to be
|
||||
finished before the "copy" event is triggered.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("beforecopy", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "beforecopy",
|
||||
target: currentlyActivatedElementOrNull,
|
||||
relatedTarget: dataClipboardElementTargetOfCurrentlyActivatedElementOrNull,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
timeStamp: Date.now()
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
#### `"copy"`
|
||||
|
||||
On `click` (and after the `beforecopy` event), the Flash object will fire off a `copy` event. If
|
||||
the HTML object has `data-clipboard-text` or `data-clipboard-target`, then ZeroClipboard will take
|
||||
care of getting an initial set of data. It will then invoke any `copy` event handlers, in which you
|
||||
can call `event.clipboardData.setData` to set the text, which will complete the loop.
|
||||
|
||||
**IMPORTANT:** If a handler of this event intends to modify the pending data for clipboard
|
||||
injection, it _MUST_ operate synchronously in order to maintain the temporarily elevated
|
||||
permissions granted by the user's `click` event. The most common "gotcha" for this restriction is
|
||||
if someone wants to make an asynchronous XMLHttpRequest in response to the `copy` event to get the
|
||||
data to inject — this won't work; make it a _synchronous_ XMLHttpRequest instead, or do the
|
||||
work in advance before the `copy` event is fired.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("copy", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "copy",
|
||||
target: currentlyActivatedElementOrNull,
|
||||
relatedTarget: dataClipboardElementTargetOfCurrentlyActivatedElementOrNull,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
timeStamp: Date.now(),
|
||||
clipboardData: {
|
||||
setData: ZeroClipboard.setData,
|
||||
clearData: ZeroClipboard.clearData
|
||||
}
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
#### `"aftercopy"`
|
||||
|
||||
The `aftercopy` event is fired when the text is copied [or failed to copy] to the clipboard.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("aftercopy", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "aftercopy",
|
||||
target: currentlyActivatedElementOrNull,
|
||||
relatedTarget: dataClipboardElementTargetOfCurrentlyActivatedElementOrNull,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
timeStamp: Date.now(),
|
||||
success: {
|
||||
"text/plain": true,
|
||||
"text/html": true,
|
||||
"application/rtf": false
|
||||
},
|
||||
data: {
|
||||
"text/plain": "Blah",
|
||||
"text/html": "<b>Blah</b>",
|
||||
"application/rtf": "{\\rtf1\\ansi\n{\\b Blah}}"
|
||||
}
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
#### `"destroy"`
|
||||
|
||||
The `destroy` event is fired when `ZeroClipboard.destroy()` is invoked.
|
||||
|
||||
**IMPORTANT:** Handlers of this event are expected to operate synchronously if they intend to be
|
||||
finished before the destruction is complete.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("destroy", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "destroy",
|
||||
target: null,
|
||||
relatedTarget: null,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
timeStamp: Date.now(),
|
||||
success: {
|
||||
"text/plain": true,
|
||||
"text/html": true,
|
||||
"application/rtf": false
|
||||
},
|
||||
data: {
|
||||
"text/plain": "Blah",
|
||||
"text/html": "<b>Blah</b>",
|
||||
"application/rtf": "{\\rtf1\\ansi\n{\\b Blah}}"
|
||||
}
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
#### `"error"`
|
||||
|
||||
The `error` event is fired under a number of conditions, which will be detailed as sub-sections below.
|
||||
|
||||
Some consumers may not consider all `error` types to be critical, and thus ZeroClipboard does not take it upon
|
||||
itself to implode by calling `ZeroClipboard.destroy()` under error conditions. However, many consumers may
|
||||
want to do just that.
|
||||
|
||||
|
||||
##### `error[name = "flash-disabled"]`
|
||||
|
||||
This type of `error` event fires when Flash Player is either not installed or not enabled in the browser.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("error", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "error",
|
||||
name: "flash-disabled",
|
||||
messsage: "Flash is disabled or not installed",
|
||||
target: null,
|
||||
relatedTarget: null,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
timeStamp: Date.now(),
|
||||
minimumVersion: "11.0.0"
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
##### `error[name = "flash-outdated"]`
|
||||
|
||||
This type of `error` event fires when Flash Player is installed in the browser but the version is too old
|
||||
for ZeroClipboard. ZeroClipboard requires Flash Player 11.0.0 or above.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("error", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "error",
|
||||
name: "flash-outdated",
|
||||
messsage: "Flash is too outdated to support ZeroClipboard",
|
||||
target: null,
|
||||
relatedTarget: null,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
timeStamp: Date.now(),
|
||||
minimumVersion: "11.0.0",
|
||||
version: "10.3.183"
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
##### `error[name = "flash-unavailable"]`
|
||||
|
||||
This type of `error` event fires when the browser's installation of Flash Player cannot communicate bidirectionally with JavaScript.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("error", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "error",
|
||||
name: "flash-unavailable",
|
||||
messsage: "Flash is unable to communicate bidirectionally with JavaScript",
|
||||
target: null,
|
||||
relatedTarget: null,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
timeStamp: Date.now(),
|
||||
minimumVersion: "11.0.0",
|
||||
version: "11.2.202"
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
##### `error[name = "flash-deactivated"]`
|
||||
|
||||
This type of `error` event fires when the browser's installation of Flash Player is either too old
|
||||
for the browser [but _not_ too old for ZeroClipboard] or if Flash objects are configured as
|
||||
click-to-play and the user does not authorize it within `_globalConfig.flashLoadTimeout`
|
||||
milliseconds or does not authorize it at all.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("error", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "error",
|
||||
name: "flash-deactivated",
|
||||
messsage: "Flash is too outdated for your browser and/or is configured as click-to-activate",
|
||||
target: null,
|
||||
relatedTarget: null,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
timeStamp: Date.now(),
|
||||
minimumVersion: "11.0.0",
|
||||
version: "11.2.202"
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
##### `error[name = "flash-overdue"]`
|
||||
|
||||
This type of `error` event fires when the SWF loads successfully but takes longer than
|
||||
`_globalConfig.flashLoadTimeout` milliseconds to do so. This would likely be caused by
|
||||
one of the following situations:
|
||||
1. Too short of a `_globalConfig.flashLoadTimeout` duration configured
|
||||
2. Network latency
|
||||
3. The user's installation of Flash is configured as click-to-play but then authorized
|
||||
by the user too late such that the SWF does not finish loading before the timeout
|
||||
period has expired (or it may have expired before they authorized it at all).
|
||||
|
||||
The appropriate response to this event is left up to the consumer. For instance, if they
|
||||
chose to invoke `ZeroClipboard.destroy()` in response to the earlier
|
||||
`error[name = "flash-deactivated"]` event but then receive this `error[name = "flash-overdue"]`
|
||||
event, they may choose to "restart" their process and construct new ZeroClipboard client instances,
|
||||
or they may choose to just log the error to their server so they can consider increasing the
|
||||
allowed timeout duration in the future.
|
||||
|
||||
This may be especially important for SPA or PJAX-based applications to consider as their users
|
||||
may remain on a single page for an extended period of time during which they _possibly_ could
|
||||
have enjoyed an improved experience if ZeroClipboard had been "restarted" after an initial hiccup.
|
||||
|
||||
```js
|
||||
ZeroClipboard.on("error", function(e) {
|
||||
/*
|
||||
e = {
|
||||
type: "error",
|
||||
name: "flash-overdue",
|
||||
messsage: "Flash communication was established but NOT within the acceptable time limit",
|
||||
target: null,
|
||||
relatedTarget: null,
|
||||
currentTarget: flashSwfObjectRef,
|
||||
timeStamp: Date.now(),
|
||||
minimumVersion: "11.0.0",
|
||||
version: "11.2.202"
|
||||
};
|
||||
*/
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Instance
|
||||
|
||||
The following properties and methods are accessible via a `ZeroClipboard` client instance, e.g.
|
||||
|
||||
```js
|
||||
var clippedEl = document.getElementById("d_clip_button");
|
||||
var client = new ZeroClipboard(clippedEl);
|
||||
```
|
||||
|
||||
|
||||
### Instance Properties
|
||||
|
||||
#### `client.id`
|
||||
|
||||
_[`String`]_ A unique identifier for this ZeroClipboard client instance.
|
||||
|
||||
|
||||
### Instance Methods
|
||||
|
||||
#### `client.destroy()`
|
||||
|
||||
_[`undefined`]_ Remove all event handlers and unclip all clipped elements.
|
||||
|
||||
|
||||
#### `client.setText(...)`
|
||||
|
||||
```js
|
||||
client.setText("Blah");
|
||||
```
|
||||
|
||||
_[`this`]_ Set the pending `data` of type `"text/plain"` for clipboard injection.
|
||||
|
||||
|
||||
#### `client.setHtml(...)`
|
||||
|
||||
```js
|
||||
client.setHtml("<b>Blah</b>");
|
||||
```
|
||||
|
||||
_[`this`]_ Set the pending `data` of type `"text/html"` for clipboard injection.
|
||||
|
||||
|
||||
#### `client.setRichText(...)`
|
||||
|
||||
```js
|
||||
client.setRichText("{\\rtf1\\ansi\n{\\b Blah}}");
|
||||
```
|
||||
|
||||
_[`this`]_ Set the pending `data` of type `"application/rtf"` for clipboard injection.
|
||||
|
||||
|
||||
#### `client.setData(...)`
|
||||
|
||||
```js
|
||||
client.setData("text/plain", "Blah");
|
||||
```
|
||||
|
||||
_[`this`]_ Set the pending `data` of type `format` for clipboard injection.
|
||||
|
||||
```js
|
||||
client.setData({
|
||||
"text/plain": "Blah",
|
||||
"text/html": "<b>Blah</b>"
|
||||
});
|
||||
```
|
||||
|
||||
_[`this`]_ Set the pending `data` of various formats for clipboard injection. This particular
|
||||
function signature (passing in an `Object`) will implicitly clear out any existing pending data.
|
||||
|
||||
|
||||
#### `client.clearData(...)`
|
||||
|
||||
```js
|
||||
client.clearData("text/plain");
|
||||
```
|
||||
|
||||
_[`this`]_ Clear the pending data of type `format` for clipboard injection.
|
||||
|
||||
```js
|
||||
client.clearData();
|
||||
```
|
||||
|
||||
_[`this`]_ Clear the pending data of ALL formats for clipboard injection.
|
||||
|
||||
|
||||
#### `client.getData(...)`
|
||||
|
||||
```js
|
||||
var text = client.getData("text/plain");
|
||||
```
|
||||
|
||||
_[`String`]_ Get the pending data of type `format` for clipboard injection.
|
||||
|
||||
```js
|
||||
var dataObj = client.getData();
|
||||
```
|
||||
|
||||
_[`Object`]_ Get a copy of the pending data of ALL formats for clipboard injection.
|
||||
|
||||
|
||||
#### `client.clip(...)`
|
||||
|
||||
```js
|
||||
client.clip(document.getElementById("d_clip_button"))
|
||||
client.clip(document.querySelectorAll(".clip_button"));
|
||||
client.clip(jQuery(".clip_button"));
|
||||
```
|
||||
|
||||
_[`this`]_ Register clipboard actions for new element(s) to the client. This includes
|
||||
automatically invoking `ZeroClipboard.focus` on the current element when it is hovered over,
|
||||
unless the `autoActivate` configuration property is set to `false`.
|
||||
|
||||
|
||||
#### `client.unclip(...)`
|
||||
|
||||
```js
|
||||
client.unclip(document.getElementById("d_clip_button"))
|
||||
client.unclip(document.querySelectorAll(".clip_button"));
|
||||
client.unclip(jQuery(".clip_button"));
|
||||
client.unclip();
|
||||
```
|
||||
|
||||
_[`this`]_ Unregister the clipboard actions of previously registered element(s) on the page.
|
||||
If no elements are provided, ALL clipped/registered elements will be unregistered.
|
||||
|
||||
|
||||
#### `client.elements()`
|
||||
|
||||
```js
|
||||
var els = client.elements();
|
||||
```
|
||||
|
||||
_[`Array`]_ Get all of the elements to which this client is clipped/registered.
|
||||
|
||||
|
||||
#### `client.on(...)`
|
||||
|
||||
```js
|
||||
var listenerFn = function(e) { var client = this; /* ... */ };
|
||||
client.on("ready", listenerFn);
|
||||
|
||||
var listenerObj = {
|
||||
handleEvent: function(e) { var listenerObj = this; /* ... */ }
|
||||
};
|
||||
client.on("error", listenerObj);
|
||||
```
|
||||
|
||||
_[`this`]_ Add a `listener` function/object for an `eventType` within this client instance.
|
||||
|
||||
```js
|
||||
client.on("ready error", function(e) { /* ... */ });
|
||||
```
|
||||
|
||||
_[`this`]_ Add a `listener` function/object for multiple `eventType`s within this client instance.
|
||||
|
||||
```js
|
||||
client.on({
|
||||
"ready": function(e) { /* ... */ },
|
||||
"error": function(e) { /* ... */ }
|
||||
});
|
||||
```
|
||||
|
||||
_[`this`]_ Add a set of `eventType` to `listener` function/object mappings within this client instance.
|
||||
|
||||
|
||||
#### `client.off(...)`
|
||||
|
||||
```js
|
||||
client.off("ready", listenerFn);
|
||||
client.off("error", listenerObj);
|
||||
```
|
||||
|
||||
_[`this`]_ Remove a `listener` function/object for an `eventType` within this client instance.
|
||||
|
||||
```js
|
||||
client.off("ready error", listenerFn);
|
||||
```
|
||||
|
||||
_[`this`]_ Remove a `listener` function/object for multiple `eventType`s within this client instance.
|
||||
|
||||
```js
|
||||
client.off({
|
||||
"ready": readyListenerFn,
|
||||
"error": errorListenerFn
|
||||
});
|
||||
```
|
||||
|
||||
_[`this`]_ Remove a set of `eventType` to `listener` function/object mappings within this client instance.
|
||||
|
||||
```js
|
||||
client.off("ready");
|
||||
```
|
||||
|
||||
_[`this`]_ Remove ALL listener functions/objects for an `eventType` within this client instance.
|
||||
|
||||
```js
|
||||
client.off();
|
||||
```
|
||||
|
||||
_[`this`]_ Remove ALL listener functions/objects for ALL registered event types within this client instance.
|
||||
|
||||
|
||||
#### `client.emit(...)`
|
||||
|
||||
```js
|
||||
client.emit("ready");
|
||||
client.emit({
|
||||
type: "error",
|
||||
name: "flash-disabled"
|
||||
});
|
||||
```
|
||||
|
||||
_[`undefined`]_ Dispatch an event to all registered listeners within this client instance.
|
||||
|
||||
|
||||
#### `client.handlers(...)`
|
||||
|
||||
```js
|
||||
var listeners = client.handlers("ready");
|
||||
```
|
||||
|
||||
_[`Array`]_ Retrieves a copy of the registered listener functions/objects for the given `eventType` within this client instance.
|
||||
|
||||
|
||||
```js
|
||||
var listeners = client.handlers();
|
||||
```
|
||||
|
||||
_[`Object`]_ Retrieves a copy of the map of registered listener functions/objects for ALL event types within this client instance.
|
||||
|
||||
|
||||
|
||||
### Instance Events
|
||||
|
||||
See the [Static Events](#static-events) listing. The ZeroClipboard client instances regurgitate the `ZeroClipboard.Core` events, ONLY if the event is NOT impertinent to this particular client. The only difference is that the clients' event dispatching will update the `event` object to include a `client` property that references the relevant client instance, e.g.:
|
||||
|
||||
```js
|
||||
var client = new ZeroClipboard();
|
||||
client.on("ready", function(e) {
|
||||
if (e.client === client && client === this) {
|
||||
console.log("This client instance is ready!");
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Configuration Options
|
||||
|
||||
These are default values for the global configurations options. You should generally update these _before_ you create your clients.
|
||||
|
||||
```js
|
||||
var _globalConfig = {
|
||||
|
||||
// SWF URL, relative to the page. Default value will be "ZeroClipboard.swf"
|
||||
// under the same path as the ZeroClipboard JS file.
|
||||
swfPath: _swfPath,
|
||||
|
||||
// SWF inbound scripting policy: page domains that the SWF should trust.
|
||||
// (single string, or array of strings)
|
||||
trustedDomains: window.location.host ? [window.location.host] : [],
|
||||
|
||||
// Include a "noCache" query parameter on requests for the SWF.
|
||||
cacheBust: true,
|
||||
|
||||
// Enable use of the fancy "Desktop" clipboard, even on Linux where it is
|
||||
// known to suck.
|
||||
forceEnhancedClipboard: false,
|
||||
|
||||
// How many milliseconds to wait for the Flash SWF to load and respond before assuming that
|
||||
// Flash is deactivated (e.g. click-to-play) in the user's browser. If you don't care about
|
||||
// how long it takes to load the SWF, you can set this to `null`.
|
||||
flashLoadTimeout: 30000,
|
||||
|
||||
// Setting this to `false` would allow users to handle calling `ZeroClipboard.focus(...);`
|
||||
// themselves instead of relying on our per-element `mouseover` handler.
|
||||
autoActivate: true,
|
||||
|
||||
// Bubble synthetic events in JavaScript after they are received by the Flash object.
|
||||
bubbleEvents: true,
|
||||
|
||||
// Sets the ID of the `div` encapsulating the Flash object.
|
||||
// Value is validated against the [HTML4 spec for `ID` tokens][valid_ids].
|
||||
containerId: "global-zeroclipboard-html-bridge",
|
||||
|
||||
// Sets the class of the `div` encapsulating the Flash object.
|
||||
containerClass: "global-zeroclipboard-container",
|
||||
|
||||
// Sets the ID and name of the Flash `object` element.
|
||||
// Value is validated against the [HTML4 spec for `ID` and `Name` tokens][valid_ids].
|
||||
swfObjectId: "global-zeroclipboard-flash-bridge",
|
||||
|
||||
// The class used to indicate that a clipped element is being hovered over.
|
||||
hoverClass: "zeroclipboard-is-hover",
|
||||
|
||||
// The class used to indicate that a clipped element is active (is being clicked).
|
||||
activeClass: "zeroclipboard-is-active",
|
||||
|
||||
|
||||
|
||||
// Forcibly set the hand cursor ("pointer") for all clipped elements.
|
||||
// IMPORTANT: This configuration value CAN be modified while a SWF is actively embedded.
|
||||
forceHandCursor: false,
|
||||
|
||||
// Sets the title of the `div` encapsulating the Flash object.
|
||||
// IMPORTANT: This configuration value CAN be modified while a SWF is actively embedded.
|
||||
title: null,
|
||||
|
||||
// The z-index used by the Flash object.
|
||||
// Max value (32-bit): 2147483647.
|
||||
// IMPORTANT: This configuration value CAN be modified while a SWF is actively embedded.
|
||||
zIndex: 999999999
|
||||
|
||||
};
|
||||
```
|
||||
|
||||
You can override the defaults by making calls like `ZeroClipboard.config({ swfPath: "new/path" });`
|
||||
before you create any clients.
|
||||
|
||||
|
||||
### SWF Inbound Scripting Access: The `trustedDomains` option
|
||||
|
||||
This allows other SWF files and HTML pages from the allowed domains to access/call publicly
|
||||
exposed ActionScript code, e.g. functions shared via `ExternalInterface.addCallback`. In other
|
||||
words, it controls the SWF inbound scripting access.
|
||||
|
||||
If your ZeroClipboard SWF is served from a different origin/domain than your page, you need to tell
|
||||
the SWF that it's OK to trust your page. The default value of `[window.location.host]` is almost
|
||||
_**always**_ what you will want unless you specifically want the SWF to communicate with pages from
|
||||
other domains (e.g. in `iframe`s or child windows).
|
||||
|
||||
For more information about trusted domains, consult the [_official Flash documentation for `flash.system.Security.allowDomain(...)`_](http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/system/Security.html#allowDomain\(\)).
|
||||
|
||||
|
||||
### SWF Outbound Scripting Access
|
||||
|
||||
The `allowScriptAccess` parameter (for Flash embedding markup) allows the SWF file to access/call
|
||||
JavaScript/HTML functionality of HTML pages on allowed domains, e.g. invoking functions via
|
||||
`ExternalInterface.call`. In other words, it controls the SWF outbound scripting access.
|
||||
|
||||
As of version `v2.0.0-alpha.2`, the `allowScriptAccess` configuration option no longer exists. The
|
||||
appropriate value will be determined immediately before the Flash object is embedded on the page.
|
||||
The value is based on a relationship between the current domain (`window.location.host`) and the
|
||||
value of the `trustedDomains` configuration option.
|
||||
|
||||
For more information about `allowScriptAccess`, consult the [_official Flash documentation_](http://helpx.adobe.com/flash/kb/control-access-scripts-host-web.html).
|
||||
|
||||
|
||||
### Cross-Protocol Limitations
|
||||
|
||||
ZeroClipboard was intentionally configured to _not_ allow the SWF to be served from a secure domain (HTTPS) but scripted by an insecure domain (HTTP).
|
||||
|
||||
If you find yourself in this situation (as in [Issue #170](https://github.com/zeroclipboard/zeroclipboard/issues/170)), please consider the following options:
|
||||
1. Serve the SWF over HTTP instead of HTTPS. If the page's protocol can vary (e.g. authorized/unauthorized, staging/production, etc.), you should include add the SWF with a relative protocol (`//s3.amazonaws.com/blah/ZeroClipboard.swf`) instead of an absolute protocol (`https://s3.amazonaws.com/blah/ZeroClipboard.swf`).
|
||||
2. Serve the page over HTTPS instead of HTTP. If the page's protocol can vary, see the note on the previous option (1).
|
||||
3. Update ZeroClipboard's ActionScript codebase to call the [`allowInsecureDomain`](http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/system/Security.html#allowInsecureDomain\(\)) method, then recompile the SWF with your custom changes.
|
||||
|
||||
|
||||
### `file://` Protocol Limitations
|
||||
|
||||
If you want to host a page locally on the `file://` protocol, you must specifically configure
|
||||
ZeroClipboard to trust ALL domains for SWF interaction via a wildcard. This configuration must be
|
||||
set _before_ creating ZeroClipboard client instances as a typical consumer, or before calling
|
||||
`ZeroClipboard.create()` in a 3rd party wrapper:
|
||||
|
||||
```js
|
||||
ZeroClipboard.config({ trustedDomains: ["*"] });
|
||||
```
|
||||
|
||||
This wildcard configuration should _**NOT**_ be used in environments hosted over HTTP/HTTPS.
|
439
public/filemanager/scripts/zeroclipboard/docs/instructions.md
Normal file
439
public/filemanager/scripts/zeroclipboard/docs/instructions.md
Normal file
@@ -0,0 +1,439 @@
|
||||
### WARNING
|
||||
**This `master` branch contains the `v2.x` codebase for ZeroClipboard! For the `v1.x` codebase, see the [`1.x-master`](https://github.com/zeroclipboard/zeroclipboard/tree/1.x-master) branch instead.**
|
||||
|
||||
|
||||
# Overview
|
||||
|
||||
The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible [Adobe Flash](http://en.wikipedia.org/wiki/Adobe_Flash) movie and a [JavaScript](http://en.wikipedia.org/wiki/JavaScript) interface. The "Zero" signifies that the library is invisible and the user interface is left entirely up to you.
|
||||
|
||||
This is achieved by automatically floating the invisible movie on top of a [DOM](http://en.wikipedia.org/wiki/Document_Object_Model) element of your choice. Standard mouse events are even propagated out to your DOM element, so you can still have rollover and mousedown effects.
|
||||
|
||||
|
||||
## Limitations
|
||||
|
||||
### User Interaction Required
|
||||
|
||||
Due to browser and Flash security restrictions, this clipboard injection can _**ONLY**_ occur when
|
||||
the user clicks on the invisible Flash movie. A simulated `click` event from JavaScript will not
|
||||
suffice as this would enable [clipboard poisoning](http://www.computerworld.com/s/article/9117268/Adobe_patches_Flash_clickjacking_and_clipboard_poisoning_bugs).
|
||||
|
||||
### Synchronicity Required During `copy`
|
||||
|
||||
If a handler of `copy` event intends to modify the pending data for clipboard
|
||||
injection, it _MUST_ operate synchronously in order to maintain the temporarily elevated
|
||||
permissions granted by the user's `click` event. The most common "gotcha" for this restriction is
|
||||
if someone wants to make an asynchronous XMLHttpRequest in response to the `copy` event to get the
|
||||
data to inject — this will not work. You must make it a _synchronous_ XMLHttpRequest instead, or do the
|
||||
work in advance before the `copy` event is fired.
|
||||
|
||||
### OS-Specific Limitations
|
||||
|
||||
See [OS Considerations](#os-considerations) below.
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
### [NPM](https://www.npmjs.org/) [](https://www.npmjs.org/package/zeroclipboard)
|
||||
|
||||
```shell
|
||||
npm install zeroclipboard
|
||||
```
|
||||
|
||||
### [Bower](http://bower.io/) [](http://bower.io/search/?q=zeroclipboard)
|
||||
|
||||
```shell
|
||||
bower install zeroclipboard
|
||||
```
|
||||
|
||||
### [SPM](http://spmjs.io/) [](http://spmjs.io/package/zeroclipboard)
|
||||
|
||||
```shell
|
||||
spm install zeroclipboard
|
||||
```
|
||||
|
||||
### [PHP Composer](https://getcomposer.org/) [](https://packagist.org/packages/zeroclipboard/zeroclipboard)
|
||||
|
||||
For any PHP Composer users, ZeroClipboard is also [available on Packagist](https://packagist.org/packages/zeroclipboard/zeroclipboard).
|
||||
|
||||
### [Ruby Gem](https://rubygems.org/)
|
||||
|
||||
For any Rails users, the [`zeroclipboard-rails` Ruby Gem](https://rubygems.org/gems/zeroclipboard-rails) is available to automatically add ZeroClipboard into your Rails asset pipeline.
|
||||
|
||||
|
||||
## CDN Availability
|
||||
|
||||
If you'd like to use ZeroClipboard hosted via a CDN (content delivery network), you can try:
|
||||
|
||||
- **cdnjs**: http://cdnjs.com/libraries/zeroclipboard
|
||||
- **jsDelivr**: http://www.jsdelivr.com/#!zeroclipboard
|
||||
|
||||
|
||||
## Setup
|
||||
|
||||
To use the library, simply include the following JavaScript file in your page:
|
||||
|
||||
```html
|
||||
<script type="text/javascript" src="ZeroClipboard.js"></script>
|
||||
```
|
||||
|
||||
You also need to have the "`ZeroClipboard.swf`" file available to the browser. If this file is
|
||||
located in the same directory as your web page, then it will work out of the box. However, if the
|
||||
SWF file is hosted elsewhere, you need to set the URL like this (place this code _after_ the script
|
||||
tag):
|
||||
|
||||
```js
|
||||
ZeroClipboard.config( { swfPath: "http://YOURSERVER/path/ZeroClipboard.swf" } );
|
||||
```
|
||||
|
||||
|
||||
## Clients
|
||||
|
||||
Now you are ready to create one or more _clients_. A client is a single instance of the clipboard
|
||||
library on the page, linked to one or more DOM elements. Here is how to create a client instance:
|
||||
|
||||
```js
|
||||
var client = new ZeroClipboard();
|
||||
```
|
||||
|
||||
You can also include an element or array of elements in the new client. _\*\*This example uses jQuery to find "copy buttons"._
|
||||
|
||||
```js
|
||||
var client = new ZeroClipboard($(".copy-button"));
|
||||
```
|
||||
|
||||
|
||||
## API
|
||||
|
||||
For the full API documentation, see [api/ZeroClipboard.md](api/ZeroClipboard.md). The full set of
|
||||
[Configuration Options](api/ZeroClipboard.md#configuration-options) are also documented there.
|
||||
|
||||
For developers who want to wrap ZeroClipboard into a 3rd party plugin
|
||||
(e.g. [jquery.zeroclipboard](https://github.com/zeroclipboard/jquery.zeroclipboard)),
|
||||
see the [api/ZeroClipboard.Core.md](api/ZeroClipboard.Core.md) documentation instead.
|
||||
|
||||
|
||||
### Text To Copy
|
||||
|
||||
Setting the clipboard text can be done in 4 ways:
|
||||
|
||||
1. Add a `copy` event handler in which you call `event.clipboardData.setData` to set the appropriate data. This event is triggered every time ZeroClipboard tries to inject into the clipboard. Example:
|
||||
|
||||
```js
|
||||
client.on( "copy", function (event) {
|
||||
var clipboard = event.clipboardData;
|
||||
clipboard.setData( "text/plain", "Copy me!" );
|
||||
clipboard.setData( "text/html", "<b>Copy me!</b>" );
|
||||
clipboard.setData( "application/rtf", "{\\rtf1\\ansi\n{\\b Copy me!}}" );
|
||||
});
|
||||
```
|
||||
|
||||
2. Set the "text/plain" [and _usually_ "text/html"] clipboard segments via `data-clipboard-target` attribute on the button. ZeroClipboard will look for the target element via ID and try to get the HTML value via `.value`, `.outerHTML`, or `.innerHTML`, and the text value via `.value`, `.textContent`, or `.innerText`. If the HTML and text values for the targeted element match, the value will only be placed into the "text/plain" segment of the clipboard (i.e. the "text/html" segment will cleared).
|
||||
|
||||
```html
|
||||
<button id="my-button_text" data-clipboard-target="clipboard_text">Copy to Clipboard</button>
|
||||
<button id="my-button_textarea" data-clipboard-target="clipboard_textarea">Copy to Clipboard</button>
|
||||
<button id="my-button_pre" data-clipboard-target="clipboard_pre">Copy to Clipboard</button>
|
||||
|
||||
<input type="text" id="clipboard_text" value="Clipboard Text"/>
|
||||
<textarea id="clipboard_textarea">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</textarea>
|
||||
<pre id="clipboard_pre">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</pre>
|
||||
```
|
||||
|
||||
3. Set the "text/plain" clipboard segment via `data-clipboard-text` attribute on the button. Doing this will let ZeroClipboard take care of the rest.
|
||||
|
||||
```html
|
||||
<button id="my-button" data-clipboard-text="Copy me!">Copy to Clipboard</button>
|
||||
```
|
||||
|
||||
4. Set the data via the `ZeroClipboard.setData` (any segment) method. You can call this function at any time: when the page first loads, or later like in a `copy` event handler. Example:
|
||||
|
||||
```js
|
||||
ZeroClipboard.setData( "text/plain", "Copy me!" );
|
||||
```
|
||||
|
||||
The important caveat of using `ZeroClipboard.setData` is that the data it sets is **transient** and _will only be used for a single copy operation_. As such, we do not particularly
|
||||
recommend using `ZeroClipboard.setData` (and friends) other than inside of a `copy` event handler; however, the API will not prevent you from using it in other ways.
|
||||
|
||||
5. Set the data via the `client.setText` ("text/plain" segment), `client.setHtml` ("text/html" segment), `client.setRichText` ("application/rtf" segment), or `client.setData` (any segment) methods. You can call this function at any time: when the page first loads, or later like in a `copy` event handler. Example:
|
||||
|
||||
```js
|
||||
client.setText( "Copy me!" );
|
||||
```
|
||||
|
||||
The important caveat of using `client.setData` (and friends) is that the data it sets is **transient** and _will only be used for a single copy operation_. As such, we do not particularly
|
||||
recommend using `client.setData` (and friends) other than inside of a `copy` event handler; however, the API will not prevent you from using it in other ways.
|
||||
|
||||
|
||||
### Clipping
|
||||
|
||||
Clipping refers to the process of "linking" the Flash movie to a DOM element on the page. Since the Flash movie is completely transparent, the user sees nothing out of the ordinary.
|
||||
|
||||
The Flash movie receives the click event and copies the text to the clipboard. Also, mouse actions like hovering and `mousedown` generate events that you can capture (see [_Event Handlers_](#event-handlers) below).
|
||||
|
||||
To clip elements, you must pass an element, or array of elements to the `clip` function.
|
||||
|
||||
Here is how to clip your client library instance to a DOM element:
|
||||
|
||||
```js
|
||||
client.clip( document.getElementById("d_clip_button") );
|
||||
```
|
||||
|
||||
You can pass in a reference to the actual DOM element object itself or an array of DOM objects. The rest all happens automatically: the movie is created, all your options set, and it is floated above the element, awaiting clicks from the user.
|
||||
|
||||
|
||||
### Example Implementation
|
||||
|
||||
```html
|
||||
<button id="my-button" data-clipboard-text="Copy me!" title="Click to copy to clipboard.">Copy to Clipboard</button>
|
||||
```
|
||||
|
||||
And the code:
|
||||
|
||||
```js
|
||||
var client = new ZeroClipboard( $("button#my-button") );
|
||||
```
|
||||
|
||||
|
||||
## CSS Effects
|
||||
|
||||
Since the Flash movie is floating on top of your DOM element, it will receive all the mouse events before the browser has a chance to catch them. However, for convenience, these events are passed through to your clipboard client which you can capture (see _Event Handlers_ below), so long as the `bubbleEvents` configuration property remains set to `true`.
|
||||
|
||||
In addition to this, ZeroClipboard can also manage CSS classes on the clipped elements that mimic the CSS pseudo-classes ":hover" and ":active" on your DOM element. This essentially allows your elements to behave normally, even though the floating Flash movie is the first object receiving all the mouse events during the event bubbling phase. These "pseudo-pseudo-class" names are configurable via the `hoverClass` and `activeClass` configuration properties.
|
||||
|
||||
Example CSS, targeting a DOM element with a class of "clip_button":
|
||||
|
||||
```css
|
||||
.clip_button {
|
||||
width: 150px;
|
||||
text-align: center;
|
||||
border: 1px solid black;
|
||||
background-color: #ccc;
|
||||
margin: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
.clip_button.zeroclipboard-is-hover { background-color: #eee; }
|
||||
.clip_button.zeroclipboard-is-active { background-color: #aaa; }
|
||||
```
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
The following are complete, working examples of using the clipboard client library in HTML pages.
|
||||
|
||||
|
||||
### Minimal Example
|
||||
|
||||
Here is a quick example using as few calls as possible:
|
||||
|
||||
```html
|
||||
<html>
|
||||
<body>
|
||||
<div id="d_clip_button" class="clip_button" data-clipboard-text="Copy Me!" title="Click to copy." style="border:1px solid black; padding:20px;">Copy To Clipboard</div>
|
||||
|
||||
<script type="text/javascript" src="ZeroClipboard.js"></script>
|
||||
<script type="text/javascript">
|
||||
var client = new ZeroClipboard( document.getElementById('d_clip_button') );
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
When clicked, the text "Copy me!" will be copied to the clipboard.
|
||||
|
||||
|
||||
### A More Complete Example
|
||||
|
||||
Here is a more complete example which exercises many of the configuration options and event handlers:
|
||||
|
||||
```html
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
.clip_button {
|
||||
text-align: center;
|
||||
border: 1px solid black;
|
||||
background-color: #ccc;
|
||||
margin: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
.clip_button.zeroclipboard-is-hover { background-color: #eee; }
|
||||
.clip_button.zeroclipboard-is-active { background-color: #aaa; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="ZeroClipboard.js"></script>
|
||||
|
||||
<div class="clip_button">Copy To Clipboard</div>
|
||||
<div class="clip_button">Copy This Too!</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var client = new ZeroClipboard( $('.clip_button') );
|
||||
|
||||
client.on( 'ready', function(event) {
|
||||
// console.log( 'movie is loaded' );
|
||||
|
||||
client.on( 'copy', function(event) {
|
||||
event.clipboardData.setData('text/plain', event.target.innerHTML);
|
||||
} );
|
||||
|
||||
client.on( 'aftercopy', function(event) {
|
||||
console.log('Copied text to clipboard: ' + event.data['text/plain']);
|
||||
} );
|
||||
} );
|
||||
|
||||
client.on( 'error', function(event) {
|
||||
// console.log( 'ZeroClipboard error of type "' + event.name + '": ' + event.message );
|
||||
ZeroClipboard.destroy();
|
||||
} );
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
|
||||
## Namespacing ZeroClipboard
|
||||
|
||||
ZeroClipboard creates DOM elements with pre-configured attributes, e.g. a `div` element with an ID of `"global-zeroclipboard-html-bridge"` to encapsulate the Flash object.
|
||||
|
||||
If you have a need to change the default values, they can be configured by passing in values for `containerId`, `containerClass`, and/or `swfObjectId` using the `ZeroClipboard.config` method. Configuration of these values is completely optional. These values cannot be reconfigured while the ZeroClipboard SWF is actively embedded, and so are completely ignored during that time.
|
||||
|
||||
Values for `containerId` and `swfObjectId` are validated against the [HTML4 spec for `ID` and `Name` tokens][valid_ids].
|
||||
|
||||
|
||||
## AMD
|
||||
|
||||
If using [AMD](https://github.com/amdjs/amdjs-api/wiki/AMD) with a library such as [RequireJS](http://requirejs.org/), etc., you shouldn't need to do any special configuration for ZeroClipboard to work correctly as an AMD module.
|
||||
|
||||
|
||||
## CommonJS
|
||||
|
||||
If using [CommonJS](http://wiki.commonjs.org/wiki/Modules/1.1) with a library such as [Browserify](http://browserify.org/), [Webmake](https://github.com/medikoo/modules-webmake), etc., you shouldn't need to do any special configuration for ZeroClipboard to work correctly as an CommonJS module.
|
||||
|
||||
|
||||
## Known Conflicts With Other Libraries
|
||||
|
||||
### [IE freezes when clicking a ZeroClipboard clipped element within a Bootstrap Modal](https://github.com/zeroclipboard/zeroclipboard/issues/159).
|
||||
- **Cause:** Bootstrap's Modal has an `enforceFocus` function that tries to keep the focus on the modal.
|
||||
However, since the ZeroClipboard container is an immediate child of the `body`, this enforcement conflicts. Note that
|
||||
this workaround actually _overrides_ a core Bootstrap Modal function, and as such must be kept in sync as this function
|
||||
changes in future versions of Bootstrap.
|
||||
- **Workaround:** _Targeted against [Bootstrap v3.x](https://github.com/twbs/bootstrap/blob/96a9e1bae06cb21f8cf72ec528b8e31b6ab27272/js/modal.js#L115-123)._
|
||||
|
||||
#### Workaround A
|
||||
|
||||
```js
|
||||
if (/MSIE|Trident/.test(window.navigator.userAgent)) {
|
||||
(function($) {
|
||||
var zcContainerId = ZeroClipboard.config('containerId');
|
||||
$('#' + zcContainerId).on('focusin', false);
|
||||
})(window.jQuery);
|
||||
}
|
||||
```
|
||||
|
||||
#### Workaround B
|
||||
|
||||
```js
|
||||
if (/MSIE|Trident/.test(window.navigator.userAgent)) {
|
||||
(function($) {
|
||||
var zcClass = '.' + ZeroClipboard.config('containerClass');
|
||||
var proto = $.fn.modal.Constructor.prototype;
|
||||
proto.enforceFocus = function() {
|
||||
$(document)
|
||||
.off('focusin.bs.modal') /* Guard against infinite focus loop */
|
||||
.on('focusin.bs.modal', $.proxy(function(e) {
|
||||
if (this.$element[0] !== e.target &&
|
||||
!this.$element.has(e.target).length &&
|
||||
/* Adding this final condition check is the only real change */
|
||||
!$(e.target).closest(zcClass).length
|
||||
) {
|
||||
this.$element.focus();
|
||||
}
|
||||
}, this));
|
||||
};
|
||||
})(window.jQuery);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### [IE freezes when clicking a ZeroClipboard clipped element within a jQuery UI [Modal] Dialog](https://github.com/zeroclipboard/zeroclipboard/issues/159).
|
||||
- **Cause:** jQuery UI's Dialog (with `{ modal: true }` set) has a `_keepFocus` function that tries to keep the focus on the modal.
|
||||
However, since the ZeroClipboard container is an immediate child of the `body`, this enforcement conflicts. Luckily, jQuery UI offers
|
||||
more natural extension points than Bootstrap, so the workaround is smaller and less likely to be broken in future versions.
|
||||
- **Workaround:** _Targeted against [jQuery UI v1.10.x](https://github.com/jquery/jquery-ui/blob/457b275880b63b05b16b7c9ee6c22f29f682ebc8/ui/jquery.ui.dialog.js#L695-703)._
|
||||
|
||||
```js
|
||||
if (/MSIE|Trident/.test(window.navigator.userAgent)) {
|
||||
(function($) {
|
||||
var zcClass = '.' + ZeroClipboard.config('containerClass');
|
||||
$.widget( 'ui.dialog', $.ui.dialog, {
|
||||
_allowInteraction: function( event ) {
|
||||
return this._super(event) || $( event.target ).closest( zcClass ).length;
|
||||
}
|
||||
} );
|
||||
})(window.jQuery);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Support
|
||||
|
||||
This library is fully compatible with Flash Player 11.0.0 and above, which requires
|
||||
that the clipboard copy operation be initiated by a user click event inside the
|
||||
Flash movie. This is achieved by automatically floating the invisible movie on top
|
||||
of a [DOM](http://en.wikipedia.org/wiki/Document_Object_Model) element of your
|
||||
choice. Standard mouse events are even propagated out to your DOM element, so you
|
||||
can still have rollover and mousedown effects with just a _little_ extra effort.
|
||||
|
||||
ZeroClipboard `v2.x` is expected to work in IE9+ and all of the evergreen browsers.
|
||||
|
||||
|
||||
|
||||
## OS Considerations
|
||||
|
||||
Because ZeroClipboard will be interacting with your users' system clipboards, there are some special considerations
|
||||
specific to the users' operating systems that you should be aware of. With this information, you can make informed
|
||||
decisions of how _your_ site should handle each of these situations.
|
||||
|
||||
- **Windows:**
|
||||
- If you want to ensure that your Windows users will be able to paste their copied text into Windows
|
||||
Notepad and have it honor line breaks, you'll need to ensure that the text uses the sequence `\r\n` instead of
|
||||
just `\n` for line breaks. If the text to copy is based on user input (e.g. a `textarea`), then you can achieve
|
||||
this transformation by utilizing the `copy` event handler, e.g.
|
||||
|
||||
```js
|
||||
client.on('copy', function(event) {
|
||||
var text = document.getElementById('yourTextArea').value;
|
||||
var windowsText = text.replace(/\n/g, '\r\n');
|
||||
event.clipboardData.setData('text/plain', windowsText);
|
||||
});
|
||||
```
|
||||
|
||||
- **Linux:**
|
||||
- The Linux Clipboard system (a.k.a. "Selection Atoms" within the [X Consortium's Standard Inter-Client Communication Conventions Manual](http://www.x.org/docs/ICCCM/icccm.pdf)) is a complex but capable setup. However,
|
||||
for normal end users, it stinks. Flash Player's Clipboard API can either:
|
||||
1. Insert plain text into the "System Clipboard" and have it available everywhere; or
|
||||
2. Insert plain, HTML, and RTF text into the "Desktop Clipboard" but it will only be available in applications whose UI are managed by the Desktop Manager System (e.g. GNOME, etc.). This, for example, means that a user on a typical Linux configuration would not be able to paste something copied with ZeroClipboard into a terminal shell but they may still be able to paste it into OpenOffice, the browser, etc.
|
||||
|
||||
As such, the default behavior for ZeroClipboard while running on Linux is to only inject plain text into the "System Clipboard" to cover the most bases. If you want to ignore that caution and use the "Desktop Clipboard" anyway, just set the `forceEnhancedClipboard` configuration option to `true`, i.e.:
|
||||
|
||||
```js
|
||||
ZeroClipboard.config({
|
||||
forceEnhancedClipboard: true
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
[valid_ids]: http://www.w3.org/TR/html4/types.html#type-id "HTML4 specification for `ID` and `Name` tokens"
|
9
public/filemanager/scripts/zeroclipboard/docs/roadmap.md
Normal file
9
public/filemanager/scripts/zeroclipboard/docs/roadmap.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Roadmap
|
||||
|
||||
These are things that we have expressed interest in but haven't implemented yet. There is no order, if you feel like you can complete one of the tasks. Feel free to fork the project and send a pull request with the new code.
|
||||
|
||||
## HTML5 Clipboard API
|
||||
In a perfect world we wouldn't need ZeroClipboard, and the browsers would just take care of it. We would like to write ZeroClipboard to use the browser's clipboard API when available. See Issues [#171](https://github.com/zeroclipboard/zeroclipboard/issues/171) and [~~#105~~](https://github.com/zeroclipboard/zeroclipboard/issues/105).
|
||||
|
||||
## Flash Tests
|
||||
We want to setup a unit test suite for the Flash SWF and/or its underlying ActionScript files. See Issue [#43](https://github.com/zeroclipboard/zeroclipboard/issues/43).
|
32
public/filemanager/scripts/zeroclipboard/docs/security.md
Normal file
32
public/filemanager/scripts/zeroclipboard/docs/security.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Security
|
||||
|
||||
We try our best to keep ZeroClipboard secure but there are some rules that you should consider following to keep your site safe.
|
||||
|
||||
|
||||
## Existing Configuration
|
||||
|
||||
For the existing configuration options available for security, see [Configuration Options](api/ZeroClipboard.md#configuration-options).
|
||||
|
||||
|
||||
## Rules
|
||||
|
||||
Basically, if an attacker gets access to the main window/global object via an XSS exploit, it's pretty much an instant "GAME OVER" unless **ALL** of the following are true:
|
||||
1. The `ZeroClipboard` object itself is not globally accessible.
|
||||
2. The `ZeroClipboard.prototype` object itself is not globally accessible.
|
||||
3. No `ZeroClipboard` instances are globally accessible.
|
||||
4. No callback functions for dispatched ZeroClipboard events are globally accessible.
|
||||
5. If a variable is used to set the path to the SWF via `ZeroClipboard.config`, that variable must not be globally accessible.
|
||||
6. The DOM is not accessible (due to built-in support for `data-clipboard-text` and `data-clipboard-target` attributes).
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
1. Having `ZeroClipboard` instances globally accessible (versus encapsulated in a closure). This allows an attacker to manually call a client's `setText` method and inject their own text.
|
||||
2. As with all globally accessible functions in JavaScript, any globally accessible callback functions (hooked to events) can be overridden by an attacker. This isn't terribly dangerous but could be annoying.
|
||||
3. Overriding any of the `ZeroClipboard` or `ZeroClipboard.prototype` properties or methods, if globally accessible.
|
||||
4. Adding `data-clipboard-text` or `data-clipboard-target` attributes to every element in the DOM.
|
||||
|
||||
|
||||
### Responsible Disclosure
|
||||
|
||||
If you find any security holes that you believe can be patched, please submit a pull request or file an issue. We will be very appreciative!
|
29
public/filemanager/scripts/zeroclipboard/index.js
vendored
Normal file
29
public/filemanager/scripts/zeroclipboard/index.js
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
/*jshint node:true */
|
||||
|
||||
|
||||
// Module exports
|
||||
exports = module.exports = setup;
|
||||
|
||||
// Module dependencies
|
||||
var http = require("http");
|
||||
var send = require("send");
|
||||
|
||||
|
||||
var root = __dirname;
|
||||
var swf = "/ZeroClipboard.swf";
|
||||
|
||||
function setup() {
|
||||
return http.createServer(onReq);
|
||||
}
|
||||
|
||||
function onReq(req, res) {
|
||||
send(req, swf)
|
||||
.root(root)
|
||||
.on("error", onError)
|
||||
.pipe(res);
|
||||
}
|
||||
|
||||
function onError(err) {
|
||||
res.statusCode = err.status || 500;
|
||||
res.end(err.message);
|
||||
}
|
83
public/filemanager/scripts/zeroclipboard/package.json
Normal file
83
public/filemanager/scripts/zeroclipboard/package.json
Normal file
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"name": "zeroclipboard",
|
||||
"title": "ZeroClipboard",
|
||||
"version": "2.1.6",
|
||||
"description": "The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface.",
|
||||
"keywords": [
|
||||
"flash",
|
||||
"clipboard",
|
||||
"copy",
|
||||
"cut",
|
||||
"paste",
|
||||
"zclip",
|
||||
"clip",
|
||||
"clippy"
|
||||
],
|
||||
"homepage": "http://zeroclipboard.org/",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT",
|
||||
"url": "https://github.com/zeroclipboard/zeroclipboard/blob/master/LICENSE"
|
||||
}
|
||||
],
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Jon Rohan",
|
||||
"url": "http://jonrohan.me/"
|
||||
},
|
||||
{
|
||||
"name": "James M. Greene",
|
||||
"email": "james.m.greene@gmail.com",
|
||||
"url": "http://jamesgreene.net/"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zeroclipboard/zeroclipboard.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/zeroclipboard/zeroclipboard/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"send": "0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"flex-sdk": "~4.6.0-0",
|
||||
"flexpmd": "^1.3.0-1",
|
||||
"grunt": "^0.4.5",
|
||||
"grunt-chmod": "^1.0.3",
|
||||
"grunt-contrib-clean": "^0.5.0",
|
||||
"grunt-contrib-concat": "^0.4.0",
|
||||
"grunt-contrib-connect": "^0.8.0",
|
||||
"grunt-contrib-jshint": "^0.10.0",
|
||||
"grunt-contrib-uglify": "^0.5.0",
|
||||
"grunt-contrib-watch": "^0.6.1",
|
||||
"grunt-coveralls": "^0.3.0",
|
||||
"grunt-flexpmd": "^0.1.2",
|
||||
"grunt-mxmlc": "^0.5.1",
|
||||
"grunt-qunit-istanbul": "^0.4.5",
|
||||
"grunt-template": "^0.2.3",
|
||||
"jquery": "^2.1.1",
|
||||
"load-grunt-tasks": "^0.6.0",
|
||||
"qunit-composite": "^1.0.1",
|
||||
"qunitjs": "^1.14.0",
|
||||
"spm": "^3.0.1"
|
||||
},
|
||||
"main": "./dist/ZeroClipboard.js",
|
||||
"component": {
|
||||
"scripts": {
|
||||
"zeroclipboard": "./dist/ZeroClipboard.js"
|
||||
}
|
||||
},
|
||||
"spm": {
|
||||
"main": "dist/ZeroClipboard.js",
|
||||
"output": [
|
||||
"dist/ZeroClipboard.swf",
|
||||
"dist/ZeroClipboard.Core.js"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt travis --verbose",
|
||||
"postpublish": "spm publish"
|
||||
}
|
||||
}
|
@@ -0,0 +1,185 @@
|
||||
package {
|
||||
|
||||
import flash.system.Capabilities;
|
||||
import flash.system.System;
|
||||
import flash.desktop.Clipboard;
|
||||
import flash.desktop.ClipboardFormats;
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
|
||||
/**
|
||||
* An abstraction for injecting data into the user's clipboard.
|
||||
*/
|
||||
internal class ClipboardInjector {
|
||||
/**
|
||||
* Use the fancy "Desktop" clipboard for expanded text support (e.g. HTML, RTF, etc.) if not on Linux
|
||||
*/
|
||||
private var useEnhancedClipboard:Boolean = Capabilities.os.slice(0, 5).toLowerCase() !== "linux";
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
public function ClipboardInjector(forceEnhancedClipboard:Boolean = false) {
|
||||
// The JIT Compiler does not compile constructors, so any
|
||||
// cyclomatic complexity higher than 1 is discouraged.
|
||||
this.ctor(forceEnhancedClipboard);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The real constructor.
|
||||
*
|
||||
* @return `undefined`
|
||||
*/
|
||||
private function ctor(forceEnhancedClipboard:Boolean = false): void {
|
||||
// Should we use the fancy "Desktop" clipboard for expanded text support (e.g. HTML, RTF, etc.)?
|
||||
this.useEnhancedClipboard = this.useEnhancedClipboard || forceEnhancedClipboard;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inject data into the user's clipboard.
|
||||
*
|
||||
* @return A clipboard "results" object
|
||||
*/
|
||||
public function inject(
|
||||
clipData:Object // NOPMD
|
||||
): Object { // NOPMD
|
||||
var results:Object = {}; // NOPMD
|
||||
|
||||
// Set all data formats' results to `false` (failed) initially
|
||||
for (var dataFormat:String in clipData) {
|
||||
if (dataFormat && clipData.hasOwnProperty(dataFormat)) {
|
||||
results[dataFormat] = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If there is any viable data to copy...
|
||||
if (ClipboardInjector.hasData(clipData)) {
|
||||
// ...and we only need to handle plain text...
|
||||
if (!this.useEnhancedClipboard || ClipboardInjector.hasOnlyPlainText(clipData)) {
|
||||
this.injectPlainTextOnly(clipData, results);
|
||||
}
|
||||
// ...else if there is viable data to copy and we can copy enhanced formats
|
||||
else if (this.useEnhancedClipboard) {
|
||||
this.injectEnhancedData(clipData, results);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Inject plain text into the System clipboard (i.e. Flash 9+ Clipboard).
|
||||
*
|
||||
* @return `undefined`
|
||||
*/
|
||||
private function injectPlainTextOnly(
|
||||
clipData:Object, // NOPMD
|
||||
results:Object // NOPMD
|
||||
): void {
|
||||
// Linux currently doesn't use the correct clipboard buffer with the new
|
||||
// Flash 10 API, so we need to use this until we can figure out an alternative
|
||||
try {
|
||||
System.setClipboard(clipData.text);
|
||||
results.text = true;
|
||||
}
|
||||
catch (e:Error) {
|
||||
// Yes, this is already set but FlexPMD complains about empty `catch` blocks
|
||||
results.text = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inject plain text, HTML, and RTF into the Desktop clipboard (i.e. Flash 10+ Clipboard).
|
||||
*
|
||||
* @return `undefined`
|
||||
*/
|
||||
private function injectEnhancedData(
|
||||
clipData:Object, // NOPMD
|
||||
results:Object // NOPMD
|
||||
): void {
|
||||
// Clear out the clipboard before starting to copy data
|
||||
Clipboard.generalClipboard.clear();
|
||||
|
||||
//
|
||||
// Handle each data type in succession...
|
||||
//
|
||||
// Plain text
|
||||
if (typeof clipData.text === "string" && clipData.text) {
|
||||
try {
|
||||
results.text = Clipboard.generalClipboard.setData(ClipboardFormats.TEXT_FORMAT, clipData.text);
|
||||
}
|
||||
catch (e:Error) {
|
||||
results.text = false;
|
||||
}
|
||||
}
|
||||
|
||||
// HTML
|
||||
if (typeof clipData.html === "string" && clipData.html) {
|
||||
try {
|
||||
results.html = Clipboard.generalClipboard.setData(ClipboardFormats.HTML_FORMAT, clipData.html);
|
||||
}
|
||||
catch (e:Error) {
|
||||
results.html = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Rich Text (RTF)
|
||||
if (typeof clipData.rtf === "string" && clipData.rtf) {
|
||||
try {
|
||||
var bytes:ByteArray = new ByteArray();
|
||||
bytes.writeUTFBytes(clipData.rtf);
|
||||
if (bytes && bytes.length > 0) {
|
||||
results.rtf = Clipboard.generalClipboard.setData(ClipboardFormats.RICH_TEXT_FORMAT, bytes);
|
||||
}
|
||||
}
|
||||
catch (e:Error) {
|
||||
results.rtf = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if data object contains any keys with associated values that are non-empty Strings.
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
private static function hasData(
|
||||
clipData:Object // NOPMD
|
||||
): Boolean {
|
||||
return typeof clipData === "object" && clipData &&
|
||||
(
|
||||
(typeof clipData.text === "string" && clipData.text) ||
|
||||
(typeof clipData.html === "string" && clipData.html) ||
|
||||
(typeof clipData.rtf === "string" && clipData.rtf )
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if a data object's ONLY injectable data is plain text.
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
private static function hasOnlyPlainText(
|
||||
clipData:Object // NOPMD
|
||||
): Boolean {
|
||||
var hasPlainText:Boolean = false;
|
||||
var hasOtherTypes:Boolean = false;
|
||||
if (typeof clipData === "object" && clipData) {
|
||||
hasPlainText = typeof clipData.text === "string" && clipData.text;
|
||||
hasOtherTypes = (
|
||||
(typeof clipData.html === "string" && clipData.html) ||
|
||||
(typeof clipData.rtf === "string" && clipData.rtf )
|
||||
);
|
||||
}
|
||||
return !hasOtherTypes && hasPlainText;
|
||||
}
|
||||
}
|
||||
}
|
140
public/filemanager/scripts/zeroclipboard/src/flash/JsProxy.as
Normal file
140
public/filemanager/scripts/zeroclipboard/src/flash/JsProxy.as
Normal file
@@ -0,0 +1,140 @@
|
||||
package {
|
||||
|
||||
import flash.external.ExternalInterface;
|
||||
import flash.net.navigateToURL;
|
||||
import flash.net.URLRequest;
|
||||
|
||||
|
||||
/**
|
||||
* An abstraction for communicating with JavaScript from Flash.
|
||||
*/
|
||||
internal class JsProxy {
|
||||
private var hosted:Boolean = false;
|
||||
private var bidirectional:Boolean = false;
|
||||
private var disabled:Boolean = false;
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
public function JsProxy(expectedObjectId:String = null) {
|
||||
// The JIT Compiler does not compile constructors, so any
|
||||
// cyclomatic complexity higher than 1 is discouraged.
|
||||
this.ctor(expectedObjectId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The real constructor.
|
||||
*
|
||||
* @return `undefined`
|
||||
*/
|
||||
private function ctor(expectedObjectId:String = null): void {
|
||||
// Do we authoritatively know that this Flash object is hosted in a browser?
|
||||
this.hosted = ExternalInterface.available === true &&
|
||||
ExternalInterface.objectID &&
|
||||
(expectedObjectId ? (expectedObjectId === ExternalInterface.objectID) : true);
|
||||
|
||||
// Can we retrieve values from JavaScript?
|
||||
// Try this regardless of the return value of `ExternalInterface.call`.
|
||||
try {
|
||||
this.bidirectional = ExternalInterface.call("(function() { return true; })") === true;
|
||||
}
|
||||
catch (e:Error) {
|
||||
// We do NOT authoritatively know if this Flash object is hosted in a browser,
|
||||
// nor if JavaScript is disabled.
|
||||
this.bidirectional = false;
|
||||
}
|
||||
|
||||
// If hosted but cannot bidirectionally communicate with JavaScript,
|
||||
// then JavaScript is disabled on the page!
|
||||
this.disabled = this.hosted && !this.bidirectional;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Are we authoritatively certain that we can execute JavaScript bidirectionally?
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isComplete(): Boolean {
|
||||
return this.hosted && this.bidirectional;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register an ActionScript method as callable from the container's JavaScript
|
||||
*
|
||||
* This will execute the JavaScript ONLY if ExternalInterface is completely
|
||||
* available (hosted in the browser AND supporting bidirectional communication).
|
||||
*
|
||||
* @return `undefined`
|
||||
*/
|
||||
public function addCallback(functionName:String, closure:Function): void {
|
||||
if (this.isComplete()) {
|
||||
ExternalInterface.addCallback(functionName, closure);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a function expression or named function, with optional arguments,
|
||||
* and receive its return value.
|
||||
*
|
||||
* This will execute the JavaScript ONLY if ExternalInterface is completely
|
||||
* available (hosted in the browser AND supporting bidirectional communication).
|
||||
*
|
||||
* @example
|
||||
* var jsProxy:JsProxy = new JsProxy("global-zeroclipboard-flash-bridge");
|
||||
* var result:Object = jsProxy.call("ZeroClipboard.emit", [{ type: "copy" }]);
|
||||
* jsProxy.call("(function(eventObj) { return ZeroClipboard.emit(eventObj); })", [{ type: "ready"}]);
|
||||
*
|
||||
* @return `undefined`, or anything
|
||||
*/
|
||||
public function call(
|
||||
jsFuncExpr:String,
|
||||
args:Array = null
|
||||
): * { // NOPMD
|
||||
var result:* = undefined; // NOPMD
|
||||
if (jsFuncExpr && this.isComplete()) {
|
||||
if (args == null) {
|
||||
args = [];
|
||||
}
|
||||
result = ExternalInterface.call.apply(ExternalInterface, [jsFuncExpr].concat(args));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute a function expression or named function, with optional arguments.
|
||||
* No return values will ever be received.
|
||||
*
|
||||
* This will attempt to execute the JavaScript, even if ExternalInterface is
|
||||
* not available; in which case: the worst thing that can happen is that
|
||||
* the JavaScript is not executed (i.e. if JavaScript is disabled, or if
|
||||
* the SWF is not allowed to communicate with JavaScript on its host page).
|
||||
*
|
||||
* @return `undefined`
|
||||
*/
|
||||
public function send(jsFuncExpr:String, args:Array = null): void {
|
||||
if (jsFuncExpr) {
|
||||
if (this.isComplete()) {
|
||||
this.call(jsFuncExpr, args);
|
||||
}
|
||||
else if (!this.disabled) {
|
||||
if (args == null) {
|
||||
args = [];
|
||||
}
|
||||
var argsStr:String = "";
|
||||
for (var counter:int = 0; counter < args.length; counter++) {
|
||||
argsStr += JSON.stringify(args[counter]);
|
||||
if ((counter + 1) < args.length) {
|
||||
argsStr += ", ";
|
||||
}
|
||||
}
|
||||
navigateToURL(new URLRequest("javascript:" + jsFuncExpr + "(" + argsStr + ");"), "_self");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
package {
|
||||
|
||||
/**
|
||||
* Utility methods for XSS attack prevention.
|
||||
*/
|
||||
internal class XssUtils {
|
||||
|
||||
/**
|
||||
* Sanitize a string to avoid XSS vulnerabilities.
|
||||
*
|
||||
* @return an XSS safe String
|
||||
* @static
|
||||
*/
|
||||
public static function sanitizeString(dirty:String): String {
|
||||
return (typeof dirty === "string" && dirty) ? dirty.replace(/\\/g, "\\\\") : "";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sanitize the Loader parameters by filtering out all URL query parameters,
|
||||
* leaving ONLY parameters that were specified via FlashVars in the HTML
|
||||
* embedding markup.
|
||||
*
|
||||
* @return a filtered parameters object, a.k.a. FlashVars
|
||||
* @static
|
||||
*/
|
||||
public static function filterToFlashVars(
|
||||
parameters:Object // NOPMD
|
||||
): Object { // NOPMD
|
||||
//
|
||||
// TODO: Implement this for real
|
||||
// See: https://github.com/zeroclipboard/zeroclipboard/pull/336
|
||||
//
|
||||
return parameters;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,299 @@
|
||||
package {
|
||||
|
||||
import flash.display.Stage;
|
||||
import flash.display.StageAlign;
|
||||
import flash.display.StageScaleMode;
|
||||
import flash.display.StageQuality;
|
||||
import flash.display.Sprite;
|
||||
import flash.events.Event;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.system.Security;
|
||||
|
||||
|
||||
/**
|
||||
* The ZeroClipboard class creates a simple Sprite button that will put
|
||||
* text in the user's clipboard when clicked.
|
||||
*/
|
||||
[SWF(widthPercent="100%", heightPercent="100%", backgroundColor="#FFFFFF")]
|
||||
public class ZeroClipboard extends Sprite {
|
||||
|
||||
/**
|
||||
* Function through which JavaScript events are emitted. Accounts for scenarios
|
||||
* in which ZeroClipboard is used via AMD/CommonJS module loaders, too.
|
||||
*/
|
||||
private var jsEmitter:String = null;
|
||||
|
||||
/**
|
||||
* JavaScript proxy object.
|
||||
*/
|
||||
private var jsProxy:JsProxy = null;
|
||||
|
||||
/**
|
||||
* Clipboard proxy object.
|
||||
*/
|
||||
private var clipboard:ClipboardInjector = null;
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
public function ZeroClipboard() {
|
||||
// The JIT Compiler does not compile constructors, so ANY
|
||||
// cyclomatic complexity higher than 1 is discouraged.
|
||||
this.ctor();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The real constructor.
|
||||
*
|
||||
* @return `undefined`
|
||||
*/
|
||||
private function ctor(): void {
|
||||
// If the `stage` is available, begin!
|
||||
if (stage) {
|
||||
this.init();
|
||||
}
|
||||
else {
|
||||
// Otherwise, wait for the `stage`....
|
||||
this.addEventListener(Event.ADDED_TO_STAGE, this.init);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the class when the Stage is ready.
|
||||
*
|
||||
* @return `undefined`
|
||||
*/
|
||||
private function init(): void {
|
||||
// Remove the event listener, if any
|
||||
this.removeEventListener(Event.ADDED_TO_STAGE, this.init);
|
||||
|
||||
// Get the flashvars
|
||||
var flashvars:Object; // NOPMD
|
||||
flashvars = XssUtils.filterToFlashVars(this.loaderInfo.parameters);
|
||||
|
||||
// Configure the SWF object's ID
|
||||
var swfObjectId:String = "global-zeroclipboard-flash-bridge";
|
||||
if (flashvars.swfObjectId && typeof flashvars.swfObjectId === "string") {
|
||||
var swfId = XssUtils.sanitizeString(flashvars.swfObjectId);
|
||||
|
||||
// Validate the ID against the HTML4 spec for `ID` tokens.
|
||||
if (/^[A-Za-z][A-Za-z0-9_:\-\.]*$/.test(swfId)) {
|
||||
swfObjectId = swfId;
|
||||
}
|
||||
}
|
||||
|
||||
// Allow the SWF object to communicate with a page on a different origin than its own (e.g. SWF served from CDN)
|
||||
if (flashvars.trustedOrigins && typeof flashvars.trustedOrigins === "string") {
|
||||
var origins:Array = XssUtils.sanitizeString(flashvars.trustedOrigins).split(",");
|
||||
Security.allowDomain.apply(Security, origins);
|
||||
}
|
||||
|
||||
// Enable use of the fancy "Desktop" clipboard, even on Linux where it is known to suck
|
||||
var forceEnhancedClipboard:Boolean = false;
|
||||
if (flashvars.forceEnhancedClipboard === "true" || flashvars.forceEnhancedClipboard === true) {
|
||||
forceEnhancedClipboard = true;
|
||||
}
|
||||
|
||||
this.jsEmitter =
|
||||
"(function(eventObj) {\n" +
|
||||
" var objectId = '" + swfObjectId + "',\n" +
|
||||
" ZC = null,\n" +
|
||||
" swf = null;\n" +
|
||||
" if (typeof ZeroClipboard === 'function' && typeof ZeroClipboard.emit === 'function') {\n" +
|
||||
" \nZC = ZeroClipboard;\n" +
|
||||
" }\n" +
|
||||
" else {\n" +
|
||||
" swf = document[objectId] || document.getElementById(objectId);\n" +
|
||||
" if (swf && typeof swf.ZeroClipboard === 'function' && typeof swf.ZeroClipboard.emit === 'function') {\n" +
|
||||
" ZC = swf.ZeroClipboard;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" if (!ZC) {\n" +
|
||||
" throw new Error('ERROR: ZeroClipboard SWF could not locate ZeroClipboard JS object!\\n" +
|
||||
"Expected element ID: ' + objectId);\n" +
|
||||
" }\n" +
|
||||
" return ZC.emit(eventObj);\n" +
|
||||
"})";
|
||||
|
||||
// Create an invisible "button" and transparently fill the entire Stage
|
||||
var button:Sprite = this.prepareUI();
|
||||
|
||||
// Configure the clipboard injector
|
||||
this.clipboard = new ClipboardInjector(forceEnhancedClipboard);
|
||||
|
||||
// Establish a communication line with JavaScript
|
||||
this.jsProxy = new JsProxy(swfObjectId);
|
||||
|
||||
// Only proceed if this SWF is hosted in the browser as expected
|
||||
if (this.jsProxy.isComplete()) {
|
||||
|
||||
// Add the MouseEvent listeners
|
||||
this.addMouseHandlers(button);
|
||||
|
||||
// Expose the external functions
|
||||
this.jsProxy.addCallback(
|
||||
"setHandCursor",
|
||||
function(enabled:Boolean) {
|
||||
button.useHandCursor = enabled === true;
|
||||
}
|
||||
);
|
||||
|
||||
// Signal to the browser that we are ready
|
||||
this.emit("ready");
|
||||
}
|
||||
else {
|
||||
// Signal to the browser that something is wrong
|
||||
this.emit("error", {
|
||||
name: "flash-unavailable"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare the Stage and Button.
|
||||
*
|
||||
* @return Button
|
||||
*/
|
||||
private function prepareUI(): Sprite {
|
||||
// Set the stage!
|
||||
stage.align = StageAlign.TOP_LEFT;
|
||||
stage.scaleMode = StageScaleMode.EXACT_FIT;
|
||||
stage.quality = StageQuality.BEST;
|
||||
|
||||
// Create an invisible "button" and transparently fill the entire Stage
|
||||
var button:Sprite = new Sprite();
|
||||
button.graphics.beginFill(0xFFFFFF);
|
||||
button.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
|
||||
button.alpha = 0.0;
|
||||
|
||||
// Act like a button. This includes:
|
||||
// - Showing a hand cursor by default
|
||||
// - Receiving click events
|
||||
// - Receiving keypress events of space/"Enter" as click
|
||||
// events IF AND ONLY IF the Sprite is focused.
|
||||
button.buttonMode = true;
|
||||
|
||||
// Override the hand cursor default
|
||||
button.useHandCursor = false;
|
||||
|
||||
// Add the invisible "button" to the stage!
|
||||
this.addChild(button);
|
||||
|
||||
// Return the button for adding event listeners
|
||||
return button;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clears the clipboard and sets new clipboard text. It gets this from the "_clipData"
|
||||
* variable on the JavaScript side. Once the text has been placed in the clipboard, it
|
||||
* then signals to the JavaScript that it is done.
|
||||
*
|
||||
* @return `undefined`
|
||||
*/
|
||||
private function onClick(event:MouseEvent): void {
|
||||
var clipData:Object; // NOPMD
|
||||
var clipInjectSuccess:Object = {}; // NOPMD
|
||||
|
||||
// Allow for any "UI preparation" work before the "copy" event begins
|
||||
this.emit("beforecopy");
|
||||
|
||||
// Request pending clipboard data from the page
|
||||
clipData = this.emit("copy");
|
||||
|
||||
// Inject all pending data into the user's clipboard
|
||||
clipInjectSuccess = this.clipboard.inject(clipData);
|
||||
|
||||
// Compose and serialize a results object, send it back to the page
|
||||
this.emit(
|
||||
"aftercopy",
|
||||
{
|
||||
success: clipInjectSuccess,
|
||||
data: clipData
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Emit events to JavaScript.
|
||||
*
|
||||
* @return `undefined`, or the new "_clipData" object
|
||||
*/
|
||||
private function emit(
|
||||
eventType:String,
|
||||
eventObj:Object = null // NOPMD
|
||||
): Object { // NOPMD
|
||||
if (eventObj == null) {
|
||||
eventObj = {};
|
||||
}
|
||||
eventObj.type = eventType;
|
||||
|
||||
var result:Object = undefined; // NOPMD
|
||||
if (this.jsProxy.isComplete()) {
|
||||
result = this.jsProxy.call(this.jsEmitter, [eventObj]);
|
||||
}
|
||||
else {
|
||||
this.jsProxy.send(this.jsEmitter, [eventObj]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Signals to the page that a MouseEvent occurred.
|
||||
*
|
||||
* @return `undefined`
|
||||
*/
|
||||
private function onMouseEvent(event:MouseEvent): void {
|
||||
var evtData:Object = {}; // NOPMD
|
||||
|
||||
// If an event is passed in, return what modifier keys are pressed, etc.
|
||||
if (event) {
|
||||
var props:Object; // NOPMD
|
||||
props = {
|
||||
"altKey": "altKey",
|
||||
"commandKey": "metaKey",
|
||||
"controlKey": "ctrlKey",
|
||||
"shiftKey": "shiftKey",
|
||||
"clickCount": "detail",
|
||||
"movementX": "movementX",
|
||||
"movementY": "movementY",
|
||||
"stageX": "_stageX",
|
||||
"stageY": "_stageY"
|
||||
};
|
||||
|
||||
for (var prop in props) {
|
||||
if (event.hasOwnProperty(prop) && event[prop] != null) {
|
||||
evtData[props[prop]] = event[prop];
|
||||
}
|
||||
}
|
||||
evtData.type = "_" + event.type.toLowerCase();
|
||||
evtData._source = "swf";
|
||||
}
|
||||
|
||||
this.emit(evtData.type, evtData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add mouse event handlers to the button.
|
||||
*
|
||||
* @return `undefined`
|
||||
*/
|
||||
private function addMouseHandlers(button:Sprite): Sprite {
|
||||
button.addEventListener(MouseEvent.MOUSE_MOVE, this.onMouseEvent);
|
||||
button.addEventListener(MouseEvent.MOUSE_OVER, this.onMouseEvent);
|
||||
button.addEventListener(MouseEvent.MOUSE_OUT, this.onMouseEvent);
|
||||
button.addEventListener(MouseEvent.MOUSE_DOWN, this.onMouseEvent);
|
||||
button.addEventListener(MouseEvent.MOUSE_UP, this.onMouseEvent);
|
||||
button.addEventListener(MouseEvent.CLICK, this.onClick);
|
||||
button.addEventListener(MouseEvent.CLICK, this.onMouseEvent);
|
||||
return button;
|
||||
}
|
||||
}
|
||||
}
|
162
public/filemanager/scripts/zeroclipboard/src/js/client/api.js
vendored
Normal file
162
public/filemanager/scripts/zeroclipboard/src/js/client/api.js
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* Creates a new ZeroClipboard client instance.
|
||||
* Optionally, auto-`clip` an element or collection of elements.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
ZeroClipboard._createClient = function(/* elements */) {
|
||||
// Invoke the real constructor
|
||||
_clientConstructor.apply(this, _args(arguments));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Register an event listener to the client.
|
||||
*
|
||||
* @returns `this`
|
||||
*/
|
||||
ZeroClipboard.prototype.on = function(/* eventType, listener */) {
|
||||
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(/* eventType, listener */) {
|
||||
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(/* eventType */) {
|
||||
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(/* event */) {
|
||||
return _clientEmit.apply(this, _args(arguments));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Register clipboard actions for new element(s) to the client.
|
||||
*
|
||||
* @returns `this`
|
||||
*/
|
||||
ZeroClipboard.prototype.clip = function(/* elements */) {
|
||||
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(/* elements */) {
|
||||
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) {
|
||||
ZeroClipboard.setData("text/plain", text);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Stores the pending HTML text to inject into the clipboard.
|
||||
*
|
||||
* @returns `this`
|
||||
*/
|
||||
ZeroClipboard.prototype.setHtml = function(html) {
|
||||
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) {
|
||||
ZeroClipboard.setData("application/rtf", richText);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Stores the pending data to inject into the clipboard.
|
||||
*
|
||||
* @returns `this`
|
||||
*/
|
||||
ZeroClipboard.prototype.setData = function(/* format, data */) {
|
||||
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(/* format */) {
|
||||
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(/* format */) {
|
||||
return ZeroClipboard.getData.apply(this, _args(arguments));
|
||||
};
|
476
public/filemanager/scripts/zeroclipboard/src/js/client/private.js
vendored
Normal file
476
public/filemanager/scripts/zeroclipboard/src/js/client/private.js
vendored
Normal file
@@ -0,0 +1,476 @@
|
||||
/**
|
||||
* The real constructor for `ZeroClipboard` client instances.
|
||||
* @private
|
||||
*/
|
||||
var _clientConstructor = function(elements) {
|
||||
// Save a closure reference for the following event handlers
|
||||
var client = this;
|
||||
|
||||
// Assign an ID to the client instance
|
||||
client.id = "" + (_clientIdCounter++);
|
||||
|
||||
// Create the meta information store for this client
|
||||
_clientMeta[client.id] = {
|
||||
instance: client,
|
||||
elements: [],
|
||||
handlers: {}
|
||||
};
|
||||
|
||||
// If the elements argument exists, clip it
|
||||
if (elements) {
|
||||
client.clip(elements);
|
||||
}
|
||||
|
||||
// ECHO! Our client's sounding board.
|
||||
ZeroClipboard.on("*", function(event) {
|
||||
return client.emit(event);
|
||||
});
|
||||
|
||||
// Await imminent destruction...
|
||||
ZeroClipboard.on("destroy", function() {
|
||||
client.destroy();
|
||||
});
|
||||
|
||||
// Move on: embed the SWF
|
||||
ZeroClipboard.create();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The underlying implementation of `ZeroClipboard.Client.prototype.on`.
|
||||
* @private
|
||||
*/
|
||||
var _clientOn = function(eventType, listener) {
|
||||
// add user event handler for event
|
||||
var i, len, events,
|
||||
added = {},
|
||||
handlers = _clientMeta[this.id] && _clientMeta[this.id].handlers;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// The following events must be memorized and fired immediately if relevant as they only occur
|
||||
// once per Flash object load.
|
||||
|
||||
// If the SWF was already loaded, we're à gogo!
|
||||
if (added.ready && _flashState.ready) {
|
||||
this.emit({
|
||||
type: "ready",
|
||||
client: this
|
||||
});
|
||||
}
|
||||
if (added.error) {
|
||||
var errorTypes = ["disabled", "outdated", "unavailable", "deactivated", "overdue"];
|
||||
for (i = 0, len = errorTypes.length; i < len; i++) {
|
||||
if (_flashState[errorTypes[i]]) {
|
||||
this.emit({
|
||||
type: "error",
|
||||
name: "flash-" + errorTypes[i],
|
||||
client: this
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The underlying implementation of `ZeroClipboard.Client.prototype.off`.
|
||||
* @private
|
||||
*/
|
||||
var _clientOff = function(eventType, listener) {
|
||||
var i, len, foundIndex, events, perEventHandlers,
|
||||
handlers = _clientMeta[this.id] && _clientMeta[this.id].handlers;
|
||||
if (arguments.length === 0) {
|
||||
// Remove ALL of the handlers for ALL event types
|
||||
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 {
|
||||
// If no `listener` was provided, remove ALL of the handlers for this event type
|
||||
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 {
|
||||
// Make a deep copy of the handlers object
|
||||
copy = _deepCopy(handlers);
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The underlying implementation of `ZeroClipboard.Client.prototype.emit`.
|
||||
* @private
|
||||
*/
|
||||
var _clientEmit = function(event) {
|
||||
if (_clientShouldEmit.call(this, event)) {
|
||||
// Don't modify the original Event, if it is an object (as expected)
|
||||
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) {
|
||||
elements = _prepClip(elements);
|
||||
|
||||
for (var i = 0; i < elements.length ; i++) {
|
||||
if (_hasOwn.call(elements, i) && elements[i] && elements[i].nodeType === 1) {
|
||||
// If the element hasn't been clipped to ANY client yet, add a metadata ID and event handler
|
||||
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);
|
||||
}
|
||||
|
||||
// If the element hasn't been clipped to THIS client yet, add it
|
||||
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 no elements were provided, unclip ALL of this client's clipped elements
|
||||
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) {
|
||||
// If the element was clipped to THIS client yet, remove it
|
||||
arrayIndex = 0;
|
||||
while ((arrayIndex = clippedElements.indexOf(elements[i], arrayIndex)) !== -1) {
|
||||
clippedElements.splice(arrayIndex, 1);
|
||||
}
|
||||
|
||||
// If the element isn't clipped to ANY other client, remove its metadata ID and event handler
|
||||
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() {
|
||||
// Unclip all the elements
|
||||
this.unclip();
|
||||
|
||||
// Remove all event handlers
|
||||
this.off();
|
||||
|
||||
// Delete the client's metadata store
|
||||
delete _clientMeta[this.id];
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Helper functions
|
||||
//
|
||||
|
||||
/**
|
||||
* Inspect an Event to see if the Client (`this`) should honor it for emission.
|
||||
* @private
|
||||
*/
|
||||
var _clientShouldEmit = function(event) {
|
||||
// If no event is received
|
||||
if (!(event && event.type)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this event's `client` was specifically set to a client other than this client, bail out
|
||||
if (event.client && event.client !== this) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this event's targeted element(s) is/are not clipped by this client, bail out
|
||||
// unless the event's `client` was specifically set to this client.
|
||||
var clippedEls = _clientMeta[this.id] && _clientMeta[this.id].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;
|
||||
// At least one of these must be true....
|
||||
if (!(goodTarget || goodRelTarget || goodClient)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise... go for it!
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handle the actual dispatching of events to a client instance.
|
||||
*
|
||||
* @returns `this`
|
||||
* @private
|
||||
*/
|
||||
var _clientDispatchCallbacks = function(event) {
|
||||
if (!(typeof event === "object" && event && event.type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var async = _shouldPerformAsync(event);
|
||||
|
||||
// User defined handlers for events
|
||||
var wildcardTypeHandlers = (_clientMeta[this.id] && _clientMeta[this.id].handlers["*"]) || [];
|
||||
var specificTypeHandlers = (_clientMeta[this.id] && _clientMeta[this.id].handlers[event.type]) || [];
|
||||
// Execute wildcard handlers before type-specific handlers
|
||||
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 the user provided a string for their callback, grab that function
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Prepares the elements for clipping/unclipping.
|
||||
*
|
||||
* @returns An Array of elements.
|
||||
* @private
|
||||
*/
|
||||
var _prepClip = function(elements) {
|
||||
// if elements is a string, ignore it
|
||||
if (typeof elements === "string") {
|
||||
elements = [];
|
||||
}
|
||||
// if the elements isn't an array, wrap it with one
|
||||
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;
|
||||
}
|
||||
|
||||
// Create a `mouseout` handler function
|
||||
var _suppressMouseEvents = function(event) {
|
||||
if (!(event || (event = _window.event))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't allow this event to be handled by consumers unless it originated from ZeroClipboard
|
||||
if (event._source !== "js") {
|
||||
event.stopImmediatePropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
delete event._source;
|
||||
};
|
||||
|
||||
// Create a `mouseover` handler function
|
||||
var _elementMouseOver = function(event) {
|
||||
if (!(event || (event = _window.event))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't allow this event to be handled by consumers unless it originated from ZeroClipboard
|
||||
_suppressMouseEvents(event);
|
||||
|
||||
// Set this as the new currently active element
|
||||
ZeroClipboard.focus(element);
|
||||
};
|
||||
|
||||
// Add the `mouseover` handler function
|
||||
element.addEventListener("mouseover", _elementMouseOver, false);
|
||||
|
||||
// Add other mouse event handler functions
|
||||
element.addEventListener("mouseout", _suppressMouseEvents, false);
|
||||
element.addEventListener("mouseenter", _suppressMouseEvents, false);
|
||||
element.addEventListener("mouseleave", _suppressMouseEvents, false);
|
||||
element.addEventListener("mousemove", _suppressMouseEvents, false);
|
||||
|
||||
// Save these function references to a global variable
|
||||
_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;
|
||||
}
|
||||
|
||||
// Retrieve these function references from a global variable
|
||||
var mouseHandlers = _mouseHandlers[element.zcClippingId];
|
||||
if (!(typeof mouseHandlers === "object" && mouseHandlers)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the mouse event handlers
|
||||
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 these function references from a global variable
|
||||
delete _mouseHandlers[element.zcClippingId];
|
||||
};
|
60
public/filemanager/scripts/zeroclipboard/src/js/client/state.js
vendored
Normal file
60
public/filemanager/scripts/zeroclipboard/src/js/client/state.js
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 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, {
|
||||
|
||||
// Setting this to `false` would allow users to handle calling
|
||||
// `ZeroClipboard.focus(...);` themselves instead of relying on our
|
||||
// per-element `mouseover` handler.
|
||||
autoActivate: true
|
||||
|
||||
});
|
211
public/filemanager/scripts/zeroclipboard/src/js/core/api.js
vendored
Normal file
211
public/filemanager/scripts/zeroclipboard/src/js/core/api.js
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
/**
|
||||
* A shell constructor for `ZeroClipboard` client instances.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
var ZeroClipboard = function() {
|
||||
|
||||
// Ensure the constructor is invoked with the `new` keyword.
|
||||
if (!(this instanceof ZeroClipboard)) {
|
||||
return new ZeroClipboard();
|
||||
}
|
||||
|
||||
// EXTREMELY IMPORTANT!
|
||||
// Ensure the `ZeroClipboard._createClient` function is invoked if available.
|
||||
// This allows an extension point for 3rd parties to create their own
|
||||
// interpretations of what a ZeroClipboard "Client" should be like.
|
||||
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: "<%= version %>",
|
||||
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(/* options */) {
|
||||
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(/* eventType, listener */) {
|
||||
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(/* eventType, listener */) {
|
||||
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(/* eventType */) {
|
||||
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(/* event */) {
|
||||
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(/* format, data */) {
|
||||
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(/* format */) {
|
||||
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(/* format */) {
|
||||
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(/* element */) {
|
||||
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));
|
||||
};
|
1701
public/filemanager/scripts/zeroclipboard/src/js/core/private.js
vendored
Normal file
1701
public/filemanager/scripts/zeroclipboard/src/js/core/private.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
147
public/filemanager/scripts/zeroclipboard/src/js/core/state.js
vendored
Normal file
147
public/filemanager/scripts/zeroclipboard/src/js/core/state.js
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Keep track of the state of the Flash object.
|
||||
* @private
|
||||
*/
|
||||
var _flashState = {
|
||||
// Flash object reference
|
||||
bridge: null,
|
||||
|
||||
// Flash metadata
|
||||
version: "0.0.0",
|
||||
pluginType: "unknown",
|
||||
|
||||
// Flash SWF state
|
||||
disabled: null,
|
||||
outdated: null,
|
||||
unavailable: null,
|
||||
deactivated: null,
|
||||
overdue: null,
|
||||
ready: null
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The minimum Flash Player version required to use ZeroClipboard completely.
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
var _minimumFlashVersion = "11.0.0";
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
|
||||
/**
|
||||
* The `message` store for events
|
||||
* @private
|
||||
*/
|
||||
var _eventMessages = {
|
||||
"ready": "Flash communication is established",
|
||||
"error": {
|
||||
"flash-disabled": "Flash is disabled or not installed",
|
||||
"flash-outdated": "Flash is too outdated to support ZeroClipboard",
|
||||
"flash-unavailable": "Flash is unable to communicate bidirectionally with JavaScript",
|
||||
"flash-deactivated": "Flash is too outdated for your browser and/or is configured as click-to-activate",
|
||||
"flash-overdue": "Flash communication was established but NOT within the acceptable time limit"
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* ZeroClipboard configuration defaults for the Core module.
|
||||
* @private
|
||||
*/
|
||||
var _globalConfig = {
|
||||
|
||||
// SWF URL, relative to the page. Default value will be "ZeroClipboard.swf"
|
||||
// under the same path as the ZeroClipboard JS file.
|
||||
swfPath: _getDefaultSwfPath(),
|
||||
|
||||
// SWF inbound scripting policy: page domains that the SWF should trust.
|
||||
// (single string, or array of strings)
|
||||
trustedDomains: window.location.host ? [window.location.host] : [],
|
||||
|
||||
// Include a "noCache" query parameter on requests for the SWF.
|
||||
cacheBust: true,
|
||||
|
||||
// Enable use of the fancy "Desktop" clipboard, even on Linux where it is
|
||||
// known to suck.
|
||||
forceEnhancedClipboard: false,
|
||||
|
||||
// How many milliseconds to wait for the Flash SWF to load and respond before assuming that
|
||||
// Flash is deactivated (e.g. click-to-play) in the user's browser. If you don't care about
|
||||
// how long it takes to load the SWF, you can set this to `null`.
|
||||
flashLoadTimeout: 30000,
|
||||
|
||||
// Setting this to `false` would allow users to handle calling `ZeroClipboard.focus(...);`
|
||||
// themselves instead of relying on our per-element `mouseover` handler.
|
||||
autoActivate: true,
|
||||
|
||||
// Bubble synthetic events in JavaScript after they are received by the Flash object.
|
||||
bubbleEvents: true,
|
||||
|
||||
// Sets the ID of the `div` encapsulating the Flash object.
|
||||
// Value is validated against the HTML4 spec for `ID` tokens.
|
||||
containerId: "global-zeroclipboard-html-bridge",
|
||||
|
||||
// Sets the class of the `div` encapsulating the Flash object.
|
||||
containerClass: "global-zeroclipboard-container",
|
||||
|
||||
// Sets the ID and name of the Flash `object` element.
|
||||
// Value is validated against the HTML4 spec for `ID` and `Name` tokens.
|
||||
swfObjectId: "global-zeroclipboard-flash-bridge",
|
||||
|
||||
// The class used to indicate that a clipped element is being hovered over.
|
||||
hoverClass: "zeroclipboard-is-hover",
|
||||
|
||||
// The class used to indicate that a clipped element is active (is being clicked).
|
||||
activeClass: "zeroclipboard-is-active",
|
||||
|
||||
|
||||
|
||||
// Forcibly set the hand cursor ("pointer") for all clipped elements.
|
||||
// IMPORTANT: This configuration value CAN be modified while a SWF is actively embedded.
|
||||
forceHandCursor: false,
|
||||
|
||||
// Sets the title of the `div` encapsulating the Flash object.
|
||||
// IMPORTANT: This configuration value CAN be modified while a SWF is actively embedded.
|
||||
title: null,
|
||||
|
||||
// The z-index used by the Flash object.
|
||||
// Max value (32-bit): 2147483647.
|
||||
// IMPORTANT: This configuration value CAN be modified while a SWF is actively embedded.
|
||||
zIndex: 999999999
|
||||
|
||||
};
|
21
public/filemanager/scripts/zeroclipboard/src/js/end.js
vendored
Normal file
21
public/filemanager/scripts/zeroclipboard/src/js/end.js
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
|
||||
// The AMDJS logic branch is evaluated first to avoid potential confusion over
|
||||
// the CommonJS syntactical sugar offered by AMD.
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(function() {
|
||||
return ZeroClipboard;
|
||||
});
|
||||
}
|
||||
else if (typeof module === "object" && module && typeof module.exports === "object" && module.exports) {
|
||||
// CommonJS module loaders....
|
||||
module.exports = ZeroClipboard;
|
||||
}
|
||||
else {
|
||||
window.ZeroClipboard = ZeroClipboard;
|
||||
}
|
||||
|
||||
})((function() {
|
||||
/*jshint strict: false */
|
||||
return this || window;
|
||||
})());
|
317
public/filemanager/scripts/zeroclipboard/src/js/shared/private.js
vendored
Normal file
317
public/filemanager/scripts/zeroclipboard/src/js/shared/private.js
vendored
Normal file
@@ -0,0 +1,317 @@
|
||||
/**
|
||||
* 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++) {
|
||||
// Only deal with non-null/undefined values
|
||||
if ((arg = args[i]) != null) {
|
||||
// Extend the base object
|
||||
for (prop in arg) {
|
||||
if (_hasOwn.call(arg, prop)) {
|
||||
src = target[prop];
|
||||
copy = arg[prop];
|
||||
|
||||
// Prevent never-ending loops and copying `undefined` valeus
|
||||
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 not a non-null object, just return the original
|
||||
if (typeof source !== "object" || source == null) {
|
||||
copy = source;
|
||||
}
|
||||
// If an Array, iterate and recurse
|
||||
else if (typeof source.length === "number") {
|
||||
copy = [];
|
||||
for (i = 0, len = source.length; i < len; i++) {
|
||||
// Skip empty indices in sparse arrays
|
||||
if (_hasOwn.call(source, i)) {
|
||||
// Recurse
|
||||
copy[i] = _deepCopy(source[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// If an Object, enumerate and recurse
|
||||
else {
|
||||
copy = {};
|
||||
for (prop in source) {
|
||||
// Skip prototype properties
|
||||
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() {
|
||||
/*jshint newcap:false */
|
||||
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;
|
||||
|
||||
// Try to leverage the `currentScript` feature
|
||||
if (_document.currentScript && (jsPath = _document.currentScript.src)) {
|
||||
return jsPath;
|
||||
}
|
||||
|
||||
// If it it not available, then seek the script out instead...
|
||||
scripts = _document.getElementsByTagName("script");
|
||||
|
||||
// If there is only one script
|
||||
if (scripts.length === 1) {
|
||||
return scripts[0].src || undefined;
|
||||
}
|
||||
|
||||
// If `script` elements have the `readyState` property in this browser
|
||||
if ("readyState" in scripts[0]) {
|
||||
for (i = scripts.length; i--; ) {
|
||||
if (scripts[i].readyState === "interactive" && (jsPath = scripts[i].src)) {
|
||||
return jsPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the document is still parsing, then the last script in the document is the one that is currently loading
|
||||
if (_document.readyState === "loading" && (jsPath = scripts[scripts.length - 1].src)) {
|
||||
return jsPath;
|
||||
}
|
||||
|
||||
// Else take more drastic measures...
|
||||
if ((jsPath = _getCurrentScriptUrlFromError())) {
|
||||
return jsPath;
|
||||
}
|
||||
|
||||
// Otherwise we cannot reliably know which exact script is executing....
|
||||
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");
|
||||
|
||||
// If every `script` has a `src` attribute AND they all come from the same directory
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise we cannot reliably know what script is executing....
|
||||
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";
|
||||
};
|
41
public/filemanager/scripts/zeroclipboard/src/js/shared/state.js
vendored
Normal file
41
public/filemanager/scripts/zeroclipboard/src/js/shared/state.js
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
/*jshint -W079 */
|
||||
|
||||
/**
|
||||
* 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,
|
||||
_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,
|
||||
_round = _window.Math.round,
|
||||
_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;
|
||||
};
|
||||
// For Polymer
|
||||
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) {
|
||||
// Some unreliable `window.unwrap` function is exposed
|
||||
}
|
||||
}
|
||||
return unwrapper;
|
||||
})();
|
2
public/filemanager/scripts/zeroclipboard/src/js/start.js
vendored
Normal file
2
public/filemanager/scripts/zeroclipboard/src/js/start.js
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
(function(window, undefined) {
|
||||
"use strict";
|
@@ -0,0 +1,8 @@
|
||||
The MIT License (MIT)
|
||||
Copyright (c) <%= grunt.template.today("yyyy") %> <%= _.pluck(contributors, "name").join(", ") %>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "<%= name %>",
|
||||
"description": "<%= description %>",
|
||||
"version": "<%= version %>",
|
||||
"main": ["./dist/ZeroClipboard.js", "./dist/ZeroClipboard.swf"],
|
||||
"keywords": <%= JSON.stringify(keywords) %>,
|
||||
"license": "<%= licenses[0].url %>",
|
||||
"authors": <%= JSON.stringify(contributors) %>,
|
||||
"homepage": "<%= homepage %>",
|
||||
"repository": <%= JSON.stringify(repository) %>,
|
||||
"location": "<%= repository.url.replace(/^https:\/\//, "git://") %>",
|
||||
"ignore": [
|
||||
"*",
|
||||
"!/bower.json",
|
||||
"!/dist/**"
|
||||
]
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "<%= name %>/<%= name %>",
|
||||
"description": "<%= description %>",
|
||||
"version": "<%= version %>",
|
||||
"type": "library",
|
||||
"keywords": <%= JSON.stringify(keywords) %>,
|
||||
"license": "<%= licenses[0].type %>",
|
||||
"authors": <%= JSON.stringify(_.filter(_.map(contributors, function(c) {
|
||||
var a;
|
||||
/* Does not currently support the NPM package.json string format (as opposed to object format) for "people" types */
|
||||
if (c && typeof c === "object") {
|
||||
/* The `name` property is required */
|
||||
if (c.name) {
|
||||
a = {};
|
||||
a.name = c.name;
|
||||
|
||||
if (c.email) {
|
||||
a.email = c.email;
|
||||
}
|
||||
if (c.url) {
|
||||
a.homepage = c.url;
|
||||
}
|
||||
a.role = c.role || "Developer";
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}), function(a) { return !!a; })) %>,
|
||||
"homepage": "<%= homepage %>",
|
||||
"support": {
|
||||
"source": "<%= repository.url %>",
|
||||
"issues": "<%= bugs.url %>"
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
/*!
|
||||
* <%= title || name %>
|
||||
* <%= description %>
|
||||
* Copyright (c) <%= grunt.template.today("yyyy") %> <%= _.pluck(contributors, "name").join(", ") %>
|
||||
* Licensed <%= _.pluck(licenses, "type").join(", ") %>
|
||||
* <%= homepage %>
|
||||
* v<%= version %>
|
||||
*/
|
68
public/filemanager/scripts/zeroclipboard/test/.jshintrc
Normal file
68
public/filemanager/scripts/zeroclipboard/test/.jshintrc
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
/* 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": 2,
|
||||
"maxdepth": 3,
|
||||
"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": {
|
||||
"$": false,
|
||||
"QUnit": false
|
||||
}
|
||||
}
|
67
public/filemanager/scripts/zeroclipboard/test/built/ZeroClipboard.Core.tests.js
vendored
Normal file
67
public/filemanager/scripts/zeroclipboard/test/built/ZeroClipboard.Core.tests.js
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
/*global ZeroClipboard */
|
||||
|
||||
(function(module, test) {
|
||||
"use strict";
|
||||
|
||||
// Helper functions
|
||||
var TestUtils = {
|
||||
getHtmlBridge: function() {
|
||||
return document.getElementById(ZeroClipboard.config("containerId"));
|
||||
}
|
||||
};
|
||||
|
||||
var originalConfig, originalFlashDetect;
|
||||
|
||||
|
||||
module("ZeroClipboard.Core.js (built) unit tests", {
|
||||
setup: function() {
|
||||
// Store
|
||||
originalConfig = ZeroClipboard.config();
|
||||
originalFlashDetect = ZeroClipboard.isFlashUnusable;
|
||||
// Modify
|
||||
ZeroClipboard.isFlashUnusable = function() {
|
||||
return false;
|
||||
};
|
||||
},
|
||||
teardown: function() {
|
||||
// Restore
|
||||
ZeroClipboard.destroy();
|
||||
ZeroClipboard.config(originalConfig);
|
||||
ZeroClipboard.isFlashUnusable = originalFlashDetect;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
test("`swfPath` finds the expected default URL", function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
// Assert, act, assert
|
||||
var rootOrigin = window.location.protocol + "//" + window.location.host + "/";
|
||||
var indexOfTest = window.location.pathname.toLowerCase().indexOf("/test/");
|
||||
var rootDir = window.location.pathname.slice(1, indexOfTest + 1);
|
||||
var rootPath = rootOrigin + rootDir;
|
||||
//var zcJsUrl = rootPath + "dist/ZeroClipboard.Core.js";
|
||||
var swfPathBasedOnZeroClipboardJsPath = rootPath + "dist/ZeroClipboard.swf";
|
||||
|
||||
// Test that the client has the expected default URL [even if it's not correct]
|
||||
assert.strictEqual(ZeroClipboard.config("swfPath"), swfPathBasedOnZeroClipboardJsPath);
|
||||
});
|
||||
|
||||
|
||||
test("`destroy` destroys the bridge", function(assert) {
|
||||
assert.expect(3);
|
||||
|
||||
// Arrange
|
||||
ZeroClipboard.isFlashUnusable = function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Assert, arrange, assert, act, assert
|
||||
assert.equal(TestUtils.getHtmlBridge(), null, "The bridge does not exist before creating a client");
|
||||
ZeroClipboard.create();
|
||||
assert.notEqual(TestUtils.getHtmlBridge(), null, "The bridge does exist after creating a client");
|
||||
ZeroClipboard.destroy();
|
||||
assert.equal(TestUtils.getHtmlBridge(), null, "The bridge does not exist after calling `destroy`");
|
||||
});
|
||||
|
||||
})(QUnit.module, QUnit.test);
|
@@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>ZeroClipboard.Core.js unit tests</title>
|
||||
<link rel="stylesheet" href="../../node_modules/qunitjs/qunit/qunit.css">
|
||||
<script src="../../node_modules/qunitjs/qunit/qunit.js"></script>
|
||||
<script>
|
||||
// Polyfill in future functionality: https://github.com/jquery/qunit/issues/490
|
||||
if (!QUnit.assert.expect) {
|
||||
QUnit.assert.expect = QUnit.expect;
|
||||
}
|
||||
|
||||
// Require `expect` calls
|
||||
QUnit.config.requireExpects = true;
|
||||
|
||||
// Prevent against Firefox/Firebug failing the global pollution check
|
||||
var getInterface = null;
|
||||
|
||||
// Prevent against failing the global pollution check in all browsers other than IE
|
||||
if (typeof window.ActiveXObject === "undefined") {
|
||||
window.ActiveXObject = null;
|
||||
}
|
||||
|
||||
// Prevent against Flash's ExternalInterface failing the global pollution check (seems to be only in IE < 11)
|
||||
var __flash__arrayToXML = null,
|
||||
__flash__argumentsToXML = null,
|
||||
__flash__objectToXML = null,
|
||||
__flash__escapeXML = null,
|
||||
__flash__toXML = null,
|
||||
__flash__addCallback = null,
|
||||
__flash__removeCallback = null,
|
||||
__flash__request = null;
|
||||
</script>
|
||||
<script src="../../dist/ZeroClipboard.Core.js"></script>
|
||||
<script src="../../node_modules/jquery/dist/jquery.js"></script>
|
||||
<script src="ZeroClipboard.Core.tests.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture"></div>
|
||||
</body>
|
||||
</html>
|
228
public/filemanager/scripts/zeroclipboard/test/built/ZeroClipboard.tests.js
vendored
Normal file
228
public/filemanager/scripts/zeroclipboard/test/built/ZeroClipboard.tests.js
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
/*global ZeroClipboard */
|
||||
|
||||
(function(module, test) {
|
||||
"use strict";
|
||||
|
||||
var originalConfig, originalFlashDetect;
|
||||
|
||||
// Helper functions
|
||||
var TestUtils = {
|
||||
getHtmlBridge: function() {
|
||||
return document.getElementById(ZeroClipboard.config("containerId"));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
module("ZeroClipboard.js (built) unit tests - Core", {
|
||||
setup: function() {
|
||||
// Store
|
||||
originalConfig = ZeroClipboard.config();
|
||||
originalFlashDetect = ZeroClipboard.isFlashUnusable;
|
||||
// Modify
|
||||
ZeroClipboard.isFlashUnusable = function() {
|
||||
return false;
|
||||
};
|
||||
ZeroClipboard.config({ swfPath: originalConfig.swfPath.replace(/\/(?:src|test)\/.*$/i, "/dist/ZeroClipboard.swf") });
|
||||
},
|
||||
teardown: function() {
|
||||
// Restore
|
||||
ZeroClipboard.destroy();
|
||||
ZeroClipboard.config(originalConfig);
|
||||
ZeroClipboard.isFlashUnusable = originalFlashDetect;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
test("`swfPath` finds the expected default URL", function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
// Assert, act, assert
|
||||
var rootOrigin = window.location.protocol + "//" + window.location.host + "/";
|
||||
var indexOfTest = window.location.pathname.toLowerCase().indexOf("/test/");
|
||||
var rootDir = window.location.pathname.slice(1, indexOfTest + 1);
|
||||
var rootPath = rootOrigin + rootDir;
|
||||
//var zcJsUrl = rootPath + "dist/ZeroClipboard.js";
|
||||
var swfPathBasedOnZeroClipboardJsPath = rootPath + "dist/ZeroClipboard.swf";
|
||||
|
||||
// Test that the client has the expected default URL [even if it's not correct]
|
||||
assert.strictEqual(ZeroClipboard.config("swfPath"), swfPathBasedOnZeroClipboardJsPath);
|
||||
});
|
||||
|
||||
|
||||
test("`destroy` destroys the bridge", function(assert) {
|
||||
assert.expect(3);
|
||||
|
||||
// Arrange
|
||||
ZeroClipboard.isFlashUnusable = function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Assert, arrange, assert, act, assert
|
||||
assert.equal(TestUtils.getHtmlBridge(), null, "The bridge does not exist before creating a client");
|
||||
/*jshint nonew:false */
|
||||
new ZeroClipboard();
|
||||
assert.notEqual(TestUtils.getHtmlBridge(), null, "The bridge does exist after creating a client");
|
||||
ZeroClipboard.destroy();
|
||||
assert.equal(TestUtils.getHtmlBridge(), null, "The bridge does not exist after calling `destroy`");
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
module("ZeroClipboard.js (built) unit tests - Client", {
|
||||
setup: function() {
|
||||
// Store
|
||||
originalConfig = ZeroClipboard.config();
|
||||
originalFlashDetect = ZeroClipboard.isFlashUnusable;
|
||||
// Modify
|
||||
ZeroClipboard.isFlashUnusable = function() {
|
||||
return false;
|
||||
};
|
||||
ZeroClipboard.config({ swfPath: originalConfig.swfPath.replace(/\/(?:src|test)\/.*$/i, "/dist/ZeroClipboard.swf") });
|
||||
},
|
||||
teardown: function() {
|
||||
// Restore
|
||||
ZeroClipboard.destroy();
|
||||
ZeroClipboard.config(originalConfig);
|
||||
ZeroClipboard.isFlashUnusable = originalFlashDetect;
|
||||
}
|
||||
});
|
||||
|
||||
test("`ZeroClipboard` exists", function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
// Arrange -> N/A
|
||||
|
||||
// Act -> N/A
|
||||
|
||||
// Assert
|
||||
assert.ok(ZeroClipboard);
|
||||
});
|
||||
|
||||
test("Client is created properly", function(assert) {
|
||||
assert.expect(2);
|
||||
|
||||
// Arrange & Act
|
||||
var client = new ZeroClipboard();
|
||||
|
||||
// Assert
|
||||
assert.ok(client);
|
||||
assert.ok(client.id);
|
||||
});
|
||||
|
||||
test("Client without selector doesn't have elements", function(assert) {
|
||||
assert.expect(2);
|
||||
|
||||
// Arrange & Act
|
||||
var client = new ZeroClipboard();
|
||||
|
||||
// Assert
|
||||
assert.ok(client);
|
||||
assert.deepEqual(client.elements(), []);
|
||||
});
|
||||
|
||||
test("Object has a title", function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
// Arrange
|
||||
var client = new ZeroClipboard();
|
||||
var currentEl = document.getElementById("d_clip_button");
|
||||
|
||||
// Act
|
||||
client.clip(currentEl);
|
||||
ZeroClipboard.activate(currentEl);
|
||||
|
||||
// Assert
|
||||
assert.strictEqual(TestUtils.getHtmlBridge().getAttribute("title"), "Click me to copy to clipboard.");
|
||||
|
||||
// Revert
|
||||
ZeroClipboard.deactivate();
|
||||
});
|
||||
|
||||
test("Object has no title", function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
// Arrange
|
||||
var client = new ZeroClipboard();
|
||||
var currentEl = document.getElementById("d_clip_button_no_title");
|
||||
|
||||
// Act
|
||||
client.clip(currentEl);
|
||||
ZeroClipboard.activate(currentEl);
|
||||
|
||||
// Assert
|
||||
assert.ok(!TestUtils.getHtmlBridge().getAttribute("title"));
|
||||
});
|
||||
|
||||
test("Object doesn't have data-clipboard-text", function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
// Arrange
|
||||
var client = new ZeroClipboard();
|
||||
var currentEl = document.getElementById("d_clip_button_no_text");
|
||||
|
||||
// Act
|
||||
client.clip(currentEl);
|
||||
ZeroClipboard.activate(currentEl);
|
||||
|
||||
// Assert
|
||||
assert.ok(!TestUtils.getHtmlBridge().getAttribute("data-clipboard-text"));
|
||||
});
|
||||
|
||||
test("New client is not the same client (no singleton) but does share the same bridge", function(assert) {
|
||||
assert.expect(6);
|
||||
|
||||
// Assert, arrange, assert, act, assert
|
||||
var containerClass = "." + ZeroClipboard.config("containerClass");
|
||||
assert.strictEqual($(containerClass).length, 0);
|
||||
var client1 = new ZeroClipboard();
|
||||
assert.ok(client1.id);
|
||||
assert.strictEqual($(containerClass).length, 1);
|
||||
var client2 = new ZeroClipboard();
|
||||
assert.strictEqual($(containerClass).length, 1);
|
||||
assert.notEqual(client2.id, client1.id);
|
||||
assert.notEqual(client2, client1);
|
||||
});
|
||||
|
||||
test("Calculations based on borderWidth never return NaN", function(assert) {
|
||||
assert.expect(4);
|
||||
|
||||
// Arrange
|
||||
var client = new ZeroClipboard();
|
||||
var currentEl = document.getElementById("d_clip_button");
|
||||
|
||||
// Act
|
||||
client.clip(currentEl);
|
||||
ZeroClipboard.activate(currentEl);
|
||||
|
||||
// Assert
|
||||
var htmlBridge = TestUtils.getHtmlBridge();
|
||||
assert.strictEqual(/^-?[0-9\.]+px$/.test(htmlBridge.style.top), true);
|
||||
assert.strictEqual(/^-?[0-9\.]+px$/.test(htmlBridge.style.left), true);
|
||||
assert.strictEqual(/^-?[0-9\.]+px$/.test(htmlBridge.style.width), true);
|
||||
assert.strictEqual(/^-?[0-9\.]+px$/.test(htmlBridge.style.height), true);
|
||||
});
|
||||
|
||||
test("No more client singleton!", function(assert) {
|
||||
assert.expect(7);
|
||||
|
||||
// Arrange
|
||||
ZeroClipboard.isFlashUnusable = function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Assert, arrange, assert, act, assert
|
||||
assert.ok(!ZeroClipboard.prototype._singleton, "The client singleton does not exist on the prototype before creating a client");
|
||||
var client1 = new ZeroClipboard();
|
||||
assert.ok(!ZeroClipboard.prototype._singleton, "The client singleton does not exist on the prototype after creating a client");
|
||||
assert.ok(!client1._singleton, "The client singleton does not exist on the client instance after creating a client");
|
||||
var client2 = new ZeroClipboard();
|
||||
assert.ok(!ZeroClipboard.prototype._singleton, "The client singleton does not exist on the prototype after creating a second client");
|
||||
assert.ok(!client1._singleton, "The client singleton does not exist on the first client instance after creating a second client");
|
||||
assert.ok(!client2._singleton, "The client singleton does not exist on the second client instance after creating a second client");
|
||||
ZeroClipboard.destroy();
|
||||
assert.ok(!ZeroClipboard.prototype._singleton, "The client singleton does not exist on the prototype after calling `destroy`");
|
||||
});
|
||||
|
||||
|
||||
})(QUnit.module, QUnit.test);
|
@@ -0,0 +1,73 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>ZeroClipboard.js unit tests</title>
|
||||
<link rel="stylesheet" href="../../node_modules/qunitjs/qunit/qunit.css">
|
||||
<script src="../../node_modules/qunitjs/qunit/qunit.js"></script>
|
||||
<script>
|
||||
// Polyfill in future functionality: https://github.com/jquery/qunit/issues/490
|
||||
if (!QUnit.assert.expect) {
|
||||
QUnit.assert.expect = QUnit.expect;
|
||||
}
|
||||
|
||||
// Require `expect` calls
|
||||
QUnit.config.requireExpects = true;
|
||||
|
||||
// Prevent against Firefox/Firebug failing the global pollution check
|
||||
var getInterface = null;
|
||||
|
||||
// Prevent against failing the global pollution check in all browsers other than IE
|
||||
if (typeof window.ActiveXObject === "undefined") {
|
||||
window.ActiveXObject = null;
|
||||
}
|
||||
|
||||
// Prevent against Flash's ExternalInterface failing the global pollution check (seems to be only in IE < 11)
|
||||
var __flash__arrayToXML = null,
|
||||
__flash__argumentsToXML = null,
|
||||
__flash__objectToXML = null,
|
||||
__flash__escapeXML = null,
|
||||
__flash__toXML = null,
|
||||
__flash__addCallback = null,
|
||||
__flash__removeCallback = null,
|
||||
__flash__request = null;
|
||||
</script>
|
||||
<script src="../../dist/ZeroClipboard.js"></script>
|
||||
<script src="../../node_modules/jquery/dist/jquery.js"></script>
|
||||
<script src="ZeroClipboard.tests.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture">
|
||||
<p>
|
||||
<button id="d_clip_button" class="my_clip_button" title="Click me to copy to clipboard." data-clipboard-text="Copy me!"><b>Copy To Clipboard...</b></button>
|
||||
</p>
|
||||
<p>
|
||||
<button id="d_clip_button_no_title" class="my_clip_button" data-clipboard-text="Copy me!"><b>Copy To Clipboard...</b></button>
|
||||
</p>
|
||||
<p>
|
||||
<button id="d_clip_button_no_text" class="my_clip_button"><b>Copy To Clipboard...</b></button>
|
||||
</p>
|
||||
<p>
|
||||
<button id="d_clip_button_input_text" class="my_clip_button" data-clipboard-target="clipboard_text"><b>Copy To Clipboard...</b></button>
|
||||
</p>
|
||||
<p>
|
||||
<button id="d_clip_button_textarea_text" class="my_clip_button" data-clipboard-target="clipboard_textarea"><b>Copy To Clipboard...</b></button>
|
||||
</p>
|
||||
<button id="d_clip_button_pre_text" class="my_clip_button" data-clipboard-target="clipboard_pre"><b>Copy To Clipboard...</b></button>
|
||||
<input type="text" id="clipboard_text" value="Clipboard Text"/>
|
||||
<textarea id="clipboard_textarea">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</textarea>
|
||||
<pre id="clipboard_pre">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</pre>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
1132
public/filemanager/scripts/zeroclipboard/test/client/api.tests.js
vendored
Normal file
1132
public/filemanager/scripts/zeroclipboard/test/client/api.tests.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,83 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>ZeroClipboard unit tests: client/api.js</title>
|
||||
<link rel="stylesheet" href="../../node_modules/qunitjs/qunit/qunit.css">
|
||||
<script src="../../node_modules/qunitjs/qunit/qunit.js"></script>
|
||||
<script>
|
||||
// Polyfill in future functionality: https://github.com/jquery/qunit/issues/490
|
||||
if (!QUnit.assert.expect) {
|
||||
QUnit.assert.expect = QUnit.expect;
|
||||
}
|
||||
|
||||
// Require `expect` calls
|
||||
QUnit.config.requireExpects = true;
|
||||
|
||||
// Prevent against Firefox/Firebug failing the global pollution check
|
||||
var getInterface = null;
|
||||
|
||||
// Prevent against failing the global pollution check in all browsers other than IE
|
||||
if (typeof window.ActiveXObject === "undefined") {
|
||||
window.ActiveXObject = null;
|
||||
}
|
||||
|
||||
// Prevent against Flash's ExternalInterface failing the global pollution check (seems to be only in IE < 11)
|
||||
var __flash__arrayToXML = null,
|
||||
__flash__argumentsToXML = null,
|
||||
__flash__objectToXML = null,
|
||||
__flash__escapeXML = null,
|
||||
__flash__toXML = null,
|
||||
__flash__addCallback = null,
|
||||
__flash__removeCallback = null,
|
||||
__flash__request = null;
|
||||
</script>
|
||||
<script src="../../src/js/shared/state.js"></script>
|
||||
<script src="../../src/js/shared/private.js"></script>
|
||||
<script src="../../src/js/core/state.js"></script>
|
||||
<script src="../../src/js/core/private.js"></script>
|
||||
<script src="../../src/js/core/api.js"></script>
|
||||
<script src="../../src/js/client/state.js"></script>
|
||||
<script src="../../src/js/client/private.js"></script>
|
||||
<script src="../../src/js/client/api.js"></script>
|
||||
<script src="../../node_modules/jquery/dist/jquery.js"></script>
|
||||
<script src="api.tests.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture">
|
||||
<p>
|
||||
<button id="d_clip_button" class="my_clip_button" title="Click me to copy to clipboard." data-clipboard-text="Copy me!"><b>Copy To Clipboard...</b></button>
|
||||
</p>
|
||||
<p>
|
||||
<button id="d_clip_button2" class="my_clip_button" title="Click me to copy to clipboard.2" data-clipboard-text="Copy me!"><b>Copy To Clipboard...</b></button>
|
||||
</p>
|
||||
<p>
|
||||
<button id="d_clip_button3" class="my_clip_button" title="Click me to copy to clipboard.3" data-clipboard-text="Copy me!"><b>Copy To Clipboard...</b></button>
|
||||
</p>
|
||||
<p>
|
||||
<button id="d_clip_button_no_text" class="my_clip_button"><b>Copy To Clipboard...</b></button>
|
||||
</p>
|
||||
<p>
|
||||
<button id="d_clip_button_input_text" class="my_clip_button" data-clipboard-target="clipboard_text"><b>Copy To Clipboard...</b></button>
|
||||
</p>
|
||||
<p>
|
||||
<button id="d_clip_button_textarea_text" class="my_clip_button" data-clipboard-target="clipboard_textarea"><b>Copy To Clipboard...</b></button>
|
||||
</p>
|
||||
<button id="d_clip_button_pre_text" class="my_clip_button" data-clipboard-target="clipboard_pre"><b>Copy To Clipboard...</b></button>
|
||||
<input type="text" id="clipboard_text" value="Clipboard Text"/>
|
||||
<textarea id="clipboard_textarea">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</textarea>
|
||||
<pre id="clipboard_pre">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</pre>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
40
public/filemanager/scripts/zeroclipboard/test/client/private.tests.js
vendored
Normal file
40
public/filemanager/scripts/zeroclipboard/test/client/private.tests.js
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/*global ZeroClipboard, _clientConstructor, _clientClip, _clientShouldEmit */
|
||||
|
||||
(function(module, test) {
|
||||
"use strict";
|
||||
|
||||
module("client/private.js unit tests");
|
||||
|
||||
test("`_clientShouldEmit` works", function(assert) {
|
||||
assert.expect(9);
|
||||
|
||||
// Arrange
|
||||
var currentEl = document.getElementById("d_clip_button");
|
||||
var client = new ZeroClipboard();
|
||||
_clientConstructor.call(client);
|
||||
|
||||
// Act
|
||||
var actual1 = _clientShouldEmit.call(client, null);
|
||||
var actual2 = _clientShouldEmit.call(client, {});
|
||||
var actual3 = _clientShouldEmit.call(client, { type: "beforecopy", client: {} });
|
||||
var actual4 = _clientShouldEmit.call(client, { type: "beforecopy", target: {} });
|
||||
_clientClip.call(client, currentEl);
|
||||
var actual5 = _clientShouldEmit.call(client, { type: "beforecopy", target: {}, relatedTarget: {} });
|
||||
var actual6 = _clientShouldEmit.call(client, { type: "beforecopy", client: client });
|
||||
var actual7 = _clientShouldEmit.call(client, { type: "beforecopy", target: null });
|
||||
var actual8 = _clientShouldEmit.call(client, { type: "beforecopy", target: currentEl });
|
||||
var actual9 = _clientShouldEmit.call(client, { type: "beforecopy", relatedTarget: currentEl });
|
||||
|
||||
// Assert
|
||||
assert.strictEqual(actual1, false, "Non-event returns `false`");
|
||||
assert.strictEqual(actual2, false, "Event without `type` returns `false`");
|
||||
assert.strictEqual(actual3, false, "Event with non-matching `client` returns `false`");
|
||||
assert.strictEqual(actual4, false, "Event with non-clipped `target` returns `false`");
|
||||
assert.strictEqual(actual5, false, "Event with non-clipped `relatedTarget` returns `false`");
|
||||
assert.strictEqual(actual6, true, "Event with matching `client` returns `true`");
|
||||
assert.strictEqual(actual7, true, "Event with `target` of `null` returns `true`");
|
||||
assert.strictEqual(actual8, true, "Event with clipped `target` returns `true`");
|
||||
assert.strictEqual(actual9, true, "Event with clipped `relatedTarget` returns `true`");
|
||||
});
|
||||
|
||||
})(QUnit.module, QUnit.test);
|
@@ -0,0 +1,53 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>ZeroClipboard unit tests: client/private.js</title>
|
||||
<link rel="stylesheet" href="../../node_modules/qunitjs/qunit/qunit.css">
|
||||
<script src="../../node_modules/qunitjs/qunit/qunit.js"></script>
|
||||
<script>
|
||||
// Polyfill in future functionality: https://github.com/jquery/qunit/issues/490
|
||||
if (!QUnit.assert.expect) {
|
||||
QUnit.assert.expect = QUnit.expect;
|
||||
}
|
||||
|
||||
// Require `expect` calls
|
||||
QUnit.config.requireExpects = true;
|
||||
|
||||
// Prevent against Firefox/Firebug failing the global pollution check
|
||||
var getInterface = null;
|
||||
|
||||
// Prevent against failing the global pollution check in all browsers other than IE
|
||||
if (typeof window.ActiveXObject === "undefined") {
|
||||
window.ActiveXObject = null;
|
||||
}
|
||||
|
||||
// Prevent against Flash's ExternalInterface failing the global pollution check (seems to be only in IE < 11)
|
||||
var __flash__arrayToXML = null,
|
||||
__flash__argumentsToXML = null,
|
||||
__flash__objectToXML = null,
|
||||
__flash__escapeXML = null,
|
||||
__flash__toXML = null,
|
||||
__flash__addCallback = null,
|
||||
__flash__removeCallback = null,
|
||||
__flash__request = null;
|
||||
</script>
|
||||
<script src="../../src/js/shared/state.js"></script>
|
||||
<script src="../../src/js/shared/private.js"></script>
|
||||
<script src="../../src/js/core/state.js"></script>
|
||||
<script src="../../src/js/core/private.js"></script>
|
||||
<script src="../../src/js/core/api.js"></script>
|
||||
<script src="../../src/js/client/state.js"></script>
|
||||
<script src="../../src/js/client/private.js"></script>
|
||||
<script src="../../node_modules/jquery/dist/jquery.js"></script>
|
||||
<script src="private.tests.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture">
|
||||
<p>
|
||||
<button id="d_clip_button" class="my_clip_button" title="Click me to copy to clipboard." data-clipboard-text="Copy me!"><b>Copy To Clipboard...</b></button>
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
441
public/filemanager/scripts/zeroclipboard/test/core/api.tests.js
vendored
Normal file
441
public/filemanager/scripts/zeroclipboard/test/core/api.tests.js
vendored
Normal file
@@ -0,0 +1,441 @@
|
||||
/*global ZeroClipboard, _globalConfig:true, _flashState, _clipData, _clipDataFormatMap, _deleteOwnProperties */
|
||||
|
||||
(function(module, test) {
|
||||
"use strict";
|
||||
|
||||
// Helper functions
|
||||
var TestUtils = {
|
||||
getHtmlBridge: function() {
|
||||
return document.getElementById("global-zeroclipboard-html-bridge");
|
||||
}
|
||||
};
|
||||
|
||||
var originalConfig, originalFlashDetect;
|
||||
|
||||
|
||||
module("core/api.js unit tests - state");
|
||||
|
||||
|
||||
test("`state` produces expected result", function(assert) {
|
||||
assert.expect(8);
|
||||
|
||||
// Act
|
||||
var result = ZeroClipboard.state();
|
||||
|
||||
// Assert
|
||||
assert.deepEqual(Object.keys(result), ["browser", "flash", "zeroclipboard"], "Has all expected keys");
|
||||
assert.strictEqual(typeof result.browser, "object", ".browser is an object");
|
||||
assert.notStrictEqual(result.browser, null, ".browser is a non-null object");
|
||||
assert.strictEqual(typeof result.flash, "object", ".flash is an object");
|
||||
assert.notStrictEqual(result.flash, null, ".flash is a non-null object");
|
||||
assert.strictEqual(typeof result.zeroclipboard, "object", ".zeroclipboard is an object");
|
||||
assert.notStrictEqual(result.zeroclipboard, null, ".zeroclipboard is a non-null object");
|
||||
assert.deepEqual(Object.keys(result.zeroclipboard), ["version", "config"], ".zeroclipboard has all expected keys");
|
||||
});
|
||||
|
||||
|
||||
module("core/api.js unit tests - config", {
|
||||
setup: function() {
|
||||
originalConfig = ZeroClipboard.config();
|
||||
},
|
||||
teardown: function() {
|
||||
_globalConfig = originalConfig;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
test("`swfPath` finds the expected default URL", function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
// Assert, act, assert
|
||||
var rootOrigin = window.location.protocol + "//" + window.location.host + "/";
|
||||
var indexOfTest = window.location.pathname.toLowerCase().indexOf("/test/");
|
||||
var rootDir = window.location.pathname.slice(1, indexOfTest + 1);
|
||||
var rootPath = rootOrigin + rootDir;
|
||||
//var stateJsUrl = rootPath + "src/js/core/state.js";
|
||||
// This is, for the record, a totally incorrect path due to being the development
|
||||
// file structure but it IS the correct URL based on calculated assumption of using
|
||||
// the built distributable versions of the library
|
||||
var swfPathBasedOnStateJsPath = rootPath + "src/js/core/ZeroClipboard.swf";
|
||||
|
||||
// Test that the client has the expected default URL [even if it's not correct]
|
||||
assert.strictEqual(ZeroClipboard.config("swfPath"), swfPathBasedOnStateJsPath);
|
||||
});
|
||||
|
||||
|
||||
test("Changing `trustedDomains` works", function(assert) {
|
||||
assert.expect(5);
|
||||
|
||||
// Arrange
|
||||
var currentHost = window.location.host;
|
||||
var originalValue = currentHost ? [currentHost] : [];
|
||||
var updatedValue = currentHost ? [currentHost, "otherDomain.com"] : ["otherDomain.com"];
|
||||
|
||||
// Assert, act, assert
|
||||
// Test that the client has the default value
|
||||
assert.deepEqual(ZeroClipboard.config("trustedDomains"), originalValue);
|
||||
assert.deepEqual(ZeroClipboard.config().trustedDomains, originalValue);
|
||||
// Change the value
|
||||
var updatedConfig = ZeroClipboard.config({ trustedDomains: updatedValue });
|
||||
// Test that the client has the changed value
|
||||
assert.deepEqual(updatedConfig.trustedDomains, updatedValue);
|
||||
assert.deepEqual(ZeroClipboard.config("trustedDomains"), updatedValue);
|
||||
assert.deepEqual(ZeroClipboard.config().trustedDomains, updatedValue);
|
||||
});
|
||||
|
||||
|
||||
test("Some config values are ignored if SWF is actively embedded", function(assert) {
|
||||
assert.expect(2);
|
||||
|
||||
// Arrange
|
||||
var _swfPath = ZeroClipboard.config("swfPath");
|
||||
var expectedBefore = {
|
||||
swfPath: _swfPath,
|
||||
trustedDomains: window.location.host ? [window.location.host] : [],
|
||||
cacheBust: true,
|
||||
forceEnhancedClipboard: false,
|
||||
flashLoadTimeout: 30000,
|
||||
autoActivate: true,
|
||||
containerId: "global-zeroclipboard-html-bridge",
|
||||
containerClass: "global-zeroclipboard-container",
|
||||
swfObjectId: "global-zeroclipboard-flash-bridge",
|
||||
hoverClass: "zeroclipboard-is-hover",
|
||||
activeClass: "zeroclipboard-is-active",
|
||||
|
||||
// These configuration values CAN be modified while a SWF is actively embedded.
|
||||
bubbleEvents: true,
|
||||
forceHandCursor: false,
|
||||
title: null,
|
||||
zIndex: 999999999
|
||||
};
|
||||
var expectedAfter = {
|
||||
swfPath: _swfPath,
|
||||
trustedDomains: window.location.host ? [window.location.host] : [],
|
||||
cacheBust: true,
|
||||
forceEnhancedClipboard: false,
|
||||
flashLoadTimeout: 30000,
|
||||
autoActivate: true,
|
||||
containerId: "global-zeroclipboard-html-bridge",
|
||||
containerClass: "global-zeroclipboard-container",
|
||||
swfObjectId: "global-zeroclipboard-flash-bridge",
|
||||
hoverClass: "zeroclipboard-is-hover",
|
||||
activeClass: "zeroclipboard-is-active",
|
||||
|
||||
// These configuration values CAN be modified while a SWF is actively embedded.
|
||||
bubbleEvents: false,
|
||||
forceHandCursor: true,
|
||||
title: "test",
|
||||
zIndex: 1000
|
||||
};
|
||||
|
||||
// Act
|
||||
var actualBefore = ZeroClipboard.config();
|
||||
|
||||
_flashState.bridge = {};
|
||||
|
||||
var actualAfter = ZeroClipboard.config({
|
||||
swfPath: "/path/to/test.swf",
|
||||
trustedDomains: ["test.domain.com"],
|
||||
cacheBust: false,
|
||||
forceEnhancedClipboard: true,
|
||||
flashLoadTimeout: 15000,
|
||||
autoActivate: false,
|
||||
containerId: "test-id",
|
||||
containerClass: "test-class",
|
||||
swfObjectId: "test-swf",
|
||||
hoverClass: "test-hover",
|
||||
activeClass: "test-active",
|
||||
|
||||
// These configuration values CAN be modified while a SWF is actively embedded.
|
||||
bubbleEvents: false,
|
||||
forceHandCursor: true,
|
||||
title: "test",
|
||||
zIndex: 1000
|
||||
});
|
||||
|
||||
// Assert
|
||||
assert.deepEqual(actualBefore, expectedBefore, "Original config is as expected");
|
||||
assert.deepEqual(actualAfter, expectedAfter, "Updated config is as expected");
|
||||
});
|
||||
|
||||
|
||||
module("core/api.js unit tests - clipboard", {
|
||||
teardown: function() {
|
||||
_deleteOwnProperties(_clipData);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
test("`setData` works", function(assert) {
|
||||
assert.expect(4);
|
||||
|
||||
// Assert, Act, repeat ad nauseam
|
||||
assert.deepEqual(_clipData, {}, "`_clipData` is empty");
|
||||
|
||||
ZeroClipboard.setData("text/plain", "zc4evar");
|
||||
assert.deepEqual(_clipData, { "text/plain": "zc4evar" }, "`_clipData` contains expected text");
|
||||
|
||||
ZeroClipboard.setData("text/x-markdown", "**ZeroClipboard**");
|
||||
assert.deepEqual(_clipData, { "text/plain": "zc4evar", "text/x-markdown": "**ZeroClipboard**" }, "`_clipData` contains expected text and custom format");
|
||||
|
||||
ZeroClipboard.setData({ "text/html": "<b>Win</b>" });
|
||||
assert.deepEqual(_clipData, { "text/html": "<b>Win</b>" }, "`_clipData` contains expected HTML and cleared out old data because an object was passed in");
|
||||
});
|
||||
|
||||
|
||||
test("`clearData` works", function(assert) {
|
||||
assert.expect(4);
|
||||
|
||||
// Assert
|
||||
assert.deepEqual(_clipData, {}, "`_clipData` is empty");
|
||||
|
||||
// Arrange & Assert
|
||||
_clipData["text/plain"] = "zc4evar";
|
||||
_clipData["text/html"] = "<b>Win</b>";
|
||||
_clipData["text/x-markdown"] = "**ZeroClipboard**";
|
||||
assert.deepEqual(_clipData, {
|
||||
"text/plain": "zc4evar",
|
||||
"text/html": "<b>Win</b>",
|
||||
"text/x-markdown": "**ZeroClipboard**"
|
||||
}, "`_clipData` contains all expected data");
|
||||
|
||||
// Act & Assert
|
||||
ZeroClipboard.clearData("text/html");
|
||||
assert.deepEqual(_clipData, {
|
||||
"text/plain": "zc4evar",
|
||||
"text/x-markdown": "**ZeroClipboard**"
|
||||
}, "`_clipData` had 'text/html' successfully removed");
|
||||
|
||||
// Act & Assert
|
||||
ZeroClipboard.clearData();
|
||||
assert.deepEqual(_clipData, {}, "`_clipData` had all data successfully removed");
|
||||
});
|
||||
|
||||
|
||||
module("core/api.js unit tests - flash", {
|
||||
setup: function() {
|
||||
// Store
|
||||
originalFlashDetect = ZeroClipboard.isFlashUnusable;
|
||||
// Modify
|
||||
ZeroClipboard.isFlashUnusable = function() {
|
||||
return false;
|
||||
};
|
||||
},
|
||||
teardown: function() {
|
||||
// Restore
|
||||
ZeroClipboard.isFlashUnusable = originalFlashDetect;
|
||||
ZeroClipboard.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
test("Flash object is ready after emitting `ready`", function(assert) {
|
||||
assert.expect(2);
|
||||
|
||||
// Arrange
|
||||
ZeroClipboard.isFlashUnusable = function() {
|
||||
return false;
|
||||
};
|
||||
ZeroClipboard.create();
|
||||
|
||||
// Assert, act, assert
|
||||
assert.strictEqual(_flashState.ready, false);
|
||||
// `emit`-ing event handlers are async (generally) but the internal `ready` state is set synchronously
|
||||
ZeroClipboard.emit("ready");
|
||||
assert.strictEqual(_flashState.ready, true);
|
||||
});
|
||||
|
||||
|
||||
test("Object has a title", function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
// Arrange
|
||||
var currentEl = document.getElementById("d_clip_button");
|
||||
ZeroClipboard.create();
|
||||
|
||||
// Act
|
||||
ZeroClipboard.activate(currentEl);
|
||||
|
||||
// Assert
|
||||
assert.strictEqual(TestUtils.getHtmlBridge().getAttribute("title"), "Click me to copy to clipboard.");
|
||||
|
||||
// Revert
|
||||
ZeroClipboard.deactivate();
|
||||
});
|
||||
|
||||
|
||||
test("Object has no title", function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
// Arrange
|
||||
var currentEl = document.getElementById("d_clip_button_no_title");
|
||||
ZeroClipboard.create();
|
||||
|
||||
// Act
|
||||
ZeroClipboard.activate(currentEl);
|
||||
|
||||
// Assert
|
||||
assert.ok(!TestUtils.getHtmlBridge().getAttribute("title"));
|
||||
|
||||
// Revert
|
||||
ZeroClipboard.deactivate();
|
||||
});
|
||||
|
||||
|
||||
test("Object has data-clipboard-text", function(assert) {
|
||||
assert.expect(3);
|
||||
|
||||
// Arrange
|
||||
var currentEl = document.getElementById("d_clip_button");
|
||||
ZeroClipboard.create();
|
||||
|
||||
// Act
|
||||
ZeroClipboard.activate(currentEl);
|
||||
var pendingText = ZeroClipboard.emit("copy");
|
||||
|
||||
// Assert
|
||||
assert.deepEqual(_clipData, { "text/plain": "Copy me!" });
|
||||
assert.deepEqual(pendingText, { "text": "Copy me!" });
|
||||
assert.deepEqual(_clipDataFormatMap, { "text": "text/plain" });
|
||||
|
||||
// Revert
|
||||
ZeroClipboard.deactivate();
|
||||
});
|
||||
|
||||
|
||||
test("Object has data-clipboard-target textarea", function(assert) {
|
||||
assert.expect(3);
|
||||
|
||||
// Arrange
|
||||
var currentEl = document.getElementById("d_clip_button_textarea_text");
|
||||
var expectedText =
|
||||
"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n"+
|
||||
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n"+
|
||||
"quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n"+
|
||||
"consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n"+
|
||||
"cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n"+
|
||||
"proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
|
||||
|
||||
ZeroClipboard.create();
|
||||
|
||||
// Act
|
||||
ZeroClipboard.activate(currentEl);
|
||||
var pendingText = ZeroClipboard.emit("copy");
|
||||
|
||||
// Assert
|
||||
assert.strictEqual(_clipData["text/plain"].replace(/\r\n/g, "\n"), expectedText);
|
||||
assert.strictEqual(pendingText.text.replace(/\r\n/g, "\n"), expectedText);
|
||||
assert.deepEqual(_clipDataFormatMap, { "text": "text/plain" });
|
||||
|
||||
// Revert
|
||||
ZeroClipboard.deactivate();
|
||||
});
|
||||
|
||||
|
||||
test("Object has data-clipboard-target pre", function(assert) {
|
||||
assert.expect(5);
|
||||
|
||||
// Arrange
|
||||
var currentEl = document.getElementById("d_clip_button_pre_text");
|
||||
var expectedText =
|
||||
"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n"+
|
||||
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n"+
|
||||
"quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n"+
|
||||
"consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n"+
|
||||
"cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n"+
|
||||
"proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
|
||||
var expectedHtml =
|
||||
"<pre id=\"clipboard_pre\">"+
|
||||
"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n"+
|
||||
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n"+
|
||||
"quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n"+
|
||||
"consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n"+
|
||||
"cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n"+
|
||||
"proident, sunt in culpa qui officia deserunt mollit anim id est laborum."+
|
||||
"</pre>";
|
||||
|
||||
ZeroClipboard.create();
|
||||
|
||||
// Act
|
||||
ZeroClipboard.activate(currentEl);
|
||||
var pendingText = ZeroClipboard.emit("copy");
|
||||
|
||||
// Assert
|
||||
assert.strictEqual(_clipData["text/plain"].replace(/\r\n/g, "\n"), expectedText);
|
||||
assert.strictEqual(
|
||||
_clipData["text/html"]
|
||||
.replace(/\r\n/g, "\n")
|
||||
.replace(/<\/?pre(?:\s+[^>]*)?>/gi, function($0) { return $0.toLowerCase(); }),
|
||||
expectedHtml
|
||||
);
|
||||
assert.strictEqual(pendingText.text.replace(/\r\n/g, "\n"), expectedText);
|
||||
assert.strictEqual(
|
||||
pendingText.html
|
||||
.replace(/\r\n/g, "\n")
|
||||
.replace(/<\/?pre(?:\s+[^>]*)?>/gi, function($0) { return $0.toLowerCase(); }),
|
||||
expectedHtml
|
||||
);
|
||||
assert.deepEqual(_clipDataFormatMap, { "text": "text/plain", "html": "text/html" });
|
||||
|
||||
// Revert
|
||||
ZeroClipboard.deactivate();
|
||||
});
|
||||
|
||||
|
||||
test("Object has data-clipboard-target input", function(assert) {
|
||||
assert.expect(3);
|
||||
|
||||
// Arrange
|
||||
var currentEl = document.getElementById("d_clip_button_input_text");
|
||||
ZeroClipboard.create();
|
||||
|
||||
// Act
|
||||
ZeroClipboard.activate(currentEl);
|
||||
var pendingText = ZeroClipboard.emit("copy");
|
||||
|
||||
// Assert
|
||||
assert.deepEqual(_clipData, { "text/plain": "Clipboard Text" });
|
||||
assert.deepEqual(pendingText, { "text": "Clipboard Text" });
|
||||
assert.deepEqual(_clipDataFormatMap, { "text": "text/plain" });
|
||||
|
||||
// Revert
|
||||
ZeroClipboard.deactivate();
|
||||
});
|
||||
|
||||
|
||||
test("Object doesn't have data-clipboard-text", function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
// Arrange
|
||||
var currentEl = document.getElementById("d_clip_button_no_text");
|
||||
ZeroClipboard.create();
|
||||
|
||||
// Act
|
||||
ZeroClipboard.activate(currentEl);
|
||||
|
||||
// Assert
|
||||
assert.ok(!TestUtils.getHtmlBridge().getAttribute("data-clipboard-text"));
|
||||
|
||||
// Revert
|
||||
ZeroClipboard.deactivate();
|
||||
});
|
||||
|
||||
|
||||
test("Calculations based on borderWidth never return NaN", function(assert) {
|
||||
assert.expect(4);
|
||||
|
||||
// Arrange
|
||||
var currentEl = document.getElementById("d_clip_button");
|
||||
ZeroClipboard.create();
|
||||
|
||||
// Act
|
||||
ZeroClipboard.activate(currentEl);
|
||||
|
||||
// Assert
|
||||
assert.strictEqual(/^-?[0-9\.]+px$/.test(TestUtils.getHtmlBridge().style.top), true);
|
||||
assert.strictEqual(/^-?[0-9\.]+px$/.test(TestUtils.getHtmlBridge().style.left), true);
|
||||
assert.strictEqual(/^-?[0-9\.]+px$/.test(TestUtils.getHtmlBridge().style.width), true);
|
||||
assert.strictEqual(/^-?[0-9\.]+px$/.test(TestUtils.getHtmlBridge().style.height), true);
|
||||
});
|
||||
|
||||
})(QUnit.module, QUnit.test);
|
@@ -0,0 +1,77 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>ZeroClipboard unit tests: core/api.js</title>
|
||||
<link rel="stylesheet" href="../../node_modules/qunitjs/qunit/qunit.css">
|
||||
<script src="../../node_modules/qunitjs/qunit/qunit.js"></script>
|
||||
<script>
|
||||
// Polyfill in future functionality: https://github.com/jquery/qunit/issues/490
|
||||
if (!QUnit.assert.expect) {
|
||||
QUnit.assert.expect = QUnit.expect;
|
||||
}
|
||||
|
||||
// Require `expect` calls
|
||||
QUnit.config.requireExpects = true;
|
||||
|
||||
// Prevent against Firefox/Firebug failing the global pollution check
|
||||
var getInterface = null;
|
||||
|
||||
// Prevent against failing the global pollution check in all browsers other than IE
|
||||
if (typeof window.ActiveXObject === "undefined") {
|
||||
window.ActiveXObject = null;
|
||||
}
|
||||
|
||||
// Prevent against Flash's ExternalInterface failing the global pollution check (seems to be only in IE < 11)
|
||||
var __flash__arrayToXML = null,
|
||||
__flash__argumentsToXML = null,
|
||||
__flash__objectToXML = null,
|
||||
__flash__escapeXML = null,
|
||||
__flash__toXML = null,
|
||||
__flash__addCallback = null,
|
||||
__flash__removeCallback = null,
|
||||
__flash__request = null;
|
||||
</script>
|
||||
<script src="../../src/js/shared/state.js"></script>
|
||||
<script src="../../src/js/shared/private.js"></script>
|
||||
<script src="../../src/js/core/state.js"></script>
|
||||
<script src="../../src/js/core/private.js"></script>
|
||||
<script src="../../src/js/core/api.js"></script>
|
||||
<script src="../../node_modules/jquery/dist/jquery.js"></script>
|
||||
<script src="api.tests.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture">
|
||||
<p>
|
||||
<button id="d_clip_button" class="my_clip_button" title="Click me to copy to clipboard." data-clipboard-text="Copy me!"><b>Copy To Clipboard...</b></button>
|
||||
</p>
|
||||
<p>
|
||||
<button id="d_clip_button_no_title" class="my_clip_button" data-clipboard-text="Copy me!"><b>Copy To Clipboard...</b></button>
|
||||
</p>
|
||||
<p>
|
||||
<button id="d_clip_button_no_text" class="my_clip_button"><b>Copy To Clipboard...</b></button>
|
||||
</p>
|
||||
<p>
|
||||
<button id="d_clip_button_input_text" class="my_clip_button" data-clipboard-target="clipboard_text"><b>Copy To Clipboard...</b></button>
|
||||
</p>
|
||||
<p>
|
||||
<button id="d_clip_button_textarea_text" class="my_clip_button" data-clipboard-target="clipboard_textarea"><b>Copy To Clipboard...</b></button>
|
||||
</p>
|
||||
<button id="d_clip_button_pre_text" class="my_clip_button" data-clipboard-target="clipboard_pre"><b>Copy To Clipboard...</b></button>
|
||||
<input type="text" id="clipboard_text" value="Clipboard Text"/>
|
||||
<textarea id="clipboard_textarea">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</textarea>
|
||||
<pre id="clipboard_pre">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</pre>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
494
public/filemanager/scripts/zeroclipboard/test/core/private.tests.js
vendored
Normal file
494
public/filemanager/scripts/zeroclipboard/test/core/private.tests.js
vendored
Normal file
@@ -0,0 +1,494 @@
|
||||
/*global _flashState:true, _currentElement:true, _copyTarget:true, _extend, _getStyle, _removeClass, _addClass, _vars, _cacheBust, _extractDomain, _determineScriptAccess, _mapClipDataToFlash, _mapClipResultsFromFlash, _createEvent, _preprocessEvent, _getRelatedTarget, _shouldPerformAsync, _dispatchCallback, _detectFlashSupport */
|
||||
|
||||
(function(module, test) {
|
||||
"use strict";
|
||||
|
||||
var mimeType, ax, flashState;
|
||||
|
||||
|
||||
module("core/private.js unit tests - utils");
|
||||
|
||||
|
||||
test("`_getStyle` returns computed styles", function(assert) {
|
||||
assert.expect(5);
|
||||
|
||||
// Arrange
|
||||
var pointerEl = $("a.no_cursor_style")[0];
|
||||
var nonPointerEl = $("a.no_pointer_anchor")[0];
|
||||
var zIndexAutoEl = $(".zindex-auto")[0];
|
||||
var clipButtonEl = $("#d_clip_button")[0];
|
||||
var bigBorderEl = $(".big-border")[0];
|
||||
|
||||
// Act
|
||||
var pointerElComputedCursor = _getStyle(pointerEl, "cursor");
|
||||
var nonPointerElComputedCursor = _getStyle(nonPointerEl, "cursor");
|
||||
var zIndexAutoElComputedZIndex = _getStyle(zIndexAutoEl, "z-index");
|
||||
var clipButtonElComputedBorderLeftWidth = _getStyle(clipButtonEl, "border-left-width");
|
||||
var bigBorderElComputedBorderLeftWith = _getStyle(bigBorderEl, "border-left-width");
|
||||
|
||||
// Assert
|
||||
assert.strictEqual(pointerElComputedCursor, "pointer");
|
||||
assert.notStrictEqual(nonPointerElComputedCursor, "pointer");
|
||||
// Returns 0 in IE7, "auto" everywhere else
|
||||
assert.strictEqual(/^(?:auto|0)$/.test(zIndexAutoElComputedZIndex), true);
|
||||
// This varies between "0px" and "3px" depending on the browser (WAT?)
|
||||
assert.strictEqual(/^[0-3]px$/.test(clipButtonElComputedBorderLeftWidth), true);
|
||||
assert.strictEqual(bigBorderElComputedBorderLeftWith, "10px");
|
||||
});
|
||||
|
||||
|
||||
test("`_removeClass` removes classes from element", function(assert) {
|
||||
assert.expect(5);
|
||||
|
||||
// Arrange
|
||||
var div = $("<div></div>").addClass("class1 class-2 class_3")[0];
|
||||
|
||||
// Act & Assert
|
||||
_removeClass(div, "class1");
|
||||
assert.strictEqual(div.className, "class-2 class_3");
|
||||
|
||||
_removeClass(div, "classd");
|
||||
assert.strictEqual(div.className, "class-2 class_3");
|
||||
|
||||
_removeClass(div, "class-2");
|
||||
assert.strictEqual(div.className, "class_3");
|
||||
|
||||
_removeClass(div, "class_3");
|
||||
assert.strictEqual(div.className, "");
|
||||
|
||||
_removeClass(div, "class-3");
|
||||
assert.strictEqual(div.className, "");
|
||||
|
||||
div = null;
|
||||
});
|
||||
|
||||
|
||||
test("`_removeClass` doesn't remove partial class names", function(assert) {
|
||||
assert.expect(3);
|
||||
|
||||
// Arrange
|
||||
var div = $("<div></div>").addClass("class1 class-2 class_3")[0];
|
||||
|
||||
// Act & Assert
|
||||
_removeClass(div, "ass");
|
||||
assert.strictEqual(div.className, "class1 class-2 class_3");
|
||||
|
||||
_removeClass(div, "-2");
|
||||
assert.strictEqual(div.className, "class1 class-2 class_3");
|
||||
|
||||
_removeClass(div, "_3");
|
||||
assert.strictEqual(div.className, "class1 class-2 class_3");
|
||||
|
||||
div = null;
|
||||
});
|
||||
|
||||
|
||||
test("`_addClass` adds a class name", function(assert) {
|
||||
assert.expect(4);
|
||||
|
||||
// Arrange
|
||||
var div = $("<div></div>")[0];
|
||||
|
||||
// Act & Assert
|
||||
_addClass(div, "class1");
|
||||
assert.strictEqual(div.className, "class1");
|
||||
|
||||
_addClass(div, "class-2");
|
||||
assert.strictEqual(div.className, "class1 class-2");
|
||||
|
||||
_addClass(div, "class_3");
|
||||
assert.strictEqual(div.className, "class1 class-2 class_3");
|
||||
|
||||
_addClass(div, "class_3");
|
||||
assert.strictEqual(div.className, "class1 class-2 class_3");
|
||||
|
||||
div = null;
|
||||
});
|
||||
|
||||
|
||||
test("`_vars` builds FlashVars", function(assert) {
|
||||
assert.expect(6);
|
||||
|
||||
// Arrange
|
||||
var clipOptionsEmpty = {};
|
||||
var clipOptionsTrustedDomains = {
|
||||
trustedDomains: ["*"]
|
||||
};
|
||||
var clipOptionsEnhancedClipboardFalse = {
|
||||
forceEnhancedClipboard: false
|
||||
};
|
||||
var clipOptionsEnhancedClipboardTrue = {
|
||||
forceEnhancedClipboard: true
|
||||
};
|
||||
var clipOptionsTrustedDomainsPlusEnhancedClipboardFalse = {
|
||||
trustedDomains: ["*"],
|
||||
forceEnhancedClipboard: false
|
||||
};
|
||||
var clipOptionsTrustedDomainsPlusEnhancedClipboardTrue = {
|
||||
trustedDomains: ["*"],
|
||||
forceEnhancedClipboard: true
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
assert.strictEqual(_vars(clipOptionsEmpty), "");
|
||||
assert.strictEqual(_vars(clipOptionsTrustedDomains), "trustedOrigins=*");
|
||||
assert.strictEqual(_vars(clipOptionsEnhancedClipboardFalse), "");
|
||||
assert.strictEqual(_vars(clipOptionsEnhancedClipboardTrue), "forceEnhancedClipboard=true");
|
||||
assert.strictEqual(_vars(clipOptionsTrustedDomainsPlusEnhancedClipboardFalse), "trustedOrigins=*");
|
||||
assert.strictEqual(_vars(clipOptionsTrustedDomainsPlusEnhancedClipboardTrue), "trustedOrigins=*&forceEnhancedClipboard=true");
|
||||
});
|
||||
|
||||
|
||||
test("`_cacheBust` adds cache-buster appropriately", function(assert) {
|
||||
assert.expect(2);
|
||||
|
||||
// Arrange
|
||||
var pathWithoutQuery = "path.com/z.swf";
|
||||
var pathWithQuery = "path.com/z.swf?q=jon";
|
||||
|
||||
// Act & Assert
|
||||
assert.strictEqual(_cacheBust(pathWithoutQuery).indexOf("?noCache="), 0);
|
||||
assert.strictEqual(_cacheBust(pathWithQuery).indexOf("&noCache="), 0);
|
||||
});
|
||||
|
||||
|
||||
test("`_cacheBust` can be disabled", function(assert) {
|
||||
assert.expect(2);
|
||||
|
||||
// Arrange
|
||||
var pathWithoutQuery = "path.com/z.swf";
|
||||
var pathWithQuery = "path.com/z.swf?q=jon";
|
||||
var options = {
|
||||
cacheBust: false
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
assert.strictEqual(_cacheBust(pathWithoutQuery, options), "");
|
||||
assert.strictEqual(_cacheBust(pathWithQuery, options), "");
|
||||
});
|
||||
|
||||
|
||||
test("`_extractDomain` extracts domains from origins and URLs", function(assert) {
|
||||
assert.expect(20);
|
||||
|
||||
// Arrange
|
||||
var inputToExpectedMap = {
|
||||
"": null,
|
||||
" ": null,
|
||||
"ZeroClipboard.swf": null,
|
||||
"js/ZeroClipboard.swf": null,
|
||||
"/js/ZeroClipboard.swf": null,
|
||||
"/zeroclipboard/zeroclipboard/": null,
|
||||
"zeroclipboard/zeroclipboard/": null,
|
||||
"*": "*",
|
||||
"github.com": "github.com",
|
||||
"http://github.com": "github.com",
|
||||
"https://github.com": "github.com",
|
||||
"github.com:80": "github.com:80",
|
||||
"http://github.com:80": "github.com:80",
|
||||
"https://github.com:443": "github.com:443",
|
||||
"http://github.com/zeroclipboard/zeroclipboard/": "github.com",
|
||||
"https://github.com/zeroclipboard/zeroclipboard/": "github.com",
|
||||
"http://github.com:80/zeroclipboard/zeroclipboard/": "github.com:80",
|
||||
"https://github.com:443/zeroclipboard/zeroclipboard/": "github.com:443"
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
assert.strictEqual(_extractDomain(undefined), null, "Processing: `undefined`");
|
||||
assert.strictEqual(_extractDomain(null), null, "Processing: `null`");
|
||||
for (var originOrUrl in inputToExpectedMap) {
|
||||
if (inputToExpectedMap.hasOwnProperty(originOrUrl)) {
|
||||
assert.strictEqual(_extractDomain(originOrUrl), inputToExpectedMap[originOrUrl], "Processing: \"" + originOrUrl + "\"");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
test("`_determineScriptAccess` determines the appropriate script access level", function(assert) {
|
||||
// Arrange
|
||||
var i, len, tmp;
|
||||
var currentDomain = window.location.host || "localhost";
|
||||
var _globalConfig = {
|
||||
swfPath: "ZeroClipboard.swf",
|
||||
trustedDomains: [currentDomain]
|
||||
};
|
||||
var inputToExpectedMap = [
|
||||
// Same-domain SWF
|
||||
{ args: [currentDomain, _globalConfig], result: "sameDomain" },
|
||||
{ args: [currentDomain, _extend({}, _globalConfig, { trustedDomains: [] })], result: "never" },
|
||||
{ args: [currentDomain, _extend({}, _globalConfig, { trustedDomains: ["*"] })], result: "always" },
|
||||
{ args: [currentDomain, _extend({}, _globalConfig, { trustedDomains: [currentDomain, "otherDomain.com"] })], result: "always" },
|
||||
{ args: [currentDomain, _extend({}, _globalConfig, { trustedDomains: ["otherDomain.com"] })], result: "never" },
|
||||
// Cross-domain SWF
|
||||
{ args: [currentDomain, _extend({}, _globalConfig, { swfPath: "//otherDomain.com/ZeroClipboard.swf" })], result: "always" },
|
||||
{ args: [currentDomain, _extend({}, _globalConfig, { swfPath: "//otherDomain.com/ZeroClipboard.swf", trustedDomains: [] })], result: "never" },
|
||||
{ args: [currentDomain, _extend({}, _globalConfig, { swfPath: "//otherDomain.com/ZeroClipboard.swf", trustedDomains: ["*"] })], result: "always" },
|
||||
{ args: [currentDomain, _extend({}, _globalConfig, { swfPath: "//otherDomain.com/ZeroClipboard.swf", trustedDomains: [currentDomain, "otherDomain.com"] })], result: "always" }
|
||||
];
|
||||
|
||||
// Act & Assert
|
||||
assert.expect(9);
|
||||
for (i = 0, len = inputToExpectedMap.length; i < len; i++) {
|
||||
tmp = inputToExpectedMap[i];
|
||||
assert.strictEqual(_determineScriptAccess.apply(this, tmp.args), tmp.result, "Processing: " + JSON.stringify(tmp));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
test("`_mapClipDataToFlash` works", function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
// Arrange
|
||||
var clipData = {
|
||||
"text/plain": "Zero",
|
||||
"text/html": "<b>Zero</b>"
|
||||
};
|
||||
var expectedOutput = {
|
||||
data: {
|
||||
"text": "Zero",
|
||||
"html": "<b>Zero</b>"
|
||||
},
|
||||
formatMap: {
|
||||
"text": "text/plain",
|
||||
"html": "text/html"
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
var actual = _mapClipDataToFlash(clipData);
|
||||
|
||||
// Assert
|
||||
assert.deepEqual(actual, expectedOutput, "Converted keys to Flash-friendly names and provided a format map");
|
||||
});
|
||||
|
||||
|
||||
test("`_mapClipResultsFromFlash` works", function(assert) {
|
||||
assert.expect(2);
|
||||
|
||||
// Arrange
|
||||
var clipResults = {
|
||||
type: "aftercopy",
|
||||
success: {
|
||||
"text": true,
|
||||
"html": false
|
||||
},
|
||||
data: {
|
||||
"text": "Zero",
|
||||
"html": "<b>Zero</b>"
|
||||
}
|
||||
};
|
||||
var formatMap = {
|
||||
"text": "text/plain",
|
||||
"html": "text/html"
|
||||
};
|
||||
var expectedOutput = {
|
||||
type: "aftercopy",
|
||||
success: {
|
||||
"text/plain": true,
|
||||
"text/html": false
|
||||
},
|
||||
data: {
|
||||
"text/plain": "Zero",
|
||||
"text/html": "<b>Zero</b>"
|
||||
}
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
var thisWontChange = _mapClipResultsFromFlash(clipResults, null);
|
||||
assert.deepEqual(thisWontChange, clipResults, "Should return the original object if it cannot map it");
|
||||
|
||||
// Act & Assert
|
||||
var revisedClipResults = _mapClipResultsFromFlash(clipResults, formatMap);
|
||||
assert.deepEqual(revisedClipResults, expectedOutput, "Should reverse the key mapping process");
|
||||
});
|
||||
|
||||
|
||||
test("`_createEvent` works", function(assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var actual = _createEvent("ready");
|
||||
|
||||
assert.strictEqual(typeof actual === "object" && actual != null, true, "Returns non-null object");
|
||||
assert.strictEqual(actual.type, "ready", "Object has a `type` property of 'ready'");
|
||||
|
||||
// etc.
|
||||
});
|
||||
|
||||
|
||||
// Tests fix for: https://github.com/zeroclipboard/zeroclipboard/issues/467
|
||||
test("`_copyTarget` element is handled appropriately", function(assert) {
|
||||
assert.expect(18);
|
||||
|
||||
// Arrange
|
||||
var el1 = $("#d_clip_button")[0];
|
||||
var el2 = $("#goodTargetId")[0];
|
||||
_currentElement = el1;
|
||||
_copyTarget = null;
|
||||
|
||||
// Act
|
||||
var evt = _createEvent("beforecopy");
|
||||
_preprocessEvent(evt);
|
||||
|
||||
// Assert
|
||||
assert.strictEqual(_currentElement, el1, "`_currentElement` is 'el1'");
|
||||
assert.strictEqual(_copyTarget, el1, "`_copyTarget` is 'el1'");
|
||||
assert.strictEqual(evt.target, el1, "`beforecopy` target is 'el1'");
|
||||
|
||||
// Act some more
|
||||
_currentElement = el2;
|
||||
evt = _createEvent("copy");
|
||||
_preprocessEvent(evt);
|
||||
|
||||
// Assert some more
|
||||
assert.strictEqual(_currentElement, el2, "`_currentElement` is 'el2'");
|
||||
assert.strictEqual(_copyTarget, el1, "`_copyTarget` is 'el1'");
|
||||
assert.strictEqual(evt.target, el1, "`copy` target is 'el1'");
|
||||
|
||||
// Act some more: interruption due to mouse movement (only happens in Firefox,
|
||||
// though similar issues occur in Chrome for Windows if the user clicks on
|
||||
// another clipped element)
|
||||
evt = _createEvent("_mouseover");
|
||||
_preprocessEvent(evt);
|
||||
|
||||
// Assert some more
|
||||
assert.strictEqual(_currentElement, el2, "`_currentElement` is 'el2'");
|
||||
assert.strictEqual(_copyTarget, el1, "`_copyTarget` is 'el1'");
|
||||
assert.strictEqual(evt.target, el2, "`_mouseover` target is 'el2'");
|
||||
|
||||
// Act some more
|
||||
evt = _createEvent("aftercopy");
|
||||
_preprocessEvent(evt);
|
||||
|
||||
// Assert some more
|
||||
assert.strictEqual(_currentElement, el2, "`_currentElement` is 'el2'");
|
||||
assert.strictEqual(_copyTarget, el1, "`_copyTarget` is 'el1'");
|
||||
assert.strictEqual(evt.target, el1, "`aftercopy` target is 'el1'");
|
||||
|
||||
// Act some more
|
||||
evt = _createEvent("_click");
|
||||
|
||||
// Assert some more
|
||||
assert.strictEqual(_currentElement, el2, "`_currentElement` is 'el2'");
|
||||
assert.strictEqual(_copyTarget, el1, "`_copyTarget` is 'el1'");
|
||||
assert.strictEqual(evt.target, el1, "`_click` target is 'el1'");
|
||||
|
||||
// Act some more
|
||||
_preprocessEvent(evt);
|
||||
|
||||
// Assert some more
|
||||
assert.strictEqual(_currentElement, el2, "`_currentElement` is 'el2'");
|
||||
assert.strictEqual(_copyTarget, null, "`_copyTarget` is `null`");
|
||||
assert.strictEqual(evt.target, el1, "`_click` target is 'el1'");
|
||||
|
||||
// Reset
|
||||
_currentElement = _copyTarget = el1 = el2 = null;
|
||||
});
|
||||
|
||||
|
||||
test("`_getRelatedTarget` works", function(assert) {
|
||||
assert.expect(4);
|
||||
|
||||
var relTarget = $("#relTargetId")[0];
|
||||
var goodTarget = $("#goodTargetId")[0];
|
||||
var badTarget1 = $("#badTargetId1")[0];
|
||||
var badTarget2 = $("#badTargetId2")[0];
|
||||
|
||||
assert.notEqual(relTarget, null, "The related target is `null`");
|
||||
assert.strictEqual(_getRelatedTarget(goodTarget), relTarget, "Element with `data-clipboard-target` returns `null`");
|
||||
assert.strictEqual(_getRelatedTarget(badTarget1), null, "Element with `data-clipboard-target` that doesn't much any elements returns `null`");
|
||||
assert.strictEqual(_getRelatedTarget(badTarget2), null, "Element without `data-clipboard-target` returns `null`");
|
||||
});
|
||||
|
||||
|
||||
test("`_shouldPerformAsync` works", function(assert) {
|
||||
assert.expect(4);
|
||||
|
||||
// Act & Assert
|
||||
assert.strictEqual(_shouldPerformAsync({ type: "beforecopy" }), false, "`beforecopy` should be performed synchronously");
|
||||
assert.strictEqual(_shouldPerformAsync({ type: "copy" }), false, "`copy` should be performed synchronously");
|
||||
assert.strictEqual(_shouldPerformAsync({ type: "destroy" }), false, "`destroy` should be performed synchronously");
|
||||
assert.strictEqual(_shouldPerformAsync({ type: "ready" }), true, "All other event types should be performed asynchronously");
|
||||
});
|
||||
|
||||
|
||||
test("`_dispatchCallback` can fire asynchronously", function(assert) {
|
||||
assert.expect(6);
|
||||
|
||||
// Arrange
|
||||
var syncExec = false;
|
||||
var syncProof = false;
|
||||
var syncProveIt = function() {
|
||||
syncProof = true;
|
||||
};
|
||||
var asyncExec = true;
|
||||
var asyncProof = false;
|
||||
var asyncProveIt = function() {
|
||||
// Resume test evaluation
|
||||
QUnit.start();
|
||||
|
||||
assert.strictEqual(asyncProof, false);
|
||||
asyncProof = true;
|
||||
assert.strictEqual(asyncProof, true);
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
// Synchronous
|
||||
assert.strictEqual(syncProof, false);
|
||||
_dispatchCallback(syncProveIt, null, null, syncExec);
|
||||
assert.strictEqual(syncProof, true);
|
||||
|
||||
// Asynchronous
|
||||
assert.strictEqual(asyncProof, false);
|
||||
_dispatchCallback(asyncProveIt, null, null, asyncExec);
|
||||
assert.strictEqual(asyncProof, false);
|
||||
|
||||
// Stop test evaluation
|
||||
QUnit.stop();
|
||||
});
|
||||
|
||||
|
||||
module("core/private.js unit tests - flash", {
|
||||
setup: function() {
|
||||
flashState = _flashState;
|
||||
mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"];
|
||||
ax = window.ActiveXObject;
|
||||
},
|
||||
teardown: function() {
|
||||
window.navigator.mimeTypes["application/x-shockwave-flash"] = mimeType;
|
||||
window.ActiveXObject = ax;
|
||||
_flashState = flashState;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
test("Detecting no Flash", function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
// Arrange
|
||||
window.navigator.mimeTypes["application/x-shockwave-flash"] = undefined;
|
||||
window.ActiveXObject = undefined;
|
||||
|
||||
// Act
|
||||
_detectFlashSupport(window.ActiveXObject);
|
||||
|
||||
// Assert
|
||||
assert.strictEqual(_flashState.disabled, true);
|
||||
});
|
||||
|
||||
|
||||
test("Detecting has Flash mimetype", function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
// Arrange
|
||||
window.navigator.mimeTypes["application/x-shockwave-flash"] = {};
|
||||
window.ActiveXObject = function() { };
|
||||
|
||||
// Act
|
||||
_detectFlashSupport(window.ActiveXObject);
|
||||
|
||||
// Assert
|
||||
assert.strictEqual(_flashState.disabled, false);
|
||||
});
|
||||
|
||||
|
||||
})(QUnit.module, QUnit.test);
|
@@ -0,0 +1,68 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>ZeroClipboard unit tests: core/private.js</title>
|
||||
<link rel="stylesheet" href="../../node_modules/qunitjs/qunit/qunit.css">
|
||||
<script src="../../node_modules/qunitjs/qunit/qunit.js"></script>
|
||||
<script>
|
||||
// Polyfill in future functionality: https://github.com/jquery/qunit/issues/490
|
||||
if (!QUnit.assert.expect) {
|
||||
QUnit.assert.expect = QUnit.expect;
|
||||
}
|
||||
|
||||
// Require `expect` calls
|
||||
QUnit.config.requireExpects = true;
|
||||
|
||||
// Prevent against Firefox/Firebug failing the global pollution check
|
||||
var getInterface = null;
|
||||
|
||||
// Prevent against failing the global pollution check in all browsers other than IE
|
||||
if (typeof window.ActiveXObject === "undefined") {
|
||||
window.ActiveXObject = null;
|
||||
}
|
||||
|
||||
// Prevent against Flash's ExternalInterface failing the global pollution check (seems to be only in IE < 11)
|
||||
var __flash__arrayToXML = null,
|
||||
__flash__argumentsToXML = null,
|
||||
__flash__objectToXML = null,
|
||||
__flash__escapeXML = null,
|
||||
__flash__toXML = null,
|
||||
__flash__addCallback = null,
|
||||
__flash__removeCallback = null,
|
||||
__flash__request = null;
|
||||
|
||||
// Provide a shell of the `ZeroClipboard` object to pass through a few tests
|
||||
var ZeroClipboard = {
|
||||
setData: function() {},
|
||||
clearData: function() {},
|
||||
focus: function(el) {
|
||||
_currentElement = el;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<script src="../../src/js/shared/state.js"></script>
|
||||
<script src="../../src/js/shared/private.js"></script>
|
||||
<script src="../../src/js/core/state.js"></script>
|
||||
<script src="../../src/js/core/private.js"></script>
|
||||
<script src="../../node_modules/jquery/dist/jquery.js"></script>
|
||||
<script src="private.tests.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture">
|
||||
<div id="goodTargetId" data-clipboard-target="relTargetId"></div>
|
||||
<div id="relTargetId"></div>
|
||||
<div id="badTargetId1" data-clipboard-target="elementIdWithoutMatch"></div>
|
||||
<div id="badTargetId2"></div>
|
||||
|
||||
<button id="d_clip_button" class="my_clip_button" title="Click me to copy to clipboard." data-clipboard-text="Copy me!">
|
||||
<b>Copy To Clipboard...</b>
|
||||
</button>
|
||||
<a href="" class="no_pointer_anchor" style="cursor:default;"></a>
|
||||
<a href="" class="no_cursor_style" style="cursor:auto;"></a>
|
||||
<span class="zindex-auto" style="z-index:auto;"></span>
|
||||
<span class="big-border" style="border: 10px solid red;"></span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
28
public/filemanager/scripts/zeroclipboard/test/index.html
Normal file
28
public/filemanager/scripts/zeroclipboard/test/index.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>ZeroClipboard unit tests</title>
|
||||
<link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css">
|
||||
<link rel="stylesheet" href="../node_modules/qunit-composite/qunit-composite.css">
|
||||
<script src="../node_modules/qunitjs/qunit/qunit.js"></script>
|
||||
<script src="../node_modules/qunit-composite/qunit-composite.js"></script>
|
||||
<script>
|
||||
(function() {
|
||||
var queryParams = "?noglobals=true";
|
||||
QUnit.testSuites([
|
||||
"shared/private.tests.js.html" + queryParams,
|
||||
"core/private.tests.js.html" + queryParams,
|
||||
"core/api.tests.js.html" + queryParams,
|
||||
"client/private.tests.js.html" + queryParams,
|
||||
"client/api.tests.js.html" + queryParams,
|
||||
"built/ZeroClipboard.Core.tests.js.html" + queryParams,
|
||||
"built/ZeroClipboard.tests.js.html" + queryParams
|
||||
]);
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="qunit"></div>
|
||||
</body>
|
||||
</html>
|
911
public/filemanager/scripts/zeroclipboard/test/shared/private.tests.js
vendored
Normal file
911
public/filemanager/scripts/zeroclipboard/test/shared/private.tests.js
vendored
Normal file
@@ -0,0 +1,911 @@
|
||||
/*global _document:true, _Error:true, _args, _extend, _deepCopy, _pick, _omit, _deleteOwnProperties, _containedBy, _getDirPathOfUrl, _getCurrentScriptUrlFromErrorStack, _getCurrentScriptUrlFromError:true, _getCurrentScriptUrl, _getUnanimousScriptParentDir, _getDefaultSwfPath */
|
||||
|
||||
(function(module, test) {
|
||||
"use strict";
|
||||
|
||||
var doc, errorDef, getUrlFromError;
|
||||
module("shared/private.js unit tests", {
|
||||
setup: function() {
|
||||
doc = _document;
|
||||
errorDef = _Error;
|
||||
getUrlFromError = _getCurrentScriptUrlFromError;
|
||||
},
|
||||
teardown: function() {
|
||||
_document = doc;
|
||||
_Error = errorDef;
|
||||
_getCurrentScriptUrlFromError = getUrlFromError;
|
||||
}
|
||||
});
|
||||
|
||||
test("`_args` works", function(assert) {
|
||||
assert.expect(4);
|
||||
|
||||
// Arrange
|
||||
var _arguments = function() {
|
||||
return arguments;
|
||||
};
|
||||
var fn = function() {};
|
||||
var expectedOutput1 = [1, 2, 3];
|
||||
var expectedOutput2 = [fn];
|
||||
var expectedOutput3 = [{ foo: "bar" }];
|
||||
var expectedOutput4 = [[1, 2, 3]];
|
||||
var inputArgs1 = _arguments(1, 2, 3);
|
||||
var inputArgs2 = _arguments(fn);
|
||||
var inputArgs3 = _arguments({ foo: "bar" });
|
||||
var inputArgs4 = _arguments([1, 2, 3]);
|
||||
|
||||
// Act
|
||||
var actualOutput1 = _args(inputArgs1);
|
||||
var actualOutput2 = _args(inputArgs2);
|
||||
var actualOutput3 = _args(inputArgs3);
|
||||
var actualOutput4 = _args(inputArgs4);
|
||||
|
||||
// Arrange
|
||||
assert.deepEqual(actualOutput1, expectedOutput1);
|
||||
assert.deepEqual(actualOutput2, expectedOutput2);
|
||||
assert.deepEqual(actualOutput3, expectedOutput3);
|
||||
assert.deepEqual(actualOutput4, expectedOutput4);
|
||||
});
|
||||
|
||||
|
||||
test("`_extend` works on plain objects", function(assert) {
|
||||
assert.expect(5);
|
||||
|
||||
// Plain objects
|
||||
var a = {
|
||||
"a": "apple",
|
||||
"c": "cantalope"
|
||||
},
|
||||
b = {
|
||||
"b": "banana",
|
||||
"c": "cherry" // cuz cantalope sucks ;)
|
||||
},
|
||||
c = {
|
||||
"a": "apple",
|
||||
"b": "banana",
|
||||
"c": "cherry"
|
||||
};
|
||||
|
||||
assert.deepEqual(_extend({}, a), a, "actual equals expected, `target` is updated, `source` is unaffected");
|
||||
assert.deepEqual(_extend({}, b), b, "actual equals expected, `target` is updated, `source` is unaffected");
|
||||
assert.deepEqual(_extend({}, c), c, "actual equals expected, `target` is updated, `source` is unaffected");
|
||||
assert.deepEqual(_extend(a, b), c, "actual equals expected");
|
||||
assert.deepEqual(a, c, "`a` equals `c` because `_extend` updates the `target` argument");
|
||||
});
|
||||
|
||||
|
||||
test("`_extend` only copies owned properties", function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
// Now prototypes...
|
||||
var SomeClass = function() {
|
||||
this.b = "banana";
|
||||
};
|
||||
SomeClass.prototype.c = "cantalope"; // cuz cantalope sucks ;)
|
||||
|
||||
var a = {
|
||||
"a": "apple",
|
||||
"c": "cherry"
|
||||
},
|
||||
b = new SomeClass(),
|
||||
c = {
|
||||
"a": "apple",
|
||||
"b": "banana",
|
||||
"c": "cherry"
|
||||
};
|
||||
|
||||
assert.deepEqual(_extend(a, b), c, "actual equals expected because `_extend` does not copy over prototype properties");
|
||||
});
|
||||
|
||||
|
||||
test("`_extend` only copies owned properties from Array source", function(assert) {
|
||||
assert.expect(3);
|
||||
|
||||
var a = {
|
||||
"a": "apple",
|
||||
"b": "banana"
|
||||
},
|
||||
b = ["zero", "one", "two"],
|
||||
c = {
|
||||
"a": "apple",
|
||||
"b": "banana",
|
||||
"0": "zero",
|
||||
"1": "one",
|
||||
"2": "two"
|
||||
};
|
||||
|
||||
assert.deepEqual(_extend(a, b), c, "actual equals expected because `_extend` does not copy over prototype properties");
|
||||
assert.strictEqual("length" in a, false, "`a` should not have gained a `length` property");
|
||||
assert.strictEqual("length" in b, true, "`b` should still have a `length` property");
|
||||
});
|
||||
|
||||
|
||||
test("`_extend` will merge multiple objects", function(assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var a = {
|
||||
"a": "apple",
|
||||
"c": "cantalope",
|
||||
"d": "dragon fruit"
|
||||
},
|
||||
b = {
|
||||
"b": "banana",
|
||||
"c": "cherry" // cuz cantalope sucks ;)
|
||||
},
|
||||
c = {
|
||||
"a": "apricot",
|
||||
"b": "blueberry"
|
||||
},
|
||||
d = {
|
||||
"a": "apricot",
|
||||
"b": "blueberry",
|
||||
"c": "cherry",
|
||||
"d": "dragon fruit"
|
||||
};
|
||||
|
||||
assert.deepEqual(_extend({}, a, b, c), d, "actual equals expected, `target` is updated, `source` is unaffected");
|
||||
assert.deepEqual(_extend(a, b, c), d, "actual equals expected");
|
||||
});
|
||||
|
||||
|
||||
test("`_deepCopy` works", function(assert) {
|
||||
assert.expect(13);
|
||||
|
||||
// Arrange
|
||||
var input1 = {
|
||||
"a": "b",
|
||||
"b": {
|
||||
"c": "d"
|
||||
}
|
||||
};
|
||||
var input2 = [[1, 2], 2];
|
||||
var expected1 = {
|
||||
"a": "b",
|
||||
"b": {
|
||||
"c": "d"
|
||||
}
|
||||
};
|
||||
var expected2 = [[1, 2], 2];
|
||||
|
||||
// Act
|
||||
var actual1 = _deepCopy(input1);
|
||||
var actual2 = _deepCopy(input2);
|
||||
|
||||
// Assert
|
||||
assert.deepEqual(actual1, expected1, "Objects are deeply equal");
|
||||
assert.notStrictEqual(actual1, expected1, "Objects are not strictly equal");
|
||||
assert.strictEqual(actual1.a, expected1.a, "Objects' non-object properties are strictly equal");
|
||||
assert.deepEqual(actual1.b, expected1.b, "Objects' object properties are deeply equal");
|
||||
assert.notStrictEqual(actual1.b, expected1.b, "Objects' object properties are not strictly equal");
|
||||
assert.strictEqual(actual1.b.c, expected1.b.c, "Objects' object properties' non-object properties are strictly equal");
|
||||
|
||||
assert.deepEqual(actual2, expected2, "Arrays are deeply equal");
|
||||
assert.notStrictEqual(actual2, expected2, "Arrays are not strictly equal");
|
||||
assert.deepEqual(actual2[0], expected2[0], "Sub-arrays are deeply equal");
|
||||
assert.notStrictEqual(actual2[0], expected2[0], "Sub-arrays are not strictly equal");
|
||||
assert.strictEqual(actual2[0][0], expected2[0][0], "Sub-arrays' first items are strictly equal");
|
||||
assert.strictEqual(actual2[0][1], expected2[0][1], "Sub-arrays' second items are strictly equal");
|
||||
assert.strictEqual(actual2[1], expected2[1], "Sub-items are strictly equal");
|
||||
});
|
||||
|
||||
|
||||
test("`_pick` works", function(assert) {
|
||||
assert.expect(6);
|
||||
|
||||
// Arrange
|
||||
var obj1 = {};
|
||||
var obj2 = {
|
||||
"name": "Zero",
|
||||
"version": "v2.x",
|
||||
"other": "test"
|
||||
};
|
||||
var filter1 = [];
|
||||
var filter2 = ["name", "version"];
|
||||
var filter3 = ["name", "version", "other"];
|
||||
|
||||
var expected1x = {};
|
||||
var expected21 = {};
|
||||
var expected22 = {
|
||||
"name": "Zero",
|
||||
"version": "v2.x"
|
||||
};
|
||||
var expected23 = {
|
||||
"name": "Zero",
|
||||
"version": "v2.x",
|
||||
"other": "test"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result11 = _pick(obj1, filter1);
|
||||
var result12 = _pick(obj1, filter2);
|
||||
var result13 = _pick(obj1, filter3);
|
||||
var result21 = _pick(obj2, filter1);
|
||||
var result22 = _pick(obj2, filter2);
|
||||
var result23 = _pick(obj2, filter3);
|
||||
|
||||
// Assert
|
||||
assert.deepEqual(result11, expected1x, "An empty object cannot have any properties picked");
|
||||
assert.deepEqual(result12, expected1x, "An empty object cannot have any properties picked");
|
||||
assert.deepEqual(result13, expected1x, "An empty object cannot have any properties picked");
|
||||
assert.deepEqual(result21, expected21, "An object with an empty pick list will have nothing picked");
|
||||
assert.deepEqual(result22, expected22, "An object with a subset pick list will have only those properties picked");
|
||||
assert.deepEqual(result23, expected23, "An object with a complete pick list will have all of its properties picked");
|
||||
});
|
||||
|
||||
|
||||
test("`_omit` works", function(assert) {
|
||||
assert.expect(6);
|
||||
|
||||
// Arrange
|
||||
var obj1 = {};
|
||||
var obj2 = {
|
||||
"name": "Zero",
|
||||
"version": "v2.x",
|
||||
"other": "test"
|
||||
};
|
||||
var filter1 = [];
|
||||
var filter2 = ["name", "version"];
|
||||
var filter3 = ["name", "version", "other"];
|
||||
|
||||
var expected1x = {};
|
||||
var expected21 = {
|
||||
"name": "Zero",
|
||||
"version": "v2.x",
|
||||
"other": "test"
|
||||
};
|
||||
var expected22 = {
|
||||
"other": "test"
|
||||
};
|
||||
var expected23 = {};
|
||||
|
||||
// Act
|
||||
var result11 = _omit(obj1, filter1);
|
||||
var result12 = _omit(obj1, filter2);
|
||||
var result13 = _omit(obj1, filter3);
|
||||
var result21 = _omit(obj2, filter1);
|
||||
var result22 = _omit(obj2, filter2);
|
||||
var result23 = _omit(obj2, filter3);
|
||||
|
||||
// Assert
|
||||
assert.deepEqual(result11, expected1x, "An empty object cannot have any properties picked");
|
||||
assert.deepEqual(result12, expected1x, "An empty object cannot have any properties picked");
|
||||
assert.deepEqual(result13, expected1x, "An empty object cannot have any properties picked");
|
||||
assert.deepEqual(result21, expected21, "An object with an empty omit list will have everything picked");
|
||||
assert.deepEqual(result22, expected22, "An object with a subset omit list will have everything but those properties picked");
|
||||
assert.deepEqual(result23, expected23, "An object with a complete omit list will have nothing picked");
|
||||
});
|
||||
|
||||
|
||||
test("`_deleteOwnProperties` will delete all owned enumerable properties", function(assert) {
|
||||
assert.expect(24);
|
||||
|
||||
var getNonObjectKeys = function(obj) {
|
||||
var prop,
|
||||
keys = [];
|
||||
if (obj) {
|
||||
for (prop in obj) {
|
||||
if (obj.hasOwnProperty(prop)) {
|
||||
keys.push(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
};
|
||||
var getProtoKeys = function(obj) {
|
||||
var prop,
|
||||
keys = [];
|
||||
if (obj) {
|
||||
for (prop in obj) {
|
||||
if (!obj.hasOwnProperty(prop)) {
|
||||
keys.push(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
};
|
||||
|
||||
var a = {
|
||||
"a": "apple",
|
||||
"c": "cantalope",
|
||||
"d": "dragon fruit"
|
||||
},
|
||||
b = {},
|
||||
c = ["banana", "cherry"],
|
||||
d = (function() {
|
||||
function SomePrototype() {
|
||||
this.protoProp = "foo";
|
||||
}
|
||||
function SomeClass() {
|
||||
this.ownedProp = "bar";
|
||||
}
|
||||
SomeClass.prototype = new SomePrototype();
|
||||
SomeClass.prototype.constructor = SomeClass;
|
||||
|
||||
return new SomeClass();
|
||||
})(),
|
||||
e = null,
|
||||
f; // = undefined;
|
||||
|
||||
assert.deepEqual(Object.keys(a), ["a", "c", "d"]);
|
||||
assert.deepEqual(getProtoKeys(a), []);
|
||||
_deleteOwnProperties(a);
|
||||
assert.deepEqual(Object.keys(a), []);
|
||||
assert.deepEqual(getProtoKeys(a), []);
|
||||
|
||||
assert.deepEqual(Object.keys(b), []);
|
||||
assert.deepEqual(getProtoKeys(b), []);
|
||||
_deleteOwnProperties(b);
|
||||
assert.deepEqual(Object.keys(b), []);
|
||||
assert.deepEqual(getProtoKeys(b), []);
|
||||
|
||||
assert.deepEqual(getNonObjectKeys(c), ["0", "1"]);
|
||||
assert.deepEqual(getProtoKeys(c), []);
|
||||
_deleteOwnProperties(c);
|
||||
assert.deepEqual(getNonObjectKeys(c), []);
|
||||
assert.deepEqual(getProtoKeys(c), []);
|
||||
|
||||
assert.deepEqual(Object.keys(d), ["ownedProp"]);
|
||||
assert.deepEqual(getProtoKeys(d), ["protoProp", "constructor"]);
|
||||
_deleteOwnProperties(d);
|
||||
assert.deepEqual(Object.keys(d), []);
|
||||
assert.deepEqual(getProtoKeys(d), ["protoProp", "constructor"]);
|
||||
|
||||
assert.deepEqual(getNonObjectKeys(e), []);
|
||||
assert.deepEqual(getProtoKeys(e), []);
|
||||
_deleteOwnProperties(e);
|
||||
assert.deepEqual(getNonObjectKeys(e), []);
|
||||
assert.deepEqual(getProtoKeys(e), []);
|
||||
|
||||
assert.deepEqual(getNonObjectKeys(f), []);
|
||||
assert.deepEqual(getProtoKeys(f), []);
|
||||
_deleteOwnProperties(f);
|
||||
assert.deepEqual(getNonObjectKeys(f), []);
|
||||
assert.deepEqual(getProtoKeys(f), []);
|
||||
});
|
||||
|
||||
|
||||
test("`_containedBy` works", function(assert) {
|
||||
/*jshint camelcase:false */
|
||||
|
||||
assert.expect(29);
|
||||
|
||||
// Arrange
|
||||
var fixture = document.getElementById("qunit-fixture");
|
||||
fixture.innerHTML =
|
||||
"<div id='container'>" +
|
||||
"<div id='contained1'>" +
|
||||
"<div id='contained1_1'></div>" +
|
||||
"<div id='contained1_2'>" +
|
||||
"<div id='contained1_2_1'></div>" +
|
||||
"</div>" +
|
||||
"</div>" +
|
||||
"<div id='contained2'></div>" +
|
||||
"</div>" +
|
||||
"<div id='not_container'>" +
|
||||
"<div id='not_contained'></div>" +
|
||||
"</div>";
|
||||
|
||||
var container = document.getElementById("container");
|
||||
var contained1 = document.getElementById("contained1");
|
||||
var contained1_1 = document.getElementById("contained1_1");
|
||||
var contained1_2 = document.getElementById("contained1_2");
|
||||
var contained1_2_1 = document.getElementById("contained1_2_1");
|
||||
var contained2 = document.getElementById("contained2");
|
||||
var not_container = document.getElementById("not_container");
|
||||
var not_contained = document.getElementById("not_contained");
|
||||
|
||||
// Act & Assert
|
||||
assert.strictEqual(_containedBy(contained1_2_1, contained1_2_1), true);
|
||||
assert.strictEqual(_containedBy(contained1_2_1, contained1_2), true);
|
||||
assert.strictEqual(_containedBy(contained1_2_1, contained1), true);
|
||||
assert.strictEqual(_containedBy(contained1_2_1, container), true);
|
||||
assert.strictEqual(_containedBy(contained1_2_1, fixture), true);
|
||||
assert.strictEqual(_containedBy(contained1_2_1, not_container), false);
|
||||
|
||||
assert.strictEqual(_containedBy(contained1_1, contained1_1), true);
|
||||
assert.strictEqual(_containedBy(contained1_1, contained1), true);
|
||||
assert.strictEqual(_containedBy(contained1_1, container), true);
|
||||
assert.strictEqual(_containedBy(contained1_1, fixture), true);
|
||||
assert.strictEqual(_containedBy(contained1_1, not_container), false);
|
||||
|
||||
assert.strictEqual(_containedBy(contained1, contained1), true);
|
||||
assert.strictEqual(_containedBy(contained1, container), true);
|
||||
assert.strictEqual(_containedBy(contained1, fixture), true);
|
||||
assert.strictEqual(_containedBy(contained1, not_container), false);
|
||||
|
||||
assert.strictEqual(_containedBy(contained2, contained2), true);
|
||||
assert.strictEqual(_containedBy(contained2, container), true);
|
||||
assert.strictEqual(_containedBy(contained2, fixture), true);
|
||||
assert.strictEqual(_containedBy(contained2, not_container), false);
|
||||
|
||||
assert.strictEqual(_containedBy(container, container), true);
|
||||
assert.strictEqual(_containedBy(container, fixture), true);
|
||||
assert.strictEqual(_containedBy(container, not_container), false);
|
||||
|
||||
assert.strictEqual(_containedBy(not_contained, not_contained), true);
|
||||
assert.strictEqual(_containedBy(not_contained, not_container), true);
|
||||
assert.strictEqual(_containedBy(not_contained, fixture), true);
|
||||
assert.strictEqual(_containedBy(not_contained, container), false);
|
||||
|
||||
assert.strictEqual(_containedBy(not_container, not_container), true);
|
||||
assert.strictEqual(_containedBy(not_container, fixture), true);
|
||||
assert.strictEqual(_containedBy(not_container, container), false);
|
||||
});
|
||||
|
||||
|
||||
test("`_getDirPathOfUrl` works", function(assert) {
|
||||
assert.expect(8);
|
||||
|
||||
// Arrange
|
||||
var input1 = "http://example.com/blah/foo/index.html";
|
||||
var input2 = "http://example.com/blah/foo/index.html?q=p";
|
||||
var input3 = "http://example.com/blah/foo/index.html?q=p&x=z";
|
||||
var input4 = "http://example.com/blah/foo/index.html?#xyz";
|
||||
var input5 = "http://example.com/blah/foo/index.html?q=p#xyz";
|
||||
var input6 = "http://example.com/blah/foo/index.html?q=p&x=z#xyz";
|
||||
var input7 = "http://example.com/blah/foo/";
|
||||
var input8 = "";
|
||||
var expected1 = "http://example.com/blah/foo/";
|
||||
var expected2 = "http://example.com/blah/foo/";
|
||||
var expected3 = "http://example.com/blah/foo/";
|
||||
var expected4 = "http://example.com/blah/foo/";
|
||||
var expected5 = "http://example.com/blah/foo/";
|
||||
var expected6 = "http://example.com/blah/foo/";
|
||||
var expected7 = "http://example.com/blah/foo/";
|
||||
var expected8;
|
||||
|
||||
// Act
|
||||
var actual1 = _getDirPathOfUrl(input1);
|
||||
var actual2 = _getDirPathOfUrl(input2);
|
||||
var actual3 = _getDirPathOfUrl(input3);
|
||||
var actual4 = _getDirPathOfUrl(input4);
|
||||
var actual5 = _getDirPathOfUrl(input5);
|
||||
var actual6 = _getDirPathOfUrl(input6);
|
||||
var actual7 = _getDirPathOfUrl(input7);
|
||||
var actual8 = _getDirPathOfUrl(input8);
|
||||
|
||||
// Assert
|
||||
assert.strictEqual(actual1, expected1);
|
||||
assert.strictEqual(actual2, expected2);
|
||||
assert.strictEqual(actual3, expected3);
|
||||
assert.strictEqual(actual4, expected4);
|
||||
assert.strictEqual(actual5, expected5);
|
||||
assert.strictEqual(actual6, expected6);
|
||||
assert.strictEqual(actual7, expected7);
|
||||
assert.strictEqual(actual8, expected8);
|
||||
});
|
||||
|
||||
|
||||
test("`_getCurrentScriptUrlFromErrorStack` works", function(assert) {
|
||||
assert.expect(25);
|
||||
|
||||
// Arrange
|
||||
var localStacks = [
|
||||
"Error: my uncaught error\n at http://example.com/index.html:123:4\n at jQuery.event.dispatch (http://code.jquery.com/blah.js:567:8)\n at foo",
|
||||
"http://example.com/index.html:123:4\ndispatch@http://code.jquery.com/blah.js:567:8\nfoo",
|
||||
"@http://example.com/index.html:123\ndispatch@http://code.jquery.com/blah.js:567\nfoo",
|
||||
"<anonymous function>([arguments not available])@http://example.com/index.html:123\n<anonymous function: dispatch>([arguments not available])@http://code.jquery.com/blah.js:567\nfoo",
|
||||
"Error: my error\n at http://example.com/index.html:123\n at http://code.jquery.com/blah.js:567\nfoo",
|
||||
"Error(\"my error\")@:0\u000a([object Object])@http://example.com/index.html:123\u000a([object Object])@http://code.jquery.com/blah.js:567\u000afoo",
|
||||
"Error: my error\n at Anonymous function (http://example.com/index.html:123:4)\n at dispatch (http://code.jquery.com/blah.js:567:8)\n at foo",
|
||||
"Error: my sneaky error message has a URL in it at http://google.com/mean.js:987\n at Anonymous function (http://example.com/index.html:123:4)\n at dispatch (http://code.jquery.com/blah.js:567:8)\n at foo"
|
||||
];
|
||||
var remoteStacks = [
|
||||
"Error: my error\n at window.onload (http://example.com/blah/foo.js:95:11)\n at jQuery.event.dispatch (http://code.jquery.com/blah.js:567:8)\n at foo",
|
||||
"onload@http://example.com/blah/foo.js:95:11\ndispatch@http://code.jquery.com/blah.js:567:8\nfoo",
|
||||
"onload@http://example.com/blah/foo.js:95\ndispatch@http://code.jquery.com/blah.js:567\nfoo",
|
||||
"<anonymous function: window.onload>([arguments not available])@http://example.com/blah/foo.js:95\n<anonymous function: dispatch>([arguments not available])@http://code.jquery.com/blah.js:567\nfoo",
|
||||
"Error: my error\n at http://example.com/blah/foo.js:95\n at http://code.jquery.com/blah.js:567\nfoo",
|
||||
"Error(\"my error\")@:0\u000a@http://example.com/blah/foo.js:95\u000a([object Object])@http://code.jquery.com/blah.js:567\u000afoo",
|
||||
"Error: my error\n at onload (http://example.com/blah/foo.js:95:11)\n at dispatch (http://code.jquery.com/blah.js:567:8)\n at foo",
|
||||
"Error: my sneaky error message has a URL in it at http://google.com/mean.js:987\n at onload (http://example.com/blah/foo.js:95:11)\n at dispatch (http://code.jquery.com/blah.js:567:8)\n at foo"
|
||||
];
|
||||
var badStacks = [
|
||||
"blah",
|
||||
"",
|
||||
[],
|
||||
{},
|
||||
null,
|
||||
undefined
|
||||
];
|
||||
var localExpected = "http://example.com/index.html",
|
||||
remoteExpected = "http://example.com/blah/foo.js",
|
||||
badExpected;
|
||||
|
||||
// Act & Assert
|
||||
assert.strictEqual(localStacks.length, 8, "Local stacks x 8");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(localStacks[0]), localExpected, "Inline script: Chrome");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(localStacks[1]), localExpected, "Inline script: Safari 6.1+");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(localStacks[2]), localExpected, "Inline script: Safari 6.0");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(localStacks[3]), localExpected, "Inline script: Opera");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(localStacks[4]), localExpected, "Inline script: PhantomJS");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(localStacks[5]), localExpected, "Inline script: Firefox 3.6");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(localStacks[6]), localExpected, "Inline script: IE 10.0");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(localStacks[7]), localExpected, "Inline script: SneakyError");
|
||||
|
||||
assert.strictEqual(remoteStacks.length, 8, "Remote stacks x 8");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(remoteStacks[0]), remoteExpected, "External script: Chrome");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(remoteStacks[1]), remoteExpected, "External script: Safari 6.1+");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(remoteStacks[2]), remoteExpected, "External script: Safari 6.0");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(remoteStacks[3]), remoteExpected, "External script: Opera");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(remoteStacks[4]), remoteExpected, "External script: PhantomJS");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(remoteStacks[5]), remoteExpected, "External script: Firefox 3.6");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(remoteStacks[6]), remoteExpected, "External script: IE 10.0");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(remoteStacks[7]), remoteExpected, "External script: SneakyError");
|
||||
|
||||
assert.strictEqual(badStacks.length, 6, "Bad stacks x 6");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(badStacks[0]), badExpected, "Useless stack");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(badStacks[1]), badExpected, "Empty string");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(badStacks[2]), badExpected, "Array");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(badStacks[3]), badExpected, "Object");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(badStacks[4]), badExpected, "`null`");
|
||||
assert.strictEqual(_getCurrentScriptUrlFromErrorStack(badStacks[5]), badExpected, "`undefined`");
|
||||
});
|
||||
|
||||
|
||||
test("`_getCurrentScriptUrlFromError` works", function(assert) {
|
||||
assert.expect(4);
|
||||
|
||||
// Arrange
|
||||
var actual1, actual2, actual3, actual4;
|
||||
var expected = "http://example.com/blah/foo.js";
|
||||
var _sourceUrl, _fileName, _stack;
|
||||
|
||||
// Do NOT inherit from the real `Error` definition
|
||||
_Error = function() {
|
||||
this.sourceURL = _sourceUrl;
|
||||
this.fileName = _fileName;
|
||||
this.stack = _stack;
|
||||
};
|
||||
|
||||
// Act
|
||||
_sourceUrl = expected;
|
||||
_fileName = undefined;
|
||||
_stack = undefined;
|
||||
actual1 = _getCurrentScriptUrlFromError();
|
||||
|
||||
_sourceUrl = undefined;
|
||||
_fileName = expected;
|
||||
_stack = undefined;
|
||||
actual2 = _getCurrentScriptUrlFromError();
|
||||
|
||||
_sourceUrl = undefined;
|
||||
_fileName = undefined;
|
||||
_stack = "Error: my uncaught error\n at " + expected + ":123:4\n at jQuery.event.dispatch (http://code.jquery.com/blah.js:123:0)\n at foo";
|
||||
actual3 = _getCurrentScriptUrlFromError();
|
||||
|
||||
_sourceUrl = undefined;
|
||||
_fileName = undefined;
|
||||
_stack = undefined;
|
||||
actual4 = _getCurrentScriptUrlFromError();
|
||||
|
||||
// Assert
|
||||
assert.strictEqual(actual1, expected, "Current script derived from `err.sourceURL`");
|
||||
assert.strictEqual(actual2, expected, "Current script derived from `err.fileName`");
|
||||
assert.strictEqual(actual3, expected, "Current script derived from `err.stack`");
|
||||
assert.strictEqual(actual4, undefined, "Current script cannot be derived from the Error");
|
||||
});
|
||||
|
||||
|
||||
test("`_getCurrentScriptUrl` works", function(assert) {
|
||||
assert.expect(9);
|
||||
|
||||
// Arrange
|
||||
var actual1, actual2, actual3, actual4, actual5, actual6, actual7, actual8, actual9;
|
||||
var expected1, expected2, expected3, expected4, expected5, expected6, expected7, expected8, expected9;
|
||||
expected1 = expected2 = expected3 = expected4 = expected5 = "http://example.com/blah/foo/bar.js";
|
||||
|
||||
// Arrange & Act
|
||||
_document = {
|
||||
currentScript: {
|
||||
src: "http://example.com/blah/foo/bar.js"
|
||||
}
|
||||
};
|
||||
_getCurrentScriptUrlFromError = function() {};
|
||||
actual1 = _getCurrentScriptUrl();
|
||||
|
||||
_document = {
|
||||
getElementsByTagName: function(/* tagName */) {
|
||||
return [
|
||||
{ src: "http://example.com/blah/foo/bar.js" }
|
||||
];
|
||||
}
|
||||
};
|
||||
actual2 = _getCurrentScriptUrl();
|
||||
|
||||
_document = {
|
||||
getElementsByTagName: function(/* tagName */) {
|
||||
return [
|
||||
{ src: "http://example.com/blah/foo.js", readyState: "complete" },
|
||||
{ src: "http://example.com/blah/foo/bar.js", readyState: "interactive" }
|
||||
];
|
||||
}
|
||||
};
|
||||
actual3 = _getCurrentScriptUrl();
|
||||
|
||||
_document = {
|
||||
readyState: "loading",
|
||||
getElementsByTagName: function(/* tagName */) {
|
||||
return [
|
||||
{ src: "http://example.com/blah/foo.js" },
|
||||
{ src: "http://example.com/blah/wat.js" },
|
||||
{ src: "http://example.com/blah/foo/bar.js" }
|
||||
];
|
||||
}
|
||||
};
|
||||
actual4 = _getCurrentScriptUrl();
|
||||
|
||||
_document = {
|
||||
getElementsByTagName: function(/* tagName */) {
|
||||
return [
|
||||
{ src: "http://example.com/blah/foo.js" },
|
||||
{ src: "http://example.com/blah/wat.js" },
|
||||
{ src: "http://example.com/blah/foo/bar.js" }
|
||||
];
|
||||
}
|
||||
};
|
||||
_getCurrentScriptUrlFromError = function() {
|
||||
return "http://example.com/blah/foo/bar.js";
|
||||
};
|
||||
actual5 = _getCurrentScriptUrl();
|
||||
|
||||
_document = {
|
||||
getElementsByTagName: function(/* tagName */) {
|
||||
return [
|
||||
{ src: "http://example.com/blah/foo.js" },
|
||||
{ src: "http://example.com/blah/wat.js" }
|
||||
];
|
||||
}
|
||||
};
|
||||
_getCurrentScriptUrlFromError = function() {};
|
||||
actual6 = _getCurrentScriptUrl();
|
||||
|
||||
_document = {
|
||||
getElementsByTagName: function(/* tagName */) {
|
||||
return [
|
||||
{ src: "http://example.com/blah/foo.js" },
|
||||
{ /* inline script */ },
|
||||
{ src: "http://example.com/blah/wat.js" }
|
||||
];
|
||||
}
|
||||
};
|
||||
actual7 = _getCurrentScriptUrl();
|
||||
|
||||
_document = {
|
||||
getElementsByTagName: function(/* tagName */) {
|
||||
return [
|
||||
{ src: "http://example.com/blah/foo.js" },
|
||||
{ src: "http://example.com/blah/wat.js" },
|
||||
{ /* inline script */ }
|
||||
];
|
||||
}
|
||||
};
|
||||
actual8 = _getCurrentScriptUrl();
|
||||
|
||||
_document = {
|
||||
getElementsByTagName: function(/* tagName */) {
|
||||
return [
|
||||
{ /* inline script */ }
|
||||
];
|
||||
}
|
||||
};
|
||||
actual9 = _getCurrentScriptUrl();
|
||||
|
||||
assert.strictEqual(actual1, expected1, "Value from `document.currentScript`");
|
||||
assert.strictEqual(actual2, expected2, "Value from the only script");
|
||||
assert.strictEqual(actual3, expected3, "Value from `scripts[i].readyState === \"interactive\"`");
|
||||
assert.strictEqual(actual4, expected4, "Value from last script while `document.readyState === \"loading\"");
|
||||
assert.strictEqual(actual5, expected5, "Value from `_getCurrentScriptUrlFromError`");
|
||||
assert.strictEqual(actual6, expected6, "No value can be confirmed");
|
||||
assert.strictEqual(actual7, expected7, "No value can be confirmed as there is at least one inline script (middle)");
|
||||
assert.strictEqual(actual8, expected8, "No value can be confirmed as there is at least one inline script (last)");
|
||||
assert.strictEqual(actual9, expected9, "No value can be confirmed as the only script tag is an inline script");
|
||||
});
|
||||
|
||||
|
||||
test("`_getUnanimousScriptParentDir` works", function(assert) {
|
||||
assert.expect(5);
|
||||
|
||||
// Arrange
|
||||
var actual1, actual2, actual3, actual4, actual5;
|
||||
var expected1, expected2, expected3, expected4, expected5;
|
||||
var _scripts = [];
|
||||
_document = {
|
||||
getElementsByTagName: function(/* tagName */) {
|
||||
return _scripts;
|
||||
}
|
||||
};
|
||||
expected1 = "http://example.com/blah/";
|
||||
|
||||
// Arrange & Act
|
||||
_scripts.length = 0;
|
||||
_scripts.push.apply(_scripts, [
|
||||
{ src: "http://example.com/blah/foo.js" },
|
||||
{ src: "http://example.com/blah/wat.js" },
|
||||
{ src: "http://example.com/blah/bar.js" }
|
||||
]);
|
||||
actual1 = _getUnanimousScriptParentDir();
|
||||
|
||||
_scripts.length = 0;
|
||||
_scripts.push.apply(_scripts, [
|
||||
{ src: "http://example.org/blah/foo.js" },
|
||||
{ src: "http://example.net/blah/wat.js" },
|
||||
{ src: "http://example.com/blah/bar.js" }
|
||||
]);
|
||||
actual2 = _getUnanimousScriptParentDir();
|
||||
|
||||
_scripts.length = 0;
|
||||
_scripts.push.apply(_scripts, [
|
||||
{ src: "http://example.com/blah/foo.js" },
|
||||
{ src: "http://example.com/blah/wat.js" },
|
||||
{ src: "http://example.com/blah/foo/bar.js" }
|
||||
]);
|
||||
actual3 = _getUnanimousScriptParentDir();
|
||||
|
||||
_scripts.length = 0;
|
||||
_scripts.push.apply(_scripts, [
|
||||
{ src: "http://example.com/blah/foo.js" },
|
||||
{ /* inline script */ },
|
||||
{ src: "http://example.com/blah/foo/bar.js" }
|
||||
]);
|
||||
actual4 = _getUnanimousScriptParentDir();
|
||||
|
||||
_scripts.length = 0;
|
||||
_scripts.push.apply(_scripts, [
|
||||
{ src: "http://example.com/blah/foo.js" },
|
||||
{ src: "http://example.com/blah/wat.js" },
|
||||
{ /* inline script */ }
|
||||
]);
|
||||
actual5 = _getUnanimousScriptParentDir();
|
||||
|
||||
// Assert
|
||||
assert.strictEqual(actual1, expected1, "All script tags have the same parent directory");
|
||||
assert.strictEqual(actual2, expected2, "Not all script tags have the same domains");
|
||||
assert.strictEqual(actual3, expected3, "Not all script tags have the same parent directory");
|
||||
assert.strictEqual(actual4, expected4, "Not all script tags have `src` URLs (middle)");
|
||||
assert.strictEqual(actual5, expected5, "Not all script tags have `src` URLs (last)");
|
||||
});
|
||||
|
||||
|
||||
test("`_getDefaultSwfPath` works", function(assert) {
|
||||
assert.expect(11);
|
||||
|
||||
// Arrange
|
||||
var actual1, actual2, actual3, actual4, actual5, actual6, actual7, actual8, actual9, actual10, actual11;
|
||||
var expected1, expected2, expected3, expected4, expected5, expected6, expected7, expected8, expected9, expected10, expected11;
|
||||
expected1 = expected2 = expected3 = expected4 = expected5 = "http://example.com/blah/foo/ZeroClipboard.swf";
|
||||
expected6 = "http://example.com/blah/ZeroClipboard.swf";
|
||||
expected7 = expected8 = expected9 = expected10 = expected11 = "ZeroClipboard.swf";
|
||||
|
||||
// Arrange & Act
|
||||
_document = {
|
||||
currentScript: {
|
||||
src: "http://example.com/blah/foo/bar.js"
|
||||
}
|
||||
};
|
||||
actual1 = _getDefaultSwfPath();
|
||||
|
||||
_document = {
|
||||
getElementsByTagName: function(/* tagName */) {
|
||||
return [
|
||||
{ src: "http://example.com/blah/foo/bar.js" }
|
||||
];
|
||||
}
|
||||
};
|
||||
actual2 = _getDefaultSwfPath();
|
||||
|
||||
_document = {
|
||||
getElementsByTagName: function(/* tagName */) {
|
||||
return [
|
||||
{ src: "http://example.com/blah/foo.js", readyState: "complete" },
|
||||
{ src: "http://example.com/blah/foo/bar.js", readyState: "interactive" }
|
||||
];
|
||||
}
|
||||
};
|
||||
actual3 = _getDefaultSwfPath();
|
||||
|
||||
_document = {
|
||||
readyState: "loading",
|
||||
getElementsByTagName: function(/* tagName */) {
|
||||
return [
|
||||
{ src: "http://example.com/blah/foo.js" },
|
||||
{ src: "http://example.com/blah/wat.js" },
|
||||
{ src: "http://example.com/blah/foo/bar.js" }
|
||||
];
|
||||
}
|
||||
};
|
||||
actual4 = _getDefaultSwfPath();
|
||||
|
||||
_document = {
|
||||
getElementsByTagName: function(/* tagName */) {
|
||||
return [
|
||||
{ src: "http://example.com/blah/foo.js" },
|
||||
{ src: "http://example.com/blah/wat.js" },
|
||||
{ src: "http://example.com/blah/foo/bar.js" }
|
||||
];
|
||||
}
|
||||
};
|
||||
_getCurrentScriptUrlFromError = function() {
|
||||
return "http://example.com/blah/foo/bar.js";
|
||||
};
|
||||
actual5 = _getDefaultSwfPath();
|
||||
|
||||
_document = {
|
||||
getElementsByTagName: function(/* tagName */) {
|
||||
return [
|
||||
{ src: "http://example.com/blah/foo.js" },
|
||||
{ src: "http://example.com/blah/wat.js" },
|
||||
{ src: "http://example.com/blah/bar.js" }
|
||||
];
|
||||
}
|
||||
};
|
||||
_getCurrentScriptUrlFromError = function() {};
|
||||
actual6 = _getDefaultSwfPath();
|
||||
|
||||
_document = {
|
||||
getElementsByTagName: function(/* tagName */) {
|
||||
return [
|
||||
{ src: "http://example.org/blah/foo.js" },
|
||||
{ src: "http://example.net/blah/wat.js" },
|
||||
{ src: "http://example.com/blah/bar.js" }
|
||||
];
|
||||
}
|
||||
};
|
||||
actual7 = _getDefaultSwfPath();
|
||||
|
||||
_document = {
|
||||
getElementsByTagName: function(/* tagName */) {
|
||||
return [
|
||||
{ src: "http://example.com/blah/foo.js" },
|
||||
{ src: "http://example.com/blah/wat.js" },
|
||||
{ src: "http://example.com/blah/foo/bar.js" }
|
||||
];
|
||||
}
|
||||
};
|
||||
actual8 = _getDefaultSwfPath();
|
||||
|
||||
_document = {
|
||||
getElementsByTagName: function(/* tagName */) {
|
||||
return [
|
||||
{ src: "http://example.com/blah/foo.js" },
|
||||
{ /* inline script */ },
|
||||
{ src: "http://example.com/blah/foo/bar.js" }
|
||||
];
|
||||
}
|
||||
};
|
||||
actual9 = _getDefaultSwfPath();
|
||||
|
||||
_document = {
|
||||
getElementsByTagName: function(/* tagName */) {
|
||||
return [
|
||||
{ src: "http://example.com/blah/foo.js" },
|
||||
{ src: "http://example.com/blah/wat.js" },
|
||||
{ /* inline script */ }
|
||||
];
|
||||
}
|
||||
};
|
||||
actual10 = _getDefaultSwfPath();
|
||||
|
||||
_document = {
|
||||
getElementsByTagName: function(/* tagName */) {
|
||||
return [
|
||||
{ /* inline script */ }
|
||||
];
|
||||
}
|
||||
};
|
||||
actual11 = _getDefaultSwfPath();
|
||||
|
||||
assert.strictEqual(actual1, expected1, "Value derived from `document.currentScript`");
|
||||
assert.strictEqual(actual2, expected2, "Value derived from the only script");
|
||||
assert.strictEqual(actual3, expected3, "Value derived from `scripts[i].readyState === \"interactive\"`");
|
||||
assert.strictEqual(actual4, expected4, "Value derived from last script while `document.readyState === \"loading\"");
|
||||
assert.strictEqual(actual5, expected5, "Value derived from Error stack");
|
||||
assert.strictEqual(actual6, expected6, "Value derived from confirming all scripts have the same parent directory");
|
||||
assert.strictEqual(actual7, expected7, "No value can be confirmed due to differing script domains");
|
||||
assert.strictEqual(actual8, expected8, "No value can be confirmed due to differing script parent directories");
|
||||
assert.strictEqual(actual9, expected9, "No value can be confirmed due to the existence of inline scripts");
|
||||
assert.strictEqual(actual10, expected10, "No value can be confirmed as the last script is an inline script");
|
||||
assert.strictEqual(actual11, expected11, "No value can be confirmed as the only script is an inline script");
|
||||
});
|
||||
|
||||
})(QUnit.module, QUnit.test);
|
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>ZeroClipboard unit tests: shared/private.js</title>
|
||||
<link rel="stylesheet" href="../../node_modules/qunitjs/qunit/qunit.css">
|
||||
<script src="../../node_modules/qunitjs/qunit/qunit.js"></script>
|
||||
<script>
|
||||
// Polyfill in future functionality: https://github.com/jquery/qunit/issues/490
|
||||
if (!QUnit.assert.expect) {
|
||||
QUnit.assert.expect = QUnit.expect;
|
||||
}
|
||||
|
||||
// Require `expect` calls
|
||||
QUnit.config.requireExpects = true;
|
||||
|
||||
// Prevent against Firefox/Firebug failing the global pollution check
|
||||
var getInterface = null;
|
||||
</script>
|
||||
<script src="../../src/js/shared/state.js"></script>
|
||||
<script src="../../src/js/shared/private.js"></script>
|
||||
<script src="private.tests.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture"></div>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user