Wondering what the SCSS equivalent of LESS's escape is? - sass

I'm converting a stylesheet from LESS to SCSS and for the most part it's gone smoothly but there's one issue: I can't seem to get one of my mixins to work.
Basically I haven't entirely jumped on the html5 bandwagon and I still use images for gradients for browser compatibility.
I wrote a PHP script to generate the gradients on the fly (yes, and cache them!) and then LESS takes care of linking to that when the mixin is called.
Anyway,
My old mixin (from LESS):
.verticalGradient(#startColor, #endColor, #height){
#tmpStartColor: escape("#{startColor}");
#tmpEndColor: escape("#{endColor}");
background: #endColor url('#{img_path}gradient/v/5px/#{height}/#{tmpStartColor}/#{tmpEndColor}.png') 0 0 repeat-x;
}
This is what I have so far for my new mixin (SCSS):
#mixin verticalGradient($startColor, $endColor, $height){
background: $endColor url('#{$img_path}gradient/v/5px/' + $height + '/' + $startColor + '/' + $endColor + '.png') 0 0 repeat-x;
}
So here's the issue:
Without being escaped, the url ends up being something like:
/img/gradient/v/5px/25px/transparent/#ffe4c4.png
It should be:
/img/gradient/v/5px/25px/transparent/%23ffe4c4.png
Of course, because of the hash tag, the server can only see up to transparent/ so it doesn't get the color information.
Stripping hash tags IS an acceptable solution if it can be done (although I'd prefer to just escape them as I was doing before), but I can't seem to find any way to do it.
Thanks!

I figured this out.
This got me pointed in the right direction:
How do I load extensions to the Sass::Script::Functions module?
And this got me the rest of the way there:
http://sass-lang.com/documentation/Sass/Script/Functions.html#adding_custom_functions
And here's my code if this is useful to anyone else :)
config.rb (require lib):
require File.dirname(__FILE__) + "/lib/urlencode.rb"
lib/urlencode.rb:
module Sass::Script::Functions
def urlencode(string)
Sass::Script::String.new(ERB::Util.url_encode(string));
end
declare :urlencode, :args => [:string]
end
Then it was just a matter of implementing in my stylesheet:
#mixin verticalGradient($startColor, $endColor, $height){
background: $endColor url('#{$img_path}gradient/v/5px/' + $height + '/' + urlencode($startColor) + '/' + urlencode($endColor) + '.png') 0 0 repeat-x;
}

Related

How do I use multiple fonts ie a composite font in HexaPDF

Our users are giving us Emoji and a lot of other weird characters and the built-in Helvetica can't handle it. Neither can Google's Noto fonts by themselves - I need to figure out how to declare the Noto Font Family in HexaPDF and I can't figure out how to do that with the given documentation. OpenSans was an improvement, but I still want more glyph coverage than that.
Update:
I used this method to set the font:
def self.pdf_summary_font
##pdf_summary_font ||= File.open(Rails.root.join('public',
'OpenSansEmoji.ttf'), 'r')
end
canvas = page.canvas(type: :overlay)
canvas.font(self.class.pdf_summary_font, size: 10)
However, no Noto font ever worked with this - I would get errors like "Missing glyph - 'A'"
The best I could do was to use OpenSansEmoji, and replace missing glyphs with the following block:
begin
style = HexaPDF::Layout::Style.new(font: canvas.font, fill_color: color, stroke_color: color, align: :left, valign: :center)
fragment = HexaPDF::Layout::TextFragment.create(str, style)
layouter = HexaPDF::Layout::TextLayouter.new(style)
layouter.fit([fragment], w, h).draw(canvas, x1, y2)
rescue HexaPDF::Error => e
if e.message.include?('Glyph for')
glyph = e.message.match(/\{(.*?)\}/).captures.first
str = str.grapheme_clusters.map do |char|
if char.dump.include?(glyph)
"\u{FFFD}"
else
char
end
end.join
retry
end
Have a look at https://hexapdf.gettalong.org/documentation/reference/api/HexaPDF/index.html and the configuration option "font_map". This allows you to declare any TrueType file and use it.
You could also use the path to the font file directly with the Canvas#font method.
If you need to cover a wide array of characters you need to use a single font that covers all of them, one of the fonts included in this ZIP file should probably work (Google says 582 languages, 237 regions included).

Browser Print dialog not showing

I have print.min.js referenced in my angularjs project. I have it printing successfully (very simple!) for most of my needs. I have run into a case where the browser print dialog does not appear when a user presses my 'Print' button. The issue seems to be related to file size. I don't know the size threshold yet, but it seems after a few pages in length, the process hangs in print.min.js somewhere. Smaller files (2 - 3 pages or so) print without issue. Any thoughts?
Thanks!
Joe
By default, Print.js will process the computed styles for each html element. When printing large and / or complex html, this process may take a while. Specially on slower machines.
To prevent this, the library has a parameter scanStyles that can be set to false.
However, for this to work properly, you may want to style your html with css classes instead of inline style. Since the library isn't scanning the computed styles, it needs to receive the css you want to use when printing.
For example, when printing an element of id myElement on a page with two attached stylesheets, myStylesheet.css and vendor.css:
printJS(
{
printable: 'myElement',
type: 'html',
scanStyles: false,
css: ['myStyleSheet', 'vendor.css']
}
)
This supports css print media query as well.
You can also pass custom inline style if necessary:
printJS(
{
printable: 'myElement',
type: 'html',
scanStyles: false,
css: ['myStyleSheet', 'vendor.css'],
style: 'h1 { color: blue; }, someClass { font-size: 1rem; }'
}
)
http://printjs.crabbly.com/#configuration

How to allocate the label center of case using sphinx?

I'm writing equations using sphinx. My code looks like this:
.. math::
:label: eq1
\begin{eqnarray}
\begin{cases}
a_{11}x_{1} + \dots + a_{1m}x_{m} = b_1\\
a_{21}x_{1} + \dots + a_{2m}x_{m} = b_2
\end{cases}
\end{eqnarray}
This displays the label (1) on the right side of the first line, but I would to allocate it the center of this {cases}, namely, between the first and the second line.
How do I do this?
This question seems to pertain principally about MathJax usage.
By some experimenting I discovered it understands \smash and that using it provides the hoped for label placement. But perhaps there is some MathJax setting which would avoid using this \smash. Besides \smash works fine only for two or three "cases".
I have moved the \smash approach to second part, where also its drawbacks are explained. Indeed, I have since found a half-satisfying CSS approach.
At any rate, don't use eqnarray there.
CSS based approach
Create a file _static/custom.css in your source repertory with these contents.
.MathJax_Display {
transform: translate(0%,-50%) translate(0%,8px);
}
div.math {
transform: translate(0%,50%);
}
Add this at end of conf.py:
if html_theme != 'alabaster':
def setup(app):
app.add_stylesheet('custom.css')
For example I obtain this with 'classic' theme:
This works also with 'agogo' and 'alabaster' themes, but some fine tuning might be needed for equations with only one line to be positioned like the label.
In the case RTD theme it does not work at all.
Support may be browser dependent.
\smash approach
Text before.
.. math::
:label: eq1
\smash{\begin{cases}
a_{11}x_{1} + \dots + a_{1m}x_{m} &= b_1\\
a_{21}x_{1} + \dots + a_{2m}x_{m} &= b_2
\end{cases}}
Text after.
I get from make html (with classic theme)
conf.py contains
extensions = ['sphinx.ext.mathjax',
]
html_theme = 'classic'
By the way your eqnarray is not good mark-up. IF you use it you should use :nowrap: option. See Sphinx doc.
Note Of course usage of cases here is dubious because your example is one of equations. I added &'s but the spacing is one appropriate for cases, which is surely not the one expected. So remove them.
Here is mark-up which does not abuse cases environment:
Text before.
.. math::
:label: eq1
\smash{\left\{\begin{aligned}
a_{11}x_{1} + \dots + a_{1m}x_{m} &= b_1\\
a_{21}x_{1} + \dots + a_{2m}x_{m} &= b_2
\end{aligned}\right.}
Text after.
CAVEAT The smash trick only works with two (perhaps three) equations, even in MathJax.

SASS::Script::Color not being interpreted as a color by some SASS functions

I've recently decided I want to have some default actions that run when my SASS is compiled and found this stack overflow question which helped me write a function to do it (Use variable defined in config.rb in scss files)
The colour value gets pulled through fine and is treated like a SASS color object (i.e. if I pass '#ff0000' into the function it comes out as 'red' which is fine) but it doesn't work in the tint() and shade() functions.
The error I get is
(Line 137: "#ff1122" is not a color for 'shade')
But if I comment out all of the instances of tint() and shade() then it works perfectly.
Here's all the code that's being used:
config.rb (taken from the stack overflow link up there mentioned before)
sass_options = {:custom => { :custom_colors => {"main" => "#ff1122"} } }
module Sass::Script::Functions
def custom_color(value)
rgb = options[:custom][:custom_colors][value.to_s].scan(/^#?(..?)(..?)(..?)$/).first.map {|a| a.ljust(2, a).to_i(16)}
Sass::Script::Color.new(rgb)
end
end
style.scss (line 5)
$col_primary : #{custom_color(main)};
style.scss (line 137 that was mentioned in the error)
#include background-with-css2-fallback(linear-gradient(-45deg, transparent 51%, shade($col_primary, 10) 50%, $col_primary 75%, $col_primary 0%));
I can't see a reason that this wouldn't work as it works as a colour elsewhere.
I can give more info if needed
My problem ended up being this
$col_primary : #{custom_color(main)};
Which I took from the example - I think SASS interprets that as a string and so it doesn't matter that the function is returning the correct type.

Issue with algorithm to shorten sentences

I have a webpage which displays multiple textual entries which have no restriction on their length. They get automatically cut if they are too long to avoid going to a new line. This is the PHP function to cut them:
function cutSentence($sentence, $maxlen = 16) {
$result = trim(substr($sentence, 0, $maxlen));
$resultarr = array(
'result' => $result,
'islong' => (strlen($sentence) > $maxlen) ? true : false
);
return $resultarr;
}
As you can see in the image below, the result is fine, but there are a few exceptions. A string containing multiple Ms (I have to account for those) will go to a newline.
Right now all strings get cut after just 16 characters, which is already very low and makes them hard to read.
I'd like to know if a way exists to make sure sentences which deserve more spaces get it and those which contain wide characters end up being cut at a lower number of characters (please do not suggest using the CSS property text-overflow: ellipsis because it's not widely supported and it won't allow me to make the "..." click-able to link to the complete entry, and I need this at all costs).
Thanks in advance.
You could use a fixed width font so all characters are equal in width. Or optionally get how many pixels wide every character is and add them together and remove the additional character wont the pixel length is over a certain amount.
If the style of your application isn't too important, you could simply use a font in the monospace family such as Courier.
Do it in Javascript rather than in PHP. Use the DOM property offsetWidth to get the width of the containing element. If it exceeds some maximum width, then truncate accordingly.
Code copied from How can I mimic text-overflow: ellipsis in Firefox? :
function addOverflowEllipsis( containerElement, maxWidth )
{
var contents = containerElement.innerHTML;
var pixelWidth = containerElement.offsetWidth;
if(pixelWidth > maxWidth)
{
contents = contents + "…"; // ellipsis character, not "..." but "…"
}
while(pixelWidth > maxWidth)
{
contents = contents.substring(0,(contents.length - 2)) + "…";
containerElement.innerHTML = contents;
pixelWidth = containerElement.offsetWidth;
}
}
Since you are asking for a web page then you can use CSS text-overflow to do that.
It seems to be supported enough, and for firefox there seems to be css workarounds or jquery workarounds...
Something like this:
span.ellipsis {
white-space:nowrap;
text-overflow:ellipsis;
overflow:hidden;
width:100%;
display:block;
}
If you fill more text than it fits it will add the three dots at the end.
Just cut the text if it is really too long so you don't waste html space.
More info here:
https://developer.mozilla.org/En/CSS/Text-overflow
Adding a 'see more' link at the end is easy enough, as appending another span with fixed width, containing the link to see more. text will be truncated with ellipsis before that.

Resources