ACC SHELL

Path : /srv/www/vhosts/eqnx/flash/
File Upload :
Current File : /srv/www/vhosts/eqnx/flash/sIFR.as

/*****************************************************************************
scalable Inman Flash Replacement (sIFR) version 3.

Copyright 2006 – 2008 Mark Wubben, <http://novemberborn.net/>

Older versions:
* IFR by Shaun Inman
* sIFR 1.0 by Mike Davidson, Shaun Inman and Tomas Jogin
* sIFR 2.0 by Mike Davidson, Shaun Inman, Tomas Jogin and Mark Wubben

See also <http://novemberborn.net/sifr3> and <http://wiki.novemberborn.net/sifr3>.

This software is licensed and provided under the CC-GNU LGPL.
See <http://creativecommons.org/licenses/LGPL/2.1/>
*****************************************************************************/

import SifrStyleSheet;
import flash.external.*;

class sIFR {
  public static var DEFAULT_TEXT                 = 'Rendered with sIFR 3, revision 436<br><strong>Rendered with sIFR 3, revision 436</strong><br><em>Rendered with sIFR 3, revision 436</em><br><strong><em>Rendered with sIFR 3, revision 436</em></strong>';
  public static var VERSION_WARNING              = 'Movie (436) is incompatible with sifr.js (%s). Use movie of %s.<br><strong>Movie (436) is incompatible with sifr.js (%s). Use movie of %s.</strong><br><em>Movie (436) is incompatible with sifr.js (%s). Use movie of %s.</em><br><strong><em>Movie (436) is incompatible with sifr.js (%s). Use movie of %s.</em></strong>';
  public static var CSS_ROOT_CLASS               = 'sIFR-root';
  public static var DEFAULT_WIDTH                = 300;
  public static var DEFAULT_HEIGHT               = 100;
  public static var DEFAULT_ANTI_ALIAS_TYPE      = 'advanced';
  public static var MARGIN_LEFT                  = -3;
  public static var PADDING_BOTTOM               = 5; // Extra padding to make sure the movie is high enough in most cases.
  public static var LEADING_REMAINDER            = 2; // Flash uses the specified leading minus 2 as the applied leading, so we increment by 2

  public static var MIN_FONT_SIZE                = 6;
  public static var MAX_FONT_SIZE                = 126;
  // Minimal height of the Flash movie. This height is required in order to detect incorrect Stage height in the
  // scaling calculations. JavaScript sets the size of the Flash movie to 0px by 0px, but at least Opera makes this
  // 1px by 1px. With 1000% page zoom this would get to 10px, but the highest I saw was 8px. Seems safe enough to have
  // the min height at 10px then.
  public static var MIN_HEIGHT                   = 10;
  public static var ALIASING_MAX_FONT_SIZE       = 48;
  public static var VERSION                      = '436';
  
  //= Holds CSS properties and other rendering properties for the Flash movie.
  //  *Don't overwrite!*
  public static var styles:SifrStyleSheet        = new SifrStyleSheet();
  //= Allow sIFR to be run from the filesystem
  public static var fromLocal:Boolean            = true;
  //= Array containing domains for which sIFR may render text. Used to prevent
  //  hotlinking. Use `*` to allow all domains.
  public static var domains:Array                = [];
  //= Whether kerning is enabled by default. This can be overriden from the client side.
  //  See also <http://livedocs.macromedia.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00002811.html>.
  public static var defaultKerning:Boolean       = true;
  //= Default value which can be overriden from the client side.
  //  See also <http://livedocs.macromedia.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00002788.html>.
  public static var defaultSharpness:Number      = 0;
  //= Default value which can be overriden from the client side.
  //  See also <http://livedocs.macromedia.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00002787.html>.
  public static var defaultThickness:Number      = 0;
  //= Default value which can be overriden from the client side.
  //  See also <http://livedocs.macromedia.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00002732.html>.
  public static var defaultOpacity:Number        = -1; // Use client settings
  //= Default value which can be overriden from the client side.
  //  See also <http://livedocs.macromedia.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00002788.html>.
  public static var defaultBlendMode:Number      = -1; // Use cliest settings
  //= Overrides the grid fit type as defined on the client side.
  //  See also <http://livedocs.macromedia.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00002444.html>.
  public static var enforcedGridFitType:String   = null;
  //= If `true` sIFR won't override the anti aliasing set in the Flash IDE when exporting.
  //  Thickness and sharpness won't be affected either.
  public static var preserveAntiAlias:Boolean    = false;
  //= If `true` sIFR will disable anti-aliasing if the font size is larger than `ALIASING_MAX_FONT_SIZE`.
  //  This setting is *independent* from `preserveAntiAlias`.
  public static var conditionalAntiAlias:Boolean = true;
  //= Sets the anti alias type. By default it's `DEFAULT_ANTI_ALIAS_TYPE`.
  //  See also <http://livedocs.macromedia.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00002733.html>.
  public static var antiAliasType:String         = null;
  //= Flash filters can be added to this array and will be applied to the text field.
  public static var filters:Array                = [];
  //= A mapping from the names of the filters to their actual objecs, used when transforming
  //  filters defined on the client. You can add additional filters here so they'll be supported
  //  when defined on the client.
  public static var filterMap:Object             = {
    DisplacementMapFilter : flash.filters.DisplacementMapFilter,
    ColorMatrixFilter     : flash.filters.ColorMatrixFilter,
    ConvolutionFilter     : flash.filters.ConvolutionFilter,
    GradientBevelFilter   : flash.filters.GradientBevelFilter,
    GradientGlowFilter    : flash.filters.GradientGlowFilter,
    BevelFilter           : flash.filters.BevelFilter,
    GlowFilter            : flash.filters.GlowFilter,
    BlurFilter            : flash.filters.BlurFilter,
    DropShadowFilter      : flash.filters.DropShadowFilter
  };

  private static var instance;
  private static var menu;
  private static var menuItems = [];
  
  private var textField;
  private var content;
  private var forceSingleLine;
  private var fontSize;
  private var tuneWidth;
  private var tuneHeight;
  private var primaryLink;
  private var primaryLinkTarget;
  
  public var realHeight;
  public var renderHeight;
  public var firstResize = true;
  

  
  //= Sets the default styles for `sIFR.styles`. This method is called
  //  directly in `sifr.fla`, before options are applied.
  public static function setDefaultStyles() {
    sIFR.styles.parseCSS([
      '.', CSS_ROOT_CLASS, ' { color: #000000; }',
      'strong { display: inline; font-weight: bold; } ',
      'em { display: inline; font-style: italic; }',
      'a { color: #0000FF; text-decoration: underline; }',
      'a:hover { color: #0000FF; text-decoration: none; }'
    ].join(''));
  }
  
  //= Validates the domain sIFR is being used on.
  //  Returns `true` if the domain is valid, `false` otherwise.  
  public static function checkDomain():Boolean {
    if(sIFR.domains.length == 0) return true;

    var domain = (new LocalConnection()).domain();
    for(var i = 0; i < sIFR.domains.length; i++) {
      var match = sIFR.domains[i];
      if(match == '*' || match == domain) return true;

      var wildcard = match.lastIndexOf('*');
      if(wildcard > -1) {
        match = match.substr(wildcard + 1);
        var matchPosition = domain.lastIndexOf(match);
        if(matchPosition > -1 && (matchPosition + match.length) == domain.length) return true;
      }
    }
    
    return false;
  }
  
  public static function checkLocation():Boolean {
    return _root._url.indexOf('?') == -1;
  }
  
  //= Runs sIFR. Called automatically.
  public static function run(delayed) {
    // Flash version older than 9,0,115 under IE incorrectly approach the Flash movie, breaking ExternalInterface.
    // sIFR has a workaround, but this workaround cannot be applied until the Flash movie has been added to the document,
    // which usually causes the ActionScript to run and set up ExternalInterface. Delaying for a couple milliseconds
    // gives the JavaScript time to set up the workaround.
    if(_root.delayrun == 'true' && !delayed) {
      var interval;
      interval = setInterval(
        function() {
          clearInterval(interval);
          sIFR.run(true);
        }, 200);
        
      return;
    }
    
    // Have to set up the menu items first!
    menuItems.push(
      new ContextMenuItem("Follow link", function() { getURL(sIFR.instance.primaryLink, sIFR.instance.primaryLinkTarget) }),
      new ContextMenuItem("Open link in new window", function() { getURL(sIFR.instance.primaryLink, "_blank") })
    );
    
    var holder       = _root.holder;
    var content      = DEFAULT_TEXT;
    var checkVersion = true;
    if(checkLocation() && checkDomain()) content = unescapeUnicode(_root.content);
    if(content == 'undefined' || content == '') {
      var resetting = ExternalInterface.call('sIFR.__resetBrokenMovies');
      if(resetting) return;
      content      = DEFAULT_TEXT;
      checkVersion = false;
    }
    
    if(checkVersion && _root.version != VERSION) content = VERSION_WARNING.split('%s').join(_root.version);
    
    // Sets stage parameters
    Stage.scaleMode = 'noscale';
    Stage.align = 'TL';

    menu = new ContextMenu();
    menu.hideBuiltInItems();
    _root.menu = menu;
    
    // Other parameters
    var opacity = parseInt(_root.opacity, 10);
    if(!isNaN(opacity)) holder._alpha = sIFR.defaultOpacity == -1 ? opacity : sIFR.defaultOpacity;
    else holder._alpha = 100;
    _root.blendMode = sIFR.defaultBlendMode == -1 ? _root.blendmode : sIFR.defaultBlendMode;

    sIFR.instance = new sIFR(holder.txtF, content);
    Key.addListener({onKeyDown: function() { sIFR.instance.blur() }});
    Mouse.addListener({onMouseWheel: function() { sIFR.instance.blur() }});
    Stage.addListener({onResize: function() { sIFR.instance.onResize(); }});
    if(_root.selectable == 'false') Mouse.addListener({onMouseDown: function() { sIFR.instance.blur() }});
    if(_root.cursor == 'arrow') _root.holder.useHandCursor = false;

    ExternalInterface.addCallback('replaceText', sIFR.instance, sIFR.instance.replaceText);
    ExternalInterface.addCallback('calculateRatios', sIFR.instance, sIFR.instance.calculateRatios);
    ExternalInterface.addCallback('resize', sIFR.instance, sIFR.instance.resize);
    ExternalInterface.addCallback('scaleMovie', sIFR.instance, sIFR.instance.repaint);
    ExternalInterface.addCallback('changeCSS', sIFR.instance, sIFR.instance.changeCSS);
  }
  
  private static function eval(str) {
    var as;

    if(str.charAt(0) == '{') { // Ah, we need to create an object
      as = {};
      str = str.substring(1, str.length - 1);
      var $ = str.split(',');
      for(var i = 0; i < $.length; i++) {
        var $1 = $[i].split(':');
        as[$1[0]] = sIFR.eval($1[1]);
      }
    } else if(str.charAt(0) == '"') { // String
      as = str.substring(1, str.length - 1);
    } else if(str == 'true' || str == 'false') { // Boolean
      as = str == 'true';
    } else { // Float
      as = parseFloat(str);
    }
    
    return as;
  }
  
  private static function unescapeUnicode(str) {
    var result = [];
    var escapees = str.split('%');
    
    for(var i = 0; i < escapees.length; i++) {
      var escapee = escapees[i];
      if(i > 0 || str.charAt(0) == '%') {
        var hex = escapee.charAt(0) == 'u' ? escapee.substr(1, 4) : escapee.substr(0, 2);
        result.push(String.fromCharCode(parseInt(hex, 16)), escapee.substr(escapee.charAt(0) == 'u' ? 5 : 2));
      } else result.push(escapee);
    }

    return result.join('');
  }
  
  private function applyFilters() {
    var $filters = this.textField.filters;
    $filters = $filters.concat(sIFR.filters);
    
    var $ = unescapeUnicode(_root.flashfilters).split(';'); // name,prop:value,...;
    for(var i = 0; i < $.length; i++) {
      var $1 = $[i].split(',');
      
      var newFilter = new sIFR.filterMap[$1[0]]();
      for(var j = 1; j < $1.length; j++) {
        var $2 = $1[j].split(':');
        newFilter[$2[0]] = sIFR.eval(unescapeUnicode($2[1]));
      }
      
      $filters.push(newFilter);
    }

    this.textField.filters = $filters;
  }
  
  private function applyBackground() {
    if(!_root.background) return;
    
    var background = _root.createEmptyMovieClip('backgroundClip', 10);
    var loader = new MovieClipLoader();
    loader.addListener({onLoadInit: function() { background.setMask(_root.holder) }});
    loader.loadClip("/projectfiles/img.jpg", background);
  }
  
  private function setTextFieldSize(width, height) {
    textField._width = tuneWidth + (isNaN(width) ? DEFAULT_WIDTH : width);
    textField._height = tuneHeight + (isNaN(height) ? DEFAULT_HEIGHT : height);
  }
  
  private function sIFR(textField, content) {
    sIFR.instance = this; // Need to set it right now, because it's used in closures later
    
    this.textField = textField;
    this.content   = content;
    
    this.primaryLink       = unescapeUnicode(_root.link);
    this.primaryLinkTarget = unescapeUnicode(_root.target);

    var offsetLeft         = parseInt(_root.offsetleft, 10);
    textField._x           = MARGIN_LEFT + (isNaN(offsetLeft) ? 0 : offsetLeft);
    var offsetTop          = parseInt(_root.offsettop, 10);
    if(!isNaN(offsetTop)) textField._y += offsetTop;
    
    tuneWidth = parseInt(_root.tunewidth, 10);
    if(isNaN(tuneWidth)) tuneWidth = 0;
    tuneHeight = parseInt(_root.tuneheight, 10);
    if(isNaN(tuneHeight)) tuneHeight = 0;
    
    this.renderHeight     = parseInt(_root.renderheight, 10);
    this.setTextFieldSize(parseInt(_root.width, 10), parseInt(this.renderHeight, 10));
    this.forceSingleLine  = _root.forcesingleline == 'true';
    textField.wordWrap    = _root.preventwrap != 'true';
    textField.selectable  = _root.selectable == 'true';
    textField.gridFitType = sIFR.enforcedGridFitType || _root.gridfittype;

    this.applyFilters();
    this.applyBackground();

    this.fontSize = parseInt(_root.size, 10);
    if(isNaN(this.fontSize)) this.fontSize = 26;

    this.setStyles(unescapeUnicode(_root.css), false);
    
    if(!sIFR.preserveAntiAlias && (sIFR.conditionalAntiAlias && this.fontSize < ALIASING_MAX_FONT_SIZE
    || !sIFR.conditionalAntiAlias)) {
      textField.antiAliasType = (_root.antialiastype != '' ? _root.antialiastype : sIFR.antiAliasType) || DEFAULT_ANTI_ALIAS_TYPE;      
    }

    if(!sIFR.preserveAntiAlias || !isNaN(parseInt(_root.sharpness, 10))) {
      textField.sharpness = parseInt(_root.sharpness, 10);
    }
    if(isNaN(textField.sharpness)) textField.sharpness = sIFR.defaultSharpness;

    if(!sIFR.preserveAntiAlias || !isNaN(parseInt(_root.thickness, 10))) {
      textField.thickness = parseInt(_root.thickness, 10);
    }
    if(isNaN(textField.thickness)) textField.thickness = sIFR.defaultThickness;
    
    textField._parent._xscale = textField._parent._yscale = 100;
    
    this.setupEvents();
    this.write(content);
    this.repaint();
  }
  
  private static function call(method) {
    var args = Array.prototype.slice.call(arguments, 1);
    args.unshift('sIFR.replacements["' + _root.id + '"].' + method);
    return ExternalInterface.call.apply(ExternalInterface, args);
  }
  
  private function repaint() {
    if(this.forceSingleLine) {
      this.textField._width = 50000;
      // 50 000 is a bit too much, filters won't work at that size etc. Therefore we size it down to the text width, and
      // a bit of margin.
      this.textField._width = this.textField.textWidth + 500;
    }
    
    var leadingFix = this.isSingleLine() ? sIFR.styles.latestLeading : 0;
    
    // Flash wants to scroll the movie by one line, by adding the fontSize to the
    // textField height this is no longer happens. We also add the absolute tuneHeight,
    // to prevent a negative value from triggering the bug. We won't send the fake
    // value to the JavaScript side, though.
    textField._height = Math.max(MIN_HEIGHT, textField.textHeight + PADDING_BOTTOM + tuneHeight - leadingFix) + this.fontSize + Math.abs(tuneHeight);
    this.realHeight = Math.floor(textField._height - this.fontSize - Math.abs(tuneHeight));
    var width = _root.fitexactly == 'true' ? textField.textWidth + tuneWidth : null;

    this.doScale(function() {
      // Store in a local variable to deal with synchronous interaction with JavaScript.
      var firstResize = sIFR.instance.firstResize;
      sIFR.instance.firstResize = false;
      sIFR.call('resizeFlashElement', sIFR.instance.realHeight, width, firstResize);
      sIFR.instance.renderHeight = sIFR.instance.realHeight;
    });
  }
  
  private function write(content) {
    this.textField.htmlText = ['<p class="', CSS_ROOT_CLASS, '">', 
                                content, '</p>'
                              ].join('');
  }
  
  private function isSingleLine() {
    return Math.round((this.textField.textHeight - sIFR.styles.latestLeading) / this.fontSize) == 1;
  }
  
  public function doScale(callback) {
    if(this.validScale()) return this.scale(callback);

    var self = this;
    this.textField._parent.onEnterFrame = function() {
      if(!self.validScale()) return;
      delete self.textField._parent.onEnterFrame;
      self.scale(callback);
    }
  }

  //= Scales the text field to the new scale of the Flash movie itself.
  public function scale(callback) {
    this.textField._parent._xscale = this.textField._parent._yscale = this.calculateScale();
    if(callback) callback();
  }
  
  public function calculateScale() {
    return 10 * Math.round(10 * Stage.height / this.renderHeight);
  }
  
  public function validScale() {
    return Stage.height >= 10 && this.calculateScale() >= 20;
  }
  
  public function onResize() {
    if(!this.validScale()) return;
    
    var oldZoom = this.textField._parent._xscale;
    var zoom    = this.calculateScale();
    
    this.scale();
    if(oldZoom != zoom) sIFR.call('resizeAfterScale');
  }
  
  private function calculateRatios() {
    var strings = ['x', 'x<br>x', 'x<br>x<br>x', 'x<br>x<br>x<br>x'];
    var results = {};
    
    this.setTextFieldSize(1000, 1000);

    for(var i = 1; i <= strings.length; i++) {
      var size = MIN_FONT_SIZE;

      this.write(strings[i - 1]);
      while(size < MAX_FONT_SIZE) {
        var rootStyle = sIFR.styles.getStyle('.sIFR-root') || {};
        rootStyle.fontSize = size;
        sIFR.styles.setStyle('.sIFR-root', rootStyle);
        this.textField.styleSheet = sIFR.styles;
        this.repaint();
        var ratio = (this.realHeight - PADDING_BOTTOM - tuneHeight) / i / size;
        if(!results[size]) results[size] = ratio;
        else results[size] = ((i - 1) * results[size] + ratio) / i;
        size++;
      }
    }

    var ratios = [];

    // Here we round the ratios to two decimals and try to create an optimized array of ratios 
    // to be used by sIFR.
    // lastRatio is the ratio we are currently optimizing
    var lastRatio = roundDecimals(results[MIN_FONT_SIZE], 2);
    for(var size = MIN_FONT_SIZE + 1; size < MAX_FONT_SIZE; size++) {
      var ratio = roundDecimals(results[size], 2);
      
      // If the lastRatio is different from the previous ratio, and from the current ratio, 
      // try to see if there's at least a 1px difference between the two. If so, store the 
      // lastRatio with the previous size, then optimize the current ratio.
      if(lastRatio != results[size - 1] && lastRatio != ratio && Math.abs(Math.round(size * ratio) - Math.round(size * lastRatio)) >= 1) {
        ratios.push(size -1, lastRatio);
        lastRatio = ratio;
      }
    }

    // Add the last optimized ratio as the default ratio.
    ratios.push(lastRatio);

    ExternalInterface.call('sIFR.debug.__ratiosCallback', _root.id, ratios);
  }
  
  private function roundDecimals(value, decimals) {
    return Math.round(value * Math.pow(10, decimals)) / Math.pow(10, decimals);
  }
  
  public function replaceText(content) {
    this.content = unescapeUnicode(content);
    this.setupEvents();
    this.write(this.content);
    this.repaint();
  }
  
  public function resize(height) {
    this.setTextFieldSize(height, this.realHeight);
    this.repaint();
  }
  
  public function changeCSS(css) {
    this.setStyles(unescapeUnicode(css), true);
    this.repaint();
  }
  
  private function contentIsLink() {
    return this.content.indexOf('<a ') == 0 && this.content.indexOf('<a ') == this.content.lastIndexOf('<a ')
      && this.content.indexOf('</a>') == this.content.length - 4;
  }
  
  private function setupEvents() {
    if(_root.fixhover == 'true' && this.contentIsLink()) {
      
      this.textField._parent.onRollOver = function() { 
        sIFR.call('fireEvent', 'onRollOver');
      };
      
      this.textField._parent.onRollOut  = function() { 
        sIFR.instance.fixHover();
        sIFR.call('fireEvent', 'onRollOut');
      };
      
      this.textField._parent.onRelease  = function() {
        sIFR.call('fireEvent', 'onRelease');
        getURL(sIFR.instance.primaryLink, sIFR.instance.primaryLinkTarget);
      };
      
      menu.customItems = menuItems;
    } else {
      if(_root.events == 'true') {
        this.textField._parent.onRollOver = function() { sIFR.call('fireEvent', 'onRollOver') };
        this.textField._parent.onRollOut  = function() { sIFR.call('fireEvent', 'onRollOut') };
        this.textField._parent.onRelease  = function() { sIFR.call('fireEvent', 'onRelease') };
      } else {
        if(_root.cursor == 'pointer') this.textField._parent.onRelease = function() {};
        else delete this.textField._parent.onRelease;
        delete this.textField._parent.onRollOver;
        delete this.textField._parent.onRollOut;
      }
      
      menu.customItems = [];
    }
  }
  
  private function fixHover() {
    this.write('');
    this.write(this.content);
  }
  
  public function blur() {
    switch(Key.getCode()) {
      case Key.SHIFT:
      case Key.CONTROL:
        break;
      default:
        sIFR.call('blurFlashElement');
    }
  }
  
  private function setStyles(css, reset) {
    if(reset) {
      sIFR.styles = new SifrStyleSheet();
      sIFR.setDefaultStyles();
    }
    
    sIFR.styles.fontSize = this.fontSize;
    // Set font-size and other styles
    sIFR.styles.parseCSS(css);
    
    var rootStyle = sIFR.styles.getStyle('.sIFR-root') || {};
    rootStyle.fontSize = this.fontSize; // won't go higher than 126!
    sIFR.styles.setStyle('.sIFR-root', rootStyle);
    this.textField.styleSheet = sIFR.styles;
  }
}

ACC SHELL 2018