<commit_before>// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
// License: GNU General Public License v3. See license.txt

// Onload
// -----------------------------------------
cur_frm.cscript.onload = function(doc, cdt, cdn) {
}

// Refresh
// -----------------------------------------
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
	if(doc.__islocal) {
		msgprint("Please create new account from Chart of Accounts.");
		throw "cannot create";
	}

	cur_frm.toggle_display('account_name', doc.__islocal);

	// hide fields if group
	cur_frm.toggle_display(['account_type', 'master_type', 'master_name',
		'credit_days', 'credit_limit', 'tax_rate'], doc.group_or_ledger=='Ledger')

	// disable fields
	cur_frm.toggle_enable(['account_name', 'debit_or_credit', 'group_or_ledger',
		'is_pl_account', 'company'], false);

	if(doc.group_or_ledger=='Ledger') {
		wn.model.with_doc("Accounts Settings", "Accounts Settings", function (name) {
			var accounts_settings = wn.model.get_doc("Accounts Settings", name);
			var display = accounts_settings["frozen_accounts_modifier"]
				&& in_list(user_roles, accounts_settings["frozen_accounts_modifier"]);

			cur_frm.toggle_display('freeze_account', display);
		});
	}

	// read-only for root accounts
	if(!doc.parent_account) {
		cur_frm.perm = [[1,0,0], [1,0,0]];
		cur_frm.set_intro("This is a root account and cannot be edited.");
	} else {
		// credit days and type if customer or supplier
		cur_frm.set_intro(null);
		cur_frm.toggle_display(['credit_days', 'credit_limit'], in_list(['Customer', 'Supplier'],
			doc.master_type));

		cur_frm.cscript.master_type(doc, cdt, cdn);
		cur_frm.cscript.account_type(doc, cdt, cdn);

		// show / hide convert buttons
		cur_frm.cscript.add_toolbar_buttons(doc);
	}
}

cur_frm.cscript.master_type = function(doc, cdt, cdn) {
	cur_frm.toggle_display(['credit_days', 'credit_limit'], in_list(['Customer', 'Supplier'],
		doc.master_type));

	cur_frm.toggle_display('master_name', doc.account_type=='Warehouse' ||
		in_list(['Customer', 'Supplier'], doc.master_type));
}

// Fetch parent details
// -----------------------------------------
cur_frm.add_fetch('parent_account', 'debit_or_credit', 'debit_or_credit');
cur_frm.add_fetch('parent_account', 'is_pl_account', 'is_pl_account');

// Hide tax rate based on account type
// -----------------------------------------
cur_frm.cscript.account_type = function(doc, cdt, cdn) {
	if(doc.group_or_ledger=='Ledger') {
		cur_frm.toggle_display(['tax_rate'], doc.account_type == 'Tax');
		cur_frm.toggle_display('master_type', cstr(doc.account_type)=='');
		cur_frm.toggle_display('master_name', doc.account_type=='Warehouse' ||
			in_list(['Customer', 'Supplier'], doc.master_type));
	}
}

// Hide/unhide group or ledger
// -----------------------------------------
cur_frm.cscript.add_toolbar_buttons = function(doc) {
	cur_frm.add_custom_button('Chart of Accounts',
		function() { wn.set_route("Accounts Browser", "Account"); }, 'icon-sitemap')

	if (cstr(doc.group_or_ledger) == 'Group') {
		cur_frm.add_custom_button('Convert to Ledger',
			function() { cur_frm.cscript.convert_to_ledger(); }, 'icon-retweet')
	} else if (cstr(doc.group_or_ledger) == 'Ledger') {
		cur_frm.add_custom_button('Convert to Group',
			function() { cur_frm.cscript.convert_to_group(); }, 'icon-retweet')

		cur_frm.add_custom_button('View Ledger', function() {
			wn.route_options = {
				"account": doc.name,
				"from_date": sys_defaults.year_start_date,
				"to_date": sys_defaults.year_end_date
			};
			wn.set_route("general-ledger");
		});
	}
}
// Convert group to ledger
// -----------------------------------------
cur_frm.cscript.convert_to_ledger = function(doc, cdt, cdn) {
  return $c_obj(cur_frm.get_doclist(),'convert_group_to_ledger','',function(r,rt) {
    if(r.message == 1) {
	  cur_frm.refresh();
    }
  });
}

// Convert ledger to group
// -----------------------------------------
cur_frm.cscript.convert_to_group = function(doc, cdt, cdn) {
  return $c_obj(cur_frm.get_doclist(),'convert_ledger_to_group','',function(r,rt) {
    if(r.message == 1) {
	  cur_frm.refresh();
    }
  });
}

cur_frm.fields_dict['master_name'].get_query = function(doc) {
	if (doc.master_type || doc.account_type=="Warehouse") {
		var dt = doc.master_type || "Warehouse";
		return {
			doctype: dt,
			query: "accounts.doctype.account.account.get_master_name",
			filters: {
				"master_type": dt,
				"company": doc.company
			}
		}
	}
}

cur_frm.fields_dict['parent_account'].get_query = function(doc) {
	return {
		filters: {
			"group_or_ledger": "Group",
			"company": doc.company
		}
	}
}<commit_msg>Fix translate account.js<commit_after>// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
// License: GNU General Public License v3. See license.txt

// Onload
// -----------------------------------------
cur_frm.cscript.onload = function(doc, cdt, cdn) {
}

// Refresh
// -----------------------------------------
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
	if(doc.__islocal) {
		msgprint(wn._("Please create new account from Chart of Accounts."));
		throw "cannot create";
	}

	cur_frm.toggle_display('account_name', doc.__islocal);

	// hide fields if group
	cur_frm.toggle_display(['account_type', 'master_type', 'master_name',
		'credit_days', 'credit_limit', 'tax_rate'], doc.group_or_ledger=='Ledger')

	// disable fields
	cur_frm.toggle_enable(['account_name', 'debit_or_credit', 'group_or_ledger',
		'is_pl_account', 'company'], false);

	if(doc.group_or_ledger=='Ledger') {
		wn.model.with_doc("Accounts Settings", "Accounts Settings", function (name) {
			var accounts_settings = wn.model.get_doc("Accounts Settings", name);
			var display = accounts_settings["frozen_accounts_modifier"]
				&& in_list(user_roles, accounts_settings["frozen_accounts_modifier"]);

			cur_frm.toggle_display('freeze_account', display);
		});
	}

	// read-only for root accounts
	if(!doc.parent_account) {
		cur_frm.perm = [[1,0,0], [1,0,0]];
		cur_frm.set_intro(wn._("This is a root account and cannot be edited."));
	} else {
		// credit days and type if customer or supplier
		cur_frm.set_intro(null);
		cur_frm.toggle_display(['credit_days', 'credit_limit'], in_list(['Customer', 'Supplier'],
			doc.master_type));

		cur_frm.cscript.master_type(doc, cdt, cdn);
		cur_frm.cscript.account_type(doc, cdt, cdn);

		// show / hide convert buttons
		cur_frm.cscript.add_toolbar_buttons(doc);
	}
}

cur_frm.cscript.master_type = function(doc, cdt, cdn) {
	cur_frm.toggle_display(['credit_days', 'credit_limit'], in_list(['Customer', 'Supplier'],
		doc.master_type));

	cur_frm.toggle_display('master_name', doc.account_type=='Warehouse' ||
		in_list(['Customer', 'Supplier'], doc.master_type));
}

// Fetch parent details
// -----------------------------------------
cur_frm.add_fetch('parent_account', 'debit_or_credit', 'debit_or_credit');
cur_frm.add_fetch('parent_account', 'is_pl_account', 'is_pl_account');

// Hide tax rate based on account type
// -----------------------------------------
cur_frm.cscript.account_type = function(doc, cdt, cdn) {
	if(doc.group_or_ledger=='Ledger') {
		cur_frm.toggle_display(['tax_rate'], doc.account_type == 'Tax');
		cur_frm.toggle_display('master_type', cstr(doc.account_type)=='');
		cur_frm.toggle_display('master_name', doc.account_type=='Warehouse' ||
			in_list(['Customer', 'Supplier'], doc.master_type));
	}
}

// Hide/unhide group or ledger
// -----------------------------------------
cur_frm.cscript.add_toolbar_buttons = function(doc) {
	cur_frm.add_custom_button(wn._('Chart of Accounts'),
		function() { wn.set_route("Accounts Browser", "Account"); }, 'icon-sitemap')

	if (cstr(doc.group_or_ledger) == 'Group') {
		cur_frm.add_custom_button(wn._('Convert to Ledger'),
			function() { cur_frm.cscript.convert_to_ledger(); }, 'icon-retweet')
	} else if (cstr(doc.group_or_ledger) == 'Ledger') {
		cur_frm.add_custom_button(wn._('Convert to Group'),
			function() { cur_frm.cscript.convert_to_group(); }, 'icon-retweet')

		cur_frm.add_custom_button(wn._('View Ledger'), function() {
			wn.route_options = {
				"account": doc.name,
				"from_date": sys_defaults.year_start_date,
				"to_date": sys_defaults.year_end_date
			};
			wn.set_route("general-ledger");
		});
	}
}
// Convert group to ledger
// -----------------------------------------
cur_frm.cscript.convert_to_ledger = function(doc, cdt, cdn) {
  return $c_obj(cur_frm.get_doclist(),'convert_group_to_ledger','',function(r,rt) {
    if(r.message == 1) {
	  cur_frm.refresh();
    }
  });
}

// Convert ledger to group
// -----------------------------------------
cur_frm.cscript.convert_to_group = function(doc, cdt, cdn) {
  return $c_obj(cur_frm.get_doclist(),'convert_ledger_to_group','',function(r,rt) {
    if(r.message == 1) {
	  cur_frm.refresh();
    }
  });
}

cur_frm.fields_dict['master_name'].get_query = function(doc) {
	if (doc.master_type || doc.account_type=="Warehouse") {
		var dt = doc.master_type || "Warehouse";
		return {
			doctype: dt,
			query: "accounts.doctype.account.account.get_master_name",
			filters: {
				"master_type": dt,
				"company": doc.company
			}
		}
	}
}

cur_frm.fields_dict['parent_account'].get_query = function(doc) {
	return {
		filters: {
			"group_or_ledger": "Group",
			"company": doc.company
		}
	}
}<|endoftext|>


<commit_before>import Ember from 'ember';
import renderTooltip from 'ember-tooltips/utils/render-tooltip';

const { on } = Ember;

export default Ember.Mixin.create({

  /**
  The tooltip object

  @property tooltip
  @type Object
  */

  tooltip: null,

  /**
  A list of Tooltip properties currently supported
  by this addon

  @property tooltipSupportedProperties
  @type Array
  */

  tooltipSupportedProperties: [
    'auto',
    'content',
    'effectClass',
    'event',
    'place',
    'spacing',
    'typeClass',
    'open'
  ],

  /* Tooltip options - see http://darsa.in/tooltip/ */

  tooltipAuto: true,
  tooltipContent: null,
  tooltipEffectClass: 'slide', // fade, grow, slide, null
  tooltipEvent: 'hover', // DOM event or "manual"
  tooltipPlace: 'top',
  tooltipSpacing: 10,
  tooltipTypeClass: null,
  tooltipOpen: null, // for manual-mode triggering

  /**
  Removes a tooltip from the DOM if the element it is attached
  to is destroyed.

  @method destroyTooltip
  */

  destroyTooltip: on('willDestroyElement', function() {
    const tooltip = this.get('tooltip');

    if (tooltip) {
      tooltip.effect(null); // Remove animation
      tooltip.detach();
    }

    /* Remove observer, even if it was never added */
    this.removeObserver('tooltipOpen', this, this.tooltipOpenDidChange);
  }),

  /**
  Adds a tooltip to the current view using the values of the tooltip
  properties on the view or, if a `{{tooltip-on-parent}}` component is
  passed, the values set on the component.

  In the latter case, the `{{tooltip-on-parent}}` block template will
  be used for the tooltip content.

  ## Example 1 - Setting values on a view or component

  ```hbs
  {{#some-component tooltipContent='This will show' tooltipPlace='right'}}
    Hover over me
  {{/some-component}}
  ```

  ## Example 2 - Using a child component

  ```hbs
  {{#some-component}}

    {{#tooltip-on-parent place='right'}}
      This will show
    {{/tooltip-on-parent}}

    Hover over me

  {{/some-component}}
  ```

  Usually you won't have to call the `renderTooltip` method directly but it's still
  made publically available. In the above examples, the components handle calling
  this `renderTooltip()` method at the correct time.

  Supported options are in the format tooltip{$capitalizedProperty} where
  capitalizedProperty is each property, capitalized, in tooltipSupportedProperties.

  @method renderTooltip
  @param [maybeTooltipComponent] An optionally-passed component for a `{{tooltip-on-parent}}` class
  */

  renderTooltip: on('didInsertElement', function(maybeTooltipComponent) {
    const componentWasPassed = Ember.typeOf(maybeTooltipComponent) === 'instance';
    const component = componentWasPassed ? maybeTooltipComponent : Ember.Object.create({});

    let content = this.get('tooltipContent');
    let tooltip, tooltipOptions;

    if (componentWasPassed) {
      const componentContent = component.get('content');

      if (componentContent) {
        content = componentContent;
      } else {
        content = component.get('element').innerHTML;
      }
    }

    if (!content) {
      return;
    }

    tooltipOptions = {
      content
    };

    this.get('tooltipSupportedProperties').forEach(function(property) {

      /* Ignore content because we dealt with it already */

      if (property === 'content') {
        return;
      }

      const capitalizedProperty = Ember.String.capitalize(property);

      tooltipOptions[property] = component.get(property) || this.get(`tooltip${capitalizedProperty}`);
    }, this);

    tooltip = renderTooltip(this.get('element'), tooltipOptions);

    this.set('tooltip', tooltip);

    /* Bind observer if manual-triggering mode */
    if (tooltipOptions.event === 'manual') {
      if (componentWasPassed) {
        // Keep track of child tooltip component
        this.set('tooltipChildComponent', component);
        // Turn 'tooltipOpen' into a computed property, reading from child tooltip component's 'open' option
        Ember.defineProperty(this, 'tooltipOpen', Ember.computed.reads('tooltipChildComponent.open'));
      }
      Ember.addObserver(this, 'tooltipOpen', this, this.tooltipOpenDidChange);
      this.tooltipOpenDidChange();
    }
  }),

  /**
  Opens / closes tooltip based on value of 'tooltipOpen'.
  Only used when event is 'manual'.

  @method tooltipOpenDidChange
  */

  tooltipOpenDidChange: function() {
    const tooltip = this.get('tooltip');

    if (this.get('tooltipOpen')) {
      tooltip.show();
    } else {
      tooltip.hide();
    }
  },

  /**
  Call this method on any view to attach tooltips to all elements in its
  template that have a `.tooltip` class. Tooltip options are set using
  data attributes.

  ```hbs
  {{!--app/templates/components/some-widget.hbs--}}
  <div
    class="has-tooltip"
    data-tooltip-content="This will show"
    data-tooltip-position="right"
    data-tooltip-effect-class="grow"
  >
    Hover over me!
  </div>
  ```

  ```js
  // app/components/some-widget.js

  export default Ember.Component.extend({

    renderTooltipsInTemplate: function() {
      this.renderTooltip();
    }.on('didInsertElement'),

  });
  ```

  Supported options are in the format data-tooltip-{$dasherizedProperty} where
  dasherizedProperty is each property, dasherized, in tooltipSupportedProperties.

  @method renderChildTooltips
  */

  renderChildTooltips: function() {
    const _this = this;
    const tooltipSupportedProperties = this.get('tooltipSupportedProperties');

    Ember.run.scheduleOnce('render', this, function() {
      const tooltipOptions = {};

      this.$().find('.has-tooltip').each(function() {
        const $element = Ember.$(this);

        tooltipSupportedProperties.forEach(function(property) {
          const capitalizedProperty = Ember.String.capitalize(property);
          const dasherizedProperty = Ember.String.dasherize(property);
          const value = $element.data(`tooltip-${dasherizedProperty}`);

          tooltipOptions[property] = value || _this.get(`tooltip${capitalizedProperty}`);
        }, this);

        renderTooltip(this, tooltipOptions);
      });
    });
  },

});
<commit_msg>Switch to 'this.addObserver' for consistency<commit_after>import Ember from 'ember';
import renderTooltip from 'ember-tooltips/utils/render-tooltip';

const { on } = Ember;

export default Ember.Mixin.create({

  /**
  The tooltip object

  @property tooltip
  @type Object
  */

  tooltip: null,

  /**
  A list of Tooltip properties currently supported
  by this addon

  @property tooltipSupportedProperties
  @type Array
  */

  tooltipSupportedProperties: [
    'auto',
    'content',
    'effectClass',
    'event',
    'place',
    'spacing',
    'typeClass',
    'open'
  ],

  /* Tooltip options - see http://darsa.in/tooltip/ */

  tooltipAuto: true,
  tooltipContent: null,
  tooltipEffectClass: 'slide', // fade, grow, slide, null
  tooltipEvent: 'hover', // DOM event or "manual"
  tooltipPlace: 'top',
  tooltipSpacing: 10,
  tooltipTypeClass: null,
  tooltipOpen: null, // for manual-mode triggering

  /**
  Removes a tooltip from the DOM if the element it is attached
  to is destroyed.

  @method destroyTooltip
  */

  destroyTooltip: on('willDestroyElement', function() {
    const tooltip = this.get('tooltip');

    if (tooltip) {
      tooltip.effect(null); // Remove animation
      tooltip.detach();
    }

    /* Remove observer, even if it was never added */
    this.removeObserver('tooltipOpen', this, this.tooltipOpenDidChange);
  }),

  /**
  Adds a tooltip to the current view using the values of the tooltip
  properties on the view or, if a `{{tooltip-on-parent}}` component is
  passed, the values set on the component.

  In the latter case, the `{{tooltip-on-parent}}` block template will
  be used for the tooltip content.

  ## Example 1 - Setting values on a view or component

  ```hbs
  {{#some-component tooltipContent='This will show' tooltipPlace='right'}}
    Hover over me
  {{/some-component}}
  ```

  ## Example 2 - Using a child component

  ```hbs
  {{#some-component}}

    {{#tooltip-on-parent place='right'}}
      This will show
    {{/tooltip-on-parent}}

    Hover over me

  {{/some-component}}
  ```

  Usually you won't have to call the `renderTooltip` method directly but it's still
  made publically available. In the above examples, the components handle calling
  this `renderTooltip()` method at the correct time.

  Supported options are in the format tooltip{$capitalizedProperty} where
  capitalizedProperty is each property, capitalized, in tooltipSupportedProperties.

  @method renderTooltip
  @param [maybeTooltipComponent] An optionally-passed component for a `{{tooltip-on-parent}}` class
  */

  renderTooltip: on('didInsertElement', function(maybeTooltipComponent) {
    const componentWasPassed = Ember.typeOf(maybeTooltipComponent) === 'instance';
    const component = componentWasPassed ? maybeTooltipComponent : Ember.Object.create({});

    let content = this.get('tooltipContent');
    let tooltip, tooltipOptions;

    if (componentWasPassed) {
      const componentContent = component.get('content');

      if (componentContent) {
        content = componentContent;
      } else {
        content = component.get('element').innerHTML;
      }
    }

    if (!content) {
      return;
    }

    tooltipOptions = {
      content
    };

    this.get('tooltipSupportedProperties').forEach(function(property) {

      /* Ignore content because we dealt with it already */

      if (property === 'content') {
        return;
      }

      const capitalizedProperty = Ember.String.capitalize(property);

      tooltipOptions[property] = component.get(property) || this.get(`tooltip${capitalizedProperty}`);
    }, this);

    tooltip = renderTooltip(this.get('element'), tooltipOptions);

    this.set('tooltip', tooltip);

    /* Bind observer if manual-triggering mode */
    if (tooltipOptions.event === 'manual') {
      if (componentWasPassed) {
        // Keep track of child tooltip component
        this.set('tooltipChildComponent', component);
        // Turn 'tooltipOpen' into a computed property, reading from child tooltip component's 'open' option
        Ember.defineProperty(this, 'tooltipOpen', Ember.computed.reads('tooltipChildComponent.open'));
      }
      this.addObserver('tooltipOpen', this, this.tooltipOpenDidChange);
      this.tooltipOpenDidChange();
    }
  }),

  /**
  Opens / closes tooltip based on value of 'tooltipOpen'.
  Only used when event is 'manual'.

  @method tooltipOpenDidChange
  */

  tooltipOpenDidChange: function() {
    const tooltip = this.get('tooltip');

    if (this.get('tooltipOpen')) {
      tooltip.show();
    } else {
      tooltip.hide();
    }
  },

  /**
  Call this method on any view to attach tooltips to all elements in its
  template that have a `.tooltip` class. Tooltip options are set using
  data attributes.

  ```hbs
  {{!--app/templates/components/some-widget.hbs--}}
  <div
    class="has-tooltip"
    data-tooltip-content="This will show"
    data-tooltip-position="right"
    data-tooltip-effect-class="grow"
  >
    Hover over me!
  </div>
  ```

  ```js
  // app/components/some-widget.js

  export default Ember.Component.extend({

    renderTooltipsInTemplate: function() {
      this.renderTooltip();
    }.on('didInsertElement'),

  });
  ```

  Supported options are in the format data-tooltip-{$dasherizedProperty} where
  dasherizedProperty is each property, dasherized, in tooltipSupportedProperties.

  @method renderChildTooltips
  */

  renderChildTooltips: function() {
    const _this = this;
    const tooltipSupportedProperties = this.get('tooltipSupportedProperties');

    Ember.run.scheduleOnce('render', this, function() {
      const tooltipOptions = {};

      this.$().find('.has-tooltip').each(function() {
        const $element = Ember.$(this);

        tooltipSupportedProperties.forEach(function(property) {
          const capitalizedProperty = Ember.String.capitalize(property);
          const dasherizedProperty = Ember.String.dasherize(property);
          const value = $element.data(`tooltip-${dasherizedProperty}`);

          tooltipOptions[property] = value || _this.get(`tooltip${capitalizedProperty}`);
        }, this);

        renderTooltip(this, tooltipOptions);
      });
    });
  },

});
<|endoftext|>


<commit_before>import { InterpolationModes } from './animation_sampler.js';
import { InterpolationPath } from './channel.js';
import { clamp, jsToGlSlice } from './utils.js';
import { quat, glMatrix } from 'gl-matrix';

class gltfInterpolator
{
    constructor()
    {
        this.prevKey = 0;
        this.prevT = 0.0;
    }

    slerpQuat(q1, q2, t)
    {
        const qn1 = quat.create();
        const qn2 = quat.create();

        quat.normalize(qn1, q1);
        quat.normalize(qn2, q2);

        const quatResult = quat.create();

        quat.slerp(quatResult, qn1, qn2, t);
        quat.normalize(quatResult, quatResult);

        return quatResult;
    }

    linear(prevKey, nextKey, output, t, stride)
    {
        const result = new glMatrix.ARRAY_TYPE(stride);

        for(let i = 0; i < stride; ++i)
        {
            result[i] = output[prevKey * stride + i] * (1-t) + output[nextKey * stride + i] * t;
        }

        return result;
    }

    cubicSpline(prevKey, nextKey, output, keyDelta, t, stride)
    {
        // stride: Count of components (4 in a quaternion).
        // Scale by 3, because each output entry consist of two tangents and one data-point.
        const prevIndex = prevKey * stride * 3;
        const nextIndex = nextKey * stride * 3;
        const A = 0;
        const V = 1 * stride;
        const B = 2 * stride;

        const result = new glMatrix.ARRAY_TYPE(stride);
        const tSq = t ** 2;
        const tCub = t ** 3;

        // We assume that the components in output are laid out like this: in-tangent, point, out-tangent.
        // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#appendix-c-spline-interpolation
        for(let i = 0; i < stride; ++i)
        {
            const p0 = output[prevIndex + V + i];
            const m0 = keyDelta * output[prevIndex + B + i];
            const p1 = output[nextIndex + V + i];
            const m1 = keyDelta * output[nextIndex + A + i];

            result[i] = ((2*tCub - 3*tSq + 1) * p0) + ((tCub - 2*tSq + t) * m0) + ((-2*tCub + 3*tSq) * p1) + ((tCub - tSq) * m1);
        }

        return result;
    }

    resetKey()
    {
        this.prevKey = 0;
    }

    interpolate(gltf, channel, sampler, t, stride)
    {
        const input = gltf.accessors[sampler.input].getDeinterlacedView(gltf);
        const output = gltf.accessors[sampler.output].getDeinterlacedView(gltf);

        if(output.length === stride) // no interpolation for single keyFrame animations
        {
            return jsToGlSlice(output, 0, stride);
        }

        let nextKey = undefined;

        const maxKeyTime = input[input.length - 1];
        t = t % maxKeyTime; // loop animation

        if (this.prevT > t)
        {
            this.prevKey = 0;
        }

        this.prevT = t;

        for (let i = this.prevKey; i < input.length; ++i) // find current keyframe interval
        {
            if (t <= input[i])
            {
                nextKey = i;
                break;
            }
        }

        nextKey = clamp(nextKey, 1, input.length - 1);
        this.prevKey = clamp(nextKey - 1, 0, nextKey);

        const keyDelta = input[nextKey] - input[this.prevKey];
        t = (t - input[this.prevKey]) / keyDelta; // normalize t to 0..1

        if(channel.target.path === InterpolationPath.ROTATION)
        {
            // When using a cubic spline interpolator, the output index needs to be remapped
            // onto the spline data point: <in-tangent> <data-point> <out-tangent>
            const outputLocation = InterpolationModes.CUBICSPLINE === sampler.interpolation
                ? i => i * 3 + 1
                : i => i;

            const q0 = this.getQuat(output, outputLocation(this.prevKey));
            const q1 = this.getQuat(output, outputLocation(nextKey));

            return this.slerpQuat(q0, q1, t);
        }

        switch(sampler.interpolation)
        {
            case InterpolationModes.STEP: return jsToGlSlice(output, this.prevKey * stride, stride); // t < 0.5 ? output[preKey] : output[nextKey]
            case InterpolationModes.CUBICSPLINE: return this.cubicSpline(this.prevKey, nextKey, output, keyDelta, t, stride);
            default: return this.linear(this.prevKey, nextKey, output, t, stride);
        }
    }

    getQuat(output, index)
    {
        const x = output[4 * index];
        const y = output[4 * index + 1];
        const z = output[4 * index + 2];
        const w = output[4 * index + 3];
        return quat.fromValues(x, y, z, w);
    }
}

export { gltfInterpolator };
<commit_msg>Annotate that quaternions are always interpolated linearly<commit_after>import { InterpolationModes } from './animation_sampler.js';
import { InterpolationPath } from './channel.js';
import { clamp, jsToGlSlice } from './utils.js';
import { quat, glMatrix } from 'gl-matrix';

class gltfInterpolator
{
    constructor()
    {
        this.prevKey = 0;
        this.prevT = 0.0;
    }

    slerpQuat(q1, q2, t)
    {
        const qn1 = quat.create();
        const qn2 = quat.create();

        quat.normalize(qn1, q1);
        quat.normalize(qn2, q2);

        const quatResult = quat.create();

        quat.slerp(quatResult, qn1, qn2, t);
        quat.normalize(quatResult, quatResult);

        return quatResult;
    }

    linear(prevKey, nextKey, output, t, stride)
    {
        const result = new glMatrix.ARRAY_TYPE(stride);

        for(let i = 0; i < stride; ++i)
        {
            result[i] = output[prevKey * stride + i] * (1-t) + output[nextKey * stride + i] * t;
        }

        return result;
    }

    cubicSpline(prevKey, nextKey, output, keyDelta, t, stride)
    {
        // stride: Count of components (4 in a quaternion).
        // Scale by 3, because each output entry consist of two tangents and one data-point.
        const prevIndex = prevKey * stride * 3;
        const nextIndex = nextKey * stride * 3;
        const A = 0;
        const V = 1 * stride;
        const B = 2 * stride;

        const result = new glMatrix.ARRAY_TYPE(stride);
        const tSq = t ** 2;
        const tCub = t ** 3;

        // We assume that the components in output are laid out like this: in-tangent, point, out-tangent.
        // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#appendix-c-spline-interpolation
        for(let i = 0; i < stride; ++i)
        {
            const p0 = output[prevIndex + V + i];
            const m0 = keyDelta * output[prevIndex + B + i];
            const p1 = output[nextIndex + V + i];
            const m1 = keyDelta * output[nextIndex + A + i];

            result[i] = ((2*tCub - 3*tSq + 1) * p0) + ((tCub - 2*tSq + t) * m0) + ((-2*tCub + 3*tSq) * p1) + ((tCub - tSq) * m1);
        }

        return result;
    }

    resetKey()
    {
        this.prevKey = 0;
    }

    interpolate(gltf, channel, sampler, t, stride)
    {
        const input = gltf.accessors[sampler.input].getDeinterlacedView(gltf);
        const output = gltf.accessors[sampler.output].getDeinterlacedView(gltf);

        if(output.length === stride) // no interpolation for single keyFrame animations
        {
            return jsToGlSlice(output, 0, stride);
        }

        let nextKey = undefined;

        const maxKeyTime = input[input.length - 1];
        t = t % maxKeyTime; // loop animation

        if (this.prevT > t)
        {
            this.prevKey = 0;
        }

        this.prevT = t;

        for (let i = this.prevKey; i < input.length; ++i) // find current keyframe interval
        {
            if (t <= input[i])
            {
                nextKey = i;
                break;
            }
        }

        nextKey = clamp(nextKey, 1, input.length - 1);
        this.prevKey = clamp(nextKey - 1, 0, nextKey);

        const keyDelta = input[nextKey] - input[this.prevKey];
        t = (t - input[this.prevKey]) / keyDelta; // normalize t to 0..1

        if(channel.target.path === InterpolationPath.ROTATION)
        {
            // When using a cubic spline interpolator, the output index needs to be remapped
            // onto the spline data point: <in-tangent> <data-point> <out-tangent>
            //
            // TODO: Currently, only linear slerp is implemented.
            // Cubic splines are simply re-interpreted as linear interpolations
            // and all tangent data is ignored.
            const outputLocation = InterpolationModes.CUBICSPLINE === sampler.interpolation
                ? i => i * 3 + 1
                : i => i;

            const q0 = this.getQuat(output, outputLocation(this.prevKey));
            const q1 = this.getQuat(output, outputLocation(nextKey));

            return this.slerpQuat(q0, q1, t);
        }

        switch(sampler.interpolation)
        {
            case InterpolationModes.STEP: return jsToGlSlice(output, this.prevKey * stride, stride); // t < 0.5 ? output[preKey] : output[nextKey]
            case InterpolationModes.CUBICSPLINE: return this.cubicSpline(this.prevKey, nextKey, output, keyDelta, t, stride);
            default: return this.linear(this.prevKey, nextKey, output, t, stride);
        }
    }

    getQuat(output, index)
    {
        const x = output[4 * index];
        const y = output[4 * index + 1];
        const z = output[4 * index + 2];
        const w = output[4 * index + 3];
        return quat.fromValues(x, y, z, w);
    }
}

export { gltfInterpolator };
<|endoftext|>


<commit_before>/*!
 * Drop-it v1.0.0
 * Licensed under http://www.apache.org/licenses/LICENSE-2.0
 *
 * Developed by HellCoderz | www.makefbcoverscom
 */

(function($){
    if(!$.bhs){
        $.bhs = new Object();
    };

    $.bhs.uploader = function(el,options){

        var base = this;
		var files, target, maxfile, errorResp, fileReader;
		var resp = new Array();
		var fileArr = new Array();
		var errorArr = new Array();
		var uploadedArr = new Array();
        var Progressor= [];
		var busyFlag = false;

        base.$el = target = $(el);
        base.el = el;
        base.$el.data("bhs.uploader", base);

        base.init = function(){
            base.options = $.extend({},$.bhs.uploader.defaultOptions, options);
			//Initializations
			dataArray = [];
			maxfile = base.options.maxfile;
			$.event.props.push('dataTransfer');

        };
		ondragover =  function(callback){
			target.bind('dragover', function(e) {
				e.preventDefault();
				e.stopPropagation();
				if(typeof callback == 'function')
					callback.call(this);
				return false;
			});
		};

		base.init();
		ondragover();

		if(base.options.fileUpload){
			$(base.options.fileUpload).bind("change", function () {
				traverseFiles(this.files);
			});
		}

		if(typeof base.options.onDragEnter == 'function'){
			target.bind('dragenter', function(e) {
				e.preventDefault();
				e.stopPropagation();
				base.options.onDragEnter.call(this);
				return false;
			});
		}

		if(typeof base.options.onDragOver == 'function'){
			ondragover(base.options.onDragOver);
		}

		if(typeof base.options.onDragLeave == 'function'){
			target.bind('dragleave', function(e) {
				e.preventDefault();
				e.stopPropagation();
				base.options.onDragLeave.call(this);
				return false;
			});
		}

		target.bind('drop', function(e) {
			e.preventDefault();
			e.stopPropagation();
			var files = e.dataTransfer.files;
			traverseFiles(files);
			return false;
		});

		/***--------- Private Methods ----------***/

		uniqueData =  function(){
			var text = "";
			var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

			for( var i=0; i < 5; i++ )
				text += possible.charAt(Math.floor(Math.random() * possible.length));

			return text;
		}

		traverseFiles = function(files){
			if(files.length <= maxfile){
				var len = 0;
				$.each(files, function(index, file) {

					if(base.isImage(file)){
						len++;
						var uniq = uniqueData();
						file.handle = uniq;
						fileReader = new FileReader();
						fileReader.onload = (function(file) {
							return function(e) {
								file.src = this.result;
							};
						})(files[index]);
						fileReader.readAsDataURL(file);
						fileArr.push(file);
					}else{
						errorResp = 'file '+file.name+' id('+index+') is not a valid image file';
						parseError(base.options.error, errorResp);
					}
				});
				resp = { fileinfo: fileArr, error: errorArr};
				resp.count = resp.fileinfo.length;
				parsePreview(base.options.preview, resp);
				if(typeof base.options.error == 'function')
					base.error();
				}
			else{
				errorResp = "Maximum "+maxfile+" files are allowed";
				parseError(base.options.error, errorResp);
				return false;
			}
		}

		parsePreview = function(MethodOpt, Args){
			if(typeof MethodOpt == 'function'){
				if(Args){
					if(MethodOpt == base.options.error){
						errorArr.push(Args);
					}
					MethodOpt.call(target,Args);
				}				else

					MethodOpt.call(target);
			}
			return false;
		}

		parseError = function(MethodOpt, Args){
			errorArr.push(Args);
			if(typeof MethodOpt == 'function'){
				MethodOpt.call(target,Args);
			}
			return false;
		}

		parseFunc = function(arg){
			arg.call(target);
		}

		clearArr = function(arr){
			if(arr && arr.length > 0){
				$.grep(arr, function(e,i){
					arr.splice(i,arr.length);
				});
			}
			return arr;
		}

		doAjax = function(postFile, array, xhr, callback){

			var file = $(array.shift());
			var fileName = file[0].name;
			var fileSize = file[0].size;
			var fileType = file[0].type;
			var fileSrc = file[0].src;
			var fileHandle = file[0].handle;
			busyFlag = true;
			$.userdata = file;
			provider = function () { return xhr; };
			data = fileSrc.substr(fileSrc.indexOf('base64') + 7);
			$.ajax({
					type: 'POST',
					url: postFile,
					xhr: provider,
					cache: false,
					data: {
						name: fileName,
						size: fileSize,
						type: fileType,
						data: data,
					},
					success: function (data) {
						$.userdata[0].response =  data;
						console.log(resp.fileinfo);
						$.grep(resp.fileinfo, function(e,i){
							if(e.handle == fileHandle)
							{
								resp.fileinfo.splice(i,1);
							}
						});
						callback($.userdata);
						busyFlag = false;
					},
					error: function (data,e1,e2) {
						$(array.unshift(file[0]));
						busyFlag = false;
						console.log(data.statusText);
						resp.count = resp.fileinfo.length;
						errorResp = 'The image could not be saved on server';
						parseError(base.options.error, errorResp);
					}
			}).done(function(){
				if(array.length === 0){
					return false;
				}
				doAjax(postFile,array, xhr,callback);
			});
			resp.count = resp.fileinfo.length;
		}

		/***--------- Public Methods ----------***/

		base.isImage =  function(file){
			if (file.type.match('image.*')) {
				return true;
			}
			return false;
		}

		base.preview = function(arg){
			if(typeof arg === 'undefined')
				return resp;
			else{
				var index = arg;
				try
				{
					if(arg < 1) return false;
					return resp.fileinfo[arg-1];
				}
				catch(exception){
					return false;
				}
			}
		}

		base.uploaded = function(){
			return uploadedArr;
		}

		base.error = function(){
			return (typeof resp == 'object' && resp.error)?resp.error:false;
		}

		base.dropped = function(){
			var x = resp.fileinfo;
			var chk = (x)?x:[];
			var dropped = $.merge( $.merge( [], chk ),  uploadedArr );
			return dropped;
		}

		base.removeAll =  function(arg){
			if(busyFlag == true){
				console.log('File currently under upload. Could not remove the file now');
				return false;
			}
			else{
				if(typeof arg == 'function')
					parseFunc(arg);
				resp.fileinfo = clearArr(resp.fileinfo);
				resp.error = clearArr(resp.error);
				resp.count = 0;
				return resp;
			}
		}

		base.upload = function(arg){
			if(typeof resp != 'undefined' && resp.count)
			{
				var xhr, provider;
				xhr = $.ajaxSettings.xhr();
				if(typeof arg === 'undefined' || arg == ''){
					errorResp = 'Please provide the argument for uploading image';
					parseError(base.options.error, errorResp);
					return false;
				}
				if(typeof arg == 'object' && !arg.file){
					errorResp = 'Please mention a PHP file before uploading';
					parseError(base.options.error, errorResp);
					return false;
				}
				if(typeof(arg.progress) == 'function')
				{
					if (xhr.upload) {
						xhr.upload.addEventListener('progress', function (evt) {
							if (evt.lengthComputable) {
								var percentage = Math.round((evt.loaded / evt.total) * 100);
								$.userdata.progress = percentage;
								arg.progress.call(target,$.userdata);
							}
						}, false);
					}
				}

				var file = (typeof arg == 'object')?arg.file:arg;
				doAjax(file, resp.fileinfo, xhr, function(data){
					$.grep(data, function(e,i){
						uploadedArr.push(data[i]);
					});
					if(typeof(arg.done) == 'function'){
						arg.done.call(target,data);
					}
				});

			}else{
				errorResp = 'No Valid files to upload';
				parseError(base.options.error, errorResp);
				return false;
			}
		}

    };

    $.bhs.uploader.defaultOptions = {
		maxfile: 5
    };

    $.fn.bhs_uploader = function(options){
		var args = Array.prototype.slice.call(arguments, 1);
        return this.each(function(){
				var item = $(this), instance = item.data('bhs_uploader');
				if(!instance) {
					item.data('bhs_uploader', new $.bhs.uploader(this, options));
				} else {
					if(typeof options === 'string') {
						return instance[options].apply(instance, args);
					}
				}
        });
    };

})(jQuery);
<commit_msg>Added thumb option for source extraction from HTML5 fileReader<commit_after>/*!
 * Drop-it v1.0.0
 * Licensed under http://www.apache.org/licenses/LICENSE-2.0
 *
 * Developed by HellCoderz | www.makefbcoverscom
 */

(function($){
    if(!$.bhs){
        $.bhs = new Object();
    };

    $.bhs.uploader = function(el,options){

        var base = this;
		var files, target, maxfile, errorResp, fileReader;
		var resp = new Array();
		var fileArr = new Array();
		var errorArr = new Array();
		var uploadedArr = new Array();
        var Progressor= [];
		var busyFlag = false;

        base.$el = target = $(el);
        base.el = el;
        base.$el.data("bhs.uploader", base);

        base.init = function(){
            base.options = $.extend({},$.bhs.uploader.defaultOptions, options);
			//Initializations
			dataArray = [];
			maxfile = base.options.maxfile;
			$.event.props.push('dataTransfer');

        };
		ondragover =  function(callback){
			target.bind('dragover', function(e) {
				e.preventDefault();
				e.stopPropagation();
				if(typeof callback == 'function')
					callback.call(this);
				return false;
			});
		};

		base.init();
		ondragover();

		if(base.options.fileUpload){
			$(base.options.fileUpload).bind("change", function () {
				traverseFiles(this.files);
			});
		}

		if(typeof base.options.onDragEnter == 'function'){
			target.bind('dragenter', function(e) {
				e.preventDefault();
				e.stopPropagation();
				base.options.onDragEnter.call(this);
				return false;
			});
		}

		if(typeof base.options.onDragOver == 'function'){
			ondragover(base.options.onDragOver);
		}

		if(typeof base.options.onDragLeave == 'function'){
			target.bind('dragleave', function(e) {
				e.preventDefault();
				e.stopPropagation();
				base.options.onDragLeave.call(this);
				return false;
			});
		}

		target.bind('drop', function(e) {
			e.preventDefault();
			e.stopPropagation();
			var files = e.dataTransfer.files;
			traverseFiles(files);
			return false;
		});

		/***--------- Private Methods ----------***/

		uniqueData =  function(){
			var text = "";
			var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

			for( var i=0; i < 5; i++ )
				text += possible.charAt(Math.floor(Math.random() * possible.length));

			return text;
		}

		createWriter = function(files){
			for (var i = 0, file; file = files[i]; i++) {
				if(base.isImage(file)){
					var uniq = uniqueData();
					file.handle = uniq;
					fileReader = new FileReader();
					fileReader.onload = (function(file) {
						return function(e) {
							 var Handler = [];
							 file.src  = this.result;
							 Handler.push(file);
							 if(typeof base.options.thumb == 'function'){
								base.options.thumb.call(target,Handler);
							 }
						};
					})(file);
					fileReader.readAsDataURL(file);
					fileArr.push(file);
				}else{
					errorResp = 'file '+file.name+' id('+index+') is not a valid image file';
					parseError(base.options.error, errorResp);
				}
			}
		}

		callPreview = function(){
					resp = { fileinfo: fileArr, error: errorArr};
					resp.count = resp.fileinfo.length;
					parsePreview(base.options.preview, resp);
					if(typeof base.options.error == 'function')
						base.error();
		}

		traverseFiles = function(files){
			if(files.length <= maxfile){
				createWriter(files);
				callPreview();
				}
			else{
				errorResp = "Maximum "+maxfile+" files are allowed";
				parseError(base.options.error, errorResp);
				return false;
			}
		}

		parsePreview = function(MethodOpt, Args){
			if(typeof MethodOpt == 'function'){
				if(Args){
					if(MethodOpt == base.options.error){
						errorArr.push(Args);
					}
					MethodOpt.call(target,Args);
				}				else

					MethodOpt.call(target);
			}
			return false;
		}

		parseError = function(MethodOpt, Args){
			errorArr.push(Args);
			if(typeof MethodOpt == 'function'){
				MethodOpt.call(target,Args);
			}
			return false;
		}

		parseFunc = function(arg){
			arg.call(target);
		}

		clearArr = function(arr){
			if(arr && arr.length > 0){
				$.grep(arr, function(e,i){
					arr.splice(i,arr.length);
				});
			}
			return arr;
		}

		doAjax = function(postFile, array, xhr, callback){

			var file = $(array.shift());
			var fileName = file[0].name;
			var fileSize = file[0].size;
			var fileType = file[0].type;
			var fileSrc = file[0].src;
			var fileHandle = file[0].handle;
			busyFlag = true;
			$.userdata = file;
			provider = function () { return xhr; };
			data = fileSrc.substr(fileSrc.indexOf('base64') + 7);
			$.ajax({
					type: 'POST',
					url: postFile,
					xhr: provider,
					cache: false,
					data: {
						name: fileName,
						size: fileSize,
						type: fileType,
						data: data,
					},
					success: function (data) {
						$.userdata[0].response =  data;
						console.log(resp.fileinfo);
						$.grep(resp.fileinfo, function(e,i){
							if(e.handle == fileHandle)
							{
								resp.fileinfo.splice(i,1);
							}
						});
						callback($.userdata);
						busyFlag = false;
					},
					error: function (data,e1,e2) {
						$(array.unshift(file[0]));
						busyFlag = false;
						console.log(data.statusText);
						resp.count = resp.fileinfo.length;
						errorResp = 'The image could not be saved on server';
						parseError(base.options.error, errorResp);
					}
			}).done(function(){
				if(array.length === 0){
					return false;
				}
				doAjax(postFile,array, xhr,callback);
			});
			resp.count = resp.fileinfo.length;
		}

		/***--------- Public Methods ----------***/

		base.isImage =  function(file){
			if (file.type.match('image.*')) {
				return true;
			}
			return false;
		}

		base.preview = function(arg){
			if(typeof arg === 'undefined')
				return resp;
			else{
				var index = arg;
				try
				{
					if(arg < 1) return false;
					return resp.fileinfo[arg-1];
				}
				catch(exception){
					return false;
				}
			}
		}

		base.uploaded = function(){
			return uploadedArr;
		}

		base.error = function(){
			return (typeof resp == 'object' && resp.error)?resp.error:false;
		}

		base.dropped = function(){
			var x = resp.fileinfo;
			var chk = (x)?x:[];
			var dropped = $.merge( $.merge( [], chk ),  uploadedArr );
			return dropped;
		}

		base.removeAll =  function(arg){
			if(busyFlag == true){
				console.log('File currently under upload. Could not remove the file now');
				return false;
			}
			else{
				if(typeof arg == 'function')
					parseFunc(arg);
				resp.fileinfo = clearArr(resp.fileinfo);
				resp.error = clearArr(resp.error);
				resp.count = 0;
				return resp;
			}
		}

		base.upload = function(arg){
			if(typeof resp != 'undefined' && resp.count)
			{
				var xhr, provider;
				xhr = $.ajaxSettings.xhr();
				if(typeof arg === 'undefined' || arg == ''){
					errorResp = 'Please provide the argument for uploading image';
					parseError(base.options.error, errorResp);
					return false;
				}
				if(typeof arg == 'object' && !arg.file){
					errorResp = 'Please mention a PHP file before uploading';
					parseError(base.options.error, errorResp);
					return false;
				}
				if(typeof(arg.progress) == 'function')
				{
					if (xhr.upload) {
						xhr.upload.addEventListener('progress', function (evt) {
							if (evt.lengthComputable) {
								var percentage = Math.round((evt.loaded / evt.total) * 100);
								$.userdata.progress = percentage;
								arg.progress.call(target,$.userdata);
							}
						}, false);
					}
				}

				var file = (typeof arg == 'object')?arg.file:arg;
				doAjax(file, resp.fileinfo, xhr, function(data){
					$.grep(data, function(e,i){
						uploadedArr.push(data[i]);
					});
					if(typeof(arg.done) == 'function'){
						arg.done.call(target,data);
					}
				});

			}else{
				errorResp = 'No Valid files to upload';
				parseError(base.options.error, errorResp);
				return false;
			}
		}

    };

    $.bhs.uploader.defaultOptions = {
		maxfile: 5
    };

    $.fn.bhs_uploader = function(options){

		var args = Array.prototype.slice.call(arguments, 1);
        return this.each(function(){
				var item = $(this), instance = item.data('bhs_uploader');
				if(!instance) {
					item.data('bhs_uploader', new $.bhs.uploader(this, options));
				} else {
					if(typeof options === 'string') {
						return instance[options].apply(instance, args);
					}
				}
        });
    };

})(jQuery);
<|endoftext|>


<commit_before>/*
 * ace-scroll - jQuery UI Widget
 * Copyright (c) 2011 Jesse Baird
 * *
 * Depends:
 *   - jQuery 1.4
 *   - jQuery UI 1.8.16 (core, widget factory, draggable, position)
 *   - jQuery mousewheel plugin - Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net)
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 *
 * events
 * 	click - user clicked on track or scrollbar
 * 	scroll - the scrollPos has changed
 *
*/
(function($) {

    $.widget("jb.acescroll", {
		options: {
			scrollSpeed: 100,
			animationSpeed: 150,
			orientation: 'vertical',
			//numeric value in % or false to disable(use css value and is always that width)
			minScrollBarWidth: 10,
			//hide the scrollbar if the  content is not scrollable, show it if it is
			//TODO: make work like css overflow property, none, auto, scroll
			autoHide: true,
			//in ms how fast we check the target element for scrollChanges like resize or content chagnes
			//set to 0 to disable
			scrollChangeInterval: 500,
			position: {
				my:'left top',
                at:'right top',
                offset:'5 0',
                collision:'none'
			}
		},
		name: 'jb-ace-scroll',

		_create: function() {

			var self = this,
				options = self.options,
				element = self.element;

			//add the target class first thinng. makes sure the math for the scrollDim will be correct
			element.addClass('jb-ace-scroll-target')

            self.wrapper = $('
'+
            					'
'+
            					'
'+
            						'

'+
            						'

'+
            						'

'+
            						'
'+
            					'
'+
            				'
'
            				).insertAfter(element);

            self.scrollbar = self.wrapper.find('.jb-ace-scroll-scrollbar');

            self.isDragging = false;

            self.wrapper.addClass('jb-ace-scroll-orientation-' + options.orientation )

            if( options.orientation == 'vertical' ){
            	self._scrollProp = 'scrollTop';
            	self._axis = 'y';
            }else{
            	self._scrollProp = 'scrollLeft';
            	self._axis = 'x';
            }

            self._positionWrapper();

            //keep track if the wrapper is visible, used when we check the element for scroll changes
            self._isWrapperVisible = true;

           element
            .bind( 'scroll.' + this.name,function( event ){
            	self._positionScrollbar();

            	self._eventHelper('scroll', event, {} )

            	return self._getScrollDimension('scroll', event, {} );

            })
            .bind( 'mousewheel.' + this.name , function( event, delta, deltaX, deltaY){
        		//console.log( 'mosuewheel', event, delta, deltaX, deltaY );

        		var target = event.target;

        		/*
        		 * if the event target can be scrolled and is not this element, let it do so
        		 * could be a another div with scroll, textarea or another acescroll instance
        		 */
        		if( self._isScrollable( target ) && target != element[ 0 ]){

        			return;
        		}

        		if( self._isVert() ){

        			   var dirY = deltaY > 0 ? 'Up' : 'Down',
		                	vel = (dirY=='Up')?-Math.abs(deltaY):Math.abs(deltaY);
		                	//
		              //  	console.log( this.scrollTop, this.scrollHeight )
		               	if( this[ self._scrollProp ] == 0 && dirY == 'Up' || this[ self._scrollProp ] + self._viewPort == this.scrollHeight && dirY=='Down'  ){
		                    //console.log('up false');
		                    return;
		                }

		                this.scrollTop =+ this.scrollTop + vel * options.scrollSpeed;

        		}else{

        			   var dirX = deltaX > 0 ? 'Right' : 'Left',
                			vel = (dirX=='Left')?-Math.abs(deltaX):Math.abs(deltaX);

		                this.scrollLeft =+ this.scrollLeft + vel * options.scrollSpeed;

        		}

            })
            .bind('resize.' + this.name, function( event ) {
            	self._positionWrapper();
            });

            /*
             * bind events on the track and scrollbar
             *
             */

            //trigger click event
            this.wrapper.delegate( 'div','mousedown', function( event ){
            	return self._eventHelper('click', event, {} )
            })
            //click on the track move to that point
            this.wrapper
            	.find('.jb-ace-scroll-track')
            	.bind('click.' + this.name, function( e ){
            		//figure out the scroll top from the e.layerY
            		if( self._isVert() ){
            			element.animate({
	                    	'scrollTop': self._pixelRatio() * e.layerY
	                	},options.animationSpeed);
            		}else{
            			element.animate({
	                    	'scrollLeft': self._pixelRatio() * e.layerX
	                	},options.animationSpeed);
            		}
            	})
            	.bind('mouseenter.' + this.name,function(){
            		self.wrapper.addClass('jb-state-hover')
            	})
            	.bind('mouseleave.' + this.name,function(){
            		if( self.isDragging == true ){
            			return;
            		}
            		self.wrapper.removeClass('jb-state-hover')
            	})
            	.bind('mousedown.' + this.name,function(){

            		self.wrapper.addClass('jb-state-active')
            	})
            	.bind('mouseup.' + this.name,function(){

            		self.wrapper.removeClass('jb-state-active')
            	})

            this.wrapper.find('div.jb-ace-scroll-scrollbar-btn')
	            .hover(function(e){
	                $(this).toggleClass('jb-state-hover')
	            })
	            //TODO this interaction is kinda funky
	            .bind('click.' + this.name ,function(e){
	            	self.isDragging = true;
	            	var done = function(){
	            		//console.log( 'done')
	            		self.isDragging = false;
	            	}
	                if( self._isVert() ){
            			element.animate({
	                    	'scrollTop':'+='+(($(this).attr('data-dir')=='up')?-self._viewPort:self._viewPort)
	                	},options.animationSpeed,done);
            		}else{
            			element.animate({
	                    	'scrollLeft':'+='+(($(this).attr('data-dir')=='up')?-self._viewPort:self._viewPort)
	                	},options.animationSpeed,done);
            		}

	            })

           this.scrollbar.draggable({
                axis: self._axis,
                containment: 'parent',

                cancel: '.jb-ace-scroll-scrollbar-btn',
                start: function( e, ui ){
                	///if the scrollHeight is the same as the offsetHeight then we can scroll
                	if( self._isScrollable() == false ){
                		return false;
                	}
                	self.isDragging = true;
                	// $(this).addClass('jb-state-active')
                	// self.wrapper.find('.jb-ace-scroll-track').addClass('jb-state-active')
                },
                drag: function(e,ui) {
                	if( self._isVert() ){
                		element[0].scrollTop = self._pixelRatio() * ui.position.top;
                	}else{
                		element[0].scrollLeft = self._pixelRatio() * ui.position.left;
                	}

               },
               stop: function(){
                	self.isDragging = false;
                	// $(this).removeClass('jb-state-active')

                	self.wrapper.removeClass('jb-state-active jb-state-hover')
                }
            });

            //recursively called

            self._handleElementChange();
		},

		destroy: function() {
			this.wrapper.remove();
			//remove wrapper and mouse wheel events
			$(window).unbind("resize");
		},
		//TODO: fix this up
		_setOption: function( key, value) {

			//if( option == 'orientation')
			$.Widget.prototype._setOption.apply( this, arguments );

			switch( key ){
				case 'position':
					this._positionWrapper();
					break;
			}

		},
        /*
            get the ratio of pixs to the target to scroll bar
        */
        _pixelRatio: function(){
          	if( this._isVert() ){
          		return (
          				( this.element[0].scrollHeight - this._viewPort)
          				/
          				( this._viewPort - this.scrollbar.outerHeight() )
          		);
          	}else{
          		return (
          				( this.element[0].scrollWidth - this._viewPort)
          				/
          				( this._viewPort - this.scrollbar.outerWidth() )
          		);
          	}
        },
        //used to set the scrollbar in the right position within the track
        _positionScrollbar: function(){

        	if( this.isDragging ){
        		///if draggging return becuase it messes witht the view
        		return;
        	}
        	if( this._isVert() ){
        		this.scrollbar.css( 'top',  ( this.element[ 0 ].scrollTop / this._pixelRatio()) )
        	}else{
        		this.scrollbar.css( 'left',  ( this.element[ 0 ].scrollLeft / this._pixelRatio()) )
        	}

        },
        //sets the s
        _positionWrapper: function(){
            var css = {},
            	element = this.element;
            if( this._isVert() ){

            	this._viewPort = element.innerHeight();
            	css[ 'height' ] = this._viewPort;

            }else{

				this._viewPort = element.innerWidth();
            	css[ 'width' ] = this._viewPort;
            }

            this.wrapper
	            .css(css)
	            .position( $.extend( this.options.position, { of:this.element}))

	        //since the wrapper _getScrollPosition might have changed make sure the scrollbar postion is perportional to it
	       	//set the width before posiion, insures that the bar doesnt overhang on the track
	        this.setScrollBarWidth();
	        this._positionScrollbar();

        },
        _isVert: function(){
        	return ( this.options.orientation == 'vertical' ) ? true : false;
        },
        /*
         * check if an element can be scrolled
         */
        _isScrollable: function( element ){
        	var isVert = this._isVert(),
        		element = ( element ) ? element : this.element[0];
        	if( element.scrollHeight <= element.offsetHeight && isVert ){
        		//disable reset dragable and disable
        		return false;
        	}else if( element.scrollWidth <= element.offsetWidth && !isVert ){
        		return false;
        	}

        	return true;
        },

        _eventHelper: function( eventName, event, options ){
        	var isVert = this._isVert(),
        		element = this.element[0];

        	return this._trigger(
        		eventName,
        		event,
        		$.extend(
        			{},
        			{
        				scrollDimension: this._getScrollDimension(),
        				scrollPosition: this._getScrollPosition(),
        				viewPort: this._viewPort
        			},
        			options
        		)
        	)
        },

        //make the scrollbar size relitave to the scrollHeight/Width
        setScrollBarWidth: function(){
        	//this.scrollbar
        	//disabled option
        	if( this.options.minScrollBarWidth === false ){
        		return;
        	}
        	//figure out how many "pages" are in the scrollable and devide that by 100 to get the height perenctage
        	var height = 100 / Math.ceil( this._getScrollDimension() / this._viewPort ) ;

        	//console.log( 'height ', height, this._getScrollDimension(), this.element.css('overflow') )

        	if( height < this.options.minScrollBarWidth ){
        		height = this.options.minScrollBarWidth;
        	}
        	if( this._isVert() ){
        		this.scrollbar.css( 'height', height +'%' )
        	}else{
        		this.scrollbar.css( 'width', height +'%' )
        	}

        },
        //returns scrollHeight or scrollWidth depening orentation
        _getScrollDimension: function(){
        	var element = this.element[ 0 ];
        	return ( this._isVert() ) ? element.scrollHeight : element.scrollWidth;
        },
        //get the scrollbar position
        _getScrollPosition: function(){
        	var element = this.element[ 0 ];
        	return ( this._isVert() ) ? element.scrollTop : element.scrollLeft;
        },

        /*
         * ran at an interval
         * 	catches scroll postion and changes and if the element if visible it will show / hide the scrollbar
         */
        _handleElementChange: function(){
        	var self = this,
        		isScrollable = this._isScrollable();

        	if( this._getScrollDimension() != this._prevScrollDimension && this._prevScrollDimension != undefined && isScrollable == true ){

        		this.setScrollBarWidth();

        	//hide the scrollbar if not scrollable
        	}else if( isScrollable == false && this.options.autoHide == true && this._isWrapperVisible == true ){

        		this.wrapper.hide();
        		this._isWrapperVisible = false;

        	}else if( isScrollable == true && this.options.autoHide == true && this._isWrapperVisible == false ){

        		this.wrapper.show();
        		//makes sure it gets positioned on the correctly based on the visible position
        		this._positionWrapper();
        		this._isWrapperVisible = true;

        	}

        	this._prevScrollDimension = this._getScrollDimension();

        	//call again
        	if( this.options.scrollChangeInterval != 0 ){
        		setTimeout(
	        		function(){
	        			self._handleElementChange()
	        		},
	        		this.options.scrollChangeInterval
	        	);
        	}
        }

	});
})(jQuery);<commit_msg>cleaned up _isScrollable now it doesnt depend on the direction set in the options<commit_after>/*
 * ace-scroll - jQuery UI Widget
 * Copyright (c) 2011 Jesse Baird
 * *
 * Depends:
 *   - jQuery 1.4
 *   - jQuery UI 1.8.16 (core, widget factory, draggable, position)
 *   - jQuery mousewheel plugin - Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net)
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 *
 * events
 * 	click - user clicked on track or scrollbar
 * 	scroll - the scrollPos has changed
 *
*/
(function($) {

	var abs = Math.abs;

    $.widget("jb.acescroll", {
		options: {
			scrollSpeed: 100,
			animationSpeed: 150,
			orientation: 'vertical',
			//numeric value in % or false to disable(use css value and is always that width)
			minScrollBarWidth: 10,
			//hide the scrollbar if the  content is not scrollable, show it if it is
			//TODO: make work like css overflow property, none, auto, scroll
			autoHide: true,
			//in ms how fast we check the target element for scrollChanges like resize or content chagnes
			//set to 0 to disable
			scrollChangeInterval: 500,
			position: {
				my:'left top',
                at:'right top',
                offset:'5 0',
                collision:'none'
			}
		},
		name: 'jb-ace-scroll',

		_create: function() {

			var self = this,
				options = self.options,
				element = self.element;

			//add the target class first thinng. makes sure the math for the scrollDim will be correct
			element.addClass('jb-ace-scroll-target')

            self.wrapper = $('
'+
            					'
'+
            					'
'+
            						'

'+
            						'

'+
            						'

'+
            						'
'+
            					'
'+
            				'
'
            				).insertAfter(element);

            self.scrollbar = self.wrapper.find('.jb-ace-scroll-scrollbar');

            self.isDragging = false;

            self.wrapper.addClass('jb-ace-scroll-orientation-' + options.orientation )

            if( options.orientation == 'vertical' ){
            	self._scrollProp = 'scrollTop';
            	self._axis = 'y';
            }else{
            	self._scrollProp = 'scrollLeft';
            	self._axis = 'x';
            }

            self._positionWrapper();

            //keep track if the wrapper is visible, used when we check the element for scroll changes
            self._isWrapperVisible = true;

           element
            .bind( 'scroll.' + this.name,function( event ){
            	self._positionScrollbar();

            	self._eventHelper('scroll', event, {} )

            	return self._getScrollDimension('scroll', event, {} );

            })
            .bind( 'mousewheel.' + this.name , function( event, delta, deltaX, deltaY){
        		//console.log( 'mosuewheel', event, delta, deltaX, deltaY );

        		var target = event.target;
        		//console.log( target, self._isScrollable( target ))
        		/*
        		 * if the event target can be scrolled and is not this element, let it do so
        		 * could be a another div with scroll, textarea or another acescroll instance
        		 */
        		if( self._isScrollable( target ) && target != element[ 0 ]){
        			return;
        		}
        		//vertical
        		if( self._isVert() ){

        			   var dirY = deltaY > 0 ? 'Up' : 'Down',
		                	vel = (dirY=='Up')?-Math.abs(deltaY):Math.abs(deltaY);

		               	if( this[ self._scrollProp ] == 0 && dirY == 'Up' || this[ self._scrollProp ] + self._viewPort == this.scrollHeight && dirY=='Down'  ){
		               		//can't scroll any more
		                    return;
		                }else{
		                	//only prevent the default if we can can scroll on this element
		                	this.scrollTop =+ this.scrollTop + vel * options.scrollSpeed;
		                	return false;
		                }

        		}else{
        			//horizontal

        			   var dirX = deltaX > 0 ? 'Right' : 'Left',
                			vel = (dirX=='Left')?-abs(deltaX):abs(deltaX);
		                //TODO: add scroll check like vertical has, i currenty dont have a mouse that has horz scrolling
		                this.scrollLeft =+ this.scrollLeft + vel * options.scrollSpeed;

        		}

            })
            .bind('resize.' + this.name, function( event ) {
            	self._positionWrapper();
            });

            /*
             * bind events on the track and scrollbar
             *
             */

            //trigger click event
            this.wrapper.delegate( 'div','mousedown', function( event ){
            	return self._eventHelper('click', event, {} )
            })
            //click on the track move to that point
            this.wrapper
            	.find('.jb-ace-scroll-track')
            	.bind('click.' + this.name, function( e ){
            		//figure out the scroll top from the e.layerY
            		if( self._isVert() ){
            			element.animate({
	                    	'scrollTop': self._pixelRatio() * e.layerY
	                	},options.animationSpeed);
            		}else{
            			element.animate({
	                    	'scrollLeft': self._pixelRatio() * e.layerX
	                	},options.animationSpeed);
            		}
            	})
            	.bind('mouseenter.' + this.name,function(){
            		self.wrapper.addClass('jb-state-hover')
            	})
            	.bind('mouseleave.' + this.name,function(){
            		if( self.isDragging == true ){
            			return;
            		}
            		self.wrapper.removeClass('jb-state-hover')
            	})
            	.bind('mousedown.' + this.name,function(){

            		self.wrapper.addClass('jb-state-active')
            	})
            	.bind('mouseup.' + this.name,function(){

            		self.wrapper.removeClass('jb-state-active')
            	})

            this.wrapper.find('div.jb-ace-scroll-scrollbar-btn')
	            .hover(function(e){
	                $(this).toggleClass('jb-state-hover')
	            })
	            //TODO this interaction is kinda funky
	            .bind('click.' + this.name ,function(e){
	            	self.isDragging = true;
	            	var done = function(){
	            		//console.log( 'done')
	            		self.isDragging = false;
	            	}
	                if( self._isVert() ){
            			element.animate({
	                    	'scrollTop':'+='+(($(this).attr('data-dir')=='up')?-self._viewPort:self._viewPort)
	                	},options.animationSpeed,done);
            		}else{
            			element.animate({
	                    	'scrollLeft':'+='+(($(this).attr('data-dir')=='up')?-self._viewPort:self._viewPort)
	                	},options.animationSpeed,done);
            		}

	            })

           this.scrollbar.draggable({
                axis: self._axis,
                containment: 'parent',

                cancel: '.jb-ace-scroll-scrollbar-btn',
                start: function( e, ui ){
                	///if the scrollHeight is the same as the offsetHeight then we can scroll
                	if( self._isScrollable( element[ 0 ] ) == false ){
                		return false;
                	}
                	self.isDragging = true;
                	// $(this).addClass('jb-state-active')
                	// self.wrapper.find('.jb-ace-scroll-track').addClass('jb-state-active')
                },
                drag: function(e,ui) {
                	if( self._isVert() ){
                		element[0].scrollTop = self._pixelRatio() * ui.position.top;
                	}else{
                		element[0].scrollLeft = self._pixelRatio() * ui.position.left;
                	}

               },
               stop: function(){
                	self.isDragging = false;
                	// $(this).removeClass('jb-state-active')

                	self.wrapper.removeClass('jb-state-active jb-state-hover')
                }
            });

            //recursively called

            self._handleElementChange();
		},

		destroy: function() {
			this.wrapper.remove();
			//remove wrapper and mouse wheel events
			$(window).unbind("resize");
		},
		//TODO: fix this up
		_setOption: function( key, value) {

			//if( option == 'orientation')
			$.Widget.prototype._setOption.apply( this, arguments );

			switch( key ){
				case 'position':
					this._positionWrapper();
					break;
			}

		},
        /*
            get the ratio of pixs to the target to scroll bar
        */
        _pixelRatio: function(){
          	if( this._isVert() ){
          		return (
          				( this.element[0].scrollHeight - this._viewPort)
          				/
          				( this._viewPort - this.scrollbar.outerHeight() )
          		);
          	}else{
          		return (
          				( this.element[0].scrollWidth - this._viewPort)
          				/
          				( this._viewPort - this.scrollbar.outerWidth() )
          		);
          	}
        },
        //used to set the scrollbar in the right position within the track
        _positionScrollbar: function(){

        	if( this.isDragging ){
        		///if draggging return becuase it messes witht the view
        		return;
        	}
        	if( this._isVert() ){
        		this.scrollbar.css( 'top',  ( this.element[ 0 ].scrollTop / this._pixelRatio()) )
        	}else{
        		this.scrollbar.css( 'left',  ( this.element[ 0 ].scrollLeft / this._pixelRatio()) )
        	}

        },
        //sets the s
        _positionWrapper: function(){
            var css = {},
            	element = this.element;
            if( this._isVert() ){

            	this._viewPort = element.innerHeight();
            	css[ 'height' ] = this._viewPort;

            }else{

				this._viewPort = element.innerWidth();
            	css[ 'width' ] = this._viewPort;
            }

            this.wrapper
	            .css(css)
	            .position( $.extend( this.options.position, { of:this.element}))

	        //since the wrapper _getScrollPosition might have changed make sure the scrollbar postion is perportional to it
	       	//set the width before posiion, insures that the bar doesnt overhang on the track
	        this.setScrollBarWidth();
	        this._positionScrollbar();

        },
        _isVert: function(){
        	return ( this.options.orientation == 'vertical' ) ? true : false;
        },
        /*
         * check if an element can be scrolled
         */
        _isScrollable: function( element ){
        	if( element.scrollHeight > element.offsetHeight || element.scrollWidth > element.offsetWidth ){
        		return true;
        	}

        	return false;
        },

        _eventHelper: function( eventName, event, options ){
        	var isVert = this._isVert(),
        		element = this.element[0];

        	return this._trigger(
        		eventName,
        		event,
        		$.extend(
        			{},
        			{
        				scrollDimension: this._getScrollDimension(),
        				scrollPosition: this._getScrollPosition(),
        				viewPort: this._viewPort
        			},
        			options
        		)
        	)
        },

        //make the scrollbar size relitave to the scrollHeight/Width
        setScrollBarWidth: function(){
        	//this.scrollbar
        	//disabled option
        	if( this.options.minScrollBarWidth === false ){
        		return;
        	}
        	//figure out how many "pages" are in the scrollable and devide that by 100 to get the height perenctage
        	var height = 100 / Math.ceil( this._getScrollDimension() / this._viewPort ) ;

        	//console.log( 'height ', height, this._getScrollDimension(), this.element.css('overflow') )

        	if( height < this.options.minScrollBarWidth ){
        		height = this.options.minScrollBarWidth;
        	}
        	if( this._isVert() ){
        		this.scrollbar.css( 'height', height +'%' )
        	}else{
        		this.scrollbar.css( 'width', height +'%' )
        	}

        },
        //returns scrollHeight or scrollWidth depening orentation
        _getScrollDimension: function(){
        	var element = this.element[ 0 ];
        	return ( this._isVert() ) ? element.scrollHeight : element.scrollWidth;
        },
        //get the scrollbar position
        _getScrollPosition: function(){
        	var element = this.element[ 0 ];
        	return ( this._isVert() ) ? element.scrollTop : element.scrollLeft;
        },

        /*
         * ran at an interval
         * 	catches scroll postion and changes and if the element if visible it will show / hide the scrollbar
         */
        _handleElementChange: function(){
        	var self = this,
        		isScrollable = this._isScrollable( this.element[ 0 ] );

        	if( this._getScrollDimension() != this._prevScrollDimension && this._prevScrollDimension != undefined && isScrollable == true ){

        		this.setScrollBarWidth();

        	//hide the scrollbar if not scrollable
        	}else if( isScrollable == false && this.options.autoHide == true && this._isWrapperVisible == true ){

        		this.wrapper.hide();
        		this._isWrapperVisible = false;

        	}else if( isScrollable == true && this.options.autoHide == true && this._isWrapperVisible == false ){

        		this.wrapper.show();
        		//makes sure it gets positioned on the correctly based on the visible position
        		this._positionWrapper();
        		this._isWrapperVisible = true;

        	}

        	this._prevScrollDimension = this._getScrollDimension();

        	//call again
        	if( this.options.scrollChangeInterval != 0 ){
        		setTimeout(
	        		function(){
	        			self._handleElementChange()
	        		},
	        		this.options.scrollChangeInterval
	        	);
        	}
        }

	});
})(jQuery);<|endoftext|>