<commit_before>'use strict';

function create_gates(new_gates){
    new_gates = new_gates || [{}];
    for(var gate in new_gates){
        gates.push({
          'color': new_gates[gate]['color'] || '#fff',
          'destroy': new_gates[gate]['destroy'] !== void 0
            ? new_gates[gate]['destroy']
            : false,
          'dx': new_gates[gate]['dx'] || false,
          'dy': new_gates[gate]['dy'] || false,
          'event': new_gates[gate]['event'] || function(){},
          'height': new_gates[gate]['height'] || 40,
          'interval': new_gates[gate]['interval'] || 0,
          'x': canvas_x + new_gates[gate]['x'] || canvas_x,
          'y': canvas_y + new_gates[gate]['y'] || canvas_y,
          'width': new_gates[gate]['width'] || 40,
        });
    }
}

function create_particles(new_particles){
    if(particles.length >= storage_data['max-particles']){
        return;
    }

    new_particles = new_particles || [{}];
    for(var particle in new_particles){
        particles.push({
          'dx': new_particles[particle]['dx'] || 0,
          'dy': new_particles[particle]['dy'] || 0,
          'height': new_particles[particle]['height'] || storage_data['particle-height'],
          'width': new_particles[particle]['width'] || storage_data['particle-width'],
          'x': new_particles[particle]['x'] || 0,
          'y': new_particles[particle]['y'] || 0,
        });
    }
}

function draw_logic(){
    canvas_buffer.save();
    canvas_buffer.translate(
      -camera_x,
      -camera_y
    );

    // Draw gates.
    for(var gate in gates){
        canvas_buffer.fillStyle = gates[gate]['color'];
        canvas_buffer.fillRect(
          gates[gate]['x'],
          gates[gate]['y'],
          gates[gate]['width'],
          gates[gate]['height']
       );
    }

    // Draw particles.
    canvas_buffer.fillStyle = '#fff';
    for(var particle in particles){
        canvas_buffer.fillRect(
          particles[particle]['x'],
          particles[particle]['y'],
          particles[particle]['width'],
          particles[particle]['height']
        );
    };

    canvas_buffer.restore();

    canvas_buffer.fillStyle = '#fff';
    // Draw camera position.
    canvas_buffer.fillText(
      camera_x + 'x ' + camera_y + 'y',
      5,
      25
    );

    // Draw number of particles
    //   and max-particles.
    canvas_buffer.fillText(
      particles.length
        + '/'
        + storage_data['max-particles'],
      5,
      50
    );
}

function logic(){
    if(core_menu_open){
        return;
    }

    if(key_left){
        camera_x -= storage_data['scroll-speed'];
    }

    if(key_right){
        camera_x += storage_data['scroll-speed'];
    }

    if(key_down){
        camera_y += storage_data['scroll-speed'];
    }

    if(key_up){
        camera_y -= storage_data['scroll-speed'];
    }

    frame_counter += 1;
    if(frame_counter > 99){
        frame_counter = 0;
    }

    for(var particle in particles){
        particles[particle]['x'] += particles[particle]['dx'];
        particles[particle]['y'] += particles[particle]['dy'];

        if(!math_rectangle_overlap({
          'h0': particles[particle]['height'],
          'h1': boundaries['height'],
          'w0': particles[particle]['width'],
          'w1': boundaries['width'],
          'x0': particles[particle]['x'],
          'x1': boundaries['x'],
          'y0': particles[particle]['x'],
          'y1': boundaries['y'],
        })){
            particles.splice(
              particle,
              1
            );
        }
    }

    for(var gate in gates){
        if(gates[gate]['interval'] > 0
          && frame_counter % gates[gate]['interval'] === 0){
            gates[gate]['event']();
        }

        for(var particle in particles){
            if(math_rectangle_overlap({
              'h0': particles[particle]['height'],
              'h1': gates[gate]['height'],
              'w0': particles[particle]['width'],
              'w1': gates[gate]['width'],
              'x0': particles[particle]['x'],
              'x1': gates[gate]['x'],
              'y0': particles[particle]['y'],
              'y1': gates[gate]['y'],
            })){
                if(gates[gate]['destroy']){
                    particles.splice(
                      particle,
                      1
                    );
                    continue;
                }

                if(gates[gate]['dx'] !== false){
                    particles[particle]['dx'] = gates[gate]['dx'];
                }
                if(gates[gate]['dy'] !== false){
                    particles[particle]['dy'] = gates[gate]['dy'];
                }
            }
        }
    }
}

function setmode_logic(newgame){
    gates = [];
    particles = [];

    // Main menu mode.
    if(canvas_mode === 0){
        document.body.innerHTML = '

Test Level

'
          + '

<input disabled value=ESC>Menu
'
          + '<input id=movement-keys maxlength=4>Camera ↑←↓→
'
          + '<input id=reset-camera-key maxlength=1>Reset Camera

'
          + '
<input id=audio-volume max=1 min=0 step=0.01 type=range>Audio
'
          + '<input id=max-particles>Max Particles
'
          + '<input id=ms-per-frame>ms/Frame
'
          + '<input id=particle-height>Particle Height
'
          + '<input id=particle-width>Particle Width
'
          + '<input id=scroll-speed>Scroll Speed
'
          + 'Reset Settings

';
        storage_update();

    // New game mode.
    }else{
        if(newgame){
            storage_save();
        }

        camera_x = 0;
        camera_y = 0;
        frame_counter = 0;
        key_left = false;
        key_right = false;
    }
}

var boundaries = {};
var camera_x = 0;
var camera_y = 0;
var drag = false;
var drag_x = 0;
var drag_y = 0;
var frame_counter = 0;
var gates = [];
var key_down = false;
var key_left = false;
var key_right = false;
var key_up = false;
var particles = [];

window.onload = function(){
    storage_init({
      'data': {
        'audio-volume': 1,
        'movement-keys': 'WASD',
        'max-particles': 1000,
        'ms-per-frame': 25,
        'particle-height': 5,
        'particle-width': 5,
        'reset-camera-key': 'H',
        'scroll-speed': 5,
      },
      'prefix': 'ParticleRun-2D.htm-',
    });
    canvas_init();

    window.onkeydown = function(e){
        if(canvas_mode <= 0){
            return;
        }

        var key = e.keyCode || e.which;

        // ESC: menu.
        if(key === 27){
            core_menu_toggle();
            return;
        }

        key = String.fromCharCode(key);

        if(key === storage_data['movement-keys'][0]){
            key_up = true;

        }else if(key === storage_data['movement-keys'][1]){
            key_left = true;

        }else if(key === storage_data['movement-keys'][2]){
            key_down = true;

        }else if(key === storage_data['movement-keys'][3]){
            key_right = true;

        }else if(key === storage_data['reset-camera-key']){
            camera_x = 0;
            camera_y = 0;

        }else if(key === 'Q'){
            canvas_menu_quit();
        }
    };

    window.onkeyup = function(e){
        var key = String.fromCharCode(e.keyCode || e.which);

        if(key === storage_data['movement-keys'][0]){
            key_up = false;

        }else if(key === storage_data['movement-keys'][1]){
            key_left = false;

        }else if(key === storage_data['movement-keys'][2]){
            key_down = false;

        }else if(key === storage_data['movement-keys'][3]){
            key_right = false;
        }
    };

    window.onmousedown =
      window.ontouchstart = function(e){
        drag = true;
        drag_x = e.pageX;
        drag_y = e.pageY;
    };

    window.onmousemove =
      window.ontouchmove = function(e){
        if(!drag){
            return;
        }

        camera_x += drag_x - e.pageX;
        camera_y += drag_y - e.pageY;
        drag_x = e.pageX;
        drag_y = e.pageY;
    };

    window.onmouseup =
      window.ontouchend = function(e){
        drag = false;
    };
};
<commit_msg>moved core_menu_open check to canvas_logicloop()<commit_after>'use strict';

function create_gates(new_gates){
    new_gates = new_gates || [{}];
    for(var gate in new_gates){
        gates.push({
          'color': new_gates[gate]['color'] || '#fff',
          'destroy': new_gates[gate]['destroy'] !== void 0
            ? new_gates[gate]['destroy']
            : false,
          'dx': new_gates[gate]['dx'] || false,
          'dy': new_gates[gate]['dy'] || false,
          'event': new_gates[gate]['event'] || function(){},
          'height': new_gates[gate]['height'] || 40,
          'interval': new_gates[gate]['interval'] || 0,
          'x': canvas_x + new_gates[gate]['x'] || canvas_x,
          'y': canvas_y + new_gates[gate]['y'] || canvas_y,
          'width': new_gates[gate]['width'] || 40,
        });
    }
}

function create_particles(new_particles){
    if(particles.length >= storage_data['max-particles']){
        return;
    }

    new_particles = new_particles || [{}];
    for(var particle in new_particles){
        particles.push({
          'dx': new_particles[particle]['dx'] || 0,
          'dy': new_particles[particle]['dy'] || 0,
          'height': new_particles[particle]['height'] || storage_data['particle-height'],
          'width': new_particles[particle]['width'] || storage_data['particle-width'],
          'x': new_particles[particle]['x'] || 0,
          'y': new_particles[particle]['y'] || 0,
        });
    }
}

function draw_logic(){
    canvas_buffer.save();
    canvas_buffer.translate(
      -camera_x,
      -camera_y
    );

    // Draw gates.
    for(var gate in gates){
        canvas_buffer.fillStyle = gates[gate]['color'];
        canvas_buffer.fillRect(
          gates[gate]['x'],
          gates[gate]['y'],
          gates[gate]['width'],
          gates[gate]['height']
       );
    }

    // Draw particles.
    canvas_buffer.fillStyle = '#fff';
    for(var particle in particles){
        canvas_buffer.fillRect(
          particles[particle]['x'],
          particles[particle]['y'],
          particles[particle]['width'],
          particles[particle]['height']
        );
    };

    canvas_buffer.restore();

    canvas_buffer.fillStyle = '#fff';
    // Draw camera position.
    canvas_buffer.fillText(
      camera_x + 'x ' + camera_y + 'y',
      5,
      25
    );

    // Draw number of particles
    //   and max-particles.
    canvas_buffer.fillText(
      particles.length
        + '/'
        + storage_data['max-particles'],
      5,
      50
    );
}

function logic(){
    if(key_left){
        camera_x -= storage_data['scroll-speed'];
    }

    if(key_right){
        camera_x += storage_data['scroll-speed'];
    }

    if(key_down){
        camera_y += storage_data['scroll-speed'];
    }

    if(key_up){
        camera_y -= storage_data['scroll-speed'];
    }

    frame_counter += 1;
    if(frame_counter > 99){
        frame_counter = 0;
    }

    for(var particle in particles){
        particles[particle]['x'] += particles[particle]['dx'];
        particles[particle]['y'] += particles[particle]['dy'];

        if(!math_rectangle_overlap({
          'h0': particles[particle]['height'],
          'h1': boundaries['height'],
          'w0': particles[particle]['width'],
          'w1': boundaries['width'],
          'x0': particles[particle]['x'],
          'x1': boundaries['x'],
          'y0': particles[particle]['x'],
          'y1': boundaries['y'],
        })){
            particles.splice(
              particle,
              1
            );
        }
    }

    for(var gate in gates){
        if(gates[gate]['interval'] > 0
          && frame_counter % gates[gate]['interval'] === 0){
            gates[gate]['event']();
        }

        for(var particle in particles){
            if(math_rectangle_overlap({
              'h0': particles[particle]['height'],
              'h1': gates[gate]['height'],
              'w0': particles[particle]['width'],
              'w1': gates[gate]['width'],
              'x0': particles[particle]['x'],
              'x1': gates[gate]['x'],
              'y0': particles[particle]['y'],
              'y1': gates[gate]['y'],
            })){
                if(gates[gate]['destroy']){
                    particles.splice(
                      particle,
                      1
                    );
                    continue;
                }

                if(gates[gate]['dx'] !== false){
                    particles[particle]['dx'] = gates[gate]['dx'];
                }
                if(gates[gate]['dy'] !== false){
                    particles[particle]['dy'] = gates[gate]['dy'];
                }
            }
        }
    }
}

function setmode_logic(newgame){
    gates = [];
    particles = [];

    // Main menu mode.
    if(canvas_mode === 0){
        document.body.innerHTML = '

Test Level

'
          + '

<input disabled value=ESC>Menu
'
          + '<input id=movement-keys maxlength=4>Camera ↑←↓→
'
          + '<input id=reset-camera-key maxlength=1>Reset Camera

'
          + '
<input id=audio-volume max=1 min=0 step=0.01 type=range>Audio
'
          + '<input id=max-particles>Max Particles
'
          + '<input id=ms-per-frame>ms/Frame
'
          + '<input id=particle-height>Particle Height
'
          + '<input id=particle-width>Particle Width
'
          + '<input id=scroll-speed>Scroll Speed
'
          + 'Reset Settings

';
        storage_update();

    // New game mode.
    }else{
        if(newgame){
            storage_save();
        }

        camera_x = 0;
        camera_y = 0;
        frame_counter = 0;
        key_left = false;
        key_right = false;
    }
}

var boundaries = {};
var camera_x = 0;
var camera_y = 0;
var drag = false;
var drag_x = 0;
var drag_y = 0;
var frame_counter = 0;
var gates = [];
var key_down = false;
var key_left = false;
var key_right = false;
var key_up = false;
var particles = [];

window.onload = function(){
    storage_init({
      'data': {
        'audio-volume': 1,
        'movement-keys': 'WASD',
        'max-particles': 1000,
        'ms-per-frame': 25,
        'particle-height': 5,
        'particle-width': 5,
        'reset-camera-key': 'H',
        'scroll-speed': 5,
      },
      'prefix': 'ParticleRun-2D.htm-',
    });
    canvas_init();

    window.onkeydown = function(e){
        if(canvas_mode <= 0){
            return;
        }

        var key = e.keyCode || e.which;

        // ESC: menu.
        if(key === 27){
            core_menu_toggle();
            return;
        }

        key = String.fromCharCode(key);

        if(key === storage_data['movement-keys'][0]){
            key_up = true;

        }else if(key === storage_data['movement-keys'][1]){
            key_left = true;

        }else if(key === storage_data['movement-keys'][2]){
            key_down = true;

        }else if(key === storage_data['movement-keys'][3]){
            key_right = true;

        }else if(key === storage_data['reset-camera-key']){
            camera_x = 0;
            camera_y = 0;

        }else if(key === 'Q'){
            canvas_menu_quit();
        }
    };

    window.onkeyup = function(e){
        var key = String.fromCharCode(e.keyCode || e.which);

        if(key === storage_data['movement-keys'][0]){
            key_up = false;

        }else if(key === storage_data['movement-keys'][1]){
            key_left = false;

        }else if(key === storage_data['movement-keys'][2]){
            key_down = false;

        }else if(key === storage_data['movement-keys'][3]){
            key_right = false;
        }
    };

    window.onmousedown =
      window.ontouchstart = function(e){
        drag = true;
        drag_x = e.pageX;
        drag_y = e.pageY;
    };

    window.onmousemove =
      window.ontouchmove = function(e){
        if(!drag){
            return;
        }

        camera_x += drag_x - e.pageX;
        camera_y += drag_y - e.pageY;
        drag_x = e.pageX;
        drag_y = e.pageY;
    };

    window.onmouseup =
      window.ontouchend = function(e){
        drag = false;
    };
};
<|endoftext|>


<commit_before>/**
 * Created by Karen Cohen on 7/20/14.
 */

/**
 * Contact Name information
 * @typedef {Object} Contact.Name
 * @property {string} prefix - The prefix of the contact's name
 * @property {string} first - The contact's first name
 * @property {string} middle - The contact's middle name
 * @property {string} last - The contact's last name
 * @property {string} suffix - The suffix of the contact's name
 */
function Name(obj){
    this._prefix = obj && obj.prefix;
    this._first = obj && obj.first;
    this._last = obj && obj.last;
    this._middle = obj && obj.middle;
    this._suffix = obj && obj.suffix;
}
Name.prototype.prefix = function (str) {
    if (str !== undefined) _prefix = str;
    return _prefix;
};
Name.prototype.first = function (str) {
    if (str !== undefined) _first = str;
    return _first;
};
Name.prototype.last = function (str) {
    if (str !== undefined) _last = str;
    return _last;
};
Name.prototype.middle = function (str) {
    if (str !== undefined) _middle = str;
    return _middle;
};
Name.prototype.suffix = function (str) {
    if (str !== undefined) _suffix = str;
    return _suffix;
};

/**
 * Contact Company information
 * @typedef {Object} Contact.Company
 * @property {string} role - The contact's role within their company,
 * @property {string} name - The name of the contact's current company
 */
function Company(obj){
    this._role = obj && obj.role;
    this._name = obj && obj.name;
}
Company.prototype.role = function (str) {
    if (str !== undefined)
        _role = str;
    return _role;
};
Company.prototype.name = function (str) {
    if (str !== undefined)
        _name = str;
    return _name;
};

/**
 * Contact Email information
 * @typedef {Object} Contact.Email
 * @property {string} tag - a context tag
 * @property {string} email - The email address to add
 * @property {string} contactSubscriptionStatus - The subscription status of the current contact ['optIn' or 'optInOut' or 'notSet']
 * @property {string} siteOwnerSubscriptionStatus - The subscription status of the site owner in relation to this contact ['optIn' or 'optInOut' or 'notSet']
 */
function Email(obj){
    this._tag = obj && obj.tag;
    this._email = obj && obj.email;
    this._contactSubscriptionStatus = obj && obj.contactSubscriptionStatus;
    this._siteOwnerSubscriptionStatus = obj && obj.siteOwnerSubscriptionStatus;
}

Email.prototype.tag = function (str) {
    if (str !== undefined)
        _tag = str;
    return _tag;
};
Email.prototype.email = function (str) {
    if (str !== undefined)
        _email = str;
    return _email;
};
Email.prototype.contactSubscriptionStatus = function (str) {
    if (str !== undefined)
        _contactSubscriptionStatus = str;
    return _contactSubscriptionStatus;
};
Email.prototype.siteOwnerSubscriptionStatus = function (str) {
    if (str !== undefined)
        _siteOwnerSubscriptionStatus = str;
    return _siteOwnerSubscriptionStatus;
};

/**
 * Contact Phone information
 * @typedef {Object} Contact.Phone
 * @property {string} tag - a context tag
 * @property {string} phone - The phone number to add
 * @property {string} normalizedPhone - The contact's normalized phone number
 */
function Phone(obj){
    this._tag = obj && obj.tag;
    this._phone = obj && obj.phone;
    this._normalizedPhone = obj && obj.normalizedPhone;
}
Phone.prototype.tag = function (str) {
    if (str !== undefined)
        _tag = str;
    return _tag;
};
Phone.prototype.phone = function (str) {
    if (str !== undefined)
        _phone = str;
    return _phone;
};
Phone.prototype.normalizedPhone = function (str) {
    if (str !== undefined)
        _normalizedPhone = str;
    return _normalizedPhone;
};

/**
 * Contact Address information
 * @typedef {Object} Contact.Address
 * @property {String} tag - The context tag associated with this address,
 * @property {?String} address - The contact's street address,
 * @property {?String} neighborhood - The contact's street neighborhood,
 * @property {?String} city - The contact's city,
 * @property {?String} region - The contact's region. An example of this would be a state in the US, or a province in Canada,
 * @property {?String} country - The contact's country,
 * @property {?Number} postalCode - The contact's postal code
 */
function Address(obj){
    this._tag = obj && obj.tag;
    this._address = obj && obj.address;
    this._neighborhood = obj && obj.neighborhood;
    this._region = obj && obj.region;
    this._country = obj && obj.country;
    this._postalCode = obj && obj.postalCode;
}

Address.prototype.tag = function (str) {
    if (str !== undefined)
        _tag = str;
    return _tag;
};
Address.prototype.address = function (str) {
    if (str !== undefined)
        _address = str;
    return _address;
};
Address.prototype.neighborhood = function (str) {
    if (str !== undefined)
        _neighborhood = str;
    return _neighborhood;
};
Address.prototype.city = function (str) {
    if (str !== undefined)
        _city = str;
    return _city;
};
Address.prototype.region = function (str) {
    if (str !== undefined)
        _region = str;
    return _region;
};
Address.prototype.country = function (str) {
    if (str !== undefined)
        _country = str;
    return _country;
};
Address.prototype.postalCode = function (code) {
    if (code !== undefined)
        _postalCode = code;
    return _postalCode;
};

/**
 * Contact Url information
 * @typedef {Object} Contact.Url
 * @property {string} tag - The context tag associated with this url
 * @property {string} url - A url associated with this contact
 */
function Url(obj){
    this._tag = obj && obj.tag;
    this._url = obj && obj.url;
}

Url.prototype.tag = function (str) {
    if (str !== undefined)
        _tag = str;
    return _tag;
};
Url.prototype.url = function (str) {
    if (str !== undefined)
        _url = str;
    return _url;
};

/**
 * Contact Important Date information
 * @typedef {Object} Contact.ImportantDate
 * @property {string} tag - The context tag associated with this date
 * @property {dateTime} date - An important date for this contact, as an ISO 8601 timestamp
 */
function ImportantDate(obj){
    this._tag = obj && obj.tag;
    this._date = obj && obj.date;
}

ImportantDate.prototype.tag = function (str) {
    if (str !== undefined)
        _tag = str;
    return _tag;
};
ImportantDate.prototype.date = function (str) {
    if (str !== undefined)
        _date = str;
    return _date;
};

/**
 * CustomField
 * @typedef {Object} Contact.CustomField
 * @property {string} field - The name of the custom field
 * @property {string} value - The value of the custom field
 */
function CustomField(obj){
    this._field = obj && obj.field;
    this._value = obj && obj.value;
}

CustomField.prototype.field = function (str) {
    if (str !== undefined)
        _field = str;
    return _field;
};
CustomField.prototype.value = function (str) {
    if (str !== undefined)
        _value = str;
    return _value;
};

/**
 * Contact Note information
 * @typedef {Object} Contact.Note
 * @property {string} tag - a context tag
 * @property {string} note - The note to add
 */
function Note(obj){
    this._tag = obj && obj.tag;
    this._note = obj && obj.note;
}
Note.prototype.tag = function (str) {
    if (str !== undefined)
        _tag = str;
    return _tag;
};
Note.prototype.note = function (str) {
    if (str !== undefined)
        _note = str;
    return _note;
};

/**
 * Contact ID information
 * @typedef {Object} Contact.ID
 * @property {boolean} exists - true if this id exists
 * @property {string} id - The id of this Contact
 */
function Id(obj){
    this._id = obj && obj.id;
    this._exists = obj && obj.exists;
}
Id.prototype.exists = function () {
    return _exists;
};
Id.prototype.id = function () {
    return _id;
};

/**
 * @class
 * @constructor
 * @alias Contact
 */
module.exports = function Contact() {

    var name = new Name();
    this.name = function (obj) {
        if (obj !== undefined && obj != null)
            name = new Name(obj);
        return name;
    };

    var company = new Company();
    this.company = function (obj) {
        if (obj !== undefined && obj != null)
            company = new Company(obj);
        return company;
    };

    var picture = null;
    this.picture = function (url) {
        if (url !== undefined && url != null)
            picture = url;
        return picture;
    };

    var emails = [];
    this.emails = function () {
        return emails;
    };
    this.addEmail = function (email) {
        emails.push(email);
    };

    var phones = [];
    this.phones = function () {
        return phones;
    };
    this.addPhone = function (phone) {
        phones.push(phone);
    };

    var addresses = [];
    this.addresses = function () {
        return addresses;
    };
    this.addAddress = function (address) {
        addresses.push(address);
    };

    var labels = [];
    this.labels = function () {
        return labels;
    };
    this.addLabel = function (label) {
        labels.push(label);
    };

    var urls = [];
    this.urls = function () {
        return urls;
    };
    this.addUrl = function (url) {
        urls.push(url);
    };

    var dates = [];
    this.dates = function () {
        return dates;
    };
    this.addDate = function (date) {
        dates.push(date);
    };

    var customFields = [];
    this.customFields = function () {
        return customFields;
    };
    this.addCustomField = function (field) {
        customFields.push(field);
    };

    var notes = [];
    this.notes = function () {
        return notes;
    };
    this.addNote = function (note) {
        notes.push(note);
    };

    var id = new Id();

    var modifiedAt = Date.now;
    this.modifiedAt = function () {
        return modifiedAt;
    };

    var createdAt = Date.now;
    this.createdAt = function () {
        return createdAt;
    };

    /**
     * Contact Save information
     * @typedef {Object} Contact.SaveData
     * @property {Contact.ID} contactId - The id of this Contact
     * @property {Contact} contact - The Contact object
     * @property {?string} activityId - The optional id of an {@link Activity} if one was added to this {@link Contact}
     */
};

/**
 * A callback that returns if the save operation completed successfully
 *
 * @callback Contact.SaveCompletedCallback
 * @param {Contact.SaveData} data - the save information about this operation
 */

/**
 * A callback that returns if the save operation failed
 *
 * @callback Contact.SaveFailedCallback
 * @param {number} errorCode - the error code for this failure
 * @param {string} errorMessage - the error message for this failure
 */

/**
 *
 * @param {Contact.SaveCompletedCallback} onSuccess A callback to indicate the operation was successful, with the updated Contact
 * @param {Contact.SaveFailedCallback} onFailure A callback to indicate the operation failed
 */
//Contact.prototype.save = function(onSuccess, onFailure) {};

/**
 * Adds an Activity to this {@link Contact}. Note, the {@link Contact} must be saved for the {@link Activity} to be persisted
 * @param activity {Activity} The Activity to post
 */
//Contact.prototype.addActivity = function(activity) {};

/**
 * A callback that returns if the get operation completed successfully
 *
 * @callback Contact.GetActivitiesCallback
 * @param {Contact} data - the retrieved {@link Contact}
 */

/**
 * A callback that returns if the get operation failed
 *
 * @callback Contact.GetActivitiesFailureCallback
 * @param {number} errorCode - the error code for this failure
 * @param {string} errorMessage - the error message for this failure
 */

/**
 * Get Activities Query Options
 * @typedef {Object} GetActivitiesOptions
 * @property {?Number} pageSize - The number of results to return per page of data. Valid options are: 25, 50 and 100. Defaults to 25
 * @property {?string} activityTypes - The activity types to filter against. Multiple activity types are separated by a comma
 * @property {?dateTime} until - The ending date for activities we want to return, as an ISO 8601 timestamp This field is only relevant when a cursor is not present
 * @property {?dateTime} from - The beginning date for activities we want to return, as an ISO 8601 timestamp. This field is only relevant when a cursor is not present
 * @property {?string} scope - The scope of the results to return, either for the entire site or limited to the current application. Can either be site or app. By default, all activities for the site will be returned
 */

/**
 * Returns a list of {@link Activity} for this contact, based on the filter. By default, all Activities are returned
 * @param options {GetActivitiesOptions} The Activity to post
 * @param onSuccess {Contact.GetActivitiesCallback} a callback function that receives a WixDataCursor object
 * @param onFailure {Contact.GetActivitiesFailureCallback} failure callback
 */
//Contact.prototype.getActivities = function(options, onSuccess, onFailure) {};

<commit_msg>OH MY GOD<commit_after>/**
 * Created by Karen Cohen on 7/20/14.
 */

/**
 * Contact Name information
 * @typedef {Object} Contact.Name
 * @property {string} prefix - The prefix of the contact's name
 * @property {string} first - The contact's first name
 * @property {string} middle - The contact's middle name
 * @property {string} last - The contact's last name
 * @property {string} suffix - The suffix of the contact's name
 */
function Name(obj){
    this._prefix = obj && obj.prefix;
    this._first = obj && obj.first;
    this._last = obj && obj.last;
    this._middle = obj && obj.middle;
    this._suffix = obj && obj.suffix;
}
Name.prototype.prefix = function (str) {
    if (str !== undefined) this._prefix = str;
    return this._prefix;
};
Name.prototype.first = function (str) {
    if (str !== undefined) this._first = str;
    return this._first;
};
Name.prototype.last = function (str) {
    if (str !== undefined) this._last = str;
    return this._last;
};
Name.prototype.middle = function (str) {
    if (str !== undefined) this._middle = str;
    return this._middle;
};
Name.prototype.suffix = function (str) {
    if (str !== undefined) this._suffix = str;
    return this._suffix;
};

/**
 * Contact Company information
 * @typedef {Object} Contact.Company
 * @property {string} role - The contact's role within their company,
 * @property {string} name - The name of the contact's current company
 */
function Company(obj){
    this._role = obj && obj.role;
    this._name = obj && obj.name;
}
Company.prototype.role = function (str) {
    if (str !== undefined)
        this._role = str;
    return this._role;
};
Company.prototype.name = function (str) {
    if (str !== undefined)
        this._name = str;
    return this._name;
};

/**
 * Contact Email information
 * @typedef {Object} Contact.Email
 * @property {string} tag - a context tag
 * @property {string} email - The email address to add
 * @property {string} contactSubscriptionStatus - The subscription status of the current contact ['optIn' or 'optInOut' or 'notSet']
 * @property {string} siteOwnerSubscriptionStatus - The subscription status of the site owner in relation to this contact ['optIn' or 'optInOut' or 'notSet']
 */
function Email(obj){
    this._tag = obj && obj.tag;
    this._email = obj && obj.email;
    this._contactSubscriptionStatus = obj && obj.contactSubscriptionStatus;
    this._siteOwnerSubscriptionStatus = obj && obj.siteOwnerSubscriptionStatus;
}

Email.prototype.tag = function (str) {
    if (str !== undefined)
        this._tag = str;
    return this._tag;
};
Email.prototype.email = function (str) {
    if (str !== undefined)
        this._email = str;
    return this._email;
};
Email.prototype.contactSubscriptionStatus = function (str) {
    if (str !== undefined)
        this._contactSubscriptionStatus = str;
    return this._contactSubscriptionStatus;
};
Email.prototype.siteOwnerSubscriptionStatus = function (str) {
    if (str !== undefined)
        this._siteOwnerSubscriptionStatus = str;
    return this._siteOwnerSubscriptionStatus;
};

/**
 * Contact Phone information
 * @typedef {Object} Contact.Phone
 * @property {string} tag - a context tag
 * @property {string} phone - The phone number to add
 * @property {string} normalizedPhone - The contact's normalized phone number
 */
function Phone(obj){
    this._tag = obj && obj.tag;
    this._phone = obj && obj.phone;
    this._normalizedPhone = obj && obj.normalizedPhone;
}
Phone.prototype.tag = function (str) {
    if (str !== undefined)
        this._tag = str;
    return this._tag;
};
Phone.prototype.phone = function (str) {
    if (str !== undefined)
        this._phone = str;
    return this._phone;
};
Phone.prototype.normalizedPhone = function (str) {
    if (str !== undefined)
        this._normalizedPhone = str;
    return this._normalizedPhone;
};

/**
 * Contact Address information
 * @typedef {Object} Contact.Address
 * @property {String} tag - The context tag associated with this address,
 * @property {?String} address - The contact's street address,
 * @property {?String} neighborhood - The contact's street neighborhood,
 * @property {?String} city - The contact's city,
 * @property {?String} region - The contact's region. An example of this would be a state in the US, or a province in Canada,
 * @property {?String} country - The contact's country,
 * @property {?Number} postalCode - The contact's postal code
 */
function Address(obj){
    this._tag = obj && obj.tag;
    this._address = obj && obj.address;
    this._neighborhood = obj && obj.neighborhood;
    this._region = obj && obj.region;
    this._country = obj && obj.country;
    this._postalCode = obj && obj.postalCode;
}

Address.prototype.tag = function (str) {
    if (str !== undefined)
        this._tag = str;
    return this._tag;
};
Address.prototype.address = function (str) {
    if (str !== undefined)
        this._address = str;
    return this._address;
};
Address.prototype.neighborhood = function (str) {
    if (str !== undefined)
        this._neighborhood = str;
    return this._neighborhood;
};
Address.prototype.city = function (str) {
    if (str !== undefined)
        this._city = str;
    return this._city;
};
Address.prototype.region = function (str) {
    if (str !== undefined)
        this._region = str;
    return this._region;
};
Address.prototype.country = function (str) {
    if (str !== undefined)
        this._country = str;
    return this._country;
};
Address.prototype.postalCode = function (code) {
    if (code !== undefined)
        this._postalCode = code;
    return this._postalCode;
};

/**
 * Contact Url information
 * @typedef {Object} Contact.Url
 * @property {string} tag - The context tag associated with this url
 * @property {string} url - A url associated with this contact
 */
function Url(obj){
    this._tag = obj && obj.tag;
    this._url = obj && obj.url;
}

Url.prototype.tag = function (str) {
    if (str !== undefined)
        this._tag = str;
    return this._tag;
};
Url.prototype.url = function (str) {
    if (str !== undefined)
        this._url = str;
    return this._url;
};

/**
 * Contact Important Date information
 * @typedef {Object} Contact.ImportantDate
 * @property {string} tag - The context tag associated with this date
 * @property {dateTime} date - An important date for this contact, as an ISO 8601 timestamp
 */
function ImportantDate(obj){
    this._tag = obj && obj.tag;
    this._date = obj && obj.date;
}

ImportantDate.prototype.tag = function (str) {
    if (str !== undefined)
        this._tag = str;
    return this._tag;
};
ImportantDate.prototype.date = function (str) {
    if (str !== undefined)
        this._date = str;
    return this._date;
};

/**
 * CustomField
 * @typedef {Object} Contact.CustomField
 * @property {string} field - The name of the custom field
 * @property {string} value - The value of the custom field
 */
function CustomField(obj){
    this._field = obj && obj.field;
    this._value = obj && obj.value;
}

CustomField.prototype.field = function (str) {
    if (str !== undefined)
        this._field = str;
    return this._field;
};
CustomField.prototype.value = function (str) {
    if (str !== undefined)
        this._value = str;
    return this._value;
};

/**
 * Contact Note information
 * @typedef {Object} Contact.Note
 * @property {string} tag - a context tag
 * @property {string} note - The note to add
 */
function Note(obj){
    this._tag = obj && obj.tag;
    this._note = obj && obj.note;
}
Note.prototype.tag = function (str) {
    if (str !== undefined)
        this._tag = str;
    return this._tag;
};
Note.prototype.note = function (str) {
    if (str !== undefined)
        this._note = str;
    return this._note;
};

/**
 * Contact ID information
 * @typedef {Object} Contact.ID
 * @property {boolean} exists - true if this id exists
 * @property {string} id - The id of this Contact
 */
function Id(obj){
    this._id = obj && obj.id;
    this._exists = obj && obj.exists;
}
Id.prototype.exists = function () {
    return this._exists;
};
Id.prototype.id = function () {
    return this._id;
};

/**
 * @class
 * @constructor
 * @alias Contact
 */
module.exports = function Contact() {

    var name = new Name();
    this.name = function (obj) {
        if (obj !== undefined && obj != null)
            name = new Name(obj);
        return name;
    };

    var company = new Company();
    this.company = function (obj) {
        if (obj !== undefined && obj != null)
            company = new Company(obj);
        return company;
    };

    var picture = null;
    this.picture = function (url) {
        if (url !== undefined && url != null)
            picture = url;
        return picture;
    };

    var emails = [];
    this.emails = function () {
        return emails;
    };
    this.addEmail = function (email) {
        emails.push(email);
    };

    var phones = [];
    this.phones = function () {
        return phones;
    };
    this.addPhone = function (phone) {
        phones.push(phone);
    };

    var addresses = [];
    this.addresses = function () {
        return addresses;
    };
    this.addAddress = function (address) {
        addresses.push(address);
    };

    var labels = [];
    this.labels = function () {
        return labels;
    };
    this.addLabel = function (label) {
        labels.push(label);
    };

    var urls = [];
    this.urls = function () {
        return urls;
    };
    this.addUrl = function (url) {
        urls.push(url);
    };

    var dates = [];
    this.dates = function () {
        return dates;
    };
    this.addDate = function (date) {
        dates.push(date);
    };

    var customFields = [];
    this.customFields = function () {
        return customFields;
    };
    this.addCustomField = function (field) {
        customFields.push(field);
    };

    var notes = [];
    this.notes = function () {
        return notes;
    };
    this.addNote = function (note) {
        notes.push(note);
    };

    var id = new Id();

    var modifiedAt = Date.now;
    this.modifiedAt = function () {
        return modifiedAt;
    };

    var createdAt = Date.now;
    this.createdAt = function () {
        return createdAt;
    };

    /**
     * Contact Save information
     * @typedef {Object} Contact.SaveData
     * @property {Contact.ID} contactId - The id of this Contact
     * @property {Contact} contact - The Contact object
     * @property {?string} activityId - The optional id of an {@link Activity} if one was added to this {@link Contact}
     */
};

/**
 * A callback that returns if the save operation completed successfully
 *
 * @callback Contact.SaveCompletedCallback
 * @param {Contact.SaveData} data - the save information about this operation
 */

/**
 * A callback that returns if the save operation failed
 *
 * @callback Contact.SaveFailedCallback
 * @param {number} errorCode - the error code for this failure
 * @param {string} errorMessage - the error message for this failure
 */

/**
 *
 * @param {Contact.SaveCompletedCallback} onSuccess A callback to indicate the operation was successful, with the updated Contact
 * @param {Contact.SaveFailedCallback} onFailure A callback to indicate the operation failed
 */
//Contact.prototype.save = function(onSuccess, onFailure) {};

/**
 * Adds an Activity to this {@link Contact}. Note, the {@link Contact} must be saved for the {@link Activity} to be persisted
 * @param activity {Activity} The Activity to post
 */
//Contact.prototype.addActivity = function(activity) {};

/**
 * A callback that returns if the get operation completed successfully
 *
 * @callback Contact.GetActivitiesCallback
 * @param {Contact} data - the retrieved {@link Contact}
 */

/**
 * A callback that returns if the get operation failed
 *
 * @callback Contact.GetActivitiesFailureCallback
 * @param {number} errorCode - the error code for this failure
 * @param {string} errorMessage - the error message for this failure
 */

/**
 * Get Activities Query Options
 * @typedef {Object} GetActivitiesOptions
 * @property {?Number} pageSize - The number of results to return per page of data. Valid options are: 25, 50 and 100. Defaults to 25
 * @property {?string} activityTypes - The activity types to filter against. Multiple activity types are separated by a comma
 * @property {?dateTime} until - The ending date for activities we want to return, as an ISO 8601 timestamp This field is only relevant when a cursor is not present
 * @property {?dateTime} from - The beginning date for activities we want to return, as an ISO 8601 timestamp. This field is only relevant when a cursor is not present
 * @property {?string} scope - The scope of the results to return, either for the entire site or limited to the current application. Can either be site or app. By default, all activities for the site will be returned
 */

/**
 * Returns a list of {@link Activity} for this contact, based on the filter. By default, all Activities are returned
 * @param options {GetActivitiesOptions} The Activity to post
 * @param onSuccess {Contact.GetActivitiesCallback} a callback function that receives a WixDataCursor object
 * @param onFailure {Contact.GetActivitiesFailureCallback} failure callback
 */
//Contact.prototype.getActivities = function(options, onSuccess, onFailure) {};

<|endoftext|>


<commit_before>import Ember from 'ember';
import TransitionDurationMixin from 'ember-cli-paint/mixins/transition-duration';

export default Ember.Component.extend(TransitionDurationMixin, {
  classNameBindings: [':sidebar', 'isCollapsed:collapsed'],

  applicationName: null,
  currentUser: null,
  navigationItems: [],
  isCollapsed: false,
  actionsTarget: null,
  scrollable: null,

  actionItems: [{
    name: 'logout',
    label: 'Logout'
  }],

  _recalculateScrollable: Ember.observer('isCollapsed', function() {
    var scrollable = this.get('scrollable');
    var calculationId;

    function repeatCalculation() {
      scrollable.send('recalculate');
      calculationId = requestAnimationFrame(repeatCalculation);
    }

    if (scrollable != null) {
      requestAnimationFrame(repeatCalculation);

      Ember.run.later(function() {
        cancelAnimationFrame(calculationId);
      }, this.get('transitionDuration'));
    }
  }),

  actions: {
    toggleCollapse: function() {
      this.toggleProperty('isCollapsed');
      this.sendAction('toggleCollapse');
    }
  }
});
<commit_msg>Immediately invoke the function<commit_after>import Ember from 'ember';
import TransitionDurationMixin from 'ember-cli-paint/mixins/transition-duration';

export default Ember.Component.extend(TransitionDurationMixin, {
  classNameBindings: [':sidebar', 'isCollapsed:collapsed'],

  applicationName: null,
  currentUser: null,
  navigationItems: [],
  isCollapsed: false,
  actionsTarget: null,
  scrollable: null,

  actionItems: [{
    name: 'logout',
    label: 'Logout'
  }],

  _recalculateScrollable: Ember.observer('isCollapsed', function() {
    var scrollable = this.get('scrollable');
    var calculationId;

    if (scrollable != null) {
      (function repeatCalculation() {
        scrollable.send('recalculate');
        calculationId = requestAnimationFrame(repeatCalculation);
      })();

      Ember.run.later(function() {
        cancelAnimationFrame(calculationId);
      }, this.get('transitionDuration'));
    }
  }),

  actions: {
    toggleCollapse: function() {
      this.toggleProperty('isCollapsed');
      this.sendAction('toggleCollapse');
    }
  }
});
<|endoftext|>


<commit_before>// modal pattern.
//
// Author: Rok Garbas
// Contact: rok@garbas.si
// Version: 1.0
// Depends: jquery.js patterns.js pickadate.js
//
// Description:
//
// License:
//
// Copyright (C) 2010 Plone Foundation
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 51
// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//

/*jshint bitwise:true, curly:true, eqeqeq:true, immed:true, latedef:true,
  newcap:true, noarg:true, noempty:true, nonew:true, plusplus:true,
  undef:true, strict:true, trailing:true, browser:true, evil:true */
/*global define:false */
define([
  'jquery',
  'js/patterns/base',
  'js/patterns/backdrop',
  'jam/Patterns/src/registry'
], function($, Base, Backdrop, registry, undefined) {
  "use strict";

  var Modal = Base.extend({
    name: "modal",
    jqueryPlugin: "modal",
    defaults: {
      triggers: '',
      position: "center middle",
      width: "",
      height: "",
      margin: "20px",
      klass: "modal",
      klassWrapper: "modal-wrapper",
      klassWrapperInner: "modal-wrapper-inner",
      klassLoading: "modal-loading",
      klassActive: "active",
      backdrop: "body",
      backdropZIndex: "1000",
      backdropOpacity: "0.8",
      backdropKlass: "backdrop",
      backdropKlassActive: "backdrop-active",
      backdropCloseOnEsc: true,
      backdropCloseOnClick: true
    },
    init: function() {
      var self = this;

      self.backdrop = new Backdrop(self.$el.parents(self.options.backdrop), {
        zindex: self.options.backdropZIndex,
        klass: self.options.backdropKlass,
        klassActive: self.options.backdropKlassActive,
        styles: self.options.backdropStyles,
        opacity: self.options.backdropOpacity,
        closeOnEsc: self.options.backdropCloseOnEsc,
        closeOnClick: self.options.backdropCloseOnClick
      });
      self.backdrop.on('hidden', function(e) {
        self.hide();
      });

      self.$wrapper = $('> .' + self.options.klassWrapper, self.backdrop.$el);
      if (self.$wrapper.size() === 0) {
        self.$wrapper = $('
')
          .hide()
          .css({
            'z-index': self.options.backdropZIndex + 1,
            'overflow-y': 'auto',
            'position': 'fixed',
            'height': '100%',
            'width': '100%',
            'bottom': '0',
            'left': '0',
            'right': '0',
            'top': '0'
          })
          .addClass(self.options.klassWrapper)
          .insertBefore(self.backdrop.$backdrop)
          .on('click', function(e) {
            e.stopPropagation();
            e.preventDefault();
            self.backdrop.hide();
          });
      }

      self.$wrapperInner = $('> .' + self.options.klassWrapperInner, self.$wrapper);
      if (self.$wrapperInner.size() === 0) {
        self.$wrapperInner = $('
')
          .addClass(self.options.klassWrapperInner)
          .css({
            'position': 'absolute',
            'bottom': '0',
            'left': '0',
            'right': '0',
            'top': '0'
          })
          .appendTo(self.$wrapper);
      }

      self.$loading = $('> .' + self.options.klassLoading, self.$wrapperInner);
      if (self.$loading.size() === 0) {
        self.$loading = $('
').hide()
          .addClass(self.options.klassLoading)
          .appendTo(self.$wrapperInner);
      }
      $(window.parent).resize(function() {
        self.positionModal();
      });

      if (self.options.triggers) {
        $.each(self.options.triggers, function(i, item) {
          item = item.split(' ');
          $(item[1] || self.$el).on(item[0], function() {
            self.show();
          });
        });
      }

      if (self.$el.is('a')) {
        if (self.$el.attr('href')) {
          if (!self.options.target && self.$el.attr('href').substr(0, 1) === '#') {
            self.options.target = self.$el.attr('href');
          }
          if (!self.options.ajaxUrl && self.$el.attr('href').substr(0, 1) !== '#') {
            self.options.ajaxUrl = self.$el.attr('href');
          }
        }
        self.$el.on('click', function(e) {
          e.stopPropagation();
          e.preventDefault();
          self.show();
        });
      }

      self.initModal();
      self.$wrapper.on('hidden', function(e) {
        e.stopPropagation();
        e.preventDefault();
        self.hide();
      });
    },
    initModalElement: function($modal) {
      var self = this;
      $modal
        .addClass(self.options.klass)
        .on('click', function(e) {
          e.stopPropagation();
          if ($.nodeName(e.target, 'a')) {
            e.preventDefault();
            // TODO: open links inside modal
          }
        })
        .on('destroy.modal.patterns', function(e) {
          e.stopPropagation();
          self.hide();
        })
        .on('resize.modal.patterns', function(e) {
          e.stopPropagation();
          e.preventDefault();
          self.positionModal(true);
        });
      return $modal;
    },
    initModal: function() {
      var self = this;
      if (self.options.ajaxUrl) {
        self.$modal = function() {
          self.trigger('before-ajax');
          self.$wrapper.parent().css('overflow', 'hidden');
          self.$wrapper.show();
          self.backdrop.show();
          self.$loading.show();
          self.positionLoading();
          self.ajaxXHR = $.ajax({
              url: self.options.ajaxUrl,
              type: self.options.ajaxType
          }).done(function(response, textStatus, xhr) {
            self.ajaxXHR = undefined;
            self.$loading.hide();
            self.$modal = self.initModalElement(
              $($((/]*>((.|[\n\r])*)<\/body>/im).exec(response)[0]
                .replace('<body', '<div').replace('', '
'))[0]))
              .appendTo(self.$wrapperInner);
            self.trigger('after-ajax', self, textStatus, xhr);
            self.show();
          });
        };
      } else if (self.options.target) {
        self.$modal = function() {
          self.$modal = self.initModalElement($('
'))
              .html($(self.options.target).clone())
              .appendTo(self.$wrapperInner);
          self.show();
        };
      } else {
        self.$modal = self.initModalElement($('
'))
              .html(self.$el.clone())
              .appendTo(self.$wrapperInner);
      }

    },
    positionLoading: function() {
      var self = this;
      self.$loading.css({
        'margin-left': self.$wrapper.width()/2 - self.$loading.width()/2,
        'margin-top': self.$wrapper.height()/2 - self.$loading.height()/2,
        'position': 'absolute',
        'bottom': '0',
        'left': '0',
        'right': '0',
        'top': '0'
      });
    },
    positionModal: function(preserve_top) {
      var self = this;
      if (typeof self.$modal !== 'function') {

        if (preserve_top) {
          preserve_top = self.$modal.css('top');
        }

        self.$modal.removeAttr('style');
        // if backdrop wrapper is set on body then wrapper should have height
        // of window so we can do scrolling of inner wrapper
        self.$wrapperInner.css({
          'height': '',
          'width': self.options.width
        });
        if (self.$wrapper.parent().is('body')) {
          self.$wrapper.height($(window.parent).height());
        }

        // place modal at top left with desired width/height and margin
        self.$modal.css({
          'padding': '0',
          'margin': '0',
          'width': '',
          'height': self.options.height,
          'position': 'absolute',
          'top': preserve_top ? preserve_top : '0',
          'left': '0'
        });

        self.$modal.css({'margin': '0'});
        var modalOffsetBefore = self.$modal.offset();
        self.$modal.css({ 'margin': self.options.margin });
        var modalOffset = self.$modal.offset(),
            modalOuterWidth = self.$modal.outerWidth(true),
            modalInnerWidth = self.$modal.innerWidth(),
            modalOuterHeight = self.$modal.outerHeight(true),
            modalInnerHeight = self.$modal.innerHeight();
        self.$modal.css({ 'margin': '0' });

        var topMargin = modalOffset.top - modalOffsetBefore.top,
            bottomMargin = modalOuterHeight - modalInnerHeight - topMargin,
            leftMargin = modalOffset.left - modalOffsetBefore.left,
            rightMargin = modalOuterWidth - modalInnerWidth - leftMargin;

        // place modal in right position
        var positionHorizontal = self.options.position.split(' ')[0],
            positionVertical = self.options.position.split(' ')[1],
            positionTop, positionBottom, positionLeft, positionRight;

        if (positionHorizontal === 'left') {
          positionLeft = leftMargin + 'px';
          if (self.$wrapperInner.width() < self.$modal.width()) {
            positionRight = rightMargin + 'px';
          } else {
            positionRight = 'auto';
          }
        } else if (positionHorizontal === 'bottom') {
          positionRight = leftMargin + 'px';
          if (self.$wrapperInner.width() < self.$modal.width()) {
            positionLeft = leftMargin + 'px';
          } else {
            positionLeft = 'auto';
          }
        } else {
          if (self.$wrapperInner.width() < self.$modal.width() + leftMargin + rightMargin) {
            positionLeft = leftMargin + 'px';
            positionRight = rightMargin + 'px';
          } else {
            positionLeft = positionRight = (self.$wrapperInner.innerWidth()/2 -
                self.$modal.width()/2 - leftMargin - rightMargin) + 'px';
          }
        }
        self.$modal.css({
          'left': positionLeft,
          'right': positionRight
        });

        // if modal is bigger then wrapperInner then resize wrapperInner to
        // mach modal height
        if (self.$wrapperInner.height() < self.$modal.height()) {
          self.$wrapperInner.height(self.$modal.height() + topMargin + bottomMargin);
        }

        if (preserve_top || positionVertical === 'top') {
          positionTop = topMargin + 'px';
          if (self.$wrapperInner.height() < self.$modal.height()) {
            positionBottom = bottomMargin + 'px';
          } else {
            positionBottom = 'auto';
          }
        } else if (positionVertical === 'bottom') {
          positionBottom = bottomMargin + 'px';
          if (self.$wrapperInner.height() < self.$modal.height()) {
            positionTop = topMargin + 'px';
          } else {
            positionTop= 'auto';
          }
        } else {
          if (self.$wrapperInner.height() < self.$modal.height()) {
            positionTop = topMargin + 'px';
            positionBottom = bottomMargin + 'px';
          } else {
            positionTop = positionBottom = (self.$wrapperInner.height()/2 -
                self.$modal.height()/2) + 'px';
          }
        }
        self.$modal.css({
          'top': positionTop,
          'bottom': positionBottom
        });

      }
    },
    show: function() {
      var self = this;
      if (!self.$el.hasClass(self.options.klassActive)) {
        if (typeof self.$modal === 'function') {
          self._$modal = self.$modal;
          self.$modal();
        } else {
          self.trigger('show');
          self.backdrop.show();
          self.$wrapper.show();
          self.$wrapper.parent().css('overflow', 'hidden');
          self.$el.addClass(self.options.klassActive);
          self.$modal.addClass(self.options.klassActive);
          registry.scan(self.$modal);
          self.positionModal();
          $(window.parent).on('resize.modal.patterns', function() {
            self.positionModal();
          });
          self.trigger('shown');
        }
      }
    },
    hide: function() {
      var self = this;
      if (self.ajaxXHR) {
        self.ajaxXHR.abort();
      }
      if (self.$el.hasClass(self.options.klassActive)) {
        self.trigger('hide');
        self.backdrop.hide();
        self.$wrapper.hide();
        self.$wrapper.parent().css('overflow', 'visible');
        self.$el.removeClass(self.options.klassActive);
        if (self.$modal.remove) {
          self.$modal.remove();
          self.initModal();
        }
        $(window.parent).off('resize.modal.patterns');
        self.trigger('hidden');
      }
    }
  });

  return Modal;

});
<commit_msg>index was 10001 instead of 1000<commit_after>// modal pattern.
//
// Author: Rok Garbas
// Contact: rok@garbas.si
// Version: 1.0
// Depends: jquery.js patterns.js pickadate.js
//
// Description:
//
// License:
//
// Copyright (C) 2010 Plone Foundation
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 51
// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//

/*jshint bitwise:true, curly:true, eqeqeq:true, immed:true, latedef:true,
  newcap:true, noarg:true, noempty:true, nonew:true, plusplus:true,
  undef:true, strict:true, trailing:true, browser:true, evil:true */
/*global define:false */
define([
  'jquery',
  'js/patterns/base',
  'js/patterns/backdrop',
  'jam/Patterns/src/registry'
], function($, Base, Backdrop, registry, undefined) {
  "use strict";

  var Modal = Base.extend({
    name: "modal",
    jqueryPlugin: "modal",
    defaults: {
      triggers: '',
      position: "center middle",
      width: "",
      height: "",
      margin: "20px",
      klass: "modal",
      klassWrapper: "modal-wrapper",
      klassWrapperInner: "modal-wrapper-inner",
      klassLoading: "modal-loading",
      klassActive: "active",
      backdrop: "body",
      backdropZIndex: "1000",
      backdropOpacity: "0.8",
      backdropKlass: "backdrop",
      backdropKlassActive: "backdrop-active",
      backdropCloseOnEsc: true,
      backdropCloseOnClick: true
    },
    init: function() {
      var self = this;

      self.backdrop = new Backdrop(self.$el.parents(self.options.backdrop), {
        zindex: self.options.backdropZIndex,
        klass: self.options.backdropKlass,
        klassActive: self.options.backdropKlassActive,
        styles: self.options.backdropStyles,
        opacity: self.options.backdropOpacity,
        closeOnEsc: self.options.backdropCloseOnEsc,
        closeOnClick: self.options.backdropCloseOnClick
      });
      self.backdrop.on('hidden', function(e) {
        self.hide();
      });

      self.$wrapper = $('> .' + self.options.klassWrapper, self.backdrop.$el);
      if (self.$wrapper.size() === 0) {
        self.$wrapper = $('
')
          .hide()
          .css({
            'z-index': parseInt(self.options.backdropZIndex, 10) + 1,
            'overflow-y': 'auto',
            'position': 'fixed',
            'height': '100%',
            'width': '100%',
            'bottom': '0',
            'left': '0',
            'right': '0',
            'top': '0'
          })
          .addClass(self.options.klassWrapper)
          .insertBefore(self.backdrop.$backdrop)
          .on('click', function(e) {
            e.stopPropagation();
            e.preventDefault();
            self.backdrop.hide();
          });
      }

      self.$wrapperInner = $('> .' + self.options.klassWrapperInner, self.$wrapper);
      if (self.$wrapperInner.size() === 0) {
        self.$wrapperInner = $('
')
          .addClass(self.options.klassWrapperInner)
          .css({
            'position': 'absolute',
            'bottom': '0',
            'left': '0',
            'right': '0',
            'top': '0'
          })
          .appendTo(self.$wrapper);
      }

      self.$loading = $('> .' + self.options.klassLoading, self.$wrapperInner);
      if (self.$loading.size() === 0) {
        self.$loading = $('
').hide()
          .addClass(self.options.klassLoading)
          .appendTo(self.$wrapperInner);
      }
      $(window.parent).resize(function() {
        self.positionModal();
      });

      if (self.options.triggers) {
        $.each(self.options.triggers, function(i, item) {
          item = item.split(' ');
          $(item[1] || self.$el).on(item[0], function() {
            self.show();
          });
        });
      }

      if (self.$el.is('a')) {
        if (self.$el.attr('href')) {
          if (!self.options.target && self.$el.attr('href').substr(0, 1) === '#') {
            self.options.target = self.$el.attr('href');
          }
          if (!self.options.ajaxUrl && self.$el.attr('href').substr(0, 1) !== '#') {
            self.options.ajaxUrl = self.$el.attr('href');
          }
        }
        self.$el.on('click', function(e) {
          e.stopPropagation();
          e.preventDefault();
          self.show();
        });
      }

      self.initModal();
      self.$wrapper.on('hidden', function(e) {
        e.stopPropagation();
        e.preventDefault();
        self.hide();
      });
    },
    initModalElement: function($modal) {
      var self = this;
      $modal
        .addClass(self.options.klass)
        .on('click', function(e) {
          e.stopPropagation();
          if ($.nodeName(e.target, 'a')) {
            e.preventDefault();
            // TODO: open links inside modal
          }
        })
        .on('destroy.modal.patterns', function(e) {
          e.stopPropagation();
          self.hide();
        })
        .on('resize.modal.patterns', function(e) {
          e.stopPropagation();
          e.preventDefault();
          self.positionModal(true);
        });
      return $modal;
    },
    initModal: function() {
      var self = this;
      if (self.options.ajaxUrl) {
        self.$modal = function() {
          self.trigger('before-ajax');
          self.$wrapper.parent().css('overflow', 'hidden');
          self.$wrapper.show();
          self.backdrop.show();
          self.$loading.show();
          self.positionLoading();
          self.ajaxXHR = $.ajax({
              url: self.options.ajaxUrl,
              type: self.options.ajaxType
          }).done(function(response, textStatus, xhr) {
            self.ajaxXHR = undefined;
            self.$loading.hide();
            self.$modal = self.initModalElement(
              $($((/]*>((.|[\n\r])*)<\/body>/im).exec(response)[0]
                .replace('<body', '<div').replace('', '
'))[0]))
              .appendTo(self.$wrapperInner);
            self.trigger('after-ajax', self, textStatus, xhr);
            self.show();
          });
        };
      } else if (self.options.target) {
        self.$modal = function() {
          self.$modal = self.initModalElement($('
'))
              .html($(self.options.target).clone())
              .appendTo(self.$wrapperInner);
          self.show();
        };
      } else {
        self.$modal = self.initModalElement($('
'))
              .html(self.$el.clone())
              .appendTo(self.$wrapperInner);
      }

    },
    positionLoading: function() {
      var self = this;
      self.$loading.css({
        'margin-left': self.$wrapper.width()/2 - self.$loading.width()/2,
        'margin-top': self.$wrapper.height()/2 - self.$loading.height()/2,
        'position': 'absolute',
        'bottom': '0',
        'left': '0',
        'right': '0',
        'top': '0'
      });
    },
    positionModal: function(preserve_top) {
      var self = this;
      if (typeof self.$modal !== 'function') {

        if (preserve_top) {
          preserve_top = self.$modal.css('top');
        }

        self.$modal.removeAttr('style');
        // if backdrop wrapper is set on body then wrapper should have height
        // of window so we can do scrolling of inner wrapper
        self.$wrapperInner.css({
          'height': '',
          'width': self.options.width
        });
        if (self.$wrapper.parent().is('body')) {
          self.$wrapper.height($(window.parent).height());
        }

        // place modal at top left with desired width/height and margin
        self.$modal.css({
          'padding': '0',
          'margin': '0',
          'width': '',
          'height': self.options.height,
          'position': 'absolute',
          'top': preserve_top ? preserve_top : '0',
          'left': '0'
        });

        self.$modal.css({'margin': '0'});
        var modalOffsetBefore = self.$modal.offset();
        self.$modal.css({ 'margin': self.options.margin });
        var modalOffset = self.$modal.offset(),
            modalOuterWidth = self.$modal.outerWidth(true),
            modalInnerWidth = self.$modal.innerWidth(),
            modalOuterHeight = self.$modal.outerHeight(true),
            modalInnerHeight = self.$modal.innerHeight();
        self.$modal.css({ 'margin': '0' });

        var topMargin = modalOffset.top - modalOffsetBefore.top,
            bottomMargin = modalOuterHeight - modalInnerHeight - topMargin,
            leftMargin = modalOffset.left - modalOffsetBefore.left,
            rightMargin = modalOuterWidth - modalInnerWidth - leftMargin;

        // place modal in right position
        var positionHorizontal = self.options.position.split(' ')[0],
            positionVertical = self.options.position.split(' ')[1],
            positionTop, positionBottom, positionLeft, positionRight;

        if (positionHorizontal === 'left') {
          positionLeft = leftMargin + 'px';
          if (self.$wrapperInner.width() < self.$modal.width()) {
            positionRight = rightMargin + 'px';
          } else {
            positionRight = 'auto';
          }
        } else if (positionHorizontal === 'bottom') {
          positionRight = leftMargin + 'px';
          if (self.$wrapperInner.width() < self.$modal.width()) {
            positionLeft = leftMargin + 'px';
          } else {
            positionLeft = 'auto';
          }
        } else {
          if (self.$wrapperInner.width() < self.$modal.width() + leftMargin + rightMargin) {
            positionLeft = leftMargin + 'px';
            positionRight = rightMargin + 'px';
          } else {
            positionLeft = positionRight = (self.$wrapperInner.innerWidth()/2 -
                self.$modal.width()/2 - leftMargin - rightMargin) + 'px';
          }
        }
        self.$modal.css({
          'left': positionLeft,
          'right': positionRight
        });

        // if modal is bigger then wrapperInner then resize wrapperInner to
        // mach modal height
        if (self.$wrapperInner.height() < self.$modal.height()) {
          self.$wrapperInner.height(self.$modal.height() + topMargin + bottomMargin);
        }

        if (preserve_top || positionVertical === 'top') {
          positionTop = topMargin + 'px';
          if (self.$wrapperInner.height() < self.$modal.height()) {
            positionBottom = bottomMargin + 'px';
          } else {
            positionBottom = 'auto';
          }
        } else if (positionVertical === 'bottom') {
          positionBottom = bottomMargin + 'px';
          if (self.$wrapperInner.height() < self.$modal.height()) {
            positionTop = topMargin + 'px';
          } else {
            positionTop= 'auto';
          }
        } else {
          if (self.$wrapperInner.height() < self.$modal.height()) {
            positionTop = topMargin + 'px';
            positionBottom = bottomMargin + 'px';
          } else {
            positionTop = positionBottom = (self.$wrapperInner.height()/2 -
                self.$modal.height()/2) + 'px';
          }
        }
        self.$modal.css({
          'top': positionTop,
          'bottom': positionBottom
        });

      }
    },
    show: function() {
      var self = this;
      if (!self.$el.hasClass(self.options.klassActive)) {
        if (typeof self.$modal === 'function') {
          self._$modal = self.$modal;
          self.$modal();
        } else {
          self.trigger('show');
          self.backdrop.show();
          self.$wrapper.show();
          self.$wrapper.parent().css('overflow', 'hidden');
          self.$el.addClass(self.options.klassActive);
          self.$modal.addClass(self.options.klassActive);
          registry.scan(self.$modal);
          self.positionModal();
          $(window.parent).on('resize.modal.patterns', function() {
            self.positionModal();
          });
          self.trigger('shown');
        }
      }
    },
    hide: function() {
      var self = this;
      if (self.ajaxXHR) {
        self.ajaxXHR.abort();
      }
      if (self.$el.hasClass(self.options.klassActive)) {
        self.trigger('hide');
        self.backdrop.hide();
        self.$wrapper.hide();
        self.$wrapper.parent().css('overflow', 'visible');
        self.$el.removeClass(self.options.klassActive);
        if (self.$modal.remove) {
          self.$modal.remove();
          self.initModal();
        }
        $(window.parent).off('resize.modal.patterns');
        self.trigger('hidden');
      }
    }
  });

  return Modal;

});
<|endoftext|>


<commit_before>/*
 * (C) Copyright 2013 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 */

var EventEmitter = require("events").EventEmitter;

var XMLHttpRequest = require("xmlhttprequest");
var RpcBuilder     = require("kws-rpc-builder");

const MAX_FRAMERATE = 15;

/**
 * @constructor
 * @abstract
 *
 * @param {String} url: URL of the WebRTC endpoint server.
 * @param {Object} options: optional configuration parameters
 *   {Enum('inactive', 'sendonly', 'recvonly', 'sendrecv')} audio: audio stream mode
 *   {Enum('inactive', 'sendonly', 'recvonly', 'sendrecv')} video: video stream mode
 *   {[Object]} iceServers: array of objects to initialize the ICE servers. It
 *     structure is the same as an Array of WebRTC RTCIceServer objects.
 *
 * @throws RangeError
 */
function Content(url, options)
{
  EventEmitter.call(this);

  var self = this;

  const ERROR_NO_REMOTE_VIDEO_TAG = -1;

  /**
   * Decode the mode of the streams
   *
   * @private
   *
   * @param {Object} options: constraints to update and decode
   * @param {String} type: name of the constraints to decode
   *
   * @returns {Object}
   *
   * @throws RangeError
   */
  function decodeMode(options, type)
  {
    var result = {};

    // If not defined, set send & receive by default
    options[type] = options[type] || 'sendrecv';

    switch(options[type])
    {
      case 'sendrecv':
        result.local  = true;
        result.remote = true;
      break;

      case 'sendonly':
        result.local  = true;
        result.remote = false;
      break;

      case 'recvonly':
        result.local  = false;
        result.remote = true;
      break;

      case 'inactive':
        result.local  = false;
        result.remote = false;
      break;

      default:
        throw new RangeError("Invalid "+type+" media mode");
    }

    return result;
  }

  // We can't disable both audio and video on a stream, raise error
  if(options.audio == 'inactive' && options.video == 'inactive')
    throw new RangeError("At least one audio or video must to be enabled");

  // Audio media
  this._audio = decodeMode(options, "audio");

  // Video media
  this._video = decodeMode(options, "video");

  if(this._video.local)
      this._video.local =
      {
        mandatory:
        {
//          minHeight   : options.minHeight    || MIN_HEIGHT,
//          maxHeight   : options.maxHeight    || MAX_HEIGHT,
//          minWidth    : options.minWidth     || MIN_WIDTH,
//          maxWidth    : options.maxWidth     || MAX_WIDTH,
//          minFrameRate: options.minFrameRate || MIN_FRAMERATE,
          maxFrameRate: options.maxFrameRate || MAX_FRAMERATE
        }
      };

  // Init the KwsWebRtcContent object

  var _sessionId = null;
  var pollingTimeout = null;
  var polling = false;
  var terminatedByServer = false;

  this.__defineGetter__('sessionId', function()
  {
    return _sessionId;
  });

  function setSessionId(sessionId)
  {
    if(sessionId == undefined)
      throw new TypeError('sessionId is undefined');

    if(_sessionId == undefined)
      _sessionId = sessionId;

    else if(sessionId != _sessionId)
      throw new TypeError('sessionId is not equal to already defined one');
  }

  var rpc = new RpcBuilder();

  function doRPC(method, params, callback)
  {
    var xhr = new XMLHttpRequest();

    // Set XmlHttpRequest error callback
    xhr.addEventListener('error', function(error)
    {
      self.emit('error', error);
    });

    // Connect to Content Server
    xhr.open('POST', url);

    // Send request
    xhr.send(rpc.encodeJSON(method, params, callback));

    // Register callback for the Application Server
    xhr.addEventListener('load', function()
    {
      rpc.decodeJSON(this.responseText);
    });
  };

  function close()
  {
//    xhr.abort();

    _sessionId = null;
  };

  self.on('error',     close);
  self.on('terminate', close);

  // Error dispatcher functions

  var MAX_ALLOWED_ERROR_TRIES = 10;

  var error_tries = 0;

  // RPC calls

  // Start

  this.start = function(params, success)
  {
    if(this.sessionId)
      params.sessionId = this.sessionId;

    doRPC('start', params, function(error, result)
    {
      error = error || result.rejected;

      if(error) return self.emit('error', error);

      setSessionId(result.sessionId);

      success(result);
    });
  };

  // Pool

  /**
   * Pool for events dispatched on the server pipeline
   *
   * @private
   */
  function pollMediaEvents()
  {
    if(!self.sessionId)
      return;

    if(polling)
      return;
    polling = true;

    var params =
    {
      sessionId: self.sessionId
    };

    function success(result)
    {
      error_tries = 0;

      // Content events
      if(result.contentEvents)
        for(var i=0, data; data=result.contentEvents[i]; i++)
          self.emit('mediaevent', data);

      // Control events
      if(result.controlEvents)
        for(var i=0, data; data=result.controlEvents[i]; i++)
        {
          var type = data.type;

          switch(type)
          {
            case "sessionTerminated":
              terminatedByServer = true;
              self.emit('terminate', Content.REASON_SERVER_ENDED_SESSION);
            break;

            case "sessionError":
              self.emit('error', data.data);
            break;

            default:
              console.warn("Unknown control event type: "+type);
          }
        };

      // Check if we should keep polling events
      if(pollingTimeout != 'stopped')
         pollingTimeout = setTimeout(pollMediaEvents, 0);
    };

    function failure(error)
    {
      // A poll error has occurred, retry it
      if(error_tries < MAX_ALLOWED_ERROR_TRIES)
      {
        if(pollingTimeout != 'stopped')
           pollingTimeout = setTimeout(pollMediaEvents, Math.pow(2, error_tries));

        error_tries++;
      }

      // Max number of poll errors achieved, raise error
      else
        terminateConnection('error', error);
    };

    doRPC('poll', params, function(error, result)
    {
      if(error) return failure(error);

      success(result);
    });
  };

  this.on('start', pollMediaEvents);

  /**
   * Terminate the connection with the WebRTC media server
   */
  function terminateConnection(action, reason)
  {
    // Stop polling
    clearTimeout(pollingTimeout);
    pollingTimeout = 'stopped';
    polling = false;

    if(terminatedByServer)
      return;

    // Notify to the WebRTC endpoint server
    if(self.sessionId)
    {
      var params =
      {
        sessionId: self.sessionId,
        reason: reason
      };

      doRPC('terminate', params, function()
      {
        self.emit(action, reason);
      });

      _sessionId = null;
    };
  };

  //
  // Methods
  //

  /**
   * @private
   */
  this._setRemoteVideoTag = function(src)
  {
    var remoteVideo = document.getElementById(options.remoteVideoTag);
    if(remoteVideo)
    {
      remoteVideo.src = src;

      return remoteVideo;
    };

    var msg = "Requested remote video tag '" + options.remoteVideoTag
            + "' is not available";

    var error = new Error(msg);
        error.code = ERROR_NO_REMOTE_VIDEO_TAG;

    self.emit('error', error);
  };

  /**
   * Send a command to be executed on the server
   *
   * @param {string} type - The command to execute
   * @param {*} data - Data needed by the command
   * @param {} callback - Function executed after getting a result or an error
   */
  this.execute = function(type, data, callback)
  {
    callback = callback || function(){};

    var params =
    {
      command:
      {
        type: type,
        data: data
      }
    };

    if(this.sessionId)
      params.sessionId = this.sessionId;

    doRPC('execute', params, function(error, result)
    {
      if(error) return callback(error);

      setSessionId(result.sessionId);

      self.emit('execute');
      callback(null, result.commandResult);
    });
  }

  this.on('execute', pollMediaEvents);

  /**
   * Close the connection
   */
  this.terminate = function()
  {
    terminateConnection('terminate', Content.REASON_USER_ENDED_SESSION);
  };
};
Content.prototype.__proto__   = EventEmitter.prototype;
Content.prototype.constructor = Content;

Content.REASON_USER_ENDED_SESSION =
{
  code: 1,
  message: "User ended session"
};
Content.REASON_SERVER_ENDED_SESSION =
{
  code: 2,
  message: "Server ended session"
};

module.exports = Content;
<commit_msg>Fixed pollMediaEvents() called once<commit_after>/*
 * (C) Copyright 2013 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 */

var EventEmitter = require("events").EventEmitter;

var XMLHttpRequest = require("xmlhttprequest");
var RpcBuilder     = require("kws-rpc-builder");

const MAX_FRAMERATE = 15;

/**
 * @constructor
 * @abstract
 *
 * @param {String} url: URL of the WebRTC endpoint server.
 * @param {Object} options: optional configuration parameters
 *   {Enum('inactive', 'sendonly', 'recvonly', 'sendrecv')} audio: audio stream mode
 *   {Enum('inactive', 'sendonly', 'recvonly', 'sendrecv')} video: video stream mode
 *   {[Object]} iceServers: array of objects to initialize the ICE servers. It
 *     structure is the same as an Array of WebRTC RTCIceServer objects.
 *
 * @throws RangeError
 */
function Content(url, options)
{
  EventEmitter.call(this);

  var self = this;

  const ERROR_NO_REMOTE_VIDEO_TAG = -1;

  /**
   * Decode the mode of the streams
   *
   * @private
   *
   * @param {Object} options: constraints to update and decode
   * @param {String} type: name of the constraints to decode
   *
   * @returns {Object}
   *
   * @throws RangeError
   */
  function decodeMode(options, type)
  {
    var result = {};

    // If not defined, set send & receive by default
    options[type] = options[type] || 'sendrecv';

    switch(options[type])
    {
      case 'sendrecv':
        result.local  = true;
        result.remote = true;
      break;

      case 'sendonly':
        result.local  = true;
        result.remote = false;
      break;

      case 'recvonly':
        result.local  = false;
        result.remote = true;
      break;

      case 'inactive':
        result.local  = false;
        result.remote = false;
      break;

      default:
        throw new RangeError("Invalid "+type+" media mode");
    }

    return result;
  }

  // We can't disable both audio and video on a stream, raise error
  if(options.audio == 'inactive' && options.video == 'inactive')
    throw new RangeError("At least one audio or video must to be enabled");

  // Audio media
  this._audio = decodeMode(options, "audio");

  // Video media
  this._video = decodeMode(options, "video");

  if(this._video.local)
      this._video.local =
      {
        mandatory:
        {
//          minHeight   : options.minHeight    || MIN_HEIGHT,
//          maxHeight   : options.maxHeight    || MAX_HEIGHT,
//          minWidth    : options.minWidth     || MIN_WIDTH,
//          maxWidth    : options.maxWidth     || MAX_WIDTH,
//          minFrameRate: options.minFrameRate || MIN_FRAMERATE,
          maxFrameRate: options.maxFrameRate || MAX_FRAMERATE
        }
      };

  // Init the KwsWebRtcContent object

  var _sessionId = null;
  var pollingTimeout = null;
  var polling = false;
  var terminatedByServer = false;

  this.__defineGetter__('sessionId', function()
  {
    return _sessionId;
  });

  function setSessionId(sessionId)
  {
    if(sessionId == undefined)
      throw new TypeError('sessionId is undefined');

    if(_sessionId == undefined)
      _sessionId = sessionId;

    else if(sessionId != _sessionId)
      throw new TypeError('sessionId is not equal to already defined one');
  }

  var rpc = new RpcBuilder();

  function doRPC(method, params, callback)
  {
    var xhr = new XMLHttpRequest();

    // Set XmlHttpRequest error callback
    xhr.addEventListener('error', function(error)
    {
      self.emit('error', error);
    });

    // Connect to Content Server
    xhr.open('POST', url);

    // Send request
    xhr.send(rpc.encodeJSON(method, params, callback));

    // Register callback for the Application Server
    xhr.addEventListener('load', function()
    {
      rpc.decodeJSON(this.responseText);
    });
  };

  function close()
  {
//    xhr.abort();

    _sessionId = null;
  };

  self.on('error',     close);
  self.on('terminate', close);

  // Error dispatcher functions

  var MAX_ALLOWED_ERROR_TRIES = 10;

  var error_tries = 0;

  // RPC calls

  // Start

  this.start = function(params, success)
  {
    if(this.sessionId)
      params.sessionId = this.sessionId;

    doRPC('start', params, function(error, result)
    {
      error = error || result.rejected;

      if(error) return self.emit('error', error);

      setSessionId(result.sessionId);

      success(result);
    });
  };

  // Pool

  /**
   * Pool for events dispatched on the server pipeline
   *
   * @private
   */
  function pollMediaEvents()
  {
    if(!self.sessionId)
      return;

    if(!polling)
      return;

    var params =
    {
      sessionId: self.sessionId
    };

    function success(result)
    {
      error_tries = 0;

      // Content events
      if(result.contentEvents)
        for(var i=0, data; data=result.contentEvents[i]; i++)
          self.emit('mediaevent', data);

      // Control events
      if(result.controlEvents)
        for(var i=0, data; data=result.controlEvents[i]; i++)
        {
          var type = data.type;

          switch(type)
          {
            case "sessionTerminated":
              terminatedByServer = true;
              self.emit('terminate', Content.REASON_SERVER_ENDED_SESSION);
            break;

            case "sessionError":
              self.emit('error', data.data);
            break;

            default:
              console.warn("Unknown control event type: "+type);
          }
        };

      // Check if we should keep polling events
      if(pollingTimeout != 'stopped')
         pollingTimeout = setTimeout(pollMediaEvents, 0);
    };

    function failure(error)
    {
      // A poll error has occurred, retry it
      if(error_tries < MAX_ALLOWED_ERROR_TRIES)
      {
        if(pollingTimeout != 'stopped')
           pollingTimeout = setTimeout(pollMediaEvents, Math.pow(2, error_tries));

        error_tries++;
      }

      // Max number of poll errors achieved, raise error
      else
        terminateConnection('error', error);
    };

    doRPC('poll', params, function(error, result)
    {
      if(error) return failure(error);

      success(result);
    });
  };

  this.on('start', function()
  {
    polling = true;
    pollMediaEvents()
  });

  /**
   * Terminate the connection with the WebRTC media server
   */
  function terminateConnection(action, reason)
  {
    // Stop polling
    clearTimeout(pollingTimeout);
    pollingTimeout = 'stopped';
    polling = false;

    if(terminatedByServer)
      return;

    // Notify to the WebRTC endpoint server
    if(self.sessionId)
    {
      var params =
      {
        sessionId: self.sessionId,
        reason: reason
      };

      doRPC('terminate', params, function()
      {
        self.emit(action, reason);
      });

      _sessionId = null;
    };
  };

  //
  // Methods
  //

  /**
   * @private
   */
  this._setRemoteVideoTag = function(src)
  {
    var remoteVideo = document.getElementById(options.remoteVideoTag);
    if(remoteVideo)
    {
      remoteVideo.src = src;

      return remoteVideo;
    };

    var msg = "Requested remote video tag '" + options.remoteVideoTag
            + "' is not available";

    var error = new Error(msg);
        error.code = ERROR_NO_REMOTE_VIDEO_TAG;

    self.emit('error', error);
  };

  /**
   * Send a command to be executed on the server
   *
   * @param {string} type - The command to execute
   * @param {*} data - Data needed by the command
   * @param {} callback - Function executed after getting a result or an error
   */
  this.execute = function(type, data, callback)
  {
    callback = callback || function(){};

    var params =
    {
      command:
      {
        type: type,
        data: data
      }
    };

    if(this.sessionId)
      params.sessionId = this.sessionId;

    doRPC('execute', params, function(error, result)
    {
      if(error) return callback(error);

      setSessionId(result.sessionId);

      self.emit('execute');
      callback(null, result.commandResult);
    });
  }

  this.on('execute', pollMediaEvents);

  /**
   * Close the connection
   */
  this.terminate = function()
  {
    terminateConnection('terminate', Content.REASON_USER_ENDED_SESSION);
  };
};
Content.prototype.__proto__   = EventEmitter.prototype;
Content.prototype.constructor = Content;

Content.REASON_USER_ENDED_SESSION =
{
  code: 1,
  message: "User ended session"
};
Content.REASON_SERVER_ENDED_SESSION =
{
  code: 2,
  message: "Server ended session"
};

module.exports = Content;
<|endoftext|>


<commit_before>import Ember from 'ember';
import without from 'lodash/array/without';
import Node from '../utils/node';
import includes from 'lodash/collection/includes';
import ResizeAware from 'ember-resize/mixins/resize-aware';

const {
  computed,
  set,
  RSVP,
  isEmpty,
  isNone,
  Component
} = Ember;

export default Component.extend(ResizeAware, {
  resizeDebouncedEventsEnabled: false,
  classNameBindings: [':async-tree', 'isLoading'],

  'row-height': 20,
  indentation: 20,

  isInitialChanged: computed(
    'initial',
    '_initial',
    'initial-filter',
    '_initial-filter', {
      get() {
        return this.get('initial') !== this.get('_initial') ||
               this.get('initial-filter') !== this.get('_initial-filter');
      }
  }),

  didReceiveAttrs() {
    this._super(...arguments);

    this.updateInitial();
  },

  didInsertElement() {
    this._super(...arguments);

    this.set('width', this.$().width());
  },

  updateInitial() {
    if (this.get('isInitialChanged')) {
      let initial = this.get('initial');
      let initialFilter = this.get('initial-filter');
      let { root, openNodes } = Node.load(initial, initialFilter);

      this.setRoot(root);
      this.setProperties({
        openNodes,
        _initial: initial,
        '_initial-filter': initialFilter
      });
    }
  },

  didResize(width) {
    this.set('width', width);
  },

  setRoot(root) {
    this.set('_root', root);
    this.updateFlattened();
  },

  visibleNodes: computed(
    '_root',
    'openNodes.[]',
    '_flattened.[]',
    'hasMore', {
      get() {
        let root = this.get('_root');
        if (isNone(root)) {
          return;
        }

        let openNodes = this.get('openNodes');
        let flattened = this.get('_flattened');
        let hasMore = this.get('hasMore');

        let visible = flattened.filter(function (node) {
          return node.parent === root || node.hasAllParents(openNodes);
        });

        if (hasMore) {
          return visible.concat({isMore: true});
        }

        return visible;
      }
    }
  ),

  hasMore: computed('meta', 'check-has-more', {
    get() {
      const meta = this.get('meta');
      const checkHasMore = this.get('check-has-more');
      if (meta && checkHasMore) {
        return checkHasMore(meta);
      }
    }
  }),

  startLoading(node) {
    this.set('isLoading', node);
    set(node, 'isLoading', true);
  },

  finishLoading(node) {
    this.set('isLoading', null);
    set(node, 'isLoading', false);
  },

  afterFetch() {
    this.finishLoading();
  },

  updateFlattened() {
    let root = this.get('_root');
    this.set('_flattened', root.flatten());
  },

  addChildren(node, children) {
    node.addChildren(children);
    this.updateFlattened();
  },

  markLoaded(node) {
    node.markLoaded();
  },

  openNode(node) {
    let openNodes = this.get('openNodes');
    this.set('openNodes', openNodes.concat(node));
  },

  closeNode(node) {
    let openNodes = this.get('openNodes');
    this.set('openNodes', without(openNodes, node));
  },

  _open(node) {
    if (node.isLoaded) {
      this.openNode(node);
      return;
    }
    this._fetch(node).then((children)=>{
      if (!isEmpty(children)) {
        this.addChildren(node, children);
      }
      this.markLoaded(node);
      this.openNode(node);
      return children;
    });
  },

  _close(node) {
    this.closeNode(node);
  },

  _fetch(node, meta){
    let { content } = node;

    this.startLoading(node);
    let fetch = this.get('fetch');
    let fetched = fetch(content, meta);

    let promise = fetched && fetched.then ? fetched : RSVP.resolve(fetched);

    promise.finally(()=>{
      this.finishLoading(node);
    });

    return promise;
  },

  style({ depth }) {
    let indentation = this.get('indentation');
    return `margin-left: ${indentation * depth}px`;
  },

  saveMeta(meta) {
    this.set('meta', meta);
  },

  actions: {

    toggle(node) {
      let openNodes = this.get('openNodes');
      let isOpen = includes(openNodes, node);
      if (isOpen) {
        this._close(node);
      } else {
        this._open(node);
      }
    },

    fetchMore(meta) {
      let node = this.get('_root');
      this._fetch(node, meta).then((children)=>{
        this.addChildren(node, children);
        let { meta } = children;
        this.saveMeta(meta);
        return children;
      });
    }

  }
});
<commit_msg>Setting width afterRender<commit_after>import Ember from 'ember';
import without from 'lodash/array/without';
import Node from '../utils/node';
import includes from 'lodash/collection/includes';
import ResizeAware from 'ember-resize/mixins/resize-aware';

const {
  computed,
  set,
  RSVP,
  isEmpty,
  isNone,
  Component
} = Ember;

export default Component.extend(ResizeAware, {
  resizeDebouncedEventsEnabled: false,
  classNameBindings: [':async-tree', 'isLoading'],

  'row-height': 20,
  indentation: 20,

  isInitialChanged: computed(
    'initial',
    '_initial',
    'initial-filter',
    '_initial-filter', {
      get() {
        return this.get('initial') !== this.get('_initial') ||
               this.get('initial-filter') !== this.get('_initial-filter');
      }
  }),

  didReceiveAttrs() {
    this._super(...arguments);

    this.updateInitial();
  },

  didInsertElement() {
    this._super(...arguments);

    Ember.run.scheduleOnce('afterRender', this, this.updateWidth);
  },

  updateWidth() {
    this.set('width', this.$().width());
  },

  updateInitial() {
    if (this.get('isInitialChanged')) {
      let initial = this.get('initial');
      let initialFilter = this.get('initial-filter');
      let { root, openNodes } = Node.load(initial, initialFilter);

      this.setRoot(root);
      this.setProperties({
        openNodes,
        _initial: initial,
        '_initial-filter': initialFilter
      });
    }
  },

  didResize(width) {
    this.set('width', width);
  },

  setRoot(root) {
    this.set('_root', root);
    this.updateFlattened();
  },

  visibleNodes: computed(
    '_root',
    'openNodes.[]',
    '_flattened.[]',
    'hasMore', {
      get() {
        let root = this.get('_root');
        if (isNone(root)) {
          return;
        }

        let openNodes = this.get('openNodes');
        let flattened = this.get('_flattened');
        let hasMore = this.get('hasMore');

        let visible = flattened.filter(function (node) {
          return node.parent === root || node.hasAllParents(openNodes);
        });

        if (hasMore) {
          return visible.concat({isMore: true});
        }

        return visible;
      }
    }
  ),

  hasMore: computed('meta', 'check-has-more', {
    get() {
      const meta = this.get('meta');
      const checkHasMore = this.get('check-has-more');
      if (meta && checkHasMore) {
        return checkHasMore(meta);
      }
    }
  }),

  startLoading(node) {
    this.set('isLoading', node);
    set(node, 'isLoading', true);
  },

  finishLoading(node) {
    this.set('isLoading', null);
    set(node, 'isLoading', false);
  },

  afterFetch() {
    this.finishLoading();
  },

  updateFlattened() {
    let root = this.get('_root');
    this.set('_flattened', root.flatten());
  },

  addChildren(node, children) {
    node.addChildren(children);
    this.updateFlattened();
  },

  markLoaded(node) {
    node.markLoaded();
  },

  openNode(node) {
    let openNodes = this.get('openNodes');
    this.set('openNodes', openNodes.concat(node));
  },

  closeNode(node) {
    let openNodes = this.get('openNodes');
    this.set('openNodes', without(openNodes, node));
  },

  _open(node) {
    if (node.isLoaded) {
      this.openNode(node);
      return;
    }
    this._fetch(node).then((children)=>{
      if (!isEmpty(children)) {
        this.addChildren(node, children);
      }
      this.markLoaded(node);
      this.openNode(node);
      return children;
    });
  },

  _close(node) {
    this.closeNode(node);
  },

  _fetch(node, meta){
    let { content } = node;

    this.startLoading(node);
    let fetch = this.get('fetch');
    let fetched = fetch(content, meta);

    let promise = fetched && fetched.then ? fetched : RSVP.resolve(fetched);

    promise.finally(()=>{
      this.finishLoading(node);
    });

    return promise;
  },

  style({ depth }) {
    let indentation = this.get('indentation');
    return `margin-left: ${indentation * depth}px`;
  },

  saveMeta(meta) {
    this.set('meta', meta);
  },

  actions: {

    toggle(node) {
      let openNodes = this.get('openNodes');
      let isOpen = includes(openNodes, node);
      if (isOpen) {
        this._close(node);
      } else {
        this._open(node);
      }
    },

    fetchMore(meta) {
      let node = this.get('_root');
      this._fetch(node, meta).then((children)=>{
        this.addChildren(node, children);
        let { meta } = children;
        this.saveMeta(meta);
        return children;
      });
    }

  }
});
<|endoftext|>