Search code examples
javascriptmagentoprototypejsscriptaculous

how to override javascript function declared within Prototype.js Class


NOTE

This is not a duplicate of How to override product.js file in magento as this question refers to a function used in Magento core within a Prototype Class. Additionally the question refers to a different JavaScript library, i.e. scriptaculous, and different files. Hence the solution is also different.

As originally explained below. Updated question title to be more clear.


I'm working on a Magento site which loads the scriptaculous library.

I want to overide the Autocompleter.Base function in my local.js file, it's defined in control.js with:

control.js

var Autocompleter = { };
Autocompleter.Base = Class.create({
  baseInitialize: function(element, update, options) {
    element          = $(element);
    this.element     = element;
    this.update      = $(update);
    this.hasFocus    = false;
    this.changed     = false;
    this.active      = false;
    this.index       = 0;
    this.entryCount  = 0;
    this.oldElementValue = this.element.value;

    if(this.setOptions)
      this.setOptions(options);
    else
      this.options = options || { };

    this.options.paramName    = this.options.paramName || this.element.name;
    this.options.tokens       = this.options.tokens || [];
    this.options.frequency    = this.options.frequency || 0.4;
    this.options.minChars     = this.options.minChars || 1;
    this.options.onShow       = this.options.onShow ||
      function(element, update){
        if(!update.style.position || update.style.position=='absolute') {
          update.style.position = 'absolute';
          Position.clone(element, update, {
            setHeight: false,
            offsetTop: element.offsetHeight
          });
        }
        Effect.Appear(update,{duration:0.15});
      };
    this.options.onHide = this.options.onHide ||
      function(element, update){ new Effect.Fade(update,{duration:0.15}) };

    if(typeof(this.options.tokens) == 'string')
      this.options.tokens = new Array(this.options.tokens);
    // Force carriage returns as token delimiters anyway
    if (!this.options.tokens.include('\n'))
      this.options.tokens.push('\n');

    this.observer = null;

    this.element.setAttribute('autocomplete','off');

    Element.hide(this.update);

    Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
    Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
  },

How can I overide this, when it's coming from a Prototype Class?

I'm able to override override Effect.Fade class which it calls, but this is not a Prototype Class.

effect.js

Effect.Fade = function(element) {
  element = $(element);
  var oldOpacity = element.getInlineOpacity();
  var options = Object.extend({
    from: element.getOpacity() || 1.0,
    to:   0.0,
    afterFinishInternal: function(effect) {
      if (effect.options.to!=0) return;
      effect.element.hide().setStyle({opacity: oldOpacity});
    }
  }, arguments[1] || { });
  return new Effect.Opacity(element,options);
};

Attempts So Far:

local.js

// WORKS
Effect.Fade = function(element) {
    element = $(element);
    var oldOpacity = element.getInlineOpacity();
    var options = Object.extend({
        from: element.getOpacity() || 1.0,
        to:   0.0,
        afterFinishInternal: function(effect) {
            if (effect.options.to!=0) return;
            effect.element.hide().setStyle({opacity: oldOpacity});
        }
    }, arguments[1] || { });
    return new Effect.Opacity(element,options);
};

// DOES NOT WORK
Autocompleter.Base.baseInitialize = function(element, update, options) {
    element          = $(element);
    this.element     = element;
    this.update      = $(update);
    this.hasFocus    = false;
    this.changed     = false;
    this.active      = false;
    this.index       = 0;
    this.entryCount  = 0;
    this.oldElementValue = this.element.value;

    if(this.setOptions)
        this.setOptions(options);
    else
        this.options = options || { };

    this.options.paramName    = this.options.paramName || this.element.name;
    this.options.tokens       = this.options.tokens || [];
    this.options.frequency    = this.options.frequency || 0.4;
    this.options.minChars     = this.options.minChars || 1;
    this.options.onShow       = this.options.onShow ||
        function(element, update){
            if(!update.style.position || update.style.position=='absolute') {
                update.style.position = 'absolute';
                Position.clone(element, update, {
                    setHeight: false,
                    offsetTop: element.offsetHeight
                });
            }
            Effect.Appear(update,{duration:0.15});
        };
    debugger;
    this.options.onHide = this.options.onHide ||
        function(element, update){ new Effect.Fade(update,{duration:0.15}) };

    if(typeof(this.options.tokens) == 'string')
        this.options.tokens = new Array(this.options.tokens);
    // Force carriage returns as token delimiters anyway
    if (!this.options.tokens.include('\n'))
        this.options.tokens.push('\n');

    this.observer = null;

    this.element.setAttribute('autocomplete','off');

    Element.hide(this.update);

    Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
    Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
};

Solution

  • Instead of:

    Autocompleter.Base.baseInitialize = function(element, update, options) {
    

    Try:

    Autocompleter.Base.prototype.baseInitialize = function(element, update, options) {
    

    Run the demo below.

    var Autocompleter = { };
    Autocompleter.Base = Class.create({
      baseInitialize: function(element, update, options) {
        console.log("I'm original baseInitialize")
      }
    });
    
    new Autocompleter.Base().baseInitialize();
    
    Autocompleter.Base.prototype.baseInitialize = function () { console.log("I'm modified baseInitialize"); }
    
    new Autocompleter.Base().baseInitialize();
    <script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.3/prototype.js"></script>