@ -33,7 +33,7 @@ import {
FONTS ,
FONTS ,
} from '../lib/constants'
} from '../lib/constants'
import { serializeState , getRouteState } from '../lib/routing'
import { serializeState , getRouteState } from '../lib/routing'
import { getSettings , unescapeHtml , formatCode , omit } from '../lib/util'
import { getSettings , unescapeHtml , formatCode , omit , dataURLtoBlob } from '../lib/util'
import domtoimage from '../lib/dom-to-image'
import domtoimage from '../lib/dom-to-image'
const languageIcon = < LanguageIcon / >
const languageIcon = < LanguageIcon / >
@ -110,32 +110,8 @@ class Editor extends React.Component {
exportSize = ( EXPORT _SIZES _HASH [ this . state . exportSize ] || DEFAULT _EXPORT _SIZE ) . value ,
exportSize = ( EXPORT _SIZES _HASH [ this . state . exportSize ] || DEFAULT _EXPORT _SIZE ) . value ,
} = { format : 'png' }
} = { format : 'png' }
) => {
) => {
// if safari, get image from api
const isPNG = format !== 'svg'
if ( this . context . image && this . isSafari && isPNG ) {
const themeConfig = this . getTheme ( )
// pull from custom theme highlights, or state highlights
const encodedState = serializeState ( {
... this . state ,
highlights : { ... themeConfig . highlights , ... this . state . highlights } ,
} )
return this . context . image ( encodedState )
}
const node = this . carbonNode . current
const node = this . carbonNode . current
// const map = new Map()
// if (isPNG) {
// node.querySelectorAll('span[role="presentation"]').forEach(node => {
// if (node.innerText && node.innerText.match(/%[A-Fa-f0-9]{2}/)) {
// map.set(node, node.innerHTML)
// node.innerText.match(/%[A-Fa-f0-9]{2}/g).forEach(t => {
// node.innerHTML = node.innerHTML.replace(t, encodeURIComponent(t))
// })
// }
// })
// }
const width = node . offsetWidth * exportSize
const width = node . offsetWidth * exportSize
const height = squared ? node . offsetWidth * exportSize : node . offsetHeight * exportSize
const height = squared ? node . offsetWidth * exportSize : node . offsetHeight * exportSize
@ -163,14 +139,13 @@ class Editor extends React.Component {
// current font-family used
// current font-family used
const fontFamily = this . state . fontFamily
const fontFamily = this . state . fontFamily
try {
// TODO consolidate type/format to only use one param
// TODO consolidate type/format to only use one param
if ( type === 'objectURL' ) {
if ( format === 'svg' ) {
if ( format === 'svg' ) {
return domtoimage
return domtoimage
. toSvg ( node , config )
. toSvg ( node , config )
. then ( dataUrl =>
. then ( dataURL =>
dataUrl
dataURL
. replace ( / /g , ' ' )
. replace ( / /g , ' ' )
// https://github.com/tsayen/dom-to-image/blob/fae625bce0970b3a039671ea7f338d05ecb3d0e8/src/dom-to-image.js#L551
// https://github.com/tsayen/dom-to-image/blob/fae625bce0970b3a039671ea7f338d05ecb3d0e8/src/dom-to-image.js#L551
. replace ( /%23/g , '#' )
. replace ( /%23/g , '#' )
@ -185,21 +160,28 @@ class Editor extends React.Component {
)
)
. then ( uri => uri . slice ( uri . indexOf ( ',' ) + 1 ) )
. then ( uri => uri . slice ( uri . indexOf ( ',' ) + 1 ) )
. then ( data => new Blob ( [ data ] , { type : 'image/svg+xml' } ) )
. then ( data => new Blob ( [ data ] , { type : 'image/svg+xml' } ) )
. then ( data => window . URL . createObjectURL ( data ) )
}
}
return await domtoimage . toBlob ( node , config ) . then ( blob => window . URL . createObjectURL ( blob ) )
// if safari, get image from api
if ( this . context . image && this . isSafari ) {
const themeConfig = this . getTheme ( )
// pull from custom theme highlights, or state highlights
const encodedState = serializeState ( {
... this . state ,
highlights : { ... themeConfig . highlights , ... this . state . highlights } ,
} )
// TODO consider returning blob responseType from axios
return this . context
. image ( encodedState )
. then ( dataURL => ( type === 'blob' ? dataURLtoBlob ( dataURL ) : dataURL ) )
}
}
if ( type === 'blob' ) {
if ( type === 'blob' ) {
return await domtoimage . toBlob ( node , config )
return domtoimage . toBlob ( node , config )
}
}
// Twitter needs regular dataurls
// Twitter needs regular dataURLs
return await domtoimage . toPng ( node , config )
return domtoimage . toPng ( node , config )
} finally {
// map.forEach((value, node) => (node.innerHTML = value))
}
}
}
tweet = ( ) => {
tweet = ( ) => {
@ -213,7 +195,9 @@ class Editor extends React.Component {
const prefix = options . filename || this . state . name || 'carbon'
const prefix = options . filename || this . state . name || 'carbon'
return this . getCarbonImage ( { format , type : 'objectURL' } ) . then ( url => {
return this . getCarbonImage ( { format , type : 'blob' } )
. then ( blob => window . URL . createObjectURL ( blob ) )
. then ( url => {
if ( format !== 'open' ) {
if ( format !== 'open' ) {
link . download = ` ${ prefix } . ${ format } `
link . download = ` ${ prefix } . ${ format } `
}
}
@ -228,13 +212,15 @@ class Editor extends React.Component {
}
}
copyImage = ( ) =>
copyImage = ( ) =>
this . getCarbonImage ( { format : 'png' , type : 'blob' } ) . then ( blob =>
this . getCarbonImage ( { format : 'png' , type : 'blob' } )
. then ( blob =>
navigator . clipboard . write ( [
navigator . clipboard . write ( [
new window . ClipboardItem ( {
new window . ClipboardItem ( {
'image/png' : blob ,
[ blob . type ] : blob ,
} ) ,
} ) ,
] )
] )
)
)
. catch ( console . error )
updateSetting = ( key , value ) => {
updateSetting = ( key , value ) => {
this . updateState ( { [ key ] : value } )
this . updateState ( { [ key ] : value } )