Что нового

Получение CSS стилей у элемента без атрибута style

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Есть ли возможность получить CSS стиль у элемента, у которого отсутствует атрибут style?

HTML:
<div id="test"></div>

сам стиль элемента ведь может задаваться в заголовке (head), через #test {...}, так вот мне и нужно его узнать на лету, не прибегая к крайним мерам (парсинг заголовка страницы).

Вроде есть cssText, но не работает...
Пример:
Код:
#include <IE.au3>

$oIE = _IECreate('', 0, 0)
_IEDocWriteHTML($oIE, '<html><head><style type="text/css">#test {border: thin solid;float: left;text-align: center;}</style></head><body><div id="test">hi</div></body></html>')
$oTest = _IEGetObjById($oIE, 'test')

;Тут я бы хотел увидеть "border: thin solid;float: left;text-align: center;"
ConsoleWrite($oTest.style.cssText() & @CRLF)

_IEQuit($oIE)


:scratch:
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
CreatoR [?]
мне и нужно его узнать на лету
Код:
$oIE = _IECreate('', 0, 0)
_IEDocWriteHTML($oIE, '<html><head><style type="text/css">#test {background-color: lightblue; border: thin solid; float: left; text-align: center;}</style></head><body><div id="test">hi</div></body></html>')
$oElem = _IEGetObjById($oIE, 'test')
$oWind = $oIE.document.parentWindow

$oSCntrl = ObjCreate("ScriptControl")
With $oSCntrl
   .Language = 'JScript'
   .AddObject('window', $oWind, False)
   .AddCode('function getStyle(elem){ return window.getComputedStyle ? window.getComputedStyle(elem, "") : elem.currentStyle; }')
   $oEl = .Run('getStyle', $oElem)
EndWith

MsgBox(0, "", StringFormat( "#test {\n\t" _
						   &"background-color: %s;\n\t" _
						   &"border-width: %s;\n\t" _
						   &"border-style: %s\n\t" _
						   &"float: %s\n\t" _
						   &"text-align: %s\n}", _
						   $oEl.getPropertyValue("background-color"), _
						   $oEl.getPropertyValue("border-left-width"), _
						   $oEl.getPropertyValue("border-left-style"), _
						   $oEl.getPropertyValue("float"), _
						   $oEl.getPropertyValue("text-align")))

_IEQuit($oIE)


P.S. Win7 x86 IE11
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Garrett
Мне нужно получить "#test {background-color: lightblue; border: thin solid; float: left; text-align: center;}", я не знаю заранее что там внутри, какие там свойства.

А вообще если подумать, на самом деле мне нужно наверное присваивать стили выбранному элементу (при чём и его дочерним элементам), при том что я заранее не знаю какие стили используются на странице.
Можно конечно получить стили:

Код:
Func _IEGetStyleSheets($oIE)
	Local $oCSSs = $oIE.Document.StyleSheets
	Local $sCSS = ''
	
	If IsObj($oCSSs) Then
		For $oCSS In $oCSSs
			$sCSS &= $oCSS.cssText & @CRLF
		Next
		
		$sCSS = '<style type="text/css">' & @CRLF & StringStripWS($sCSS, 3) & @CRLF & '</style>'
	EndIf
	
	Return $sCSS
EndFunc


и тогда не трогать элементы, а просто использовать в заголовке глобальные стили.
Но было бы конечно лучше как бы расширить классы до их используемых стилей:

HTML:
<div class="myclass" style="float: left;">
тут class="myclass" должен "превратиться" в стили и подставиться в атрибут style (если он имеется конечно, если нет - то создать его).
Кстати интересно, в таком случае style игнорируется (если класс задан)? или они совместно действуют?
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
CreatoR [?]
мне нужно наверное присваивать стили выбранному элементу (при чём и его дочерним элементам)
Так?
Код:
#include <IE.au3>

$oIE = _IECreate('')
_IEDocWriteHTML($oIE, '<html><head><style type="text/css">#test {background-color: lightblue; border: thin solid; float: left; text-align: center;}</style></head><body><div id="test">hi</div></body></html>')
$oElem = _IEGetObjById($oIE, 'test')
$oWind = $oIE.document.parentWindow
$oDoc = $oIE.document

$oSCntrl = ObjCreate("ScriptControl")
With $oSCntrl
   .Language = 'JScript'
   .AddObject('window', $oWind, False)
   .AddObject('document', $oDoc, False)
   .AddCode('function getStyle(elem){ return window.getComputedStyle ? window.getComputedStyle(elem, "") : elem.currentStyle; }')
   .AddCode('function setStyle(newStyle){ var styleElement = document.getElementById("styles_CreatoR"); if (!styleElement){ styleElement = document.createElement("style"); styleElement.type = "text/css"; styleElement.id = "styles_CreatoR"; document.getElementsByTagName("head")[0].appendChild(styleElement); } styleElement.appendChild(document.createTextNode(newStyle)); }')
   $oEl = .Run('getStyle', $oElem)
EndWith

; смотрим
MsgBox(0, "", StringFormat( "#test {\n\t" _
						   &"background-color: %s;\n}", _
						   $oEl.getPropertyValue("background-color")))

Sleep(1000)

; добавляем
With $oSCntrl
   $oEl = .Run('setStyle', '#test {width: 300px; background-color: #FF9933 !important;}')
   $oEl = .Run('getStyle', $oElem)
EndWith

; смотрим
MsgBox(0, "", StringFormat( "#test {\n\t" _
						   &"background-color: %s;\n}", _
						   $oEl.getPropertyValue("background-color")))
Sleep(1000)

_IEQuit($oIE)


P.S. Win7 x86 IE11
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Garrett [?]
Не совсем.
Попробую описать получше...

Мне нужно из некой страницы получить элемент (div), и отобразить его в своём Embed IE, так вот я бы хотел чтобы при отображений сохранились стили той страницы откуда я взял элемент.
Вот как я делаю сейчас:

Код:
#include <IE.au3>

$sURL = 'https://autoit-script.ru'
$sID = 'upper_section'

$oMy_IE = _IECreate('about:blank')
$oTmp_IE = _IECreate($sURL, 0, 0, 0, 0)

$oDiv = _IEGetObjById($oTmp_IE, $sID)

$oHead = $oMy_IE.document.head
$oStyle = $oMy_IE.document.createElement('Style')
$oStyle.setAttribute('type', 'text/css')
$oStyle.innerText = _IEExpandRelativePath(_IEGetStyleSheets($oTmp_IE), $sURL)
$oHead.insertBefore($oStyle)

_IEBodyWriteHTML($oMy_IE, _IEExpandRelativePath($oDiv.OuterHtml, $sURL))
_IEAction($oMy_IE, 'visible')

_IEQuit($oTmp_IE)

Func _IEGetStyleSheets($oIE)
	Local $oCSSs = $oIE.Document.StyleSheets
	Local $sCSS = ''
	
	If IsObj($oCSSs) Then
		For $oCSS In $oCSSs
			$sCSS &= $oCSS.cssText & @CRLF
		Next
		
		$sCSS = StringStripWS($sCSS, 3)
	EndIf
	
	Return $sCSS
EndFunc

;Кстати тут бы не помешала какая то альтернатива (для выпрямления ссылок), потому что это не надёжно (например ссылки типа "../" не выпрямляет)
Func _IEExpandRelativePath($sHtml, $sURL)
	$sHtml = StringRegExpReplace($sHtml, '(?i)(url\("|url":")//', '\1http://')
	$sHtml = StringRegExpReplace($sHtml, '(?i) href=(")?//', ' href=\1http://')
	$sHtml = StringRegExpReplace($sHtml, '(?i) src=(")?//', ' src=\1http://')
	$sHtml = StringRegExpReplace($sHtml, '(?i)(url\("|url":")\.\./', '\1' & $sURL & '/../')
	$sHtml = StringRegExpReplace($sHtml, '(?i) href=(")?/', ' href=\1' & $sURL & '/')
	$sHtml = StringRegExpReplace($sHtml, '(?i) src=(")?/', ' src=\1' & $sURL & '/')
	
	Return $sHtml
EndFunc


но это долго, и оно подгружает все стили, не важно используются они выбранным элементом или нет.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
OffTopic:
Кстати, вот как я придумал сделать выпрямитель ссылок:

Код:
Func _IEExpandRelativePath($oSrcIE, $sDstHtml)
	Local $aURLs = StringRegExp($sDstHtml, '(?i)(?:url(?:\(|":)|(?:href|src)=)"([^"]+?)"', 3)
	
	For $i = 0 To UBound($aURLs) - 1
		$oA = $oSrcIE.document.createElement('a')
		$oA.href = $aURLs[$i]
		$sDstHtml = StringRegExpReplace($sDstHtml, '(?i)(url(?:\(|":)|(?:href|src)=)"' & $aURLs[$i] & '"', '\1' & $oA.href)
		$oA.remove()
	Next
	
	Return $sDstHtml
EndFunc


Т.е создаётся временный элемент ссылки (а), куда помещается относительная ссылка, и уже там она автоматический выпрямляется.
Впрочем это не быстрее, а возможно даже дольше обрабатывает...
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
CreatoR
Долго я "мозг морщил", взвешивал все за и против, в итоге написал оптимальное решение (IMHO). :scratch:

Мне нужно из некой страницы получить элемент (div), и отобразить его в своём Embed IE
Тут дело в том, что один DIV может тянуть за собой несколько родительских, которые в свою очередь влияют на стиль.
Решение:
- для каждого случая своё.

так вот я бы хотел чтобы при отображений сохранились стили той страницы откуда я взял элемент.
IMHO, копирование ссылок достаточно в данном случае.
Однако, может быть недостаточным в других случаях.
Решение:
- опять же, для каждого случая своё.
Код:
#include <IE.au3>

;~ Мне нужно из некой страницы получить элемент (div),
$oIE = _IECreate('https://autoit-script.ru')
$oUpperSection = _IEGetObjById($oIE, 'upper_section')
$oTopSection = _IEGetObjById($oIE, 'top_section')
$oStyles = _IETagNameGetCollection($oIE, 'link')

;~ и отобразить его в своём Embed IE
$oMyIE = _IECreate('about:blank')
_IEDocWriteHTML($oMyIE, '<html><head></head><body>' _
					   &'	<div id="wrapper" style="width: 90%">' _
					   &'		<div id="header"><div class="frame">' _
					   &'			<div id="top_section">' _
					   &'				<img id="upshrink" src="'& $oTopSection.firstElementChild.src _
					   &'					" alt="*" title="Свернуть/Развернуть" style="cursor: pointer;">' _
					   &'				<a href="'& $oTopSection.firstElementChild.nextSibling.href &'">' _
					   &'					<img id="smflogo" src="'& $oTopSection.firstElementChild.nextSibling.firstElementChild.src _
					   &'						" alt="Русское сообщество AutoIt" title="Русское сообщество AutoIt">' _
					   &'				</a>' _
					   &'			</div>'& $oUpperSection.outerHtml &'</div></div></div></body></html>')

;~  так вот я бы хотел чтобы при отображений сохранились стили той страницы откуда я взял элемент.
For $oStile In $oStyles
   If $oStile.rel == "stylesheet" Then
	  _IESetStylesheet($oMyIE, $oStile.href)
	  ; ConsoleWrite(StringFormat("%s\n", $oStile.href))
   EndIf
Next

Func _IESetStylesheet($_Obj, $_Url)

   $oHead = $_Obj.document.getElementsByTagName('head')(0)
   $oLink = $_Obj.document.createElement('link')
   $oLink.rel  = 'stylesheet'
   $oLink.type = 'text/css'
   $oLink.href = $_Url
   $oLink.media = 'all'
   $oHead.appendChild($oLink)
EndFunc ;==>_IESetStylesheet

P.S. Win7 x86 IE11
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Garrett
Решение хорошее, возьму его на заметку, но увы мою проблему оно не решает, с шапкой этого форума - это был пример, мне нужно нечто более универсальное.

OffTopic:
Кстати а что по поводу выпрямления ссылок, есть идеи как это ускорить, или может есть метод получше? :scratch:


Спасибо.
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
CreatoR [?]
но увы мою проблему оно не решает
Если данные не конфиденциальные, то ссылка была бы кстати.

Кстати а что по поводу выпрямления ссылок, есть идеи как это ускорить, или может есть метод получше?
Честно говоря не пойму о чём вы? Если о ссылках в HTML и CSS, то они уже возвращаются скриптом абсолютными.
Код:
#include <IE.au3>
$oIE = _IECreate('https://autoit-script.ru')
;~ $oElem = _IEGetObjById($oIE, 'upper_section')
$oElem = _IETagNameGetCollection($oIE, 'body', 0)
$oWind = $oIE.document.parentWindow
$oDoc = $oIE.document

$oSCntrl = ObjCreate("ScriptControl")
With $oSCntrl
   .Language = 'JScript'
   .AddObject('window', $oWind, False)
   .AddObject('document', $oDoc, False)
   .AddCode('function getStyle(elem, sel){ var sel = document.querySelector(sel); var ret = window.getComputedStyle ? window.getComputedStyle(elem, sel) : elem.currentStyle; return ret; }')
EndWith

$oGetStyle = $oSCntrl.Run('getStyle', $oElem, Null)

For $i = 0 To $oGetStyle.length - 1
   $sStyle =  $oGetStyle.item($i)
   $sVal = $oGetStyle.getPropertyValue($sStyle)
   ; If $sVal <> "" Then ConsoleWrite(StringFormat("%s : %s\n", $sStyle, $sVal))
   If $sVal <> "" And $sStyle == "background-image" Then ConsoleWrite(StringFormat("%s : %s\n", $sStyle, $sVal))
Next
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Garrett [?]
Если данные не конфиденциальные, то ссылка была бы кстати.
Это может быть любой сайт.
Ну допустим, один из тех где есть проблемы - это http://m.facebook.com/

Вот пример как я делаю на данный момент:

Код:
#include <IE.au3>

$sURL = 'https://m.facebook.com'
$sID = 'tag=div|id=RE:u_.+?|role=article'

$oMain_IE = _IECreate('', 0, 0)
$oEmbed = _IEEmbed_Create()

_IENavigate($oMain_IE, $sURL, 1)

$sHtml = '<html><head>' & @CRLF & '<meta charset="utf-8" />' & @CRLF & _IEGetStyleSheets($oMain_IE) & @CRLF & '</head><body>'

$aoContent = _IEGetObjByParams($oMain_IE, $sID, True)

If IsArray($aoContent) And IsObj($aoContent[1]) Then
	For $i = 1 To $aoContent[0]
		$sHtml &= @CRLF & '<div id="FB" style="padding: 20px; border: 2px solid black;>' & $aoContent[$i].OuterHtml & '</div>
' & @CRLF
	Next
EndIf

$sHtml &= '</body></html>'

_IEDocWriteHTML($oEmbed, $sHtml)
_IEAction($oEmbed, 'visible')
_IEQuit($oMain_IE)

Func _IEEmbed_Create()
	Local $oEmbed = _IECreate('', 0, 0)
	
	_IEPropertySet($oEmbed, 'Silent', True)
	_IEPropertySet($oEmbed, 'ToolBar', False)
	_IEPropertySet($oEmbed, 'AddressBar', False)
	_IEPropertySet($oEmbed, 'MenuBar', False)
	_IEPropertySet($oEmbed, 'StatusBar', False)
	_IEPropertySet($oEmbed, 'Resizable', False)
	
	Return $oEmbed
EndFunc

Func _IEGetObjByParams($oObj, $sParams, $bRetAllObjcts = False)
	Local $aParams = StringRegExp($sParams, '(?i)(.*?)=(.*?)(?:\||$)', 3)
	If Mod(UBound($aParams), 2) <> 0 Then Return SetError(1, 0, 0)
	
	Local $oTags = _IETagNameAllGetCollection($oObj)
	Local $iCount = @extended, $vTag, $bRegExp
	Local $aFound_Tags[$iCount]
	
	For $oTag In $oTags
		For $i = 0 To UBound($aParams) - 1 Step 2
			$aParams[$i] &= (($aParams[$i] = 'class' Or $aParams[$i] = 'tag') ? 'name' : '')
			
			$vTag = $oTag.getAttribute($aParams[$i])
			If Not $vTag Then $vTag = Execute('$oTag.' & $aParams[$i])
			
			$bRegExp = StringLeft($aParams[$i + 1], 3) = 'RE:'
			$sNextParam = $aParams[$i + 1]
			
			If $bRegExp Then
				$sNextParam = StringTrimLeft(StringReplace($aParams[$i + 1], '~', '|'), 3)
			EndIf
			
			If ($bRegExp And Not StringRegExp($vTag, '(?i)' & $sNextParam)) Or (Not $bRegExp And String($vTag) <> String($sNextParam)) Then
				ContinueLoop 2
			EndIf
		Next
		
		;Tag is ok (matched params)
		$aFound_Tags[0] += 1
		$aFound_Tags[$aFound_Tags[0]] = $oTag
	Next
	
	If $aFound_Tags[0] > 0 Then
		ReDim $aFound_Tags[$aFound_Tags[0] + 1]
		
		If $bRetAllObjcts Then
			Return $aFound_Tags
		EndIf
		
		Return $aFound_Tags[1]
	EndIf
	
	Return SetError(2, 0, 0)
EndFunc

Func _IEGetStyleSheets($oIE)
	Local $oCSSs = $oIE.Document.StyleSheets
	Local $sCSS = ''
	
	If IsObj($oCSSs) Then
		For $oCSS In $oCSSs
			$sCSS &= $oCSS.cssText & @CRLF
		Next
		
		$sCSS = '<style type="text/css">' & @CRLF & StringStripWS($sCSS, 3) & @CRLF & '</style>'
	EndIf
	
	Return $sCSS
EndFunc


Перед запуском нужно убедиться что в фейсбуке произведён вход в аккаунт из под Internet Explorer.
Здесь я убрал выпрямление ссылок, и в коде страницы явно видно что ссылки относительные.

Вот в этом примере хотелось бы увидеть как можно получая блоки кода, расширить указанные в них стили (по классу или в явном виде) до их реальных значений, также и с ссылками.
 
Верх