Skip to content

Commit

Permalink
Merge pull request #5 from layerssss/contenteditable
Browse files Browse the repository at this point in the history
refactor
  • Loading branch information
layerssss committed Nov 10, 2014
2 parents 18132a3 + 808a84c commit ac4ce33
Show file tree
Hide file tree
Showing 5 changed files with 402 additions and 167 deletions.
35 changes: 19 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,36 @@
paste.js
=====

paste.js is an interface to read from clipboard data ( text / image ) in different browsers. Currenttly only tested (and works) under:
paste.js is an interface to read data ( text / image ) from clipboard in different browsers. It also contains several hacks.

* IE 11 (Windows 7)
* Chrome 32 (Windows 7 / OSX)
* Firefox 26 (Windows 7 / OSX)

Image pasting is NOT working under:
browser compatibility
-----

* Opera
* Safari
| | IE11 | Firefox 33 | Chrome 38 | Safari | Opera |
|------------------------------|------|------------|-----------|--------|-------|
| pasteText (non-inputable) | ok | ok | ok | ok | ok |
| pasteText (textarea) | ok | ok | ok | ok | ok |
| pasteText (contenteditable) | ok | ok | ok | ok | ok |
| pasteImage (non-inputable) | ok | ok | ok | | |
| pasteImage (textarea) | | ok | ok | | |
| pasteImage (contenteditable) | ok | ok | ok | | |

usage
-----

```
// jQuery needed
paste = $.paste().appendTo('body');
paste.on('pasteImage', function (ev, data){
$('.mydiv').pastableNonInputable();
$('textarea').pastableTextarea();
$('div[contenteditable]').pastableContenteditable();
$('*').on('pasteImage', function (ev, data){
console.log("dataURL: " + data.dataURL)
});
paste.on('pasteText', function (ev, data){
}).on('pasteText', function (ev, data){
console.log("text: " + data.text)
});
paste.focus(); // it's actually a hidden div element
// ... when you don't need it anymore
paste.remove();
```

more
Expand Down
4 changes: 2 additions & 2 deletions bower.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "paste.js",
"version": "0.0.4",
"version": "0.0.5",
"authors": [
"Michael Yin <[email protected]>"
],
Expand All @@ -16,6 +16,6 @@
"index.html"
],
"dependencies": {
"jquery": "~2.1.0"
"jquery": "*"
}
}
44 changes: 39 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,50 @@
padding: .5em;
margin: 0.5em auto;
}
iframe{
height: 25em;
.demo, .result{
border: solid 1px #999;
padding: 0.5em;
margin: 1em 0 0 0;
box-sizing: contentbox;
width: 100%;
}
.result > img{
border: solid 1px #ccc;
height: 50px;
}
.pastable{
transition: box-shadow ease .3s;
}
.pastable:hover{
box-shadow: 0 0 3px black;
}
.pastable.pastable-focus{
box-shadow: 0 0 10px black;
}
</style>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.js"></script>
<script type="text/javascript" src="paste.js"></script>
<script type="text/javascript">
$(function(){
$('.demo-noninputable').pastableNonInputable();
$('.demo-textarea').pastableTextarea();
$('.demo-contenteditable').pastableContenteditable();
$('.demo').on('pasteImage', function(ev, data){
$('<div class="result">image: ' + data.width + ' x ' + data.height + '<img src="' + data.dataURL +'" ></div>').insertAfter(this);
}).on('pasteText', function(ev, data){
$('<div class="result"></div>').text('text: "' + data.text + '"').insertAfter(this);
});
});
</script>
<body>
<div>
<h1>Paste.js</h1>
<p><a href="https://github.com/layerssss/paste.js">github.com/layerssss/paste.js</a></p>
<iframe width="100%" height="300" src="http://jsfiddle.net/layerssss/84Hda/embedded/result,js,html/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
<iframe width="100%" height="300" src="http://jsfiddle.net/layerssss/59YWx/embedded/result,js,html/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
<p>
<a href="https://github.com/layerssss/paste.js">github.com/layerssss/paste.js</a>
</p>
<div class="demo demo-noninputable">I'm a div, using `$('.demo-noninputable').pastableNonInputable()`.</div>
<textarea class="demo demo-textarea">I'm a textarea, using `$('.demo-textarea').pastableTextarea()`.</textarea>
<div class="demo demo-contenteditable" contenteditable>I'm a div[contenteditable], using `$('.demo-contenteditable').pastableContenteditable()`.</div>
</div>
</body>
</html>
178 changes: 118 additions & 60 deletions paste.coffee
Original file line number Diff line number Diff line change
@@ -1,69 +1,127 @@
$ = jQuery
readImagesFromEditable = (element, cb)->
setTimeout (->
$(element).find('img').each (i, img)->
getImageData img.src, cb
), 1
getImageData = (src, cb)->
loader = new Image()
loader.onload = ->
canvas = document.createElement 'canvas'
canvas.width = loader.width
canvas.height = loader.height
ctx = canvas.getContext '2d'
ctx.drawImage loader, 0, 0, canvas.width, canvas.height
dataURL = null
try
dataURL = canvas.toDataURL 'image/png'
catch
if dataURL
cb
dataURL: dataURL
width: loader.width
height: loader.height
loader.src = src
$ = window.jQuery
$.paste = (pasteContainer) ->
console?.log "DEPRECATED: This method is deprecated. Please use $.fn.pastableNonInputable() instead."
pm = Paste.mountNonInputable pasteContainer
pm._container
$.fn.pastableNonInputable = ->
for el in @
paste = Paste.mountNonInputable el
@
$.fn.pastableTextarea = ->
for el in @
paste = Paste.mountTextarea el
@
$.fn.pastableContenteditable = ->
for el in @
paste = Paste.mountContenteditable el
@

$.paste = ->
div = document.createElement 'div'
div.contentEditable = true
$(div).css
createHiddenEditable = ->
$(document.createElement 'div')
.attr 'contenteditable', true
.css
width: 1
height: 1
position: 'fixed'
left: -100
overflow: 'hidden'
# backgroundColor: '#ccc'
.on 'paste', (ev)->
if ev.originalEvent?.clipboardData?
clipboardData = ev.originalEvent.clipboardData
if clipboardData.items #webkit
for item in clipboardData.items
if item.type.match /^image\//
reader = new FileReader()
reader.onload = (event)=>
getImageData event.target.result, (data)->
$(div).trigger 'pasteImage', data
reader.readAsDataURL item.getAsFile()
if item.type == 'text/plain'
item.getAsString (string)->
$(div).trigger 'pasteText', text: string
else
if clipboardData.types.length
if (text = clipboardData.getData 'Text')?.length
$(div).trigger 'pasteText', text: text
else
readImagesFromEditable div, (data)->
$(div).trigger 'pasteImage', data
if clipboardData = window.clipboardData # ie
if (text = clipboardData.getData 'Text')?.length
$(div).trigger 'pasteText', text: text
else
readImagesFromEditable div, (data)->
$(div).trigger 'pasteImage', data

setTimeout (->
$(div).html('')
), 2
return $ div
class Paste
# Element to receive final events.
_target: null

# Actual element to do pasting.
_container: null

@mountNonInputable: (nonInputable)->
paste = new Paste createHiddenEditable().appendTo(nonInputable), nonInputable
$(nonInputable).on 'click', => paste._container.focus()

paste._container.on 'focus', => $(nonInputable).addClass 'pastable-focus'
paste._container.on 'blur', => $(nonInputable).removeClass 'pastable-focus'


@mountTextarea: (textarea)->
return @mountContenteditable textarea unless window.ClipboardEvent
# Firefox only
paste = new Paste createHiddenEditable().insertBefore(textarea), textarea
$(textarea).on 'keypress', (ev)=>
return unless 'v' == String.fromCharCode ev.charCode
return unless ev.ctrlKey || ev.metaKey
paste._container.focus()
$(paste._target).on 'pasteImage', =>
$(textarea).focus()
$(paste._target).on 'pasteText', =>
$(textarea).focus()

$(textarea).on 'focus', => $(textarea).addClass 'pastable-focus'
$(textarea).on 'blur', => $(textarea).removeClass 'pastable-focus'

@mountContenteditable: (contenteditable)->
paste = new Paste contenteditable, contenteditable

$(contenteditable).on 'focus', => $(contenteditable).addClass 'pastable-focus'
$(contenteditable).on 'blur', => $(contenteditable).removeClass 'pastable-focus'


constructor: (@_container, @_target)->
@_container = $ @_container
@_target = $ @_target
.addClass 'pastable'
@_container.on 'paste', (ev)=>
if ev.originalEvent?.clipboardData?
clipboardData = ev.originalEvent.clipboardData
if clipboardData.items
# Chrome & Safari(text-only)
for item in clipboardData.items
if item.type.match /^image\//
reader = new FileReader()
reader.onload = (event)=>
@_handleImage event.target.result
reader.readAsDataURL item.getAsFile()
if item.type == 'text/plain'
item.getAsString (string)=>
@_target.trigger 'pasteText', text: string
else
# Firefox
if clipboardData.types.length
text = clipboardData.getData 'Text'
@_target.trigger 'pasteText', text: text
else
@_checkImagesInContainer (src)=>
@_handleImage src
# IE
if clipboardData = window.clipboardData
if (text = clipboardData.getData 'Text')?.length
@_target.trigger 'pasteText', text: text
else
for file in clipboardData.files
@_handleImage URL.createObjectURL(file)
@_checkImagesInContainer ->

_handleImage: (src)->
loader = new Image()
loader.onload = =>
canvas = document.createElement 'canvas'
canvas.width = loader.width
canvas.height = loader.height
ctx = canvas.getContext '2d'
ctx.drawImage loader, 0, 0, canvas.width, canvas.height
dataURL = null
try
dataURL = canvas.toDataURL 'image/png'
if dataURL
@_target.trigger 'pasteImage',
dataURL: dataURL
width: loader.width
height: loader.height
loader.src = src

_checkImagesInContainer: (cb)->
timespan = Math.floor 1000 * Math.random()
img["_paste_marked_#{timespan}"] = true for img in @_container.find('img')
setTimeout =>
for img in @_container.find('img')
cb img.src unless img["_paste_marked_#{timespan}"]
$(img).remove()
, 1
Loading

0 comments on commit ac4ce33

Please sign in to comment.