Skip to content

Commit

Permalink
Add npm note.
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan McQuen <[email protected]>
  • Loading branch information
ryanpcmcquen committed Jan 29, 2021
1 parent f5f41bb commit bd43206
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 92 deletions.
48 changes: 27 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,41 +17,47 @@ Provided by:

Then use the following elements:

1. `<textarea>` with the class `text-to-copy` (can be `readonly` but *not* `disabled`)
1. `<textarea>` with the class `text-to-copy` (can be `readonly` but _not_ `disabled`)
2. `<button>` with the class `js-copy-btn`

The library takes cares of the rest. :shipit:

:newspaper: You don't have to write any JavaScript to use it!

-----
Alternatively, you can use the project with npm:

```
npm install cheval
```

---

#### Featured in MarkApp!

[![MarkApp](https://usercontent.irccloud-cdn.com/file/X2uIqOZA/Screen%20Shot%202017-10-17%20at%208.23.37%20AM.png)](http://markapp.io)

-----
---

#### So what?! Where does it work?

Almost everywhere!

Desktop:

- Chrome/Chromium 42+
- Firefox 41+
- Internet Explorer 9+
- Opera 29+
- Safari 10+
- Chrome/Chromium 42+
- Firefox 41+
- Internet Explorer 9+
- Opera 29+
- Safari 10+

Android:

- Chrome 42+
- Firefox 41+
- Chrome 42+
- Firefox 41+

iOS:

- 10+
- 10+

##### What about other browsers?

Expand All @@ -61,7 +67,7 @@ On desktop Safari (< v10), the button will change to `Press Command + C to copy`

On failure the button will say `Please copy manually`.

-----
---

:warning: If you want your textarea to be invisible for some reason, use this CSS:

Expand Down Expand Up @@ -109,7 +115,7 @@ For example:

Positioning of the elements and buttons does not matter, they do not need to be near each other on the page. This allows you to write declarative markup and not be concerned with the inner workings of this library. Enjoy!

-----
---

#### But ...

Expand All @@ -120,28 +126,28 @@ You're right! That's why in version `1.3.0`, `cheval` also adds itself to global
Now you can invoke at will on dynamic elements!

```js
cheval(".dynamic-js-copy-btn", ".dynamic-text-to-copy");
cheval('.dynamic-js-copy-btn', '.dynamic-text-to-copy');
```

-----
---

What does `cheval` mean?

The name comes from Cheval glass, a type of mirror.

-----
---

This project is LibreJS compliant!

[![LibreJS](https://www.gnu.org/software/librejs/images/logo-medium.png)](https://www.gnu.org/software/librejs/)

-----
---

If you prefer using specific tags instead of the latest version, you may specify a tag in the `jsDelivr` URL:

https://cdn.jsdelivr.net/gh/ryanpcmcquen/cheval@1.4.0/cheval.min.js
https://cdn.jsdelivr.net/gh/ryanpcmcquen/cheval@2.0.0/cheval.min.js

-----
---

### Contributing:

Expand All @@ -152,7 +158,7 @@ If you wish to contribute to this project, pull requests are always welcome! Ple
/*jslint browser: true*/
```

-----
---

Thanks to [Lea Verou](https://github.com/LeaVerou) for lots of support and help with the name.

Expand All @@ -171,7 +177,7 @@ Thanks to BrowserStack and Koding!
alt="Made with Koding"/>
</a>

-----
---

Full download stats available here:

Expand Down
115 changes: 45 additions & 70 deletions cheval.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,43 @@
// @license magnet:?xt=urn:btih:3877d6d54b3accd4bc32f8a48bf32ebc0901502a&dn=mpl-2.0.txt MPL-v2
/*! cheval v1.4.0 by ryanpcmcquen */
/*! cheval v2.0.0 by ryanpcmcquen */
// Ryan P. C. McQuen | Everett, WA

/*global module, window*/
/*jslint browser: true*/
(function () {
"use strict";
'use strict';

var textClassName = "text-to-copy";
var buttonClassName = "js-copy-btn";
var textClassName = 'text-to-copy';
var buttonClassName = 'js-copy-btn';
var allowingButtonTextToChange = true;
var afterCopyText = {
desktop: "Copy again",
desktop: 'Copy again',
iPad: "Now tap the text, then 'Copy'",
iPhoneOriPod: "Now tap 'Copy'",
oldSafari: "Press Command + C to copy",
notSupported: "Please copy manually"
oldSafari: 'Press Command + C to copy',
notSupported: 'Please copy manually',
};
var sets = {};
var regexBuilder = function (prefix) {
return new RegExp(prefix + "\\S*");
return new RegExp(prefix + '\\S*');
};

window.addEventListener("DOMContentLoaded", function () {
var texts = Array.prototype.slice.call(document.querySelectorAll(
"[class*=" + textClassName + "]"
));
var buttons = Array.prototype.slice.call(document.querySelectorAll(
"[class*=" + buttonClassName + "]"
));
window.addEventListener('DOMContentLoaded', function () {
var texts = Array.prototype.slice.call(
document.querySelectorAll('[class*=' + textClassName + ']')
);
var buttons = Array.prototype.slice.call(
document.querySelectorAll('[class*=' + buttonClassName + ']')
);

var classNameFinder = function (arr, regex, namePrefix) {
return arr.map(function (item) {
return (item.className.match(regex))
? item.className.match(regex)[0].replace(
namePrefix,
""
)
: false;
}).sort();
return arr
.map(function (item) {
return item.className.match(regex)
? item.className.match(regex)[0].replace(namePrefix, '')
: false;
})
.sort();
};

sets.texts = classNameFinder(
Expand All @@ -54,9 +53,7 @@
);

var matches = sets.texts.map(function (ignore, index) {
return sets.texts[index].match(sets.buttons[
index
]);
return sets.texts[index].match(sets.buttons[index]);
});

var throwErr = function (err) {
Expand All @@ -67,10 +64,9 @@
var oldSafari = false;
var navAgent = window.navigator.userAgent;
if (
(/^((?!chrome).)*safari/i).test(navAgent) &&
/^((?!chrome).)*safari/i.test(navAgent) &&
// ^ Fancy safari detection thanks to: https://stackoverflow.com/a/23522755
!(/^((?!chrome).)*[0-9][0-9](\.[0-9][0-9]?)?\ssafari/i)
.test(navAgent)
!/^((?!chrome).)*[0-9][0-9](\.[0-9][0-9]?)?\ssafari/i.test(navAgent)
// ^ Even fancier Safari < 10 detection thanks to regex. :^)
) {
oldSafari = true;
Expand All @@ -90,28 +86,25 @@
};
if (iPhoneORiPod || iPad) {
if (oldSafari) {
setCopyBtnText("Select text");
setCopyBtnText('Select text');
}
}
if (copyBtn) {
copyBtn.addEventListener("click", function () {
copyBtn.addEventListener('click', function () {
var oldPosX = window.scrollX;
var oldPosY = window.scrollY;
// Clone the text-to-copy node so that we can
// create a hidden textarea, with its text value.
// Thanks to @LeaVerou for the idea.
var originalCopyItem = document.querySelector(
text
);
var originalCopyItem = document.querySelector(text);
var dollyTheSheep = originalCopyItem.cloneNode(true);
var copyItem = document.createElement(
"textarea"
);
var copyItem = document.createElement('textarea');
copyItem.style.opacity = 0;
copyItem.style.position = "absolute";
copyItem.style.position = 'absolute';
// If .value is undefined, .textContent will
// get assigned to the textarea we made.
var copyValue = dollyTheSheep.value || dollyTheSheep.textContent;
var copyValue =
dollyTheSheep.value || dollyTheSheep.textContent;
copyItem.value = copyValue;
document.body.appendChild(copyItem);
if (copyItem) {
Expand All @@ -123,13 +116,10 @@
copyItem.selectionEnd = copyValue.length;
try {
// Now that we've selected the text, execute the copy command:
document.execCommand("copy");
document.execCommand('copy');
// And disable the cloned area to prevent jumping.
// This has to come after the `copy` command.
copyItem.setAttribute(
"disabled",
true
);
copyItem.setAttribute('disabled', true);
// Allow the button text to be changed.
// Set `allowingButtonTextToChange = false` to leave it alone.
// Default is `true`.
Expand All @@ -143,72 +133,57 @@
} else if (iPad) {
// The iPad doesn't have the 'Copy' box pop up,
// you have to tap the text first.
setCopyBtnText(
afterCopyText.iPad
);
setCopyBtnText(afterCopyText.iPad);
} else {
// Just old!
setCopyBtnText(
afterCopyText.oldSafari
);
setCopyBtnText(afterCopyText.oldSafari);
}
} else {
// Hide the onscreen keyboard, which opens
// on iOS devices, due to the target element
// being focused on.
document.activeElement.blur();
setCopyBtnText(
afterCopyText.desktop
);
setCopyBtnText(afterCopyText.desktop);
}
}
} catch (ignore) {
if (allowingButtonTextToChange) {
setCopyBtnText(
afterCopyText.notSupported
);
setCopyBtnText(afterCopyText.notSupported);
}
}
originalCopyItem.focus();
// Restore the user's original position to avoid
// 'jumping' when they click a copy button.
window.scrollTo(
oldPosX,
oldPosY
);
window.scrollTo(oldPosX, oldPosY);
originalCopyItem.selectionStart = 0;
originalCopyItem.selectionEnd = copyValue.length;
copyItem.remove();
} else {
throwErr(
"You don't have an element with the class: '" +
textClassName +
"'. Please check the cheval README."
textClassName +
"'. Please check the cheval README."
);
}
});
} else {
throwErr(
"You don't have a <button> with the class: '" +
buttonClassName +
"'. Please check the cheval README."
buttonClassName +
"'. Please check the cheval README."
);
}
};

// Copy all sets of elements and buttons:
matches.forEach(function (i) {
return cheval(
"." + buttonClassName + i,
"." + textClassName + i
);
return cheval('.' + buttonClassName + i, '.' + textClassName + i);
});

try {
window.cheval = cheval;
module.exports = cheval;
} catch (ignore) {}
});

}());
})();
// @license-end
2 changes: 1 addition & 1 deletion cheval.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "cheval",
"version": "2.0.0",
"description": "Copy to the clipboard using JavaScript without writing JS.",
"main": "cheval.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ryanpcmcquen/cheval.git"
},
"keywords": [
"clipboard"
],
"author": "Ryan McQuen",
"license": "MPL-2.0",
"bugs": {
"url": "https://github.com/ryanpcmcquen/cheval/issues"
},
"homepage": "https://github.com/ryanpcmcquen/cheval#readme"
}

0 comments on commit bd43206

Please sign in to comment.