<commit_before>/**
 * 为常用的 button 组件添加点击效果，同时全局增加 tap 事件
 *
 * @author      mufeng  <smufeng@gmail.com>
 * @version     0.2     <2016-01-19>
 */

$(function() {
    var $document = $(document), tap, fastmove, input;

    /* 修复path对象，无则自己模拟一个出来 */
    function fixPath(e) {
        var target = e.target, arr = [];

        while (target && target.parentNode) {
            arr.push(target);   // 当前存下来

            target = target.parentNode;
        }

        return arr;     // 返回创建的对象
    }

    function checkClass(item, test) {
        var find, cls = item.attr ? item.attr("class") :
                  item.getAttribute || item.getAttribute("class");

        /* 转换为数组，便于后面操作 */
        cls  = (cls || "").split(" ");
        find = (test || "button item tab-item").split(" ");

        for (var i=0; i<find.length; i++) {
            if (cls.indexOf(find[i]) >= 0) return true;
        }

        return false;
    }

    // 清除激活类
    function clearActive($target) {
        if (checkClass($target)) {
            $target.removeClass("active");
        }
    }
    $._ui_clearActive = clearActive;

    tap = {
        delay  : 200,
        animate: 240,

        /**
         * checkMove 点击移动判断容错率
         *
         * checkMoveBad 是针对移动设备
         *
         * 提高容错率可以提高点击的成功率，但
         * 同时也可能会导致误点几率变大
         * 国产山寨设备建议设置为 30以上
         */
        checkMove: 4,
        checkMoveBad: 30,

        doubleTime: 300,
        delayClass: 80,

        /* 为true会在移动后，清除元素class */
        moveClear: true,
        hasClear : false,

        input: null,
        target: null,
        lastType: "",
        disClick: false,
        delayStart: null,
        tapIsStart: false,

        startX: 0,
        startY: 0,
        startTime: null,

        _focus: function(e) {
            this.input = e.target;
        },

        _isMove: function(e, move) {
            var mv = move ? move : this.checkMove,
                touch = e.changedTouches, cx, cy;

            // 如果不是精确点击事件，采用加大的值
            if (!move && !e.type.match(/^mouse|pinter/)) {
                mv = this.checkMoveBad;
            }

            touch = touch && touch[0] ? touch[0] : e;
            cx = Math.abs(touch.pageX - this.startX);
            cy = Math.abs(touch.pageY - this.startY);

            return !!(cx >= mv || cy >= mv);
        },

        _isOne: function(now, old) {
            var reg = /^mouse|touch|pointer/;

            old = old.match(reg);
            now = now.match(reg);

            return old && now && old[0] == now[0];
        },

        _addActive: function(e) {
            var path = fixPath(e);

            for (var i = 0; i<path.length; i++) {
                var $item = $(path[i]);

                if (checkClass($item)) {
                    $item.addClass("active");
                }
            }
        },

        _clearActive: function(e) {
            var path = fixPath(e);

            for(var i = 0; i<path.length; i++) {
                clearActive($(path[i]));
            }
        },

        _start: function(e) {
            var touch = e.touches ? e.touches[0] : e, ct,
                tagName, path = fixPath(e), ltype = this.lastType;

            /* 修复移动端input点击焦点不更新的问题 */
            if (e.target != this.input) {
                this.input && this.input.blur();        // 刷新焦点
                this.input = null;
            }

            ct = $.getTime() - this.startTime;

            if ((e.touches && e.touches.length > 1) ||
                (!this._isOne(e.type, ltype) && ct < 600) ) {
                this.startX = null;      this.startY = null;

                return true;
            }

            this.lastType = e.type;
            tagName = e.target.tagName;
            $(e.target).trigger("tapstart", e);

            /* 记录此次点击事件的相关信息，用于方法判断 */
            this.startX = touch.pageX;
            this.startY = touch.pageY;
            this.startTime = $.getTime();
            this.target    = e.target;
            this.hasClear  = false;

            // 修复 BUTTON元素 出现点击两次的问题
            for (var i = 0; i<path.length; i++) {
                var $item = $(path[i]), type;
                tagName = $item[0].tagName.toUpperCase();
                type    = ($item.attr("type") || "").toUpperCase();

                if (tagName == "BUTTON" || (tagName == "INPUT" &&
                    "RADIO CHECKBOX".split(" ").indexOf(type) >= 0) ) {
                    e.preventDefault();
                    break;
                }
            }

            // 清除上一次的状态，解决双击问题
            clearTimeout(this.delayStart);
            this._clearActive(e);

            // 给按钮类的组件添加点击样式
            if (this.moveClear) {
                this.delayStart = setTimeout(function() {
                    tap._addActive(e);
                }, this.delayClass);
            } else {
                tap._addActive(e);
            }
        },

        _move: function(e) {
            e.preventDefault(); // 修复微信下拉显示网页地址

            // 创建 tapmove 事件
            if (this.startX != null) {
                $(e.target).trigger("tapmove", e);
            }

            if (this.moveClear && !this.hasClear && this._isMove(e)) {
                // 清除 tap 自定义相关操作
                clearTimeout(this.delayStart);

                // 清除事件中相关的元素的激活类
                tap._clearActive(e);
                this.hasClear = true;
            }
        },

        _end: function(e) {
            var ct, $target = $(e.target);

            ct = $.getTime() - this.startTime;

            if (this.startX != null) {
                $target.trigger("tapend", e);
            }

            if (!this._isMove(e) && ct < this.delay) {
                this.disClick = false;
                $target.trigger("click");
                $target.trigger("tap");
            }

            setTimeout(function() {
                tap._clearActive(e);
            }, this.delayClass*1.2);
        },

        handleEvent: function (e) {
            switch ( e.type ) {
                case 'touchstart':
                case 'pointerdown':
                case 'MSPointerDown':
                case 'mousedown':
                    this._start(e);
                    break;
                case 'touchmove':
                case 'pointermove':
                case 'MSPointerMove':
                case 'mousemove':
                    this._move(e);
                    break;
                case 'touchend':
                case 'pointerup':
                case 'MSPointerUp':
                case 'mouseup':
                case 'touchcancel':
                case 'pointercancel':
                case 'MSPointerCancel':
                case 'mousecancel':
                    this._end(e);
                    break;
            }
        }
    };

    /**
     *
     * 事件初始化，同时修复移动端 点击穿透问题，原理如下:
     *
     * 移动端的click都是touch之后，才会模拟触发。触发的顺序如下:
     *
     * touchstart -> touchmove -> touchend ->
     * mousedown  -> mousemove -> mouseenter -> click
     *
     * 在重叠的区域里，被遮盖的元素绑定click，遮盖的元素绑定touch事件，
     * 且touch后遮盖的元素会隐藏的话，就会造成穿透，因为click是在touch
     * 之后延迟触发的，浏览器会误认为是在遮盖的元素上触发了click。
     *
     */
    ;(function() {
        var kt = window.ontouchstart !== undefined ? 0 : 1,
            doc = document, bind = "addEventListener";

        /* 修复input 焦点问题 */
        doc[bind]("focus", tap._focus, true)

        doc[bind]("touchstart", tap);
        doc[bind]("touchmove", tap);
        doc[bind]("touchend", tap);
        doc[bind]("touchcancel", tap);

        doc[bind]("mousedown", tap);
        doc[bind]("mousemove", tap);
        doc[bind]("mouseup", tap);
        doc[bind]("mousecancel", tap);

        doc[bind]("pointerdown", tap);
        doc[bind]("pointermove", tap);
        doc[bind]("pointerup", tap);
        doc[bind]("pointercancel", tap);

        doc[bind]("MSPointerDown", tap);
        doc[bind]("MSPointerMove", tap);
        doc[bind]("MSPointerUp", tap);
        doc[bind]("MSPointerCancel", tap);

        $document.on("click", function(e) {
            if (!tap.disClick &&
                (e.timeStamp - tap.startTime) < 300) {

                // checkbox radio 元素，点击后value值修复
                var tar = e.target, $tar = $(tar), type;

                if (tar.tagName == "INPUT") {
                    type = tar.type.toUpperCase();

                    if (["RADIO", "CHECKBOX"].findIn(type)) {
                        if (tar.checked === true) {
                            $tar.val(false);
                            $tar.removeClass("checked");
                        } else if (type === "CHECKBOX") {
                            $tar.val(true);
                            $tar.addClass("checked");
                        }
                    }
                }

                tap.disClick = true;
            } else {
                e.preventDefault();
                e.stopImmediatePropagation();
            }
        }, true);
    })(window, tap);
});
<commit_msg>点击事件优化<commit_after>/**
 * 为常用的 button 组件添加点击效果，同时全局增加 tap 事件
 *
 * @author      mufeng  <smufeng@gmail.com>
 * @version     0.2     <2016-01-19>
 */

$(function() {
    var $document = $(document), tap, fastmove, input;

    /* 修复path对象，无则自己模拟一个出来 */
    function fixPath(e) {
        var target = e.target, arr = [];

        while (target && target.parentNode) {
            arr.push(target);   // 当前存下来

            target = target.parentNode;
        }

        return arr;     // 返回创建的对象
    }

    function checkClass(item, test) {
        var find, cls = item.attr ? item.attr("class") :
                  item.getAttribute || item.getAttribute("class");

        /* 转换为数组，便于后面操作 */
        cls  = (cls || "").split(" ");
        find = (test || "button item tab-item").split(" ");

        for (var i=0; i<find.length; i++) {
            if (cls.indexOf(find[i]) >= 0) return true;
        }

        return false;
    }

    // 清除激活类
    function clearActive($target) {
        if (checkClass($target)) {
            $target.removeClass("active");
        }
    }
    $._ui_clearActive = clearActive;

    tap = {
        delay  : 200,
        animate: 240,

        /**
         * checkMove 点击移动判断容错率
         *
         * checkMoveBad 是针对移动设备
         *
         * 提高容错率可以提高点击的成功率，但
         * 同时也可能会导致误点几率变大
         * 国产山寨设备建议设置为 30以上
         */
        checkMove: 4,
        checkMoveBad: 30,

        doubleTime: 300,
        delayClass: 80,

        /* 为true会在移动后，清除元素class */
        moveClear: true,
        hasClear : false,

        input: null,
        target: null,
        lastType: "",
        disClick: false,
        delayStart: null,
        tapIsStart: false,

        startX: 0,
        startY: 0,
        startTime: null,

        _focus: function(e) {
            this.input = e.target;
        },

        _isMove: function(e, move) {
            var mv = move ? move : this.checkMove,
                touch = e.changedTouches, cx, cy;

            // 如果不是精确点击事件，采用加大的值
            if (!move && !e.type.match(/^mouse|pinter/)) {
                mv = this.checkMoveBad;
            }

            touch = touch && touch[0] ? touch[0] : e;
            cx = Math.abs(touch.pageX - this.startX);
            cy = Math.abs(touch.pageY - this.startY);

            return !!(cx >= mv || cy >= mv);
        },

        _isOne: function(now, old) {
            var reg = /^mouse|touch|pointer/;

            old = old.match(reg);
            now = now.match(reg);

            return old && now && old[0] == now[0];
        },

        _addActive: function(e) {
            var path = fixPath(e);

            for (var i = 0; i<path.length; i++) {
                var $item = $(path[i]);

                if (checkClass($item)) {
                    $item.addClass("active");
                }
            }
        },

        _clearActive: function(e) {
            var path = fixPath(e);

            for(var i = 0; i<path.length; i++) {
                clearActive($(path[i]));
            }
        },

        _start: function(e) {
            var touch = e.touches ? e.touches[0] : e, ct,
                tagName, path = fixPath(e), ltype = this.lastType;

            /* 修复移动端input点击焦点不更新的问题 */
            if (e.target != this.input) {
                this.input && this.input.blur();        // 刷新焦点
                this.input = null;
            }

            ct = $.getTime() - this.startTime;

            if ((e.touches && e.touches.length > 1) ||
                (!this._isOne(e.type, ltype) && ct < 600) ) {
                this.startX = null;      this.startY = null;

                return true;
            }

            this.lastType = e.type;
            tagName = e.target.tagName;
            $(e.target).trigger("tapstart", e);

            /* 记录此次点击事件的相关信息，用于方法判断 */
            this.startX = touch.pageX;
            this.startY = touch.pageY;
            this.startTime = $.getTime();
            this.target    = e.target;
            this.hasClear  = false;

            // 修复 BUTTON元素 出现点击两次的问题
            for (var i = 0; i<path.length; i++) {
                var $item = $(path[i]), type;
                tagName = $item[0].tagName.toUpperCase();
                type    = ($item.attr("type") || "").toUpperCase();

                if (tagName == "BUTTON" || (tagName == "INPUT" &&
                    "RADIO CHECKBOX".split(" ").indexOf(type) >= 0) ) {
                    e.preventDefault();
                    break;
                }
            }

            // 清除上一次的状态，解决双击问题
            clearTimeout(this.delayStart);
            this._clearActive(e);

            // 给按钮类的组件添加点击样式
            if (this.moveClear) {
                this.delayStart = setTimeout(function() {
                    tap._addActive(e);
                }, this.delayClass);
            } else {
                tap._addActive(e);
            }
        },

        _move: function(e) {
            e.preventDefault(); // 修复微信下拉显示网页地址

            // 创建 tapmove 事件
            if (this.startX != null) {
                $(e.target).trigger("tapmove", e);
            }

            if (this.moveClear && !this.hasClear && this._isMove(e)) {
                // 清除 tap 自定义相关操作
                clearTimeout(this.delayStart);

                // 清除事件中相关的元素的激活类
                tap._clearActive(e);
                this.hasClear = true;
            }
        },

        _end: function(e) {
            var ct, $target = $(e.target);

            ct = $.getTime() - this.startTime;

            if (this.startX != null) {
                $target.trigger("tapend", e);
            }

            if (!this._isMove(e) && ct < this.delay) {
                this.disClick = false;
                $target.trigger("click");
                $target.trigger("tap");
            }

            setTimeout(function() {
                tap._clearActive(e);
            }, this.delayClass*1.2);
        },

        handleEvent: function (e) {
            switch ( e.type ) {
                case 'touchstart':
                case 'pointerdown':
                case 'MSPointerDown':
                case 'mousedown':
                    this._start(e);
                    break;
                case 'touchmove':
                case 'pointermove':
                case 'MSPointerMove':
                case 'mousemove':
                    this._move(e);
                    break;
                case 'touchend':
                case 'pointerup':
                case 'MSPointerUp':
                case 'mouseup':
                case 'touchcancel':
                case 'pointercancel':
                case 'MSPointerCancel':
                case 'mousecancel':
                    this._end(e);
                    break;
            }
        }
    };

    /**
     *
     * 事件初始化，同时修复移动端 点击穿透问题，原理如下:
     *
     * 移动端的click都是touch之后，才会模拟触发。触发的顺序如下:
     *
     * touchstart -> touchmove -> touchend ->
     * mousedown  -> mousemove -> mouseenter -> click
     *
     * 在重叠的区域里，被遮盖的元素绑定click，遮盖的元素绑定touch事件，
     * 且touch后遮盖的元素会隐藏的话，就会造成穿透，因为click是在touch
     * 之后延迟触发的，浏览器会误认为是在遮盖的元素上触发了click。
     *
     */
    ;(function() {
        var kt = window.ontouchstart !== undefined ? 0 : 1,
            doc = document, bind = "addEventListener";

        /* 修复input 焦点问题 */
        doc[bind]("focus", tap._focus, true)

        if (kt === 0) {
            doc[bind]("touchstart", tap);
            doc[bind]("touchmove", tap);
            doc[bind]("touchend", tap);
            doc[bind]("touchcancel", tap);
        } else {
            doc[bind]("mousedown", tap);
            doc[bind]("mousemove", tap);
            doc[bind]("mouseup", tap);
            doc[bind]("mousecancel", tap);
        }

        doc[bind]("pointerdown", tap);
        doc[bind]("pointermove", tap);
        doc[bind]("pointerup", tap);
        doc[bind]("pointercancel", tap);

        doc[bind]("MSPointerDown", tap);
        doc[bind]("MSPointerMove", tap);
        doc[bind]("MSPointerUp", tap);
        doc[bind]("MSPointerCancel", tap);

        $document.on("click", function(e) {
            if (!tap.disClick &&
                (e.timeStamp - tap.startTime) < 300) {

                // checkbox radio 元素，点击后value值修复
                var tar = e.target, $tar = $(tar), type;

                if (tar.tagName == "INPUT") {
                    type = tar.type.toUpperCase();

                    if (["RADIO", "CHECKBOX"].findIn(type)) {
                        if (tar.checked === true) {
                            $tar.val(false);
                            $tar.removeClass("checked");
                        } else if (type === "CHECKBOX") {
                            $tar.val(true);
                            $tar.addClass("checked");
                        }
                    }
                }

                tap.disClick = true;
            } else {
                e.preventDefault();
                e.stopImmediatePropagation();
            }
        }, true);
    })(window, tap);
});
<|endoftext|>


<commit_before>var page = require("webpage").create();
var system = require("system");

page.paperSize = {
    width: '6in',
    height: '4in',
    margin: {
        top: '10px',
        left: '15px',
        right: '15px',
        bottom: '10px'
    }
}

page.zoomFactor = 0.5;

page.viewportSize = {
  width: 800,
  height: 640
};

page.open(system.args[1], function (status) {
    window.setTimeout(function () {
        var size = page.evaluate(function () {
            return {width: width = 800, height : 640 };
        });
        page.paperSize = size;

        page.render(system.args[2]);
        phantom.exit();
    }, 3000);
});

page.onError = function(msg, trace) {
    console.log(msg);
}<commit_msg>adjust height smaller - 10<commit_after>var page = require("webpage").create();
var system = require("system");

page.paperSize = {
    width: '6in',
    height: '4in',
    margin: {
        top: '10px',
        left: '15px',
        right: '15px',
        bottom: '10px'
    }
}

page.zoomFactor = 0.5;

page.viewportSize = {
  width: 800,
  height: 630
};

page.open(system.args[1], function (status) {
    window.setTimeout(function () {
        var size = page.evaluate(function () {
            return {width: width = 800, height : 630 };
        });
        page.paperSize = size;

        page.render(system.args[2]);
        phantom.exit();
    }, 3000);
});

page.onError = function(msg, trace) {
    console.log(msg);
}<|endoftext|>


<commit_before>function setUserEvents(mix){
  startAndStopTrack(mix)
  globalPause(mix);

  dropTrack(mix);

  //Put in deck user event file
  // changeTrackVolume(mix);

};

function dropTrack(mix){
  $(".cell").droppable({
    accept: ".draggableTrack",
    drop: function(event, ui) {

      var draggable = ui.draggable.clone();
      var divId = Number($(this).attr("id"));

      var trackId = Number(draggable.attr("id"));
      var trackTitle = draggable.text();
      var image = draggable.attr("image");
      var trackAdded = {src: draggable.attr("url"), id: trackId, name: draggable.html()}

      mix.addTrack({'urls': draggable.attr("url"), 'divId': divId})
      trackInfoHover($(this), trackTitle);
      loadImage(image, $(this));
      draggableImage();
      removeFromMixer(trackId);
      addToDeck();
    }
  });
}

function trackInfoHover(cell, trackTitle){
  $(cell).hover(function() {
    var targetComb = $(this).find('.inner-text')
      $(targetComb).html(trackTitle);
    },
    mouseExitCell
    );
}

function mouseExitCell(){
  $(this).find("#track-info").remove();
}

function returnDivs() {
  return $('div.cell')
};

function startAndStopTrack(mix) {

  // ON CLICK - PLAY AND STOP
  // returnDivs().on('click', controlBoard.togglePlay.bind(controlBoard));
  returnDivs().on('click', function(){
    var $targetDiv = $(this);
    var divId =  $targetDiv.attr("id");
    $targetDiv.toggleClass('active');
    $targetDiv.hasClass("active") ? mix.playTrack(divId) : mix.stopTrack(divId);
  });
}

// function ControlBoard() {
//   this.mix = mix;
// }

// ControlBoard.prototype.startSound = function(){}

// var controlBoard = {
//   mix: "foo",
//   startSound: function() {},
//   togglePlay: function() {
//     this.mix;
//   }
// }

function globalPause(mix) {
  // console.log( "running pause");
 $(window).on('keyup', function(e) {
  // console.log( "In Keyup");

    e.preventDefault();
    if(e.keyCode == 32) {
      // if Howls playing, pause
      if(mix.pause === false) {
        mix.globalPause();
      } else {
        mix.globalPlay();
      }

      //else Howls paused, play

    };
  });
}

function changeTrackVolume(mix) {
  $(window).on("keyup", function(event) {
    event.preventDefault();
    var $targetDiv   = $("div.on-deck")
    var soundId = $targetDiv.attr("id")

    var targetSound = _.find(mix.wads, function(wad) { return wad.label === Number(soundId) })

    if(event.keyCode == 38 && targetSound.volume < 4) {
      // increase volume
      console.log("Increase Volume")

      targetSound.setVolume(-2)
      // console
      // targetSound.defaultEnv.sustain = 0

      // targetSound.gain[0].gain.defaultValue = 5
      // targetSound.gain[0].gain.defaultValue = 5
      // targetSound.gain[0].gain.value = 5
      // targetSound.volume = 5
      // targetSound.defaultVolume = 5
      // console.log(targetSound.nodes[1].gain.value = 5)

      // targetSound.gain[0].gain.value = 5

      console.log(targetSound)

    } else if (event.keyCode == 40 && targetSound.volume > 1) {
      // decrease volume
      console.log("Decrease Volume")
      targetSound.setVolume(targetSound.volume - .5)
    }

  });
}

function removeFromMixer(trackId) {
  $(".cell").on("click", ".boxclose", function() {
    var cell = $(this).parent();
    sounds = _.reject(sounds, function(sound){
      return sound.id === trackId;
    });
    cell.removeClass("on-deck");
    $(cell.children("p")).remove();
    $(cell.children("img")).remove();
    $(cell.children(".boxclose")).remove();
  });
}

// ON DRAG -LOAD AND REMOVE FILES FROM MIXER
function addToMixer(){
// when dragged to mixer, load sound and assign to div
// loadSound(activeMix, trackId, divId)
};

function addToDeck(){
// when dragged to deck, enable effects
// only one item on Deck at a time
// if there is a track there already
// replace it
};

function noLongerActive(sound) {
// a function that removes the class "active" when a track finishes playing on its own
}

<commit_msg>Add controlPanelHover function<commit_after>function setUserEvents(mix){
  startAndStopTrack(mix)
  globalPause(mix);

  dropTrack(mix);

  //Put in deck user event file
  // changeTrackVolume(mix);

};

function dropTrack(mix){
  $(".cell").droppable({
    accept: ".draggableTrack",
    drop: function(event, ui) {

      var draggable = ui.draggable.clone();
      var divId = Number($(this).attr("id"));

      var trackId = Number(draggable.attr("id"));
      var trackTitle = draggable.text();
      var image = draggable.attr("image");
      var trackAdded = {src: draggable.attr("url"), id: trackId, name: draggable.html()}

      mix.addTrack({'urls': draggable.attr("url"), 'divId': divId})
      trackInfoHover($(this), trackTitle);
      loadImage(image, $(this));
      draggableImage();
      removeFromMixer(trackId);
      addToDeck();
    }
  });
}

function trackInfoHover(cell, trackTitle){
  $(cell).hover(function() {
    var targetComb = $(this).find('.inner-text')
      $(targetComb).html(trackTitle);
    },
    mouseExitCell
    );
}

function mouseExitCell(){
  $(this).find("#track-info").remove();
}

function returnDivs() {
  return $('div.cell')
};

function startAndStopTrack(mix) {

  // ON CLICK - PLAY AND STOP
  // returnDivs().on('click', controlBoard.togglePlay.bind(controlBoard));
  returnDivs().on('click', function(){
    var $targetDiv = $(this);
    var divId =  $targetDiv.attr("id");
    $targetDiv.toggleClass('active');
    $targetDiv.hasClass("active") ? mix.playTrack(divId) : mix.stopTrack(divId);
  });
}

function globalPause(mix) {
 $(window).on('keyup', function(e) {

    e.preventDefault();
    if(e.keyCode == 32) {
      if(mix.pause === false) {
        mix.globalPause();
      } else {
        mix.globalPlay();
      }

    };
  });
}

function controlPanelHover(cell){
  $(cell).hover(function() {
    $(this).toggleClass('on-deck')
    });
}

function changeTrackVolume(mix) {
  $(window).on("keyup", function(event) {
    event.preventDefault();
    var $targetDiv   = $("div.on-deck")
    var soundId = $targetDiv.attr("id")

    var targetSound = _.find(mix.wads, function(wad) { return wad.label === Number(soundId) })

    if(event.keyCode == 38 && targetSound.volume < 4) {
      // increase volume
      console.log("Increase Volume")

      targetSound.setVolume(-2)
      // console
      // targetSound.defaultEnv.sustain = 0

      // targetSound.gain[0].gain.defaultValue = 5
      // targetSound.gain[0].gain.defaultValue = 5
      // targetSound.gain[0].gain.value = 5
      // targetSound.volume = 5
      // targetSound.defaultVolume = 5
      // console.log(targetSound.nodes[1].gain.value = 5)

      // targetSound.gain[0].gain.value = 5

      console.log(targetSound)

    } else if (event.keyCode == 40 && targetSound.volume > 1) {
      // decrease volume
      console.log("Decrease Volume")
      targetSound.setVolume(targetSound.volume - .5)
    }

  });
}

function removeFromMixer(trackId) {
  $(".cell").on("click", ".boxclose", function() {
    var cell = $(this).parent();
    sounds = _.reject(sounds, function(sound){
      return sound.id === trackId;
    });
    cell.removeClass("on-deck");
    $(cell.children("p")).remove();
    $(cell.children("img")).remove();
    $(cell.children(".boxclose")).remove();
  });
}

// ON DRAG -LOAD AND REMOVE FILES FROM MIXER
function addToMixer(){
// when dragged to mixer, load sound and assign to div
// loadSound(activeMix, trackId, divId)
};

function addToDeck(){
// when dragged to deck, enable effects
// only one item on Deck at a time
// if there is a track there already
// replace it
};

function noLongerActive(sound) {
// a function that removes the class "active" when a track finishes playing on its own
}

<|endoftext|>


<commit_before>var Backbone = require('backbone');
var _ = require('underscore');
var LayerDefinitionModel = require('../../../../../../../javascripts/cartodb3/data/layer-definition-model');
var AnalysisFormsCollection = require('../../../../../../../javascripts/cartodb3/editor/layers/layer-content-views/analyses/analysis-forms-collection');
var AnalysesWorkflowListView = require('../../../../../../../javascripts/cartodb3/editor/layers/layer-content-views/analyses/analyses-workflow-list-view');
var AnalysisDefinitionNodesCollection = require('../../../../../../../javascripts/cartodb3/data/analysis-definition-nodes-collection');

describe('editor/layers/layer-content-view/analyses/analyses-workflow-list-view', function () {
  beforeEach(function () {
    this.analysisDefinitionNodesCollection = new AnalysisDefinitionNodesCollection(null, {
      configModel: {},
      userModel: {}
    });

    this.analysisDefinitionNodesCollection.add({
      id: 'a1',
      type: 'source',
      status: 'ready'
    });

    this.analysisDefinitionNodesCollection.add({
      id: 'a2',
      type: 'source',
      status: 'ready'
    });

    this.analysisDefinitionNodesCollection.add({
      id: 'a3',
      type: 'source',
      status: 'ready'
    });

    this.layerDefModel = new LayerDefinitionModel({
      id: 'l-1',
      options: {
        type: 'CartoDB',
        table_name: 'foo',
        source: 'a1',
        letter: 'a'
      }
    }, {
      parse: true,
      collection: new Backbone.Collection(),
      configModel: {}
    });
    spyOn(this.layerDefModel, 'getAnalysisDefinitionNodeModel');

    this.viewModel = new Backbone.Model({
      selectedNodeId: 'a2'
    });

    this.analysisFormsCollection = new AnalysisFormsCollection(null, {
      configModel: {},
      userActions: {},
      layerDefinitionModel: this.layerDefModel,
      analysisSourceOptionsModel: {}
    });
    this.analysisFormsCollection.add([
      {id: 'a3'},
      {id: 'a2'},
      {id: 'a1'}
    ]);
    spyOn(this.analysisFormsCollection, 'deleteNode');

    this.view = new AnalysesWorkflowListView({
      analysisDefinitionNodesCollection: this.analysisDefinitionNodesCollection,
      analysisFormsCollection: this.analysisFormsCollection,
      model: this.viewModel,
      layerId: this.layerDefModel.id,
      hideAddButton: false
    });
    this.view.render();
  });

  it('should render correctly', function () {
    expect(_.size(this.view._subviews)).toBe(4); // [3 x Analysis Node, Tooltip]
  });

  it('should display add button and the list of analysis', function () {
    expect(this.view.$('.js-add-analysis').length).toBe(1);
    expect(this.view.$('.js-add-analysis').data('layer-id')).toEqual('l-1');
  });

  it('should render an item per node', function () {
    var content = this.view.$el.html();

    expect(content).toContain('a3');
    expect(content).toContain('a2');
    expect(content).toContain('a1');
  });

  it('should highlight selected node', function () {
    expect(this.view.$('li:eq(1) .VerticalRadioList-radio .CDB-Radio').attr('checked')).toBe('checked');
    expect(this.view.$('li:eq(1)').text()).toContain('a2');
  });

  describe('when another non-selected node is clicked', function () {
    beforeEach(function () {
      this.view.$('li:eq(2)').click();
    });

    it('should change selected workflow item', function () {
      expect(this.viewModel.get('selectedNodeId')).toEqual('a1');
    });

    it('should only have one item selected still', function () {
      expect(this.view.$('.CDB-Radio:checked').length).toEqual(1);
    });
  });

  it('should not have any leaks', function () {
    expect(this.view).toHaveNoLeaks();
  });

  afterEach(function () {
    this.view.clean();
  });
});
<commit_msg>Add tests for error/loading states<commit_after>var Backbone = require('backbone');
var _ = require('underscore');
var LayerDefinitionModel = require('../../../../../../../javascripts/cartodb3/data/layer-definition-model');
var AnalysisFormsCollection = require('../../../../../../../javascripts/cartodb3/editor/layers/layer-content-views/analyses/analysis-forms-collection');
var AnalysesWorkflowListView = require('../../../../../../../javascripts/cartodb3/editor/layers/layer-content-views/analyses/analyses-workflow-list-view');
var AnalysisDefinitionNodesCollection = require('../../../../../../../javascripts/cartodb3/data/analysis-definition-nodes-collection');

describe('editor/layers/layer-content-view/analyses/analyses-workflow-list-view', function () {
  beforeEach(function () {
    this.analysisDefinitionNodesCollection = new AnalysisDefinitionNodesCollection(null, {
      configModel: {},
      userModel: {}
    });

    this.analysisDefinitionNodesCollection.add({
      id: 'a1',
      type: 'source',
      status: 'ready'
    });

    this.analysisDefinitionNodesCollection.add({
      id: 'a2',
      type: 'source',
      status: 'ready'
    });

    this.analysisDefinitionNodesCollection.add({
      id: 'a3',
      type: 'source',
      status: 'ready'
    });

    this.layerDefModel = new LayerDefinitionModel({
      id: 'l-1',
      options: {
        type: 'CartoDB',
        table_name: 'foo',
        source: 'a1',
        letter: 'a'
      }
    }, {
      parse: true,
      collection: new Backbone.Collection(),
      configModel: {}
    });
    spyOn(this.layerDefModel, 'getAnalysisDefinitionNodeModel');

    this.viewModel = new Backbone.Model({
      selectedNodeId: 'a2'
    });

    this.analysisFormsCollection = new AnalysisFormsCollection(null, {
      configModel: {},
      userActions: {},
      layerDefinitionModel: this.layerDefModel,
      analysisSourceOptionsModel: {}
    });
    this.analysisFormsCollection.add([
      {id: 'a3'},
      {id: 'a2'},
      {id: 'a1'}
    ]);
    spyOn(this.analysisFormsCollection, 'deleteNode');

    this.view = new AnalysesWorkflowListView({
      analysisDefinitionNodesCollection: this.analysisDefinitionNodesCollection,
      analysisFormsCollection: this.analysisFormsCollection,
      model: this.viewModel,
      layerId: this.layerDefModel.id,
      hideAddButton: false
    });
    this.view.render();
  });

  it('should render correctly', function () {
    expect(_.size(this.view._subviews)).toBe(4); // [3 x Analysis Node, Tooltip]
  });

  it('should display add button and the list of analysis', function () {
    expect(this.view.$('.js-add-analysis').length).toBe(1);
    expect(this.view.$('.js-add-analysis').data('layer-id')).toEqual('l-1');
  });

  it('should render an item per node', function () {
    var content = this.view.$el.html();

    expect(content).toContain('a3');
    expect(content).toContain('a2');
    expect(content).toContain('a1');
  });

  it('should highlight selected node', function () {
    expect(this.view.$('li:eq(1) .VerticalRadioList-radio .CDB-Radio').attr('checked')).toBe('checked');
    expect(this.view.$('li:eq(1)').text()).toContain('a2');
  });

  describe('when another non-selected node is clicked', function () {
    beforeEach(function () {
      this.view.$('li:eq(2)').click();
    });

    it('should change selected workflow item', function () {
      expect(this.viewModel.get('selectedNodeId')).toEqual('a1');
    });

    it('should only have one item selected still', function () {
      expect(this.view.$('.CDB-Radio:checked').length).toEqual(1);
    });
  });

  describe('when a node has failed', function () {
    it('should have a has-failed class', function () {
      var analysisNodeModel = this.analysisDefinitionNodesCollection.models[0];
      analysisNodeModel.set('status', 'failed');
      this.view.render();

      // The first analysis is the last in the list
      expect(this.view.$('li:eq(2) .VerticalRadioList-itemInner').hasClass('has-error')).toBe(true);
    });
  });

  describe('when a node is loading', function () {
    it('should show a loader', function () {
      var analysisNodeModel = this.analysisDefinitionNodesCollection.models[0];
      analysisNodeModel.set('status', 'loading');
      this.view.render();

      // The first analysis is the last in the list
      expect(this.view.$('li:eq(2)').html()).toContain('CDB-LoaderIcon');
    });
  });

  it('should not have any leaks', function () {
    expect(this.view).toHaveNoLeaks();
  });

  afterEach(function () {
    this.view.clean();
  });
});
<|endoftext|>


<commit_before>'use strict';

(function(window) {
    /******************** private variables ********************/
    var _isDeviceMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),
        _dataAttributes = {
            accountBlockTrigger: 'ptn-account-block-trigger',
            dropdownTrigger: 'ptn-dropdown-trigger'
        },
        _selectors = {
            pageLoader: '#page-loader',
            asideTrigger: '#aside-trigger',
            aside: '#aside',
            listItem: '.ptn-list__item',
            listItemActive: '.ptn-list__item_active',
            listLink: '.ptn-list__link',
            sublist: '.ptn-list_sublist',
            sublistTrigger: '.ptn-list__item_sublist > .ptn-list__link',
            dropdown: '.ptn-dropdown',
            dropdownTrigger: '.ptn-dropdown__trigger',
            dropdownTriggerGeneral: '[' + _dataAttributes.dropdownTrigger + ']',
            accountBlockTrigger: '[' + _dataAttributes.accountBlockTrigger + ']',
            accountBlock: '.ptn-account-block',
            accountBlockSubmit: '.ptn-account-block__submit',
            inputBlock: '.ptn-input-block',
            inputBlockInputText: '.ptn-input-block__input-text'
        },
        // Disabled because localStorage doesn't work in private browsing.
        // _localStorageKeys = {
        //     statusAside: 'ptn-status-aside'
        // },
        _classes = {
            triggerOn: 'ptn-util__trigger_on',
            widgetOn: 'ptn-util__widget_on',
            htmlMobileDevice: 'ptn-html_mobile-device',
            bodyAsideOn: 'ptn-body_aside-on'
        },
        _actions = {
            show: 'show',
            hide: 'hide'
        },
        _statuses = {
            on: 'on',
            off: 'off'
        },
        _animationDurations = {
            slide: 200,
            click: 500,
            fade: 500
        },
        _delay = {
            pageLoader: 500
        },
        _$window = $(window),
        _$document = $(document),
        _$html = $('html'),
        _$body = $('body');

    /******************** mobile device class ********************/
    if (_isDeviceMobile) {
        _$html.addClass(_classes.htmlMobileDevice);
    }

    /******************** event: DOM ready ********************/
    $(function() {
        /******************** disable pinch-to-zoom for iOS safari ********************/
        _$document.on('gesturestart', function(e) {
            e.preventDefault();
        });

        /******************** widget: waves ********************/
        (function() {
            Waves.attach(_selectors.listLink, ['waves-light']);
            Waves.attach(_selectors.accountBlockSubmit);

            Waves.init({
                duration: _animationDurations.click
            });
        })();

        /******************** widget: scrollbar ********************/
        (function() {
            _addScrollBar($(_selectors.aside), 'minimal-dark', 'y');
        })();

        /******************** widget: aside | toggle ********************/
        // Disabled because localStorage doesn't work in private browsing.
        // (function() {
        //     var asideStatus = localStorage.getItem(_localStorageKeys.statusAside);
        //
        //     if (asideStatus === _statuses.on) {
        //         _toggleAsideStatelessly(_actions.show);
        //     }
        //
        //     _$body.on('click touchend', _selectors.asideTrigger, function(e) {
        //         _toggleAside();
        //     });
        // })();

        (function() {
            _$body.on('click touchend', _selectors.asideTrigger, function() {
                _toggleAside();
            });
        })();

        /******************** widget: sublist | init ********************/
        (function() {
            _resetSublists();
        })();

        /******************** widget: sublist | toggle ********************/
        (function() {
            _$body.on('click touchend', _selectors.sublistTrigger, function() {
                _toggleSublist($(this));
            });

            function _toggleSublist($trigger) {
                var isSublistOn = $trigger.hasClass(_classes.triggerOn),
                    $listItemClosest = $trigger.closest(_selectors.listItem);

                if (isSublistOn) {
                    $listItemClosest.find(_selectors.sublist).slideUp(_animationDurations.slide);
                    $listItemClosest.find(_selectors.listLink).removeClass(_classes.triggerOn);
                } else {
                    $trigger.next(_selectors.sublist).slideDown(_animationDurations.slide);
                    $trigger.addClass(_classes.triggerOn);
                }
            }
        })();

        /******************** widget: dropdown | toggle ********************/
        (function() {
            _$body.on('click touchend', _selectors.dropdownTrigger, function() {
                var $dropdownTrigger = $(this),
                    $dropdown = $dropdownTrigger.closest(_selectors.dropdown);

                $dropdownTrigger.toggleClass(_classes.triggerOn);
                $dropdown.toggleClass(_classes.widgetOn);
            });

            _$body.on('click touchend', _selectors.dropdownTriggerGeneral, function(e) {
                e.stopPropagation();

                var dropdownId = $(this).attr(_dataAttributes.dropdownTrigger),
                    $dropdown = $('#' + dropdownId),
                    $dropdownTrigger = $dropdown.find(_selectors.dropdownTrigger);

                $dropdownTrigger.addClass(_classes.triggerOn);
                $dropdown.addClass(_classes.widgetOn);
            });

            _$body.on('click touchend', function(e) {
                var $target = $(e.target),
                    isTargetDropdown = $target.closest(_selectors.dropdown).length > 0;

                if (isTargetDropdown) {
                    return;
                }

                $(_selectors.dropdownTrigger).removeClass(_classes.triggerOn);
                $(_selectors.dropdown).removeClass(_classes.widgetOn);
            });
        })();

        /******************** widget: account block | switch ********************/
        (function() {
            _switchAccountBlock('account-block-sign-up');
            _switchAccountBlock('account-block-update');

            _$body.on('click touchend', _selectors.accountBlockTrigger, function() {
                var accountBlockId = $(this).attr(_dataAttributes.accountBlockTrigger);

                _switchAccountBlock(accountBlockId);
            });
        })();

        /******************** widget: input block | focus ********************/
        (function() {
            _$body.on('focus', _selectors.inputBlockInputText, function() {
                $(this).closest(_selectors.inputBlock).addClass(_classes.widgetOn);
            }).on('blur', _selectors.inputBlockInputText, function() {
                $(this).closest(_selectors.inputBlock).removeClass(_classes.widgetOn);
            });
        })();
    });

    /******************** event: page load ********************/
    _$window.on('load', function() {
        /******************** widget: page loader ********************/
        var $pageLoader = $(_selectors.pageLoader);

        if (_isElementExistent($pageLoader)) {
            window.setTimeout(function() {
                $pageLoader.fadeOut(_animationDurations.fade);
            }, _delay.pageLoader);
        }
    });

    /******************** private functions ********************/
    function _isElementExistent($element) {
        return !!$element.length;
    }

    function _addScrollBar($element, theme, mouseWheelAxis) {
        if (!_isElementExistent($element)) {
            return;
        }

        $element.mCustomScrollbar({
            theme: theme,
            scrollInertia: 100,
            axis: 'y',
            mouseWheel: {
                preventDefault: true,
                enable: true,
                axis: mouseWheelAxis
            }
        });
    }

    function _scrollTo($element, position) {
        $element.mCustomScrollbar('scrollTo', position, {
            scrollInertia: 0
        });
    }

    // Disabled because localStorage doesn't work in private browsing.
    // function _toggleAside() {
    //     var statusOld = localStorage.getItem(_localStorageKeys.statusAside),
    //         statusNew = statusOld === _statuses.on ? _statuses.off : _statuses.on,
    //         $asideTrigger = $(_selectors.asideTrigger),
    //         $aside = $(_selectors.aside);
    //
    //     localStorage.setItem(_localStorageKeys.statusAside, statusNew);
    //
    //     _$body.toggleClass(_classes.bodyAsideOn);
    //     $asideTrigger.toggleClass(_classes.triggerOn);
    //     $aside.toggleClass(_classes.widgetOn);
    //
    //     statusNew === _statuses.on && _resetSublists();
    //     _scrollTo($aside, 'top');
    // }

    function _toggleAside() {
        var $asideTrigger = $(_selectors.asideTrigger),
            $aside = $(_selectors.aside);

        _$body.toggleClass(_classes.bodyAsideOn);
        $asideTrigger.toggleClass(_classes.triggerOn);
        $aside.toggleClass(_classes.widgetOn);

        _$body.hasClass(_classes.bodyAsideOn) && _resetSublists();
        _scrollTo($aside, 'top');
    }

    function _toggleAsideStatelessly(action) {
        var $asideTrigger = $(_selectors.asideTrigger),
            $aside = $(_selectors.aside);

        if (action === _actions.show) {
            _$body.addClass(_classes.bodyAsideOn);
            $asideTrigger.addClass(_classes.triggerOn);
            $aside.addClass(_classes.widgetOn);
        } else if (action === _actions.hide) {
            _$body.removeClass(_classes.bodyAsideOn);
            $asideTrigger.removeClass(_classes.triggerOn);
            $aside.removeClass(_classes.widgetOn);
        }

        _resetSublists();
        _scrollTo($aside, 'top');
    }

    function _resetSublists() {
        var $activeListItemAncestors = $(_selectors.listItemActive).parents();

        $(_selectors.sublist).hide();
        $(_selectors.sublistTrigger).removeClass(_classes.triggerOn);

        $activeListItemAncestors.each(function() {
            var $listItem = $(this);

            $listItem.children(_selectors.sublist).show();
            $listItem.children(_selectors.sublistTrigger).addClass(_classes.triggerOn);
        });
    }

    function _switchAccountBlock(accountBlockId) {
        var $accountBlocks = $(_selectors.accountBlock),
            $accountBlock = $('#' + accountBlockId);

        if (!_isElementExistent($accountBlock)) {
            return;
        }

        $accountBlocks.removeClass(_classes.widgetOn);
        $accountBlock.addClass(_classes.widgetOn);
    }
})(window);
<commit_msg>[JS] Recovered some "preventDefault" statements.<commit_after>'use strict';

(function(window) {
    /******************** private variables ********************/
    var _isDeviceMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),
        _dataAttributes = {
            accountBlockTrigger: 'ptn-account-block-trigger',
            dropdownTrigger: 'ptn-dropdown-trigger'
        },
        _selectors = {
            pageLoader: '#page-loader',
            asideTrigger: '#aside-trigger',
            aside: '#aside',
            listItem: '.ptn-list__item',
            listItemActive: '.ptn-list__item_active',
            listLink: '.ptn-list__link',
            sublist: '.ptn-list_sublist',
            sublistTrigger: '.ptn-list__item_sublist > .ptn-list__link',
            dropdown: '.ptn-dropdown',
            dropdownTrigger: '.ptn-dropdown__trigger',
            dropdownTriggerGeneral: '[' + _dataAttributes.dropdownTrigger + ']',
            accountBlockTrigger: '[' + _dataAttributes.accountBlockTrigger + ']',
            accountBlock: '.ptn-account-block',
            accountBlockSubmit: '.ptn-account-block__submit',
            inputBlock: '.ptn-input-block',
            inputBlockInputText: '.ptn-input-block__input-text'
        },
        // Disabled because localStorage doesn't work in private browsing.
        // _localStorageKeys = {
        //     statusAside: 'ptn-status-aside'
        // },
        _classes = {
            triggerOn: 'ptn-util__trigger_on',
            widgetOn: 'ptn-util__widget_on',
            htmlMobileDevice: 'ptn-html_mobile-device',
            bodyAsideOn: 'ptn-body_aside-on'
        },
        _actions = {
            show: 'show',
            hide: 'hide'
        },
        _statuses = {
            on: 'on',
            off: 'off'
        },
        _animationDurations = {
            slide: 200,
            click: 500,
            fade: 500
        },
        _delay = {
            pageLoader: 500
        },
        _$window = $(window),
        _$document = $(document),
        _$html = $('html'),
        _$body = $('body');

    /******************** mobile device class ********************/
    if (_isDeviceMobile) {
        _$html.addClass(_classes.htmlMobileDevice);
    }

    /******************** event: DOM ready ********************/
    $(function() {
        /******************** disable pinch-to-zoom for iOS safari ********************/
        _$document.on('gesturestart', function(e) {
            e.preventDefault();
        });

        /******************** widget: waves ********************/
        (function() {
            Waves.attach(_selectors.listLink, ['waves-light']);
            Waves.attach(_selectors.accountBlockSubmit);

            Waves.init({
                duration: _animationDurations.click
            });
        })();

        /******************** widget: scrollbar ********************/
        (function() {
            _addScrollBar($(_selectors.aside), 'minimal-dark', 'y');
        })();

        /******************** widget: aside | toggle ********************/
        // Disabled because localStorage doesn't work in private browsing.
        // (function() {
        //     var asideStatus = localStorage.getItem(_localStorageKeys.statusAside);
        //
        //     if (asideStatus === _statuses.on) {
        //         _toggleAsideStatelessly(_actions.show);
        //     }
        //
        //     _$body.on('click touchend', _selectors.asideTrigger, function(e) {
        //         e.preventDefault();
        //
        //         _toggleAside();
        //     });
        // })();

        (function() {
            _$body.on('click touchend', _selectors.asideTrigger, function(e) {
                e.preventDefault();

                _toggleAside();
            });
        })();

        /******************** widget: sublist | init ********************/
        (function() {
            _resetSublists();
        })();

        /******************** widget: sublist | toggle ********************/
        (function() {
            _$body.on('click touchend', _selectors.sublistTrigger, function(e) {
                e.preventDefault();

                _toggleSublist($(this));
            });

            function _toggleSublist($trigger) {
                var isSublistOn = $trigger.hasClass(_classes.triggerOn),
                    $listItemClosest = $trigger.closest(_selectors.listItem);

                if (isSublistOn) {
                    $listItemClosest.find(_selectors.sublist).slideUp(_animationDurations.slide);
                    $listItemClosest.find(_selectors.listLink).removeClass(_classes.triggerOn);
                } else {
                    $trigger.next(_selectors.sublist).slideDown(_animationDurations.slide);
                    $trigger.addClass(_classes.triggerOn);
                }
            }
        })();

        /******************** widget: dropdown | toggle ********************/
        (function() {
            _$body.on('click touchend', _selectors.dropdownTrigger, function(e) {
                e.preventDefault();

                var $dropdownTrigger = $(this),
                    $dropdown = $dropdownTrigger.closest(_selectors.dropdown);

                $dropdownTrigger.toggleClass(_classes.triggerOn);
                $dropdown.toggleClass(_classes.widgetOn);
            });

            _$body.on('click touchend', _selectors.dropdownTriggerGeneral, function(e) {
                e.preventDefault();
                e.stopPropagation();

                var dropdownId = $(this).attr(_dataAttributes.dropdownTrigger),
                    $dropdown = $('#' + dropdownId),
                    $dropdownTrigger = $dropdown.find(_selectors.dropdownTrigger);

                $dropdownTrigger.addClass(_classes.triggerOn);
                $dropdown.addClass(_classes.widgetOn);
            });

            _$body.on('click touchend', function(e) {
                var $target = $(e.target),
                    isTargetDropdown = $target.closest(_selectors.dropdown).length > 0;

                if (isTargetDropdown) {
                    return;
                }

                $(_selectors.dropdownTrigger).removeClass(_classes.triggerOn);
                $(_selectors.dropdown).removeClass(_classes.widgetOn);
            });
        })();

        /******************** widget: account block | switch ********************/
        (function() {
            _switchAccountBlock('account-block-sign-up');
            _switchAccountBlock('account-block-update');

            _$body.on('click touchend', _selectors.accountBlockTrigger, function(e) {
                e.preventDefault();

                var accountBlockId = $(this).attr(_dataAttributes.accountBlockTrigger);

                _switchAccountBlock(accountBlockId);
            });
        })();

        /******************** widget: input block | focus ********************/
        (function() {
            _$body.on('focus', _selectors.inputBlockInputText, function(e) {
                e.preventDefault();

                $(this).closest(_selectors.inputBlock).addClass(_classes.widgetOn);
            }).on('blur', _selectors.inputBlockInputText, function(e) {
                e.preventDefault();

                $(this).closest(_selectors.inputBlock).removeClass(_classes.widgetOn);
            });
        })();
    });

    /******************** event: page load ********************/
    _$window.on('load', function() {
        /******************** widget: page loader ********************/
        var $pageLoader = $(_selectors.pageLoader);

        if (_isElementExistent($pageLoader)) {
            window.setTimeout(function() {
                $pageLoader.fadeOut(_animationDurations.fade);
            }, _delay.pageLoader);
        }
    });

    /******************** private functions ********************/
    function _isElementExistent($element) {
        return !!$element.length;
    }

    function _addScrollBar($element, theme, mouseWheelAxis) {
        if (!_isElementExistent($element)) {
            return;
        }

        $element.mCustomScrollbar({
            theme: theme,
            scrollInertia: 100,
            axis: 'y',
            mouseWheel: {
                preventDefault: true,
                enable: true,
                axis: mouseWheelAxis
            }
        });
    }

    function _scrollTo($element, position) {
        $element.mCustomScrollbar('scrollTo', position, {
            scrollInertia: 0
        });
    }

    // Disabled because localStorage doesn't work in private browsing.
    // function _toggleAside() {
    //     var statusOld = localStorage.getItem(_localStorageKeys.statusAside),
    //         statusNew = statusOld === _statuses.on ? _statuses.off : _statuses.on,
    //         $asideTrigger = $(_selectors.asideTrigger),
    //         $aside = $(_selectors.aside);
    //
    //     localStorage.setItem(_localStorageKeys.statusAside, statusNew);
    //
    //     _$body.toggleClass(_classes.bodyAsideOn);
    //     $asideTrigger.toggleClass(_classes.triggerOn);
    //     $aside.toggleClass(_classes.widgetOn);
    //
    //     statusNew === _statuses.on && _resetSublists();
    //     _scrollTo($aside, 'top');
    // }

    function _toggleAside() {
        var $asideTrigger = $(_selectors.asideTrigger),
            $aside = $(_selectors.aside);

        _$body.toggleClass(_classes.bodyAsideOn);
        $asideTrigger.toggleClass(_classes.triggerOn);
        $aside.toggleClass(_classes.widgetOn);

        _$body.hasClass(_classes.bodyAsideOn) && _resetSublists();
        _scrollTo($aside, 'top');
    }

    function _toggleAsideStatelessly(action) {
        var $asideTrigger = $(_selectors.asideTrigger),
            $aside = $(_selectors.aside);

        if (action === _actions.show) {
            _$body.addClass(_classes.bodyAsideOn);
            $asideTrigger.addClass(_classes.triggerOn);
            $aside.addClass(_classes.widgetOn);
        } else if (action === _actions.hide) {
            _$body.removeClass(_classes.bodyAsideOn);
            $asideTrigger.removeClass(_classes.triggerOn);
            $aside.removeClass(_classes.widgetOn);
        }

        _resetSublists();
        _scrollTo($aside, 'top');
    }

    function _resetSublists() {
        var $activeListItemAncestors = $(_selectors.listItemActive).parents();

        $(_selectors.sublist).hide();
        $(_selectors.sublistTrigger).removeClass(_classes.triggerOn);

        $activeListItemAncestors.each(function() {
            var $listItem = $(this);

            $listItem.children(_selectors.sublist).show();
            $listItem.children(_selectors.sublistTrigger).addClass(_classes.triggerOn);
        });
    }

    function _switchAccountBlock(accountBlockId) {
        var $accountBlocks = $(_selectors.accountBlock),
            $accountBlock = $('#' + accountBlockId);

        if (!_isElementExistent($accountBlock)) {
            return;
        }

        $accountBlocks.removeClass(_classes.widgetOn);
        $accountBlock.addClass(_classes.widgetOn);
    }
})(window);
<|endoftext|>


<commit_before>const fs = require('fs');
const path = require('path');

const prettierOptions = JSON.parse(
  fs.readFileSync(path.resolve(__dirname, '.prettierrc'), 'utf8'),
);

module.exports = {
  parser: '@babel/eslint-parser',
  extends: ['airbnb-base', 'prettier'],
  plugins: ['prettier', 'import'],
  rules: {
    'prettier/prettier': ['error', prettierOptions],
    'no-use-before-define': 0,
    'import/no-extraneous-dependencies': 0,
  },
  globals: {
    document: true,
    window: true,
    location: true,
    fetch: true,
  },
  settings: {
    'import/resolver': {
      webpack: {
        config: 'webpack/webpack.config.base.js',
      },
    },
  },
};
<commit_msg>stop checking for babel config file (it's in our webpack configs now)<commit_after>const fs = require('fs');
const path = require('path');

const prettierOptions = JSON.parse(
  fs.readFileSync(path.resolve(__dirname, '.prettierrc'), 'utf8'),
);

module.exports = {
  extends: ['airbnb-base', 'prettier'],
  plugins: ['prettier', 'import'],
  parser: '@babel/eslint-parser',
  parserOptions: {
    requireConfigFile: false,
  },
  rules: {
    'prettier/prettier': ['error', prettierOptions],
    'no-use-before-define': 0,
    'import/no-extraneous-dependencies': 0,
  },
  globals: {
    document: true,
    window: true,
    location: true,
    fetch: true,
  },
  settings: {
    'import/resolver': {
      webpack: {
        config: 'webpack/webpack.config.base.js',
      },
    },
  },
};
<|endoftext|>


<commit_before>(function($window, $ember, $io, $jq) {

    "use strict";

    /**
     * @module ES
     * @subModule Module
     */
    $window.EmberSockets = $ember.ObjectController.extend({

        /**
         * @constant NAMESPACE
         * @type {String}
         */
        NAMESPACE: 'sockets',

        /**
         * @property host
         * @type {String}
         * @default 'localhost'
         */
        host: '',

        /**
         * @property secure
         * @type {Boolean}
         * @default false
         */
        secure: false,

        /**
         * @property port
         * @type {Number}
         * @default null
         */
        port: null,

        /**
         * List of controllers for which the events can be emitted to.
         *
         * @property controllers
         * @type {Array}
         * @default []
         */
        controllers: [],

        /**
         * @property socket {Object}
         * @type {Object|null}
         */
        socket: null,

        /**
         * @method init
         * @return {void}
         */
        init: function init() {

            if ($ember.get(this, 'autoConnect')) {

                // Connect immediately to the WebSockets server unless the developer has decided
                // to disable the auto-connect option.
                this.connect();

            }

        },

        /**
         * Responsible for establishing a connect to the Socket.io server.
         *
         * @method connect
         * @param params {Object}
         * @return {void}
         */
        connect: function connect(params) {

            /**
             * @property server
             * @type {String}
             */
            var server = '';

            (function determineHost(controller) {

                var host    = $ember.get(controller, 'host'),
                    port    = $ember.get(controller, 'port'),
                    scheme  = $ember.get(controller, 'secure') === true ? 'https' : 'http',
                    path    = $ember.get(controller, 'path') || '';

                if (!host && !port) {
                    return;
                }

                // Use the host to compile the connect string.
                server = !port ? '%@://%@/%@'.fmt(scheme, host, path)
                               : '%@://%@:%@/%@'.fmt(scheme, host, port, path);

            })(this);

            // Create the host:port string for connecting, and then attempt to establish
            // a connection.
            var options = $ember.get(this, 'options') || {},
                socket  = $io(server, $jq.extend(options, params || {}));

            socket.on('error', this.error);

            // Store a reference to the socket.
            this.set('socket', socket);

            /**
             * @on connect
             */
            socket.on('connect', this._listen.bind(this));

        },

        /**
         * @method error
         * @param errorData {Object}
         * @return {void}
         */
        error: function(errorData) {

            // Throw an exception if an error occurs.
            $window.console.error(errorData);
            throw 'EmberSockets: An error occurred.';

        },

        /**
         * Responsible for emitting an event to the waiting Socket.io server.
         *
         * @method emit
         * @param eventName {String}
         * @param params {Array}
         * @return {void}
         */
        emit: function emit(eventName, params) {

            //jshint unused:false
            var args    = Array.prototype.slice.call(arguments),
                scope   = $ember.get(this, 'socket');

            scope.emit.apply(scope, args);

        },

        /**
         * Responsible for listening to events from Socket.io, and updating controller properties that
         * subscribe to those events.
         *
         * @method _listen
         * @return {void}
         * @private
         */
        _listen: function _listen() {

            var controllers     = $ember.get(this, 'controllers'),
                getController   = this._getController.bind(this),
                events          = [],
                forEach         = $ember.EnumerableUtils,
                module          = this,
                respond         = function respond() {
                    var eventData = Array.prototype.slice.call(arguments);
                    module._update.call(module, this, eventData);
                };

            forEach.forEach(controllers, function controllerIteration(controllerName) {

                // Fetch the controller if it's valid.
                var controller  = getController(controllerName),
                    eventNames  = controller[this.NAMESPACE];

                if (controller) {

                    // Invoke the `connect` method if it has been defined on this controller.
                    if (typeof controller[this.NAMESPACE] === 'object' && typeof controller[this.NAMESPACE].connect === 'function') {
                        controller[this.NAMESPACE].connect.apply(controller);
                    }

                    // Iterate over each event defined in the controller's `sockets` hash, so that we can
                    // keep an eye open for them.
                    for (var eventName in eventNames) {

                        if (eventNames.hasOwnProperty(eventName)) {

                            if (events.indexOf(eventName) !== -1) {
                                // Don't observe this event if we're already observing it.
                                continue;
                            }

                            // Push the event so we don't listen for it twice.
                            events.push(eventName);

                            // Check to ensure the event was not previously registered due to a reconnect
                            if (!(eventName in $ember.get(module, 'socket')._callbacks)) {

                                // ...And finally we can register the event to listen for it.
                                $ember.get(module, 'socket').on(eventName, respond.bind(eventName));

                            }

                        }

                    }

                }

            }, this);

        },

        /**
         * @method _update
         * @param eventName {String}
         * @param eventData {String|Number|Object}
         * @return {Number} Number of controllers which responded to the event.
         * @private
         */
        _update: function _update(eventName, eventData) {

            var controllers             = $ember.get(this, 'controllers'),
                respondingControllers   = 0,
                getController           = this._getController.bind(this),
                forEach                 =  $ember.EnumerableUtils.forEach;

            $ember.run(this, function() {

                // Iterate over each listener controller and emit the event we caught.
                forEach(controllers, function(controllerName) {

                    // Fetch the controller if it's valid.
                    var controller = getController(controllerName);

                    if (controller) {

                        // Attempt to find a match for the current event name.
                        var correspondingAction = controller[this.NAMESPACE][eventName];

                        if (!correspondingAction) {
                            // If we can't find it, then we can't go any further for this controller.
                            return;
                        }

                        if (typeof correspondingAction === 'function') {

                            // We need to invoke the function to respond to the event because the coder
                            // has specified a callback instead of a property to update.
                            correspondingAction.apply(controller, eventData);
                            respondingControllers++;
                            return;

                        }

                        // Determine if the property is specifying multiple properties to update.
                        if ($ember.isArray(correspondingAction)) {

                            forEach(correspondingAction, function propertyIteration(property, index) {

                                // Update each property included in the array of properties.
                                $ember.set(controller, property, eventData[index]);

                            });

                            respondingControllers++;
                            return;

                        }

                        // Otherwise it's a single property to update.
                        $ember.set(controller, correspondingAction, eventData);
                        respondingControllers++;

                    }

                }, this);

            });

            return respondingControllers;

        },

        /**
         * Responsible for retrieving a controller if it exists, and if it has defined a `events` hash.
         *
         * @method _getController
         * @param name {String}
         * @return {Object|Boolean}
         * @private
         */
        _getController: function _getController(name) {

            // Format the `name` to match what the lookup container is expecting, and then
            // we'll locate the controller from the `container`.
            name = 'controller:%@'.fmt(name);
            var controller = this.container.lookup(name);

            if (!controller || (this.NAMESPACE in controller === false)) {
                // Don't do anything with this controller if it hasn't defined a `sockets` hash.
                return false;
            }

            return controller;

        }

    });

    /**
     * @onLoad Ember.Application
     * @param $app {Object}
     */
    $ember.onLoad('Ember.Application', function($app) {

        $app.initializer({

            /**
             * @property name
             * @type {String}
             * @default 'sockets'
             */
            name: 'sockets',

            /**
             * @method initialize
             * @param container {Object}
             * @param application {Object}
             * @return {void}
             */
            initialize: function(container, application) {

                if (typeof application.Socket === 'undefined') {

                    // Ensure the developer has defined `Socket` in their `Ember.Application`.
                    throw 'You have forgotten to add `EmberSockets` into `Ember.Application`! See: https://github.com/Wildhoney/EmberSockets#getting-started';

                }

                // Register `socket:main` with Ember.js.
                application.register('socket:main', application.Socket, {
                    singleton: true
                });

                // We then want to inject `socket` into each controller and route.
                application.inject('controller', 'socket', 'socket:main');
                application.inject('route', 'socket', 'socket:main');

            }

        });
    });

})(window, window.Ember, window.io, window.jQuery);<commit_msg>Defined optional param<commit_after>(function($window, $ember, $io, $jq) {

    "use strict";

    /**
     * @module ES
     * @subModule Module
     */
    $window.EmberSockets = $ember.ObjectController.extend({

        /**
         * @constant NAMESPACE
         * @type {String}
         */
        NAMESPACE: 'sockets',

        /**
         * @property host
         * @type {String}
         * @default 'localhost'
         */
        host: '',

        /**
         * @property secure
         * @type {Boolean}
         * @default false
         */
        secure: false,

        /**
         * @property port
         * @type {Number}
         * @default null
         */
        port: null,

        /**
         * List of controllers for which the events can be emitted to.
         *
         * @property controllers
         * @type {Array}
         * @default []
         */
        controllers: [],

        /**
         * @property socket {Object}
         * @type {Object|null}
         */
        socket: null,

        /**
         * @method init
         * @return {void}
         */
        init: function init() {

            if ($ember.get(this, 'autoConnect')) {

                // Connect immediately to the WebSockets server unless the developer has decided
                // to disable the auto-connect option.
                this.connect();

            }

        },

        /**
         * Responsible for establishing a connect to the Socket.io server.
         *
         * @method connect
         * @param [params={}] {Object}
         * @return {void}
         */
        connect: function connect(params) {

            /**
             * @property server
             * @type {String}
             */
            var server = '';

            (function determineHost(controller) {

                var host    = $ember.get(controller, 'host'),
                    port    = $ember.get(controller, 'port'),
                    scheme  = $ember.get(controller, 'secure') === true ? 'https' : 'http',
                    path    = $ember.get(controller, 'path') || '';

                if (!host && !port) {
                    return;
                }

                // Use the host to compile the connect string.
                server = !port ? '%@://%@/%@'.fmt(scheme, host, path)
                               : '%@://%@:%@/%@'.fmt(scheme, host, port, path);

            })(this);

            // Create the host:port string for connecting, and then attempt to establish
            // a connection.
            var options = $ember.get(this, 'options') || {},
                socket  = $io(server, $jq.extend(options, params || {}));

            socket.on('error', this.error);

            // Store a reference to the socket.
            this.set('socket', socket);

            /**
             * @on connect
             */
            socket.on('connect', this._listen.bind(this));

        },

        /**
         * @method error
         * @param errorData {Object}
         * @return {void}
         */
        error: function(errorData) {

            // Throw an exception if an error occurs.
            $window.console.error(errorData);
            throw 'EmberSockets: An error occurred.';

        },

        /**
         * Responsible for emitting an event to the waiting Socket.io server.
         *
         * @method emit
         * @param eventName {String}
         * @param params {Array}
         * @return {void}
         */
        emit: function emit(eventName, params) {

            //jshint unused:false
            var args    = Array.prototype.slice.call(arguments),
                scope   = $ember.get(this, 'socket');

            scope.emit.apply(scope, args);

        },

        /**
         * Responsible for listening to events from Socket.io, and updating controller properties that
         * subscribe to those events.
         *
         * @method _listen
         * @return {void}
         * @private
         */
        _listen: function _listen() {

            var controllers     = $ember.get(this, 'controllers'),
                getController   = this._getController.bind(this),
                events          = [],
                forEach         = $ember.EnumerableUtils,
                module          = this,
                respond         = function respond() {
                    var eventData = Array.prototype.slice.call(arguments);
                    module._update.call(module, this, eventData);
                };

            forEach.forEach(controllers, function controllerIteration(controllerName) {

                // Fetch the controller if it's valid.
                var controller  = getController(controllerName),
                    eventNames  = controller[this.NAMESPACE];

                if (controller) {

                    // Invoke the `connect` method if it has been defined on this controller.
                    if (typeof controller[this.NAMESPACE] === 'object' && typeof controller[this.NAMESPACE].connect === 'function') {
                        controller[this.NAMESPACE].connect.apply(controller);
                    }

                    // Iterate over each event defined in the controller's `sockets` hash, so that we can
                    // keep an eye open for them.
                    for (var eventName in eventNames) {

                        if (eventNames.hasOwnProperty(eventName)) {

                            if (events.indexOf(eventName) !== -1) {
                                // Don't observe this event if we're already observing it.
                                continue;
                            }

                            // Push the event so we don't listen for it twice.
                            events.push(eventName);

                            // Check to ensure the event was not previously registered due to a reconnect
                            if (!(eventName in $ember.get(module, 'socket')._callbacks)) {

                                // ...And finally we can register the event to listen for it.
                                $ember.get(module, 'socket').on(eventName, respond.bind(eventName));

                            }

                        }

                    }

                }

            }, this);

        },

        /**
         * @method _update
         * @param eventName {String}
         * @param eventData {String|Number|Object}
         * @return {Number} Number of controllers which responded to the event.
         * @private
         */
        _update: function _update(eventName, eventData) {

            var controllers             = $ember.get(this, 'controllers'),
                respondingControllers   = 0,
                getController           = this._getController.bind(this),
                forEach                 =  $ember.EnumerableUtils.forEach;

            $ember.run(this, function() {

                // Iterate over each listener controller and emit the event we caught.
                forEach(controllers, function(controllerName) {

                    // Fetch the controller if it's valid.
                    var controller = getController(controllerName);

                    if (controller) {

                        // Attempt to find a match for the current event name.
                        var correspondingAction = controller[this.NAMESPACE][eventName];

                        if (!correspondingAction) {
                            // If we can't find it, then we can't go any further for this controller.
                            return;
                        }

                        if (typeof correspondingAction === 'function') {

                            // We need to invoke the function to respond to the event because the coder
                            // has specified a callback instead of a property to update.
                            correspondingAction.apply(controller, eventData);
                            respondingControllers++;
                            return;

                        }

                        // Determine if the property is specifying multiple properties to update.
                        if ($ember.isArray(correspondingAction)) {

                            forEach(correspondingAction, function propertyIteration(property, index) {

                                // Update each property included in the array of properties.
                                $ember.set(controller, property, eventData[index]);

                            });

                            respondingControllers++;
                            return;

                        }

                        // Otherwise it's a single property to update.
                        $ember.set(controller, correspondingAction, eventData);
                        respondingControllers++;

                    }

                }, this);

            });

            return respondingControllers;

        },

        /**
         * Responsible for retrieving a controller if it exists, and if it has defined a `events` hash.
         *
         * @method _getController
         * @param name {String}
         * @return {Object|Boolean}
         * @private
         */
        _getController: function _getController(name) {

            // Format the `name` to match what the lookup container is expecting, and then
            // we'll locate the controller from the `container`.
            name = 'controller:%@'.fmt(name);
            var controller = this.container.lookup(name);

            if (!controller || (this.NAMESPACE in controller === false)) {
                // Don't do anything with this controller if it hasn't defined a `sockets` hash.
                return false;
            }

            return controller;

        }

    });

    /**
     * @onLoad Ember.Application
     * @param $app {Object}
     */
    $ember.onLoad('Ember.Application', function($app) {

        $app.initializer({

            /**
             * @property name
             * @type {String}
             * @default 'sockets'
             */
            name: 'sockets',

            /**
             * @method initialize
             * @param container {Object}
             * @param application {Object}
             * @return {void}
             */
            initialize: function(container, application) {

                if (typeof application.Socket === 'undefined') {

                    // Ensure the developer has defined `Socket` in their `Ember.Application`.
                    throw 'You have forgotten to add `EmberSockets` into `Ember.Application`! See: https://github.com/Wildhoney/EmberSockets#getting-started';

                }

                // Register `socket:main` with Ember.js.
                application.register('socket:main', application.Socket, {
                    singleton: true
                });

                // We then want to inject `socket` into each controller and route.
                application.inject('controller', 'socket', 'socket:main');
                application.inject('route', 'socket', 'socket:main');

            }

        });
    });

})(window, window.Ember, window.io, window.jQuery);<|endoftext|>


<commit_before>(function() {
  // cache of loaded/loading modules
  var modules = {};

  // Gets a module from the cache based on it's absolute path
  function getModule(path) {
    var m = modules[path];
    if (!m) {
      m = modules[path] = new Module(path);
    }
    return m;
  }

  function print() {
    for (var i=0, l=arguments.length; i<l; i++) {
      document.getElementById("stdout").innerHTML += arguments[i] + '\n';
    }
  }

  var fakeConsole = {
    log: function() {
      window.eval("console.log('log')");
    }
  }

  // The Module class is instantiated once per module
  // that gets loaded. It has an absolute path, an "exports"
  // Object that gets injected into the module's sandbox scope.
  function Module(absolutePath) {
    //console.log("ModuleJS: Creating Module, path: " + absolutePath);

    var self = this;
    Sandbox.apply(self, arguments);
    self.loadListeners = [];
    self.path = absolutePath;
    self.loaded = false;

    var module = {};
    var exports = {};
    self.module = module;
    self.exports = exports;
    module.exports = exports;

    self.global.module = module;
    self.global.exports = exports;
    self.global.load = function(deps, factory) {
      if (!isArray(deps)) {
        var argc = arguments.length;
        deps = Array.prototype.slice.call(arguments, 0, argc-1);
        factory = arguments[argc-1];
      }
      self._deps = deps;
      self._factory = factory;
    }
    self.global.console = fakeConsole;
    self.global.print = print;

    // HACK: Firefox (probably others) seem to need us to wait
    // a few ms before adding the <script> to the <iframe>
    setTimeout(function() {
      // load the remote script, invoke '_onLoad' when it finishes
      self.load(self.path, function() {
        self._onLoad.apply(self, arguments);
      });
    }, 50);
  }
  extend(Module, Sandbox);
  // Internal function that gets called after the script is
  // loaded into the sandbox. It first checks if the loading
  // was successful, then checks to see if the module's "load"
  // function was called, defining a factory function and any
  // dependencies.
  Module.prototype._onLoad = function(err) {
    console.log("ModuleJS: Module <script> onload, path: " + this.path);

    if (err) {
      console.log("ModuleJS: Module failed to load: " + this.path);

      // Module failed to load!
      this._notifyLoaded(err);
      return;
    }

    var self = this;
    if (this._deps && this._deps.length > 0) {
      console.log("ModuleJS: Module has depencencies: " + this.path + ", " + this._deps);

      this._modules = [];
      for (var i=0, l=this._deps.length; i<l; i++) {
        var m = getModule(this._absolutize(this._deps[i]));
        if (!m.loaded) {
          m.addListener(function() {
            self._checkDeps.apply(self, arguments);
          });
        }
        this._modules.push(m);
      }
      this._checkDeps();
    } else {
      console.log("ModuleJS: Module did not call 'load()': " + this.path);

      if (this.module.exports !== this.exports) {
        console.log("ModuleJS: 'module.exports' was set: " + this.path);
        // 'module.exports' property was directly set, outside of 'load()'
        this.exports = this.module.exports;
      }

      // Module has no dependencies...
      this._notifyLoaded();
    }
  }
  // Add a listener. Currently the only event is 'load', which need-not be specified
  Module.prototype.addListener = function(callback) {
    this.loadListeners.push(callback);
  }
  // Called immediately after the script loads from the remote,
  // and once every time one of the module's defined dependencies
  // fires off it's load event. If all required deps have finished
  // loading, then it's time for this module to finish loading
  Module.prototype._checkDeps = function(err) {
    var self = this;
    var loaded = true;
    for (var i=0, l=self._modules.length; i<l; i++) {
      var m = self._modules[i];
      if (!m.loaded) {
        loaded = false;
        break;
      }
    }
    if (loaded) this._notifyLoaded();
  }
  // Called after all dependencies have been satisfied. If a
  // factory function had been defined in the 'load()' call,
  // then it is invoked. Then all load listeners for this module
  // are notified. Also sets the 'loaded' flag to true
  Module.prototype._notifyLoaded = function(err) {
    this.loaded = true;
    this.error = err;
    if (this._factory) {
      this._executeFactory();
    }
    console.log("ModuleJS: Notifying Module Listeners: " + this.path);

    var li = this.loadListeners;
    for (var i=0, l=li.length; i<l; i++) {
      li[i](err);
    }
  }
  // Executes the factory function that was defined in the 'load()'
  // call. It first collects the 'exports' of all dependency modules,
  // then evals the factory function in the module's isolated scope.
  // The return value is checked, as well as 'module.exports' to see
  // if they were set, which will override 'exports' if set.
  Module.prototype._executeFactory = function() {
    console.log("ModuleJS: Executing Module Factory: " + this.path);

    // At this point, we know that any deps are loaded, so get the
    // 'exports' object from the loaded Module instance.
    var deps = [];
    for (var i=0, l=this._modules.length; i<l; i++) {
      deps[i] = this._modules[i].exports;
    }
    this.global.__deps = deps;
    this.global.__factory = this._factory;
    // Eval in the module's isolated Sandbox
    var rtn = this.eval('__factory.apply(exports, __deps)');
    delete this.global.__deps;
    delete this.global.__factory;
    if (this.module.exports !== this.exports) {
      console.log("ModuleJS: 'module.exports' was set: " + this.path);
      // 'module.exports' property was directly set
      this.exports = this.module.exports;
    } else if (!!rtn && rtn !== this.exports) {
      console.log("ModuleJS: Object returned from factory function: " + this.path);
      // something was 'return'ed from the factory function
      this.exports = rtn;
    }
  }
  // Returns an absolutized version of the dependency name, based on
  // this module's base path, etc. '..', '.', are normalized.
  Module.prototype._absolutize = function(dep) {
    return dep;
  }

  // Extends a the prototype of a Constructor Function
  // with the prototype of a Super Function
  function extend(con, sup) {
    function bare() {}
    bare.prototype = sup.prototype;
    con.prototype = new bare;
    con.prototype.constructor = con;
    bare = undefined;
  }

  // Not implemented in most browsers...
  function isArray(array) {
    return Object.prototype.toString.call(array) === '[object Array]';
  }

  // For testing. API will most definitely change...
  function start(path) {
    new Module(path);
  }
  window['start'] = start;

  window['Module'] = Module;
})();
<commit_msg>Give up on `console.log()`... for now...<commit_after>(function() {
  // cache of loaded/loading modules
  var modules = {};

  // Gets a module from the cache based on it's absolute path
  function getModule(path) {
    var m = modules[path];
    if (!m) {
      m = modules[path] = new Module(path);
    }
    return m;
  }

  // Logging function, since I can't seem to get `console.log` to work in the modules...
  function print() {
    for (var i=0, l=arguments.length; i<l; i++) {
      document.getElementById("stdout").innerHTML += arguments[i] + '\n';
    }
  }

  // The Module class is instantiated once per module
  // that gets loaded. It has an absolute path, an "exports"
  // Object that gets injected into the module's sandbox scope.
  function Module(absolutePath) {
    console.log("ModuleJS: Creating Module, path: " + absolutePath);

    var self = this;
    Sandbox.apply(self, arguments);
    self.loadListeners = [];
    self.path = absolutePath;
    self.loaded = false;

    var module = {};
    var exports = {};
    self.module = module;
    self.exports = exports;
    module.exports = exports;

    self.global.module = module;
    self.global.exports = exports;
    self.global.load = function(deps, factory) {
      if (!isArray(deps)) {
        var argc = arguments.length;
        deps = Array.prototype.slice.call(arguments, 0, argc-1);
        factory = arguments[argc-1];
      }
      self._deps = deps;
      self._factory = factory;
    }
    self.global.print = print;

    // HACK: Firefox (probably others) seem to need us to wait
    // a few ms before adding the <script> to the <iframe>
    setTimeout(function() {
      // load the remote script, invoke '_onLoad' when it finishes
      self.load(self.path, function() {
        self._onLoad.apply(self, arguments);
      });
    }, 50);
  }
  extend(Module, Sandbox);
  // Internal function that gets called after the script is
  // loaded into the sandbox. It first checks if the loading
  // was successful, then checks to see if the module's "load"
  // function was called, defining a factory function and any
  // dependencies.
  Module.prototype._onLoad = function(err) {
    console.log("ModuleJS: Module <script> onload, path: " + this.path);

    if (err) {
      console.log("ModuleJS: Module failed to load: " + this.path);

      // Module failed to load!
      this._notifyLoaded(err);
      return;
    }

    var self = this;
    if (this._deps && this._deps.length > 0) {
      console.log("ModuleJS: Module has depencencies: " + this.path + ", " + this._deps);

      this._modules = [];
      for (var i=0, l=this._deps.length; i<l; i++) {
        var m = getModule(this._absolutize(this._deps[i]));
        if (!m.loaded) {
          m.addListener(function() {
            self._checkDeps.apply(self, arguments);
          });
        }
        this._modules.push(m);
      }
      this._checkDeps();
    } else {
      console.log("ModuleJS: Module did not call 'load()': " + this.path);

      if (this.module.exports !== this.exports) {
        console.log("ModuleJS: 'module.exports' was set: " + this.path);
        // 'module.exports' property was directly set, outside of 'load()'
        this.exports = this.module.exports;
      }

      // Module has no dependencies...
      this._notifyLoaded();
    }
  }
  // Add a listener. Currently the only event is 'load', which need-not be specified
  Module.prototype.addListener = function(callback) {
    this.loadListeners.push(callback);
  }
  // Called immediately after the script loads from the remote,
  // and once every time one of the module's defined dependencies
  // fires off it's load event. If all required deps have finished
  // loading, then it's time for this module to finish loading
  Module.prototype._checkDeps = function(err) {
    var self = this;
    var loaded = true;
    for (var i=0, l=self._modules.length; i<l; i++) {
      var m = self._modules[i];
      if (!m.loaded) {
        loaded = false;
        break;
      }
    }
    if (loaded) this._notifyLoaded();
  }
  // Called after all dependencies have been satisfied. If a
  // factory function had been defined in the 'load()' call,
  // then it is invoked. Then all load listeners for this module
  // are notified. Also sets the 'loaded' flag to true
  Module.prototype._notifyLoaded = function(err) {
    this.loaded = true;
    this.error = err;
    if (this._factory) {
      this._executeFactory();
    }
    console.log("ModuleJS: Notifying Module Listeners: " + this.path);

    var li = this.loadListeners;
    for (var i=0, l=li.length; i<l; i++) {
      li[i](err);
    }
  }
  // Executes the factory function that was defined in the 'load()'
  // call. It first collects the 'exports' of all dependency modules,
  // then evals the factory function in the module's isolated scope.
  // The return value is checked, as well as 'module.exports' to see
  // if they were set, which will override 'exports' if set.
  Module.prototype._executeFactory = function() {
    console.log("ModuleJS: Executing Module Factory: " + this.path);

    // At this point, we know that any deps are loaded, so get the
    // 'exports' object from the loaded Module instance.
    var deps = [];
    for (var i=0, l=this._modules.length; i<l; i++) {
      deps[i] = this._modules[i].exports;
    }
    this.global.__deps = deps;
    this.global.__factory = this._factory;
    // Eval in the module's isolated Sandbox
    var rtn = this.eval('__factory.apply(exports, __deps)');
    delete this.global.__deps;
    delete this.global.__factory;
    if (this.module.exports !== this.exports) {
      console.log("ModuleJS: 'module.exports' was set: " + this.path);
      // 'module.exports' property was directly set
      this.exports = this.module.exports;
    } else if (!!rtn && rtn !== this.exports) {
      console.log("ModuleJS: Object returned from factory function: " + this.path);
      // something was 'return'ed from the factory function
      this.exports = rtn;
    }
  }
  // Returns an absolutized version of the dependency name, based on
  // this module's base path, etc. '..', '.', are normalized.
  Module.prototype._absolutize = function(dep) {
    return dep;
  }

  // Extends a the prototype of a Constructor Function
  // with the prototype of a Super Function
  function extend(con, sup) {
    function bare() {}
    bare.prototype = sup.prototype;
    con.prototype = new bare;
    con.prototype.constructor = con;
    bare = undefined;
  }

  // Not implemented in most browsers...
  function isArray(array) {
    return Object.prototype.toString.call(array) === '[object Array]';
  }

  // For testing. API will most definitely change...
  function start(path) {
    new Module(path);
  }
  window['start'] = start;

  window['Module'] = Module;
})();
<|endoftext|>