"bootstrap": ">= 3.0.0",
"bootstrap-treeview": "https://github.com/skateman/bootstrap-treeview.git#master",
"components-font-awesome": "~4.7.0",
- "bootstrap-validator": "~0.11.9"
+ "bootstrap-validator": "~0.11.9",
+ "bootstrap-contextmenu": "https://github.com/sydcanem/bootstrap-contextmenu.git#master"
}
}
var bootstrap = gulp.src('bower_components/bootstrap/dist/**/*').pipe(gulp.dest('public/src/lib/bootstrap'));
var bootstrapTreeview = gulp.src('bower_components/bootstrap-treeview/dist/**/*').pipe(gulp.dest('public/src/lib/bootstrap-treeview'));
var bootstrapValidator = gulp.src('bower_components/bootstrap-validator/dist/**/*').pipe(gulp.dest('public/src/lib/bootstrap-validator'));
+ var bootstrapContextMenu = gulp.src('bower_components/bootstrap-contextmenu/bootstrap-contextmenu.js').pipe(gulp.dest('public/src/lib/bootstrap-contextmenu'));
var componentsFontAwesomeCss = gulp.src('bower_components/components-font-awesome/css/**/*').pipe(gulp.dest('public/src/lib/components-font-awesome/css'));
var componentsFontAwesomeFont = gulp.src('bower_components/components-font-awesome/fonts/**/*').pipe(gulp.dest('public/src/lib/components-font-awesome/fonts'));
- return merge(requirejs, jsnlog, lodash, jquery, jquerySortable, bootstrap, bootstrapTreeview, bootstrapValidator, componentsFontAwesomeCss, componentsFontAwesomeFont);
+ return merge(requirejs, jsnlog, lodash, jquery, jquerySortable, bootstrap, bootstrapTreeview, bootstrapValidator, bootstrapContextMenu, componentsFontAwesomeCss, componentsFontAwesomeFont);
});
// watch
<i class="fa fa-navicon"></i>
</button>
<ul class="dropdown-menu dropdown-menu-right">
- <li><a id="tic-package-toolbar-checkall">Check All</a></li>
- <li><a id="tic-package-toolbar-uncheckall">Uncheck All</a></li>
+ <li><a id="tic-package-toolbar-all">All</a></li>
+ <li><a id="tic-package-toolbar-debug">Debug</a></li>
+ <li><a id="tic-package-toolbar-devel">Devel</a></li>
</ul>
<button type="button" class="btn btn-default" id="tic-package-left-col-tree-toolbar-collapse-all">
<i class="fa fa-minus"></i>
<a type="button" id="log-view-content-download" class="fa fa-download log-view-content-download"> Download</a>
</div>
<div id="log-view-content-body" class="log-view-content-body"></div>
- </div>
- <!-- /End Log View -->
+ </div><!-- /End Log View -->
+
+ <!-- Context menu in package tree -->
+ <div id="tic-package-context-menu">
+ <ul class="dropdown-menu" role="menu">
+ <li><a id="tic-package-context-menu-uncheck-all" tabindex="-1">Uncheck All</a></li>
+ <!--
+ <li class="divider"></li>
+ -->
+ </ul>
+ </div><!-- /Context menu in package tree -->
<!-- library loading -->
<script src="/socket.io/socket.io.js"></script>
'bootstrap': 'lib/bootstrap/js/bootstrap',
'bootstrap-treeview': 'lib/bootstrap-treeview/bootstrap-treeview.min',
'bootstrap-validator': 'lib/bootstrap-validator/validator',
+ 'bootstrap-contextmenu': 'lib/bootstrap-contextmenu/bootstrap-contextmenu',
'jsnlog': 'lib/jsnlog/jsnlog'
},
shim: {
define([
'jquery',
'lodash',
+ 'bootstrap-contextmenu',
'js/util',
'js/page/settings',
'js/logger',
], function (
$,
_,
+ bootstrapContextmenu,
Util,
Settings,
Logger,
// button - image creation
$('#tic-package-create').on('click', onClickHandlerForImgCreationBtn);
- function _filter() {
- var filterText = $('#tic-package-toolbar-input').val();
- var matchNodes = $tree.treeview('search', [ filterText, {
+ function _filter(text) {
+ var matchNodes = $tree.treeview('search', [ text, {
ignoreCase: true, // case insensitive
exactMatch: false, // like or equals
revealResults: true, // reveal matching nodes
node.$el.show();
});
} else {
- if (_.isEmpty(filterText)) {
+ if (_.isEmpty(text)) {
_.forEach(packages, function (node) {
node.$el.show();
});
}
}
+ }
+
+ function _filterInput() {
+ var filterText = $('#tic-package-toolbar-input').val();
+ _filter(filterText);
$('#tic-package-toolbar-input-clear').toggleClass('hidden', _.isEmpty(filterText));
}
- $('#tic-package-toolbar-input').on('input change', _filter);
+ $('#tic-package-toolbar-input').on('keyup', _.debounce(_filterInput, 500));
+
+ function _filterAll() {
+ _filter('');
+ }
+ $('#tic-package-toolbar-all').on('click', _filterAll);
+ function _filterDebug() {
+ _filter('debug');
+ }
+ $('#tic-package-toolbar-debug').on('click', _filterDebug);
+ function _filterDevel() {
+ _filter('devel');
+ }
+ $('#tic-package-toolbar-devel').on('click', _filterDevel);
function _inputClearBtnHandler() {
- $('#tic-package-toolbar-input').val('').trigger('change').focus();
+ $('#tic-package-toolbar-input').val('').focus();
+ _filter('');
$(this).toggleClass('hidden', true);
}
$('#tic-package-toolbar-input-clear').on('click', _inputClearBtnHandler);
- function _checkAllBtnHandler() {
- var startTS = performance.now();
- var depPkg = {};
- _.forEach(pkgInfo, function(value, key) {
- if (!value.checked) {
- var dependents = _analyzeInstallDependency(value);
- if (dependents.result === true) {
- _.forEach(dependents.data, function(pkg, pkgName) {
- pkg.checked = true;
- depPkg[pkgName] = pkg;
- });
- }
- }
- });
- var analyzeTS = performance.now();
- var toggleNode = [];
- if (!_.isEmpty(depPkg)) {
- _.forEach(depPkg, function(value, key) {
- // update treeview data
+ function _contextMenuHandler() {
+ function _uncheckAllBtnHandler() {
+ // INFO: bug for state.checked = false in treeview objects
+ $tree.treeview('checkAll', { silent: true });
+ $tree.treeview('uncheckAll', { silent: true });
+ _.forEach(pkgInfo, function(value, key) {
+ value.checked = false;
+ value.selfChecked = false;
+ value.forward = null;
+ value.backward = null;
+ value.group = null;
+
+ // INFO: bug for state.checked = false in treeview objects
_.forEach(value.view, function(node) {
- if (node.state.checked === false) {
- toggleNode.push(node);
- }
+ node.state.checked = false;
});
});
-
- $tree.treeview('checkNode', [toggleNode, { silent: true }]);
+ groups = {};
+ conflicts = {};
_updateSummary();
}
- var endTS = performance.now();
- logger.info('[All-Check] Total time: ' + (endTS - startTS) + 'ms');
- logger.info('[All-Check] Analyze dep. time: ' + (analyzeTS - startTS) + 'ms');
- logger.info('[All-Check] Update view time: ' + (endTS - analyzeTS) + 'ms');
- }
- $('#tic-package-toolbar-checkall').on('click', _checkAllBtnHandler);
-
- function _uncheckAllBtnHandler() {
- // FIXME: bug for state.checked = false in treeview objects
- $tree.treeview('checkAll', { silent: true });
- $tree.treeview('uncheckAll', { silent: true });
- _.forEach(pkgInfo, function(value, key) {
- value.checked = false;
- value.selfChecked = false;
- value.forward = null;
- value.backward = null;
- value.group = null;
- // FIXME: bug for state.checked = false in treeview objects
- _.forEach(value.view, function(node) {
- node.state.checked = false;
- });
+ $tree.contextmenu({
+ target: '#tic-package-context-menu',
+ onItem: function (row, e) {
+ if (e.target.id === 'tic-package-context-menu-uncheck-all') {
+ _uncheckAllBtnHandler();
+ }
+ }
});
- groups = {};
- conflicts = {};
- _updateSummary();
}
- $('#tic-package-toolbar-uncheckall').on('click', _uncheckAllBtnHandler);
+ _contextMenuHandler();
function _collapseAll() {
$tree.treeview('collapseAll');
--- /dev/null
+/*!
+ * Bootstrap Context Menu
+ * Author: @sydcanem
+ * https://github.com/sydcanem/bootstrap-contextmenu
+ *
+ * Inspired by Bootstrap's dropdown plugin.
+ * Bootstrap (http://getbootstrap.com).
+ *
+ * Licensed under MIT
+ * ========================================================= */
+
+;(function($) {
+
+ 'use strict';
+
+ /* CONTEXTMENU CLASS DEFINITION
+ * ============================ */
+ var toggle = '[data-toggle="context"]';
+
+ var ContextMenu = function (element, options) {
+ this.$element = $(element);
+
+ this.before = options.before || this.before;
+ this.onItem = options.onItem || this.onItem;
+ this.scopes = options.scopes || null;
+
+ if (options.target) {
+ this.$element.data('target', options.target);
+ }
+
+ this.listen();
+ };
+
+ ContextMenu.prototype = {
+
+ constructor: ContextMenu
+ ,show: function(e) {
+
+ var $menu
+ , evt
+ , tp
+ , items
+ , relatedTarget = { relatedTarget: this, target: e.currentTarget };
+
+ if (this.isDisabled()) return;
+
+ this.closemenu();
+
+ if (this.before.call(this,e,$(e.currentTarget)) === false) return;
+
+ $menu = this.getMenu();
+ $menu.trigger(evt = $.Event('show.bs.context', relatedTarget));
+
+ tp = this.getPosition(e, $menu);
+ items = 'li:not(.divider)';
+ $menu.attr('style', '')
+ .css(tp)
+ .addClass('open')
+ .on('click.context.data-api', items, $.proxy(this.onItem, this, $(e.currentTarget)))
+ .trigger('shown.bs.context', relatedTarget);
+
+ // Delegating the `closemenu` only on the currently opened menu.
+ // This prevents other opened menus from closing.
+ $('html')
+ .on('click.context.data-api', $menu.selector, $.proxy(this.closemenu, this));
+
+ return false;
+ }
+
+ ,closemenu: function(e) {
+ var $menu
+ , evt
+ , items
+ , relatedTarget;
+
+ $menu = this.getMenu();
+
+ if(!$menu.hasClass('open')) return;
+
+ relatedTarget = { relatedTarget: this };
+ $menu.trigger(evt = $.Event('hide.bs.context', relatedTarget));
+
+ items = 'li:not(.divider)';
+ $menu.removeClass('open')
+ .off('click.context.data-api', items)
+ .trigger('hidden.bs.context', relatedTarget);
+
+ $('html')
+ .off('click.context.data-api', $menu.selector);
+ // Don't propagate click event so other currently
+ // opened menus won't close.
+ if (e) {
+ e.stopPropagation();
+ }
+ }
+
+ ,keydown: function(e) {
+ if (e.which == 27) this.closemenu(e);
+ }
+
+ ,before: function(e) {
+ return true;
+ }
+
+ ,onItem: function(e) {
+ return true;
+ }
+
+ ,listen: function () {
+ this.$element.on('contextmenu.context.data-api', this.scopes, $.proxy(this.show, this));
+ $('html').on('click.context.data-api', $.proxy(this.closemenu, this));
+ $('html').on('keydown.context.data-api', $.proxy(this.keydown, this));
+ }
+
+ ,destroy: function() {
+ this.$element.off('.context.data-api').removeData('context');
+ $('html').off('.context.data-api');
+ }
+
+ ,isDisabled: function() {
+ return this.$element.hasClass('disabled') ||
+ this.$element.attr('disabled');
+ }
+
+ ,getMenu: function () {
+ var selector = this.$element.data('target')
+ , $menu;
+
+ if (!selector) {
+ selector = this.$element.attr('href');
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, ''); //strip for ie7
+ }
+
+ $menu = $(selector);
+
+ return $menu && $menu.length ? $menu : this.$element.find(selector);
+ }
+
+ ,getPosition: function(e, $menu) {
+ var mouseX = e.clientX
+ , mouseY = e.clientY
+ , boundsX = $(window).width()
+ , boundsY = $(window).height()
+ , menuWidth = $menu.find('.dropdown-menu').outerWidth()
+ , menuHeight = $menu.find('.dropdown-menu').outerHeight()
+ , tp = {"position":"absolute","z-index":9999}
+ , Y, X, parentOffset;
+
+ if (mouseY + menuHeight > boundsY) {
+ Y = {"top": mouseY - menuHeight + $(window).scrollTop()};
+ } else {
+ Y = {"top": mouseY + $(window).scrollTop()};
+ }
+
+ if ((mouseX + menuWidth > boundsX) && ((mouseX - menuWidth) > 0)) {
+ X = {"left": mouseX - menuWidth + $(window).scrollLeft()};
+ } else {
+ X = {"left": mouseX + $(window).scrollLeft()};
+ }
+
+ // If context-menu's parent is positioned using absolute or relative positioning,
+ // the calculated mouse position will be incorrect.
+ // Adjust the position of the menu by its offset parent position.
+ parentOffset = $menu.offsetParent().offset();
+ X.left = X.left - parentOffset.left;
+ Y.top = Y.top - parentOffset.top;
+
+ return $.extend(tp, Y, X);
+ }
+
+ };
+
+ /* CONTEXT MENU PLUGIN DEFINITION
+ * ========================== */
+
+ $.fn.contextmenu = function (option,e) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('context')
+ , options = (typeof option == 'object') && option;
+
+ if (!data) $this.data('context', (data = new ContextMenu($this, options)));
+ if (typeof option == 'string') data[option].call(data, e);
+ });
+ };
+
+ $.fn.contextmenu.Constructor = ContextMenu;
+
+ /* APPLY TO STANDARD CONTEXT MENU ELEMENTS
+ * =================================== */
+
+ $(document)
+ .on('contextmenu.context.data-api', function() {
+ $(toggle).each(function () {
+ var data = $(this).data('context');
+ if (!data) return;
+ data.closemenu();
+ });
+ })
+ .on('contextmenu.context.data-api', toggle, function(e) {
+ $(this).contextmenu('show', e);
+
+ e.preventDefault();
+ e.stopPropagation();
+ });
+
+}(jQuery));