aframe-colorwheel-component
Version:
A-Frame Color Wheel component, designed for A-Frame Material
1,655 lines (1,470 loc) • 58.8 kB
JavaScript
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "/dist/";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1);
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var _copyToClipboard = __webpack_require__(2);
var _copyToClipboard2 = _interopRequireDefault(_copyToClipboard);
var _lodash = __webpack_require__(4);
var _lodash2 = _interopRequireDefault(_lodash);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Colorwheel for A-FRAME Material
* @author Mo Kargas (DEVLAD) mo@devlad.com
*/
var Event = __webpack_require__(5);
AFRAME.registerComponent('colorwheel', {
dependencies: ['raycaster'],
tweenDuration: 280,
tweenEasing: TWEEN.Easing.Cubic.Out,
padding: 0.15,
hsv: {
h: 0.0,
s: 0.0,
v: 1.0
},
defaultMaterial: {
color: '#ffffff',
flatShading: true,
transparent: true,
shader: 'flat',
fog: false,
side: 'double'
},
color: '#ffffff',
schema: {
disabled: {
type: 'boolean',
default: false
},
backgroundColor: {
type: 'color',
default: '#FFF'
},
//Size of the colorWheel. NOTE: Assumed in metres.
wheelSize: {
type: 'number',
default: 0.4
},
//Show color choice in an element
showSelection: {
type: 'boolean',
default: true
},
selectionSize: {
type: 'number',
default: 0.10
},
showHexValue: {
type: 'boolean',
default: false
},
showSwatches: {
type: 'boolean',
default: false
},
swatches: {
type: 'array',
default: ['#000000', '#FFFFFF', '#ff0045', '#2aa8dc', '#ffed00', '#4c881d', '#b14bff']
}
},
init: function init() {
var _this = this;
var that = this,
padding = this.padding,
defaultMaterial = this.defaultMaterial;
this.swatchReady = false;
//Background color of this interface
//TODO: Expose sizing for deeper customisation?
this.backgroundWidth = this.backgroundHeight = this.data.wheelSize * 2;
this.brightnessSliderHeight = (this.data.wheelSize + padding) * 2;
this.brightnessSliderWidth = 0.10;
//Check if we have the a-rounded component
if (AFRAME.components.hasOwnProperty('rounded')) {
this.background = document.createElement('a-rounded');
this.background.setAttribute('radius', 0.02);
this.background.setAttribute('position', {
x: -(this.data.wheelSize + padding),
y: -(this.data.wheelSize + padding),
z: -0.001
});
} else {
this.background = document.createElement('a-plane');
this.background.setAttribute('position', {
x: 0,
y: 0,
z: -0.001
});
}
this.background.setAttribute('width', this.backgroundWidth + 2 * padding);
this.background.setAttribute('height', this.backgroundHeight + 2 * padding);
this.background.setAttribute('material', 'shader', 'flat');
this.background.setAttribute('side', 'double');
this.el.appendChild(this.background);
//Show Swatches
this.swatchContainer = document.createElement('a-plane');
this.swatchContainer.setAttribute('class', 'swatch-container');
this.swatchContainer.setAttribute('material', this.defaultMaterial);
this.swatchContainer.addEventListener('loaded', this.onSwatchReady.bind(this));
//Give swatch panel a rakish angle
this.swatchContainer.setAttribute('rotation', {
x: -30,
y: 0,
z: 0
});
this.el.appendChild(this.swatchContainer);
//Show hex value display
if (this.data.showHexValue) {
var hexValueHeight = 0.1,
hexValueWidth = 2 * (this.data.wheelSize + padding);
this.hexValueText = document.createElement('a-entity');
//A basic geo is required for interactions
this.hexValueText.setAttribute('geometry', {
primitive: 'plane',
width: hexValueWidth - this.brightnessSliderWidth,
height: hexValueHeight
});
this.hexValueText.setAttribute('material', defaultMaterial);
this.hexValueText.setAttribute('position', {
x: -this.brightnessSliderWidth,
y: this.data.wheelSize + hexValueHeight,
z: 0.0
});
this.hexValueText.setAttribute('material', 'opacity', 0);
this.hexValueText.setAttribute('text', {
width: hexValueWidth,
height: hexValueHeight,
align: 'right',
baseline: 'center',
wrapCount: 20.4,
color: '#666'
});
//Copy value to clipboard on click
this.hexValueText.addEventListener('click', this.onHexValueClicked.bind(this));
this.el.appendChild(this.hexValueText);
}
//Circle for colorwheel
this.colorWheel = document.createElement('a-circle');
this.colorWheel.setAttribute('radius', this.data.wheelSize);
this.colorWheel.setAttribute('material', defaultMaterial);
this.colorWheel.setAttribute('position', {
x: 0,
y: 0,
z: 0.001
});
this.el.appendChild(this.colorWheel);
//Plane for the brightness slider
this.brightnessSlider = document.createElement('a-plane');
this.brightnessSlider.setAttribute('width', this.brightnessSliderWidth);
this.brightnessSlider.setAttribute('height', this.brightnessSliderHeight);
this.brightnessSlider.setAttribute('material', defaultMaterial);
this.brightnessSlider.setAttribute('position', {
x: this.data.wheelSize + this.brightnessSliderWidth,
y: 0,
z: 0.001
});
this.el.appendChild(this.brightnessSlider);
//Plane the color selection element will inhabit
if (this.data.showSelection) {
this.selectionEl = document.createElement('a-circle');
this.selectionEl.setAttribute('radius', this.data.selectionSize);
this.selectionEl.setAttribute('material', defaultMaterial);
//Place in top left, lift slightly
this.selectionEl.setAttribute('position', {
x: -this.data.wheelSize,
y: this.data.wheelSize,
z: 0.001
});
this.el.appendChild(this.selectionEl);
}
//Color 'cursor'. We'll use this to indicate a rough color selection
this.colorCursorOptions = {
cursorRadius: 0.025,
cursorSegments: 32,
cursorColor: new THREE.Color(0x000000)
};
this.colorCursorOptions.cursorMaterial = new THREE.MeshBasicMaterial({
color: this.colorCursorOptions.cursorColor,
transparent: true
});
this.colorCursor = document.createElement('a-entity');
this.brightnessCursor = document.createElement('a-entity');
var geometry = new THREE.TorusBufferGeometry(this.colorCursorOptions.cursorRadius, this.colorCursorOptions.cursorRadius - 0.02, this.colorCursorOptions.cursorSegments, this.colorCursorOptions.cursorSegments / 4);
this.colorCursor.setObject3D('mesh', new THREE.Mesh(geometry, this.colorCursorOptions.cursorMaterial));
this.brightnessCursor.setObject3D('mesh', new THREE.Mesh(geometry, this.colorCursorOptions.cursorMaterial));
this.el.appendChild(this.colorCursor);
this.brightnessSlider.appendChild(this.brightnessCursor);
this.brightnessCursor.setAttribute('position', {
x: 0,
y: this.brightnessSliderHeight / 2,
z: 0
});
//Handlers
this.bindMethods();
//TODO: Replace setTimeout as it can be unreliable
setTimeout(function () {
that.el.initColorWheel();
that.el.initBrightnessSlider();
that.el.refreshRaycaster();
if (that.data.showSwatches) that.el.generateSwatches(that.data.swatches);
that.colorWheel.addEventListener('click', _this.onColorWheelClicked.bind(_this));
that.brightnessSlider.addEventListener('click', _this.onBrightnessSliderClicked.bind(_this));
}, 5);
},
//Util to animate between positions. Item represents a mesh or object containing a position
setPositionTween: function setPositionTween(item, fromPosition, toPosition) {
this.tween = new TWEEN.Tween(fromPosition).to(toPosition, this.tweenDuration).onUpdate(function () {
item.position.x = this.x;
item.position.y = this.y;
item.position.z = this.z;
}).easing(this.tweenEasing).start();
return this.tween;
},
//Util to animate between colors. Item represents a mesh or object's material
setColorTween: function setColorTween(item, fromColor, toColor) {
this.tween = new TWEEN.Tween(new THREE.Color(fromColor)).to(toColor, this.tweenDuration).onUpdate(function () {
item.color.r = this.r;
item.color.g = this.g;
item.color.b = this.b;
}).easing(this.tweenEasing).start();
return this.tween;
},
onColorWheelClicked: function onColorWheelClicked(evt) {
if (this.data.disabled) return;
this.el.onHueDown(evt.detail.intersection.point);
},
onBrightnessSliderClicked: function onBrightnessSliderClicked(evt) {
if (this.data.disabled) return;
this.el.onBrightnessDown(evt.detail.intersection.point);
},
onHexValueClicked: function onHexValueClicked() {
(0, _copyToClipboard2.default)(this.hexValueText.getAttribute('text').value);
},
generateSwatches: function generateSwatches(swatchData) {
//Generate clickable swatch elements from a given array
if (swatchData === undefined) return;
var containerWidth = (this.data.wheelSize + this.padding) * 2,
containerHeight = 0.15,
swatchWidth = containerWidth / swatchData.length;
this.swatchContainer.setAttribute('width', containerWidth);
this.swatchContainer.setAttribute('height', containerHeight);
this.swatchContainer.setAttribute('position', {
x: 0,
y: -this.backgroundHeight + containerHeight,
z: 0.03
});
//Loop through swatches and create elements
for (var i = 0; i < swatchData.length; i++) {
var color = swatchData[i];
var swatch = document.createElement('a-plane');
swatch.setAttribute('material', this.defaultMaterial);
swatch.setAttribute('width', swatchWidth);
swatch.setAttribute('height', containerHeight);
swatch.setAttribute('color', color);
swatch.setAttribute('class', 'swatch');
swatch.setAttribute('position', {
x: -(containerWidth - swatchWidth) / 2 + i * swatchWidth,
y: 0,
z: 0.001 //prevent z-fighting
});
swatch.addEventListener('click', this.onSwatchClicked.bind(this, color));
this.swatchContainer.appendChild(swatch);
}
this.el.refreshRaycaster();
},
bindMethods: function bindMethods() {
this.el.generateSwatches = this.generateSwatches.bind(this);
this.el.initColorWheel = this.initColorWheel.bind(this);
this.el.initBrightnessSlider = this.initBrightnessSlider.bind(this);
this.el.updateColor = this.updateColor.bind(this);
this.el.onHueDown = this.onHueDown.bind(this);
this.el.onBrightnessDown = this.onBrightnessDown.bind(this);
this.el.refreshRaycaster = this.refreshRaycaster.bind(this);
this.el.clearSwatches = this.clearSwatches.bind(this);
},
onSwatchReady: function onSwatchReady() {
this.swatchReady = true;
},
clearSwatches: function clearSwatches() {
if (this.swatchReady) while (this.swatchContainer.firstChild) {
this.swatchContainer.removeChild(this.swatchContainer.firstChild);
}
},
refreshRaycaster: function refreshRaycaster() {
var raycasterEl = AFRAME.scenes[0].querySelector('[raycaster]');
raycasterEl.components.raycaster.refreshObjects();
},
initBrightnessSlider: function initBrightnessSlider() {
/*
* NOTE:
*
* In A-Painter, the brightness slider is actually a model submesh / element.
* Here we generate it using GLSL and add it to our plane material
*/
var vertexShader = '\n varying vec2 vUv;\n void main(){\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);\n }\n ';
var fragmentShader = '\n uniform vec3 color1;\n uniform vec3 color2;\n varying vec2 vUv;\n\n void main(){\n vec4 c1 = vec4(color1, 1.0);\n \t vec4 c2 = vec4(color2, 1.0);\n\n vec4 color = mix(c2, c1, smoothstep(0.0, 1.0, vUv.y));\n gl_FragColor = color;\n }\n ';
var material = new THREE.ShaderMaterial({
uniforms: {
color1: {
type: 'c',
value: new THREE.Color(0xFFFFFF)
},
color2: {
type: 'c',
value: new THREE.Color(0x000000)
}
},
vertexShader: vertexShader,
fragmentShader: fragmentShader
});
this.brightnessSlider.getObject3D('mesh').material = material;
this.brightnessSlider.getObject3D('mesh').material.needsUpdate = true;
},
initColorWheel: function initColorWheel() {
var colorWheel = this.colorWheel.getObject3D('mesh');
var vertexShader = '\n\n varying vec2 vUv;\n void main() {\n vUv = uv;\n vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);\n gl_Position = projectionMatrix * mvPosition;\n }\n ';
var fragmentShader = '\n #define M_PI2 6.28318530718\n uniform float brightness;\n varying vec2 vUv;\n vec3 hsb2rgb(in vec3 c){\n vec3 rgb = clamp(abs(mod(c.x * 6.0 + vec3(0.0, 4.0, 2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0 );\n rgb = rgb * rgb * (3.0 - 2.0 * rgb);\n return c.z * mix( vec3(1.0), rgb, c.y);\n }\n\n void main() {\n vec2 toCenter = vec2(0.5) - vUv;\n float angle = atan(toCenter.y, toCenter.x);\n float radius = length(toCenter) * 2.0;\n vec3 color = hsb2rgb(vec3((angle / M_PI2) + 0.5, radius, brightness));\n gl_FragColor = vec4(color, 1.0);\n }\n ';
var material = new THREE.ShaderMaterial({
uniforms: {
brightness: {
type: 'f',
value: this.hsv.v
}
},
vertexShader: vertexShader,
fragmentShader: fragmentShader
});
colorWheel.material = material;
colorWheel.material.needsUpdate = true;
},
onSwatchClicked: function onSwatchClicked(color) {
var colorWheel = this.colorWheel.getObject3D('mesh'),
brightnessCursor = this.brightnessCursor.getObject3D('mesh'),
brightnessSlider = this.brightnessSlider.getObject3D('mesh');
var rgb = this.hexToRgb(color);
this.hsv = this.rgbToHsv(rgb.r, rgb.g, rgb.b);
var angle = this.hsv.h * 2 * Math.PI,
radius = this.hsv.s * this.data.wheelSize;
var x = radius * Math.cos(angle),
y = radius * Math.sin(angle),
z = colorWheel.position.z;
var colorPosition = new THREE.Vector3(x, y, z);
colorWheel.localToWorld(colorPosition);
//We can reuse hueDown for this
this.onHueDown(colorPosition);
//Need to do the reverse of onbrightnessdown
var offset = this.hsv.v * this.brightnessSliderHeight;
var bY = offset - this.brightnessSliderHeight;
var brightnessPosition = new THREE.Vector3(0, bY, 0);
this.setPositionTween(brightnessCursor, brightnessCursor.position, brightnessPosition);
colorWheel.material.uniforms['brightness'].value = this.hsv.v;
},
onBrightnessDown: function onBrightnessDown(position) {
var brightnessSlider = this.brightnessSlider.getObject3D('mesh'),
brightnessCursor = this.brightnessCursor.getObject3D('mesh'),
colorWheel = this.colorWheel.getObject3D('mesh');
brightnessSlider.updateMatrixWorld();
brightnessSlider.worldToLocal(position);
//Brightness is a value between 0 and 1. The parent plane is centre registered, hence offset
var cursorOffset = position.y + this.brightnessSliderHeight / 2;
var brightness = cursorOffset / this.brightnessSliderHeight;
var updatedPosition = {
x: 0,
y: position.y - this.brightnessSliderHeight / 2,
z: 0
//Set brightness cursor position to offset position
// Uncomment to remove anims: brightnessCursor.position.copy(updatedPosition)
};this.setPositionTween(brightnessCursor, brightnessCursor.position, updatedPosition);
//Update material brightness
colorWheel.material.uniforms['brightness'].value = brightness;
this.hsv.v = brightness;
this.el.updateColor();
},
onHueDown: function onHueDown(position) {
var colorWheel = this.colorWheel.getObject3D('mesh'),
colorCursor = this.colorCursor.getObject3D('mesh'),
radius = this.data.wheelSize;
colorWheel.updateMatrixWorld();
colorWheel.worldToLocal(position);
// Uncomment to remove anims: this.colorCursor.getObject3D('mesh').position.copy(position)
this.setPositionTween(colorCursor, colorCursor.position, position);
//Determine Hue and Saturation value from polar co-ordinates
var polarPosition = {
r: Math.sqrt(position.x * position.x + position.y * position.y),
theta: Math.PI + Math.atan2(position.y, position.x)
};
var angle = (polarPosition.theta * (180 / Math.PI) + 180) % 360;
this.hsv.h = angle / 360;
this.hsv.s = polarPosition.r / radius;
this.el.updateColor();
},
updateColor: function updateColor() {
var rgb = this.hsvToRgb(this.hsv),
color = 'rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ')',
hex = '#' + new THREE.Color(color).getHexString();
var selectionEl = this.selectionEl.getObject3D('mesh'),
colorCursor = this.colorCursor.getObject3D('mesh'),
brightnessCursor = this.brightnessCursor.getObject3D('mesh');
//Update indicator element of selected color
if (this.data.showSelection) {
//Uncomment for no tweens: selectionEl.material.color.set(color)
this.setColorTween(selectionEl.material, selectionEl.material.color, new THREE.Color(color));
selectionEl.material.needsUpdate = true;
}
//Change cursor colors based on brightness
if (this.hsv.v >= 0.5) {
this.setColorTween(colorCursor.material, colorCursor.material.color, new THREE.Color(0x000000));
this.setColorTween(brightnessCursor.material, brightnessCursor.material.color, new THREE.Color(0x000000));
} else {
this.setColorTween(colorCursor.material, colorCursor.material.color, new THREE.Color(0xFFFFFF));
this.setColorTween(brightnessCursor.material, brightnessCursor.material.color, new THREE.Color(0xFFFFFF));
}
//showHexValue set to true, update text
if (this.data.showHexValue) this.hexValueText.setAttribute('text', 'value', hex);
//Notify listeners the color has changed.
var eventDetail = {
style: color,
rgb: rgb,
hsv: this.hsv,
hex: hex
};
Event.emit(this.el, 'changecolor', eventDetail);
Event.emit(document.body, 'didchangecolor', eventDetail);
},
hexToRgb: function hexToRgb(hex) {
var rgb = hex.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i, function (m, r, g, b) {
return '#' + r + r + g + g + b + b;
}).substring(1).match(/.{2}/g).map(function (x) {
return parseInt(x, 16);
});
return {
r: rgb[0],
g: rgb[1],
b: rgb[2]
};
},
rgbToHsv: function rgbToHsv(r, g, b) {
var max = Math.max(r, g, b);
var min = Math.min(r, g, b);
var d = max - min;
var h;
var s = max === 0 ? 0 : d / max;
var v = max;
if (arguments.length === 1) {
g = r.g;
b = r.b;
r = r.r;
}
switch (max) {
case min:
h = 0;
break;
case r:
h = g - b + d * (g < b ? 6 : 0);
h /= 6 * d;
break;
case g:
h = b - r + d * 2;
h /= 6 * d;
break;
case b:
h = r - g + d * 4;
h /= 6 * d;
break;
}
return {
h: h,
s: s,
v: v / 255
};
},
hsvToRgb: function hsvToRgb(hsv) {
var r, g, b, i, f, p, q, t;
var h = THREE.Math.clamp(hsv.h, 0, 1);
var s = THREE.Math.clamp(hsv.s, 0, 1);
var v = hsv.v;
i = Math.floor(h * 6);
f = h * 6 - i;
p = v * (1 - s);
q = v * (1 - f * s);
t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
case 5:
r = v;
g = p;
b = q;
break;
}
return {
r: Math.round(r * 255),
g: Math.round(g * 255),
b: Math.round(b * 255)
};
},
update: function update(oldData) {
if (!oldData) return;
if (this.data.backgroundColor !== oldData.backgroundColor) this.background.setAttribute('color', this.data.backgroundColor);
var swatchesChanged = (0, _lodash2.default)(oldData.swatches, this.data.swatches).length > 0;
if (swatchesChanged && this.data.showSwatches && this.data.swatches.filter(function (item) {
return item.length === 7;
}).length === this.data.swatches.length) {
if (this.swatchReady) {
this.el.clearSwatches();
this.el.generateSwatches(this.data.swatches);
}
}
},
tick: function tick() {},
remove: function remove() {
var that = this;
//Kill any listeners
this.colorWheel.removeEventListener('click', this.onColorWheelClicked);
this.brightnessSlider.removeEventListener('click', this.onBrightnessSliderClicked);
this.swatchContainer.removeEventListener('loaded', this.onSwatchReady);
this.hexValueText.removeEventListener('click', this.onHexValueClicked);
if (this.swatchContainer) this.swatchContainer.getObject3D('mesh').children.forEach(function (child) {
return child.removeEventListener('click', that);
});
},
pause: function pause() {},
play: function play() {}
});
AFRAME.registerPrimitive('a-colorwheel', {
defaultComponents: {
colorwheel: {}
},
mappings: {
disabled: 'colorwheel.disabled',
backgroundcolor: 'colorwheel.backgroundColor',
showselection: 'colorwheel.showSelection',
wheelsize: 'colorwheel.wheelSize',
selectionsize: 'colorwheel.selectionSize',
showhexvalue: 'colorwheel.showHexValue',
showswatches: 'colorwheel.showSwatches',
swatches: 'colorwheel.swatches'
}
});
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
var deselectCurrent = __webpack_require__(3);
var defaultMessage = 'Copy to clipboard: #{key}, Enter';
function format(message) {
var copyKey = (/mac os x/i.test(navigator.userAgent) ? '⌘' : 'Ctrl') + '+C';
return message.replace(/#{\s*key\s*}/g, copyKey);
}
function copy(text, options) {
var debug, message, reselectPrevious, range, selection, mark, success = false;
if (!options) { options = {}; }
debug = options.debug || false;
try {
reselectPrevious = deselectCurrent();
range = document.createRange();
selection = document.getSelection();
mark = document.createElement('span');
mark.textContent = text;
// reset user styles for span element
mark.style.all = 'unset';
// prevents scrolling to the end of the page
mark.style.position = 'fixed';
mark.style.top = 0;
mark.style.clip = 'rect(0, 0, 0, 0)';
// used to preserve spaces and line breaks
mark.style.whiteSpace = 'pre';
// do not inherit user-select (it may be `none`)
mark.style.webkitUserSelect = 'text';
mark.style.MozUserSelect = 'text';
mark.style.msUserSelect = 'text';
mark.style.userSelect = 'text';
document.body.appendChild(mark);
range.selectNode(mark);
selection.addRange(range);
var successful = document.execCommand('copy');
if (!successful) {
throw new Error('copy command was unsuccessful');
}
success = true;
} catch (err) {
debug && console.error('unable to copy using execCommand: ', err);
debug && console.warn('trying IE specific stuff');
try {
window.clipboardData.setData('text', text);
success = true;
} catch (err) {
debug && console.error('unable to copy using clipboardData: ', err);
debug && console.error('falling back to prompt');
message = format('message' in options ? options.message : defaultMessage);
window.prompt(message, text);
}
} finally {
if (selection) {
if (typeof selection.removeRange == 'function') {
selection.removeRange(range);
} else {
selection.removeAllRanges();
}
}
if (mark) {
document.body.removeChild(mark);
}
reselectPrevious();
}
return success;
}
module.exports = copy;
/***/ }),
/* 3 */
/***/ (function(module, exports) {
module.exports = function () {
var selection = document.getSelection();
if (!selection.rangeCount) {
return function () {};
}
var active = document.activeElement;
var ranges = [];
for (var i = 0; i < selection.rangeCount; i++) {
ranges.push(selection.getRangeAt(i));
}
switch (active.tagName.toUpperCase()) { // .toUpperCase handles XHTML
case 'INPUT':
case 'TEXTAREA':
active.blur();
break;
default:
active = null;
break;
}
selection.removeAllRanges();
return function () {
selection.type === 'Caret' &&
selection.removeAllRanges();
if (!selection.rangeCount) {
ranges.forEach(function(range) {
selection.addRange(range);
});
}
active &&
active.focus();
};
};
/***/ }),
/* 4 */
/***/ (function(module, exports) {
/* WEBPACK VAR INJECTION */(function(global) {/**
* lodash (Custom Build) <https://lodash.com/>
* Build: `lodash modularize exports="npm" -o ./`
* Copyright jQuery Foundation and other contributors <https://jquery.org/>
* Released under MIT license <https://lodash.com/license>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
*/
/** Used as the size to enable large array optimizations. */
var LARGE_ARRAY_SIZE = 200;
/** Used to stand-in for `undefined` hash values. */
var HASH_UNDEFINED = '__lodash_hash_undefined__';
/** Used as references for various `Number` constants. */
var MAX_SAFE_INTEGER = 9007199254740991;
/** `Object#toString` result references. */
var argsTag = '[object Arguments]',
funcTag = '[object Function]',
genTag = '[object GeneratorFunction]';
/**
* Used to match `RegExp`
* [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
*/
var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
/** Used to detect host constructors (Safari). */
var reIsHostCtor = /^\[object .+?Constructor\]$/;
/** Detect free variable `global` from Node.js. */
var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
/** Detect free variable `self`. */
var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
/** Used as a reference to the global object. */
var root = freeGlobal || freeSelf || Function('return this')();
/**
* A faster alternative to `Function#apply`, this function invokes `func`
* with the `this` binding of `thisArg` and the arguments of `args`.
*
* @private
* @param {Function} func The function to invoke.
* @param {*} thisArg The `this` binding of `func`.
* @param {Array} args The arguments to invoke `func` with.
* @returns {*} Returns the result of `func`.
*/
function apply(func, thisArg, args) {
switch (args.length) {
case 0: return func.call(thisArg);
case 1: return func.call(thisArg, args[0]);
case 2: return func.call(thisArg, args[0], args[1]);
case 3: return func.call(thisArg, args[0], args[1], args[2]);
}
return func.apply(thisArg, args);
}
/**
* A specialized version of `_.includes` for arrays without support for
* specifying an index to search from.
*
* @private
* @param {Array} [array] The array to inspect.
* @param {*} target The value to search for.
* @returns {boolean} Returns `true` if `target` is found, else `false`.
*/
function arrayIncludes(array, value) {
var length = array ? array.length : 0;
return !!length && baseIndexOf(array, value, 0) > -1;
}
/**
* This function is like `arrayIncludes` except that it accepts a comparator.
*
* @private
* @param {Array} [array] The array to inspect.
* @param {*} target The value to search for.
* @param {Function} comparator The comparator invoked per element.
* @returns {boolean} Returns `true` if `target` is found, else `false`.
*/
function arrayIncludesWith(array, value, comparator) {
var index = -1,
length = array ? array.length : 0;
while (++index < length) {
if (comparator(value, array[index])) {
return true;
}
}
return false;
}
/**
* A specialized version of `_.map` for arrays without support for iteratee
* shorthands.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {Array} Returns the new mapped array.
*/
function arrayMap(array, iteratee) {
var index = -1,
length = array ? array.length : 0,
result = Array(length);
while (++index < length) {
result[index] = iteratee(array[index], index, array);
}
return result;
}
/**
* Appends the elements of `values` to `array`.
*
* @private
* @param {Array} array The array to modify.
* @param {Array} values The values to append.
* @returns {Array} Returns `array`.
*/
function arrayPush(array, values) {
var index = -1,
length = values.length,
offset = array.length;
while (++index < length) {
array[offset + index] = values[index];
}
return array;
}
/**
* The base implementation of `_.findIndex` and `_.findLastIndex` without
* support for iteratee shorthands.
*
* @private
* @param {Array} array The array to inspect.
* @param {Function} predicate The function invoked per iteration.
* @param {number} fromIndex The index to search from.
* @param {boolean} [fromRight] Specify iterating from right to left.
* @returns {number} Returns the index of the matched value, else `-1`.
*/
function baseFindIndex(array, predicate, fromIndex, fromRight) {
var length = array.length,
index = fromIndex + (fromRight ? 1 : -1);
while ((fromRight ? index-- : ++index < length)) {
if (predicate(array[index], index, array)) {
return index;
}
}
return -1;
}
/**
* The base implementation of `_.indexOf` without `fromIndex` bounds checks.
*
* @private
* @param {Array} array The array to inspect.
* @param {*} value The value to search for.
* @param {number} fromIndex The index to search from.
* @returns {number} Returns the index of the matched value, else `-1`.
*/
function baseIndexOf(array, value, fromIndex) {
if (value !== value) {
return baseFindIndex(array, baseIsNaN, fromIndex);
}
var index = fromIndex - 1,
length = array.length;
while (++index < length) {
if (array[index] === value) {
return index;
}
}
return -1;
}
/**
* The base implementation of `_.isNaN` without support for number objects.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
*/
function baseIsNaN(value) {
return value !== value;
}
/**
* The base implementation of `_.unary` without support for storing metadata.
*
* @private
* @param {Function} func The function to cap arguments for.
* @returns {Function} Returns the new capped function.
*/
function baseUnary(func) {
return function(value) {
return func(value);
};
}
/**
* Checks if a cache value for `key` exists.
*
* @private
* @param {Object} cache The cache to query.
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function cacheHas(cache, key) {
return cache.has(key);
}
/**
* Gets the value at `key` of `object`.
*
* @private
* @param {Object} [object] The object to query.
* @param {string} key The key of the property to get.
* @returns {*} Returns the property value.
*/
function getValue(object, key) {
return object == null ? undefined : object[key];
}
/**
* Checks if `value` is a host object in IE < 9.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a host object, else `false`.
*/
function isHostObject(value) {
// Many host objects are `Object` objects that can coerce to strings
// despite having improperly defined `toString` methods.
var result = false;
if (value != null && typeof value.toString != 'function') {
try {
result = !!(value + '');
} catch (e) {}
}
return result;
}
/** Used for built-in method references. */
var arrayProto = Array.prototype,
funcProto = Function.prototype,
objectProto = Object.prototype;
/** Used to detect overreaching core-js shims. */
var coreJsData = root['__core-js_shared__'];
/** Used to detect methods masquerading as native. */
var maskSrcKey = (function() {
var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
return uid ? ('Symbol(src)_1.' + uid) : '';
}());
/** Used to resolve the decompiled source of functions. */
var funcToString = funcProto.toString;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;
/**
* Used to resolve the
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
* of values.
*/
var objectToString = objectProto.toString;
/** Used to detect if a method is native. */
var reIsNative = RegExp('^' +
funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
.replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
);
/** Built-in value references. */
var Symbol = root.Symbol,
propertyIsEnumerable = objectProto.propertyIsEnumerable,
splice = arrayProto.splice,
spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined;
/* Built-in method references for those with the same name as other `lodash` methods. */
var nativeMax = Math.max;
/* Built-in method references that are verified to be native. */
var Map = getNative(root, 'Map'),
nativeCreate = getNative(Object, 'create');
/**
* Creates a hash object.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function Hash(entries) {
var index = -1,
length = entries ? entries.length : 0;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
}
/**
* Removes all key-value entries from the hash.
*
* @private
* @name clear
* @memberOf Hash
*/
function hashClear() {
this.__data__ = nativeCreate ? nativeCreate(null) : {};
}
/**
* Removes `key` and its value from the hash.
*
* @private
* @name delete
* @memberOf Hash
* @param {Object} hash The hash to modify.
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
function hashDelete(key) {
return this.has(key) && delete this.__data__[key];
}
/**
* Gets the hash value for `key`.
*
* @private
* @name get
* @memberOf Hash
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
function hashGet(key) {
var data = this.__data__;
if (nativeCreate) {
var result = data[key];
return result === HASH_UNDEFINED ? undefined : result;
}
return hasOwnProperty.call(data, key) ? data[key] : undefined;
}
/**
* Checks if a hash value for `key` exists.
*
* @private
* @name has
* @memberOf Hash
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function hashHas(key) {
var data = this.__data__;
return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);
}
/**
* Sets the hash `key` to `value`.
*
* @private
* @name set
* @memberOf Hash
* @param {string} key The key of the value to set.
* @param {*} value The value to set.
* @returns {Object} Returns the hash instance.
*/
function hashSet(key, value) {
var data = this.__data__;
data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
return this;
}
// Add methods to `Hash`.
Hash.prototype.clear = hashClear;
Hash.prototype['delete'] = hashDelete;
Hash.prototype.get = hashGet;
Hash.prototype.has = hashHas;
Hash.prototype.set = hashSet;
/**
* Creates an list cache object.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function ListCache(entries) {
var index = -1,
length = entries ? entries.length : 0;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
}
/**
* Removes all key-value entries from the list cache.
*
* @private
* @name clear
* @memberOf ListCache
*/
function listCacheClear() {
this.__data__ = [];
}
/**
* Removes `key` and its value from the list cache.
*
* @private
* @name delete
* @memberOf ListCache
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
function listCacheDelete(key) {
var data = this.__data__,
index = assocIndexOf(data, key);
if (index < 0) {
return false;
}
var lastIndex = data.length - 1;
if (index == lastIndex) {
data.pop();
} else {
splice.call(data, index, 1);
}
return true;
}
/**
* Gets the list cache value for `key`.
*
* @private
* @name get
* @memberOf ListCache
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
function listCacheGet(key) {
var data = this.__data__,
index = assocIndexOf(data, key);
return index < 0 ? undefined : data[index][1];
}
/**
* Checks if a list cache value for `key` exists.
*
* @private
* @name has
* @memberOf ListCache
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function listCacheHas(key) {
return assocIndexOf(this.__data__, key) > -1;
}
/**
* Sets the list cache `key` to `value`.
*
* @private
* @name set
* @memberOf ListCache
* @param {string} key The key of the value to set.
* @param {*} value The value to set.
* @returns {Object} Returns the list cache instance.
*/
function listCacheSet(key, value) {
var data = this.__data__,
index = assocIndexOf(data, key);
if (index < 0) {
data.push([key, value]);
} else {
data[index][1] = value;
}
return this;
}
// Add methods to `ListCache`.
ListCache.prototype.clear = listCacheClear;
ListCache.prototype['delete'] = listCacheDelete;
ListCache.prototype.get = listCacheGet;
ListCache.prototype.has = listCacheHas;
ListCache.prototype.set = listCacheSet;
/**
* Creates a map cache object to store key-value pairs.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function MapCache(entries) {
var index = -1,
length = entries ? entries.length : 0;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
}
/**
* Removes all key-value entries from the map.
*
* @private
* @name clear
* @memberOf MapCache
*/
function mapCacheClear() {
this.__data__ = {
'hash': new Hash,
'map': new (Map || ListCache),
'string': new Hash
};
}
/**
* Removes `key` and its value from the map.
*
* @private
* @name delete
* @memberOf MapCache
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
function mapCacheDelete(key) {
return getMapData(this, key)['delete'](key);
}
/**
* Gets the map value for `key`.
*
* @private
* @name get
* @memberOf MapCache
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
function mapCacheGet(key) {
return getMapData(this, key).get(key);
}
/**
* Checks if a map value for `key` exists.
*
* @private
* @name has
* @memberOf MapCache
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function mapCacheHas(key) {
return getMapData(this, key).has(key);
}
/**
* Sets the map `key` to `value`.
*
* @private
* @name set
* @memberOf MapCache
* @param {string} key The key of the value to set.
* @param {*} value The value to set.
* @returns {Object} Returns the map cache instance.
*/
function mapCacheSet(key, value) {
getMapData(this, key).set(key, value);
return this;
}
// Add methods to `MapCache`.
MapCache.prototype.clear = mapCacheClear;
MapCache.prototype['delete'] = mapCacheDelete;
MapCache.prototype.get = mapCacheGet;
MapCache.prototype.has = mapCacheHas;
MapCache.prototype.set = mapCacheSet;
/**
*
* Creates an array cache object to store unique values.
*
* @private
* @constructor
* @param {Array} [values] The values to cache.
*/
function SetCache(values) {
var index = -1,
length = values ? values.length : 0;
this.__data__ = new MapCache;
while (++index < length) {
this.add(values[index]);
}
}
/**
* Adds `value` to the array cache.
*
* @private
* @name add
* @memberOf SetCache
* @alias push
* @param {*} value The value to cache.
* @returns {Object} Returns the cache instance.
*/
function setCacheAdd(value) {
this.__data__.set(value, HASH_UNDEFINED);
return this;
}
/**
* Checks if `value` is in the array cache.
*
* @private
* @name has
* @memberOf SetCache
* @param {*} value The value to search for.
* @returns {number} Returns `true` if `value` is found, else `false`.
*/
function setCacheHas(value) {
return this.__data__.has(value);
}
// Add methods to `SetCache`.
SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
SetCache.prototype.has = setCacheHas;
/**
* Gets the index at which the `key` is found in `array` of key-value pairs.
*
* @private
* @param {Array} array The array to inspect.
* @param {*} key The key to search for.
* @returns {number} Returns the index of the matched value, else `-1`.
*/
function assocIndexOf(array, key) {
var length = array.length;
while (length--) {
if (eq(array[length][0], key)) {
return length;
}
}
return -1;
}
/**
* The base implementation of methods like `_.difference` without support
* for excluding multiple arrays or iteratee shorthands.
*
* @private
* @param {Array} array The array to inspect.
* @param {Array} values The values to exclude.
* @param {Function} [iteratee] The iteratee invoked per element.
* @param {Function} [comparator] The comparator invoked per element.
* @returns {Array} Returns the new array of filtered values.
*/
function baseDifference(array, values, iteratee, comparator) {
var index = -1,
includes = arrayIncludes,
isCommon = true,
length = array.length,
result = [],
valuesLength = values.length;
if (!length) {
return result;
}
if (iteratee) {
values = arrayMap(values, baseUnary(iteratee));
}
if (comparator) {
includes = arrayIncludesWith;
isCommon = false;
}
else if (values.length >= LARGE_ARRAY_SIZE) {
includes = cacheHas;
isCommon = false;
values = new SetCache(values);
}
outer:
while (++index < length) {
var value = array[index],
computed = iteratee ? iteratee(value) : value;
value = (comparator || value !== 0) ? value : 0;
if (isCommon && computed === computed) {
var valuesIndex = valuesLength;
while (valuesIndex--) {
if (values[valuesIndex] === computed) {
continue outer;
}
}
result.push(value);
}
else if (!includes(values, computed, comparator)) {
result.push(value);
}
}
return result;
}
/**
* The base implementation of `_.flatten` with support for restricting flattening.
*
* @private
* @param {Array} array The array to flatten.
* @param {number} depth The maximum recursion depth.
* @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
* @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
* @param {Array} [result=[]] The initial result value.
* @returns {Array} Returns the new flattened array.
*/
function baseFlatten(array, depth, predicate, isStrict, result) {
var index = -1,
length = array.length;
predicate || (predicate = isFlattenable);
result || (result = []);
while (++index < length) {
var value = array[index];
if (depth > 0 && predicate(value)) {
if (depth > 1) {
// Recursively flatten arrays (susceptible to call stack limits).
baseFlatten(value, depth - 1, predicate, isStrict, result);
} else {
arrayPush(result, value);
}
} else if (!isStrict) {
result[result.length] = value;
}
}
return result;
}
/**
* The base implementation of `_.isNative` without bad shim checks.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a native function,
* else `false`.
*/
function baseIsNative(value) {
if (!isObject(value) || isMasked(value)) {
return false;
}
var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor;
return pattern.test(toSource(value));
}
/**
* The base implementation of `_.rest` which doesn't validate or coerce arguments.
*
* @private
* @param {Function} func The function to apply a rest parameter to.
* @param {number} [start=func.length-1] The start position of the rest parameter.
* @returns {Function} Returns the new function.
*/
function baseRest(func, start) {
start = nativeMax(start === undefined ? (func.length - 1) : start, 0);
return function() {
var args = arguments,
index = -1,
length = nativeMax(args.length - start, 0),
array = Array(length);
while (++index < length) {
array[index] = args[start + index];
}
index = -1;
var otherArgs = Array(start + 1);
while (++index < start) {
otherArgs[index] = args[index];
}
otherArgs[start] = array;
return apply(func, this, otherArgs);
};
}
/**
* Gets the data for `map`.
*
* @private
* @param {Object} map The map to query.
* @param {string} key The reference key.
* @returns {*} Returns the map data.
*/
function getMapData(map, key) {
var data = map.__data__;
return isKeyable(key)
? data[typeof key == 'string' ? 'string' : 'hash']
: data.map;
}
/**
* Gets the native function at `key` of `object`.
*
* @private
* @param {Object} object The object to query.
* @param {string} key The key of the method to get.
* @returns {*} Returns the function if it's native, else `undefined`.
*/
function getNative(object, key) {
var value = getValu