Skip to content

Commit 1cf8ec5

Browse files
authored
Add files via upload
0 parents  commit 1cf8ec5

File tree

4 files changed

+256
-0
lines changed

4 files changed

+256
-0
lines changed

LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
---------------------
3+
4+
Copyright 2024 Michael Otieno
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
SOFTWARE.

README.md

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
Mikeotizels Clipboard JS
2+
========================
3+
4+
Version 1.0.0 - December 2024
5+
6+
Mikeotizels Clipboard JS is a lightweight JavaScript utility for handling copy
7+
and cut operations using the asynchronous Clipboard API.
8+
9+
It supports:
10+
11+
- Using a provided text via data-clipboard-text;
12+
- If not provided, checking for a data-clipboard-target attribute to
13+
find another element by its ID;
14+
- Fallback to the old (synchronous) `document.execCommand` method if the
15+
Clipboard API isn't available;
16+
- Callback functions for handling the "onSuccess" and "onError" events after
17+
triggering an action (copy or cut).
18+
19+
---
20+
21+
### **How to Use**
22+
23+
1. **Include the Script**
24+
25+
Simply include or bundle the script with your project.
26+
27+
```html
28+
<script src="/path/to/mo.clipboard.min.js"></script>
29+
```
30+
31+
2. **Markup the HTML**
32+
33+
For an element to work with the plugin, add one or more of the following data
34+
attributes:
35+
36+
- data-clipboard-action: Specify the action to execute, either "copy" or "cut".
37+
If this attribute is omitted or has an invalid value, copy will be used by
38+
default.
39+
- data-clipboard-text (optional): Explicit text value to copy or cut. If omitted,
40+
the inner text of the trigger element will be used.
41+
- data-clipboard-target (optional): The ID of another element whose content will
42+
be used.
43+
44+
##### Copy text from explicit attribute
45+
46+
Just include a data-clipboard-text attribute in your trigger element.
47+
48+
```html
49+
<!-- Copy button that pulls text explicitly -->
50+
<button class="btn btn-clipboard" aria-label="Copy"
51+
data-clipboard-action="copy"
52+
data-clipboard-text="Hello, world!">
53+
Copy text from attribute
54+
</button>
55+
```
56+
57+
##### Copy text from another element
58+
59+
A pretty common use case is to copy content from another element. You can do
60+
that by adding a data-clipboard-target attribute in your trigger element. The
61+
value you include on this attribute needs to match the target element's ID.
62+
63+
```html
64+
<!-- Copy button that uses another element's text -->
65+
<button class="btn btn-clipboard" aria-label="Copy"
66+
data-clipboard-action="copy"
67+
data-clipboard-target="copyTarget">
68+
Copy text from element
69+
</button>
70+
71+
<!-- Target element that holds the text -->
72+
<div id="copyTarget">
73+
Text to be copied...
74+
</div>
75+
```
76+
77+
##### Cut text from another element
78+
79+
Additionally, you can set the data-clipboard-action attribute to "cut" if you
80+
want to cut content from an element. If you omit this attribute, copy will be
81+
used by default. As you may expect, the cut action only works on `<input>` or
82+
`<textarea>` elements.
83+
84+
```html
85+
<!-- Target -->
86+
<textarea id="cutTarget">Text to be cut...</textarea>
87+
88+
<!-- Trigger -->
89+
<button class="btn btn-clipboard" aria-label="Cut"
90+
data-clipboard-action="cut"
91+
data-clipboard-target="cutTarget">
92+
Cut to clipboard
93+
</button>
94+
```
95+
96+
3. **Set Up the Plugin**
97+
98+
After the DOM is ready, initialize the plugin and optionally provide callback
99+
functions:
100+
101+
```js
102+
var clipboardSetup = function() {
103+
// Return early if the moClipboard object is undefined.
104+
if (typeof moClipboard === 'undefined') {
105+
console.error('The Mikeotizels Clipboard JS is not loaded on the page.');
106+
return;
107+
}
108+
109+
// Instantiate object
110+
var clipboard = new moClipboard('.btn-clipboard', {
111+
// Success callback
112+
// Called on a successful copy or cut; receives an object:
113+
// `{ action, text, trigger }`
114+
onSuccess: (info) => {
115+
console.log(`Successfully executed: ${info.action}`);
116+
// TODO: You can add further UI feedback here, like showing a
117+
// tooltip "Copy" or "Cut" on the trigger element.
118+
showToast(info.action);
119+
},
120+
// Error callback
121+
// Called on failure; receives the error object and the trigger element.
122+
onError: (error, trigger) => {
123+
console.error(`Error during ${trigger.getAttribute("data-clipboard-action")}:`, error);
124+
// TODO: Optionally, show a generic error message to the user
125+
}
126+
});
127+
128+
// Custom toast notification.
129+
function showToast(action, timeout = 3000) {
130+
const toastDiv = document.createElement('div');
131+
let toastText = 'Copied to clipboard';
132+
133+
if (action == 'cut') {
134+
toastText = 'Cut to clipboard';
135+
}
136+
137+
toastDiv.setAttribute('style', 'position:fixed;top:100px;left:50%;z-index:9999;width:225px;text-align:center;color:#ffffff;background-color:#343a40;border:1px solid #1d2124;padding:10px 15px;border-radius:4px;margin-left:-100px;box-shadow:0 0 10px rgba(0,0,0,0.2);');
138+
toastDiv.appendChild(document.createTextNode(toastText));
139+
document.body.appendChild(toastDiv);
140+
setTimeout(function() {
141+
document.body.removeChild(toastDiv);
142+
}, timeout);
143+
}
144+
}();
145+
```
146+
147+
## Inspirations
148+
149+
[zenorocha/clipboardjs](https://clipboardjs.com)

dist/mo.clipboard.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*!
2+
* Mikeotizels Clipboard JS v1.0.0
3+
* Copyright 2024 Michael Otieno
4+
* Licensed under MIT
5+
*/
6+
7+
(() => {
8+
"use strict";
9+
10+
window.moClipboard = class {
11+
constructor(t, e = {}) {
12+
this.selector = t || "[data-clipboard]";
13+
this.onSuccess = "function" == typeof e.onSuccess ? e.onSuccess : () => {};
14+
this.onError = "function" == typeof e.onError ? e.onError : () => {};
15+
this._init()
16+
}
17+
18+
async copy(t, e) {
19+
if (navigator.clipboard && navigator.clipboard.writeText) try {
20+
await navigator.clipboard.writeText(t);
21+
this.onSuccess({
22+
text: t,
23+
trigger: e
24+
})
25+
} catch (t) {
26+
this.onError(t, e)
27+
} else try {
28+
this._fallbackCopy(t);
29+
this.onSuccess({
30+
text: t,
31+
trigger: e
32+
})
33+
} catch (t) {
34+
this.onError(t, e)
35+
}
36+
}
37+
38+
_init() {
39+
const t = document.querySelectorAll(this.selector);
40+
t.length && t.forEach(r => {
41+
r.addEventListener("click", t => {
42+
t.preventDefault();
43+
let e;
44+
if (r.hasAttribute("data-clipboard-text")) e = r.getAttribute("data-clipboard-text");
45+
else if (r.hasAttribute("data-clipboard-target")) {
46+
var t = r.getAttribute("data-clipboard-target"),
47+
o = document.getElementById(t);
48+
if (!o) return void console.error(`Target element with ID '${t}' not found.`);
49+
e = this._getText(o)
50+
} else e = this._getText(r);
51+
this.copy(e, r)
52+
})
53+
})
54+
}
55+
56+
_getText(t) {
57+
return "INPUT" === t.tagName || "TEXTAREA" === t.tagName ? t.value : t.innerText
58+
}
59+
60+
_fallbackCopy(t) {
61+
const e = document.createElement("textarea");
62+
e.style.position = "fixed";
63+
e.style.top = "0";
64+
e.style.left = "0";
65+
e.style.opacity = "0";
66+
e.value = t;
67+
e.setAttribute("readonly", "readonly");
68+
document.body.appendChild(e);
69+
e.focus();
70+
e.select();
71+
try {
72+
document.execCommand("copy");
73+
document.body.removeChild(e)
74+
} catch (t) {
75+
document.body.removeChild(e);
76+
throw t
77+
}
78+
}
79+
}
80+
})();

dist/mo.clipboard.min.js

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)