<commit_before>$(document).ready(function () {

    // Counter to different context menus on for plugin owners on one page
    var count = 0;
    var mouseClickPosition;
    $.fn.makeDraggable = function (options) {
        var $rootElement = this;
        // Callback on dragging item in new position in list
        var moveTrackToNewPosition = options.onMoveTrackToNewPosition;
        var $currentItem = null;
        //var $draggableStub = $('#draggableStub');
        var $container = $('#itemsContainer');
        // Call to create unique plugin owner id
        this._getCount = function () {
            return count++;
        };
        var contextMenu = new ContextMenu();
        contextMenu.initializeContextMenu(this._getCount(), options.contextMenu, this, options.manager);
        var $draggableStub = $('<div>');
        $draggableStub.addClass('tableRow');
        $draggableStub.addClass('draggable-item');
        $draggableStub.addClass('draggable-stub');
        $draggableStub.addClass('track');
        // Saving data about item moving (from -> to)
        var movingInfo = { "data": [] };
        var timerId = null;
        var lastEvent = null;
        var elementOffset = { x: 0, y: 0 };
        var mousedown = false;
        var deleteFlag = false;
        var moveEnable = false;
        // Mousemove start working after monig to mouseMovePxOffset pixels
        var mouseMovePxOffset = 10;

        var mousedownOnProgressBar = false;

        this.find('.draggable-list > .tableRow').each(function (index, item) {
            var $item = $(item);
            $item.toggleClass('draggable-item', true);
            $item.mousedown(_makeDraggable);
        });

        $(document).mousemove(function (event) {
            lastEvent = event;
            if ($currentItem && mousedown && !mousedownOnProgressBar) {
                var $elem = _getCurrentTarget(event);

                var currentMousePos = { x: event.clientX, y: event.clientY };
                if (moveEnable == false) {
                    if (Math.abs(mouseClickPosition.x - currentMousePos.x) > mouseMovePxOffset || Math.abs(mouseClickPosition.y - currentMousePos.y) > mouseMovePxOffset) {
                        moveEnable = true;
                    } else {
                        return;
                    }
                }

                if ($currentItem.hasClass('draggable-item-selected')) {
                    var width = $currentItem.width();
                    $currentItem = $container;
                    $currentItem.css({
                        'width': width + 'px'
                    });
                    $currentItem.append($('.draggable-item-selected'));
                }
                $currentItem.toggleClass('dragging', true);

                if (!$currentItem.hasClass('itemsContainer')) {
                    $draggableStub.insertAfter($currentItem.children().last());
                }

                _setRelativePosition(event);
                if ($elem) {

                    if ($elem.parent().attr('id') == 'playlistTracks') {
                        var playlistId = $elem.parent().find('.playlistId').text();
                        var $currentPlaylist = $('.playlist .playlistId:contains(' + playlistId + ')').parent();
                        if ($currentPlaylist.find('.readonly').text() == "true") {
                            return;
                        }

                    }

                    if ($elem.hasClass('draggable-list')) {
                        $elem.append($draggableStub);
                    } else if (!$elem.hasClass('delete-area')) {
                        var childPos = $currentItem.offset();
                        var parentPos = $draggableStub.parent().offset();

                        if ($elem.length > 0 &&
                            (!$elem.parents().hasClass('vkMusicList') || ($currentItem.children().hasClass('vk-item') && $elem.parents().hasClass('vkMusicList')))) {
                            clearTimeout(timerId);
                            var $savedItem = $currentItem;
                            timerId = setTimeout(function () {
                                var $hoverElement = _getCurrentTarget(lastEvent);
                                if ($elem.is($hoverElement)) {
                                    $elem.trigger('MergeItems', [$elem, $savedItem, event.pageY]);
                                }
                            }, 2000);
                            if (childPos && parentPos && childPos.top - parentPos.top < $($currentItem.children[0]).outerHeight() / 2 &&
                                (!$elem.parents().hasClass('vkMusicList') || ($currentItem.children().hasClass('vk-item') && $elem.parents().hasClass('vkMusicList')))) {
                                $draggableStub.insertBefore($elem);
                            } else if (!$elem.parents().hasClass('vkMusicList') || ($currentItem.children().hasClass('vk-item') && $elem.parents().hasClass('vkMusicList'))) {
                                $draggableStub.insertAfter($elem);
                            }
                        }
                    }
                }
                $draggableStub.show();
            }
        });

        $(document).mouseup(function (event) {
            if ($currentItem != null && !event.shiftKey && !event.ctrlKey && !$currentItem.hasClass('itemsContainer') && event.which != 3) {
                if ($('.draggable-item-selected').length > 1) {
                    $('.draggable-item-selected:not(:hover)').toggleClass('draggable-item-selected', false);
                }
            }

            mousedown = false;
            mousedownOnProgressBar = false;
            clearTimeout(timerId);
            if ($currentItem) {
                var $element = _getCurrentTarget(event);
                if ($element.length == 0) {
                    if ($currentItem.hasClass('itemsContainer')) {
                        $draggableStub.replaceWith($currentItem.children());
                        $currentItem = null;
                    } else {
                        $currentItem.removeAttr('style');
                        $currentItem.toggleClass('dragging', false);
                    }
                } else {

                    if (!$currentItem.children().hasClass('vk-item') && $element.parent().attr('id') == 'playlistTracks' && !$('.draggable-stub').is(':hidden') && moveEnable) {

                        $currentItem.children().insertAfter($draggableStub);
                        $draggableStub.detach();
                        moveTrackToNewPosition($rootElement.find('.draggable-list'));
                        _clearContainer();
                        moveEnable = false;
                        return;
                    }
                    moveEnable = false;

                    if ($currentItem.children().hasClass('vk-item') && !$element.hasClass('vk-item') && !$element.parent().hasClass('vkMusicList')) {
                        var playlistId = -1;
                        if ($element.hasClass('playlist')) {
                            playlistId = $element.children('.playlistId').text();
                        } else if ($element.hasClass('track')) {
                            playlistId = $element.parent().children('.playlistId').text();
                        }
                        var index = -1;
                        if (!$draggableStub.parent().hasClass('vkMusicList')) {
                            index = $draggableStub.index();
                        }
                        contextMenu._saveTrackFromVkToPlaylist($currentItem, index, playlistId);
                    }

                    if ($element.hasClass('delete-area')) {
                        $currentItem.trigger("delete");
                    }

                    if ($currentItem != null && ($currentItem.hasClass('itemsContainer') && $currentItem.children().length > 0) > 0 && !$element.hasClass('delete-area')) {
                        var $items = "Items ";
                        for (i = 0; i < $currentItem.children().length; i++) {
                            $items += $($currentItem.children()[i]).html() + " ";
                        }
                        $currentItem.trigger('OnDropped', [movingInfo, $draggableStub.parent().attr("name")]);
                        movingInfo.data.length = 0;
                        if ($currentItem.children().length > 0) {
                            $currentItem.children().insertAfter($draggableStub);
                            $currentItem.trigger('AfterDropped', [movingInfo, $draggableStub.parent().attr("name")]);
                            _clearContainer();
                        }
                    }
                }
            }
            $draggableStub.hide();
        });

        contextMenu.$contextMenuContainer.mousedown(function (event) {
            contextMenu.selectAction($currentItem);
        });

        //$(document).mousedown(function (event) {
        //    var $target = $(event.target);
        //    if ($target.hasClass('progressBar') || $target.hasClass('progress') || $target.hasClass('cache')) {
        //        mousedownOnProgressBar = true;
        //    }
        //    if (!$target.parents().hasClass('draggable-list') && !$target.parents().hasClass('list')) {
        //        document.oncontextmenu = function () {
        //            return true;
        //        }
        //    }
        //    if (!$target.hasClass('contextMenuActionName') && event.which != 3) {
        //        $('.contextMenu').detach();
        //    }
        //});

        function _makeDraggable(event) {
            mouseClickPosition = { x: event.clientX, y: event.clientY };
            if (event.which == 3) {

                var $currentList = $(event.target);
                $currentList = $currentList.parents('.draggable-list');
                if ($currentList.children().length > 0) {
                    if ($currentList.children('.draggable-item-selected').length == 0) {
                        $('.draggable-item-selected').toggleClass('draggable-item-selected', false);
                    }
                }

                contextMenu.drawContextMenu(event);
            } else {

                mousedown = true;
                $currentItem = $(this);
                var pos = $currentItem.offset();
                elementOffset.x = event.pageX - pos.left;
                elementOffset.y = event.pageY - pos.top;

                if (!$currentItem.hasClass('draggable-item-selected') && !event.shiftKey) {
                    movingInfo.data.push({ "name": $currentItem.parent().attr('name'), "item": $currentItem.html() });
                }

                if (event.ctrlKey) {
                    if ($currentItem.hasClass('draggable-item-selected')) {
                        $currentItem.toggleClass('draggable-item-selected', false);
                        for (i = 0; i < movingInfo.data.length; i++) {
                            if (movingInfo.data[i].name == $currentItem.parent().attr('name') && movingInfo.data[i].item == $currentItem.html()) {
                                movingInfo.data.splice(i, 1);
                            }
                        }
                    } else {
                        $currentItem.toggleClass('draggable-item-selected', true);
                    }
                } else if (event.shiftKey) {
                    var indexFirst = -1;
                    var indexLast = -1;
                    if ($('.draggable-item-selected').last().index() < $currentItem.index()) {
                        indexFirst = $('.draggable-item-selected').last().index();
                        indexLast = $currentItem.index();
                    } else {
                        indexFirst = $currentItem.index();
                        indexLast = $('.draggable-item-selected').last().index();
                    }

                    var currentChildren = $currentItem.parent().children();

                    for (i = indexFirst; i <= indexLast; i++) {
                        var $currentChild = $(currentChildren[i]);
                        if (!$currentChild.hasClass('draggable-item-selected')) {
                            $currentChild.toggleClass('draggable-item-selected', true);
                            movingInfo.data.push({ "name": $currentChild.parent().attr('name'), "item": $currentChild.html() });
                        }
                    }
                } else {
                    var $selectedItems = $('.draggable-item-selected');

                    if (!$currentItem.parent().children().hasClass('draggable-item-selected') && $('.draggable-item-selected').length > 0) {
                        $selectedItems.toggleClass('draggable-item-selected', false);
                    } else if ($currentItem.parent().children().hasClass('draggable-item-selected') && $('.draggable-item-selected').length > 0 && !$currentItem.hasClass('draggable-item-selected')) {
                        $selectedItems.toggleClass('draggable-item-selected', false);
                    } else if ($currentItem.hasClass('draggable-item-selected') && $('.draggable-item-selected').length < 2) {
                        $selectedItems.toggleClass('draggable-item-selected', false);
                    } else if ($('.draggable-item-selected').length == 1) {
                        $selectedItems.toggleClass('draggable-item-selected', false);
                    }
                    $currentItem.toggleClass('draggable-item-selected', true);
                }
            }
        };

        function _setRelativePosition(event) {
            var relX = event.pageX - elementOffset.x;
            var relY = event.pageY - elementOffset.y;
            $currentItem.css({
                'top': relY + 'px',
                'left': relX + 'px'
            });
        }

        function _getCurrentTarget(event) {
            if (navigator.userAgent.match('MSIE') || navigator.userAgent.match('Gecko')) {
                var x = event.clientX, y = event.clientY;
            } else {
                var x = event.pageX, y = event.pageY;
            }
            $currentItem.hide();
            var $elem = $(document.elementFromPoint(x, y));

            if (event.type == "mouseup") {
                if ($elem.hasClass('playlist')) {
                    $currentItem.show();
                    return $elem;
                }
                if ($elem.parents('.playlist').length > 0 && event.type == "mouseup") {
                    $currentItem.show();
                    return $elem.parents('.playlist');
                }
            }
            if ($elem.hasClass('delete-area'))
                _onDeleteArea();
            else if (deleteFlag == true) {
                _outDeleteArea();
            }
            $currentItem.show();

            if ($elem.hasClass('delete-area')) {
                return $elem;
            }

            if ($elem.closest('.draggable-list').find('.draggable-item').length === 0) {
                return $elem.closest('.draggable-list');
            }

            if ($elem.attr('id') == "playlistTracks" && event.type == "mouseup")
                return $($elem.children()[0]);

            return $elem.closest('.draggable-item:not(.dragging.draggable-stub)');
        }

        function _setDeleteAreaCss() {
            if (deleteFlag == true) {
                $('.delete-area').css({
                    'border': 'solid red 3px'
                })
            } else {
                $('.delete-area').css({
                    'border': 'solid black 1px'
                });
            }
        }

        function _clearContainer() {
            $currentItem.removeAttr('style');
            $currentItem.toggleClass('dragging', false);
            $('.draggable-item-selected').toggleClass('draggable-item-selected', false);
            $currentItem = null;
        }

        function _onDeleteArea() {
            deleteFlag = true;
            _setDeleteAreaCss();
        }

        function _outDeleteArea() {
            deleteFlag = false;
            _setDeleteAreaCss();
        }

        $('.draggable').on('MergeItems', function (e, mergeTo, mergeElem, pageY) {
            mergeToPos = mergeTo.offset();
            if ((!mergeTo.hasClass('draggable-stub')) && (mergeToPos.top + 0.15 * $('.draggable-item').height() < pageY) && (mergeToPos.top + 0.85 * $('.draggable-item').height() > pageY)) {
                if (mergeElem && mergeTo) {
                    if ($currentItem.hasClass('itemsContainer') && $('.draggable-item-selected').length > 0) {
                        $currentItem.children().each(function (index, item) {
                            mergeTo.text(mergeTo.html() + ' ' + $(item).html());
                        });
                        $currentItem.children().detach();
                    } else {
                        mergeTo.text(mergeTo.html() + ' ' + mergeElem.html());
                        $currentItem.detach();
                    }
                    mergeTo.trigger('OnCombined', [mergeTo.text()]);
                    _clearContainer();
                }
            }
        });

        //$('.draggable-list').on('sort', function (e, dir) {
        //    $list = $(this);
        //    var sorted = $list.find("> .draggable-item").sort(function (a, b) {
        //        return $(a).text().toLowerCase() > $(b).text().toLowerCase() ? dir : -dir;
        //    });
        //    $list.prepend(sorted);
        //});
    };
});<commit_msg>Fixed bug#45: On music page audio can't drag progress bug (all track is dragging instead)<commit_after>$(document).ready(function () {

    // Counter to different context menus on for plugin owners on one page
    var count = 0;
    var mouseClickPosition;
    $.fn.makeDraggable = function (options) {
        var $rootElement = this;
        // Callback on dragging item in new position in list
        var moveTrackToNewPosition = options.onMoveTrackToNewPosition;
        var $currentItem = null;
        //var $draggableStub = $('#draggableStub');
        var $container = $('#itemsContainer');
        // Call to create unique plugin owner id
        this._getCount = function () {
            return count++;
        };
        var contextMenu = new ContextMenu();
        contextMenu.initializeContextMenu(this._getCount(), options.contextMenu, this, options.manager);
        var $draggableStub = $('<div>');
        $draggableStub.addClass('tableRow');
        $draggableStub.addClass('draggable-item');
        $draggableStub.addClass('draggable-stub');
        $draggableStub.addClass('track');
        // Saving data about item moving (from -> to)
        var movingInfo = { "data": [] };
        var timerId = null;
        var lastEvent = null;
        var elementOffset = { x: 0, y: 0 };
        var mousedown = false;
        var deleteFlag = false;
        var moveEnable = false;
        // Mousemove start working after monig to mouseMovePxOffset pixels
        var mouseMovePxOffset = 10;

        var mousedownOnProgressBar = false;

        this.find('.draggable-list > .tableRow').each(function (index, item) {
            var $item = $(item);
            $item.toggleClass('draggable-item', true);
            $item.mousedown(_makeDraggable);
        });

        $(document).mousemove(function (event) {
            lastEvent = event;
            if ($currentItem && mousedown && !mousedownOnProgressBar) {
                var $elem = _getCurrentTarget(event);

                var currentMousePos = { x: event.clientX, y: event.clientY };
                if (moveEnable == false) {
                    if (Math.abs(mouseClickPosition.x - currentMousePos.x) > mouseMovePxOffset || Math.abs(mouseClickPosition.y - currentMousePos.y) > mouseMovePxOffset) {
                        moveEnable = true;
                    } else {
                        return;
                    }
                }

                if ($currentItem.hasClass('draggable-item-selected')) {
                    var width = $currentItem.width();
                    $currentItem = $container;
                    $currentItem.css({
                        'width': width + 'px'
                    });
                    $currentItem.append($('.draggable-item-selected'));
                }
                $currentItem.toggleClass('dragging', true);

                if (!$currentItem.hasClass('itemsContainer')) {
                    $draggableStub.insertAfter($currentItem.children().last());
                }

                _setRelativePosition(event);
                if ($elem) {

                    if ($elem.parent().attr('id') == 'playlistTracks') {
                        var playlistId = $elem.parent().find('.playlistId').text();
                        var $currentPlaylist = $('.playlist .playlistId:contains(' + playlistId + ')').parent();
                        if ($currentPlaylist.find('.readonly').text() == "true") {
                            return;
                        }

                    }

                    if ($elem.hasClass('draggable-list')) {
                        $elem.append($draggableStub);
                    } else if (!$elem.hasClass('delete-area')) {
                        var childPos = $currentItem.offset();
                        var parentPos = $draggableStub.parent().offset();

                        if ($elem.length > 0 &&
                            (!$elem.parents().hasClass('vkMusicList') || ($currentItem.children().hasClass('vk-item') && $elem.parents().hasClass('vkMusicList')))) {
                            clearTimeout(timerId);
                            var $savedItem = $currentItem;
                            timerId = setTimeout(function () {
                                var $hoverElement = _getCurrentTarget(lastEvent);
                                if ($elem.is($hoverElement)) {
                                    $elem.trigger('MergeItems', [$elem, $savedItem, event.pageY]);
                                }
                            }, 2000);
                            if (childPos && parentPos && childPos.top - parentPos.top < $($currentItem.children[0]).outerHeight() / 2 &&
                                (!$elem.parents().hasClass('vkMusicList') || ($currentItem.children().hasClass('vk-item') && $elem.parents().hasClass('vkMusicList')))) {
                                $draggableStub.insertBefore($elem);
                            } else if (!$elem.parents().hasClass('vkMusicList') || ($currentItem.children().hasClass('vk-item') && $elem.parents().hasClass('vkMusicList'))) {
                                $draggableStub.insertAfter($elem);
                            }
                        }
                    }
                }
                $draggableStub.show();
            }
        });

        $(document).mouseup(function (event) {
            if ($currentItem != null && !event.shiftKey && !event.ctrlKey && !$currentItem.hasClass('itemsContainer') && event.which != 3) {
                if ($('.draggable-item-selected').length > 1) {
                    $('.draggable-item-selected:not(:hover)').toggleClass('draggable-item-selected', false);
                }
            }

            mousedown = false;
            mousedownOnProgressBar = false;
            clearTimeout(timerId);
            if ($currentItem) {
                var $element = _getCurrentTarget(event);
                if ($element.length == 0) {
                    if ($currentItem.hasClass('itemsContainer')) {
                        $draggableStub.replaceWith($currentItem.children());
                        $currentItem = null;
                    } else {
                        $currentItem.removeAttr('style');
                        $currentItem.toggleClass('dragging', false);
                    }
                } else {

                    if (!$currentItem.children().hasClass('vk-item') && $element.parent().attr('id') == 'playlistTracks' && !$('.draggable-stub').is(':hidden') && moveEnable) {

                        $currentItem.children().insertAfter($draggableStub);
                        $draggableStub.detach();
                        moveTrackToNewPosition($rootElement.find('.draggable-list'));
                        _clearContainer();
                        moveEnable = false;
                        return;
                    }
                    moveEnable = false;

                    if ($currentItem.children().hasClass('vk-item') && !$element.hasClass('vk-item') && !$element.parent().hasClass('vkMusicList')) {
                        var playlistId = -1;
                        if ($element.hasClass('playlist')) {
                            playlistId = $element.children('.playlistId').text();
                        } else if ($element.hasClass('track')) {
                            playlistId = $element.parent().children('.playlistId').text();
                        }
                        var index = -1;
                        if (!$draggableStub.parent().hasClass('vkMusicList')) {
                            index = $draggableStub.index();
                        }
                        contextMenu._saveTrackFromVkToPlaylist($currentItem, index, playlistId);
                    }

                    if ($element.hasClass('delete-area')) {
                        $currentItem.trigger("delete");
                    }

                    if ($currentItem != null && ($currentItem.hasClass('itemsContainer') && $currentItem.children().length > 0) > 0 && !$element.hasClass('delete-area')) {
                        var $items = "Items ";
                        for (i = 0; i < $currentItem.children().length; i++) {
                            $items += $($currentItem.children()[i]).html() + " ";
                        }
                        $currentItem.trigger('OnDropped', [movingInfo, $draggableStub.parent().attr("name")]);
                        movingInfo.data.length = 0;
                        if ($currentItem.children().length > 0) {
                            $currentItem.children().insertAfter($draggableStub);
                            $currentItem.trigger('AfterDropped', [movingInfo, $draggableStub.parent().attr("name")]);
                            _clearContainer();
                        }
                    }
                }
            }
            $draggableStub.hide();
        });

        contextMenu.$contextMenuContainer.mousedown(function (event) {
            contextMenu.selectAction($currentItem);
        });

        //$(document).mousedown(function (event) {
        //    var $target = $(event.target);
        //    if ($target.hasClass('progressBar') || $target.hasClass('progress') || $target.hasClass('cache')) {
        //        mousedownOnProgressBar = true;
        //    }
        //    if (!$target.parents().hasClass('draggable-list') && !$target.parents().hasClass('list')) {
        //        document.oncontextmenu = function () {
        //            return true;
        //        }
        //    }
        //    if (!$target.hasClass('contextMenuActionName') && event.which != 3) {
        //        $('.contextMenu').detach();
        //    }
        //});

        function _makeDraggable(event) {

            var $target = $(event.target);
            if ($target.hasClass('progressBar') || $target.hasClass('progress') || $target.hasClass('cache')) {
                mousedownOnProgressBar = true;
            }

            mouseClickPosition = { x: event.clientX, y: event.clientY };
            if (event.which == 3) {

                var $currentList = $(event.target);
                $currentList = $currentList.parents('.draggable-list');
                if ($currentList.children().length > 0) {
                    if ($currentList.children('.draggable-item-selected').length == 0) {
                        $('.draggable-item-selected').toggleClass('draggable-item-selected', false);
                    }
                }

                contextMenu.drawContextMenu(event);
            } else {

                mousedown = true;
                $currentItem = $(this);
                var pos = $currentItem.offset();
                elementOffset.x = event.pageX - pos.left;
                elementOffset.y = event.pageY - pos.top;

                if (!$currentItem.hasClass('draggable-item-selected') && !event.shiftKey) {
                    movingInfo.data.push({ "name": $currentItem.parent().attr('name'), "item": $currentItem.html() });
                }

                if (event.ctrlKey) {
                    if ($currentItem.hasClass('draggable-item-selected')) {
                        $currentItem.toggleClass('draggable-item-selected', false);
                        for (i = 0; i < movingInfo.data.length; i++) {
                            if (movingInfo.data[i].name == $currentItem.parent().attr('name') && movingInfo.data[i].item == $currentItem.html()) {
                                movingInfo.data.splice(i, 1);
                            }
                        }
                    } else {
                        $currentItem.toggleClass('draggable-item-selected', true);
                    }
                } else if (event.shiftKey) {
                    var indexFirst = -1;
                    var indexLast = -1;
                    if ($('.draggable-item-selected').last().index() < $currentItem.index()) {
                        indexFirst = $('.draggable-item-selected').last().index();
                        indexLast = $currentItem.index();
                    } else {
                        indexFirst = $currentItem.index();
                        indexLast = $('.draggable-item-selected').last().index();
                    }

                    var currentChildren = $currentItem.parent().children();

                    for (i = indexFirst; i <= indexLast; i++) {
                        var $currentChild = $(currentChildren[i]);
                        if (!$currentChild.hasClass('draggable-item-selected')) {
                            $currentChild.toggleClass('draggable-item-selected', true);
                            movingInfo.data.push({ "name": $currentChild.parent().attr('name'), "item": $currentChild.html() });
                        }
                    }
                } else {
                    var $selectedItems = $('.draggable-item-selected');

                    if (!$currentItem.parent().children().hasClass('draggable-item-selected') && $('.draggable-item-selected').length > 0) {
                        $selectedItems.toggleClass('draggable-item-selected', false);
                    } else if ($currentItem.parent().children().hasClass('draggable-item-selected') && $('.draggable-item-selected').length > 0 && !$currentItem.hasClass('draggable-item-selected')) {
                        $selectedItems.toggleClass('draggable-item-selected', false);
                    } else if ($currentItem.hasClass('draggable-item-selected') && $('.draggable-item-selected').length < 2) {
                        $selectedItems.toggleClass('draggable-item-selected', false);
                    } else if ($('.draggable-item-selected').length == 1) {
                        $selectedItems.toggleClass('draggable-item-selected', false);
                    }
                    $currentItem.toggleClass('draggable-item-selected', true);
                }
            }
        };

        function _setRelativePosition(event) {
            var relX = event.pageX - elementOffset.x;
            var relY = event.pageY - elementOffset.y;
            $currentItem.css({
                'top': relY + 'px',
                'left': relX + 'px'
            });
        }

        function _getCurrentTarget(event) {
            if (navigator.userAgent.match('MSIE') || navigator.userAgent.match('Gecko')) {
                var x = event.clientX, y = event.clientY;
            } else {
                var x = event.pageX, y = event.pageY;
            }
            $currentItem.hide();
            var $elem = $(document.elementFromPoint(x, y));

            if (event.type == "mouseup") {
                if ($elem.hasClass('playlist')) {
                    $currentItem.show();
                    return $elem;
                }
                if ($elem.parents('.playlist').length > 0 && event.type == "mouseup") {
                    $currentItem.show();
                    return $elem.parents('.playlist');
                }
            }
            if ($elem.hasClass('delete-area'))
                _onDeleteArea();
            else if (deleteFlag == true) {
                _outDeleteArea();
            }
            $currentItem.show();

            if ($elem.hasClass('delete-area')) {
                return $elem;
            }

            if ($elem.closest('.draggable-list').find('.draggable-item').length === 0) {
                return $elem.closest('.draggable-list');
            }

            if ($elem.attr('id') == "playlistTracks" && event.type == "mouseup")
                return $($elem.children()[0]);

            return $elem.closest('.draggable-item:not(.dragging.draggable-stub)');
        }

        function _setDeleteAreaCss() {
            if (deleteFlag == true) {
                $('.delete-area').css({
                    'border': 'solid red 3px'
                })
            } else {
                $('.delete-area').css({
                    'border': 'solid black 1px'
                });
            }
        }

        function _clearContainer() {
            $currentItem.removeAttr('style');
            $currentItem.toggleClass('dragging', false);
            $('.draggable-item-selected').toggleClass('draggable-item-selected', false);
            $currentItem = null;
        }

        function _onDeleteArea() {
            deleteFlag = true;
            _setDeleteAreaCss();
        }

        function _outDeleteArea() {
            deleteFlag = false;
            _setDeleteAreaCss();
        }

        $('.draggable').on('MergeItems', function (e, mergeTo, mergeElem, pageY) {
            mergeToPos = mergeTo.offset();
            if ((!mergeTo.hasClass('draggable-stub')) && (mergeToPos.top + 0.15 * $('.draggable-item').height() < pageY) && (mergeToPos.top + 0.85 * $('.draggable-item').height() > pageY)) {
                if (mergeElem && mergeTo) {
                    if ($currentItem.hasClass('itemsContainer') && $('.draggable-item-selected').length > 0) {
                        $currentItem.children().each(function (index, item) {
                            mergeTo.text(mergeTo.html() + ' ' + $(item).html());
                        });
                        $currentItem.children().detach();
                    } else {
                        mergeTo.text(mergeTo.html() + ' ' + mergeElem.html());
                        $currentItem.detach();
                    }
                    mergeTo.trigger('OnCombined', [mergeTo.text()]);
                    _clearContainer();
                }
            }
        });

        //$('.draggable-list').on('sort', function (e, dir) {
        //    $list = $(this);
        //    var sorted = $list.find("> .draggable-item").sort(function (a, b) {
        //        return $(a).text().toLowerCase() > $(b).text().toLowerCase() ? dir : -dir;
        //    });
        //    $list.prepend(sorted);
        //});
    };
});<|endoftext|>


<commit_before>/* eslint-env mocha */
/* eslint-disable no-new */

'use strict'

import Parser from './index'

describe('parser', () => {
  it('should understand only predefined format of grammar', () => {
    try {
      new Parser('lemon')
      new Parser('bison')
      expect(1).equal(1)
    } catch (e) {
      expect(1).equal(0)
    }

    try {
      new Parser('antlr4')
      expect(1).equal(0)
    } catch (e) {
      expect(1).equal(1)
    }
  })

  describe('lemon', () => {
    const parser = new Parser('lemon')

    it('should understand directives', () => {
      parser.parse.bind(parser, `
        %left TOK_A TOK_B.
        %right TOK_C.
        %nonassoc TOK_D.
        %name name
        %token_prefix PREFIX_
        %start_symbol start_rule
        %stack_size 12
        %type start_rule {/*php code*/}
        %declare_class {/*php code*/}
    `).should.not.throw()
    })

    it('should properly handle closing braces in php code sections', () => {
      parser.parse.bind(parser, `
        %destructor {'}'}
        %destructor {'\\'}'}
        %destructor {'
  }'}
        %declare_class {'a\\\\b\\ac\\'de' 'a'}
        %syntax_error {"}"}
        %syntax_error {"\\"}"}
        %syntax_error {"
  }"}
        %declare_class {"a\\\\b\\ac\\"de" "a"}

        %declare_class {{{}}}
    `).should.not.throw()
    })

    it('should not properly handle closing braces in nowdoc and heredoc', () => {
      parser.parse.bind(parser, `
        %destructor {
            <<<HERE
            }
HERE;
        }
    `).should.throw()
      parser.parse.bind(parser, `
        %destructor {
            <<<'NOW'
            }
NOW;
          }
    `).should.throw()

      parser.getErrors().should.have.length.above(0)
    })

    it('should understand grammar rules', () => {
      parser.parse.bind(parser, `
        rule ::= A B.
    `).should.not.throw()
    })

    it('should understand grammar rules with params', () => {
      parser.parse.bind(parser, `
        rule(p1) ::= A(p2) B(p3).
    `).should.not.throw()
    })

    it('should understand grammar rules with params and precedence', () => {
      parser.parse.bind(parser, `
        rule(p1) ::= A(p2) B(p3). [NOT]
    `).should.not.throw()
    })

    it('should understand grammar rules with params, precedence and code section',
      () => {
        parser.parse.bind(parser, `
          rule(p1) ::= A(p2) B(p3). [NOT] {echo 'hi';}
    `).should.not.throw()
      }
    )

    it('should understand single and multiline comments', () => {
      parser.parse.bind(parser, `
        // comment
        rule(p1) ::= A(p2) B(p3)/*comment*/. [NOT] {
            // comment
            echo 'hi'/*}*/;
        }
    `).should.not.throw()
    })

    it('should understand numbers', () => {
      parser.parse.bind(parser, `
        %stack_size 0
        %stack_size 123
    `).should.not.throw()
    })
  })

  describe('bison', () => {
    const parser = new Parser('bison')
    const grammarDeclaration = `
        %left<tag> symbol 10
        %right<tag<tag>> symbol 's' "symbol" 10 0
        %right symbol 's' "symbol" 10 0
        %nonassoc symbol 's' "symbol" 10 0
        %binary symbol 's' "symbol" 10 0
        %precedence symbol 's' "symbol" 10 0

        %nterm<tag>
        %token<tag>
        %token id
        %token id 10
        %token id 10 "str"
        %token id "str"
        %type<tag> symbol symbol2

        %start a
        %start 'a'
        %start "a"

        %destructor {code} symbol "symbol" 's' <tag<tag>>
        %printer {code} symbol "symbol" 's' <tag<tag>>
        %printer {code} symbol "symbol" 's' <*>
        %printer {code} symbol "symbol" 's' <>

        %default-prec
        %no-default-prec

        %code ID {code}
        %code {code}

        %union ID {code}
        %union {code}
`
    let grammarDeclarationWithSemicolons = ''
    for (const line of grammarDeclaration.split(/(\r|\n)+/)) {
      if (line.trim() === '') {
        continue
      }

      grammarDeclarationWithSemicolons += `${line};\n`
    }

    it('should allow prologue declarations', () => {
      parser.parse.bind(parser, `
        ${grammarDeclaration}

        %{
          someCode();
        %}

        %debug
        %locations
        %pure-parser

        %define VAR VAL
        %define "VAR" "VAL"
        %define VAR {code}

        %defines "WHATEVER"
        %defines

        %error-verbose
        %fixed-output-files
        %glr-parser
        %no-default-prec
        %no-lines
        %nondeterministic-parser
        %token-table
        %verbose
        %yacc

        %file-prefix "prefix"
        %language "java"
        %name-prefix "prefix"
        %output "output"
        %require "require"
        %skeleton "skeleton"

        %expect-rr 1
        %expect 1

        %initial-action {someCode();}

        %param {someCode();} {} {moreCode();}
        %lex-param {someCode();} {} {moreCode();}
        %parse-param {someCode();} {} {moreCode();}

        ;
        %%
        a: b c;
    `).should.not.throw()
    })

    it('should allow grammarDeclaration inside grammar part', () => {
      parser.parse.bind(parser, `
        %%
        a: b c;
        ${grammarDeclarationWithSemicolons}
    `).should.not.throw()
    })

    it('should allow rules inside grammar part', () => {
      parser.parse.bind(parser, `
        %%
        a: b c;
        a:[alias] b c;
        empty:
        a: b c
        a: b c;
        a: b[alias] c[alias] d;
        a: {code}[alias];
        a: %?{predicate()} b c;
        empty: %empty;
        a: %prec symbol
        a: %dprec 10
        a: %merge <tag>
        complex
          : b c
          | d e
          |
          ;
    `).should.not.throw()
    })

    it('should allow do not specify prologue and epilogue', () => {
      parser.parse.bind(parser, `
        %%
        a: b c;
    `).should.not.throw()
    })

    it('should allow specify epilogue', () => {
      parser.parse.bind(parser, `
        %%
        a: b c;
        %%
        someCode();
    `).should.not.throw()
    })
  })
})
<commit_msg>test(bison): finish tests for bison parser<commit_after>/* eslint-env mocha */
/* eslint-disable no-new */

'use strict'

import Parser from './index'

describe('parser', () => {
  it('should understand only predefined format of grammar', () => {
    try {
      new Parser('lemon')
      new Parser('bison')
      expect(1).equal(1)
    } catch (e) {
      expect(1).equal(0)
    }

    try {
      new Parser('antlr4')
      expect(1).equal(0)
    } catch (e) {
      expect(1).equal(1)
    }
  })

  describe('lemon', () => {
    const parser = new Parser('lemon')

    it('should understand directives', () => {
      parser.parse.bind(parser, `
        %left TOK_A TOK_B.
        %right TOK_C.
        %nonassoc TOK_D.
        %name name
        %token_prefix PREFIX_
        %start_symbol start_rule
        %stack_size 12
        %type start_rule {/*php code*/}
        %declare_class {/*php code*/}
    `).should.not.throw()
    })

    it('should properly handle closing braces in php code sections', () => {
      parser.parse.bind(parser, `
        %destructor {'}'}
        %destructor {'\\'}'}
        %destructor {'
  }'}
        %declare_class {'a\\\\b\\ac\\'de' 'a'}
        %syntax_error {"}"}
        %syntax_error {"\\"}"}
        %syntax_error {"
  }"}
        %declare_class {"a\\\\b\\ac\\"de" "a"}

        %declare_class {{{}}}
    `).should.not.throw()
    })

    it('should not properly handle closing braces in nowdoc and heredoc', () => {
      parser.parse.bind(parser, `
        %destructor {
            <<<HERE
            }
HERE;
        }
    `).should.throw()
      parser.parse.bind(parser, `
        %destructor {
            <<<'NOW'
            }
NOW;
          }
    `).should.throw()

      parser.getErrors().should.have.length.above(0)
    })

    it('should understand grammar rules', () => {
      parser.parse.bind(parser, `
        rule ::= A B.
    `).should.not.throw()
    })

    it('should understand grammar rules with params', () => {
      parser.parse.bind(parser, `
        rule(p1) ::= A(p2) B(p3).
    `).should.not.throw()
    })

    it('should understand grammar rules with params and precedence', () => {
      parser.parse.bind(parser, `
        rule(p1) ::= A(p2) B(p3). [NOT]
    `).should.not.throw()
    })

    it('should understand grammar rules with params, precedence and code section',
      () => {
        parser.parse.bind(parser, `
          rule(p1) ::= A(p2) B(p3). [NOT] {echo 'hi';}
    `).should.not.throw()
      }
    )

    it('should understand single and multiline comments', () => {
      parser.parse.bind(parser, `
        // comment
        rule(p1) ::= A(p2) B(p3)/*comment*/. [NOT] {
            // comment
            echo 'hi'/*}*/;
        }
    `).should.not.throw()
    })

    it('should understand numbers', () => {
      parser.parse.bind(parser, `
        %stack_size 0
        %stack_size 123
    `).should.not.throw()
    })
  })

  describe('bison', () => {
    const parser = new Parser('bison')
    const grammarDeclaration = `
        %left<tag> symbol 10
        %right<tag<tag>> symbol 's' "symbol" 10 0
        %right symbol 's' "symbol" 10 0
        %nonassoc symbol 's' "symbol" 10 0
        %binary symbol 's' "symbol" 10 0
        %precedence symbol 's' "symbol" 10 0

        %nterm<tag>
        %token<tag>
        %token id
        %token id 10
        %token id 10 "str"
        %token id "str"
        %type<tag> symbol symbol2

        %start a
        %start 'a'
        %start "a"

        %destructor {code} symbol "symbol" 's' '\\n' <tag<tag>>
        %printer {code} symbol "symbol" 's' <tag<tag>>
        %printer {code} symbol "symbol" 's' <*>
        %printer {code} symbol "symbol" 's' <>

        %default-prec
        %no-default-prec

        %code ID {code}
        %code {code}

        %union ID {code}
        %union {code}
`
    let grammarDeclarationWithSemicolons = ''
    for (const line of grammarDeclaration.split(/(\r|\n)+/)) {
      if (line.trim() === '') {
        continue
      }

      grammarDeclarationWithSemicolons += `${line};\n`
    }

    it('should allow prologue declarations', () => {
      parser.parse.bind(parser, `
        ${grammarDeclaration}

        %{
          someCode();
        %}

        %debug
        %locations
        %pure-parser

        %define VAR VAL
        %define "VAR" "VAL"
        %define VAR {code}

        %defines "WHATEVER"
        %defines

        %error-verbose
        %fixed-output-files
        %glr-parser
        %no-default-prec
        %no-lines
        %nondeterministic-parser
        %token-table
        %verbose
        %yacc

        %file-prefix "prefix"
        %file-prefix "a\\"b\\\\c"
        %language "java"
        %name-prefix "prefix"
        %output "output"
        %require "require"
        %skeleton "skeleton"

        %expect-rr 1
        %expect 1

        %initial-action {someCode();}

        %param {someCode();} {} {moreCode();}
        %lex-param {someCode();} {} {moreCode();}
        %parse-param {someCode();} {} {moreCode();}

        ;

        // Line comment
        /*
         Block comment.
         */
        %%
        a: b c;
    `).should.not.throw()
    })

    it('should allow grammarDeclaration inside grammar part', () => {
      parser.parse.bind(parser, `
        %%
        a: b c;
        ${grammarDeclarationWithSemicolons}
    `).should.not.throw()
    })

    it('should allow rules inside grammar part', () => {
      parser.parse.bind(parser, `
        %%
        a: b c;
        a:[alias] b c;
        empty:
        a: b c
        a: b c;
        a: b[alias] c[alias] d;
        a: {code}[alias];
        a: %?{predicate()} b c;
        empty: %empty;
        a: %prec symbol
        a: %dprec 10
        a: %merge <tag>
        complex
          : b c
          | d e
          |
          ;
    `).should.not.throw()
    })

    it('should allow do not specify prologue and epilogue', () => {
      parser.parse.bind(parser, `
        %%
        a: b c;
    `).should.not.throw()
    })

    it('should allow specify epilogue', () => {
      parser.parse.bind(parser, `
        %%
        a: b c;
        %%
        someCode();
    `).should.not.throw()
    })

    it('should properly handle closing braces in code sections', () => {
      parser.parse.bind(parser, `
        %code {'}'}
        %code {'\\'}'}
        %code {'}'}
        %code {'a\\\\b\\ac\\'de' 'a'}
        %code {"}"}
        %code {"\\"}"}
        %code {"}"}
        %code {"a\\\\b\\ac\\"de" "a"}

        %code {{{}}}
        %%
        a: b c;
    `).should.not.throw()
    })
  })
})
<|endoftext|>


<commit_before>var fs = require('fs'),
    vm = require('vm'),
    qs = require('querystring'),
    url = require('url'),
    path = require('path'),
    utils = require('./utils.js'),
    mockjs = require('mockjs');

function MockData(opt){
    opt = utils.extend(true, {
        datapath: path.join(process.cwd() + "mock/"),
        mockrc: ".mockrc", //相对mock datapath
        ignore: ['html', 'js', 'css', 'jpg', 'png', 'gif'],
        regexurl: { //前面是regex new RegExp()
        }
    }, opt);

    this.init(opt);
}

MockData.prototype = {
    init: function(opt){
        this.ignore = opt.ignore;
        this.mockItems = this.convertRegexURL(opt.datapath, opt.regexurl);
        this.initMockRandom(path.isAbsolute(opt.mockrc)? opt.mockrc : path.join(opt.datapath, opt.mockrc));
    },
    initMockRandom: function(mockrcpath){
        console.log("-------mockrcpath:\n", mockrcpath)
        var mockRandom = fs.existsSync(mockrcpath) ?
                            JSON.parse(fs.readFileSync(mockrcpath)) : {};

        for(var i in mockRandom){
            var randomData = {},
                name = i.toLowerCase(),
                list = name + 's';
            (function(i, list, name){
                randomData[list] = mockRandom[i];
                randomData[name] = function(data){
                    return this.pick(this[list]);
                }
                console.log(randomData);
                mockjs.Random.extend(randomData);
                console.log("-------Random add:\n", randomData)
            })(i, list, name);
        }
    },
    convertRegexURL: function(mockPath, regexurl){
        var mockItems = {}, j = 0;
        for(var i in regexurl){
            mockItems[j++] = {
                reg: new RegExp(i),
                data: path.join(mockPath, regexurl[i])
            }
        }
        return mockItems;
    },
    // @parma url:当前请求的url,
    // @parma ext:当前请求的后缀，用于过滤一些不需要mock的文件
    // @return {cnt, ext} cnt:mock数据文件的原始内容, ext: mock类型
    getMockData: function(url, ext){
        var cnt, type, mockItems = this.mockItems;
        if(this.ignore.indexOf(ext) === -1){
            for(var i in mockItems){
                var item = mockItems[i];
                if(item.reg.test(url)){
                    cnt = fs.readFileSync(item.data);
                    type = path.extname(item.data).slice(1);
                    break;
                }
            }
        }
        return {cnt: cnt, type: type};
    },
    getMockJsonData: function(json){
        return mockjs.mock(json);
    },
    // mock response 用mock data 响应服务
    mockResponse: function(data, req, res, config){
        if(!data.cnt) return false;
        // console.log("----------ajax json:\n", data.type);
        switch(data.type){
            case 'mjson': //处理mockjson
                console.log(mockjs.mock(JSON.parse(data.cnt)))
                data.cnt = JSON.stringify(mockjs.mock(JSON.parse(data.cnt)), null, 4);
            case 'json':
                res.writeHead(200, {
                    'Content-Type': utils.MIME['json']
                });
                res.write(data.cnt);
                res.end();
                break;
            case 'js':
                //data = new vm.script(data[0]);
                // 将分解好的url给mock用户*.js
                req.wwwurl = url.parse(config.protocol + '://' + req.headers.host + req.url);
                req.wwwurl.queryObj = req.wwwurl.query ? qs.parse(req.wwwurl.query) : {};
                //extname === 'html' && console.log(req, '\n\n\n\n', req.wwwurl)
                console.log('----------mock js func:\n', data.cnt.toString());
                vm.runInThisContext('(' + data.cnt + ')')(req, res);
                break;
            default:
                console.log("mock 暂只支持.mjson .json .js文件");
                res.end("mock 暂只支持.mjson .json .js文件");
        }
        return true;
    }

}

module.exports = MockData;<commit_msg>fix mock error<commit_after>var fs = require('fs'),
    vm = require('vm'),
    qs = require('querystring'),
    url = require('url'),
    path = require('path'),
    utils = require('./utils.js'),
    mockjs = require('mockjs');

function MockData(opt){
    opt = utils.extend(true, {
        datapath: path.join(process.cwd() + "mock/"),
        mockrc: ".mockrc", //相对mock datapath
        ignore: ['html', 'js', 'css', 'jpg', 'png', 'gif'],
        regexurl: { //前面是regex new RegExp()
        }
    }, opt);

    this.init(opt);
}

MockData.prototype = {
    init: function(opt){
        this.ignore = opt.ignore;
        this.mockItems = this.convertRegexURL(opt.datapath, opt.regexurl);
        this.initMockRandom(path.isAbsolute(opt.mockrc)? opt.mockrc : path.join(opt.datapath, opt.mockrc));
    },
    initMockRandom: function(mockrcpath){
        console.log("-------mockrcpath:\n", mockrcpath)
        var mockRandom = fs.existsSync(mockrcpath) ?
                            JSON.parse(fs.readFileSync(mockrcpath)) : {};

        for(var i in mockRandom){
            var randomData = {},
                name = i.toLowerCase(),
                list = name + 's';
            (function(i, list, name){
                randomData[list] = mockRandom[i];
                randomData[name] = function(data){
                    return this.pick(this[list]);
                }
                console.log(randomData);
                mockjs.Random.extend(randomData);
                console.log("-------Random add:\n", randomData)
            })(i, list, name);
        }
    },
    convertRegexURL: function(mockPath, regexurl){
        var mockItems = {}, j = 0;
        for(var i in regexurl){
            mockItems[j++] = {
                reg: new RegExp(i),
                data: path.join(mockPath, regexurl[i])
            }
        }
        return mockItems;
    },
    // @parma url:当前请求的url,
    // @parma ext:当前请求的后缀，用于过滤一些不需要mock的文件
    // @return {cnt, ext} cnt:mock数据文件的原始内容, ext: mock类型
    getMockData: function(url, ext){
        var cnt, type, mockItems = this.mockItems;
        if(this.ignore.indexOf(ext) === -1){
            for(var i in mockItems){
                var item = mockItems[i];
                if(item.reg.test(url)){
                    cnt = fs.readFileSync(item.data);
                    type = path.extname(item.data).slice(1);
                    break;
                }
            }
        }
        return {cnt: cnt, type: type};
    },
    getMockJsonData: function(json){
        return mockjs.mock(json);
    },
    // mock response 用mock data 响应服务
    mockResponse: function(data, req, res, config){
        if(!data.cnt) return false;
        // console.log("----------ajax json:\n", data.type);
        try{
            switch(data.type){
                case 'mjson': //处理mockjson
                    console.log(mockjs.mock(JSON.parse(data.cnt)))
                    data.cnt = JSON.stringify(mockjs.mock(JSON.parse(data.cnt)), null, 4);
                case 'json':
                    res.writeHead(200, {
                        'Content-Type': utils.MIME['json']
                    });
                    res.write(data.cnt);
                    res.end();
                    break;
                case 'js':
                    //data = new vm.script(data[0]);
                    // 将分解好的url给mock用户*.js
                    req.wwwurl = url.parse(config.protocol + '://' + req.headers.host + req.url);
                    req.wwwurl.queryObj = req.wwwurl.query ? qs.parse(req.wwwurl.query) : {};
                    //extname === 'html' && console.log(req, '\n\n\n\n', req.wwwurl)
                    console.log('----------mock js func:\n', data.cnt.toString());
                    vm.runInThisContext('(' + data.cnt + ')')(req, res);
                    break;
                default:
                    console.log("mock 暂只支持.mjson .json .js文件");
                    res.end("mock 暂只支持.mjson .json .js文件");
            }
        } catch(e){
            console.log("mock error: ", e);
        }
        return true;
    }

}

module.exports = MockData;<|endoftext|>


<commit_before>(function() {
    var Ext = window.Ext4 || window.Ext;

    /**
     * Portfolio Hierarchy App
     * View and rearrange PIs and their user stories
     */
    Ext.define('Rally.apps.portfoliohierarchy.PortfolioHierarchyApp', {
        extend: 'Rally.app.App',
        requires: [
            'Rally.ui.tooltip.PercentDoneToolTip',
            'Rally.data.util.PortfolioItemHelper',
            'Rally.ui.notify.Notifier',
            'Rally.data.QueryFilter',
            'Rally.util.Test'
        ],

        layout: 'auto',

        items:[
            {
                xtype:'container',
                itemId:'header',
                cls:'header'
            },
            {
                xtype:'container',
                itemId:'bodyContainer'
            }
        ],

        appName: 'Portfolio Hierarchy',

        cls: 'portfolio-hierarchy-app',

        launch: function() {

            Rally.data.util.PortfolioItemHelper.loadTypeOrDefault({
                typeRef: this.getSetting('type'),
                context: this.getContext().getDataContext(),
                defaultToLowest: false,
                success: this.addTreeForType,
                scope: this
            });
        },

        _drawHeader: function(){
            var header = this.down('#header');
            header.add(this._buildHelpComponent());
            header.add(this._buildFilterInfo());
        },

        addTreeForType: function(record){

            this.typePath = record.get('Name');
            this._drawHeader();

            var tree = this.buildTreeForType(record);
            this.down('#bodyContainer').add(tree);

            tree.on('initialload', function(){
                if (Rally.BrowserTest) {
                    Rally.BrowserTest.publishComponentReady(this);
                }
            }, this);

        },

        buildTreeForType: function(typeRecord){
            var me = this;

            var filters = [];
            if (this.getSetting('query')) {
                try {
                  filters.push(Rally.data.QueryFilter.fromQueryString(this.getSetting('query')));
                } catch (e) {
                    Rally.ui.notify.Notifier.showError({
                        message: e.message
                    });
                }
            }

            return Ext.create('Rally.ui.tree.PortfolioTree', {
                stateful: true,
                stateId: this.getAppId() + 'rallyportfoliotree',
                topLevelModel: typeRecord.get('TypePath'),
                topLevelStoreConfig: {
                    filters: filters,
                    context: this.getContext().getDataContext()
                },
                childItemsStoreConfigForParentRecordFn: function(){
                    return {
                        context: {
                            project: undefined,
                            workspace: me.getContext().getDataContext().workspace
                        },
                        fetch: this._getChildLevelFetchFields()
                    };
                },
                emptyText: '
No portfolio items of this type found.
' +
                           '
Click the gear to set your project to match the location of your portfolio items or to filter further by type.
'
            });
        },

        _buildHelpComponent:function () {
            return Ext.create('Ext.Component', {
                cls:Rally.util.Test.toBrowserTestCssClass('portfolio-hierarchy-help-container'),
                renderTpl: Rally.util.Help.getIcon({
                    id: 268
                })
            });
        },

        _buildFilterInfo: function(){
            return Ext.create('Rally.ui.tooltip.FilterInfo', {
                projectName: this.getSetting('project') && this.getContext().get('project').Name || 'Following Global Project Setting',
                typePath: this.typePath,
                scopeUp: this.getSetting('projectScopeUp'),
                scopeDown: this.getSetting('projectScopeDown'),
                query: this.getSetting('query')
            });
        }

    });
})();
<commit_msg>DE16897: fixing Portfolio Hierarchy infinite loop if RPM module is turned off<commit_after>(function() {
    var Ext = window.Ext4 || window.Ext;

    /**
     * Portfolio Hierarchy App
     * View and rearrange PIs and their user stories
     */
    Ext.define('Rally.apps.portfoliohierarchy.PortfolioHierarchyApp', {
        extend: 'Rally.app.App',
        requires: [
            'Rally.ui.tooltip.PercentDoneToolTip',
            'Rally.data.util.PortfolioItemHelper',
            'Rally.ui.notify.Notifier',
            'Rally.data.QueryFilter',
            'Rally.util.Test'
        ],

        layout: 'auto',

        items:[
            {
                xtype:'container',
                itemId:'header',
                cls:'header'
            },
            {
                xtype:'container',
                itemId:'bodyContainer'
            }
        ],

        appName: 'Portfolio Hierarchy',

        cls: 'portfolio-hierarchy-app',

        launch: function() {

            if(Rally.environment.getContext().getSubscription().isModuleEnabled('Rally Portfolio Manager')) {
                Rally.data.util.PortfolioItemHelper.loadTypeOrDefault({
                    typeRef: this.getSetting('type'),
                    context: this.getContext().getDataContext(),
                    defaultToLowest: false,
                    success: this.addTreeForType,
                    scope: this
                });
            } else {
                this.down('#bodyContainer').add({
                    xtype: 'container',
                    html: '
You do not have RPM enabled for your subscription
'
                });

            }

        },

        _drawHeader: function(){
            var header = this.down('#header');
            header.add(this._buildHelpComponent());
            header.add(this._buildFilterInfo());
        },

        addTreeForType: function(record){

            this.typePath = record.get('Name');
            this._drawHeader();

            var tree = this.buildTreeForType(record);
            this.down('#bodyContainer').add(tree);

            tree.on('initialload', function(){
                if (Rally.BrowserTest) {
                    Rally.BrowserTest.publishComponentReady(this);
                }
            }, this);

        },

        buildTreeForType: function(typeRecord){
            var me = this;

            var filters = [];
            if (this.getSetting('query')) {
                try {
                  filters.push(Rally.data.QueryFilter.fromQueryString(this.getSetting('query')));
                } catch (e) {
                    Rally.ui.notify.Notifier.showError({
                        message: e.message
                    });
                }
            }

            return Ext.create('Rally.ui.tree.PortfolioTree', {
                stateful: true,
                stateId: this.getAppId() + 'rallyportfoliotree',
                topLevelModel: typeRecord.get('TypePath'),
                topLevelStoreConfig: {
                    filters: filters,
                    context: this.getContext().getDataContext()
                },
                childItemsStoreConfigForParentRecordFn: function(){
                    return {
                        context: {
                            project: undefined,
                            workspace: me.getContext().getDataContext().workspace
                        },
                        fetch: this._getChildLevelFetchFields()
                    };
                },
                emptyText: '
No portfolio items of this type found.
' +
                           '
Click the gear to set your project to match the location of your portfolio items or to filter further by type.
'
            });
        },

        _buildHelpComponent:function () {
            return Ext.create('Ext.Component', {
                cls:Rally.util.Test.toBrowserTestCssClass('portfolio-hierarchy-help-container'),
                renderTpl: Rally.util.Help.getIcon({
                    id: 268
                })
            });
        },

        _buildFilterInfo: function(){
            return Ext.create('Rally.ui.tooltip.FilterInfo', {
                projectName: this.getSetting('project') && this.getContext().get('project').Name || 'Following Global Project Setting',
                typePath: this.typePath,
                scopeUp: this.getSetting('projectScopeUp'),
                scopeDown: this.getSetting('projectScopeDown'),
                query: this.getSetting('query')
            });
        }

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


<commit_before>/*
!! DO NOT USE ANY OF THIS CODE, ITS ONLY FOR OUR DOCS PAGE !!
 _             _
(_)           (_)
 _  ___  _ __  _  ___
| |/ _ \| '_ \| |/ __|
| | (_) | | | | | (__
|_|\___/|_| |_|_|\___|

*/

(function(){

  /* Header menu toggle for mobile */
  $("#menu-toggle").click(function(e) {
      e.preventDefault();
      $(this).toggleClass("active");
  });

  /* Fixed left menu */
  var fixedMenu = $('.docked-menu');
  var activeId;
  if(fixedMenu.length) {
    $(document.body).scrollspy({ target: '.docked-menu', offset: 300 });

    var fixedMenuTop = fixedMenu.offset().top;
    var menuTopPadding = 20;
    fixedMenu.css({
      top: menuTopPadding + 'px'
    });

    function docScroll() {
      if(window.scrollY + menuTopPadding > fixedMenuTop) {
        fixedMenu
          .css({
            width: fixedMenu.width() + 'px'
          })
          .addClass("fixed-menu");
      } else {
        fixedMenu
          .removeClass("fixed-menu")
          .css({
            width: 'auto'
          });
        if(window.scrollY < 200) {
          $('.active').removeClass(".active");
        }
      }
    }
    $(window).resize(function(){
      fixedMenu
          .removeClass("fixed-menu")
          .css({
            width: 'auto'
          });
      docScroll();
    });
    $(window).scroll(docScroll);
  }

  /* Fixed device preview on the docs page */
  var devicePreview = $('.device-preview');
  if(devicePreview.length) {
    var docContent = $('.main-content');
    var orgDeviceTop = devicePreview.offset().top;
    var $defaultScreen = devicePreview.find('.default-screen');

    function onScroll() {
      if(window.scrollY > orgDeviceTop) {
        if( !devicePreview.hasClass('fixed-preview') ) {
          devicePreview
            .css({
              left: Math.round(devicePreview.offset().left) + 'px'
            })
            .addClass("fixed-preview");
          }
      } else {
        if( devicePreview.hasClass('fixed-preview') ) {
          devicePreview
            .removeClass("fixed-preview")
            .css({
              left: 'auto'
            });
        }
      }

    }
    $(window).resize(function(){
      devicePreview
          .removeClass("fixed-preview")
          .css({
            left: 'auto'
          });
      onScroll();
    });
    $(window).scroll(onScroll);
    onScroll();

    function scrollSpyChange(e) {
      if(smoothScrollingTo || !docContent) return;

      var id;
      if(e.target.children.length > 1) {
        // this is a top level nav link
        var activeSublinks = $(e.target).find('.active');
        if(!activeSublinks.length) {
          // no children are active for this top level link
          id = e.target.children[0].hash;
        }
      } else if(e.target.children.length === 1) {
        // this is a sub nav link
        id = e.target.children[0].hash;
      }

      if(id) {
        setTimeout(function(){
          previewSection(id);
        });
      }
    }
    fixedMenu.on('activate.bs.scrollspy', scrollSpyChange);

    var defaultScreen = devicePreview.find('.default-screen');
    function previewSection(id, doNotSetHistory) {
      var activeSection = $(id);
      if(!activeSection.length) return;

      var title = activeSection.find('h1,h2,h3').first();
      var newTitle = "Ionic Components";
      activeId = activeSection.attr('id');
      if(title.length) {
        newTitle = title.text() + " - " + newTitle;
      }
      document.title = newTitle;

      docContent.find('.active').removeClass('active');
      activeSection.addClass("active");

      if(!doNotSetHistory && window.history.replaceState) {
        window.history.replaceState({}, newTitle, "#" + activeId);
      }

      devicePreview.find('.active-preview').removeClass('active-preview');
      var docExample = activeSection.find('.doc-example');
      if( docExample.length ) {
        // this
        var exampleId = 'example-' + activeId;
        var examplePreview = $('#' + exampleId);
        if(examplePreview.length) {
          // preview has already been added
          examplePreview.addClass('active-preview');
        } else {
          // create a new example preview
          devicePreview.append( '
' + docExample.html() + '
' );
          setTimeout(function(){
            $('#' + exampleId)
              .addClass('active-preview')
              .find('a').click(function(){
                return false;
              });
          });
        }

      } else {
        defaultScreen.addClass('active-preview');
      }
    }

    var firstSection = docContent.find('.docs-section').first();
    if(firstSection.length) {
      previewSection( '#' + firstSection[0].id, true );
    }

  }

  // Smooth Scrolling
  var smoothScrollingTo;
  $(function() {
    $('a[href*=#]:not([href=#])').click(function() {
      if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {
        var target = $(this.hash);
        target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
        if (target.length) {
          smoothScrollingTo = '#' + target.attr('id');
          $('html,body').animate({ scrollTop: target.offset().top }, 100, 'swing',
            function() {
              if(docContent) {
                previewSection(smoothScrollingTo);
              }
              smoothScrollingTo = undefined;
            });
          return false;
        }
      }
    });
  });

})();
<commit_msg>window scroll fix<commit_after>/*
!! DO NOT USE ANY OF THIS CODE, ITS ONLY FOR OUR DOCS PAGE !!
 _             _
(_)           (_)
 _  ___  _ __  _  ___
| |/ _ \| '_ \| |/ __|
| | (_) | | | | | (__
|_|\___/|_| |_|_|\___|

*/

(function(){

  /* Header menu toggle for mobile */
  $("#menu-toggle").click(function(e) {
      e.preventDefault();
      $(this).toggleClass("active");
  });

  /* Fixed left menu */
  var fixedMenu = $('.docked-menu');
  var activeId;
  if(fixedMenu.length) {
    $(document.body).scrollspy({ target: '.docked-menu', offset: 300 });

    var fixedMenuTop = fixedMenu.offset().top;
    var menuTopPadding = 20;
    fixedMenu.css({
      top: menuTopPadding + 'px'
    });

    function docScroll() {
      var scrollTop = $(window).scrollTop();
      if(scrollTop + menuTopPadding > fixedMenuTop) {
        fixedMenu
          .css({
            width: fixedMenu.width() + 'px'
          })
          .addClass("fixed-menu");
      } else {
        fixedMenu
          .removeClass("fixed-menu")
          .css({
            width: 'auto'
          });
        if(scrollTop < 200) {
          $('.active').removeClass(".active");
        }
      }
    }
    $(window).resize(function(){
      fixedMenu
          .removeClass("fixed-menu")
          .css({
            width: 'auto'
          });
      docScroll();
    });
    $(window).scroll(docScroll);
  }

  /* Fixed device preview on the docs page */
  var devicePreview = $('.device-preview');
  if(devicePreview.length) {
    var docContent = $('.main-content');
    var orgDeviceTop = devicePreview.offset().top;
    var $defaultScreen = devicePreview.find('.default-screen');

    function onScroll() {
      if($(window).scrollTop() > orgDeviceTop) {
        if( !devicePreview.hasClass('fixed-preview') ) {
          devicePreview
            .css({
              left: Math.round(devicePreview.offset().left) + 'px'
            })
            .addClass("fixed-preview");
          }
      } else {
        if( devicePreview.hasClass('fixed-preview') ) {
          devicePreview
            .removeClass("fixed-preview")
            .css({
              left: 'auto'
            });
        }
      }

    }
    $(window).resize(function(){
      devicePreview
          .removeClass("fixed-preview")
          .css({
            left: 'auto'
          });
      onScroll();
    });
    $(window).scroll(onScroll);
    onScroll();

    function scrollSpyChange(e) {
      if(smoothScrollingTo || !docContent) return;

      var id;
      if(e.target.children.length > 1) {
        // this is a top level nav link
        var activeSublinks = $(e.target).find('.active');
        if(!activeSublinks.length) {
          // no children are active for this top level link
          id = e.target.children[0].hash;
        }
      } else if(e.target.children.length === 1) {
        // this is a sub nav link
        id = e.target.children[0].hash;
      }

      if(id) {
        setTimeout(function(){
          previewSection(id);
        });
      }
    }
    fixedMenu.on('activate.bs.scrollspy', scrollSpyChange);

    var defaultScreen = devicePreview.find('.default-screen');
    function previewSection(id, doNotSetHistory) {
      var activeSection = $(id);
      if(!activeSection.length) return;

      var title = activeSection.find('h1,h2,h3').first();
      var newTitle = "Ionic Components";
      activeId = activeSection.attr('id');
      if(title.length) {
        newTitle = title.text() + " - " + newTitle;
      }
      document.title = newTitle;

      docContent.find('.active').removeClass('active');
      activeSection.addClass("active");

      if(!doNotSetHistory && window.history.replaceState) {
        window.history.replaceState({}, newTitle, "#" + activeId);
      }

      devicePreview.find('.active-preview').removeClass('active-preview');
      var docExample = activeSection.find('.doc-example');
      if( docExample.length ) {
        // this
        var exampleId = 'example-' + activeId;
        var examplePreview = $('#' + exampleId);
        if(examplePreview.length) {
          // preview has already been added
          examplePreview.addClass('active-preview');
        } else {
          // create a new example preview
          devicePreview.append( '
' + docExample.html() + '
' );
          setTimeout(function(){
            $('#' + exampleId)
              .addClass('active-preview')
              .find('a').click(function(){
                return false;
              });
          });
        }

      } else {
        defaultScreen.addClass('active-preview');
      }
    }

    var firstSection = docContent.find('.docs-section').first();
    if(firstSection.length) {
      previewSection( '#' + firstSection[0].id, true );
    }

  }

  // Smooth Scrolling
  var smoothScrollingTo;
  $(function() {
    $('a[href*=#]:not([href=#])').click(function() {
      if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {
        var target = $(this.hash);
        target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
        if (target.length) {
          smoothScrollingTo = '#' + target.attr('id');
          $('html,body').animate({ scrollTop: target.offset().top }, 100, 'swing',
            function() {
              if(docContent) {
                previewSection(smoothScrollingTo);
              }
              smoothScrollingTo = undefined;
            });
          return false;
        }
      }
    });
  });

})();
<|endoftext|>


<commit_before>/**
 * @author simonThiele / https://github.com/simonThiele
 */

module( "InterleavedBuffer" );

function checkInstanceAgainstCopy(instance, copiedInstance) {
	ok( copiedInstance instanceof THREE.InterleavedBuffer, "the clone has the correct type" );

	for (var i = 0; i < instance.array.length; i++) {
		ok( copiedInstance.array[i] === instance.array[i], "array was copied" );
	}

	ok( copiedInstance.stride === instance.stride, "stride was copied" );
	ok( copiedInstance.dynamic === true, "dynamic was copied" );
}

test( "length and count", function() {
	var instance = new THREE.InterleavedBuffer( new Float32Array( [1, 2, 3, 7, 8 ,9] ), 3 );

	ok( instance.length === 6, "length is calculated via array length" );
	ok( instance.count === 2, "count is calculated via array length / stride" );
});

test( "copy", function() {
	var array = new Float32Array( [1, 2, 3, 7, 8 ,9] );
	var instance = new THREE.InterleavedBuffer( array, 3 );
	instance.setDynamic( true );

	checkInstanceAgainstCopy(instance, instance.copy( instance ) );
});

test( "clone", function() {
	var array = new Float32Array( [1, 2, 3, 7, 8 ,9] );
	var instance = new THREE.InterleavedBuffer( array, 3 );
	instance.setDynamic( true );

	checkInstanceAgainstCopy( instance, instance.clone() );
});

test( "set", function() {
	var instance = new THREE.InterleavedBuffer( new Float32Array( [1, 2, 3, 7, 8 ,9] ), 3 );

	instance.set( [0, -1] );
	ok( instance.array[0] === 0 && instance.array[1] === -1, "replace at first by default" );
});
<commit_msg>add spacings to InterleavedBuffer<commit_after>/**
 * @author simonThiele / https://github.com/simonThiele
 */

module( "InterleavedBuffer" );

function checkInstanceAgainstCopy( instance, copiedInstance ) {
	ok( copiedInstance instanceof THREE.InterleavedBuffer, "the clone has the correct type" );

	for ( var i = 0; i < instance.array.length; i++ ) {
		ok( copiedInstance.array[i] === instance.array[i], "array was copied" );
	}

	ok( copiedInstance.stride === instance.stride, "stride was copied" );
	ok( copiedInstance.dynamic === true, "dynamic was copied" );
}

test( "length and count", function() {
	var instance = new THREE.InterleavedBuffer( new Float32Array( [1, 2, 3, 7, 8 ,9] ), 3 );

	ok( instance.length === 6, "length is calculated via array length" );
	ok( instance.count === 2, "count is calculated via array length / stride" );
});

test( "copy", function() {
	var array = new Float32Array( [1, 2, 3, 7, 8 ,9] );
	var instance = new THREE.InterleavedBuffer( array, 3 );
	instance.setDynamic( true );

	checkInstanceAgainstCopy(instance, instance.copy( instance ) );
});

test( "clone", function() {
	var array = new Float32Array( [1, 2, 3, 7, 8 ,9] );
	var instance = new THREE.InterleavedBuffer( array, 3 );
	instance.setDynamic( true );

	checkInstanceAgainstCopy( instance, instance.clone() );
});

test( "set", function() {
	var instance = new THREE.InterleavedBuffer( new Float32Array( [1, 2, 3, 7, 8 ,9] ), 3 );

	instance.set( [0, -1] );
	ok( instance.array[0] === 0 && instance.array[1] === -1, "replace at first by default" );
});
<|endoftext|>


<commit_before>/**
 * @namespace
 * Module for modifying http requests
 */

/**
 * import Privly constants
 */
Components.utils.import("resource://privly/constants.jsm");

/**
 * see https://developer.mozilla.org/en/using_xmlhttprequest#Using_XMLHttpRequest_from_JavaScript_modules_.2F_XPCOM.C2.A0components
 * xmlhttprequest in javascript modules
 */
const { XMLHttpRequest } = Components.classes["@mozilla.org/appshell/appShellService;1"]
                                     .getService(Components.interfaces.nsIAppShellService)
                                     .hiddenDOMWindow;

var EXPORTED_SYMBOLS = ["privlyObservers"];

var privlyObservers =  {

  /**
   * @namespace
   * Sets headers on requests to Privly servers.
   */
  httpRequestObserver: {

    /**
     * Interface object to the extension preferences.
     */
    preferences: Components.classes["@mozilla.org/preferences-service;1"]
      .getService(Components.interfaces.nsIPrefService)
      .getBranch("extensions.privly."),

    /**
     * Add headers to Privly requests containing the extension version
     * and the authentication token.
     *
     * @param {http subject} subject the interface for accessing the http
     * channel.
     *
     * @param {string} topic The name of the object being examined.
     * "http-on-modify-request" is expected, otherwise nothing is done.
     *
     * @param {data} data The response data. This variable is currently unused.
     *
     */
    observe: function(subject, topic, data) {

      "use strict";

      if (topic === "http-on-modify-request") {
        var httpChannel = subject.QueryInterface(Components
                                                .interfaces.nsIHttpChannel);

        // Set the extension version
        httpChannel.setRequestHeader("X-Privly-Version", "0.1.8", false);
        /*
         * set the extension version and auth_token param on the request headers
         * the content server uses this authToken to identify a specific user.
         * TBD:
         * 1. version number is hardcoded. write a function to retrieve the
         * extension version number automatically
         * 2. use a regex to match the content server url to eliminate the
         * if-else
         */
        var extensionMode = this.preferences.getIntPref("extensionMode");
        if (/priv.ly/.test(httpChannel.originalURI.host)) {
          httpChannel.setRequestHeader(privlyConstants.Strings.authToken,
                                        this.preferences.getCharPref(privlyConstants.Strings.authToken), false);
        }
        else if (/localhost/.test(httpChannel.originalURI.host)) {
          httpChannel.setRequestHeader(privlyConstants.Strings.authToken,
                                        this.preferences.getCharPref(privlyConstants.Strings.authToken), false);
        }
      }
    },

    get observerService() {

      "use strict";

      return Components.classes["@mozilla.org/observer-service;1"]
                      .getService(Components.interfaces.nsIObserverService);
    },

    /**
     * Add the request observer to the overlay
     */
    register: function() {

      "use strict";

      this.observerService.addObserver(this, "http-on-modify-request", false);
    },

    /**
     * Remove this request observer from the overlay
     */
    unregister: function() {

      "use strict";

      this.observerService.removeObserver(this, "http-on-modify-request");
    }
  },

  /**
   * @namespace
   * The response observer checks whether localhost or priv.ly
   * set operation flags. These are usually set in instances
   * of high content server load. The extension will notify
   * the user of the issue, and switch into passive mode.
   *
   * The content server can set the extension to any one of the three modes.
   * it can do so by setting a header in the response header called
   * 'privlyExtensionCommand'.
   * in responseObserver, we read this header value and set the extension mode
   * accordingly
   */
  httpResponseObserver: {

    /**
     * Interface object to the extension preferences.
     */
    preferences: Components.classes["@mozilla.org/preferences-service;1"]
                            .getService(Components.interfaces.nsIPrefService)
                            .getBranch("extensions.privly."),

    /**
     * Respond to mode changes from the server.
     *
     * @param {http subject} subject the interface for accessing the http
     * channel.
     *
     * @param {string} topic The name of the object being examined.
     * "http-on-examine-response" is expected, otherwise nothing is done.
     *
     * @param {data} data The response data. This variable is currently unused.
     *
     */
    observe: function(subject, topic, data) {

      "use strict";

      if (topic === "http-on-examine-response") {
        var httpChannel = subject.QueryInterface(Components
                                                .interfaces.nsIHttpChannel);
        /*
         * read the extensionCommand header from the response.
         * if the response header is not set or the server
         * didn't reply, it will throw an error. so catch it
         */
        try {

          //Deprecated
          var extensionCommand = httpChannel.
                                 getResponseHeader("privlyExtensionCommand");

          // We are going to remove this functionality in favor of a different
          // strategy for solving this issue:
          // https://github.com/smcgregor/privly-firefox/issues/18
          if ( false ) {
          //if (/priv.ly/.test(httpChannel.originalURI.host) ||
          //   (/localhost/.test(httpChannel.originalURI.host) &&
          //      /posts/.test(httpChannel.originalURI.path))) {
            /*
             * the extensioncommand response header will be a json string.
             * passive and requireClickthrough are mutually exclusive.
             * eg - extensionCommand =
             * '{"disablePosts" : 200, "requireClickthrough":110}';
             * '{"disablePosts":110,"passive": 100}'
             */
            extensionCommand = '';
            var command = JSON.parse(extensionCommand);

            /*
             * if requireClickthrough/passive field is present, change the extension
             * mode to privlyConstants.extensionModeEnum.CLICKTHROUGH/PASSIVE
             * accordingly. Set it back to active after the time interval
             * specified in the json string.
             */
            if (command && command.requireClickthrough) {
              this.preferences.setIntPref("extensionMode",
                               privlyConstants.extensionModeEnum.CLICKTHROUGH);
              setTimeout(function() {
                  this.preferences.setIntPref("extensionMode",
                                     privlyConstants.extensionModeEnum.ACTIVE);
                },
                command.requireClickthrough);
            }
            else if (command && command.passive) {
              this.preferences.setIntPref("extensionMode",
                                    privlyConstants.extensionModeEnum.PASSIVE);
              setTimeout(function() {
                  this.preferences.setIntPref("extensionMode",
                                     privlyConstants.extensionModeEnum.ACTIVE);
                },
                command.passive);
            }
            // disable the ability to post content to the server, if the
            // disablePosts field is present in the header.
            if (command && command.disablePosts) {
              this.preferences.setBoolPref('disablePosts', true);
              setTimeout(function() {
                  this.preferences.setBoolPref('disablePosts', false);
                },
                command.disablePosts);
            }
          }
        }
        catch (err) {}
      }
    },

    get observerService() {

      "use strict";

      return Components.classes["@mozilla.org/observer-service;1"]
                       .getService(Components.interfaces.nsIObserverService);
    },

    /**
     * Add the response observer
     */
    register: function() {

      "use strict";

      this.observerService.addObserver(this, "http-on-examine-response", false);
    },

    /**
     * Remove the response observer
     */
    unregister: function() {

      "use strict";

      this.observerService.removeObserver(this, "http-on-examine-response");
    }
  }
};

<commit_msg>JS modules: bugs<commit_after>/**
 * @namespace
 * Module for modifying http requests
 */

/**
 * import Privly constants
 */
Components.utils.import("resource://privly/constants.jsm");

/**
 * see https://developer.mozilla.org/en/using_xmlhttprequest#Using_XMLHttpRequest_from_JavaScript_modules_.2F_XPCOM.C2.A0components
 * xmlhttprequest in javascript modules
 */
const { XMLHttpRequest } = Components.classes["@mozilla.org/appshell/appShellService;1"]
                                     .getService(Components.interfaces.nsIAppShellService)
                                     .hiddenDOMWindow;

var EXPORTED_SYMBOLS = ["privlyObservers"];

var privlyObservers =  {

  /**
   * @namespace
   * Sets headers on requests to Privly servers.
   */
  httpRequestObserver: {

    /**
     * Interface object to the extension preferences.
     */
    preferences: Components.classes["@mozilla.org/preferences-service;1"]
      .getService(Components.interfaces.nsIPrefService)
      .getBranch("extensions.privly."),

    /**
     * Add headers to Privly requests containing the extension version
     * and the authentication token.
     *
     * @param {http subject} subject the interface for accessing the http
     * channel.
     *
     * @param {string} topic The name of the object being examined.
     * "http-on-modify-request" is expected, otherwise nothing is done.
     *
     * @param {data} data The response data. This variable is currently unused.
     *
     */
    observe: function(subject, topic, data) {

      "use strict";

      if (topic === "http-on-modify-request") {
        var httpChannel = subject.QueryInterface(Components
                                                .interfaces.nsIHttpChannel);

        // Set the extension version
        httpChannel.setRequestHeader("X-Privly-Version", "0.1.8", false);
        /*
         * set the extension version and auth_token param on the request headers
         * the content server uses this authToken to identify a specific user.
         * TBD:
         * 1. version number is hardcoded. write a function to retrieve the
         * extension version number automatically
         * 2. use a regex to match the content server url to eliminate the
         * if-else
         */
        var extensionMode = this.preferences.getIntPref("extensionMode");
        var authToken = "";
        if (this.preferences.prefHasUserValue(privlyConstants.Strings.authToken)) {
          authToken = this.preferences.getCharPref(privlyConstants.Strings.authToken);
        }
        if (/priv.ly/.test(httpChannel.originalURI.host)) {
          httpChannel.setRequestHeader(privlyConstants.Strings.authToken,
                                        authToken, false);
        }
        else if (/localhost/.test(httpChannel.originalURI.host)) {
          httpChannel.setRequestHeader(privlyConstants.Strings.authToken,
                                        authToken, false);
        }
      }
    },

    get observerService() {

      "use strict";

      return Components.classes["@mozilla.org/observer-service;1"]
                      .getService(Components.interfaces.nsIObserverService);
    },

    /**
     * Add the request observer to the overlay
     */
    register: function() {

      "use strict";

      this.observerService.addObserver(this, "http-on-modify-request", false);
    },

    /**
     * Remove this request observer from the overlay
     */
    unregister: function() {

      "use strict";

      this.observerService.removeObserver(this, "http-on-modify-request");
    }
  },

  /**
   * @namespace
   * The response observer checks whether localhost or priv.ly
   * set operation flags. These are usually set in instances
   * of high content server load. The extension will notify
   * the user of the issue, and switch into passive mode.
   *
   * The content server can set the extension to any one of the three modes.
   * it can do so by setting a header in the response header called
   * 'privlyExtensionCommand'.
   * in responseObserver, we read this header value and set the extension mode
   * accordingly
   */
  httpResponseObserver: {

    /**
     * Interface object to the extension preferences.
     */
    preferences: Components.classes["@mozilla.org/preferences-service;1"]
                            .getService(Components.interfaces.nsIPrefService)
                            .getBranch("extensions.privly."),

    /**
     * Respond to mode changes from the server.
     *
     * @param {http subject} subject the interface for accessing the http
     * channel.
     *
     * @param {string} topic The name of the object being examined.
     * "http-on-examine-response" is expected, otherwise nothing is done.
     *
     * @param {data} data The response data. This variable is currently unused.
     *
     */
    observe: function(subject, topic, data) {

      "use strict";

      if (topic === "http-on-examine-response") {
        var httpChannel = subject.QueryInterface(Components
                                                .interfaces.nsIHttpChannel);
        /*
         * read the extensionCommand header from the response.
         * if the response header is not set or the server
         * didn't reply, it will throw an error. so catch it
         */
        try {

          //Deprecated
          var extensionCommand = httpChannel.
                                 getResponseHeader("privlyExtensionCommand");

          // We are going to remove this functionality in favor of a different
          // strategy for solving this issue:
          // https://github.com/smcgregor/privly-firefox/issues/18
          if ( false ) {
          //if (/priv.ly/.test(httpChannel.originalURI.host) ||
          //   (/localhost/.test(httpChannel.originalURI.host) &&
          //      /posts/.test(httpChannel.originalURI.path))) {
            /*
             * the extensioncommand response header will be a json string.
             * passive and requireClickthrough are mutually exclusive.
             * eg - extensionCommand =
             * '{"disablePosts" : 200, "requireClickthrough":110}';
             * '{"disablePosts":110,"passive": 100}'
             */
            extensionCommand = '';
            var command = JSON.parse(extensionCommand);

            /*
             * if requireClickthrough/passive field is present, change the extension
             * mode to privlyConstants.extensionModeEnum.CLICKTHROUGH/PASSIVE
             * accordingly. Set it back to active after the time interval
             * specified in the json string.
             */
            if (command && command.requireClickthrough) {
              this.preferences.setIntPref("extensionMode",
                               privlyConstants.extensionModeEnum.CLICKTHROUGH);
              setTimeout(function() {
                  this.preferences.setIntPref("extensionMode",
                                     privlyConstants.extensionModeEnum.ACTIVE);
                },
                command.requireClickthrough);
            }
            else if (command && command.passive) {
              this.preferences.setIntPref("extensionMode",
                                    privlyConstants.extensionModeEnum.PASSIVE);
              setTimeout(function() {
                  this.preferences.setIntPref("extensionMode",
                                     privlyConstants.extensionModeEnum.ACTIVE);
                },
                command.passive);
            }
            // disable the ability to post content to the server, if the
            // disablePosts field is present in the header.
            if (command && command.disablePosts) {
              this.preferences.setBoolPref('disablePosts', true);
              setTimeout(function() {
                  this.preferences.setBoolPref('disablePosts', false);
                },
                command.disablePosts);
            }
          }
        }
        catch (err) {}
      }
    },

    get observerService() {

      "use strict";

      return Components.classes["@mozilla.org/observer-service;1"]
                       .getService(Components.interfaces.nsIObserverService);
    },

    /**
     * Add the response observer
     */
    register: function() {

      "use strict";

      this.observerService.addObserver(this, "http-on-examine-response", false);
    },

    /**
     * Remove the response observer
     */
    unregister: function() {

      "use strict";

      this.observerService.removeObserver(this, "http-on-examine-response");
    }
  }
};

<|endoftext|>