cssfonts.lzx
<library>
<script when="immediate">
/** @access private **/
class cssFontSupport {
static const SPACE = new RegExp('\\s+');
static const SLASH = new RegExp('\\s*\\/\\s*');
static const COMMA = new RegExp('\\s*,\\s*');
static const STYLE_PATTERN = new RegExp('(italic|oblique)');
static const VARIANT_PATTERN = new RegExp('small-caps');
static const WEIGHT_PATTERN = new RegExp('(bold|bolder|lighter|[1-9]00)');
// Only thing we still cascade
static const CASCADE_ATTRS = {hasdirectionallayout: true};
static function parseFontSpecification(font, node:LzNode, attribute:String) {
// Crush out any space around commas
var canonical = font.replace(cssFontSupport.COMMA, ',');
// Crush out any space around slashes
canonical = canonical.replace(cssFontSupport.SLASH, '/');
// Get the parts
var parts = canonical.split(cssFontSupport.SPACE);
// family and size are required and are the last two components
var family = parts.pop();
var size = parts.pop();
var lineheight = 'normal';
var sizeparts = size.split(cssFontSupport.SLASH);
if (sizeparts.length > 1) {
size = sizeparts[0];
lineheight = sizeparts[1];
}
// style, variant and weight can come in any order, and are all optional
var style = 'normal', variant = 'normal', weight = 'normal';
while (parts.length > 0) {
var part = parts[0];
if (part.match(cssFontSupport.WEIGHT_PATTERN)) {
weight = parts.shift();
} else if (part.match(cssFontSupport.STYLE_PATTERN)) {
style = parts.shift();
} else if (part.match(cssFontSupport.VARIANT_PATTERN)) {
variant = parts.shift();
} else if (part === 'normal') {
// Default, ignore
parts.shift();
} else {
// Unparsable
break;
}
}
if (family && size && (parts.length == 0)) {
// Carefully contrived to be the CSS for the expander
return {
'font-family': family,
'font-size': size,
'line-height': lineheight,
'font-weight': weight,
'font-style': style,
'font-variant': variant
};
} else if ($debug) {
Debug.error("Invalid font: %w", font);
}
};
static function unparseFontSpecification (value, node:LzNode, attribute:String) {
var str = '';
if (value['font-style'] != 'normal') {
if (str) { str += ' '; }
str += value['font-style'];
}
if (value['font-variant'] != 'normal') {
if (str) { str += ' '; }
str += value['font-variant'];
}
if (value['font-weight'] != 'normal') {
if (str) { str += ' '; }
str += value['font-weight'];
}
if (str) { str += ' '; }
str += value['font-size'];
if (value['line-height'] != 'normal') {
str += '/' + value['line-height'];
}
str += ' ' + value['font-family'];
return str;
}
};
</script>
<type name="cssfontspecification">
<accept args="value, node:LzNode, attribute:String">
return cssFontSupport.parseFontSpecification(value, node, attribute);
</accept>
<present args="value, node:LzNode, attribute:String">
return cssFontSupport.unparseFontSpecification(value, node, attribute);
</present>
</type>
<mixin name="cssfonts">
<doc>
<tag name="shortdesc"><text>A mixin to control font attributes with CSS style properties.</text></tag>
<text>
<p>The <tagname>cssfonts</tagname> mixin adds CSS font styling to <sgmltag class="element" role="LzView"><text></sgmltag></p>
<p><tagname>cssfonts</tagname> implements a subset of the CSS fonts specification
<a href="http://www.w3.org/TR/css3-fonts/">http://www.w3.org/TR/css3-fonts/</a>
</p>
<example title="Using CSS styleable fonts" query-parameters="lzr=swf10"><programlisting>
<canvas height="60">
<stylesheet>
view.styled {
font: bold italic 24 helvetica, sans-serif;
}
</stylesheet>
<include href="mixins/cssfonts.lzx"/>
<view styleclass="styled" layout="axis: y; spacing: 5">
<text>This is a demonstration of NOT styling fonts with CSS</text>
<text with="cssfonts">This is a demonstration of styling fonts with CSS</text>
</view>
</canvas>
</programlisting></example>
</text>
</doc>
<method name="construct" args="p, a">
super.construct(p,a);
// initialize default values
// @devnote [2010-12-30 ptw] Because the style bindings and
// initializations can happen in any order, we set the default
// values here, then set the fallback values for each styled
// attribute to `null`, which tells us the attribute was not
// styled so we should do nothing. If the attribute _is_
// styled, the setter will be called and the value will
// propagate to both the array (abbreviated value) and the
// individual value
this.css_font = {
'font-family': "Verdana,Vera,sans-serif",
'font-size': 11,
'line-height': 'normal',
'font-weight': 'normal',
'font-style': 'normal',
'font-variant': 'normal'
};
this.css_font_family = "Verdana,Vera,sans-serif";
this.css_font_size = 11;
this.css_line_height = 'normal'
this.css_font_style = 'normal';
this.css_font_weight = 'normal';
this.css_font_variant = 'normal';
</method>
<attribute name="bgcolor" style="background-color" type="color" value="white
"/>
<attribute name="fgcolor" style="color" type="color" value="black
"/>
<attribute name="direction" style="direction" type="string" value="ltr
"/>
<method name="_expandCSSFontSpecificationProperty" args="attr, value:String">
var expanded = lz.Type.acceptTypeValue('cssfontspecification', value, this, attr);
return expanded;
</method>
<attribute name="css_font" style="font" type="cssfontspecification" value="
" expander="_expandCSSFontSpecificationProperty"/>
<event name="oncss_font"/>
<setter name="css_font" args="font">
var changed = false;
for (var prop in font) {
if (font.hasOwnProperty(prop)) {
var attr = 'css_' + prop.replace('-', '_');
if (this[attr] != font[prop]) {
changed = true;
this.setAttribute(attr, font[prop]);
}
}
}
if (changed) {
this.css_font = font;
if (this.oncss_font.ready) {
this.oncss_font.sendEvent(font);
}
}
</setter>
<attribute name="css_font_family" style="font-family" type="string" value="${null}"/>
<event name="oncss_font_family"/>
<setter name="css_font_family" args="value">
if (value == null) { return; }
if (value != this.css_font_family) {
this.css_font['font-family'] = this.css_font_family = value;
// TODO: Translate to LZX attribute
this.setAttribute('font', value);
if (this.oncss_font_family.ready) {
this.oncss_font_family.sendEvent(value);
}
}
</setter>
<attribute name="css_font_size" style="font-size" type="number" value="${null}"/>
<event name="oncss_font_size"/>
<setter name="css_font_size" args="value">
if (value == null) { return; }
if (value != this.css_font_size) {
this.css_font['font-size'] = this.css_font_size = value;
// TODO: Translate to LZX attribute
this.setAttribute('fontsize', value);
if (this.oncss_font_size.ready) {
this.oncss_font_size.sendEvent(value);
}
}
</setter>
<attribute name="css_font_style" style="font-style" type="string" value="${null}"/>
<event name="oncss_font_style"/>
<setter name="css_font_style" args="value">
if (value == null) { return; }
if (value != this.css_font_style) {
this.css_font['font-style'] = this.css_font_style = value;
// TODO: Translate to LZX attribute
var lzxval = '';
if (this.css_font_weight == 'bold') { lzxval = 'bold'; }
if (this.css_font_style == 'italic' || this.css_font_style == 'olique') { lzxval += 'italic'; }
if (lzxval == '') { lzxval = 'plain'; }
this.setAttribute('fontstyle', lzxval);
if (this.oncss_font_style.ready) {
this.oncss_font_style.sendEvent(value);
}
}
</setter>
<attribute name="css_font_weight" style="font-weight" type="string" value="${null}"/>
<event name="oncss_font_weight"/>
<setter name="css_font_weight" args="value">
if (value == null) { return; }
if (value != this.css_font_weight) {
this.css_font['font-weight'] = this.css_font_weight = value;
// TODO: Translate to LZX attribute
var lzxval = '';
if (this.css_font_weight == 'bold') { lzxval = 'bold'; }
if (this.css_font_style == 'italic' || this.css_font_style == 'olique') { lzxval += 'italic'; }
if (lzxval == '') { lzxval = 'plain'; }
this.setAttribute('fontstyle', lzxval);
if (this.oncss_font_weight.ready) {
this.oncss_font_weight.sendEvent(value);
}
}
</setter>
<attribute name="css_font_variant" style="font-variant" type="string" value="${null}"/>
<event name="oncss_font_variant"/>
<setter name="css_font_variant" args="value">
if (value == null) { return; }
if (value != this.css_font_variant) {
this.css_font['font-variant'] = this.css_font_variant = value;
// TODO: Translate to LZX attribute
if (this.oncss_font_variant.ready) {
this.oncss_font_variant.sendEvent(value);
}
}
</setter>
<attribute name="css_line_height" style="line-height" type="string" value="${null}"/>
<event name="oncss_line_height"/>
<setter name="css_line_height" args="value">
if (value == null) { return; }
if (value != this.css_font_variant) {
this.css_font['font-variant'] = this.css_font_variant = value;
// TODO: Translate to LZX attribute
if (this.oncss_font_variant.ready) {
this.oncss_font_variant.sendEvent(value);
}
}
</setter>
</mixin>
</library>
Cross References
Named Instances