Calculate text width in pixels server-side - node.js

I'm trying to use the following code on my server to estimate the length of some text fields and potentially trim them before sending them by email...
String.prototype.visualLength = function()
{
var element = document.createElement("span");
element.css({
"visibility": "hidden",
"white-space": "nowrap",
"font-weight": "normal",
"font-size": "18px",
"line-height": "40px",
"font-family": "Helvetica, Arial, sans-serif",
"text-decoration": "none"
});
document.body.appendChild(element);
element.innerHTML = this;
return element.offsetWidth;
};
String.prototype.trimToPx = function(length)
{
var tmp = this;
var trimmed = this;
if (tmp.visualLength() > length)
{
trimmed += "...";
while (trimmed.visualLength() > length)
{
tmp = tmp.substring(0, tmp.length-1);
trimmed = tmp + "...";
}
};
return trimmed;
};
Obviously I'm getting an error because "document" is not defined server-side. I added the Meteor packages htmljs and domutils hoping they might solve this, but in vain. And I can't add the Node.js package jsdom because apparently it won't work in deployed Meteor apps.
Any idea how to achieve what I'm trying to do?

You cannot truly rely what will happen on client-side. Even Ubuntu and Windows shows the fonts different because of different hinting, antialiasing and they may have an effect on the displayed sizes.
If you modify your span's css as following, when it has a text larger than the desired space, no matter what, the remaining will be displayed as ...
max-width: 10%;
border: 1px #000 solid; // JUST TO SEE the effect clearly
width: 10%;
overflow: hidden;
height: 20px;
text-overflow: ellipsis;
display: block;
white-space: nowrap;
** Please note that you need a proper height value, other wise the text will go to bottom and what you want will not be achieved.
Try on http://jsfiddle.net/sG6H2/

I don't think this is possible. Server-side code running in node.js does not run in the context of a web browser's rendering environment and so can't access the browser's DOM and available fonts and display configuration. Even if you were to successfully run your code and compute a number, that computation has no relationship to my device when I receive your email. The fonts, the display size and resolution (could be a desktop, could be a mobile device), my own configuration (for example I set a minimum font size in Firefox on my desktop), etc. Instead try defining your size in em units instead of pixels.

Related

Azure Maps - Map is not opening at the correct size

I have a page with azure maps, and most of the time it loads normally and the map covers the entire screen. But at some points when refreshing the page, the map is limited to a small size, and if I just refresh the screen or even open the browser console, the size is updated correctly.
<body>
<div id="mapDiv"></div>
</body>
I even created an event in an attempt to make a resize
map.events.add('ready', function () {
setTimeout(function () {
map.map.resize();
}, 1000);
});
Error
enter image description here
when i refresh or open da console
enter image description here
If it is meant to be full screen, make sure to set the width/height to 100% for not only the map, but the html and body tags as well. When you don't specify any styles for the map div, it inherits from it's parents. Try adding this CSS to your page:
html, body, #mapDiv {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}

Chrome Extension causing misbehavior with divs on active websites [duplicate]

I wrote a Google Chrome extension, which popups a dialog with an autocomplete field and it's own style, but there are some sites where my CSS gets totally broken, which doesn't look very nice.
I know about isolating styles with iFrames, but in Google Chrome extension there is no way to isolate my HTML and CSS in this way. Another method is to wrap all my stuff into a separated div with it's own id and relative styles for that id, and I do so, but it seems that it doesn't work on some sites with "hard" tags style overloading or "!important" directives in the CSS code.
So, I want to know is there any way to really isolate my styles in z convenient way or it's my bad carma to overload every little CSS property to fix one or another style issue for each site?
By the way: I set up my manifest to load all the things at the "document_end", but I see it's not being applied to the stylesheets which is every time loaded whenever the DOM is ready.
At the time of asking the question, your only option was to either use iframes, or stylesheets with a very high specificity and explicitly set all properties that might affect styles. The last method is very cumbersome, because there will always be some property that is overlooked by you. Consequently, the only usable method for isolating stylesheets was to use iframes.
The solution to this problem -isolation of styles without iframes- is Shadow DOM (since Chrome 25). You can find a tutorial at HTML5 Rocks. For a real-world Chrome extension that uses Shadow DOM to isolate styles, see Display #Anchors (source code here).
As I've recently gone through the gauntlet of this issue, I want to share some information I think is valuable.
First, Rob W's answer is correct. Shadow DOM is the correct solution to this problem. However, in my case not only did I need CSS isolation, I also needed JavaScript events. For example, what happens if the user clicks a button that lives within the isolated HTML? This gets really ugly with just Shadow DOM, but we have another Web Components technology, Custom Elements, to the rescue. Except that as of this writing there is a bug in chrome that prevents custom element in chrome extensions. See my questions here and here and the bug here.
So where does that leave us? I believe the best solution today is IFrames, which is what I went with. The article shahalpk linked is great but it only describes part of the process. Here's how I did it:
First, create an html file and js file for your isolated widget. Everything inside these files will run in an isolated environment in an iframe. Be sure to source your js file from the html file.
//iframe.js
var button = document.querySelector('.my-button');
button.addEventListener('click', function() {
// do useful things
});
//iframe.html
<style>
/* css */
</style>
<button class='my-button'>Hi there</button>
<script src='iframe.js'></script>
Next, inside your content script create an iframe element in javascript. You need to do it in javascript because you have to use chrome.extension.getURL in order to grab your iframe html file:
var iframe = document.createElement('iframe');
iframe.src = chrome.extension.getURL("iframe.html");
document.body.appendChild(iframe);
And that's it.
One thing to keep in mind: If you need to communicated between the iframe and the rest of the content script, you need to chrome.runtime.sendMessage() to the background page, and then chrome.tabs.sendMessage from the background page back to the tab. They can't communicate directly.
EDIT: I wrote a blog post detailing everything I learned through my process, including a complete example chrome extension and lots of links to different information:
https://apitman.com/3/#chrome-extension-content-script-stylesheet-isolation
In case my blog goes down, here's the sources to the original post:
Blog post
Example source
Either use all
.some-selector {
all: initial;
}
.some-selector * {
all: unset;
}
or use Shadow DOM
Library
function Widget(nodeName, appendTo){
this.outer = document.createElement(nodeName || 'DIV');
this.outer.className = 'extension-widget-' + chrome.runtime.id;
this.inner = this.outer.createShadowRoot();
(appendTo || document.body).appendChild(this.outer);
}
Widget.prototype.show = function(){
this.outer.style.display = 'block';
return this;
};
Widget.prototype.hide = function(){
this.outer.style.display = 'none';
return this;
};
Usage
var myWidget = new Widget();
myWidget.inner.innerHTML = '<h1>myWidget</h1>';
You can access the widget contents via myWidget.inner and the outer via myWidget.outer.
Styles
/*
* Reset Widget Wrapper Element
*/
.extension-widget-__MSG_##extension_id__ {
background: none;
border: none;
bottom: auto;
box-shadow: none;
color: black;
cursor: auto;
display: inline;
float: none;
font-family : "Helvetica Neue", "Helvetica", "Arial", sans-serif;
font-size: inherit;
font-style: normal;
font-variant: normal;
font-weight: normal;
height: auto;
left: auto;
letter-spacing: 0;
line-height: 100%;
margin: 0;
max-height: none;
max-width: none;
min-height: 0;
min-width: 0;
opacity: 1;
padding: 0;
position: static;
right: auto;
text-align: left;
text-decoration: none;
text-indent: 0;
text-shadow: none;
text-transform: none;
top: auto;
vertical-align: baseline;
white-space: normal;
width: auto;
z-index: 2147483648;
}
/*
* Add your own styles here
* but always prefix them with:
*
* .extension-widget-__MSG_##extension_id__
*
*/
.extension-widget-__MSG_##extension_id__{
position: fixed;
top: 100px;
margin: 0 auto;
left: 0;
right: 0;
width: 500px;
}
.extension-widget-__MSG_##extension_id__::shadow h1 {
display: block;
margin: 0 auto;
padding: 20px;
background-color: yellow;
border: 10px solid green;
font-size: 20px;
text-align: center;
}
I recently created Boundary, a CSS+JS library to solve problems just like this. Boundary creates elements that are completely separate from the existing webpage's CSS.
Take creating a dialog for example. After installing Boundary, you can do this in your content script
var dialog = Boundary.createBox("yourDialogID", "yourDialogClassName");
Boundary.loadBoxCSS("#yourDialogID", "style-for-elems-in-dialog.css");
Boundary.appendToBox(
"#yourDialogID",
"<button id='submit_button'>submit</button>"
);
Boundary.find("#submit_button").click(function() {
// some js after button is clicked.
});
Elements within #yourDialogID will not be affected by the existing webpage. And find() function returns a regular jQuery DOM element so you can do whatever you want with it.
Hope this helps. Please let me know if you have any question.
https://github.com/liviavinci/Boundary
Use iframes. It's a workaround, but works fine.
Maxime has written an article on it.

Display: Inline block - What is that space? [duplicate]

This question already has answers here:
How to remove the space between inline/inline-block elements?
(41 answers)
Closed 8 years ago.
Inline blocks have this weird space in-between them. I could live with it, up to a point where, if I load more content with an AJAX call, the tiny space goes away. I know I'm missing something here.
div {
width: 100px;
height: auto;
border: 1px solid red;
outline: 1px solid blue;
margin: 0;
padding: 0;
display: inline-block;
}
http://jsfiddle.net/AWMMT/
How to make the spacing consistent in Inline blocks?
The space is in the HTML. There are several possible solutions. From best to worst:
Remove the actual space in the HTML (ideally your server could do this for you when the file is served, or at least your input template could be spaced appropriately) http://jsfiddle.net/AWMMT/2/
Use float: left instead of display: inline-block, but this has undesirable effects on t he height: http://jsfiddle.net/AWMMT/3/
Set the container's font-size to 0 and set an appropriate font-size for the internal elements: http://jsfiddle.net/AWMMT/4/ -- this is pretty simple, but then you can't take advantage of relative font size rules on the internal elements (percentages, em)
http://jsfiddle.net/AWMMT/1/
<div>...</div><div>...</div>
^
|--- no whitespace/new line here.
Your spaces were the new lines the browser converted to "spaces" when displaying it.
Or you could try to hack a bit with CSS:
A flexbox conveniently ignores whitespace between its child elements and will display similarly to consecutive inline-block elements.
http://jsfiddle.net/AWMMT/470/
body { display: flex; flex-wrap: wrap; align-items: end; }
Old answer (still applies to older, pre-flexbox browsers)
http://jsfiddle.net/AWMMT/6/
body { white-space: -0.125em; }
body > * { white-space: 0; /* reset to default */ }
There’s actually a really simple way to remove whitespace from inline-block that’s both easy and semantic. It’s called a custom font with zero-width spaces, which allows you to collapse the whitespace (added by the browser for inline elements when they're on separate lines) at the font level using a very tiny font. Once you declare the font, you just change the font-family on the container and back again on the children, and voila. Like this:
#font-face{
font-family: 'NoSpace';
src: url('../Fonts/zerowidthspaces.eot');
src: url('../Fonts/zerowidthspaces.eot?#iefix') format('embedded-opentype'),
url('../Fonts/zerowidthspaces.woff') format('woff'),
url('../Fonts/zerowidthspaces.ttf') format('truetype'),
url('../Fonts/zerowidthspaces.svg#NoSpace') format('svg');
}
body {
font-face: 'OpenSans', sans-serif;
}
.inline-container {
font-face: 'NoSpace';
}
.inline-container > * {
display: inline-block;
font-face: 'OpenSans', sans-serif;
}
Suit to taste. Here’s a download to the font I just cooked up in font-forge and converted with FontSquirrel webfont generator. Took me all of 5 minutes. The css #font-face declaration is included: zipped zero-width space font. It's in Google Drive so you'll need to click File > Download to save it to your computer. You'll probably need to change the font paths as well if you copy the declaration to your main css file.
You can comment the whitespace out.
Original answer from 2013
Like:
<span>Text</span><!--
--><span>Text 2</span>
Edit 2016:
I also like the following method, where you just put the closing bracket right before the following element.
<span>Text</span
><span>Text 2</span>
Also you can do it like this (which IMHO,I believe is sintatically correct)
<div class="div1">...</div>
<div class="div1">...</div>
.
.
.div1{
display:inline-block;
}
.div1::before, div1::after { white-space-collapse:collapse; }

ckeditor 3 different body style for full page preview

Is it possible to change body style when entering a full page preview in ckeditor 3. Maybe to set a different body style for full page than when it is not in a full page mode.
The reason for this is using ckeditor when viewing a web page on a larger screen with maximized browser... in that case it is very wide and it is hard to read the content. So I would like to add in body style (but only for full page mode) something like:
...
margin: 5%;
padding: 5%;
border: 1px dotted #666;
...
... that will give more text processor look to the content.
TNX!
When CKEditor is toggled to fullscreen mode it adds "cke_maximized" class to container span.
So you may apply styles for entire container span (body+toolbar) like:
.cke_maximized{
margin: 5%;
padding: 5%;
border: 1px dotted #666;
}
or just for content body:
.cke_maximized iframe{
margin: 5%;
padding: 5%;
border: 1px dotted #666;
}
Those are just examples and you may experiment and choose css selector that is more suitable for you .
UPDATE 1:
Sure, you can use javascript code if it is not enough for your purposes. You can use something like this:
var editor = CKEDITOR.instances.editor1;
editor.on("afterCommandExec", function(e){
if(e.data.name == 'maximize'){
// maximized
if(e.data.command.state == CKEDITOR.TRISTATE_ON){
// add special css class to body(e.editor.document.getBody())
} else {
// minimized
// remove special css from body
}
}
});

Viewport meta tag for desktop browsers?

My client is asking me to reduce size of current website for desktop browsers by 30%.
is there a css or meta tag to do it like viewport meta tag on a mobile browser?
Hmmm... I know this is an old question, but there is a MUCH better way to go about this: use the CSS scale() transform function on the <html> tag to scale EVERYTHING inside. Check out this jsFiddle: http://jsfiddle.net/mike_marcacci/6fMnH/
The magic is all here:
html {
transform: scale(.5);
-webkit-transform: scale(.5);
-moz-transform: scale(.5);
-ms-transform: scale(.5);
-o-transform: scale(.5);
width: 200%;
height: 200%;
margin: -50% -50%;
}
You can look at the css screen media type.
It is:
Intended primarily for color computer screens.
You can use it this way:
#media screen {
body { font-size: 70% }
}
There is also a handheld media type, primarily:
Intended for handheld devices (typically small screen, limited bandwidth).
However, you will need to test the different devices and desktops your client is focusing on in order to determine how using these media types will effect the user experience.
Odes is right.
#media screen {
body { font-size: 70% }
}
But to make this really work well, you must use ems instead of px everywhere. That goes for margin and padding as well as width and height of all elements.
A good way to do this is to use SASS. Just create your own sass function to convert your px measurements into ems on the fly. Something like this will do:
#function em($px, $context: 16, $basesize: 16) {
#return (($px/$basesize)/($context/16))+em;
}
Which then gets used in your CSS like so:
div { font-size:em(12); width: em(200,12); }
So, if the body font size was set to 100%, then the font size would be equivalent to 12px and the width of the div would be 200px wide.
Here code for proportional scale and positioning, wnen using "transform: scale"
CSS
html,body
{
width: 100%;
height: 100%;
margin:0;
padding:0;
}
html
{
position:absolute;
}
JS
var scale = 1;
$('html').css('transform','scale('+scale+')');
var windowWidth = $(window).width();
$('body').append(windowWidth);
$('body').append(' ' + windowWidth*scale );
//$('html').width(windowWidth*scale);
var width = (100*(1/scale));
var left = -(width*(1-scale))/2;
var height = (100*(1/scale));
var top = -(height*(1-scale))/2;
$('html').css('top', top+'%');
$('html').css('left', left+'%');
$('html').width(width+'%');
$('html').height(height+'%');
You can enable the meta viewport tag on desktop with JS. First you should derive the setting (width) from the meta tag:
var viewportcontent = $( "#myviewport" ).attr('content');
var viewportcontents = viewportcontent.split(",");
//if it starts with 'width='
for (var i = 0; i < viewportcontents.length; i++) {
if(viewportcontents[i].lastIndexOf('width=', 0) === 0) {
var wspec = viewportcontents[i].substring(6);
}
}
Then you need a little JS and the solution of Mike to get this working solution: http://codepen.io/anon/pen/GqoeYJ. Note that this example forces the width to be 1200 pixels, but initial-scale: 0.7 could be implemented in the same way.

Resources