This repository has been archived on 2020-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
quay/static/js/services/ui-service.js
2019-11-12 11:09:47 -05:00

370 lines
9.9 KiB
JavaScript

/**
* Service which provides helper methods for performing some simple UI operations.
*/
angular.module('quay').factory('UIService', ['$timeout', '$rootScope', '$location', 'ApiService', function($timeout, $rootScope, $location, ApiService) {
var CheckStateController = function(items, itemKey) {
this.items = items;
this.checked = [];
this.allItems_ = items;
this.allCheckedMap_ = {};
this.itemKey_ = itemKey;
this.listeners_ = [];
this.page_ = null;
this.lastChanged_ = null;
this.ApiService = ApiService
};
CheckStateController.prototype.listen = function(callback) {
this.listeners_.push(callback);
};
CheckStateController.prototype.isChecked = function(item) {
return !!this.allCheckedMap_[item[this.itemKey_]];
};
CheckStateController.prototype.toggleItem = function(item, opt_shift) {
if (opt_shift && this.lastChanged_) {
var itemIndex = $.inArray(item, this.items);
var lastIndex = $.inArray(this.lastChanged_, this.items);
if (itemIndex >= 0 && lastIndex >= 0) {
var startIndex = Math.min(itemIndex, lastIndex);
var endIndex = Math.max(itemIndex, lastIndex);
var shouldCheck = this.isChecked(this.lastChanged_);
for (var i = startIndex; i <= endIndex; ++i) {
if (shouldCheck) {
this.checkItem(this.items[i]);
} else {
this.uncheckItem(this.items[i]);
}
}
return;
}
}
if (this.isChecked(item)) {
this.uncheckItem(item);
} else {
this.checkItem(item);
}
};
CheckStateController.prototype.toggleItems = function(opt_filter) {
this.lastChanged_= null;
this.updateMap_(this.checked, false);
if (this.checked.length) {
this.checked = [];
} else {
if (opt_filter) {
this.checked = this.items.filter((item) => (opt_filter.indexOf(item) >= 0));
} else {
this.checked = this.items.slice();
}
}
this.updateMap_(this.checked, true);
this.callListeners_();
};
CheckStateController.prototype.setPage = function(page, pageSize) {
this.items = this.allItems_.slice(page * pageSize, (page + 1) * pageSize);
this.rebuildCheckedList_();
};
CheckStateController.prototype.setChecked = function(items) {
this.allCheckedMap_ = {};
this.updateMap_(items, true);
this.rebuildCheckedList_();
};
CheckStateController.prototype.rebuildCheckedList_ = function() {
var that = this;
this.checked = [];
this.allItems_.forEach(function(item) {
if (that.allCheckedMap_[item[that.itemKey_]]) {
that.checked.push(item);
}
});
this.callListeners_();
};
CheckStateController.prototype.updateMap_ = function(items, is_checked) {
var that = this;
items.forEach(function(item) {
if (item == null) { return; }
that.allCheckedMap_[item[that.itemKey_]] = is_checked;
});
};
CheckStateController.prototype.checkByFilter = function(filter, opt_secondaryFilter) {
this.updateMap_(this.checked, false);
var filterFunc = filter;
if (opt_secondaryFilter) {
filterFunc = (item) => (opt_secondaryFilter.indexOf(item) >= 0 && filter(item));
}
this.checked = $.grep(this.items, filterFunc);
this.updateMap_(this.checked, true);
this.callListeners_();
};
CheckStateController.prototype.checkItem = function(item) {
if (this.isChecked(item)) {
return;
}
this.lastChanged_ = item;
this.checked.push(item);
this.allCheckedMap_[item[this.itemKey_]] = true;
this.callListeners_();
};
CheckStateController.prototype.uncheckItem = function(item) {
if (!this.isChecked(item)) {
return;
}
this.lastChanged_ = item;
this.checked = $.grep(this.checked, function(cItem) {
return cItem != item;
});
this.allCheckedMap_[item[this.itemKey_]] = false;
this.callListeners_();
};
CheckStateController.prototype.callListeners_ = function() {
var that = this;
var allCheckedMap = this.allCheckedMap_;
var allChecked = [];
this.allItems_.forEach(function(item) {
var key = item[that.itemKey_];
if (!!allCheckedMap[key]) {
allChecked.push(item);
}
});
this.listeners_.map(function(listener) {
listener(allChecked, that.checked);
});
};
//////////////////////////////////////////////////////////////////////////////////////
var uiService = {};
uiService.hidePopover = function(elem) {
var popover = $(elem).data('bs.popover');
if (popover) {
popover.hide();
}
};
uiService.showPopover = function(elem, content, opt_placement) {
var popover = $(elem).data('bs.popover');
if (!popover) {
$(elem).popover({'content': '-', 'placement': opt_placement || 'left'});
}
setTimeout(function() {
var popover = $(elem).data('bs.popover');
popover.options.content = content;
popover.show();
}, 500);
};
uiService.showFormError = function(elem, result, opt_placement) {
var message = ApiService.getErrorMessage(result, 'error');
if (message) {
uiService.showPopover(elem, message, opt_placement || 'bottom');
} else {
uiService.hidePopover(elem);
}
};
uiService.createCheckStateController = function(items, opt_checked) {
return new CheckStateController(items, opt_checked);
};
uiService.showPasswordDialog = function(message, callback, opt_canceledCallback) {
var success = function() {
var password = $('#passDialogBox').val();
$('#passDialogBox').val('');
callback(password);
};
var canceled = function() {
$('#passDialogBox').val('');
opt_canceledCallback && opt_canceledCallback();
};
var box = bootbox.dialog({
"message": message +
'<form style="margin-top: 10px" action="javascript:$(\'.btn-continue\').click();void(0)">' +
'<input id="passDialogBox" class="form-control" type="password" placeholder="Current Password">' +
'</form>',
"title": 'Please Verify',
"buttons": {
"verify": {
"label": "Verify",
"className": "btn-success btn-continue",
"callback": success
},
"close": {
"label": "Cancel",
"className": "btn-default",
"callback": canceled
}
}
});
box.bind('shown.bs.modal', function(){
box.find("input").focus();
box.find("form").submit(function() {
if (!$('#passDialogBox').val()) { return; }
box.modal('hide');
success();
});
});
};
uiService.clickElement = function(el) {
// From: http://stackoverflow.com/questions/16802795/click-not-working-in-mocha-phantomjs-on-certain-elements
var ev = document.createEvent("MouseEvent");
ev.initMouseEvent(
"click",
true /* bubble */, true /* cancelable */,
window, null,
0, 0, 0, 0, /* coordinates */
false, false, false, false, /* modifier keys */
0 /*left*/, null);
el.dispatchEvent(ev);
};
uiService.initializeTabs = function(scope, element, opt_clickCallback, opt_rememberCookie) {
var locationListener = null;
var disposed = false;
var changeTab = function(activeTab) {
if (disposed) { return; }
$('a[data-toggle="tab"]').each(function(index) {
var tabName = this.getAttribute('data-target').substr(1);
if (tabName != activeTab) {
return;
}
if ($(this).parent().hasClass('active')) {
return;
}
if (this.clientWidth == 0) {
setTimeout(function() {
changeTab(activeTab);
}, 100);
return;
}
var elem = this;
setTimeout(function() {
uiService.clickElement(elem);
}, 0);
});
};
var resetDefaultTab = function() {
if (disposed) { return; }
$timeout(function() {
element.find('a[data-toggle="tab"]').each(function(index) {
if (index == 0) {
var elem = this;
setTimeout(function() {
uiService.clickElement(elem);
}, 0);
}
});
});
};
var checkTabs = function() {
if (disposed) { return; }
// Poll until we find the tabs.
var tabs = element.find('a[data-toggle="tab"]');
if (tabs.length == 0) {
$timeout(checkTabs, 50);
return;
}
// Register listeners.
registerListeners(tabs);
// Set the active tab (if any).
var activeTab = $location.search()['tab'];
if (activeTab) {
changeTab(activeTab);
}
};
var registerListeners = function(tabs) {
// Listen for scope destruction.
scope.$on('$destroy', function() {
disposed = true;
locationListener && locationListener();
});
// Listen for route changes and update the tabs accordingly.
if (!opt_rememberCookie) {
locationListener = $rootScope.$on('$routeUpdate', function(){
if ($location.search()['tab']) {
changeTab($location.search()['tab']);
} else {
resetDefaultTab();
}
});
}
// Listen for tab changes.
tabs.on('shown.bs.tab', function (e) {
// Invoke the callback, if any.
opt_clickCallback && opt_clickCallback();
// Update the search location or cookie.
if (opt_rememberCookie) {
// TODO: this
} else {
var tabName = e.target.getAttribute('data-target').substr(1);
$rootScope.$apply(function() {
var isDefaultTab = tabs[0] == e.target;
var newSearch = $.extend($location.search(), {});
if (isDefaultTab) {
delete newSearch['tab'];
} else {
newSearch['tab'] = tabName;
}
$location.search(newSearch);
});
}
e.preventDefault();
});
};
// Start the checkTabs timer.
checkTabs();
};
return uiService;
}]);