I was experimenting with this HTML comparison recently, which is somewhat working:
/**
* Compare 2 dom nodes
* Given A node, identifier, B node, identifier, depth.
*/
function compare(A,Aid,B,Bid,godeep) {
if (A.nodeName != B.nodeName) {
addlog(Aid+' is <'+A.nodeName+'>, '+Bid+' is <'+B.nodeName+'>.');
}
for (let a=0; a<A.attributes.length; a++) {
let key = A.attributes[a].name,
other = B.attributes[key];
if (other !== undefined) {//both have attr.
if (A.attributes[a].value != other.value) {
addlog(Aid+' has attr '+key+'='+A.attributes[key].value);
addlog(Bid+' has attr '+key+'='+B.attributes[key].value);
}
} else {
addlog(Aid+' has attr '+key+'='+A.attributes[key].value+', not in other el.')
}
}
//Also check for the other's unique attr:
for (let b=0; b<B.attributes.length; b++) {
let key = B.attributes[b].name,
other = A.attributes[key];
if (other === undefined) {
addlog(Bid+' has attr '+key+'='+A.attributes[key].value+', not in other el.')
}
}
//TODO: Why does this not work correctly for styles? height and other attributes are not the same
// when comparing the same element to itself.
var cssA = A.ownerDocument.defaultView.getComputedStyle(A,null),
cssB = B.ownerDocument.defaultView.getComputedStyle(B,null);
console.log(cssA);
console.log(cssB);
for (let i=0; i<cssA.length; i++) {
if (cssA.getPropertyValue(cssA[i]) != cssB.getPropertyValue(cssB[i])) {
addlog(Aid+' css '+cssA[i]+'='+cssA.getPropertyValue(cssA[i]));
addlog(Bid+' css '+cssB[i]+'='+cssB.getPropertyValue(cssB[i]));
}
}
if (A.children.length != B.children.length) {
addlog(Aid+' has '+A.children.length+' children, '+Bid+' has '+B.children.length);
}
if (godeep > 0) {
for (let i=0; i<A.children.length; i++) {
if (i< B.children.length) { //compare it
compare(A.children[i], Aid+'.children['+i+']',
B.children[i], Bid+'.children['+i+']')
}
}
}
}
(Full source here) The odd thing is, when comparing the same node to itself, it says its own properties are different:
A css border-bottom-color=rgb(0, 0, 0)
B css border-bottom-color=rgb(51, 51, 51)
A css border-left-color=rgb(0, 0, 0)
B css border-left-color=rgb(51, 51, 51)
A css border-right-color=rgb(0, 0, 0)
B css border-right-color=rgb(51, 51, 51)
A css border-top-color=rgb(0, 0, 0)
B css border-top-color=rgb(51, 51, 51)
A css color=rgb(0, 0, 0)
B css color=rgb(51, 51, 51)
A css font-family=serif
B css font-family=Helvetica,arial,freesans,clean,sans-serif
A css font-size=16px
B css font-size=14px
A css font-weight=400
B css font-weight=700
A css height=auto
B css height=19.6px
A css line-height=19px
B css line-height=19.6px
A css list-style-type=disc
B css list-style-type=none
A css margin-bottom=16px
B css margin-bottom=1px
A css margin-top=16px
B css margin-top=1px
A css perspective-origin=50% 50%
B css perspective-origin=429px 9.8px
A css transform-origin=50% 50%
B css transform-origin=429px 9.8px
A css width=auto
B css width=858px
A css -moz-column-gap=16px
B css -moz-column-gap=14px
A css -moz-column-rule-color=rgb(0, 0, 0)
B css -moz-column-rule-color=rgb(51, 51, 51)
A css -moz-text-decoration-color=rgb(0, 0, 0)
B css -moz-text-decoration-color=rgb(51, 51, 51)
What could be causing this conflict? Is there some way to use getComputedStyle without this odd behavior?
Update
Here you can see this works in the browser, but it doesn't work in Chrome-privileged code, as you can see if you try this branch of devtools-tweaks.
Looks like the problem was the input - node.cloneNode(true) apparently detaches the element from its css styling information.
Related
We are using ExtJS 4.2.1. The width/height attributes of the img won't change in below example when element is dragged beyond the +/-5px y-coordinate. Changes to attribute 'show' are also ignored. However, element can be destroyed and re-created, but this is not desired.
[panel]
var dndLinkSprite = me.surface.add({
type: 'image',
x: bBox.x,
y: bBox.y,
width: 16,
height: 16,
src: '/link.png'
})
...
dragAction: function(panel, e, diff, dndConfig) {
var spriteLink = panel.dndLinkSprite;
if ( diff[1] > 5 || diff[1] < -5 ) {
spriteLink.setAttributes(height, 16);
spriteLink.setAttributes(width, 16);
} else {
spriteLink.setAttributes(height, 0);
spriteLink.setAttributes(width, 0);
};
}
Thanks for your help!
Solved - wrong syntax:
Instead of:
spriteLink.setAttributes(height, 0);
spriteLink.setAttributes(width, 0);
use:
spriteLink.setAttributes({width: 0, height:0} , true);
spriteLink.getEl().dom.setAttribute(height, 16);
Now I make markdown highlighter.
Highlight inline is not so difficult. I use CompositeDecorator to rewrite text. https://facebook.github.io/draft-js/docs/advanced-topics-decorators.html
But I can't use multiline syntax (for example, codeblock). By default, newline becomes next block and decorator is handled by block to block.
Below image is example of my implementation. I can't decorate codeblock syntax.
How do I make multiline highlighter on draft-js?
Depends on what 'Highlight' style you want. Mostly the inline style should be enough if you just want some color or font size. check the color example.
While for block style, you need a custom CSS class and map the block to your class, refer this.
I found work around. Detecting markdown codeblock by dand on blockRendererFn.
// use blockRedererFn
<Editor
blockRendererFn={(block) => blockRenderer(block, this.state.editorState)}
editorState={this.state.editorState}
/>;
// detect code block and add fontFamily: monospace
// Example
//
// ```
// here
// ```
function blockRenderer(contentBlock, editorState) {
const type = contentBlock.getType();
if (type === "unstyled") {
const allText = editorState.getCurrentContent().getPlainText();
const allCount = countCodeBlockHeader(allText);
if (allCount > 0 && allCount % 2 === 0) {
const contentText = contentBlock.getText();
const [before, after] = allText.split(contentText);
const beforeCount = countCodeBlockHeader(before);
const afterCount = countCodeBlockHeader(after);
if (beforeCount % 2 === 1) {
if (afterCount % 2 === 1) {
return {
component: (_props) => {
return <code style={{
fontFamily: "monospace",
direction: "ltr",
unicodeBidi: "bidi-override",
}}>{contentText}</code>;
},
editable: true
};
}
}
}
}
}
function countCodeBlockHeader(text) {
return text
.split("\n")
.filter(l => l.match(new RegExp("^(```)")))
.length;
}
but it's dirty.
I know tumblr has the defualt photoset sizes {photoset-500},{photoset-400},{photoset-250}, but I want to change the width, so that the width could be either 420, or 350. i have looked everywhere and cannot find a code to help me do this.
You can use {Photoset} which just resizes the photoset to fit the container (max size 700px).
https://www.tumblr.com/docs/en/custom_themes
You cannot change default sizes of images with Tumblr markup, but you can visually change size with CSS.
Tumblr markup:
{block:Photoset}
{block:Photos}
<img src="{PhotoURL-500}" class="photoset-img" />
{/block:Photos}
{/block:Photoset}
CSS:
.photoset-img { width: 420px; /* can be any value you want */ }
Add this script before the ending body tag. This will increase or decrease the size of the photoset
<script type="text/javascript">
//This will change the source address and display the correct size.
$(".photoset").each(function() {
var newSrc = $(this).attr("src").replace('700','860');
$(this).attr("src", newSrc);
});
//This will get the new size of the iframe and resize the iframe holder accordingly.
$(function(){
var iFrames = $('.photoset');
function iResize() {
for (var i = 0, j = iFrames.length; i < j; i++) {
iFrames[i].style.height = iFrames[i].contentWindow.document.body.offsetHeight + 'px';}
}
if ($.browser.safari || $.browser.opera) {
iFrames.load(function(){
setTimeout(iResize, 0);
});
for (var i = 0, j = iFrames.length; i < j; i++) {
var iSource = iFrames[i].src;
iFrames[i].src = '';
iFrames[i].src = iSource;
}
} else {
iFrames.load(function() {
this.style.height = this.contentWindow.document.body.offsetHeight + 'px';
});
}
});
</script>
OK so I have a iframe canvas app with its height set to "Settable" with the facebook javascrip sdk calls to FB.Canvas.setSize(); and FB.Canvas.setAutoGrow();. These are working perfectly, as the iframe gets set to a certain pixel height based on its content.
The problem is that when I make a call to Fancybox, it positions itself based on this height. I know that's exactly what its supposed to do as the fancybox jQuery returns the viewport by:
(line 673 of latest version of jquery.fancybox-1.3.4.js):
_get_viewport = function() {
return [
$(window).width() - (currentOpts.margin * 2),
$(window).height() - (currentOpts.margin * 2),
$(document).scrollTop() + currentOpts.margin
];
},
But the problem is the iframe will, for a lot of viewers, be longer than their browser window. So the Fancybox centers itself in the iframe and ends up only partly visible to the majority of viewers. (i.e. iframe height is 1058px and users browser is say only 650px).
Is there a way to have fancybox just calculate the physical browser height? Or do I need to change some settings in my Facebook canvas app to make it work?
I like how the only scrollbar is the one on Facebook (the parent, if you will).
All suggestions GREATLY appreciated!
For fancybox 2 try:
find:
_start: function(index) {
and replace with:
_start: function(index) {
if ((window.parent != window) && FB && FB.Canvas) {
FB.Canvas.getPageInfo(
function(info) {
window.canvasInfo = info;
F._start_orig(index);
}
);
} else {
F._start_orig(index);
}
},
_start_orig: function (index) {
Then in function getViewport replace return rez; with:
if (window.canvasInfo) {
rez.h = window.canvasInfo.clientHeight;
rez.x = window.canvasInfo.scrollLeft;
rez.y = window.canvasInfo.scrollTop - window.canvasInfo.offsetTop;
}
return rez;
and finally in _getPosition function replace line:
} else if (!current.locked) {
with:
} else if (!current.locked || window.canvasInfo) {
As facebook js api provides page info, then we could use it, so
find
_start = function() {
replace with
_start = function() {
if ((window.parent != window) && FB && FB.Canvas) {
FB.Canvas.getPageInfo(
function(info) {
window.canvasInfo = info;
_start_orig();
}
);
} else {
_start_orig();
}
},
_start_orig = function() {
and also modify _get_viewport function
_get_viewport = function() {
if (window.canvasInfo) {
console.log(window.canvasInfo);
return [
$(window).width() - (currentOpts.margin * 2),
window.canvasInfo.clientHeight - (currentOpts.margin * 2),
$(document).scrollLeft() + currentOpts.margin,
window.canvasInfo.scrollTop - window.canvasInfo.offsetTop + currentOpts.margin
];
} else {
return [
$(window).width() - (currentOpts.margin * 2),
$(window).height() - (currentOpts.margin * 2),
$(document).scrollLeft() + currentOpts.margin,
$(document).scrollTop() + currentOpts.margin
];
}
},
I had the same problem, i used 'centerOnScroll' :true, and now it works fine...
Had the same problem. Thankfully fancybox is accessable through CSS. My solution was to overwrite fancybox's positioning in my CSS file:
#fancybox-wrap {
top: 20px !important;
}
This code places the fancybox always 20px from top of the iframe. Use a different size if you like. The !important sets this positioning even though fancybox sets the position dynamically at runtime.
Here's one way to do it by positioning the Fancybox relative to the position of another element, in my case an Uploadify queue complete div that displays a view link after the user uploads an image.
Have a style block with a set ID like so:
<style id="style-block">
body { background-color: #e7ebf2; overflow: hidden; }
</style>
Then the link to open the Fancybox calls a function with the image name, width, and height to set the content and sizes. The important part is the positioning. By getting the position of the queue complete div, generating a new class declaration (fancy-position), appending it to the style block BEFORE the fancybox loads (!important in class will override positioning from fancybox), then adding the new class using the wrapCSS parameter in the fancybox options, it positions the fancybox exactly where I want it.
function viewImage(image, width, height) {
var complete_pos = $('#image_queue_complete').position();
var css_code = '.fancy-position { top: ' + complete_pos.top.toString() + 'px !important; }';
$('#style-block').append(css_code);
var img_src = '<img src="images/' + image + '" width="' + width.toString() + '" height="' + height.toString() + '" />';
$.fancybox({
content: img_src,
type: 'inline',
autoCenter: false,
wrapCSS: 'fancy-position'
});
}
I'm using tiny mce, but I found it adds multiple spans with inline styles to the content for any applied style. Inline styles are not W3c Compliant, so must avoid inline css. Is it possible to create css class on the fly and apply to the selection, while editing content in tiny mce ?
Yes that is possible, but it took me some effort. What needs to be done is to write the class into the head of the editors iframe. Here is some example code which should work for IE,FF, Safari and point you into the right direction:
fonturl = "http://myfonts.com/arial.ttf"
csstext_to_add = '#font-face {font-family: "ownfont";src: url("'+fonturl+'");}'; // example
iframe_id = ed.id;
with(document.getElementById(iframe_id).contentWindow){
var h=document.getElementsByTagName("head");
if (!h.length) {
return;
}
var newStyleSheet=document.createElement("style");
newStyleSheet.type="text/css";
h[0].appendChild(newStyleSheet);
try{
if (typeof newStyleSheet.styleSheet !== "undefined") {
newStyleSheet.styleSheet.cssText = csstext_to_add;
}
else {
newStyleSheet.appendChild(document.createTextNode(csstext_to_add));
newStyleSheet.innerHTML=csstext_to_add;
}
}
catch(e){}
}
It is also possible to add that class as option into a dropdown (what takes some effort).
Thariama's answer was perfect. I'm using the tinyMCE jQuery connector for some of my pages and I have multiple instances of tinyMCE on the page. I made some modifications, but essentially its the same thing. I've created a text area field on the page that people can provide their own CSS. Also, I needed to change some CSS rules on the fly...
// function to change tinyMCE css on the fly
function checkCustomCSS() {
var $css = $('#page_css'),
newcss;
if ($css.val().length > 0) {
// since front end, we are wrapping their HTML in a wrapper and
// the tinyMCE edit iFrame is just using <body>, we need to change
// some rules so they can see the changes
newcss = $css.val().replace('#content_wrapper', 'body');
// loop through each tinyMCE editor and apply the code changes
// You could check the editor.id to make sure that the correct
// editor gets the appropriate changes.
$.each(tinyMCE.editors, function() {
var $this = $(this),
editorID = $this[0].id,
$ifrm = $('#' + editorID+ '_ifr'),
cwin, head, sheet;
if ($ifrm.length > 0 /* && editorID === 'OUR_EDITOR_ID_NAME' */) {
cwin = $ifrm[0].contentWindow;
head = cwin.document.getElementsByTagName("head");
if (!head.length) {
return;
}
sheet = cwin.document.createElement("style");
sheet.type = "text/css";
head[0].appendChild(sheet);
try {
if (typeof sheet.styleSheet !== "undefined") {
sheet.styleSheet.cssText = newcss;
} else {
sheet.appendChild(cwin.document.createTextNode(newcss));
sheet.innerHTML = newcss;
}
} catch (e) {}
}
});
}
}
Then in the tinyMCE init call I added and onInit call to setup changes to the #page_css , like this:
oninit: function() {
$('#page_css').on('change', function() {
checkCustomCSS();
});
}
Works like a charm.