mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
352 lines
9.9 KiB
JavaScript
352 lines
9.9 KiB
JavaScript
IonicModule
|
|
|
|
.controller('$ionicHeaderBar', [
|
|
'$scope',
|
|
'$element',
|
|
'$attrs',
|
|
'$q',
|
|
'$ionicConfig',
|
|
'$ionicHistory',
|
|
function($scope, $element, $attrs, $q, $ionicConfig, $ionicHistory) {
|
|
var TITLE = 'title';
|
|
var BACK_TEXT = 'back-text';
|
|
var BACK_BUTTON = 'back-button';
|
|
var DEFAULT_TITLE = 'default-title';
|
|
var PREVIOUS_TITLE = 'previous-title';
|
|
var HIDE = 'hide';
|
|
|
|
var self = this;
|
|
var titleText = '';
|
|
var previousTitleText = '';
|
|
var titleLeft = 0;
|
|
var titleRight = 0;
|
|
var titleCss = '';
|
|
var isBackEnabled = false;
|
|
var isBackShown = true;
|
|
var isNavBackShown = true;
|
|
var isBackElementShown = false;
|
|
var titleTextWidth = 0;
|
|
|
|
|
|
self.beforeEnter = function(viewData) {
|
|
$scope.$broadcast('$ionicView.beforeEnter', viewData);
|
|
};
|
|
|
|
|
|
self.title = function(newTitleText) {
|
|
if (arguments.length && newTitleText !== titleText) {
|
|
getEle(TITLE).innerHTML = newTitleText;
|
|
titleText = newTitleText;
|
|
titleTextWidth = 0;
|
|
}
|
|
return titleText;
|
|
};
|
|
|
|
|
|
self.enableBack = function(shouldEnable, disableReset) {
|
|
// whether or not the back button show be visible, according
|
|
// to the navigation and history
|
|
if (arguments.length) {
|
|
isBackEnabled = shouldEnable;
|
|
if (!disableReset) self.updateBackButton();
|
|
}
|
|
return isBackEnabled;
|
|
};
|
|
|
|
|
|
self.showBack = function(shouldShow, disableReset) {
|
|
// different from enableBack() because this will always have the back
|
|
// visually hidden if false, even if the history says it should show
|
|
if (arguments.length) {
|
|
isBackShown = shouldShow;
|
|
if (!disableReset) self.updateBackButton();
|
|
}
|
|
return isBackShown;
|
|
};
|
|
|
|
|
|
self.showNavBack = function(shouldShow) {
|
|
// different from showBack() because this is for the entire nav bar's
|
|
// setting for all of it's child headers. For internal use.
|
|
isNavBackShown = shouldShow;
|
|
self.updateBackButton();
|
|
};
|
|
|
|
|
|
self.updateBackButton = function() {
|
|
if ((isBackShown && isNavBackShown && isBackEnabled) !== isBackElementShown) {
|
|
isBackElementShown = isBackShown && isNavBackShown && isBackEnabled;
|
|
var backBtnEle = getEle(BACK_BUTTON);
|
|
backBtnEle && backBtnEle.classList[ isBackElementShown ? 'remove' : 'add' ](HIDE);
|
|
}
|
|
};
|
|
|
|
|
|
self.titleTextWidth = function() {
|
|
if (!titleTextWidth) {
|
|
var bounds = ionic.DomUtil.getTextBounds(getEle(TITLE));
|
|
titleTextWidth = Math.min(bounds && bounds.width || 30);
|
|
}
|
|
return titleTextWidth;
|
|
};
|
|
|
|
|
|
self.titleWidth = function() {
|
|
var titleWidth = self.titleTextWidth();
|
|
var offsetWidth = getEle(TITLE).offsetWidth;
|
|
if (offsetWidth < titleWidth) {
|
|
titleWidth = offsetWidth + (titleLeft - titleRight - 5);
|
|
}
|
|
return titleWidth;
|
|
};
|
|
|
|
|
|
self.titleTextX = function() {
|
|
return ($element[0].offsetWidth / 2) - (self.titleWidth() / 2);
|
|
};
|
|
|
|
|
|
self.titleLeftRight = function() {
|
|
return titleLeft - titleRight;
|
|
};
|
|
|
|
|
|
self.backButtonTextLeft = function() {
|
|
var offsetLeft = 0;
|
|
var ele = getEle(BACK_TEXT);
|
|
while (ele) {
|
|
offsetLeft += ele.offsetLeft;
|
|
ele = ele.parentElement;
|
|
}
|
|
return offsetLeft;
|
|
};
|
|
|
|
|
|
self.resetBackButton = function() {
|
|
if ($ionicConfig.backButton.previousTitleText()) {
|
|
var previousTitleEle = getEle(PREVIOUS_TITLE);
|
|
if (previousTitleEle) {
|
|
previousTitleEle.classList.remove(HIDE);
|
|
|
|
var newPreviousTitleText = $ionicHistory.backTitle();
|
|
|
|
if (newPreviousTitleText !== previousTitleText) {
|
|
previousTitleText = previousTitleEle.innerHTML = newPreviousTitleText;
|
|
}
|
|
}
|
|
var defaultTitleEle = getEle(DEFAULT_TITLE);
|
|
if (defaultTitleEle) {
|
|
defaultTitleEle.classList.remove(HIDE);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
self.align = function(textAlign) {
|
|
var titleEle = getEle(TITLE);
|
|
|
|
textAlign = textAlign || $attrs.alignTitle || $ionicConfig.navBar.alignTitle();
|
|
|
|
var widths = self.calcWidths(textAlign, false);
|
|
|
|
if (isBackShown && previousTitleText && $ionicConfig.backButton.previousTitleText()) {
|
|
var previousTitleWidths = self.calcWidths(textAlign, true);
|
|
|
|
var availableTitleWidth = $element[0].offsetWidth - previousTitleWidths.titleLeft - previousTitleWidths.titleRight;
|
|
|
|
if (self.titleTextWidth() <= availableTitleWidth) {
|
|
widths = previousTitleWidths;
|
|
}
|
|
}
|
|
|
|
return self.updatePositions(titleEle, widths.titleLeft, widths.titleRight, widths.buttonsLeft, widths.buttonsRight, widths.css, widths.showPrevTitle);
|
|
};
|
|
|
|
|
|
self.calcWidths = function(textAlign, isPreviousTitle) {
|
|
var titleEle = getEle(TITLE);
|
|
var backBtnEle = getEle(BACK_BUTTON);
|
|
var x, y, z, b, c, d, childSize, bounds;
|
|
var childNodes = $element[0].childNodes;
|
|
var buttonsLeft = 0;
|
|
var buttonsRight = 0;
|
|
var isCountRightOfTitle;
|
|
var updateTitleLeft = 0;
|
|
var updateTitleRight = 0;
|
|
var updateCss = '';
|
|
var backButtonWidth = 0;
|
|
|
|
// Compute how wide the left children are
|
|
// Skip all titles (there may still be two titles, one leaving the dom)
|
|
// Once we encounter a titleEle, realize we are now counting the right-buttons, not left
|
|
for (x = 0; x < childNodes.length; x++) {
|
|
c = childNodes[x];
|
|
|
|
childSize = 0;
|
|
if (c.nodeType == 1) {
|
|
// element node
|
|
if (c === titleEle) {
|
|
isCountRightOfTitle = true;
|
|
continue;
|
|
}
|
|
|
|
if (c.classList.contains(HIDE)) {
|
|
continue;
|
|
}
|
|
|
|
if (isBackShown && c === backBtnEle) {
|
|
|
|
for (y = 0; y < c.childNodes.length; y++) {
|
|
b = c.childNodes[y];
|
|
|
|
if (b.nodeType == 1) {
|
|
|
|
if (b.classList.contains(BACK_TEXT)) {
|
|
for (z = 0; z < b.children.length; z++) {
|
|
d = b.children[z];
|
|
|
|
if (isPreviousTitle) {
|
|
if (d.classList.contains(DEFAULT_TITLE)) continue;
|
|
backButtonWidth += d.offsetWidth;
|
|
} else {
|
|
if (d.classList.contains(PREVIOUS_TITLE)) continue;
|
|
backButtonWidth += d.offsetWidth;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
backButtonWidth += b.offsetWidth;
|
|
}
|
|
|
|
} else if (b.nodeType == 3 && b.nodeValue.trim()) {
|
|
bounds = ionic.DomUtil.getTextBounds(b);
|
|
backButtonWidth += bounds && bounds.width || 0;
|
|
}
|
|
|
|
}
|
|
childSize = backButtonWidth || c.offsetWidth;
|
|
|
|
} else {
|
|
// not the title, not the back button, not a hidden element
|
|
childSize = c.offsetWidth;
|
|
}
|
|
|
|
} else if (c.nodeType == 3 && c.nodeValue.trim()) {
|
|
// text node
|
|
bounds = ionic.DomUtil.getTextBounds(c);
|
|
childSize = bounds && bounds.width || 0;
|
|
}
|
|
|
|
if (isCountRightOfTitle) {
|
|
buttonsRight += childSize;
|
|
} else {
|
|
buttonsLeft += childSize;
|
|
}
|
|
}
|
|
|
|
// Size and align the header titleEle based on the sizes of the left and
|
|
// right children, and the desired alignment mode
|
|
if (textAlign == 'left') {
|
|
updateCss = 'title-left';
|
|
if (buttonsLeft) {
|
|
updateTitleLeft = buttonsLeft + 15;
|
|
}
|
|
if (buttonsRight) {
|
|
updateTitleRight = buttonsRight + 15;
|
|
}
|
|
|
|
} else if (textAlign == 'right') {
|
|
updateCss = 'title-right';
|
|
if (buttonsLeft) {
|
|
updateTitleLeft = buttonsLeft + 15;
|
|
}
|
|
if (buttonsRight) {
|
|
updateTitleRight = buttonsRight + 15;
|
|
}
|
|
|
|
} else {
|
|
// center the default
|
|
var margin = Math.max(buttonsLeft, buttonsRight) + 10;
|
|
if (margin > 10) {
|
|
updateTitleLeft = updateTitleRight = margin;
|
|
}
|
|
}
|
|
|
|
return {
|
|
backButtonWidth: backButtonWidth,
|
|
buttonsLeft: buttonsLeft,
|
|
buttonsRight: buttonsRight,
|
|
titleLeft: updateTitleLeft,
|
|
titleRight: updateTitleRight,
|
|
showPrevTitle: isPreviousTitle,
|
|
css: updateCss
|
|
};
|
|
};
|
|
|
|
|
|
self.updatePositions = function(titleEle, updateTitleLeft, updateTitleRight, buttonsLeft, buttonsRight, updateCss, showPreviousTitle) {
|
|
var deferred = $q.defer();
|
|
|
|
// only make DOM updates when there are actual changes
|
|
if (titleEle) {
|
|
if (updateTitleLeft !== titleLeft) {
|
|
titleEle.style.left = updateTitleLeft ? updateTitleLeft + 'px' : '';
|
|
titleLeft = updateTitleLeft;
|
|
}
|
|
if (updateTitleRight !== titleRight) {
|
|
titleEle.style.right = updateTitleRight ? updateTitleRight + 'px' : '';
|
|
titleRight = updateTitleRight;
|
|
}
|
|
|
|
if (updateCss !== titleCss) {
|
|
updateCss && titleEle.classList.add(updateCss);
|
|
titleCss && titleEle.classList.remove(titleCss);
|
|
titleCss = updateCss;
|
|
}
|
|
}
|
|
|
|
if ($ionicConfig.backButton.previousTitleText()) {
|
|
var prevTitle = getEle(PREVIOUS_TITLE);
|
|
var defaultTitle = getEle(DEFAULT_TITLE);
|
|
|
|
prevTitle && prevTitle.classList[ showPreviousTitle ? 'remove' : 'add'](HIDE);
|
|
defaultTitle && defaultTitle.classList[ showPreviousTitle ? 'add' : 'remove'](HIDE);
|
|
}
|
|
|
|
ionic.requestAnimationFrame(function() {
|
|
if (titleEle && titleEle.offsetWidth + 10 < titleEle.scrollWidth) {
|
|
var minRight = buttonsRight + 5;
|
|
var testRight = $element[0].offsetWidth - titleLeft - self.titleTextWidth() - 20;
|
|
updateTitleRight = testRight < minRight ? minRight : testRight;
|
|
if (updateTitleRight !== titleRight) {
|
|
titleEle.style.right = updateTitleRight + 'px';
|
|
titleRight = updateTitleRight;
|
|
}
|
|
}
|
|
deferred.resolve();
|
|
});
|
|
|
|
return deferred.promise;
|
|
};
|
|
|
|
|
|
self.setCss = function(elementClassname, css) {
|
|
ionic.DomUtil.cachedStyles(getEle(elementClassname), css);
|
|
};
|
|
|
|
|
|
var eleCache = {};
|
|
function getEle(className) {
|
|
if (!eleCache[className]) {
|
|
eleCache[className] = $element[0].querySelector('.' + className);
|
|
}
|
|
return eleCache[className];
|
|
}
|
|
|
|
|
|
$scope.$on('$destroy', function() {
|
|
for (var n in eleCache) eleCache[n] = null;
|
|
});
|
|
|
|
}]);
|