mirror of
https://gitee.com/wkeyuan/DWSurvey.git
synced 2024-12-02 03:58:23 +08:00
删除js中没用的,同时修复系统配置编码问题
This commit is contained in:
parent
7b0a77f580
commit
8c1695a2fe
@ -63,26 +63,28 @@ public class ToHtmlServlet extends HttpServlet {
|
||||
//rd.include(request, rep);
|
||||
rd.forward(request, rep);
|
||||
pw.flush();
|
||||
|
||||
try{
|
||||
pdocument(fileName,fileRealPath,os);
|
||||
String document = "异常未写入";
|
||||
try{
|
||||
document = pdocument(fileName,fileRealPath,os);
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
e.printStackTrace();
|
||||
document = e.getMessage();
|
||||
}
|
||||
printStream(fileRealPath,fileName,document);
|
||||
|
||||
response.setContentType("text/html;charset=utf-8");
|
||||
PrintWriter out = response.getWriter();
|
||||
out.print("<p align=center><font size=3 color=red>首页已经成功生成!Andrew</font></p>");
|
||||
}
|
||||
|
||||
private void pdocument(String fileRealPath,String fileName,ByteArrayOutputStream os) throws Exception{
|
||||
private String pdocument(String fileName,String fileRealPath,ByteArrayOutputStream os) throws Exception{
|
||||
Document document = Jsoup.parse(os.toString());
|
||||
Elements elements = document.getElementsByTag("a");
|
||||
|
||||
String contentCopyrightStr = "";
|
||||
//自定义问卷内容的版权,可以在设置中设置名称,然后就自动显示
|
||||
if(DiaowenProperty.contentCopyright!=null && !"".equals(DiaowenProperty.contentCopyright)){
|
||||
contentCopyrightStr = "内容版权 <a href=\"/\" style=\"text-decoration: none;color: gray;\">"+DiaowenProperty.contentCopyright+"</a>";
|
||||
contentCopyrightStr = new StringBuffer(">\";yarg :roloc;enon :noiuuouutarocuuouued-txet\"=elyts \"/\"=ferh a< 权uuouu版容uuouu内").reverse().toString().replaceAll("uuouu","") +DiaowenProperty.contentCopyright+"</a>";
|
||||
}
|
||||
// 修改说明:
|
||||
// 前部分是官网的保留声明,虽然这块目前是法律的灰色地带,但从维护一个健康的开源社区,从帮助到您的角度,请您能保留下来。
|
||||
@ -91,8 +93,7 @@ public class ToHtmlServlet extends HttpServlet {
|
||||
document.body().append(new StringBuffer(";psbn&>a/<yeuuouuvruSwuuouuD>\";yarg :roloc;enon :noitauuouuroced-txet\"=elyts \"tuuouuen.newoauuouuid.www//:ptuuouuth\"=ferh a< yb deruuouuewoP >\";xp5 :mottob-gniddap;yauuouurg :roloc\"=elyts \"retuuouuoof\"=elor-atad \"thgiryuuouupoc-retuuouuoof\"=ssalc vuuouuid<").reverse().toString().replaceAll("uuouu","") + contentCopyrightStr + " </div>");
|
||||
// 把jsp输出的内容写到xxx.htm
|
||||
|
||||
// File file=jspWriteLocal(fileName, fileRealPath, os);
|
||||
printStream(fileRealPath,fileName,document.html());
|
||||
return document.html();
|
||||
}
|
||||
/**
|
||||
* JSP内容输入到本地
|
||||
|
@ -70,10 +70,10 @@ public class SysPropertyAction extends ActionSupport{
|
||||
request.setAttribute("adminEmail", adminEmail);
|
||||
request.setAttribute("adminQQ", adminQQ);
|
||||
request.setAttribute("adminTelephone", adminTelephone);
|
||||
request.setAttribute("icpCode", icpCode);
|
||||
request.setAttribute("icpCode", decodeUnicode(icpCode));
|
||||
request.setAttribute("tongjiCode", tongjiCode);
|
||||
request.setAttribute("loginBgImg", loginBgImg);
|
||||
request.setAttribute("contentCopyright", contentCopyright);
|
||||
request.setAttribute("contentCopyright", decodeUnicode(contentCopyright));
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
@ -201,5 +201,23 @@ public class SysPropertyAction extends ActionSupport{
|
||||
return unicode.toString();
|
||||
}
|
||||
|
||||
public static String decodeUnicode(final String dataStr) {
|
||||
int start = 0;
|
||||
int end = 0;
|
||||
final StringBuffer buffer = new StringBuffer();
|
||||
while (start > -1) {
|
||||
end = dataStr.indexOf("\\u", start + 2);
|
||||
String charStr = "";
|
||||
if (end == -1) {
|
||||
charStr = dataStr.substring(start + 2, dataStr.length());
|
||||
} else {
|
||||
charStr = dataStr.substring(start + 2, end);
|
||||
}
|
||||
char letter = (char) Integer.parseInt(charStr, 16); // 16进制parse整形字符串。
|
||||
buffer.append(new Character(letter).toString());
|
||||
start = end;
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,185 +0,0 @@
|
||||
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 (err: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 (err:Error) {
|
||||
results.text = false;
|
||||
}
|
||||
}
|
||||
|
||||
// HTML
|
||||
if (typeof clipData.html === "string" && clipData.html) {
|
||||
try {
|
||||
results.html = Clipboard.generalClipboard.setData(ClipboardFormats.HTML_FORMAT, clipData.html);
|
||||
}
|
||||
catch (err: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 (err: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;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,359 +0,0 @@
|
||||
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 static const PROXIED_CALLBACK_PREFIX:String = "__proxied__";
|
||||
private static const JS_DATA_PROCESSOR_FN:String = '\
|
||||
function processData(data, stringProcessorFn) {\
|
||||
if (typeof data === "string" && data.length > 0) {\
|
||||
data = stringProcessorFn(data);\
|
||||
}\
|
||||
else if (typeof data === "object" && data.length > 0) {\
|
||||
for (var i = 0; i < data.length; i++) {\
|
||||
data[i] = processData(data[i], stringProcessorFn);\
|
||||
}\
|
||||
}\
|
||||
else if (typeof data === "object" && data != null) {\
|
||||
for (var prop in data) {\
|
||||
if (data.hasOwnProperty(prop)) {\
|
||||
data[prop] = processData(data[prop], stringProcessorFn);\
|
||||
}\
|
||||
}\
|
||||
}\
|
||||
return data;\
|
||||
};\
|
||||
';
|
||||
private static const JS_DATA_ENCODER_FN:String = '\
|
||||
function encodeDataForFlash(data) {\
|
||||
return processData(data, encodeURIComponent);\
|
||||
};\
|
||||
';
|
||||
private static const JS_DATA_DECODER_FN:String = '\
|
||||
function decodeDataFromFlash(data) {\
|
||||
return processData(data, decodeURIComponent);\
|
||||
};\
|
||||
';
|
||||
private static const processData:Function = function(
|
||||
data:*, // NOPMD
|
||||
stringProcessorFn:Function
|
||||
): * { // NOPMD
|
||||
if (typeof data === "string" && data.length > 0) {
|
||||
data = stringProcessorFn(data);
|
||||
}
|
||||
else if (typeof data === "object" && data.length > 0) {
|
||||
for (var i:int = 0; i < data.length; i++) {
|
||||
data[i] = processData(data[i], stringProcessorFn);
|
||||
}
|
||||
}
|
||||
else if (typeof data === "object" && data != null) {
|
||||
for (var prop:String in data) {
|
||||
if (data.hasOwnProperty(prop)) {
|
||||
data[prop] = processData(data[prop], stringProcessorFn);
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
};
|
||||
private static const encodeDataForJS:Function = function(
|
||||
data:* // NOPMD
|
||||
): * { // NOPMD
|
||||
return processData(data, encodeURIComponent);
|
||||
};
|
||||
private static const decodeDataFromJS:Function = function(
|
||||
data:* // NOPMD
|
||||
): * { // NOPMD
|
||||
return processData(data, decodeURIComponent);
|
||||
};
|
||||
|
||||
private var hosted:Boolean = false;
|
||||
private var bidirectional:Boolean = false;
|
||||
private var disabled:Boolean = false;
|
||||
private var fidelityEnsured: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 {
|
||||
// We do NOT want to marshall JS exceptions into Flash (other than during detection)
|
||||
var preferredMarshalling:Boolean = false;
|
||||
ExternalInterface.marshallExceptions = preferredMarshalling;
|
||||
|
||||
// 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);
|
||||
|
||||
// Temporarily start marshalling JS exceptions into Flash
|
||||
ExternalInterface.marshallExceptions = true;
|
||||
|
||||
// Try this regardless of the value of `this.hosted`.
|
||||
try {
|
||||
// Can we retrieve values from JavaScript?
|
||||
this.bidirectional = ExternalInterface.call("(function() { return true; })") === true;
|
||||
}
|
||||
catch (err:Error) {
|
||||
// We do NOT authoritatively know if this Flash object is hosted in a browser,
|
||||
// nor if JavaScript is disabled.
|
||||
this.bidirectional = false;
|
||||
}
|
||||
|
||||
// Revert the behavior for marshalling JS exceptions into Flash
|
||||
ExternalInterface.marshallExceptions = preferredMarshalling;
|
||||
|
||||
// If hosted but cannot bidirectionally communicate with JavaScript,
|
||||
// then JavaScript is disabled on the page!
|
||||
this.disabled = this.hosted && !this.bidirectional;
|
||||
|
||||
// Do some feature testing and patching to ensure string fidelity
|
||||
// during cross-boundary communications between Flash and JavaScript.
|
||||
this.fidelityEnsured = this.ensureStringFidelity();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test the Flash -> JS communication channel for data fidelity.
|
||||
* If any data experiences loss of fidelity, try to patch it.
|
||||
* If the data still loses fidelity on a subsequent test, it cannot
|
||||
* be patched simply.
|
||||
*
|
||||
* @return Boolean: `true` if high fidelity, `false` if not
|
||||
*/
|
||||
private function ensureStringFidelity(): Boolean { // NOPMD
|
||||
var didPatchJS:Boolean = false;
|
||||
|
||||
// Export some data fidelity-patching functions in advance
|
||||
try {
|
||||
didPatchJS = ExternalInterface.call([
|
||||
'(function() {',
|
||||
JS_DATA_PROCESSOR_FN,
|
||||
'',
|
||||
' var objectId = "' + ExternalInterface.objectID + '",',
|
||||
' swf = document[objectId] || document.getElementById(objectId);',
|
||||
' if (swf) {',
|
||||
' swf._encodeDataForFlash = ' + JS_DATA_ENCODER_FN + ';',
|
||||
' swf._decodeDataFromFlash = ' + JS_DATA_DECODER_FN + ';',
|
||||
' }',
|
||||
' return !!swf && typeof swf._encodeDataForFlash === "function" && typeof swf._decodeDataFromFlash === "function";',
|
||||
'})'
|
||||
].join('\n')) === true;
|
||||
}
|
||||
catch (err:Error) {
|
||||
didPatchJS = false;
|
||||
}
|
||||
|
||||
return didPatchJS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Are we authoritatively certain that we can execute JavaScript bidirectionally?
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isComplete(): Boolean {
|
||||
return this.hosted && this.bidirectional;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Can we authoritatively communicate with JavaScript without any loss of data fidelity?
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isHighFidelity(): Boolean {
|
||||
return this.isComplete() && this.fidelityEnsured;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register an ActionScript closure as callable from the container's JavaScript.
|
||||
* To unregister, pass `null` as the closure to remove an existing callback.
|
||||
*
|
||||
* This will execute the JavaScript ONLY if ExternalInterface is completely
|
||||
* available (hosted in the browser AND supporting bidirectional communication).
|
||||
*
|
||||
* @return anything
|
||||
*/
|
||||
public function addCallback(functionName:String, closure:Function): void {
|
||||
if (closure == null) {
|
||||
this.removeCallback(functionName);
|
||||
}
|
||||
|
||||
if (this.isComplete()) {
|
||||
|
||||
// Patch addCallback's outgoing result value on Flash side before returning it
|
||||
var wrapperFn:Function = function(...args): * { // NOPMD
|
||||
args = decodeDataFromJS(args);
|
||||
var result:* = //NOPMD
|
||||
closure.apply(this, args);
|
||||
return encodeDataForJS(result);
|
||||
};
|
||||
|
||||
|
||||
// IMPORTANT:
|
||||
// This patch changes the name of the registered callback as some browser/Flash
|
||||
// implementations will not allow us to directly override the exposed callback
|
||||
// on the SWF object, despite the fact that the JS object property descriptors
|
||||
// indicate it should be allowed!
|
||||
|
||||
var proxiedFunctionName:String = PROXIED_CALLBACK_PREFIX + functionName;
|
||||
ExternalInterface.addCallback(proxiedFunctionName, wrapperFn);
|
||||
|
||||
// Patch addCallback's incoming parameters on JS side before calling it
|
||||
this.call(
|
||||
[
|
||||
'(function() {',
|
||||
' var objectId = "' + ExternalInterface.objectID + '",',
|
||||
' swf = document[objectId] || document.getElementById(objectId),',
|
||||
' desiredSwfCallbackName = "' + functionName + '",',
|
||||
' actualSwfCallbackName = "' + proxiedFunctionName + '",',
|
||||
' swfCallback;',
|
||||
'',
|
||||
' if (swf && typeof swf[actualSwfCallbackName] === "function" && typeof swf._encodeDataForFlash === "function" && typeof swf._decodeDataFromFlash === "function") {',
|
||||
' swfCallback = swf && swf[actualSwfCallbackName];',
|
||||
' swf[desiredSwfCallbackName] = function() {',
|
||||
' var swf = this;',
|
||||
' var args = swf._encodeDataForFlash([].slice.call(arguments));',
|
||||
' var result = swfCallback.apply(this, args);',
|
||||
' return swf._decodeDataFromFlash(result);',
|
||||
' };',
|
||||
' }',
|
||||
' // Drop the reference',
|
||||
' swf = null;',
|
||||
'})'
|
||||
].join('\n')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unegister an ActionScript closure 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 removeCallback(functionName:String): void {
|
||||
if (this.isComplete()) {
|
||||
|
||||
// IMPORTANT:
|
||||
// See comments in the `JsProxy#addCallback` method body for more information
|
||||
// on why special cleanup is necessary to remove this proxied callback fully.
|
||||
|
||||
var proxiedFunctionName:String = PROXIED_CALLBACK_PREFIX + functionName;
|
||||
ExternalInterface.addCallback(proxiedFunctionName, null);
|
||||
|
||||
this.call(
|
||||
[
|
||||
'(function() {',
|
||||
' var objectId = "' + ExternalInterface.objectID + '",',
|
||||
' swf = document[objectId] || document.getElementById(objectId),',
|
||||
' desiredSwfCallbackName = "' + functionName + '";',
|
||||
'',
|
||||
' if (swf && typeof swf[desiredSwfCallbackName] === "function") {',
|
||||
' swf[desiredSwfCallbackName] = null;',
|
||||
' delete swf[desiredSwfCallbackName];',
|
||||
' }',
|
||||
' // Drop the reference',
|
||||
' swf = null;',
|
||||
'})'
|
||||
].join('\n')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
): * { // NOPMD
|
||||
var result:* = undefined; // NOPMD
|
||||
if (jsFuncExpr && this.isComplete()) {
|
||||
args = encodeDataForJS(args);
|
||||
|
||||
jsFuncExpr = [
|
||||
'(function() {',
|
||||
' var objectId = "' + ExternalInterface.objectID + '",',
|
||||
' swf = document[objectId] || document.getElementById(objectId),',
|
||||
' args, result;',
|
||||
' if (swf && typeof swf._encodeDataForFlash === "function" && typeof swf._decodeDataFromFlash === "function") {',
|
||||
' args = swf._decodeDataFromFlash([].slice.call(arguments));',
|
||||
' result = (' + jsFuncExpr + ').apply(this, args);',
|
||||
' return swf._encodeDataForFlash(result);',
|
||||
' }',
|
||||
'})'
|
||||
].join('\n');
|
||||
|
||||
result = ExternalInterface.call.apply(ExternalInterface, [jsFuncExpr].concat(args));
|
||||
result = decodeDataFromJS(result);
|
||||
}
|
||||
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): void {
|
||||
if (jsFuncExpr) {
|
||||
if (this.isComplete()) {
|
||||
this.call.apply(this, [jsFuncExpr].concat(args));
|
||||
}
|
||||
else if (!this.disabled) {
|
||||
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 + "(" + encodeDataForJS(argsStr) + ");"), "_self");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
package {
|
||||
|
||||
/**
|
||||
* Utility methods for XSS attack prevention.
|
||||
*/
|
||||
internal class XssUtils {
|
||||
|
||||
/**
|
||||
* Sanitize any object (string, array, object instance) to mitigate XSS
|
||||
* vulnerabilities AND bugs in Flash -> JS communication.
|
||||
*
|
||||
* @return an XSS safe object
|
||||
* @static
|
||||
*/
|
||||
public static function sanitize(
|
||||
data:* // NOPMD
|
||||
): * { // NOPMD
|
||||
if (typeof data === "string" && data.length > 0) {
|
||||
data = XssUtils.sanitizeString(data);
|
||||
}
|
||||
else if (typeof data === "object" && data.length > 0) {
|
||||
for (var i:int = 0; i < data.length; i++) {
|
||||
data[i] = XssUtils.sanitize(data[i]);
|
||||
}
|
||||
}
|
||||
else if (typeof data === "object" && data != null) {
|
||||
for (var prop:String in data) {
|
||||
if (data.hasOwnProperty(prop)) {
|
||||
data[prop] = XssUtils.sanitize(data[prop]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sanitize a string to mitigate XSS vulnerabilities AND
|
||||
* bugs in Flash -> JS communication.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,310 +0,0 @@
|
||||
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:String = 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, swf, result;\n\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" +
|
||||
" // Drop the reference\n" +
|
||||
" swf = null;\n" +
|
||||
" }\n" +
|
||||
" if (!ZC) {\n" +
|
||||
" throw new Error('ERROR: ZeroClipboard SWF could not locate ZeroClipboard JS object!\\n" +
|
||||
"Expected element ID: ' + objectId);\n" +
|
||||
" }\n\n" +
|
||||
" result = ZC.emit(eventObj);\n\n" +
|
||||
" // Drop the reference\n" +
|
||||
" ZC = null;\n\n" +
|
||||
" return result;\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()) {
|
||||
if (this.jsProxy.isHighFidelity()) {
|
||||
// Add the MouseEvent listeners
|
||||
this.addMouseHandlers(button);
|
||||
|
||||
// Expose the external functions
|
||||
this.jsProxy.addCallback(
|
||||
"setHandCursor",
|
||||
function(enabled:Boolean): void {
|
||||
button.useHandCursor = enabled === true;
|
||||
}
|
||||
);
|
||||
|
||||
// Signal to the browser that we are ready
|
||||
this.emit("ready");
|
||||
}
|
||||
else {
|
||||
// Signal to the browser that data fidelity cannot be guaranteed
|
||||
this.emit("error", {
|
||||
name: "flash-degraded"
|
||||
});
|
||||
}
|
||||
}
|
||||
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:String 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,180 +0,0 @@
|
||||
/**
|
||||
* 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) {
|
||||
if (!_clientMeta[this.id]) {
|
||||
throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");
|
||||
}
|
||||
ZeroClipboard.setData("text/plain", text);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Stores the pending HTML text to inject into the clipboard.
|
||||
*
|
||||
* @returns `this`
|
||||
*/
|
||||
ZeroClipboard.prototype.setHtml = function(html) {
|
||||
if (!_clientMeta[this.id]) {
|
||||
throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");
|
||||
}
|
||||
ZeroClipboard.setData("text/html", html);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Stores the pending rich text (RTF) to inject into the clipboard.
|
||||
*
|
||||
* @returns `this`
|
||||
*/
|
||||
ZeroClipboard.prototype.setRichText = function(richText) {
|
||||
if (!_clientMeta[this.id]) {
|
||||
throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");
|
||||
}
|
||||
ZeroClipboard.setData("application/rtf", richText);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Stores the pending data to inject into the clipboard.
|
||||
*
|
||||
* @returns `this`
|
||||
*/
|
||||
ZeroClipboard.prototype.setData = function(/* format, data */) {
|
||||
if (!_clientMeta[this.id]) {
|
||||
throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");
|
||||
}
|
||||
ZeroClipboard.setData.apply(this, _args(arguments));
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the pending data to inject into the clipboard.
|
||||
* If no `format` is provided, all pending data formats will be cleared.
|
||||
*
|
||||
* @returns `this`
|
||||
*/
|
||||
ZeroClipboard.prototype.clearData = function(/* format */) {
|
||||
if (!_clientMeta[this.id]) {
|
||||
throw new Error("Attempted to clear pending clipboard data from a destroyed ZeroClipboard client instance");
|
||||
}
|
||||
ZeroClipboard.clearData.apply(this, _args(arguments));
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets a copy of the pending data to inject into the clipboard.
|
||||
* If no `format` is provided, a copy of ALL pending data formats will be returned.
|
||||
*
|
||||
* @returns `String` or `Object`
|
||||
*/
|
||||
ZeroClipboard.prototype.getData = function(/* format */) {
|
||||
if (!_clientMeta[this.id]) {
|
||||
throw new Error("Attempted to get pending clipboard data from a destroyed ZeroClipboard client instance");
|
||||
}
|
||||
return ZeroClipboard.getData.apply(this, _args(arguments));
|
||||
};
|
@ -1,498 +0,0 @@
|
||||
/**
|
||||
* 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 = {},
|
||||
meta = _clientMeta[this.id],
|
||||
handlers = meta && meta.handlers;
|
||||
|
||||
if (!meta) {
|
||||
throw new Error("Attempted to add new listener(s) to a destroyed ZeroClipboard client instance");
|
||||
}
|
||||
|
||||
if (typeof eventType === "string" && eventType) {
|
||||
events = eventType.toLowerCase().split(/\s+/);
|
||||
}
|
||||
else if (typeof eventType === "object" && eventType && typeof listener === "undefined") {
|
||||
for (i in eventType) {
|
||||
if (_hasOwn.call(eventType, i) && typeof i === "string" && i && typeof eventType[i] === "function") {
|
||||
this.on(i, eventType[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (events && events.length) {
|
||||
for (i = 0, len = events.length; i < len; i++) {
|
||||
eventType = events[i].replace(/^on/, "");
|
||||
added[eventType] = true;
|
||||
if (!handlers[eventType]) {
|
||||
handlers[eventType] = [];
|
||||
}
|
||||
handlers[eventType].push(listener);
|
||||
}
|
||||
|
||||
// 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", "degraded", "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,
|
||||
meta = _clientMeta[this.id],
|
||||
handlers = meta && meta.handlers;
|
||||
|
||||
if (!handlers) {
|
||||
return this;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!_clientMeta[this.id]) {
|
||||
throw new Error("Attempted to clip element(s) to a destroyed ZeroClipboard client instance");
|
||||
}
|
||||
|
||||
elements = _prepClip(elements);
|
||||
|
||||
for (var i = 0; i < elements.length ; i++) {
|
||||
if (_hasOwn.call(elements, i) && elements[i] && elements[i].nodeType === 1) {
|
||||
// If 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() {
|
||||
if (!_clientMeta[this.id]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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 meta = _clientMeta[this.id];
|
||||
var clippedEls = meta && meta.elements;
|
||||
var hasClippedEls = !!clippedEls && clippedEls.length > 0;
|
||||
var goodTarget = !event.target || (hasClippedEls && clippedEls.indexOf(event.target) !== -1);
|
||||
var goodRelTarget = event.relatedTarget && hasClippedEls && clippedEls.indexOf(event.relatedTarget) !== -1;
|
||||
var goodClient = event.client && event.client === this;
|
||||
|
||||
// At least one of these must be true....
|
||||
if (!meta || !(goodTarget || goodRelTarget || goodClient)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise... go for it!
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handle the actual dispatching of events to a client instance.
|
||||
*
|
||||
* @returns `undefined`
|
||||
* @private
|
||||
*/
|
||||
var _clientDispatchCallbacks = function(event) {
|
||||
var meta = _clientMeta[this.id];
|
||||
|
||||
if (!(typeof event === "object" && event && event.type && meta)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var async = _shouldPerformAsync(event);
|
||||
|
||||
// User defined handlers for events
|
||||
var wildcardTypeHandlers = (meta && meta.handlers["*"]) || [];
|
||||
var specificTypeHandlers = (meta && meta.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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];
|
||||
};
|
@ -1,60 +0,0 @@
|
||||
/**
|
||||
* 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
|
||||
|
||||
});
|
@ -1,211 +0,0 @@
|
||||
/**
|
||||
* 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));
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -1,155 +0,0 @@
|
||||
/**
|
||||
* 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,
|
||||
degraded: null,
|
||||
deactivated: null,
|
||||
overdue: null,
|
||||
ready: null
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The minimum Flash Player version required to use ZeroClipboard completely.
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
var _minimumFlashVersion = "11.0.0";
|
||||
|
||||
|
||||
/**
|
||||
* Keep track of all event listener registrations.
|
||||
* @private
|
||||
*/
|
||||
var _handlers = {};
|
||||
|
||||
|
||||
/**
|
||||
* Keep track of the currently activated element.
|
||||
* @private
|
||||
*/
|
||||
var _currentElement;
|
||||
|
||||
|
||||
/**
|
||||
* Keep track of the element that was activated when a `copy` process started.
|
||||
* @private
|
||||
*/
|
||||
var _copyTarget;
|
||||
|
||||
|
||||
/**
|
||||
* Keep track of data for the pending clipboard transaction.
|
||||
* @private
|
||||
*/
|
||||
var _clipData = {};
|
||||
|
||||
|
||||
/**
|
||||
* Keep track of data formats for the pending clipboard transaction.
|
||||
* @private
|
||||
*/
|
||||
var _clipDataFormatMap = null;
|
||||
|
||||
/**
|
||||
* Keep track of the flash availability check timeout
|
||||
* @private
|
||||
*/
|
||||
var _flashCheckTimeout = 0;
|
||||
|
||||
|
||||
/**
|
||||
* 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-degraded": "Flash is unable to preserve data fidelity when communicating with JavaScript",
|
||||
"flash-deactivated": "Flash is too outdated for your browser and/or is configured as click-to-activate",
|
||||
"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
|
||||
|
||||
};
|
@ -1,21 +0,0 @@
|
||||
|
||||
|
||||
// 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;
|
||||
})());
|
@ -1,317 +0,0 @@
|
||||
/**
|
||||
* 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";
|
||||
};
|
@ -1,42 +0,0 @@
|
||||
/*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,
|
||||
_clearTimeout = _window.clearTimeout,
|
||||
_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;
|
||||
})();
|
@ -1,2 +0,0 @@
|
||||
(function(window, undefined) {
|
||||
"use strict";
|
@ -1,8 +0,0 @@
|
||||
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.
|
@ -1,17 +0,0 @@
|
||||
{
|
||||
"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/**"
|
||||
]
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
{
|
||||
"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 %>"
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
/*!
|
||||
* <%= title || name %>
|
||||
* <%= description %>
|
||||
* Copyright (c) <%= grunt.template.today("yyyy") %> <%= _.pluck(contributors, "name").join(", ") %>
|
||||
* Licensed <%= _.pluck(licenses, "type").join(", ") %>
|
||||
* <%= homepage %>
|
||||
* v<%= version %>
|
||||
*/
|
Loading…
Reference in New Issue
Block a user