1 |
41cc1b08
|
Assos Assos
|
/*=:project
|
2 |
|
|
scalable Inman Flash Replacement (sIFR) version 3.
|
3 |
|
|
|
4 |
|
|
=:file
|
5 |
|
|
Copyright: 2006 Mark Wubben.
|
6 |
|
|
Author: Mark Wubben, <http://novemberborn.net/>
|
7 |
|
|
|
8 |
|
|
=:history
|
9 |
|
|
* IFR: Shaun Inman
|
10 |
|
|
* sIFR 1: Mike Davidson, Shaun Inman and Tomas Jogin
|
11 |
|
|
* sIFR 2: Mike Davidson, Shaun Inman, Tomas Jogin and Mark Wubben
|
12 |
|
|
|
13 |
|
|
=:license
|
14 |
|
|
This software is licensed and provided under the CC-GNU LGPL.
|
15 |
|
|
See <http://creativecommons.org/licenses/LGPL/2.1/>
|
16 |
|
|
*/
|
17 |
|
|
|
18 |
|
|
import SifrStyleSheet;
|
19 |
|
|
|
20 |
|
|
class sIFR {
|
21 |
|
|
public static var DEFAULT_TEXT = 'Rendered with sIFR 3, revision 245';
|
22 |
|
|
public static var CSS_ROOT_CLASS = 'sIFR-root';
|
23 |
|
|
public static var DEFAULT_WIDTH = 300;
|
24 |
|
|
public static var DEFAULT_HEIGHT = 100;
|
25 |
|
|
public static var DEFAULT_ANTI_ALIAS_TYPE = 'advanced';
|
26 |
|
|
public static var MARGIN_LEFT = -3;
|
27 |
|
|
public static var PADDING_BOTTOM = 5; // Extra padding to make sure the movie is high enough in most cases.
|
28 |
|
|
public static var LEADING_REMAINDER = 2; // Flash uses the specified leading minus 2 as the applied leading.
|
29 |
|
|
|
30 |
|
|
public static var MAX_FONT_SIZE = 126;
|
31 |
|
|
public static var ALIASING_MAX_FONT_SIZE = 48;
|
32 |
|
|
|
33 |
|
|
//= Holds CSS properties and other rendering properties for the Flash movie.
|
34 |
|
|
// *Don't overwrite!*
|
35 |
|
|
public static var styles:SifrStyleSheet = new SifrStyleSheet();
|
36 |
|
|
//= Allow sIFR to be run from localhost
|
37 |
|
|
public static var fromLocal:Boolean = true;
|
38 |
|
|
//= Array containing domains for which sIFR may render text. Used to prevent
|
39 |
|
|
// hotlinking. Use `*` to allow all domains.
|
40 |
|
|
public static var domains:Array = [];
|
41 |
|
|
//= Whether kerning is enabled by default. This can be overriden from the client side.
|
42 |
|
|
// See also <http://livedocs.macromedia.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00002811.html>.
|
43 |
|
|
public static var defaultKerning:Boolean = true;
|
44 |
|
|
//= Default value which can be overriden from the client side.
|
45 |
|
|
// See also <http://livedocs.macromedia.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00002788.html>.
|
46 |
|
|
public static var defaultSharpness:Number = 0;
|
47 |
|
|
//= Default value which can be overriden from the client side.
|
48 |
|
|
// See also <http://livedocs.macromedia.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00002787.html>.
|
49 |
|
|
public static var defaultThickness:Number = 0;
|
50 |
|
|
//= Default value which can be overriden from the client side.
|
51 |
|
|
// See also <http://livedocs.macromedia.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00002732.html>.
|
52 |
|
|
public static var defaultOpacity:Number = -1; // Use client settings
|
53 |
|
|
//= Default value which can be overriden from the client side.
|
54 |
|
|
// See also <http://livedocs.macromedia.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00002788.html>.
|
55 |
|
|
public static var defaultBlendMode:Number = -1; // Use cliest settings
|
56 |
|
|
//= Overrides the grid fit type as defined on the client side.
|
57 |
|
|
// See also <http://livedocs.macromedia.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00002444.html>.
|
58 |
|
|
public static var enforcedGridFitType:String = null;
|
59 |
|
|
//= If `true` sIFR won't override the anti aliasing set in the Flash IDE when exporting.
|
60 |
|
|
// Thickness and sharpness won't be affected either.
|
61 |
|
|
public static var preserveAntiAlias:Boolean = false;
|
62 |
|
|
//= If `true` sIFR will disable anti-aliasing if the font size is larger than `ALIASING_MAX_FONT_SIZE`.
|
63 |
|
|
// This setting is *independent* from `preserveAntiAlias`.
|
64 |
|
|
public static var conditionalAntiAlias:Boolean = true;
|
65 |
|
|
//= Sets the anti alias type. By default it's `DEFAULT_ANTI_ALIAS_TYPE`.
|
66 |
|
|
// See also <http://livedocs.macromedia.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00002733.html>.
|
67 |
|
|
public static var antiAliasType:String = null;
|
68 |
|
|
//= Flash filters can be added to this array and will be applied to the text field.
|
69 |
|
|
public static var filters:Array = [];
|
70 |
|
|
//= A mapping from the names of the filters to their actual objecs, used when transforming
|
71 |
|
|
// filters defined on the client. You can add additional filters here so they'll be supported
|
72 |
|
|
// when defined on the client.
|
73 |
|
|
public static var filterMap:Object = {
|
74 |
|
|
DisplacementMapFilter : flash.filters.DisplacementMapFilter,
|
75 |
|
|
ColorMatrixFilter : flash.filters.ColorMatrixFilter,
|
76 |
|
|
ConvolutionFilter : flash.filters.ConvolutionFilter,
|
77 |
|
|
GradientBevelFilter : flash.filters.GradientBevelFilter,
|
78 |
|
|
GradientGlowFilter : flash.filters.GradientGlowFilter,
|
79 |
|
|
BevelFilter : flash.filters.BevelFilter,
|
80 |
|
|
GlowFilter : flash.filters.GlowFilter,
|
81 |
|
|
BlurFilter : flash.filters.BlurFilter,
|
82 |
|
|
DropShadowFilter : flash.filters.DropShadowFilter
|
83 |
|
|
};
|
84 |
|
|
|
85 |
|
|
private static var instance;
|
86 |
|
|
|
87 |
|
|
private var textField;
|
88 |
|
|
private var content;
|
89 |
|
|
private var realHeight;
|
90 |
|
|
private var originalHeight;
|
91 |
|
|
private var currentHeight;
|
92 |
|
|
private var fontSize;
|
93 |
|
|
private var tuneWidth;
|
94 |
|
|
private var tuneHeight;
|
95 |
|
|
|
96 |
|
|
|
97 |
|
|
|
98 |
|
|
//= Sets the default styles for `sIFR.styles`. This method is called
|
99 |
|
|
// directly in `sifr.fla`, before options are applied.
|
100 |
|
|
public static function setDefaultStyles() {
|
101 |
|
|
sIFR.styles.parseCSS([
|
102 |
|
|
'.', CSS_ROOT_CLASS, ' { color: #000000; }',
|
103 |
|
|
'strong { display: inline; font-weight: bold; } ',
|
104 |
|
|
'em { display: inline; font-style: italic; }',
|
105 |
|
|
'a { color: #0000FF; text-decoration: underline; }',
|
106 |
|
|
'a:hover { color: #0000FF; text-decoration: none; }'
|
107 |
|
|
].join(''));
|
108 |
|
|
}
|
109 |
|
|
|
110 |
|
|
//= Validates the domain sIFR is being used on.
|
111 |
|
|
// Returns `true` if the domain is valid, `false` otherwise.
|
112 |
|
|
public static function checkDomain():Boolean {
|
113 |
|
|
if(sIFR.domains.length == 0) return true;
|
114 |
|
|
|
115 |
|
|
var domain = (new LocalConnection()).domain();
|
116 |
|
|
if(sIFR.fromLocal) sIFR.domains.push('localhost');
|
117 |
|
|
|
118 |
|
|
for(var i = 0; i < sIFR.domains.length; i++) {
|
119 |
|
|
var match = sIFR.domains[i];
|
120 |
|
|
if(match == '*' || match == domain) return true;
|
121 |
|
|
|
122 |
|
|
var wildcard = match.lastIndexOf('*');
|
123 |
|
|
if(wildcard > -1) {
|
124 |
|
|
match = match.substr(wildcard + 1);
|
125 |
|
|
var matchPosition = domain.lastIndexOf(match);
|
126 |
|
|
if(matchPosition > -1 && (matchPosition + match.length) == domain.length) return true;
|
127 |
|
|
}
|
128 |
|
|
}
|
129 |
|
|
|
130 |
|
|
return false;
|
131 |
|
|
}
|
132 |
|
|
|
133 |
|
|
//= Runs sIFR. Called automatically.
|
134 |
|
|
public static function run() {
|
135 |
|
|
var holder = _root.holder;
|
136 |
|
|
var content = checkDomain() ? unescape(_root.content) : DEFAULT_TEXT
|
137 |
|
|
if(content == 'undefined' || content == '') {
|
138 |
|
|
content = DEFAULT_TEXT;
|
139 |
|
|
fscommand('resetmovie', '');
|
140 |
|
|
} else fscommand('ping', '');
|
141 |
|
|
|
142 |
|
|
// Sets stage parameters
|
143 |
|
|
Stage.scaleMode = 'noscale';
|
144 |
|
|
Stage.align = 'TL';
|
145 |
|
|
Stage.showMenu = false;
|
146 |
|
|
|
147 |
|
|
// Other parameters
|
148 |
|
|
var opacity = parseInt(_root.opacity);
|
149 |
|
|
if(!isNaN(opacity)) holder._alpha = sIFR.defaultOpacity == -1 ? opacity : sIFR.defaultOpacity;
|
150 |
|
|
else holder._alpha = 100;
|
151 |
|
|
_root.blendMode = sIFR.defaultBlendMode == -1 ? _root.blendmode : sIFR.defaultBlendMode;
|
152 |
|
|
|
153 |
|
|
sIFR.instance = new sIFR(holder.txtF, content);
|
154 |
|
|
// This should ignore resizes from the callback. Disabled for now.
|
155 |
|
|
/* if(_root.zoomsupport == 'true') Stage.addListener({onResize: function() { sIFR.instance.scale() }});*/
|
156 |
|
|
|
157 |
|
|
// Setup callbacks
|
158 |
|
|
_root.watch('callbackTrigger', function() {
|
159 |
|
|
sIFR.callback();
|
160 |
|
|
return false;
|
161 |
|
|
});
|
162 |
|
|
}
|
163 |
|
|
|
164 |
|
|
private static function eval(str) {
|
165 |
|
|
var as;
|
166 |
|
|
|
167 |
|
|
if(str.charAt(0) == '{') { // Ah, we need to create an object
|
168 |
|
|
as = {};
|
169 |
|
|
str = str.substring(1, str.length - 1);
|
170 |
|
|
var $ = str.split(',');
|
171 |
|
|
for(var i = 0; i < $.length; i++) {
|
172 |
|
|
var $1 = $[i].split(':');
|
173 |
|
|
as[$1[0]] = sIFR.eval($1[1]);
|
174 |
|
|
}
|
175 |
|
|
} else if(str.charAt(0) == '"') { // String
|
176 |
|
|
as = str.substring(1, str.length - 1);
|
177 |
|
|
} else if(str == 'true' || str == 'false') { // Boolean
|
178 |
|
|
as = str == 'true';
|
179 |
|
|
} else { // Float
|
180 |
|
|
as = parseFloat(str);
|
181 |
|
|
}
|
182 |
|
|
|
183 |
|
|
return as;
|
184 |
|
|
}
|
185 |
|
|
|
186 |
|
|
private function applyFilters() {
|
187 |
|
|
var $filters = this.textField.filters;
|
188 |
|
|
$filters = $filters.concat(sIFR.filters);
|
189 |
|
|
|
190 |
|
|
var $ = _root.flashfilters.split(';'); // name,prop:value,...;
|
191 |
|
|
for(var i = 0; i < $.length; i++) {
|
192 |
|
|
var $1 = $[i].split(',');
|
193 |
|
|
|
194 |
|
|
var newFilter = new sIFR.filterMap[$1[0]]();
|
195 |
|
|
for(var j = 1; j < $1.length; j++) {
|
196 |
|
|
var $2 = $1[j].split(':');
|
197 |
|
|
newFilter[$2[0]] = sIFR.eval(unescape($2[1]));
|
198 |
|
|
}
|
199 |
|
|
|
200 |
|
|
$filters.push(newFilter);
|
201 |
|
|
}
|
202 |
|
|
|
203 |
|
|
this.textField.filters = $filters;
|
204 |
|
|
}
|
205 |
|
|
|
206 |
|
|
private function sIFR(textField, content) {
|
207 |
|
|
this.textField = textField;
|
208 |
|
|
this.content = content;
|
209 |
|
|
|
210 |
|
|
var offsetLeft = parseInt(_root.offsetleft);
|
211 |
|
|
textField._x = MARGIN_LEFT + (isNaN(offsetLeft) ? 0 : offsetLeft);
|
212 |
|
|
var offsetTop = parseInt(_root.offsettop);
|
213 |
|
|
if(!isNaN(offsetTop)) textField._y += offsetTop;
|
214 |
|
|
|
215 |
|
|
tuneWidth = parseInt(_root.tunewidth);
|
216 |
|
|
if(isNaN(tuneWidth)) tuneWidth = 0;
|
217 |
|
|
tuneHeight = parseInt(_root.tuneheight);
|
218 |
|
|
if(isNaN(tuneHeight)) tuneHeight = 0;
|
219 |
|
|
|
220 |
|
|
textField._width = tuneWidth + (isNaN(parseInt(_root.width)) ? DEFAULT_WIDTH : parseInt(_root.width));
|
221 |
|
|
textField._height = tuneHeight + (isNaN(parseInt(_root.height)) ? DEFAULT_HEIGHT : parseInt(_root.height));
|
222 |
|
|
textField.wordWrap = true;
|
223 |
|
|
textField.selectable = _root.selectable == 'true';
|
224 |
|
|
textField.gridFitType = sIFR.enforcedGridFitType || _root.gridfittype;
|
225 |
|
|
this.applyFilters();
|
226 |
|
|
|
227 |
|
|
// Determine font-size and the number of lines
|
228 |
|
|
this.fontSize = parseInt(_root.size);
|
229 |
|
|
if(isNaN(this.fontSize)) this.fontSize = 26;
|
230 |
|
|
styles.fontSize = this.fontSize;
|
231 |
|
|
|
232 |
|
|
if(!sIFR.preserveAntiAlias && (sIFR.conditionalAntiAlias && this.fontSize < ALIASING_MAX_FONT_SIZE
|
233 |
|
|
|| !sIFR.conditionalAntiAlias)) {
|
234 |
|
|
textField.antiAliasType = sIFR.antiAliasType || DEFAULT_ANTI_ALIAS_TYPE;
|
235 |
|
|
}
|
236 |
|
|
|
237 |
|
|
if(!sIFR.preserveAntiAlias || !isNaN(parseInt(_root.sharpness))) {
|
238 |
|
|
textField.sharpness = parseInt(_root.sharpness);
|
239 |
|
|
}
|
240 |
|
|
if(isNaN(textField.sharpness)) textField.sharpness = sIFR.defaultSharpness;
|
241 |
|
|
|
242 |
|
|
if(!sIFR.preserveAntiAlias || !isNaN(parseInt(_root.thickness))) {
|
243 |
|
|
textField.thickness = parseInt(_root.thickness);
|
244 |
|
|
}
|
245 |
|
|
if(isNaN(textField.thickness)) textField.thickness = sIFR.defaultThickness;
|
246 |
|
|
|
247 |
|
|
// Set font-size and other styles
|
248 |
|
|
sIFR.styles.parseCSS(unescape(_root.css));
|
249 |
|
|
|
250 |
|
|
var rootStyle = styles.getStyle('.sIFR-root') || {};
|
251 |
|
|
rootStyle.fontSize = this.fontSize; // won't go higher than 126!
|
252 |
|
|
styles.setStyle('.sIFR-root', rootStyle);
|
253 |
|
|
textField.styleSheet = styles;
|
254 |
|
|
|
255 |
|
|
this.write(content);
|
256 |
|
|
this.repaint();
|
257 |
|
|
}
|
258 |
|
|
|
259 |
|
|
private function repaint() {
|
260 |
|
|
var leadingFix = this.isSingleLine() ? sIFR.styles.latestLeading : 0;
|
261 |
|
|
if(leadingFix > 0) leadingFix -= LEADING_REMAINDER;
|
262 |
|
|
|
263 |
|
|
// Flash wants to scroll the movie by one line, by adding the fontSize to the
|
264 |
|
|
// textField height this is no longer happens. We also add the absolute tuneHeight,
|
265 |
|
|
// to prevent a negative value from triggering the bug. We won't send the fake
|
266 |
|
|
// value to the JavaScript side, though.
|
267 |
|
|
textField._height = textField.textHeight + PADDING_BOTTOM + this.fontSize + Math.abs(tuneHeight) + tuneHeight - leadingFix;
|
268 |
|
|
this.realHeight = textField._height - this.fontSize - Math.abs(tuneHeight);
|
269 |
|
|
var arg = 'height:' + this.realHeight;
|
270 |
|
|
if(_root.fitexactly == 'true') arg += ',width:' + (textField.textWidth + tuneWidth);
|
271 |
|
|
fscommand('resize', arg);
|
272 |
|
|
|
273 |
|
|
this.originalHeight = textField._height;
|
274 |
|
|
this.currentHeight = Stage.height;
|
275 |
|
|
|
276 |
|
|
textField._xscale = textField._yscale = parseInt(_root.zoom);
|
277 |
|
|
}
|
278 |
|
|
|
279 |
|
|
private function write(content) {
|
280 |
|
|
this.textField.htmlText = ['<p class="', CSS_ROOT_CLASS, '">',
|
281 |
|
|
content, '</p>'
|
282 |
|
|
].join('');
|
283 |
|
|
}
|
284 |
|
|
|
285 |
|
|
private function isSingleLine() {
|
286 |
|
|
return Math.round((this.textField.textHeight - sIFR.styles.latestLeading) / this.fontSize) == 1;
|
287 |
|
|
}
|
288 |
|
|
|
289 |
|
|
//= Scales the text field to the new scale of the Flash movie itself.
|
290 |
|
|
public function scale() {
|
291 |
|
|
this.currentHeight = Stage.height;
|
292 |
|
|
var scale = 100 * Math.round(this.currentHeight / this.originalHeight);
|
293 |
|
|
textField._xscale = textField._yscale = scale;
|
294 |
|
|
}
|
295 |
|
|
|
296 |
|
|
private function calculateRatios() {
|
297 |
|
|
var strings = ['X', 'X<br>X', 'X<br>X<br>X', 'X<br>X<br>X<br>X'];
|
298 |
|
|
var results = {};
|
299 |
|
|
|
300 |
|
|
for(var i = 1; i <= strings.length; i++) {
|
301 |
|
|
var size = 6;
|
302 |
|
|
|
303 |
|
|
this.write(strings[i - 1]);
|
304 |
|
|
while(size < MAX_FONT_SIZE) {
|
305 |
|
|
var rootStyle = sIFR.styles.getStyle('.sIFR-root') || {};
|
306 |
|
|
rootStyle.fontSize = size;
|
307 |
|
|
sIFR.styles.setStyle('.sIFR-root', rootStyle);
|
308 |
|
|
this.textField.styleSheet = sIFR.styles;
|
309 |
|
|
this.repaint();
|
310 |
|
|
var ratio = (this.realHeight - PADDING_BOTTOM) / i / size;
|
311 |
|
|
if(!results[size]) results[size] = ratio;
|
312 |
|
|
else results[size] = ((i - 1) * results[size] + ratio) / i;
|
313 |
|
|
size++;
|
314 |
|
|
}
|
315 |
|
|
}
|
316 |
|
|
|
317 |
|
|
var sizes = [], ratios = [];
|
318 |
|
|
var ratiosToSizes = {}, sizesToRatios = {};
|
319 |
|
|
|
320 |
|
|
for(var size in results) {
|
321 |
|
|
if(results[size] == Object.prototype[size]) continue;
|
322 |
|
|
var ratio = results[size];
|
323 |
|
|
ratiosToSizes[ratio] = Math.max(ratio, parseInt(size));
|
324 |
|
|
}
|
325 |
|
|
|
326 |
|
|
for(var ratio in ratiosToSizes) {
|
327 |
|
|
if(ratiosToSizes[ratio] == Object.prototype[ratio]) continue;
|
328 |
|
|
sizesToRatios[ratiosToSizes[ratio]] = roundDecimals(ratio, 2);
|
329 |
|
|
sizes.push(ratiosToSizes[ratio]);
|
330 |
|
|
}
|
331 |
|
|
|
332 |
|
|
sizes.sort(function(a, b) { return a - b; });
|
333 |
|
|
for(var j = 0; j < sizes.length - 1; j++) ratios.push(sizes[j], sizesToRatios[sizes[j]]);
|
334 |
|
|
ratios.push(sizesToRatios[sizes[sizes.length - 1]]);
|
335 |
|
|
|
336 |
|
|
fscommand('debug:ratios', '[' + ratios.join(',') + ']');
|
337 |
|
|
}
|
338 |
|
|
|
339 |
|
|
private function roundDecimals(value, decimals) {
|
340 |
|
|
return Math.round(value * Math.pow(10, decimals)) / Math.pow(10, decimals);
|
341 |
|
|
}
|
342 |
|
|
|
343 |
|
|
public static function callback() {
|
344 |
|
|
switch(_root.callbackType) {
|
345 |
|
|
case 'replacetext':
|
346 |
|
|
sIFR.instance.content = _root.callbackValue;
|
347 |
|
|
sIFR.instance.write(_root.callbackValue);
|
348 |
|
|
sIFR.instance.repaint();
|
349 |
|
|
break;
|
350 |
|
|
case 'resettext':
|
351 |
|
|
sIFR.instance.write('');
|
352 |
|
|
sIFR.instance.write(sIFR.instance.content);
|
353 |
|
|
break;
|
354 |
|
|
case 'ratios':
|
355 |
|
|
sIFR.instance.calculateRatios();
|
356 |
|
|
break;
|
357 |
|
|
}
|
358 |
|
|
}
|
359 |
|
|
} |