Às vezes, você não pode usar iframes, mas ainda quer seu próprio design e fazer com que o iframe execute seus comandos, mas fique invisível. Fiz um pequeno utilitário que usa o postmessage para enviar e receber dados DOM analisados por json.
Ainda não configurei tudo isso para ser 100% seguro, suas chamadas de origem são curingas, o que na produção não seria aconselhável. De qualquer forma, funciona e você pode enviar fluxo através do iframe e detectar erros verificando em qual página ele está ou o que o dom está fazendo. Não é bonito, mas os iframes não são bonitos.
Coloque-o no lado do iframe para permitir alguma manipulação de dom por meio de pacotes postmessage
# DOM Manipulation via PostMessage
#
do ( dom = window ) ->
#
# Abstract API for doing small DOM manipulations
#
class DomManipulator
parseHTML: ( strHtml ) ->
elConverted = document.implementation.createHTMLDocument()
elConverted.body.innerHTML = strHTML
elConverted.body.children
stringifyHTML: ( elTarget ) ->
if typeof elTarget is 'object' then elTarget.outerHTML else false
getElement: ( strElement ) ->
elTarget = document.body.querySelector( strElement )
elTarget
getText: ( strElement ) ->
elTarget = @getElement strElement
elTarget.textContent
getProperty: ( strElement, strProperty ) ->
elTarget = @getElement strElement
if elTarget then elTarget.getAttribute( strProperty ) else false
setProperty: ( strElement, strProperty, strValue ) ->
elTarget = @getElement strElement
if elTarget then elTarget.setAttribute strProperty, strValue #elTarget[strProperty] = strValue
@getProperty strElement, strProperty
doMouseEvent: ( strElement, strEvent ) ->
elTarget = @getElement strElement
if elTarget
evtMouseAny = document.createEvent('MouseEvents')
evtMouseAny.initMouseEvent strEvent, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null
elTarget.dispatchEvent evtMouseAny
true
false
#
# Extends DOM Manipulator and transforms the manipulations to be compatible with PostMessage
#
class PostMessageDomManipulator extends DomManipulator
constructor: () ->
#
# Public PostMessage DomManipulator API
#
@objApi =
getElement: (( objOptions, objJsonData ) ->
strElement = objOptions['strElement']
if strElement then objJsonData.strReturn = @stringifyHTML @getElement(strElement)
).bind @
getText: (( objOptions, objJsonData ) ->
strElement = objOptions['strElement']
if strElement then objJsonData.strReturn = @getText strElement
).bind @
getProperty: (( objOptions, objJsonData ) ->
strElement = objOptions['strElement']
strProperty = objOptions['strProperty']
if strElement and strProperty then objJsonData.strReturn = @getProperty strElement, strProperty
).bind @
setProperty: (( objOptions, objJsonData ) ->
strElement = objOptions['strElement']
strProperty = objOptions['strProperty']
strValue = objOptions['strValue']
if strElement and strProperty and strValue then objJsonData.strReturn = @setProperty strElement, strProperty, strValue
).bind @
doMouseEvent: (( objOptions, objJsonData ) ->
strElement = objOptions['strElement']
strEvent = objOptions['strEvent']
if strElement and strEvent then objJsonData.strReturn = @doMouseEvent strElement, strEvent
).bind @
# Give a debug message that can be read
console.debug 'Initializing postMessage protocol'
# Bind the postMessage to onReceiveData. That will transform the call for the Public API
dom.addEventListener 'message', @onReceiveData.bind( @ )
@doSendData.bind(@) boolInitialized: true, strId: 'intitialize'
#
# For receiving messages via PostMessage to DOM Manipulation
#
onReceiveData: ( e ) ->
strOrigin = e.origin
objJsonData = JSON.parse e.data
strLocation = objJsonData['strLocation']
strAction = objJsonData['strAction']
objParameters = objJsonData['objParameters']
# Parent always needs to say what he expects, else we might end up going out of sync
boolExpected = strLocation is window.location.href or strLocation is '*'
boolOrigin = true
boolAction = strAction
boolParameters = objParameters
boolPassing = boolExpected and boolOrigin and boolAction and boolParameters
if not boolPassing then return @doSendData strErrorMessage: 'Origin not allowed or you were expecting someone else.'
# Try to execute the request by testing if the action exists and can be called
try
objJsonData['strReturn'] = false
if @objApi[strAction] then @objApi[strAction]( objParameters, objJsonData )
@doSendData objJsonData
catch
@doSendData { strErrorMessage: 'Could not pass action onto manipulator. Something malformed..' }
#
# For sending messages via PostMessage back to the parent
#
doSendData: ( objData = {} ) ->
objData.objLocation = window.location
objData.strId = objData.strId or 'keep-alive'
strOrgin = '*' # Needs to be set for safety, only send messages to allowed domain
strJsonData = JSON.stringify objData
if parent
parent.postMessage strJsonData, strOrgin
#
# on DOMContentLoaded initialize the PostMessageDomManipulator
#
onLoad = () ->
dom.pmdm = new PostMessageDomManipulator()
dom.addEventListener 'DOMContentLoaded', onLoad
No lugar dos pais algo como
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
window.onload = function() {
var onClickDemo = function() {
console.info('Trying to post a message to the target');
var objData = {
strId: '',
strLocation: '*',
strAction: 'setProperty',
objParameters: {
strElement: '#amount',
strProperty: 'value',
strValue: '100'
}
}
document.getElementsByTagName('iframe')[0].contentWindow.postMessage(JSON.stringify(objData), '*');
},
onClickTriggerDemo = function() {
console.info('Trying to trigger the mouse event');
var objData = {
strId: 'ontoNextPage',
strLocation: '*',
strAction: 'doMouseEvent',
objParameters: {
strElement: '#continueButton',
strEvent: 'click'
}
}
document.getElementsByTagName('iframe')[0].contentWindow.postMessage(JSON.stringify(objData), '*');
},
onGetErrorMessage = function() {
console.info('Trying to get the error');
var objData = {
strLocation: '*',
strAction: 'getElement',
objParameters: {
strElement: '#textWithdrawalDeclined'
}
}
document.getElementsByTagName('iframe')[0].contentWindow.postMessage(JSON.stringify(objData), '*');
}
onMessageReceived = function( e ) {
console.debug( 'data;', JSON.parse(e.data));
}
elIframe = document.createElement('iframe');
elIframe.width = '100%';
elIframe.height = '800';
document.body.querySelectorAll( '.try' )[0].addEventListener('click', onClickDemo);
document.body.querySelectorAll( '.do' )[0].addEventListener('click', onClickTriggerDemo);
window.addEventListener( 'message', onMessageReceived )
document.body.appendChild(elIframe);
}
</script>
<input type="submit" value="Try a postMessage" class="try">
<input type="submit" value="Try a trigger" class="do">
</body>
</html>
Basicamente, você joga pacotes sobre a linha JSON stringified:
var objData = {
strId: '',
strLocation: '*',
strAction: 'setProperty',
objParameters: {
strElement: '#amount',
strProperty: 'value',
strValue: '100'
}
}
document.getElementsByTagName('iframe')[0].contentWindow.postMessage(JSON.stringify(objData), '*');
PostMessage DOM que fiz muito pequeno, você tem o seguinte:
- getElement
- getText
- getProperty
- setProperty
- doMouseEvent
Você pode verificá-los e adicioná-los no DomManipulator
Felicidades!