<commit_before>import { registerOption } from 'pretty-text/pretty-text';

registerOption((siteSettings, opts) => {
  opts.features.furigana = !!siteSettings.furigana_enabled;
  opts.furiganaForms = siteSettings.furigana_plugin_forms;
  opts.furiganaFallbackBrackets = siteSettings.furigana_fallback_brackets;
});

// This function escapes special characters for use in a regex constructor.
function escapeForRegex(string) {
  return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}

let regexList = [];
let previousFuriganaForms = '';

function updateRegexList(furiganaForms) {
  previousFuriganaForms = furiganaForms;
  const innerRegexString = '(?:[^\\u0000-\\u007F]|\\w)+';
  let formArray = furiganaForms.split('|');
  if (formArray.length === 0) {
    formArray = ['[]:^:()'];
  }
  regexList = formArray.map(form => {
    let furiganaComponents = form.split(':');
    if (furiganaComponents.length !== 3) {
      furiganaComponents = ['[]', '^', '()'];
    }
    const mainBrackets = furiganaComponents[0];
    const seperator = furiganaComponents[1];
    const furiganaBrackets = furiganaComponents[2];
    return new RegExp(
      escapeForRegex(mainBrackets[0]) +
      '(' + innerRegexString + ')' +
      escapeForRegex(mainBrackets[1]) +
      escapeForRegex(seperator) +
      escapeForRegex(furiganaBrackets[0]) +
      '(' + innerRegexString + ')' +
      escapeForRegex(furiganaBrackets[1]),
      'g'
    );
  });
}

let replacementTemplate = '';
let replacementBrackets = '';

function updateReplacementTemplate(furiganaFallbackBrackets) {
  if (furiganaFallbackBrackets.length !== 2) {
    furiganaFallbackBrackets = '【】';
  }
  replacementBrackets = furiganaFallbackBrackets;
  replacementTemplate = `<ruby>$1<rp>${furiganaFallbackBrackets[0]}</rp><rt>$2</rt><rp>${furiganaFallbackBrackets[1]}</rp></ruby>`;
}

updateReplacementTemplate('【】');

function addFurigana(text, options) {
  if (options.furiganaForms !== previousFuriganaForms) {
    updateRegexList(options.furiganaForms);
  }
  if (options.furiganaFallbackBrackets !== replacementBrackets) {
    updateReplacementTemplate(options.furiganaFallbackBrackets);
  }
  regexList.forEach(regex => {
    text = text.replace(regex, (match, match1, match2, offset, mainText) => {
      if (match.indexOf('\\') === -1 && mainText[offset - 1] !== '\\') {
        return replacementTemplate.replace('$1', match1).replace('$2', match2);
      } else {
        return match;
      }
    });
  });
  return text;
}

export function setup(helper) {
  helper.whiteList([
    'ruby',
    'rt',
    'rp'
  ]);

  helper.addPreProcessor(text => {
    return addFurigana(text, helper.getOptions());
  });
}
<commit_msg>Remove backslashes from escaped 【】<commit_after>import { registerOption } from 'pretty-text/pretty-text';

registerOption((siteSettings, opts) => {
  opts.features.furigana = !!siteSettings.furigana_enabled;
  opts.furiganaForms = siteSettings.furigana_plugin_forms;
  opts.furiganaFallbackBrackets = siteSettings.furigana_fallback_brackets;
});

// This function escapes special characters for use in a regex constructor.
function escapeForRegex(string) {
  return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}

let regexList = [];
let previousFuriganaForms = '';

function updateRegexList(furiganaForms) {
  previousFuriganaForms = furiganaForms;
  const innerRegexString = '(?:[^\\u0000-\\u007F]|\\w)+';
  let formArray = furiganaForms.split('|');
  if (formArray.length === 0) {
    formArray = ['[]:^:()'];
  }
  regexList = formArray.map(form => {
    let furiganaComponents = form.split(':');
    if (furiganaComponents.length !== 3) {
      furiganaComponents = ['[]', '^', '()'];
    }
    const mainBrackets = furiganaComponents[0];
    const seperator = furiganaComponents[1];
    const furiganaBrackets = furiganaComponents[2];
    return new RegExp(
      escapeForRegex(mainBrackets[0]) +
      '(' + innerRegexString + ')' +
      escapeForRegex(mainBrackets[1]) +
      escapeForRegex(seperator) +
      escapeForRegex(furiganaBrackets[0]) +
      '(' + innerRegexString + ')' +
      escapeForRegex(furiganaBrackets[1]),
      'g'
    );
  });
}

let replacementTemplate = '';
let replacementBrackets = '';

function updateReplacementTemplate(furiganaFallbackBrackets) {
  if (furiganaFallbackBrackets.length !== 2) {
    furiganaFallbackBrackets = '【】';
  }
  replacementBrackets = furiganaFallbackBrackets;
  replacementTemplate = `<ruby>$1<rp>${furiganaFallbackBrackets[0]}</rp><rt>$2</rt><rp>${furiganaFallbackBrackets[1]}</rp></ruby>`;
}

updateReplacementTemplate('【】');

function addFurigana(text, options) {
  if (options.furiganaForms !== previousFuriganaForms) {
    updateRegexList(options.furiganaForms);
  }
  if (options.furiganaFallbackBrackets !== replacementBrackets) {
    updateReplacementTemplate(options.furiganaFallbackBrackets);
  }
  regexList.forEach(regex => {
    text = text.replace(regex, (match, match1, match2, offset, mainText) => {
      if (match.indexOf('\\') === -1 && mainText[offset - 1] !== '\\') {
        return replacementTemplate.replace('$1', match1).replace('$2', match2);
      } else {
        return match;
      }
    });
  });
  return text;
}

function handleEscapedSpecialBrackets(text) {
  // By default 【 and 】 cannot be escaped in markdown, this will remove backslashes from in front of them to give that effect.
  return text.replace(/\\([【】])/g, '$1');
}

export function setup(helper) {
  helper.whiteList([
    'ruby',
    'rt',
    'rp'
  ]);

  helper.addPreProcessor(text => {
    return handleEscapedSpecialBrackets(addFurigana(text, helper.getOptions()));
  });
}
<|endoftext|>


<commit_before>const parser = require('../src/parser.js');
const JSDOM = require('jsdom').JSDOM;
const fs = require('fs');
const HTML = fs.readFileSync(__dirname + "/test.html");
const dom = new JSDOM(HTML);
const assert = require('assert');

let posts = Array.from(dom.window.document.querySelectorAll(".fbUserContent"));
let ads = posts.map((i) => parser(i, "Sponsored")).filter((i) => i);
assert.equal(ads.length, 2, "Found two ads");
assert.equal(ads[0].id, "hyperfeed_story_id_5944756a18bdf2794599305", "Got an ad");
<commit_msg>all tests<commit_after>const parser = require('../src/parser.js');
const JSDOM = require('jsdom').JSDOM;
const fs = require('fs');
const HTML = fs.readFileSync(__dirname + "/test.html");
const dom = new JSDOM(HTML);
const assert = require('assert');

let posts = Array.from(dom.window.document.querySelectorAll(".fbUserContent"));
let ads = posts.map((i) => parser(i, "Sponsored")).filter((i) => i);
assert.equal(ads.length, 2, "Found two ads");
assert.equal(ads[0].id, "hyperfeed_story_id_5944756a18bdf2794599305", "Got an ad");
assert.equal(ads[1].id, "hyperfeed_story_id_594474fe329fb7047789758", "Found the other.");
<|endoftext|>


<commit_before>(function (Root, $) {

    'use strict';

    function addEventHandler(p_sSubject, p_oPoints, p_oCriteria, p_iCriteriaIndex) {
        var sOpposite;

        switch (p_sSubject) {
            case 'upper':
                sOpposite = 'lower';
                break;
            case 'lower':
                sOpposite = 'upper';
                break;
        }

        p_oCriteria[p_sSubject].addClass('criteria__selector criteria__selector--' + p_sSubject);

        p_oCriteria[p_sSubject].on('click', function (/*p_oEvent*/) {
            var iScoreIndex, iTotalScore, oScores, sScoreJson;

            p_oCriteria[p_sSubject].addClass('criteria__selector--selected');
            p_oCriteria[sOpposite].removeClass('criteria__selector--selected');

            sScoreJson = $Score.attr('data-score');
            oScores = JSON.parse(sScoreJson);

            oScores[p_iCriteriaIndex] = p_oPoints[p_sSubject];

            $Score.attr('data-score', JSON.stringify(oScores));

            iTotalScore = 0;

            for (iScoreIndex in oScores) {
                if( oScores.hasOwnProperty(iScoreIndex)) {
                    iTotalScore += oScores[iScoreIndex];
                }
            }

            $Score.val(Math.floor(iTotalScore) + '%');
        });
    }

    var aCriteria = [], oPoints, $Help, $Score, $Table;

    $Table = $('.protocols-estimating-developer-pain-criteria table');

    $Table.find('tbody tr').each(function (p_iRowIndex, p_oRowElement) {

        var oCriteria = {};

        $(p_oRowElement).find('td').each(function (p_iCellIndex, p_oCellElement) {

            var sKey;

            switch (p_iCellIndex) {
                case 0:
                    sKey = 'lower';
                    break;
                case 1:
                    sKey = 'upper';
                    break;
                case 2:
                    sKey = 'info';
                    break;
            }

            oCriteria[sKey] = $(p_oCellElement);
        });

        aCriteria.push(oCriteria);
    });

    $Score = $('<input type="text" class="criteria__score" data-score="{}" readonly />');
    $Help = $('
' +
        '' +
        'To calculate the developer pain for a given issue, ' +
        'please select the most appropriate cells in the table below.' +
        '
'
    );

    $Score.insertBefore($Table.parent());
    $Help.insertAfter($Score);

    oPoints = {'lower': 10 / aCriteria.length, 'upper': 100 / aCriteria.length};

    $.each(aCriteria, function (p_iCriteriaIndex, p_oCriteria) {
        addEventHandler('lower', oPoints, p_oCriteria, p_iCriteriaIndex);
        addEventHandler('upper', oPoints, p_oCriteria, p_iCriteriaIndex);

    });
})(document, jQuery);
<commit_msg>CHANGE: Cleanup for protocols-estimating-developer-pain-criteria.js file<commit_after>(function (Root, $) {

    'use strict';

    function addEventHandler(p_sSubject, p_oPoints, p_oCriteria, p_iCriteriaIndex) {
        var sOpposite;

        switch (p_sSubject) {
            case 'upper':
                sOpposite = 'lower';
                break;
            case 'lower':
                sOpposite = 'upper';
                break;
        }

        p_oCriteria[p_sSubject].addClass('criteria__selector criteria__selector--' + p_sSubject);

        p_oCriteria[p_sSubject].on('click', function (/*p_oEvent*/) {
            var iScoreIndex, iTotalScore, oScores, sScoreJson;

            p_oCriteria[p_sSubject].addClass('criteria__selector--selected');
            p_oCriteria[sOpposite].removeClass('criteria__selector--selected');

            sScoreJson = $Score.attr('data-score');
            oScores = JSON.parse(sScoreJson);

            oScores[p_iCriteriaIndex] = p_oPoints[p_sSubject];

            $Score.attr('data-score', JSON.stringify(oScores));

            iTotalScore = 0;

            for (iScoreIndex in oScores) {
                if( oScores.hasOwnProperty(iScoreIndex)) {
                    iTotalScore += oScores[iScoreIndex];
                }
            }

            $Score.val(Math.floor(iTotalScore) + '%');
        });
    }

    function retrieveRows(p_iRowIndex, p_oRowElement) {

        var oCriteria = {};

        $(p_oRowElement).find('td').each(function (p_iCellIndex, p_oCellElement) {

            var sKey;

            switch (p_iCellIndex) {
                case 0:
                    sKey = 'lower';
                    break;
                case 1:
                    sKey = 'upper';
                    break;
                case 2:
                    sKey = 'info';
                    break;
            }

            oCriteria[sKey] = $(p_oCellElement);
        });

        aCriteria.push(oCriteria);
    }

    function main (p_sTableSelector) {
        var aCriteria = [], oPoints, $Help, $Score, $Table;

        $Table = $(p_sTableSelector);

        $Table.find('tbody tr').each(retrieveRows);

        $Score = $('<input type="text" class="criteria__score" data-score="{}" readonly />');

        $Help = $('
' +
            '' +
            'To calculate the developer pain for a given issue, ' +
            'please select the most appropriate cells in the table below.' +
            '
'
        );

        $Score.insertBefore($Table.parent());
        $Help.insertAfter($Score);

        oPoints = {'lower': 10 / aCriteria.length, 'upper': 100 / aCriteria.length};

        $.each(aCriteria, function (p_iCriteriaIndex, p_oCriteria) {
            addEventHandler('lower', oPoints, p_oCriteria, p_iCriteriaIndex);
            addEventHandler('upper', oPoints, p_oCriteria, p_iCriteriaIndex);

        });
    }

    $('.criteria sup').addClass('hidden');

    main('.protocols-estimating-developer-pain-criteria table');

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


<commit_before>// Extensions

// keep this wrapper around the ones you use!
(function( undefined ){

	wrap.fn.parent = function(){
		var ret = [],
			parent;
		this.each(function(){
			parent = this.parentElement;
			if( parent ){
				ret.push( parent );
			}
		});
		return wrap(ret);
	};

	wrap.fn.parents = function( sel ){
		var ret = [];

		this.each(function(){
			var curr = this,
				match;
			while( curr.parentElement && !match ){
				curr = curr.parentElement;
				if( sel ){
					if( curr === wrap( sel )[0] ){
						match = true;
						if( !wrap.inArray( ret, curr ) ){
							ret.push( curr );
						}
					}
				}
				else {
					if( !wrap.inArray( ret, curr ) ){
						ret.push( curr );
					}
				}
			}
		});
		return wrap(ret);
	};

	wrap.fn.children = function(){
		var ret = [],
			childs;
		this.each(function(){
			childs = this.children,
			j = -1;

			while( j++ < childs.length-1 ){
				if( !wrap.inArray( ret, childs[ j ] ) ){
					ret.push( childs[ j ] );
				}
			}
		});
		return wrap(ret);
	};

	wrap.fn.next = function(){
		var ret = [],
			next;
		this.each(function( i ){
			next = this.nextElementSibling;
			if( next ){
				ret = ret.concat( next );
			}
		});
		return wrap(ret);
	};

	wrap.fn.prev = function(){
		var ret = [],
			next;
		this.each(function( i ){
			next = this.previousElementSibling;
			if( next ){
				ret = ret.concat( next );
			}
		});
		return wrap(ret);
	};

	wrap.fn.addClass = function( cname ){
		return this.each(function(){
			this.className += " " + cname;
		});
	};

	wrap.fn.removeClass = function( cname ){
		return this.each(function(){
			this.className = this.className.replace( new RegExp( cname, "gmi" ), "" );
		});
	};

	wrap.fn.attr = function( name, val ){
		if( val !== undefined ){
			return this.each(function(){
				this.setAttribute( name, val );
			});
		}
		else {
			return this[ 0 ].getAttribute( name );
		}
	};

	wrap.fn.html = function( html ){
		if( html ){
			return this.each(function(){
				this.innerHTML = html;
			});
		}
		else{
			var pile = "";
			return this.each(function(){
				pile += this.innerHTML;
			});
			return pile;
		}
	};

	wrap.fn.append = function( frag ){
		if( typeof( frag ) === "string" ){
			frag = wrap( frag );
		}
		return this.each(function( i ){
			for( var j = 0, jl = frag.length; j < jl; j++ ){
				this.appendChild( i > 0 ? frag[ j ].cloneNode( true ) : frag[ j ] );
			}
		});
	};

	wrap.fn.prepend = function( frag ){
		if( typeof( frag ) === "string" ){
			frag = wrap( frag );
		}
		return this.each(function( i ){
			for( var j = 0, jl = frag.length; j < jl; j++ ){
				var insertEl = i > 0 ? frag[ j ].cloneNode( true ) : frag[ j ];
				if ( this.firstChild ){
					this.insertBefore( insertEl, this.firstChild );
				}
				else {
					this.appendChild( insertEl );
				}
			}
		});
	};

	wrap.fn.before = function( frag ){
		if( typeof( frag ) === "string" ){
			frag = wrap( frag );
		}
		return this.each(function( i ){
			for( var j = 0, jl = frag.length; j < jl; j++ ){
				this.parentNode.insertBefore( i > 0 ? frag[ j ].cloneNode( true ) : frag[ j ], this );
			}
		});
	};

	wrap.fn.after = function( frag ){
		if( typeof( frag ) === "string" ){
			frag = wrap( frag );
		}
		return this.each(function( i ){
			for( var j = 0, jl = frag.length; j < jl; j++ ){
				var insertEl = i > 0 ? frag[ j ].cloneNode( true ) : frag[ j ];
				this.parentNode.insertBefore( insertEl, this );
				this.parentNode.insertBefore( this, insertEl );
			}
		});
	};

})();<commit_msg>added replaceWith method<commit_after>// Extensions

// keep this wrapper around the ones you use!
(function( undefined ){

	wrap.fn.parent = function(){
		var ret = [],
			parent;
		this.each(function(){
			parent = this.parentElement;
			if( parent ){
				ret.push( parent );
			}
		});
		return wrap(ret);
	};

	wrap.fn.parents = function( sel ){
		var ret = [];

		this.each(function(){
			var curr = this,
				match;
			while( curr.parentElement && !match ){
				curr = curr.parentElement;
				if( sel ){
					if( curr === wrap( sel )[0] ){
						match = true;
						if( !wrap.inArray( ret, curr ) ){
							ret.push( curr );
						}
					}
				}
				else {
					if( !wrap.inArray( ret, curr ) ){
						ret.push( curr );
					}
				}
			}
		});
		return wrap(ret);
	};

	wrap.fn.children = function(){
		var ret = [],
			childs;
		this.each(function(){
			childs = this.children,
			j = -1;

			while( j++ < childs.length-1 ){
				if( !wrap.inArray( ret, childs[ j ] ) ){
					ret.push( childs[ j ] );
				}
			}
		});
		return wrap(ret);
	};

	wrap.fn.next = function(){
		var ret = [],
			next;
		this.each(function( i ){
			next = this.nextElementSibling;
			if( next ){
				ret = ret.concat( next );
			}
		});
		return wrap(ret);
	};

	wrap.fn.prev = function(){
		var ret = [],
			next;
		this.each(function( i ){
			next = this.previousElementSibling;
			if( next ){
				ret = ret.concat( next );
			}
		});
		return wrap(ret);
	};

	wrap.fn.addClass = function( cname ){
		return this.each(function(){
			this.className += " " + cname;
		});
	};

	wrap.fn.removeClass = function( cname ){
		return this.each(function(){
			this.className = this.className.replace( new RegExp( cname, "gmi" ), "" );
		});
	};

	wrap.fn.attr = function( name, val ){
		if( val !== undefined ){
			return this.each(function(){
				this.setAttribute( name, val );
			});
		}
		else {
			return this[ 0 ].getAttribute( name );
		}
	};

	wrap.fn.html = function( html ){
		if( html ){
			return this.each(function(){
				this.innerHTML = html;
			});
		}
		else{
			var pile = "";
			return this.each(function(){
				pile += this.innerHTML;
			});
			return pile;
		}
	};

	wrap.fn.append = function( frag ){
		if( typeof( frag ) === "string" ){
			frag = wrap( frag );
		}
		return this.each(function( i ){
			for( var j = 0, jl = frag.length; j < jl; j++ ){
				this.appendChild( i > 0 ? frag[ j ].cloneNode( true ) : frag[ j ] );
			}
		});
	};

	wrap.fn.prepend = function( frag ){
		if( typeof( frag ) === "string" ){
			frag = wrap( frag );
		}
		return this.each(function( i ){
			for( var j = 0, jl = frag.length; j < jl; j++ ){
				var insertEl = i > 0 ? frag[ j ].cloneNode( true ) : frag[ j ];
				if ( this.firstChild ){
					this.insertBefore( insertEl, this.firstChild );
				}
				else {
					this.appendChild( insertEl );
				}
			}
		});
	};

	wrap.fn.before = function( frag ){
		if( typeof( frag ) === "string" ){
			frag = wrap( frag );
		}
		return this.each(function( i ){
			for( var j = 0, jl = frag.length; j < jl; j++ ){
				this.parentNode.insertBefore( i > 0 ? frag[ j ].cloneNode( true ) : frag[ j ], this );
			}
		});
	};

	wrap.fn.after = function( frag ){
		if( typeof( frag ) === "string" ){
			frag = wrap( frag );
		}
		return this.each(function( i ){
			for( var j = 0, jl = frag.length; j < jl; j++ ){
				var insertEl = i > 0 ? frag[ j ].cloneNode( true ) : frag[ j ];
				this.parentNode.insertBefore( insertEl, this );
				this.parentNode.insertBefore( this, insertEl );
			}
		});
	};

	wrap.fn.replaceWith = function( frag ){
		if( typeof( frag ) === "string" ){
			frag = wrap( frag );
		}
		var ret = [];
		this.each(function( i ){
			for( var j = 0, jl = frag.length; j < jl; j++ ){
				var insertEl = i > 0 ? frag[ j ].cloneNode( true ) : frag[ j ];
				this.parentNode.insertBefore( insertEl, this );
				insertEl.parentNode.removeChild( this );
				ret.push( insertEl );
			}
		});
		return wrap( ret );
	};

})();<|endoftext|>


<commit_before>/**
 * Synchronize zooming and/or selections between a set of dygraphs.
 *
 * Usage:
 *
 *   var g1 = new Dygraph(...),
 *       g2 = new Dygraph(...),
 *       ...;
 *   var sync = Dygraph.synchronize(g1, g2, ...);
 *   // charts are now synchronized
 *   sync.detach();
 *   // charts are no longer synchronized
 *
 * You can set options using the last parameter, for example:
 *
 *   var sync = Dygraph.synchronize(g1, g2, g3, {
 *      selection: true,
 *      zoom: true
 *   });
 *
 * The default is to synchronize both of these.
 *
 * Instead of passing one Dygraph object as each parameter, you may also pass an
 * array of dygraphs:
 *
 *   var sync = Dygraph.synchronize([g1, g2, g3], {
 *      selection: false,
 *      zoom: true
 *   });
 *
 * You may also set `range: false` if you wish to only sync the x-axis.
 * The `range` option has no effect unless `zoom` is true (the default).
 */
(function() {
/* global Dygraph:false */
'use strict';

Dygraph.synchronize = function(/* dygraphs..., opts */) {
  if (arguments.length === 0) {
    throw 'Invalid invocation of Dygraph.synchronize(). Need >= 1 argument.';
  }

  var OPTIONS = ['selection', 'zoom', 'range'];
  var opts = {
    selection: true,
    zoom: true,
    range: true
  };
  var dygraphs = [];

  var prevCallbacks = {
    draw: null,
    highlight: null,
    unhighlight: null
  };

  var parseOpts = function(obj) {
    if (!(obj instanceof Object)) {
      throw 'Last argument must be either Dygraph or Object.';
    } else {
      for (var i = 0; i < OPTIONS.length; i++) {
        var optName = OPTIONS[i];
        if (obj.hasOwnProperty(optName)) opts[optName] = obj[optName];
      }
    }
  };

  if (arguments[0] instanceof Dygraph) {
    // Arguments are Dygraph objects.
    for (var i = 0; i < arguments.length; i++) {
      if (arguments[i] instanceof Dygraph) {
        dygraphs.push(arguments[i]);
      } else {
        break;
      }
    }
    if (i < arguments.length - 1) {
      throw 'Invalid invocation of Dygraph.synchronize(). ' +
            'All but the last argument must be Dygraph objects.';
    } else if (i == arguments.length - 1) {
      parseOpts(arguments[arguments.length - 1]);
    }
  } else if (arguments[0].length) {
    // Invoked w/ list of dygraphs, options
    for (var i = 0; i < arguments[0].length; i++) {
      dygraphs.push(arguments[0][i]);
    }
    if (arguments.length == 2) {
      parseOpts(arguments[1]);
    } else if (arguments.length > 2) {
      throw 'Invalid invocation of Dygraph.synchronize(). ' +
            'Expected two arguments: array and optional options argument.';
    }  // otherwise arguments.length == 1, which is fine.
  } else {
    throw 'Invalid invocation of Dygraph.synchronize(). ' +
          'First parameter must be either Dygraph or list of Dygraphs.';
  }

  if (dygraphs.length < 2) {
    throw 'Invalid invocation of Dygraph.synchronize(). ' +
          'Need two or more dygraphs to synchronize.';
  }

  // Listen for draw, highlight, unhighlight callbacks.
  if (opts.zoom) {
    attachZoomHandlers(dygraphs, opts, prevCallbacks);
  }

  if (opts.selection) {
    attachSelectionHandlers(dygraphs, prevCallbacks);
  }

  return {
    detach: function() {
      for (var i = 0; i < dygraphs.length; i++) {
        var g = dygraphs[i];
        if (opts.zoom) {
          g.updateOptions({drawCallback: prevCallbacks.draw});
        }
        if (opts.selection) {
          g.updateOptions({
            highlightCallback: prevCallbacks.highlight,
            unhighlightCallback: prevCallbacks.unhighlight
          });
        }
      }
      // release references & make subsequent calls throw.
      dygraphs = null;
      opts = null;
      prevCallbacks = null;
    }
  };
};

function attachZoomHandlers(gs, syncOpts, prevCallbacks) {
  var block = false;
  for (var i = 0; i < gs.length; i++) {
    var g = gs[i];
    prevCallbacks.draw = g.getFunctionOption('drawCallback');
    g.updateOptions({
      drawCallback: function(me, initial) {
        if (prevCallbacks.draw) prevCallbacks.draw(me, initial);
        if (block || initial) return;
        block = true;
        var opts = {
          dateWindow: me.xAxisRange()
        };
        if (syncOpts.range) opts.valueRange = me.yAxisRange();

        for (var j = 0; j < gs.length; j++) {
          if (gs[j] == me) continue;
          gs[j].updateOptions(opts);
        }
        block = false;
      }
    }, false /* no need to redraw */);
  }
}

function attachSelectionHandlers(gs, prevCallbacks) {
  var block = false;
  for (var i = 0; i < gs.length; i++) {
    var g = gs[i];
    prevCallbacks.highlight = g.getFunctionOption('highlightCallback');
    prevCallbacks.unhighlight = g.getFunctionOption('unhighlightCallback');
    g.updateOptions({
      highlightCallback: function(event, x, points, row, seriesName) {
        if (prevCallbacks.highlight) prevCallbacks.highlight(event, x, points, row, seriesName);
        if (block) return;
        block = true;
        var me = this;
        for (var i = 0; i < gs.length; i++) {
          if (me == gs[i]) continue;
          var idx = dygraphsBinarySearch(gs[i], x);
          if (idx !== null) {
            gs[i].setSelection(idx, seriesName);
          }
        }
        block = false;
      },
      unhighlightCallback: function(event) {
        if (prevCallbacks.unhighlight) prevCallbacks.unhighlight(event);
        if (block) return;
        block = true;
        var me = this;
        for (var i = 0; i < gs.length; i++) {
          if (me == gs[i]) continue;
          gs[i].clearSelection();
        }
        block = false;
      }
    });
  }
}

// Returns the index corresponding to xVal, or null if there is none.
function dygraphsBinarySearch(g, xVal) {
  var low = 0,
      high = g.numRows() - 1;

  while (low < high) {
    var idx = (high + low) >> 1;
    var x = g.getValue(idx, 0);
    if (x < xVal) {
      low = idx + 1;
    } else if (x > xVal) {
      high = idx - 1;
    } else {
      return idx;
    }
  }

  // TODO: give an option to find the closest point, i.e. not demand an exact match.
  return null;
}

})();
<commit_msg>Get it under 80 chars per line<commit_after>/**
 * Synchronize zooming and/or selections between a set of dygraphs.
 *
 * Usage:
 *
 *   var g1 = new Dygraph(...),
 *       g2 = new Dygraph(...),
 *       ...;
 *   var sync = Dygraph.synchronize(g1, g2, ...);
 *   // charts are now synchronized
 *   sync.detach();
 *   // charts are no longer synchronized
 *
 * You can set options using the last parameter, for example:
 *
 *   var sync = Dygraph.synchronize(g1, g2, g3, {
 *      selection: true,
 *      zoom: true
 *   });
 *
 * The default is to synchronize both of these.
 *
 * Instead of passing one Dygraph object as each parameter, you may also pass an
 * array of dygraphs:
 *
 *   var sync = Dygraph.synchronize([g1, g2, g3], {
 *      selection: false,
 *      zoom: true
 *   });
 *
 * You may also set `range: false` if you wish to only sync the x-axis.
 * The `range` option has no effect unless `zoom` is true (the default).
 */
(function() {
/* global Dygraph:false */
'use strict';

Dygraph.synchronize = function(/* dygraphs..., opts */) {
  if (arguments.length === 0) {
    throw 'Invalid invocation of Dygraph.synchronize(). Need >= 1 argument.';
  }

  var OPTIONS = ['selection', 'zoom', 'range'];
  var opts = {
    selection: true,
    zoom: true,
    range: true
  };
  var dygraphs = [];

  var prevCallbacks = {
    draw: null,
    highlight: null,
    unhighlight: null
  };

  var parseOpts = function(obj) {
    if (!(obj instanceof Object)) {
      throw 'Last argument must be either Dygraph or Object.';
    } else {
      for (var i = 0; i < OPTIONS.length; i++) {
        var optName = OPTIONS[i];
        if (obj.hasOwnProperty(optName)) opts[optName] = obj[optName];
      }
    }
  };

  if (arguments[0] instanceof Dygraph) {
    // Arguments are Dygraph objects.
    for (var i = 0; i < arguments.length; i++) {
      if (arguments[i] instanceof Dygraph) {
        dygraphs.push(arguments[i]);
      } else {
        break;
      }
    }
    if (i < arguments.length - 1) {
      throw 'Invalid invocation of Dygraph.synchronize(). ' +
            'All but the last argument must be Dygraph objects.';
    } else if (i == arguments.length - 1) {
      parseOpts(arguments[arguments.length - 1]);
    }
  } else if (arguments[0].length) {
    // Invoked w/ list of dygraphs, options
    for (var i = 0; i < arguments[0].length; i++) {
      dygraphs.push(arguments[0][i]);
    }
    if (arguments.length == 2) {
      parseOpts(arguments[1]);
    } else if (arguments.length > 2) {
      throw 'Invalid invocation of Dygraph.synchronize(). ' +
            'Expected two arguments: array and optional options argument.';
    }  // otherwise arguments.length == 1, which is fine.
  } else {
    throw 'Invalid invocation of Dygraph.synchronize(). ' +
          'First parameter must be either Dygraph or list of Dygraphs.';
  }

  if (dygraphs.length < 2) {
    throw 'Invalid invocation of Dygraph.synchronize(). ' +
          'Need two or more dygraphs to synchronize.';
  }

  // Listen for draw, highlight, unhighlight callbacks.
  if (opts.zoom) {
    attachZoomHandlers(dygraphs, opts, prevCallbacks);
  }

  if (opts.selection) {
    attachSelectionHandlers(dygraphs, prevCallbacks);
  }

  return {
    detach: function() {
      for (var i = 0; i < dygraphs.length; i++) {
        var g = dygraphs[i];
        if (opts.zoom) {
          g.updateOptions({drawCallback: prevCallbacks.draw});
        }
        if (opts.selection) {
          g.updateOptions({
            highlightCallback: prevCallbacks.highlight,
            unhighlightCallback: prevCallbacks.unhighlight
          });
        }
      }
      // release references & make subsequent calls throw.
      dygraphs = null;
      opts = null;
      prevCallbacks = null;
    }
  };
};

function attachZoomHandlers(gs, syncOpts, prevCallbacks) {
  var block = false;
  for (var i = 0; i < gs.length; i++) {
    var g = gs[i];
    prevCallbacks.draw = g.getFunctionOption('drawCallback');
    g.updateOptions({
      drawCallback: function(me, initial) {
        if (prevCallbacks.draw) prevCallbacks.draw(me, initial);
        if (block || initial) return;
        block = true;
        var opts = {
          dateWindow: me.xAxisRange()
        };
        if (syncOpts.range) opts.valueRange = me.yAxisRange();

        for (var j = 0; j < gs.length; j++) {
          if (gs[j] == me) continue;
          gs[j].updateOptions(opts);
        }
        block = false;
      }
    }, false /* no need to redraw */);
  }
}

function attachSelectionHandlers(gs, prevCallbacks) {
  var block = false;
  for (var i = 0; i < gs.length; i++) {
    var g = gs[i];
    prevCallbacks.highlight = g.getFunctionOption('highlightCallback');
    prevCallbacks.unhighlight = g.getFunctionOption('unhighlightCallback');
    g.updateOptions({
      highlightCallback: function(event, x, points, row, seriesName) {
        if (prevCallbacks.highlight) {
            prevCallbacks.highlight(event, x, points, row, seriesName);
        }
        if (block) return;
        block = true;
        var me = this;
        for (var i = 0; i < gs.length; i++) {
          if (me == gs[i]) continue;
          var idx = dygraphsBinarySearch(gs[i], x);
          if (idx !== null) {
            gs[i].setSelection(idx, seriesName);
          }
        }
        block = false;
      },
      unhighlightCallback: function(event) {
        if (prevCallbacks.unhighlight) prevCallbacks.unhighlight(event);
        if (block) return;
        block = true;
        var me = this;
        for (var i = 0; i < gs.length; i++) {
          if (me == gs[i]) continue;
          gs[i].clearSelection();
        }
        block = false;
      }
    });
  }
}

// Returns the index corresponding to xVal, or null if there is none.
function dygraphsBinarySearch(g, xVal) {
  var low = 0,
      high = g.numRows() - 1;

  while (low < high) {
    var idx = (high + low) >> 1;
    var x = g.getValue(idx, 0);
    if (x < xVal) {
      low = idx + 1;
    } else if (x > xVal) {
      high = idx - 1;
    } else {
      return idx;
    }
  }

  // TODO: give an option to find the closest point, i.e. not demand an exact match.
  return null;
}

})();
<|endoftext|>


<commit_before>export default [function(){
    return {
        searchTree: function(params) {
            // params.element
            // params.matchingId
            // params.byNodeId

            let thisNodeId = params.byNodeId ? params.element.nodeId : params.element.id;

            if(thisNodeId === params.matchingId){
                 return params.element;
            }else if (params.element.children && params.element.children.length > 0){
                 let result = null;
                 const thisService = this;
                 _.forEach(params.element.children, function(child) {
                     result = thisService.searchTree({
                         element: child,
                         matchingId: params.matchingId,
                         byNodeId: params.byNodeId ? params.byNodeId : false
                     });
                     if(result) {
                         return false;
                     }
                 });
                 return result;
            }
            return null;
        },
        removeNodeFromTree: function(params) {
            // params.tree
            // params.nodeToBeDeleted

            let parentNode = this.searchTree({
                element: params.tree,
                matchingId: params.nodeToBeDeleted.parent.id
            });
            let nodeToBeDeleted = this.searchTree({
                element: parentNode,
                matchingId: params.nodeToBeDeleted.id
            });

            if(nodeToBeDeleted.children) {
                _.forEach(nodeToBeDeleted.children, function(child) {
                    if(nodeToBeDeleted.isRoot) {
                        child.isRoot = true;
                        child.edgeType = "always";
                    }

                    parentNode.children.push(child);
                });
            }

            _.forEach(parentNode.children, function(child, index) {
                if(child.id === params.nodeToBeDeleted.id) {
                    parentNode.children.splice(index, 1);
                    return false;
                }
            });
        },
        addPlaceholderNode: function(params) {
            // params.parent
            // params.betweenTwoNodes
            // params.tree
            // params.id

            let placeholder = {
                children: [],
                c: "#D7D7D7",
                id: params.id,
                canDelete: true,
                canEdit: false,
                canAddTo: true,
                placeholder: true,
                isNew: true,
                edited: false
            };

            let parentNode = (params.betweenTwoNodes) ? this.searchTree({element: params.tree, matchingId: params.parent.source.id}) : this.searchTree({element: params.tree, matchingId: params.parent.id});
            let placeholderRef;

            if(params.betweenTwoNodes) {
                _.forEach(parentNode.children, function(child, index) {
                    if(child.id === params.parent.target.id) {
                        placeholder.children.push(angular.copy(child));
                        parentNode.children[index] = placeholder;
                        placeholderRef = parentNode.children[index];
                        return false;
                    }
                });
            }
            else {
                if(parentNode.children) {
                    parentNode.children.push(placeholder);
                    placeholderRef = parentNode.children[parentNode.children.length - 1];
                } else {
                    parentNode.children = [placeholder];
                    placeholderRef = parentNode.children[0];
                }
            }

            return placeholderRef;
        },
        getSiblingConnectionTypes: function(params) {
            // params.parentId
            // params.tree

            let siblingConnectionTypes = {};

            let parentNode = this.searchTree({
                element: params.tree,
                matchingId: params.parentId
            });

            if(parentNode.children && parentNode.children.length > 0) {
                // Loop across them and add the types as keys to siblingConnectionTypes
                _.forEach(parentNode.children, function(child) {
                    if(!child.placeholder && child.edgeType) {
                        siblingConnectionTypes[child.edgeType] = true;
                    }
                });
            }

            return Object.keys(siblingConnectionTypes);
        },
        buildTree: function(params) {
            //params.workflowNodes

            let _this = this;

            let treeData = {
                data: {
                    id: 1,
                    canDelete: false,
                    canEdit: false,
                    canAddTo: true,
                    isStartNode: true,
                    unifiedJobTemplate: {
                        name: "Workflow Launch"
                    },
                    children: [],
                    deletedNodes: [],
                    totalNodes: 0
                },
                nextIndex: 2
            };

            let nodesArray = params.workflowNodes;
            let nodesObj = {};
            let nonRootNodeIds = [];
            let allNodeIds = [];

            // Determine which nodes are root nodes
            _.forEach(nodesArray, function(node) {
                nodesObj[node.id] = _.clone(node);

                allNodeIds.push(node.id);

                _.forEach(node.success_nodes, function(nodeId){
                nonRootNodeIds.push(nodeId);
                });
                _.forEach(node.failure_nodes, function(nodeId){
                nonRootNodeIds.push(nodeId);
                });
                _.forEach(node.always_nodes, function(nodeId){
                nonRootNodeIds.push(nodeId);
                });
            });

            let rootNodes = _.difference(allNodeIds, nonRootNodeIds);

            // Loop across the root nodes and re-build the tree
            _.forEach(rootNodes, function(rootNodeId) {
                let branch = _this.buildBranch({
                    nodeId: rootNodeId,
                    edgeType: "always",
                    nodesObj: nodesObj,
                    isRoot: true,
                    treeData: treeData
                });

                treeData.data.children.push(branch);
            });

            return treeData;
        },
        buildBranch: function(params) {
            // params.nodeId
            // params.parentId
            // params.edgeType
            // params.nodesObj
            // params.isRoot
            // params.treeData

            let _this = this;

            let treeNode = {
                children: [],
                c: "#D7D7D7",
                id: params.treeData.nextIndex,
                nodeId: params.nodeId,
                canDelete: true,
                canEdit: true,
                canAddTo: true,
                placeholder: false,
                edgeType: params.edgeType,
                unifiedJobTemplate: _.clone(params.nodesObj[params.nodeId].summary_fields.unified_job_template),
                isNew: false,
                edited: false,
                originalEdge: params.edgeType,
                originalNodeObj: _.clone(params.nodesObj[params.nodeId]),
                promptValues: {},
                isRoot: params.isRoot ? params.isRoot : false,
                //jobStatus: 'failed' successful waiting running pending
            };

            params.treeData.data.totalNodes++;

            params.treeData.nextIndex++;

            if(params.parentId) {
                treeNode.originalParentId = params.parentId;
            }

            if(params.nodesObj[params.nodeId].summary_fields.job) {
                treeNode.jobStatus = params.nodesObj[params.nodeId].summary_fields.job.status;
            }

            // Loop across the success nodes and add them recursively
            _.forEach(params.nodesObj[params.nodeId].success_nodes, function(successNodeId) {
                treeNode.children.push(_this.buildBranch({
                    nodeId: successNodeId,
                    parentId: params.nodeId,
                    edgeType: "success",
                    nodesObj: params.nodesObj,
                    treeData: params.treeData
                }));
            });

            // failure nodes
            _.forEach(params.nodesObj[params.nodeId].failure_nodes, function(failureNodesId) {
                treeNode.children.push(_this.buildBranch({
                    nodeId: failureNodesId,
                    parentId: params.nodeId,
                    edgeType: "failure",
                    nodesObj: params.nodesObj,
                    treeData: params.treeData
                }));
            });

            // always nodes
            _.forEach(params.nodesObj[params.nodeId].always_nodes, function(alwaysNodesId) {
                treeNode.children.push(_this.buildBranch({
                    nodeId: alwaysNodesId,
                    parentId: params.nodeId,
                    edgeType: "always",
                    nodesObj: params.nodesObj,
                    treeData: params.treeData
                }));
            });

            return treeNode;
        },
        updateStatusOfNode: function(params) {
            // params.treeData
            // params.nodeId
            // params.status

            let matchingNode = this.searchTree({
                element: params.treeData.data,
                matchingId: params.nodeId,
                byNodeId: true
            });

            if(matchingNode) {
                matchingNode.jobStatus = params.status;
            }

        }
    };
}];
<commit_msg>Removed leftover commented code and cleaned up a variable name<commit_after>export default [function(){
    return {
        searchTree: function(params) {
            // params.element
            // params.matchingId
            // params.byNodeId

            let prospectiveId = params.byNodeId ? params.element.nodeId : params.element.id;

            if(prospectiveId === params.matchingId){
                 return params.element;
            }else if (params.element.children && params.element.children.length > 0){
                 let result = null;
                 const thisService = this;
                 _.forEach(params.element.children, function(child) {
                     result = thisService.searchTree({
                         element: child,
                         matchingId: params.matchingId,
                         byNodeId: params.byNodeId ? params.byNodeId : false
                     });
                     if(result) {
                         return false;
                     }
                 });
                 return result;
            }
            return null;
        },
        removeNodeFromTree: function(params) {
            // params.tree
            // params.nodeToBeDeleted

            let parentNode = this.searchTree({
                element: params.tree,
                matchingId: params.nodeToBeDeleted.parent.id
            });
            let nodeToBeDeleted = this.searchTree({
                element: parentNode,
                matchingId: params.nodeToBeDeleted.id
            });

            if(nodeToBeDeleted.children) {
                _.forEach(nodeToBeDeleted.children, function(child) {
                    if(nodeToBeDeleted.isRoot) {
                        child.isRoot = true;
                        child.edgeType = "always";
                    }

                    parentNode.children.push(child);
                });
            }

            _.forEach(parentNode.children, function(child, index) {
                if(child.id === params.nodeToBeDeleted.id) {
                    parentNode.children.splice(index, 1);
                    return false;
                }
            });
        },
        addPlaceholderNode: function(params) {
            // params.parent
            // params.betweenTwoNodes
            // params.tree
            // params.id

            let placeholder = {
                children: [],
                c: "#D7D7D7",
                id: params.id,
                canDelete: true,
                canEdit: false,
                canAddTo: true,
                placeholder: true,
                isNew: true,
                edited: false
            };

            let parentNode = (params.betweenTwoNodes) ? this.searchTree({element: params.tree, matchingId: params.parent.source.id}) : this.searchTree({element: params.tree, matchingId: params.parent.id});
            let placeholderRef;

            if(params.betweenTwoNodes) {
                _.forEach(parentNode.children, function(child, index) {
                    if(child.id === params.parent.target.id) {
                        placeholder.children.push(angular.copy(child));
                        parentNode.children[index] = placeholder;
                        placeholderRef = parentNode.children[index];
                        return false;
                    }
                });
            }
            else {
                if(parentNode.children) {
                    parentNode.children.push(placeholder);
                    placeholderRef = parentNode.children[parentNode.children.length - 1];
                } else {
                    parentNode.children = [placeholder];
                    placeholderRef = parentNode.children[0];
                }
            }

            return placeholderRef;
        },
        getSiblingConnectionTypes: function(params) {
            // params.parentId
            // params.tree

            let siblingConnectionTypes = {};

            let parentNode = this.searchTree({
                element: params.tree,
                matchingId: params.parentId
            });

            if(parentNode.children && parentNode.children.length > 0) {
                // Loop across them and add the types as keys to siblingConnectionTypes
                _.forEach(parentNode.children, function(child) {
                    if(!child.placeholder && child.edgeType) {
                        siblingConnectionTypes[child.edgeType] = true;
                    }
                });
            }

            return Object.keys(siblingConnectionTypes);
        },
        buildTree: function(params) {
            //params.workflowNodes

            let _this = this;

            let treeData = {
                data: {
                    id: 1,
                    canDelete: false,
                    canEdit: false,
                    canAddTo: true,
                    isStartNode: true,
                    unifiedJobTemplate: {
                        name: "Workflow Launch"
                    },
                    children: [],
                    deletedNodes: [],
                    totalNodes: 0
                },
                nextIndex: 2
            };

            let nodesArray = params.workflowNodes;
            let nodesObj = {};
            let nonRootNodeIds = [];
            let allNodeIds = [];

            // Determine which nodes are root nodes
            _.forEach(nodesArray, function(node) {
                nodesObj[node.id] = _.clone(node);

                allNodeIds.push(node.id);

                _.forEach(node.success_nodes, function(nodeId){
                nonRootNodeIds.push(nodeId);
                });
                _.forEach(node.failure_nodes, function(nodeId){
                nonRootNodeIds.push(nodeId);
                });
                _.forEach(node.always_nodes, function(nodeId){
                nonRootNodeIds.push(nodeId);
                });
            });

            let rootNodes = _.difference(allNodeIds, nonRootNodeIds);

            // Loop across the root nodes and re-build the tree
            _.forEach(rootNodes, function(rootNodeId) {
                let branch = _this.buildBranch({
                    nodeId: rootNodeId,
                    edgeType: "always",
                    nodesObj: nodesObj,
                    isRoot: true,
                    treeData: treeData
                });

                treeData.data.children.push(branch);
            });

            return treeData;
        },
        buildBranch: function(params) {
            // params.nodeId
            // params.parentId
            // params.edgeType
            // params.nodesObj
            // params.isRoot
            // params.treeData

            let _this = this;

            let treeNode = {
                children: [],
                c: "#D7D7D7",
                id: params.treeData.nextIndex,
                nodeId: params.nodeId,
                canDelete: true,
                canEdit: true,
                canAddTo: true,
                placeholder: false,
                edgeType: params.edgeType,
                unifiedJobTemplate: _.clone(params.nodesObj[params.nodeId].summary_fields.unified_job_template),
                isNew: false,
                edited: false,
                originalEdge: params.edgeType,
                originalNodeObj: _.clone(params.nodesObj[params.nodeId]),
                promptValues: {},
                isRoot: params.isRoot ? params.isRoot : false
            };

            params.treeData.data.totalNodes++;

            params.treeData.nextIndex++;

            if(params.parentId) {
                treeNode.originalParentId = params.parentId;
            }

            if(params.nodesObj[params.nodeId].summary_fields.job) {
                treeNode.jobStatus = params.nodesObj[params.nodeId].summary_fields.job.status;
            }

            // Loop across the success nodes and add them recursively
            _.forEach(params.nodesObj[params.nodeId].success_nodes, function(successNodeId) {
                treeNode.children.push(_this.buildBranch({
                    nodeId: successNodeId,
                    parentId: params.nodeId,
                    edgeType: "success",
                    nodesObj: params.nodesObj,
                    treeData: params.treeData
                }));
            });

            // failure nodes
            _.forEach(params.nodesObj[params.nodeId].failure_nodes, function(failureNodesId) {
                treeNode.children.push(_this.buildBranch({
                    nodeId: failureNodesId,
                    parentId: params.nodeId,
                    edgeType: "failure",
                    nodesObj: params.nodesObj,
                    treeData: params.treeData
                }));
            });

            // always nodes
            _.forEach(params.nodesObj[params.nodeId].always_nodes, function(alwaysNodesId) {
                treeNode.children.push(_this.buildBranch({
                    nodeId: alwaysNodesId,
                    parentId: params.nodeId,
                    edgeType: "always",
                    nodesObj: params.nodesObj,
                    treeData: params.treeData
                }));
            });

            return treeNode;
        },
        updateStatusOfNode: function(params) {
            // params.treeData
            // params.nodeId
            // params.status

            let matchingNode = this.searchTree({
                element: params.treeData.data,
                matchingId: params.nodeId,
                byNodeId: true
            });

            if(matchingNode) {
                matchingNode.jobStatus = params.status;
            }

        }
    };
}];
<|endoftext|>


<commit_before>// Shipments AJAX API
$(document).ready(function () {
  'use strict';

  // handle variant selection, show stock level.
  $('#add_variant_id').change(function(){
    var variant_id = $(this).val();

    var variant = _.find(window.variants, function(variant){
      return variant.id == variant_id
    })

    var variantStockTemplate = HandlebarsTemplates["variants/autocomplete_stock"];
    $('#stock_details').html(variantStockTemplate({variant: variant}));
    $('#stock_details').show();

    $('button.add_variant').click(addVariantFromStockLocation);
  });

  // add header to ship ujs ajax call
  $("form#admin-ship-shipment").on("ajax:beforeSend", function(event, xhr, settings) {
    xhr.setRequestHeader("X-Spree-Token", Spree.api_key);
  });

  $("form#admin-ship-shipment").on("ajax:success", function(event, xhr, settings) {
    window.location.reload();
  });
});

updateShipment = function(shipment_number, attributes) {
  var url = Spree.routes.shipments_api + '/' + shipment_number + '.json';

  return Spree.ajax({
    type: 'PUT',
    url: url,
    data: {
      shipment: attributes
    }
  });
}

adjustShipmentItems = function(shipment_number, variant_id, quantity){
    var shipment = _.findWhere(shipments, {number: shipment_number + ''});
    var inventory_units = _.where(shipment.inventory_units, {variant_id: variant_id});

    var url = Spree.routes.shipments_api + "/" + shipment_number;

    var new_quantity = 0;
    if(inventory_units.length<quantity){
      url += "/add"
      new_quantity = (quantity - inventory_units.length);
    }else if(inventory_units.length>quantity){
      url += "/remove"
      new_quantity = (inventory_units.length - quantity);
    }
    url += '.json';

    if(new_quantity!=0){
      Spree.ajax({
        type: "PUT",
        url: url,
        data: {
          variant_id: variant_id,
          quantity: new_quantity,
        },
        success: function(response) {
          window.location.reload();
        },
        error: function(response) {
          show_flash('error', response.responseJSON.message);
        }
      });
    }
}

deleteLineItem = function(line_item_id){
  var url = Spree.routes.line_items_api(order_number) + "/" + line_item_id + ".json";

  Spree.ajax({
    type: "DELETE",
    url: url,
    success: function(response) {
      window.location.reload();
    },
    error: function(response) {
      show_flash('error', response.responseJSON.message);
    }
  });
}

startItemSplit = function(event){
  event.preventDefault();
  var link = $(this);
  link.parent().find('a.split-item').toggle();
  link.parent().find('a.delete-item').toggle();
  var variant_id = link.data('variant-id');

  Spree.ajax({
    type: "GET",
    url: Spree.routes.variants_api + "/" + variant_id,
  }).success(function(variant){
    var max_quantity = link.closest('tr').data('item-quantity');
    var split_item_template = HandlebarsTemplates['variants/split'];
    link.closest('tr').after(split_item_template({ variant: variant, shipments: shipments, max_quantity: max_quantity }));

    $('#item_stock_location').select2({ width: 'resolve', placeholder: Spree.translations.item_stock_placeholder });
  })
}

completeItemSplit = function(event) {
  event.preventDefault();

  if($('#item_stock_location').val() === ""){
      alert('Please select the split destination.');
      return false;
  }

  var link = $(this);
  var stock_item_row = link.closest('tr');
  var variant_id = stock_item_row.data('variant-id');
  var quantity = stock_item_row.find('#item_quantity').val();

  var stock_location_id = stock_item_row.find('#item_stock_location').val();
  var original_shipment_number = link.closest('tbody').data('shipment-number');

  var selected_shipment = stock_item_row.find($('#item_stock_location').select2('data').element);
  var target_shipment_number = selected_shipment.data('shipment-number');
  var new_shipment = selected_shipment.data('new-shipment');

  if (stock_location_id != 'new_shipment') {
    if (new_shipment != undefined) {
      // TRANSFER TO A NEW LOCATION
      Spree.ajax({
        type: "POST",
        async: false,
        url: Spree.routes.shipments_api + "/transfer_to_location",
        data: {
            original_shipment_number: original_shipment_number,
            variant_id: variant_id,
            quantity: quantity,
            stock_location_id: stock_location_id
        }
      }).error(function(msg) {
          alert(msg.responseJSON['message']);
      }).done(function(msg) {
        window.Spree.advanceOrder();
      });
    } else {
        // TRANSFER TO AN EXISTING SHIPMENT
        Spree.ajax({
            type: "POST",
            async: false,
            url: Spree.routes.shipments_api + "/transfer_to_shipment",
            data: {
                original_shipment_number: original_shipment_number,
                target_shipment_number: target_shipment_number,
                variant_id: variant_id,
                quantity: quantity
            }
        }).error(function(msg) {
            alert(msg.responseJSON['message']);
        }).done(function(msg) {
            window.Spree.advanceOrder();
        });
    }
  }
}

addVariantFromStockLocation = function(event) {
  event.preventDefault();

  $('#stock_details').hide();

  var variant_id = $('input.variant_autocomplete').val();
  var stock_location_id = $(this).data('stock-location-id');
  var quantity = $("input.quantity[data-stock-location-id='" + stock_location_id + "']").val();

  var shipment = _.find(shipments, function(shipment){
    return shipment.stock_location_id == stock_location_id && (shipment.state == 'ready' || shipment.state == 'pending');
  });

  if(shipment==undefined){
    Spree.ajax({
      type: "POST",
      url: Spree.routes.shipments_api + "?shipment[order_id]=" + order_number,
      data: {
        variant_id: variant_id,
        quantity: quantity,
        stock_location_id: stock_location_id,
      }
    }).done(function( msg ) {
      window.location.reload();
    });
  }else{
    //add to existing shipment
    adjustShipmentItems(shipment.number, variant_id, quantity);
  }
  return 1
}

var ShipmentEditView = Backbone.View.extend({
  initialize: function(){
    var tbody = this.$("tbody[data-order-number][data-shipment-number]");
    this.shipment_number = tbody.data("shipment-number")
    this.order_number = tbody.data("order-number")
  },

  events: {
    "click a.split-item": "startItemSplit",
    "click a.edit-method": "toggleMethodEdit",
    "click a.cancel-method": "toggleMethodEdit",
    "click a.delete-item": "deleteItem",
    "click a.edit-tracking": "toggleTrackingEdit",
    "click a.cancel-tracking": "toggleTrackingEdit",
    "click a.cancel-split": "cancelItemSplit",
    "click a.save-split": "completeItemSplit",
    "click a.save-method": "saveMethod",
    "click a.save-tracking": "saveTracking",
  },

  startItemSplit: function(e){
    e.preventDefault();
    startItemSplit.apply(e.currentTarget, [e]);
  },

  toggleMethodEdit: function(e){
    e.preventDefault();
    this.$('tr.edit-method').toggle();
    this.$('tr.show-method').toggle();
  },

  cancelItemSplit: function(e){
    e.preventDefault();
    var link = $(e.currentTarget);
    var prev_row = link.closest('tr').prev();
    link.closest('tr').remove();
    prev_row.find('a.split-item').show();
    prev_row.find('a.delete-item').show();
  },

  completeItemSplit: function(e){
    completeItemSplit.apply(e.currentTarget, [e]);
  },

  deleteItem: function(e){
    e.preventDefault();
    if (confirm(Spree.translations.are_you_sure_delete)) {
      var del = $(e.currentTarget);
      var line_item_id = del.data('line-item-id');

      deleteLineItem(line_item_id);
    }
  },

  toggleTrackingEdit: function(e) {
    e.preventDefault();
    this.$("tr.edit-tracking").toggle()
    this.$("tr.show-tracking").toggle()
  },

  saveMethod: function(e) {
    e.preventDefault();
    var selected_shipping_rate_id = this.$("select#selected_shipping_rate_id").val();
    updateShipment(this.shipment_number, {
      selected_shipping_rate_id: selected_shipping_rate_id
    }).done(function () {
      window.location.reload();
    });
  },

  saveTracking: function(e) {
    e.preventDefault();
    var tracking = this.$('input#tracking').val();
    var _this = this;
    updateShipment(this.shipment_number, {
      tracking: tracking
    }).done(function (data) {
      _this.$('tr.edit-tracking').toggle();

      var show = _this.$('tr.show-tracking');
      show.toggle()
          .find('.tracking-value')
          .html($("<strong>")
          .html(Spree.translations.tracking + ": "))
          .append(document.createTextNode(data.tracking));
    });
  }
});

$(function(){
  $(".js-shipment-edit").each(function(){
    new ShipmentEditView({ el: $(this) });
  });
});
<commit_msg>Reorder Backbone events<commit_after>// Shipments AJAX API
$(document).ready(function () {
  'use strict';

  // handle variant selection, show stock level.
  $('#add_variant_id').change(function(){
    var variant_id = $(this).val();

    var variant = _.find(window.variants, function(variant){
      return variant.id == variant_id
    })

    var variantStockTemplate = HandlebarsTemplates["variants/autocomplete_stock"];
    $('#stock_details').html(variantStockTemplate({variant: variant}));
    $('#stock_details').show();

    $('button.add_variant').click(addVariantFromStockLocation);
  });

  // add header to ship ujs ajax call
  $("form#admin-ship-shipment").on("ajax:beforeSend", function(event, xhr, settings) {
    xhr.setRequestHeader("X-Spree-Token", Spree.api_key);
  });

  $("form#admin-ship-shipment").on("ajax:success", function(event, xhr, settings) {
    window.location.reload();
  });
});

updateShipment = function(shipment_number, attributes) {
  var url = Spree.routes.shipments_api + '/' + shipment_number + '.json';

  return Spree.ajax({
    type: 'PUT',
    url: url,
    data: {
      shipment: attributes
    }
  });
}

adjustShipmentItems = function(shipment_number, variant_id, quantity){
    var shipment = _.findWhere(shipments, {number: shipment_number + ''});
    var inventory_units = _.where(shipment.inventory_units, {variant_id: variant_id});

    var url = Spree.routes.shipments_api + "/" + shipment_number;

    var new_quantity = 0;
    if(inventory_units.length<quantity){
      url += "/add"
      new_quantity = (quantity - inventory_units.length);
    }else if(inventory_units.length>quantity){
      url += "/remove"
      new_quantity = (inventory_units.length - quantity);
    }
    url += '.json';

    if(new_quantity!=0){
      Spree.ajax({
        type: "PUT",
        url: url,
        data: {
          variant_id: variant_id,
          quantity: new_quantity,
        },
        success: function(response) {
          window.location.reload();
        },
        error: function(response) {
          show_flash('error', response.responseJSON.message);
        }
      });
    }
}

deleteLineItem = function(line_item_id){
  var url = Spree.routes.line_items_api(order_number) + "/" + line_item_id + ".json";

  Spree.ajax({
    type: "DELETE",
    url: url,
    success: function(response) {
      window.location.reload();
    },
    error: function(response) {
      show_flash('error', response.responseJSON.message);
    }
  });
}

startItemSplit = function(event){
  event.preventDefault();
  var link = $(this);
  link.parent().find('a.split-item').toggle();
  link.parent().find('a.delete-item').toggle();
  var variant_id = link.data('variant-id');

  Spree.ajax({
    type: "GET",
    url: Spree.routes.variants_api + "/" + variant_id,
  }).success(function(variant){
    var max_quantity = link.closest('tr').data('item-quantity');
    var split_item_template = HandlebarsTemplates['variants/split'];
    link.closest('tr').after(split_item_template({ variant: variant, shipments: shipments, max_quantity: max_quantity }));

    $('#item_stock_location').select2({ width: 'resolve', placeholder: Spree.translations.item_stock_placeholder });
  })
}

completeItemSplit = function(event) {
  event.preventDefault();

  if($('#item_stock_location').val() === ""){
      alert('Please select the split destination.');
      return false;
  }

  var link = $(this);
  var stock_item_row = link.closest('tr');
  var variant_id = stock_item_row.data('variant-id');
  var quantity = stock_item_row.find('#item_quantity').val();

  var stock_location_id = stock_item_row.find('#item_stock_location').val();
  var original_shipment_number = link.closest('tbody').data('shipment-number');

  var selected_shipment = stock_item_row.find($('#item_stock_location').select2('data').element);
  var target_shipment_number = selected_shipment.data('shipment-number');
  var new_shipment = selected_shipment.data('new-shipment');

  if (stock_location_id != 'new_shipment') {
    if (new_shipment != undefined) {
      // TRANSFER TO A NEW LOCATION
      Spree.ajax({
        type: "POST",
        async: false,
        url: Spree.routes.shipments_api + "/transfer_to_location",
        data: {
            original_shipment_number: original_shipment_number,
            variant_id: variant_id,
            quantity: quantity,
            stock_location_id: stock_location_id
        }
      }).error(function(msg) {
          alert(msg.responseJSON['message']);
      }).done(function(msg) {
        window.Spree.advanceOrder();
      });
    } else {
        // TRANSFER TO AN EXISTING SHIPMENT
        Spree.ajax({
            type: "POST",
            async: false,
            url: Spree.routes.shipments_api + "/transfer_to_shipment",
            data: {
                original_shipment_number: original_shipment_number,
                target_shipment_number: target_shipment_number,
                variant_id: variant_id,
                quantity: quantity
            }
        }).error(function(msg) {
            alert(msg.responseJSON['message']);
        }).done(function(msg) {
            window.Spree.advanceOrder();
        });
    }
  }
}

addVariantFromStockLocation = function(event) {
  event.preventDefault();

  $('#stock_details').hide();

  var variant_id = $('input.variant_autocomplete').val();
  var stock_location_id = $(this).data('stock-location-id');
  var quantity = $("input.quantity[data-stock-location-id='" + stock_location_id + "']").val();

  var shipment = _.find(shipments, function(shipment){
    return shipment.stock_location_id == stock_location_id && (shipment.state == 'ready' || shipment.state == 'pending');
  });

  if(shipment==undefined){
    Spree.ajax({
      type: "POST",
      url: Spree.routes.shipments_api + "?shipment[order_id]=" + order_number,
      data: {
        variant_id: variant_id,
        quantity: quantity,
        stock_location_id: stock_location_id,
      }
    }).done(function( msg ) {
      window.location.reload();
    });
  }else{
    //add to existing shipment
    adjustShipmentItems(shipment.number, variant_id, quantity);
  }
  return 1
}

var ShipmentEditView = Backbone.View.extend({
  initialize: function(){
    var tbody = this.$("tbody[data-order-number][data-shipment-number]");
    this.shipment_number = tbody.data("shipment-number")
    this.order_number = tbody.data("order-number")
  },

  events: {
    "click a.delete-item": "deleteItem",

    "click a.split-item": "startItemSplit",
    "click a.cancel-split": "cancelItemSplit",
    "click a.save-split": "completeItemSplit",

    "click a.edit-method": "toggleMethodEdit",
    "click a.cancel-method": "toggleMethodEdit",
    "click a.save-method": "saveMethod",

    "click a.edit-tracking": "toggleTrackingEdit",
    "click a.cancel-tracking": "toggleTrackingEdit",
    "click a.save-tracking": "saveTracking",
  },

  deleteItem: function(e){
    e.preventDefault();
    if (confirm(Spree.translations.are_you_sure_delete)) {
      var del = $(e.currentTarget);
      var line_item_id = del.data('line-item-id');

      deleteLineItem(line_item_id);
    }
  },

  startItemSplit: function(e){
    e.preventDefault();
    startItemSplit.apply(e.currentTarget, [e]);
  },

  cancelItemSplit: function(e){
    e.preventDefault();
    var link = $(e.currentTarget);
    var prev_row = link.closest('tr').prev();
    link.closest('tr').remove();
    prev_row.find('a.split-item').show();
    prev_row.find('a.delete-item').show();
  },

  completeItemSplit: function(e){
    completeItemSplit.apply(e.currentTarget, [e]);
  },

  toggleMethodEdit: function(e){
    e.preventDefault();
    this.$('tr.edit-method').toggle();
    this.$('tr.show-method').toggle();
  },

  saveMethod: function(e) {
    e.preventDefault();
    var selected_shipping_rate_id = this.$("select#selected_shipping_rate_id").val();
    updateShipment(this.shipment_number, {
      selected_shipping_rate_id: selected_shipping_rate_id
    }).done(function () {
      window.location.reload();
    });
  },

  toggleTrackingEdit: function(e) {
    e.preventDefault();
    this.$("tr.edit-tracking").toggle()
    this.$("tr.show-tracking").toggle()
  },

  saveTracking: function(e) {
    e.preventDefault();
    var tracking = this.$('input#tracking').val();
    var _this = this;
    updateShipment(this.shipment_number, {
      tracking: tracking
    }).done(function (data) {
      _this.$('tr.edit-tracking').toggle();

      var show = _this.$('tr.show-tracking');
      show.toggle()
          .find('.tracking-value')
          .html($("<strong>")
          .html(Spree.translations.tracking + ": "))
          .append(document.createTextNode(data.tracking));
    });
  }
});

$(function(){
  $(".js-shipment-edit").each(function(){
    new ShipmentEditView({ el: $(this) });
  });
});
<|endoftext|>


<commit_before>// Shipments AJAX API
$(document).ready(function () {
  'use strict';

  // handle variant selection, show stock level.
  $('#add_variant_id').change(function(){
    var variant_id = $(this).val();

    Spree.ajax({
      url: Spree.routes.variants_api + "/" + variant_id,
      success: function(variant){
        var variantStockTemplate = HandlebarsTemplates["variants/autocomplete_stock"];
        $('#stock_details').html(variantStockTemplate({variant: variant}));
        $('#stock_details').show();

        $('button.add_variant').click(addVariantFromStockLocation);
      }
    });
  });

  // add header to ship ujs ajax call
  $("form#admin-ship-shipment").on("ajax:beforeSend", function(event, xhr, settings) {
    xhr.setRequestHeader("X-Spree-Token", Spree.api_key);
  });

  $("form#admin-ship-shipment").on("ajax:success", function(event, xhr, settings) {
    window.location.reload();
  });
});

updateShipment = function(shipment_number, attributes) {
  var url = Spree.routes.shipments_api + '/' + shipment_number + '.json';

  return Spree.ajax({
    type: 'PUT',
    url: url,
    data: {
      shipment: attributes
    }
  });
}

adjustShipmentItems = function(shipment_number, variant_id, quantity){
    var shipment = _.findWhere(shipments, {number: shipment_number + ''});
    var inventory_units = _.where(shipment.inventory_units, {variant_id: variant_id});

    var url = Spree.routes.shipments_api + "/" + shipment_number;

    var new_quantity = 0;
    if(inventory_units.length<quantity){
      url += "/add"
      new_quantity = (quantity - inventory_units.length);
    }else if(inventory_units.length>quantity){
      url += "/remove"
      new_quantity = (inventory_units.length - quantity);
    }
    url += '.json';

    if(new_quantity!=0){
      Spree.ajax({
        type: "PUT",
        url: url,
        data: {
          variant_id: variant_id,
          quantity: new_quantity,
        },
        success: function(response) {
          window.location.reload();
        },
        error: function(response) {
          show_flash('error', response.responseJSON.message);
        }
      });
    }
}

deleteLineItem = function(line_item_id){
  var url = Spree.routes.line_items_api(order_number) + "/" + line_item_id + ".json";

  Spree.ajax({
    type: "DELETE",
    url: url,
    success: function(response) {
      window.location.reload();
    },
    error: function(response) {
      show_flash('error', response.responseJSON.message);
    }
  });
}

startItemSplit = function(event){
  event.preventDefault();
  var link = $(this);
  link.parent().find('a.split-item').toggle();
  link.parent().find('a.delete-item').toggle();
  var variant_id = link.data('variant-id');

  Spree.ajax({
    type: "GET",
    url: Spree.routes.variants_api + "/" + variant_id,
  }).success(function(variant){
    var max_quantity = link.closest('tr').data('item-quantity');
    var split_item_template = HandlebarsTemplates['variants/split'];
    link.closest('tr').after(split_item_template({ variant: variant, shipments: shipments, max_quantity: max_quantity }));

    $('#item_stock_location').select2({ width: 'resolve', placeholder: Spree.translations.item_stock_placeholder });
  })
}

completeItemSplit = function(event) {
  event.preventDefault();

  if($('#item_stock_location').val() === ""){
      alert('Please select the split destination.');
      return false;
  }

  var link = $(this);
  var stock_item_row = link.closest('tr');
  var variant_id = stock_item_row.data('variant-id');
  var quantity = stock_item_row.find('#item_quantity').val();

  var stock_location_id = stock_item_row.find('#item_stock_location').val();
  var original_shipment_number = link.closest('tbody').data('shipment-number');

  var selected_shipment = stock_item_row.find($('#item_stock_location').select2('data').element);
  var target_shipment_number = selected_shipment.data('shipment-number');
  var new_shipment = selected_shipment.data('new-shipment');

  if (stock_location_id != 'new_shipment') {
    if (new_shipment != undefined) {
      // TRANSFER TO A NEW LOCATION
      Spree.ajax({
        type: "POST",
        async: false,
        url: Spree.routes.shipments_api + "/transfer_to_location",
        data: {
            original_shipment_number: original_shipment_number,
            variant_id: variant_id,
            quantity: quantity,
            stock_location_id: stock_location_id
        }
      }).error(function(msg) {
          alert(msg.responseJSON['message']);
      }).done(function(msg) {
        window.Spree.advanceOrder();
      });
    } else {
        // TRANSFER TO AN EXISTING SHIPMENT
        Spree.ajax({
            type: "POST",
            async: false,
            url: Spree.routes.shipments_api + "/transfer_to_shipment",
            data: {
                original_shipment_number: original_shipment_number,
                target_shipment_number: target_shipment_number,
                variant_id: variant_id,
                quantity: quantity
            }
        }).error(function(msg) {
            alert(msg.responseJSON['message']);
        }).done(function(msg) {
            window.Spree.advanceOrder();
        });
    }
  }
}

addVariantFromStockLocation = function(event) {
  event.preventDefault();

  $('#stock_details').hide();

  var variant_id = $('input.variant_autocomplete').val();
  var stock_location_id = $(this).data('stock-location-id');
  var quantity = $("input.quantity[data-stock-location-id='" + stock_location_id + "']").val();

  var shipment = _.find(shipments, function(shipment){
    return shipment.stock_location_id == stock_location_id && (shipment.state == 'ready' || shipment.state == 'pending');
  });

  if(shipment==undefined){
    Spree.ajax({
      type: "POST",
      url: Spree.routes.shipments_api,
      data: {
        shipment: {
          order_id: order_number
        },
        variant_id: variant_id,
        quantity: quantity,
        stock_location_id: stock_location_id,
      }
    }).done(function( msg ) {
      window.location.reload();
    });
  }else{
    //add to existing shipment
    adjustShipmentItems(shipment.number, variant_id, quantity);
  }
  return 1
}

var ShipmentEditView = Backbone.View.extend({
  initialize: function(){
    var tbody = this.$("tbody[data-order-number][data-shipment-number]");
    this.shipment_number = tbody.data("shipment-number");
    this.order_number = tbody.data("order-number");
  },

  events: {
    "click a.delete-item": "deleteItem",

    "click a.split-item": "startItemSplit",
    "click a.cancel-split": "cancelItemSplit",
    "click a.save-split": "completeItemSplit",

    "click a.edit-method": "toggleMethodEdit",
    "click a.cancel-method": "toggleMethodEdit",
    "click a.save-method": "saveMethod",

    "click a.edit-tracking": "toggleTrackingEdit",
    "click a.cancel-tracking": "toggleTrackingEdit",
    "click a.save-tracking": "saveTracking",
  },

  deleteItem: function(e){
    e.preventDefault();
    if (confirm(Spree.translations.are_you_sure_delete)) {
      var del = $(e.currentTarget);
      var line_item_id = del.data('line-item-id');

      deleteLineItem(line_item_id);
    }
  },

  startItemSplit: function(e){
    e.preventDefault();
    startItemSplit.apply(e.currentTarget, [e]);
  },

  cancelItemSplit: function(e){
    e.preventDefault();
    var link = $(e.currentTarget);
    var prev_row = link.closest('tr').prev();
    link.closest('tr').remove();
    prev_row.find('a.split-item').show();
    prev_row.find('a.delete-item').show();
  },

  completeItemSplit: function(e){
    completeItemSplit.apply(e.currentTarget, [e]);
  },

  toggleMethodEdit: function(e){
    e.preventDefault();
    this.$('tr.edit-method').toggle();
    this.$('tr.show-method').toggle();
  },

  saveMethod: function(e) {
    e.preventDefault();
    var selected_shipping_rate_id = this.$("select#selected_shipping_rate_id").val();
    updateShipment(this.shipment_number, {
      selected_shipping_rate_id: selected_shipping_rate_id
    }).done(function () {
      window.location.reload();
    });
  },

  toggleTrackingEdit: function(e) {
    e.preventDefault();
    this.$("tr.edit-tracking").toggle()
    this.$("tr.show-tracking").toggle()
  },

  saveTracking: function(e) {
    e.preventDefault();
    var tracking = this.$('input#tracking').val();
    var _this = this;
    updateShipment(this.shipment_number, {
      tracking: tracking
    }).done(function (data) {
      _this.$('tr.edit-tracking').toggle();

      var show = _this.$('tr.show-tracking');
      show.toggle()
          .find('.tracking-value')
          .html($("<strong>")
          .html(Spree.translations.tracking + ": "))
          .append(document.createTextNode(data.tracking));
    });
  }
});

$(function(){
  $(".js-shipment-edit").each(function(){
    new ShipmentEditView({ el: $(this) });
  });
});
<commit_msg>Use this.$ in cancelItemSplit<commit_after>// Shipments AJAX API
$(document).ready(function () {
  'use strict';

  // handle variant selection, show stock level.
  $('#add_variant_id').change(function(){
    var variant_id = $(this).val();

    Spree.ajax({
      url: Spree.routes.variants_api + "/" + variant_id,
      success: function(variant){
        var variantStockTemplate = HandlebarsTemplates["variants/autocomplete_stock"];
        $('#stock_details').html(variantStockTemplate({variant: variant}));
        $('#stock_details').show();

        $('button.add_variant').click(addVariantFromStockLocation);
      }
    });
  });

  // add header to ship ujs ajax call
  $("form#admin-ship-shipment").on("ajax:beforeSend", function(event, xhr, settings) {
    xhr.setRequestHeader("X-Spree-Token", Spree.api_key);
  });

  $("form#admin-ship-shipment").on("ajax:success", function(event, xhr, settings) {
    window.location.reload();
  });
});

updateShipment = function(shipment_number, attributes) {
  var url = Spree.routes.shipments_api + '/' + shipment_number + '.json';

  return Spree.ajax({
    type: 'PUT',
    url: url,
    data: {
      shipment: attributes
    }
  });
}

adjustShipmentItems = function(shipment_number, variant_id, quantity){
    var shipment = _.findWhere(shipments, {number: shipment_number + ''});
    var inventory_units = _.where(shipment.inventory_units, {variant_id: variant_id});

    var url = Spree.routes.shipments_api + "/" + shipment_number;

    var new_quantity = 0;
    if(inventory_units.length<quantity){
      url += "/add"
      new_quantity = (quantity - inventory_units.length);
    }else if(inventory_units.length>quantity){
      url += "/remove"
      new_quantity = (inventory_units.length - quantity);
    }
    url += '.json';

    if(new_quantity!=0){
      Spree.ajax({
        type: "PUT",
        url: url,
        data: {
          variant_id: variant_id,
          quantity: new_quantity,
        },
        success: function(response) {
          window.location.reload();
        },
        error: function(response) {
          show_flash('error', response.responseJSON.message);
        }
      });
    }
}

deleteLineItem = function(line_item_id){
  var url = Spree.routes.line_items_api(order_number) + "/" + line_item_id + ".json";

  Spree.ajax({
    type: "DELETE",
    url: url,
    success: function(response) {
      window.location.reload();
    },
    error: function(response) {
      show_flash('error', response.responseJSON.message);
    }
  });
}

startItemSplit = function(event){
  event.preventDefault();
  var link = $(this);
  link.parent().find('a.split-item').toggle();
  link.parent().find('a.delete-item').toggle();
  var variant_id = link.data('variant-id');

  Spree.ajax({
    type: "GET",
    url: Spree.routes.variants_api + "/" + variant_id,
  }).success(function(variant){
    var max_quantity = link.closest('tr').data('item-quantity');
    var split_item_template = HandlebarsTemplates['variants/split'];
    link.closest('tr').after(split_item_template({ variant: variant, shipments: shipments, max_quantity: max_quantity }));

    $('#item_stock_location').select2({ width: 'resolve', placeholder: Spree.translations.item_stock_placeholder });
  })
}

completeItemSplit = function(event) {
  event.preventDefault();

  if($('#item_stock_location').val() === ""){
      alert('Please select the split destination.');
      return false;
  }

  var link = $(this);
  var stock_item_row = link.closest('tr');
  var variant_id = stock_item_row.data('variant-id');
  var quantity = stock_item_row.find('#item_quantity').val();

  var stock_location_id = stock_item_row.find('#item_stock_location').val();
  var original_shipment_number = link.closest('tbody').data('shipment-number');

  var selected_shipment = stock_item_row.find($('#item_stock_location').select2('data').element);
  var target_shipment_number = selected_shipment.data('shipment-number');
  var new_shipment = selected_shipment.data('new-shipment');

  if (stock_location_id != 'new_shipment') {
    if (new_shipment != undefined) {
      // TRANSFER TO A NEW LOCATION
      Spree.ajax({
        type: "POST",
        async: false,
        url: Spree.routes.shipments_api + "/transfer_to_location",
        data: {
            original_shipment_number: original_shipment_number,
            variant_id: variant_id,
            quantity: quantity,
            stock_location_id: stock_location_id
        }
      }).error(function(msg) {
          alert(msg.responseJSON['message']);
      }).done(function(msg) {
        window.Spree.advanceOrder();
      });
    } else {
        // TRANSFER TO AN EXISTING SHIPMENT
        Spree.ajax({
            type: "POST",
            async: false,
            url: Spree.routes.shipments_api + "/transfer_to_shipment",
            data: {
                original_shipment_number: original_shipment_number,
                target_shipment_number: target_shipment_number,
                variant_id: variant_id,
                quantity: quantity
            }
        }).error(function(msg) {
            alert(msg.responseJSON['message']);
        }).done(function(msg) {
            window.Spree.advanceOrder();
        });
    }
  }
}

addVariantFromStockLocation = function(event) {
  event.preventDefault();

  $('#stock_details').hide();

  var variant_id = $('input.variant_autocomplete').val();
  var stock_location_id = $(this).data('stock-location-id');
  var quantity = $("input.quantity[data-stock-location-id='" + stock_location_id + "']").val();

  var shipment = _.find(shipments, function(shipment){
    return shipment.stock_location_id == stock_location_id && (shipment.state == 'ready' || shipment.state == 'pending');
  });

  if(shipment==undefined){
    Spree.ajax({
      type: "POST",
      url: Spree.routes.shipments_api,
      data: {
        shipment: {
          order_id: order_number
        },
        variant_id: variant_id,
        quantity: quantity,
        stock_location_id: stock_location_id,
      }
    }).done(function( msg ) {
      window.location.reload();
    });
  }else{
    //add to existing shipment
    adjustShipmentItems(shipment.number, variant_id, quantity);
  }
  return 1
}

var ShipmentEditView = Backbone.View.extend({
  initialize: function(){
    var tbody = this.$("tbody[data-order-number][data-shipment-number]");
    this.shipment_number = tbody.data("shipment-number");
    this.order_number = tbody.data("order-number");
  },

  events: {
    "click a.delete-item": "deleteItem",

    "click a.split-item": "startItemSplit",
    "click a.cancel-split": "cancelItemSplit",
    "click a.save-split": "completeItemSplit",

    "click a.edit-method": "toggleMethodEdit",
    "click a.cancel-method": "toggleMethodEdit",
    "click a.save-method": "saveMethod",

    "click a.edit-tracking": "toggleTrackingEdit",
    "click a.cancel-tracking": "toggleTrackingEdit",
    "click a.save-tracking": "saveTracking",
  },

  deleteItem: function(e){
    e.preventDefault();
    if (confirm(Spree.translations.are_you_sure_delete)) {
      var del = $(e.currentTarget);
      var line_item_id = del.data('line-item-id');

      deleteLineItem(line_item_id);
    }
  },

  startItemSplit: function(e){
    e.preventDefault();
    startItemSplit.apply(e.currentTarget, [e]);
  },

  cancelItemSplit: function(e){
    e.preventDefault();
    this.$('tr.stock-item-split').remove();
    this.$('a.split-item').show();
    this.$('a.delete-item').show();
  },

  completeItemSplit: function(e){
    completeItemSplit.apply(e.currentTarget, [e]);
  },

  toggleMethodEdit: function(e){
    e.preventDefault();
    this.$('tr.edit-method').toggle();
    this.$('tr.show-method').toggle();
  },

  saveMethod: function(e) {
    e.preventDefault();
    var selected_shipping_rate_id = this.$("select#selected_shipping_rate_id").val();
    updateShipment(this.shipment_number, {
      selected_shipping_rate_id: selected_shipping_rate_id
    }).done(function () {
      window.location.reload();
    });
  },

  toggleTrackingEdit: function(e) {
    e.preventDefault();
    this.$("tr.edit-tracking").toggle()
    this.$("tr.show-tracking").toggle()
  },

  saveTracking: function(e) {
    e.preventDefault();
    var tracking = this.$('input#tracking').val();
    var _this = this;
    updateShipment(this.shipment_number, {
      tracking: tracking
    }).done(function (data) {
      _this.$('tr.edit-tracking').toggle();

      var show = _this.$('tr.show-tracking');
      show.toggle()
          .find('.tracking-value')
          .html($("<strong>")
          .html(Spree.translations.tracking + ": "))
          .append(document.createTextNode(data.tracking));
    });
  }
});

$(function(){
  $(".js-shipment-edit").each(function(){
    new ShipmentEditView({ el: $(this) });
  });
});
<|endoftext|>


<commit_before>// ==UserScript==
// @author      Robert Slifka (github @rslifka)
// @connect     docs.google.com
// @connect     rslifka.github.io
// @copyright   2017-2018, Robert Slifka (https://github.com/rslifka/fate_of_all_fools)
// @description Enhancements to the Destiny Item Manager
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_log
// @grant       GM_setValue
// @grant       GM_xmlhttpRequest
// @homepage    https://github.com/rslifka/fate_of_all_fools
// @license     MIT; https://raw.githubusercontent.com/rslifka/fate_of_all_fools/master/LICENSE.txt
// @match       https://*.destinyitemmanager.com/*
// @name        Fate of All Fools
// @require     https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.js
// @resource    fateOfAllFoolsCSS https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.css
// @run-at      document-start
// @supportURL  https://github.com/rslifka/fate_of_all_fools/issues
// @version     48
// ==/UserScript==
<commit_msg>AUTO-CREATED Release Artifact v49 c/o Travis<commit_after>// ==UserScript==
// @author      Robert Slifka (github @rslifka)
// @connect     docs.google.com
// @connect     rslifka.github.io
// @copyright   2017-2018, Robert Slifka (https://github.com/rslifka/fate_of_all_fools)
// @description Enhancements to the Destiny Item Manager
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_log
// @grant       GM_setValue
// @grant       GM_xmlhttpRequest
// @homepage    https://github.com/rslifka/fate_of_all_fools
// @license     MIT; https://raw.githubusercontent.com/rslifka/fate_of_all_fools/master/LICENSE.txt
// @match       https://*.destinyitemmanager.com/*
// @name        Fate of All Fools
// @require     https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.js
// @resource    fateOfAllFoolsCSS https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.css
// @run-at      document-start
// @supportURL  https://github.com/rslifka/fate_of_all_fools/issues
// @version     49
// ==/UserScript==
<|endoftext|>