devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
413 lines (389 loc) • 13.2 kB
JavaScript
/**
* DevExtreme (ui/themes.js)
* Version: 20.1.7
* Build date: Tue Aug 25 2020
*
* Copyright (c) 2012 - 2020 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
;
var _devices = require("../core/devices");
var _devices2 = _interopRequireDefault(_devices);
var _dom_adapter = require("../core/dom_adapter");
var _dom_adapter2 = _interopRequireDefault(_dom_adapter);
var _promise = require("../core/polyfills/promise");
var _promise2 = _interopRequireDefault(_promise);
var _renderer = require("../core/renderer");
var _renderer2 = _interopRequireDefault(_renderer);
var _deferred = require("../core/utils/deferred");
var _html_parser = require("../core/utils/html_parser");
var _iterator = require("../core/utils/iterator");
var _ready_callbacks = require("../core/utils/ready_callbacks");
var _ready_callbacks2 = _interopRequireDefault(_ready_callbacks);
var _view_port = require("../core/utils/view_port");
var _window = require("../core/utils/window");
var _themes_callback = require("./themes_callback");
var _ui = require("./widget/ui.errors");
var _ui2 = _interopRequireDefault(_ui);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
"default": obj
}
}
var window = (0, _window.getWindow)();
var ready = _ready_callbacks2.default.add;
var viewPort = _view_port.value;
var viewPortChanged = _view_port.changeCallback;
var DX_LINK_SELECTOR = "link[rel=dx-theme]";
var THEME_ATTR = "data-theme";
var ACTIVE_ATTR = "data-active";
var DX_HAIRLINES_CLASS = "dx-hairlines";
var ANY_THEME = "any";
var context;
var $activeThemeLink;
var knownThemes;
var currentThemeName;
var pendingThemeName;
var defaultTimeout = 15e3;
var THEME_MARKER_PREFIX = "dx.";
var inited = false;
_themes_callback.themeInitializedCallback.add(function() {
return inited = true
});
function readThemeMarker() {
if (!(0, _window.hasWindow)()) {
return null
}
var element = (0, _renderer2.default)("<div>", context).addClass("dx-theme-marker").appendTo(context.documentElement);
var result;
try {
result = element.css("fontFamily");
if (!result) {
return null
}
result = result.replace(/["']/g, "");
if (result.substr(0, THEME_MARKER_PREFIX.length) !== THEME_MARKER_PREFIX) {
return null
}
return result.substr(THEME_MARKER_PREFIX.length)
} finally {
element.remove()
}
}
function waitForThemeLoad(themeName) {
var waitStartTime;
var timerId;
var intervalCleared = true;
pendingThemeName = themeName;
function handleLoaded() {
pendingThemeName = null;
clearInterval(timerId);
intervalCleared = true;
_themes_callback.themeReadyCallback.fire();
_themes_callback.themeReadyCallback.empty();
if (!inited) {
_themes_callback.themeInitializedCallback.fire();
_themes_callback.themeInitializedCallback.empty()
}
}
if (isPendingThemeLoaded() || !defaultTimeout) {
handleLoaded()
} else {
if (!intervalCleared) {
if (pendingThemeName) {
pendingThemeName = themeName
}
return
}
waitStartTime = Date.now();
intervalCleared = false;
timerId = setInterval(function() {
var isLoaded = isPendingThemeLoaded();
var isTimeout = !isLoaded && Date.now() - waitStartTime > defaultTimeout;
if (isTimeout) {
_ui2.default.log("W0004", pendingThemeName)
}
if (isLoaded || isTimeout) {
handleLoaded()
}
}, 10)
}
}
function isPendingThemeLoaded() {
if (!pendingThemeName) {
return true
}
var anyThemePending = pendingThemeName === ANY_THEME;
if (inited && anyThemePending) {
return true
}
var themeMarker = readThemeMarker();
if (themeMarker && anyThemePending) {
return true
}
return themeMarker === pendingThemeName
}
function processMarkup() {
var $allThemeLinks = (0, _renderer2.default)(DX_LINK_SELECTOR, context);
if (!$allThemeLinks.length) {
return
}
knownThemes = {};
$activeThemeLink = (0, _renderer2.default)((0, _html_parser.parseHTML)("<link rel=stylesheet>"), context);
$allThemeLinks.each(function() {
var link = (0, _renderer2.default)(this, context);
var fullThemeName = link.attr(THEME_ATTR);
var url = link.attr("href");
var isActive = "true" === link.attr(ACTIVE_ATTR);
knownThemes[fullThemeName] = {
url: url,
isActive: isActive
}
});
$allThemeLinks.last().after($activeThemeLink);
$allThemeLinks.remove()
}
function resolveFullThemeName(desiredThemeName) {
var desiredThemeParts = desiredThemeName ? desiredThemeName.split(".") : [];
var result = null;
if (knownThemes) {
if (desiredThemeName in knownThemes) {
return desiredThemeName
}(0, _iterator.each)(knownThemes, function(knownThemeName, themeData) {
var knownThemeParts = knownThemeName.split(".");
if (desiredThemeParts[0] && knownThemeParts[0] !== desiredThemeParts[0]) {
return
}
if (desiredThemeParts[1] && desiredThemeParts[1] !== knownThemeParts[1]) {
return
}
if (desiredThemeParts[2] && desiredThemeParts[2] !== knownThemeParts[2]) {
return
}
if (!result || themeData.isActive) {
result = knownThemeName
}
if (themeData.isActive) {
return false
}
})
}
return result
}
function initContext(newContext) {
try {
if (newContext !== context) {
knownThemes = null
}
} catch (x) {
knownThemes = null
}
context = newContext
}
function init(options) {
options = options || {};
initContext(options.context || _dom_adapter2.default.getDocument());
if (!context) {
return
}
processMarkup();
currentThemeName = void 0;
current(options)
}
function current(options) {
if (!arguments.length) {
currentThemeName = currentThemeName || readThemeMarker();
return currentThemeName
}
detachCssClasses(viewPort());
options = options || {};
if ("string" === typeof options) {
options = {
theme: options
}
}
var isAutoInit = options._autoInit;
var loadCallback = options.loadCallback;
var currentThemeData;
currentThemeName = resolveFullThemeName(options.theme || currentThemeName);
if (currentThemeName) {
currentThemeData = knownThemes[currentThemeName]
}
if (loadCallback) {
_themes_callback.themeReadyCallback.add(loadCallback)
}
if (currentThemeData) {
$activeThemeLink.attr("href", knownThemes[currentThemeName].url);
if (_themes_callback.themeReadyCallback.has() || options._forceTimeout) {
waitForThemeLoad(currentThemeName)
}
} else {
if (isAutoInit) {
waitForThemeLoad(ANY_THEME);
_themes_callback.themeReadyCallback.fire();
_themes_callback.themeReadyCallback.empty()
} else {
throw _ui2.default.Error("E0021", currentThemeName)
}
}
checkThemeDeprecation();
attachCssClasses((0, _view_port.originalViewPort)(), currentThemeName)
}
function getCssClasses(themeName) {
themeName = themeName || current();
var result = [];
var themeNameParts = themeName && themeName.split(".");
if (themeNameParts) {
result.push("dx-theme-" + themeNameParts[0], "dx-theme-" + themeNameParts[0] + "-typography");
if (themeNameParts.length > 1) {
result.push("dx-color-scheme-" + themeNameParts[1] + (isMaterial(themeName) ? "-" + themeNameParts[2] : ""))
}
}
return result
}
var themeClasses;
function attachCssClasses(element, themeName) {
themeClasses = getCssClasses(themeName).join(" ");
(0, _renderer2.default)(element).addClass(themeClasses);
var activateHairlines = function() {
var pixelRatio = (0, _window.hasWindow)() && window.devicePixelRatio;
if (!pixelRatio || pixelRatio < 2) {
return
}
var $tester = (0, _renderer2.default)("<div>");
$tester.css("border", ".5px solid transparent");
(0, _renderer2.default)("body").append($tester);
if (1 === $tester.outerHeight()) {
(0, _renderer2.default)(element).addClass(DX_HAIRLINES_CLASS);
themeClasses += " " + DX_HAIRLINES_CLASS
}
$tester.remove()
};
activateHairlines()
}
function detachCssClasses(element) {
(0, _renderer2.default)(element).removeClass(themeClasses)
}
function themeReady(callback) {
_themes_callback.themeReadyCallback.add(callback)
}
function isTheme(themeRegExp, themeName) {
if (!themeName) {
themeName = currentThemeName || readThemeMarker()
}
return new RegExp(themeRegExp).test(themeName)
}
function isMaterial(themeName) {
return isTheme("material", themeName)
}
function isIos7(themeName) {
return isTheme("ios7", themeName)
}
function isGeneric(themeName) {
return isTheme("generic", themeName)
}
function isDark(themeName) {
return isTheme("dark", themeName)
}
function checkThemeDeprecation() {
if (isIos7()) {
_ui2.default.log("W0010", "The 'ios7' theme", "19.1", "Use the 'generic' theme instead.")
}
}
function isWebFontLoaded(text, fontWeight) {
var testedFont = "Roboto, RobotoFallback, Arial";
var etalonFont = "Arial";
var document = _dom_adapter2.default.getDocument();
var testElement = document.createElement("span");
testElement.style.position = "absolute";
testElement.style.top = "-9999px";
testElement.style.left = "-9999px";
testElement.style.visibility = "hidden";
testElement.style.fontFamily = etalonFont;
testElement.style.fontSize = "250px";
testElement.style.fontWeight = fontWeight;
testElement.innerHTML = text;
document.body.appendChild(testElement);
var etalonFontWidth = testElement.offsetWidth;
testElement.style.fontFamily = testedFont;
var testedFontWidth = testElement.offsetWidth;
testElement.parentNode.removeChild(testElement);
return etalonFontWidth !== testedFontWidth
}
function waitWebFont(text, fontWeight) {
var interval = 15;
var timeout = 2e3;
return new _promise2.default(function(resolve) {
var check = function() {
if (isWebFontLoaded(text, fontWeight)) {
clear()
}
};
var clear = function() {
clearInterval(intervalId);
clearTimeout(timeoutId);
resolve()
};
var intervalId = setInterval(check, interval);
var timeoutId = setTimeout(clear, timeout)
})
}
var initDeferred = new _deferred.Deferred;
function autoInit() {
init({
_autoInit: true,
_forceTimeout: true
});
if ((0, _renderer2.default)(DX_LINK_SELECTOR, context).length) {
throw _ui2.default.Error("E0022")
}
initDeferred.resolve()
}
if ((0, _window.hasWindow)()) {
autoInit()
} else {
ready(autoInit)
}
viewPortChanged.add(function(viewPort, prevViewPort) {
initDeferred.done(function() {
detachCssClasses(prevViewPort);
attachCssClasses(viewPort)
})
});
_devices2.default.changed.add(function() {
init({
_autoInit: true
})
});
exports.init = init;
exports.waitForThemeLoad = waitForThemeLoad;
exports.current = current;
exports.attachCssClasses = attachCssClasses;
exports.detachCssClasses = detachCssClasses;
exports.isMaterial = isMaterial;
exports.isIos7 = isIos7;
exports.isGeneric = isGeneric;
exports.isDark = isDark;
exports.checkThemeDeprecation = checkThemeDeprecation;
exports.isWebFontLoaded = isWebFontLoaded;
exports.waitWebFont = waitWebFont;
exports.ready = themeReady;
exports.resetTheme = function() {
$activeThemeLink && $activeThemeLink.attr("href", "about:blank");
currentThemeName = null;
pendingThemeName = null;
inited = false;
_themes_callback.themeInitializedCallback.add(function() {
return inited = true
})
}, exports.setDefaultTimeout = function(timeout) {
defaultTimeout = timeout
};
exports.initialized = function(callback) {
if (inited) {
callback()
} else {
_themes_callback.themeInitializedCallback.add(callback)
}
};
module.exports.default = module.exports;