@openui5/sap.ui.core 1.139.0 → 1.140.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (337) hide show
  1. package/THIRDPARTY.txt +1 -1
  2. package/package.json +1 -1
  3. package/src/jquery.sap.global.js +1 -1
  4. package/src/jquery.sap.mobile.js +0 -8
  5. package/src/jquery.sap.properties.js +1 -1
  6. package/src/jquery.sap.resources.js +1 -1
  7. package/src/jquery.sap.script.js +1 -1
  8. package/src/jquery.sap.storage.js +3 -3
  9. package/src/sap/base/Event.js +1 -1
  10. package/src/sap/base/Eventing.js +1 -1
  11. package/src/sap/base/config.js +1 -1
  12. package/src/sap/base/i18n/LanguageTag.js +1 -1
  13. package/src/sap/base/i18n/date/TimezoneUtils.js +1 -1
  14. package/src/sap/base/security/URLListValidator.js +7 -3
  15. package/src/sap/base/util/restricted/_CancelablePromise.js +1 -1
  16. package/src/sap/base/util/restricted/_castArray.js +1 -1
  17. package/src/sap/base/util/restricted/_compact.js +1 -1
  18. package/src/sap/base/util/restricted/_curry.js +1 -1
  19. package/src/sap/base/util/restricted/_debounce.js +1 -1
  20. package/src/sap/base/util/restricted/_difference.js +1 -1
  21. package/src/sap/base/util/restricted/_differenceBy.js +1 -1
  22. package/src/sap/base/util/restricted/_differenceWith.js +1 -1
  23. package/src/sap/base/util/restricted/_flatMap.js +1 -1
  24. package/src/sap/base/util/restricted/_flatMapDeep.js +1 -1
  25. package/src/sap/base/util/restricted/_flatMapDepth.js +1 -1
  26. package/src/sap/base/util/restricted/_flatten.js +1 -1
  27. package/src/sap/base/util/restricted/_flattenDeep.js +1 -1
  28. package/src/sap/base/util/restricted/_flattenDepth.js +1 -1
  29. package/src/sap/base/util/restricted/_intersection.js +1 -1
  30. package/src/sap/base/util/restricted/_intersectionBy.js +1 -1
  31. package/src/sap/base/util/restricted/_intersectionWith.js +1 -1
  32. package/src/sap/base/util/restricted/_isEqual.js +1 -1
  33. package/src/sap/base/util/restricted/_isEqualWith.js +1 -1
  34. package/src/sap/base/util/restricted/_isNil.js +1 -1
  35. package/src/sap/base/util/restricted/_max.js +1 -1
  36. package/src/sap/base/util/restricted/_merge.js +1 -1
  37. package/src/sap/base/util/restricted/_mergeWith.js +1 -1
  38. package/src/sap/base/util/restricted/_min.js +1 -1
  39. package/src/sap/base/util/restricted/_omit.js +1 -1
  40. package/src/sap/base/util/restricted/_pick.js +1 -1
  41. package/src/sap/base/util/restricted/_pickBy.js +1 -1
  42. package/src/sap/base/util/restricted/_throttle.js +1 -1
  43. package/src/sap/base/util/restricted/_toArray.js +1 -1
  44. package/src/sap/base/util/restricted/_union.js +1 -1
  45. package/src/sap/base/util/restricted/_unionBy.js +1 -1
  46. package/src/sap/base/util/restricted/_unionWith.js +1 -1
  47. package/src/sap/base/util/restricted/_uniq.js +1 -1
  48. package/src/sap/base/util/restricted/_uniqBy.js +1 -1
  49. package/src/sap/base/util/restricted/_uniqWith.js +1 -1
  50. package/src/sap/base/util/restricted/_without.js +1 -1
  51. package/src/sap/base/util/restricted/_xor.js +1 -1
  52. package/src/sap/base/util/restricted/_xorBy.js +1 -1
  53. package/src/sap/base/util/restricted/_xorWith.js +1 -1
  54. package/src/sap/base/util/restricted/_zipObject.js +1 -1
  55. package/src/sap/base/util/restricted/_zipObjectDeep.js +1 -1
  56. package/src/sap/ui/Device.js +3 -3
  57. package/src/sap/ui/Global.js +3 -3
  58. package/src/sap/ui/base/BindingParser.js +1 -1
  59. package/src/sap/ui/base/Event.js +1 -1
  60. package/src/sap/ui/base/EventProvider.js +1 -1
  61. package/src/sap/ui/base/Interface.js +1 -1
  62. package/src/sap/ui/base/ManagedObject.js +1 -1
  63. package/src/sap/ui/base/ManagedObjectMetadata.js +1 -1
  64. package/src/sap/ui/base/Metadata.js +1 -1
  65. package/src/sap/ui/base/Object.js +1 -1
  66. package/src/sap/ui/base/ObjectPool.js +1 -1
  67. package/src/sap/ui/core/.library +2 -2
  68. package/src/sap/ui/core/BusyIndicator.js +1 -1
  69. package/src/sap/ui/core/Component.js +1 -1
  70. package/src/sap/ui/core/ComponentContainer.js +1 -1
  71. package/src/sap/ui/core/ComponentMetadata.js +1 -1
  72. package/src/sap/ui/core/ComponentSupport.js +1 -1
  73. package/src/sap/ui/core/Configuration.js +1 -1
  74. package/src/sap/ui/core/Control.js +1 -1
  75. package/src/sap/ui/core/Core.js +2 -11
  76. package/src/sap/ui/core/CustomData.js +1 -1
  77. package/src/sap/ui/core/DeclarativeSupport.js +1 -1
  78. package/src/sap/ui/core/Element.js +1 -1
  79. package/src/sap/ui/core/ElementMetadata.js +1 -1
  80. package/src/sap/ui/core/EnabledPropagator.js +1 -1
  81. package/src/sap/ui/core/EventBus.js +1 -1
  82. package/src/sap/ui/core/Fragment.js +1 -1
  83. package/src/sap/ui/core/HTML.js +1 -1
  84. package/src/sap/ui/core/History.js +1 -1
  85. package/src/sap/ui/core/Icon.js +1 -1
  86. package/src/sap/ui/core/IndicationColorSupport.js +1 -1
  87. package/src/sap/ui/core/IntervalTrigger.js +1 -1
  88. package/src/sap/ui/core/InvisibleMessage.js +1 -1
  89. package/src/sap/ui/core/InvisibleRenderer.js +1 -1
  90. package/src/sap/ui/core/InvisibleText.js +1 -1
  91. package/src/sap/ui/core/Item.js +1 -1
  92. package/src/sap/ui/core/LabelEnablement.js +1 -1
  93. package/src/sap/ui/core/LayoutData.js +1 -1
  94. package/src/sap/ui/core/Lib.js +15 -108
  95. package/src/sap/ui/core/ListItem.js +1 -1
  96. package/src/sap/ui/core/LocalBusyIndicator.js +1 -1
  97. package/src/sap/ui/core/Locale.js +1 -1
  98. package/src/sap/ui/core/LocaleData.js +1 -1
  99. package/src/sap/ui/core/Manifest.js +1 -1
  100. package/src/sap/ui/core/Message.js +1 -1
  101. package/src/sap/ui/core/RenderManager.js +1 -1
  102. package/src/sap/ui/core/Renderer.js +1 -1
  103. package/src/sap/ui/core/ResizeHandler.js +1 -1
  104. package/src/sap/ui/core/ScrollBar.js +1 -1
  105. package/src/sap/ui/core/SeparatorItem.js +1 -1
  106. package/src/sap/ui/core/Theming.js +145 -76
  107. package/src/sap/ui/core/Title.js +1 -1
  108. package/src/sap/ui/core/TooltipBase.js +1 -1
  109. package/src/sap/ui/core/UIArea.js +1 -1
  110. package/src/sap/ui/core/UIComponent.js +1 -1
  111. package/src/sap/ui/core/UIComponentMetadata.js +1 -1
  112. package/src/sap/ui/core/ValueStateSupport.js +1 -1
  113. package/src/sap/ui/core/VariantLayoutData.js +1 -1
  114. package/src/sap/ui/core/XMLComposite.js +1 -1
  115. package/src/sap/ui/core/XMLCompositeMetadata.js +1 -1
  116. package/src/sap/ui/core/XMLTemplateProcessor.js +1 -1
  117. package/src/sap/ui/core/date/UI5Date.js +1 -1
  118. package/src/sap/ui/core/delegate/ItemNavigation.js +1 -1
  119. package/src/sap/ui/core/delegate/ScrollEnablement.js +1 -1
  120. package/src/sap/ui/core/dnd/DragDropBase.js +1 -1
  121. package/src/sap/ui/core/dnd/DragDropInfo.js +1 -1
  122. package/src/sap/ui/core/dnd/DragInfo.js +1 -1
  123. package/src/sap/ui/core/dnd/DropInfo.js +1 -1
  124. package/src/sap/ui/core/format/FormatUtils.js +1 -1
  125. package/src/sap/ui/core/format/NumberFormat.js +1 -1
  126. package/src/sap/ui/core/format/TimezoneUtil.js +1 -1
  127. package/src/sap/ui/core/getCompatibilityVersion.js +1 -1
  128. package/src/sap/ui/core/hyphenation/Hyphenation.js +1 -1
  129. package/src/sap/ui/core/library.js +3 -3
  130. package/src/sap/ui/core/message/ControlMessageProcessor.js +1 -1
  131. package/src/sap/ui/core/message/Message.js +1 -1
  132. package/src/sap/ui/core/message/MessageManager.js +1 -1
  133. package/src/sap/ui/core/message/MessageParser.js +1 -1
  134. package/src/sap/ui/core/message/MessageProcessor.js +1 -1
  135. package/src/sap/ui/core/messagebundle_ar.properties +26 -11
  136. package/src/sap/ui/core/messagebundle_bg.properties +21 -6
  137. package/src/sap/ui/core/messagebundle_ca.properties +24 -9
  138. package/src/sap/ui/core/messagebundle_cnr.properties +23 -8
  139. package/src/sap/ui/core/messagebundle_cs.properties +24 -9
  140. package/src/sap/ui/core/messagebundle_cy.properties +24 -9
  141. package/src/sap/ui/core/messagebundle_da.properties +21 -6
  142. package/src/sap/ui/core/messagebundle_de.properties +16 -1
  143. package/src/sap/ui/core/messagebundle_el.properties +26 -11
  144. package/src/sap/ui/core/messagebundle_en.properties +24 -9
  145. package/src/sap/ui/core/messagebundle_en_GB.properties +24 -9
  146. package/src/sap/ui/core/messagebundle_en_US_saprigi.properties +24 -9
  147. package/src/sap/ui/core/messagebundle_es.properties +21 -6
  148. package/src/sap/ui/core/messagebundle_es_MX.properties +24 -9
  149. package/src/sap/ui/core/messagebundle_et.properties +31 -16
  150. package/src/sap/ui/core/messagebundle_fi.properties +20 -5
  151. package/src/sap/ui/core/messagebundle_fr.properties +22 -7
  152. package/src/sap/ui/core/messagebundle_fr_CA.properties +20 -5
  153. package/src/sap/ui/core/messagebundle_hi.properties +24 -9
  154. package/src/sap/ui/core/messagebundle_hr.properties +20 -5
  155. package/src/sap/ui/core/messagebundle_hu.properties +23 -8
  156. package/src/sap/ui/core/messagebundle_id.properties +20 -5
  157. package/src/sap/ui/core/messagebundle_it.properties +23 -8
  158. package/src/sap/ui/core/messagebundle_iw.properties +21 -6
  159. package/src/sap/ui/core/messagebundle_ja.properties +19 -4
  160. package/src/sap/ui/core/messagebundle_kk.properties +22 -7
  161. package/src/sap/ui/core/messagebundle_ko.properties +20 -5
  162. package/src/sap/ui/core/messagebundle_lt.properties +20 -5
  163. package/src/sap/ui/core/messagebundle_lv.properties +20 -5
  164. package/src/sap/ui/core/messagebundle_mk.properties +25 -10
  165. package/src/sap/ui/core/messagebundle_ms.properties +24 -9
  166. package/src/sap/ui/core/messagebundle_nl.properties +22 -7
  167. package/src/sap/ui/core/messagebundle_no.properties +22 -7
  168. package/src/sap/ui/core/messagebundle_pl.properties +19 -4
  169. package/src/sap/ui/core/messagebundle_pt.properties +18 -3
  170. package/src/sap/ui/core/messagebundle_pt_PT.properties +18 -3
  171. package/src/sap/ui/core/messagebundle_ro.properties +22 -7
  172. package/src/sap/ui/core/messagebundle_ru.properties +19 -4
  173. package/src/sap/ui/core/messagebundle_sh.properties +23 -8
  174. package/src/sap/ui/core/messagebundle_sk.properties +23 -8
  175. package/src/sap/ui/core/messagebundle_sl.properties +20 -5
  176. package/src/sap/ui/core/messagebundle_sr.properties +23 -8
  177. package/src/sap/ui/core/messagebundle_sv.properties +23 -8
  178. package/src/sap/ui/core/messagebundle_th.properties +20 -5
  179. package/src/sap/ui/core/messagebundle_tr.properties +20 -5
  180. package/src/sap/ui/core/messagebundle_uk.properties +22 -7
  181. package/src/sap/ui/core/messagebundle_vi.properties +18 -3
  182. package/src/sap/ui/core/messagebundle_zh_CN.properties +24 -9
  183. package/src/sap/ui/core/messagebundle_zh_TW.properties +20 -5
  184. package/src/sap/ui/core/mvc/HTMLView.js +1 -1
  185. package/src/sap/ui/core/mvc/JSONView.js +1 -1
  186. package/src/sap/ui/core/mvc/JSView.js +1 -1
  187. package/src/sap/ui/core/mvc/TemplateView.js +1 -1
  188. package/src/sap/ui/core/mvc/View.js +1 -1
  189. package/src/sap/ui/core/mvc/XMLView.js +1 -1
  190. package/src/sap/ui/core/plugin/DeclarativeSupport.js +1 -1
  191. package/src/sap/ui/core/plugin/TemplatingSupport.js +1 -1
  192. package/src/sap/ui/core/postmessage/Bus.js +1 -1
  193. package/src/sap/ui/core/postmessage/confirmationDialog.js +1 -1
  194. package/src/sap/ui/core/routing/Route.js +1 -1
  195. package/src/sap/ui/core/routing/Router.js +19 -1
  196. package/src/sap/ui/core/search/OpenSearchProvider.js +1 -1
  197. package/src/sap/ui/core/search/SearchProvider.js +1 -1
  198. package/src/sap/ui/core/service/Service.js +1 -1
  199. package/src/sap/ui/core/service/ServiceFactory.js +1 -1
  200. package/src/sap/ui/core/service/ServiceFactoryRegistry.js +1 -1
  201. package/src/sap/ui/core/support/Plugin.js +1 -1
  202. package/src/sap/ui/core/support/Support.js +1 -1
  203. package/src/sap/ui/core/support/plugins/ControlTree.js +1 -1
  204. package/src/sap/ui/core/support/plugins/Interaction.js +1 -1
  205. package/src/sap/ui/core/support/plugins/LocalStorage.js +1 -1
  206. package/src/sap/ui/core/support/plugins/Performance.js +1 -1
  207. package/src/sap/ui/core/support/plugins/Selector.js +1 -1
  208. package/src/sap/ui/core/support/plugins/TechInfo.js +1 -1
  209. package/src/sap/ui/core/support/plugins/Trace.js +1 -1
  210. package/src/sap/ui/core/support/plugins/ViewInfo.js +1 -1
  211. package/src/sap/ui/core/themes/base/base.less +20 -20
  212. package/src/sap/ui/core/themes/base/shared.less +4 -1
  213. package/src/sap/ui/core/themes/base/skeleton.less +3 -3
  214. package/src/sap/ui/core/theming/Parameters.js +717 -755
  215. package/src/sap/ui/core/theming/ThemeHelper.js +0 -77
  216. package/src/sap/ui/core/theming/ThemeManager.js +535 -526
  217. package/src/sap/ui/core/tmpl/DOMAttribute.js +1 -1
  218. package/src/sap/ui/core/tmpl/DOMElement.js +1 -1
  219. package/src/sap/ui/core/tmpl/HandlebarsTemplate.js +1 -1
  220. package/src/sap/ui/core/tmpl/Template.js +1 -1
  221. package/src/sap/ui/core/tmpl/TemplateControl.js +1 -1
  222. package/src/sap/ui/core/util/AsyncHintsHelper.js +1 -1
  223. package/src/sap/ui/core/util/Export.js +1 -1
  224. package/src/sap/ui/core/util/ExportCell.js +1 -1
  225. package/src/sap/ui/core/util/ExportColumn.js +1 -1
  226. package/src/sap/ui/core/util/ExportRow.js +1 -1
  227. package/src/sap/ui/core/util/ExportType.js +1 -1
  228. package/src/sap/ui/core/util/ExportTypeCSV.js +1 -1
  229. package/src/sap/ui/core/util/File.js +1 -1
  230. package/src/sap/ui/core/util/LibraryInfo.js +1 -1
  231. package/src/sap/ui/core/util/MockServer.js +1 -1
  232. package/src/sap/ui/core/util/PasteHelper.js +1 -1
  233. package/src/sap/ui/core/util/serializer/HTMLViewSerializer.js +1 -1
  234. package/src/sap/ui/core/util/serializer/Serializer.js +1 -1
  235. package/src/sap/ui/core/util/serializer/ViewSerializer.js +1 -1
  236. package/src/sap/ui/core/util/serializer/XMLViewSerializer.js +1 -1
  237. package/src/sap/ui/core/util/serializer/delegate/Delegate.js +1 -1
  238. package/src/sap/ui/core/util/serializer/delegate/HTML.js +1 -1
  239. package/src/sap/ui/core/util/serializer/delegate/XML.js +1 -1
  240. package/src/sap/ui/core/webc/WebComponent.js +93 -45
  241. package/src/sap/ui/core/webc/WebComponentMetadata.js +40 -6
  242. package/src/sap/ui/core/ws/ReadyState.js +1 -1
  243. package/src/sap/ui/core/ws/SapPcpWebSocket.js +1 -1
  244. package/src/sap/ui/core/ws/WebSocket.js +1 -1
  245. package/src/sap/ui/debug/ControlTree.js +1 -1
  246. package/src/sap/ui/debug/DebugEnv.js +1 -1
  247. package/src/sap/ui/debug/PropertyList.js +1 -1
  248. package/src/sap/ui/dom/includeStylesheet.js +4 -1
  249. package/src/sap/ui/model/ClientModel.js +1 -1
  250. package/src/sap/ui/model/CompositeDataState.js +1 -1
  251. package/src/sap/ui/model/CompositeType.js +1 -1
  252. package/src/sap/ui/model/DataState.js +1 -1
  253. package/src/sap/ui/model/MetaModel.js +1 -1
  254. package/src/sap/ui/model/Model.js +7 -7
  255. package/src/sap/ui/model/SelectionModel.js +1 -1
  256. package/src/sap/ui/model/SimpleType.js +1 -1
  257. package/src/sap/ui/model/TreeAutoExpandMode.js +1 -1
  258. package/src/sap/ui/model/Type.js +1 -1
  259. package/src/sap/ui/model/json/JSONModel.js +1 -1
  260. package/src/sap/ui/model/json/TypedJSONContext.js +16 -0
  261. package/src/sap/ui/model/json/TypedJSONModel.js +16 -0
  262. package/src/sap/ui/model/message/MessageModel.js +1 -1
  263. package/src/sap/ui/model/odata/ODataAnnotations.js +1 -1
  264. package/src/sap/ui/model/odata/ODataMessageParser.js +1 -1
  265. package/src/sap/ui/model/odata/ODataMetaModel.js +1 -1
  266. package/src/sap/ui/model/odata/ODataMetadata.js +4 -4
  267. package/src/sap/ui/model/odata/ODataModel.js +1 -1
  268. package/src/sap/ui/model/odata/ODataTreeBindingFlat.js +9 -8
  269. package/src/sap/ui/model/odata/_AnnotationHelperExpression.js +2 -2
  270. package/src/sap/ui/model/odata/type/Boolean.js +1 -1
  271. package/src/sap/ui/model/odata/type/Byte.js +1 -1
  272. package/src/sap/ui/model/odata/type/Currency.js +1 -1
  273. package/src/sap/ui/model/odata/type/Date.js +1 -1
  274. package/src/sap/ui/model/odata/type/DateTime.js +1 -1
  275. package/src/sap/ui/model/odata/type/DateTimeBase.js +1 -1
  276. package/src/sap/ui/model/odata/type/DateTimeOffset.js +1 -1
  277. package/src/sap/ui/model/odata/type/DateTimeWithTimezone.js +1 -1
  278. package/src/sap/ui/model/odata/type/Decimal.js +1 -1
  279. package/src/sap/ui/model/odata/type/Double.js +1 -1
  280. package/src/sap/ui/model/odata/type/Guid.js +1 -1
  281. package/src/sap/ui/model/odata/type/Int.js +1 -1
  282. package/src/sap/ui/model/odata/type/Int16.js +1 -1
  283. package/src/sap/ui/model/odata/type/Int32.js +1 -1
  284. package/src/sap/ui/model/odata/type/Int64.js +1 -1
  285. package/src/sap/ui/model/odata/type/ODataType.js +1 -1
  286. package/src/sap/ui/model/odata/type/Raw.js +1 -1
  287. package/src/sap/ui/model/odata/type/SByte.js +1 -1
  288. package/src/sap/ui/model/odata/type/Single.js +1 -1
  289. package/src/sap/ui/model/odata/type/Stream.js +1 -1
  290. package/src/sap/ui/model/odata/type/String.js +1 -1
  291. package/src/sap/ui/model/odata/type/Time.js +1 -1
  292. package/src/sap/ui/model/odata/type/TimeOfDay.js +1 -1
  293. package/src/sap/ui/model/odata/type/Unit.js +1 -1
  294. package/src/sap/ui/model/odata/v2/Context.js +1 -1
  295. package/src/sap/ui/model/odata/v2/ODataAnnotations.js +1 -1
  296. package/src/sap/ui/model/odata/v2/ODataContextBinding.js +2 -2
  297. package/src/sap/ui/model/odata/v2/ODataListBinding.js +2 -2
  298. package/src/sap/ui/model/odata/v2/ODataModel.js +41 -59
  299. package/src/sap/ui/model/odata/v2/ODataTreeBinding.js +82 -60
  300. package/src/sap/ui/model/odata/v4/Context.js +1 -1
  301. package/src/sap/ui/model/odata/v4/ODataContextBinding.js +1 -1
  302. package/src/sap/ui/model/odata/v4/ODataListBinding.js +1 -1
  303. package/src/sap/ui/model/odata/v4/ODataMetaModel.js +35 -20
  304. package/src/sap/ui/model/odata/v4/ODataModel.js +1 -1
  305. package/src/sap/ui/model/odata/v4/ODataParentBinding.js +32 -5
  306. package/src/sap/ui/model/odata/v4/ODataPropertyBinding.js +1 -1
  307. package/src/sap/ui/model/odata/v4/lib/_AggregationCache.js +11 -1
  308. package/src/sap/ui/model/odata/v4/lib/_Cache.js +7 -9
  309. package/src/sap/ui/model/odata/v4/lib/_Helper.js +12 -12
  310. package/src/sap/ui/model/odata/v4/lib/_Requestor.js +16 -6
  311. package/src/sap/ui/model/resource/ResourceModel.js +1 -1
  312. package/src/sap/ui/model/type/Boolean.js +1 -1
  313. package/src/sap/ui/model/type/Currency.js +1 -1
  314. package/src/sap/ui/model/type/Date.js +1 -1
  315. package/src/sap/ui/model/type/DateInterval.js +1 -1
  316. package/src/sap/ui/model/type/DateTime.js +1 -1
  317. package/src/sap/ui/model/type/DateTimeInterval.js +1 -1
  318. package/src/sap/ui/model/type/FileSize.js +1 -1
  319. package/src/sap/ui/model/type/Float.js +1 -1
  320. package/src/sap/ui/model/type/Integer.js +1 -1
  321. package/src/sap/ui/model/type/String.js +1 -1
  322. package/src/sap/ui/model/type/Time.js +1 -1
  323. package/src/sap/ui/model/type/TimeInterval.js +1 -1
  324. package/src/sap/ui/model/type/Unit.js +19 -5
  325. package/src/sap/ui/model/xml/XMLModel.js +1 -1
  326. package/src/sap/ui/qunit/utils/ControlIterator.js +1 -2
  327. package/src/sap/ui/qunit/utils/MemoryLeakCheck.js +1 -1
  328. package/src/sap/ui/test/TestUtils.js +27 -15
  329. package/src/sap/ui/test/generic/TestBase.js +1 -1
  330. package/src/sap/ui/test/generic/Utils.js +6 -6
  331. package/src/sap/ui/test/opaQunit.js +3 -0
  332. package/src/sap/ui/thirdparty/qunit-2.js +4 -1
  333. package/src/sap/ui/util/Mobile.js +0 -9
  334. package/src/sap/ui/util/Storage.js +1 -1
  335. package/src/ui5loader.js +1 -1
  336. package/ui5.yaml +0 -1
  337. package/src/sap/ui/core/plugin/LessSupport.js +0 -542
@@ -11,11 +11,8 @@ sap.ui.define([
11
11
  "sap/base/future",
12
12
  "sap/base/Log",
13
13
  "sap/base/i18n/Localization",
14
- "sap/base/util/each",
15
- "sap/base/util/LoaderExtensions",
16
- "sap/ui/Device",
14
+ "sap/ui/base/OwnStatics",
17
15
  "sap/ui/VersionInfo",
18
- "sap/ui/core/Lib",
19
16
  "sap/ui/core/Theming",
20
17
  "sap/ui/core/theming/ThemeHelper",
21
18
  "sap/ui/dom/includeStylesheet"
@@ -25,73 +22,57 @@ sap.ui.define([
25
22
  future,
26
23
  Log,
27
24
  Localization,
28
- each,
29
- LoaderExtensions,
30
- Device,
25
+ OwnStatics,
31
26
  VersionInfo,
32
- Library,
33
27
  Theming,
34
28
  ThemeHelper,
35
29
  includeStylesheet
36
30
  ) {
37
31
  "use strict";
38
32
 
39
- const oEventing = new Eventing();
40
- const maxThemeCheckCycles = 150;
41
- const mAllLoadedLibraries = {};
42
- const CUSTOMCSSCHECK = /\.sapUiThemeDesignerCustomCss/i;
43
- const _CUSTOMID = "sap-ui-core-customcss";
44
- const _THEME_PREFIX = "sap-ui-theme-";
45
- let bAllPreloadedCssReady = true;
46
-
47
- // Collect all UI5 relevant CSS files which have been added upfront
48
- // and add them to UI5 theming lifecycle
49
- document.querySelectorAll(`link[id^=${_THEME_PREFIX}]`).forEach(function(linkNode) {
50
- let bPreloadedCssReady = true;
51
- const sLibId = linkNode.getAttribute("id").replace(_THEME_PREFIX, "");
52
-
53
- mAllLoadedLibraries[sLibId] = {};
54
- linkNode.removeAttribute("data-sap-ui-ready");
55
-
56
- Log.info(`ThemeManager: Preloaded CSS for library ${sLibId} detected: ${linkNode.href}`, undefined, "sap.ui.core.theming.ThemeManager");
57
-
58
- try {
59
- bPreloadedCssReady = !!(linkNode.sheet?.href === linkNode.href && linkNode.sheet?.cssRules);
33
+ const CUSTOM_CSS_CHECK = /\.sapUiThemeDesignerCustomCss/i;
34
+ const MODULE_NAME = "sap.ui.core.theming.ThemeManager";
35
+ const CUSTOM_ID = "sap-ui-core-customcss";
36
+ const THEME_PREFIX = "sap-ui-theme-";
37
+ const LINK_ID_REGGEX_STRING = `^${THEME_PREFIX}(.*)`;
38
+ const LINK_ID_CHECK = new RegExp(LINK_ID_REGGEX_STRING);
39
+ const LINK_ID_WITH_VARIANT_CHECK = new RegExp(`${LINK_ID_REGGEX_STRING}-(?=\\[(.*)\\]).*$`);
60
40
 
61
- if (!bPreloadedCssReady) {
62
- bAllPreloadedCssReady = bPreloadedCssReady;
63
- linkNode.addEventListener("load", (oEvent) => {
64
- const bError = oEvent.type === "error";
65
- linkNode.setAttribute("data-sap-ui-ready", !bError);
66
- });
67
- } else {
68
- linkNode.setAttribute("data-sap-ui-ready", linkNode.sheet.cssRules.length > 0);
69
- }
70
- } catch (e) {
71
- // If the stylesheet is cross-origin and throws a security error, we can't verify directly
72
- Log.info("Could not detect ready state of preloaded CSS. Request stylesheet again to verify the response status", undefined, "sap.ui.core.theming.ThemeManager");
41
+ const oEventing = new Eventing();
42
+ const mAllLoadedLibraries = new Map();
43
+ const { attachChange, registerThemeManager, getThemePath } = OwnStatics.get(Theming);
73
44
 
74
- bAllPreloadedCssReady = false;
45
+ let CORE_VERSION;
75
46
 
76
- includeStylesheet({
77
- url: linkNode.href,
78
- id: linkNode.getAttribute("id")
79
- });
80
- }
81
- });
82
-
83
- let _iCount = 0; // Prevent endless loop
47
+ let pAllCssRequests = Promise.resolve();
84
48
  let _customCSSAdded = false;
85
49
  let _themeCheckedForCustom = null;
86
- let _sFallbackTheme = null;
87
- let _mThemeFallback = {};
88
- let _sThemeCheckId;
50
+ let _sFallbackThemeFromMetadata = null;
51
+ let _sFallbackThemeFromThemeRoot = null;
52
+ let sUi5Version;
53
+ let mAllDistLibraries;
54
+
55
+ function isVersionInfoNeeded() {
56
+ const theme = Theming.getTheme();
57
+ return !ThemeHelper.isStandardTheme(theme) && Theming.getThemeRoot(theme);
58
+ }
59
+ // UI5 version is only needed in case a theming service is active but we always add it to the request
60
+ // therefore request it as early as possible
61
+ const versionInfoLoaded = VersionInfo.load().then((oVersionInfo) => {
62
+ sUi5Version = oVersionInfo.version;
63
+ mAllDistLibraries = new Set(oVersionInfo.libraries.map((library) => library.name));
64
+ }, (e) => {
65
+ if (isVersionInfoNeeded()) {
66
+ Log.error("UI5 theming lifecycle requires valid version information when a theming service is active. Please check why the version info could not be loaded in this system.", e, MODULE_NAME);
67
+ }
68
+ });
89
69
 
90
70
  /**
91
- * Helper class used by the UI5 Core to check whether the themes are applied correctly.
92
- *
93
- * It could happen that e.g. in onAfterRendering not all themes are available. In these cases the
94
- * check waits until the CSS is applied and fires an onThemeApplied event.
71
+ * The ThemeManager is responsible for managing and applying themes within the application.
72
+ * It handles the addition and updating of library CSS, including custom CSS if needed. It also
73
+ * detects and deals with UI5 relevant library CSS added to the DOM for preloading and includes
74
+ * them into the lifecycle. Additionally, it notifies subscribers after a theme has been applied,
75
+ * regardless of whether the theme was applied successfully or not.
95
76
  *
96
77
  * @namespace
97
78
  * @author SAP SE
@@ -99,359 +80,436 @@ sap.ui.define([
99
80
  * @ui5-restricted sap.ui.core
100
81
  * @alias sap.ui.core.theming.ThemeManager
101
82
  */
102
- var ThemeManager = {
83
+ const ThemeManager = {
103
84
  /**
104
- * Wether theme is already loaded or not
105
- * @private
106
- * @ui5-restricted sap.ui.core
107
- */
108
- themeLoaded: bAllPreloadedCssReady,
85
+ * Wether theme is already loaded or not
86
+ * @private
87
+ * @ui5-restricted sap.ui.core
88
+ */
89
+ themeLoaded: true
90
+ };
109
91
 
110
- /**
111
- * Trigger ThemeManager
112
- *
113
- * @private
114
- * @ui5-restricted sap.ui.core
115
- */
116
- checkThemeApplied : function() {
117
- ThemeManager.reset();
118
- delayedCheckTheme(true);
119
- if (!_sThemeCheckId) {
120
- ThemeManager.fireThemeApplied();
121
- }
122
- },
92
+ /**
93
+ * Helper functions
94
+ */
123
95
 
96
+ /**
97
+ * Retrieves the library info object for theming.
98
+ *
99
+ * If the library info object does not exist yet, it will be created and stored.
100
+ * Otherwise, the existing object is returned.
101
+ *
102
+ * @param {object} libInfo - The library info configuration.
103
+ * @param {string} libInfo.libName - The name of the library.
104
+ * @param {string} [libInfo.variant] - Optional variant name.
105
+ * @param {string} [libInfo.fileName] - Optional file name for the CSS file.
106
+ * @returns {object} The library info object with theming metadata and helper methods.
107
+ */
108
+ function getLibraryInfo(libInfo) {
124
109
  /**
125
- * Resets the internal bookkeeping
110
+ * Creates a new library info object for theming purposes.
126
111
  *
127
- * @private
128
- * @ui5-restricted sap.ui.core
112
+ * The returned object contains metadata and helper methods for managing the theme CSS of a UI5 library,
113
+ * including its ID, name, link ID, CSS link element, loading state, variant, and file name.
114
+ * It also provides a method to generate the correct CSS URL for the library, considering RTL mode,
115
+ * variants, and versioning.
116
+ *
117
+ * If the ID matches the custom CSS ID, the file name and library name are set accordingly.
118
+ * The link ID and CSS link element are automatically determined.
119
+ *
120
+ * @param {object} libInfo - The library info configuration.
121
+ * @param {string} libInfo.id - The unique ID for the library info object.
122
+ * @param {string} libInfo.libName - The name of the library.
123
+ * @param {string} [libInfo.variant] - Optional variant name.
124
+ * @param {string} [libInfo.fileName] - Optional file name for the CSS file.
125
+ * @returns {object} The library info object with theming metadata and helper methods.
129
126
  */
130
- reset: function() {
131
- ThemeManager.themeLoaded = false;
132
- if (_sThemeCheckId) {
133
- clearTimeout(_sThemeCheckId);
134
- _sThemeCheckId = null;
135
- _iCount = 0;
136
- _sFallbackTheme = null;
137
- _mThemeFallback = {};
138
- }
139
- },
127
+ function createLibraryInfoObject(libInfo) {
128
+ const oLibInfoTemplate = {
129
+ id: "",
130
+ libName: "",
131
+ linkId: "",
132
+ cssLinkElement: null,
133
+ cssLoaded: null,
134
+ failed: false,
135
+ customCss: false,
136
+ fileName: "library",
137
+ variant: "",
138
+ themeFallback: false,
139
+ getUrl: function(sTheme) {
140
+ const buildUrl = (skipVersionInfo) => {
141
+ sTheme ??= Theming.getTheme();
142
+ /**
143
+ * Custom libs which are not part of the DIST layer have no custom theme
144
+ * except they provide it as part of the library (no themeroots for the custom library)
145
+ */
146
+ if (mAllDistLibraries && !mAllDistLibraries.has(this.libName) &&
147
+ !ThemeHelper.isStandardTheme(sTheme) && Theming.getThemeRoot(sTheme, this.libName)) {
148
+ sTheme = _sFallbackThemeFromMetadata || _sFallbackThemeFromThemeRoot;
149
+ if (!sTheme) {
150
+ return undefined;
151
+ }
152
+ }
153
+ const sCssBasePath = new URL(getThemePath(this.libName, sTheme), document.baseURI).toString();
154
+ const sVariant = this.variant || "";
155
+ let sCssPath;
156
+
157
+ /*
158
+ * Create the library file name.
159
+ * By specifying a library name containing a colon (":") you can specify
160
+ * the file name of the CSS file to include (ignoring RTL).
161
+ */
162
+ const iIdx = this.libName.indexOf(":");
163
+ if (this.libName && iIdx == -1) {
164
+ sCssPath = `${sCssBasePath}${this.fileName}${sVariant}${Localization.getRTL() ? "-RTL" : ""}.css`;
165
+ } else {
166
+ sCssPath = `${sCssBasePath}${this.libName.substring(iIdx + 1)}${sVariant}.css`;
167
+ }
168
+ // Create a link tag and set the URL as href in order to ensure AppCacheBuster handling.
169
+ // AppCacheBuster ID is added to the href by defineProperty for the "href" property of
170
+ // HTMLLinkElement in AppCacheBuster.js
171
+ // Note: Considered to use AppCacheBuster.js#convertURL for adding the AppCachebuster ID
172
+ // but there would be a dependency to AppCacheBuster as trade-off
173
+ const oTmpLink = document.createElement("link");
174
+ oTmpLink.href = `${sCssPath}${skipVersionInfo ? "" : `?sap-ui-dist-version=${sUi5Version || CORE_VERSION || ""}`}`;
175
+ return oTmpLink.href;
176
+ };
177
+ return {
178
+ urlPromise: versionInfoLoaded.then(buildUrl),
179
+ url: buildUrl(),
180
+ baseUrl: buildUrl(true)
181
+ };
182
+ }
183
+ };
140
184
 
141
- /**
142
- * Includes a library theme into the current page (if a variant is specified it
143
- * will include the variant library theme) and ensure theme root
144
- * @param {object} [oLibThemingInfo] to be used only by the Core
145
- * @private
146
- * @ui5-restricted sap.ui.core
147
- */
148
- _includeLibraryThemeAndEnsureThemeRoot: function(oLibThemingInfo) {
149
- var sLibName = oLibThemingInfo.name;
150
- // ensure to register correct library theme module path even when "preloadLibCss" prevents
151
- // including the library theme as controls might use it to calculate theme-specific URLs
152
- _ensureThemeRoot(sLibName, Theming.getTheme());
153
-
154
- // also ensure correct theme root for the library's base theme which might be relevant in some cases
155
- // (e.g. IconPool which includes font files from sap.ui.core base theme)
156
- _ensureThemeRoot(sLibName, "base");
157
-
158
- // Assume CSS is preloaded in case we detect a link tag with corresponding ID
159
- const sLinkId = `${sLibName}${oLibThemingInfo.variant ? "-[" + oLibThemingInfo.variant + "]" : ""}`;
160
- oLibThemingInfo.preloadedCss = oLibThemingInfo.preloadedCss || !!mAllLoadedLibraries[sLinkId];
161
- mAllLoadedLibraries[sLinkId] = oLibThemingInfo;
162
- if (!oLibThemingInfo.preloadedCss) {
163
- ThemeManager.includeLibraryTheme(sLibName, oLibThemingInfo.variant, oLibThemingInfo);
164
- }
165
- },
185
+ const newLibInfo = Object.assign(oLibInfoTemplate, libInfo);
166
186
 
167
- /**
168
- * Includes a library theme into the current page (if a variant is specified it
169
- * will include the variant library theme)
170
- * @param {string} sLibName the name of the UI library
171
- * @param {string} [sVariant] the variant to include (optional)
172
- * @param {string|object} [vQueryOrLibInfo] to be used only by the Core
173
- * @private
174
- * @ui5-restricted sap.ui.core
175
- */
176
- includeLibraryTheme: function(sLibName, sVariant, vQueryOrLibInfo) {
177
- assert(typeof sLibName === "string", "sLibName must be a string");
178
- assert(sVariant === undefined || typeof sVariant === "string", "sVariant must be a string or undefined");
179
- var sQuery = vQueryOrLibInfo;
180
-
181
- if (typeof sQuery === "object") {
182
- // check for configured query parameters and use them
183
- sQuery = getLibraryCssQueryParams(vQueryOrLibInfo);
187
+ if (newLibInfo.id === CUSTOM_ID) {
188
+ newLibInfo.fileName = "custom";
189
+ newLibInfo.libName = "sap.ui.core";
184
190
  }
185
191
 
192
+ newLibInfo.linkId = `${newLibInfo.id === CUSTOM_ID ? "" : THEME_PREFIX}${newLibInfo.id}`;
193
+ newLibInfo.cssLinkElement ??= document.querySelector(`link[id='${newLibInfo.linkId}']`);
194
+
195
+ return newLibInfo;
196
+ }
197
+
198
+ libInfo.id ??= `${libInfo.libName}${libInfo.variant ? `-[${libInfo.variant}]` : ""}`;
199
+
200
+ if (!mAllLoadedLibraries.has(libInfo.id)) {
201
+ libInfo = createLibraryInfoObject(libInfo);
202
+ mAllLoadedLibraries.set(libInfo.id, libInfo);
203
+ } else {
204
+ libInfo = mAllLoadedLibraries.get(libInfo.id);
205
+ }
206
+
207
+ return libInfo;
208
+ }
209
+
210
+ /**
211
+ * Includes a library theme into the current page (if a variant is specified it
212
+ * will include the variant library theme)
213
+ * @param {string} libraryInfo the library info object
214
+ * @private
215
+ * @ui5-restricted sap.ui.core
216
+ */
217
+ function includeLibraryTheme(libraryInfo) {
218
+ const { libName, variant, version } = libraryInfo;
219
+ assert(typeof libName === "string", "libName must be a string");
220
+ assert(variant === undefined || typeof variant === "string", "variant must be a string or undefined");
221
+
222
+ if (libName === "sap.ui.core") {
223
+ CORE_VERSION = version;
224
+ }
225
+
226
+ if (!mAllLoadedLibraries.has(libName)) {
186
227
  /**
187
228
  * include the stylesheet for the library (except for "classic" and "legacy" lib)
188
229
  * @deprecated
189
230
  */
190
- if (sLibName === "sap.ui.legacy" || sLibName === "sap.ui.classic") {
231
+ if (libName === "sap.ui.legacy" || libName === "sap.ui.classic") {
191
232
  return;
192
233
  }
193
234
 
194
- // no variant?
195
- if (!sVariant) {
196
- sVariant = "";
197
- }
198
-
199
- // determine RTL
200
- var sRtl = (Localization.getRTL() ? "-RTL" : "");
235
+ const oLibInfo = getLibraryInfo({
236
+ libName,
237
+ variant
238
+ });
201
239
 
240
+ if (!oLibInfo.cssLinkElement) {
241
+ updateThemeUrl({
242
+ libInfo: oLibInfo,
243
+ suppressFOUC: true
244
+ });
202
245
 
203
- /*
204
- * Create the library file name.
205
- * By specifying a library name containing a colon (":") you can specify
206
- * the file name of the CSS file to include (ignoring RTL).
207
- */
208
- var sLibFileName,
209
- sLibId = sLibName + (sVariant.length > 0 ? "-[" + sVariant + "]" : sVariant);
210
- if (sLibName && sLibName.indexOf(":") == -1) {
211
- sLibFileName = "library" + sVariant + sRtl;
212
- } else {
213
- sLibFileName = sLibName.substring(sLibName.indexOf(":") + 1) + sVariant;
214
- sLibName = sLibName.substring(0, sLibName.indexOf(":"));
246
+ // if parameters have been used, update them with the new style sheet
247
+ sap.ui.require("sap/ui/core/theming/Parameters")?._addLibraryTheme(oLibInfo.id);
215
248
  }
249
+ }
250
+ }
216
251
 
217
- const sLinkId = `${_THEME_PREFIX}${sLibId}`;
218
- if (!document.querySelector("LINK[id='" + sLinkId + "']")) {
219
- var sCssBasePath = new URL(ThemeManager._getThemePath(sLibName, Theming.getTheme()), document.baseURI).toString();
220
- // Create a link tag and set the URL as href in order to ensure AppCacheBuster handling.
221
- // AppCacheBuster ID is added to the href by defineProperty for the "href" property of
222
- // HTMLLinkElement in AppCacheBuster.js
223
- // Note: Considered to use AppCacheBuster.js#convertURL for adding the AppCachebuster ID
224
- // but there would be a dependency to AppCacheBuster as trade-off
225
- var oTmpLink = document.createElement("link");
226
- oTmpLink.href = sCssBasePath + sLibFileName + ".css" + (sQuery ? sQuery : "");
227
- var sCssPathAndName = oTmpLink.href;
228
-
252
+ /**
253
+ * Adds or updates the CSS link element for the specified library info object and theme.
254
+ *
255
+ * If a link element for the library already exists, this function compares the current stylesheet URL
256
+ * with the new one for the given theme and determines whether an update is necessary.
257
+ * If the URLs differ, it loads the new stylesheet, manages the loading state, handles FOUC (Flash of Unstyled Content) markers,
258
+ * and updates the internal state accordingly. The function also triggers theme lifecycle events such as success, failure,
259
+ * and completion, and manages the global themeLoaded flag.
260
+ *
261
+ * Additionally, the function adds the CSS loading promise to the collection of all requested CSS promises,
262
+ * ensuring that the themeApplied event is fired only after all CSS files have finished loading.
263
+ *
264
+ * @param {object} params - Parameters for updating the theme URL.
265
+ * @param {object} params.libInfo - The library info object containing theming metadata.
266
+ * @param {string} params.theme - The name of the theme to apply.
267
+ * @param {boolean} params.suppressFOUC - Whether to suppress Flash of Unstyled Content (FOUC) handling.
268
+ * @param {boolean} params.force - Whether to including stylesheet regardless the baseUrl is identical or not.
269
+ * Use the old URL to prevent unnecessary requests.
270
+ */
271
+ function updateThemeUrl({libInfo, theme, suppressFOUC, force}) {
272
+ if (suppressFOUC) {
273
+ pAllCssRequests = Promise.resolve();
274
+ ThemeManager.themeLoaded = false;
275
+ Log.debug(`Register theme change for library ${libInfo.id}`, undefined, MODULE_NAME);
276
+ }
277
+ if (!sUi5Version && isVersionInfoNeeded()) {
278
+ Log.error("UI5 theming lifecycle requires valid version information when a theming service is active. Please check why the version info could not be loaded in this system.", undefined, MODULE_NAME);
279
+ }
280
+ // Compare the link including the UI5 version only if it is already available; otherwise, compare the link without the version to prevent unnecessary requests.
281
+ const sOldUrl = libInfo.cssLinkElement?.getAttribute("href")?.replace(/\?.*/, "");
282
+ const sUrl = libInfo.getUrl(theme).baseUrl;
283
+ if (!sUrl || sOldUrl !== sUrl || force) {
284
+ libInfo.finishedLoading = false;
285
+ libInfo.failed = false;
286
+ if (suppressFOUC) {
287
+ // Only add stylesheet in case there is no existing stylesheet or the href is different
229
288
  // use the special FOUC handling for initially existing stylesheets
230
289
  // to ensure that they are not just replaced when using the
231
290
  // includeStyleSheet API and to be removed later
232
- fnAddFoucmarker(sLinkId);
233
-
234
- // log and include
235
- Log.info("Including " + sCssPathAndName + " - sap.ui.core.theming.ThemeManager.includeLibraryTheme()");
236
- includeStylesheet(sCssPathAndName, sLinkId);
237
-
238
- // if parameters have been used, update them with the new style sheet
239
- var Parameters = sap.ui.require("sap/ui/core/theming/Parameters");
240
- if (Parameters) {
241
- Parameters._addLibraryTheme(sLibId);
242
- }
243
- ThemeManager.checkThemeApplied();
291
+ fnAddFoucmarker(libInfo.linkId);
244
292
  }
245
- },
246
-
247
- /**
248
- * Returns the URL of the folder in which the CSS file for the given theme and the given library is located.
249
- *
250
- * @param {string} sLibName Library name (dot separated)
251
- * @param {string} sThemeName Theme name
252
- * @returns {string} module path URL (ends with a slash)
253
- * @private
254
- * @ui5-restricted sap.ui.core,sap.ui.support.supportRules.report.DataCollector
255
- */
256
- _getThemePath: function(sLibName, sThemeName) {
257
-
258
- // make sure to register correct theme module path in case themeRoots are defined
259
- _ensureThemeRoot(sLibName, sThemeName);
260
-
261
- // use the library location as theme location
262
- return sap.ui.require.toUrl((sLibName + ".themes." + sThemeName).replace(/\./g, "/") + "/");
263
- },
264
-
265
- /**
266
- * Modify style sheet URLs to point to the given theme, using the current RTL mode
267
- *
268
- * @param {string} sThemeName The name of the theme to update
269
- * @param {boolean} bSuppressFOUC If FOUC-Marker should be added or not
270
- * @private
271
- * @ui5-restricted sap.ui.core.Core
272
- */
273
- _updateThemeUrls: function(sThemeName, bSuppressFOUC) {
274
- // select "our" stylesheets
275
- var oQueryResult = document.querySelectorAll(`link[id^=${_THEME_PREFIX}]`);
276
-
277
- Array.prototype.forEach.call(oQueryResult, function(oHTMLElement) {
278
- updateThemeUrl(oHTMLElement, sThemeName, bSuppressFOUC);
279
- });
280
- },
281
- /**
282
- * Attach to the theme applied event
283
- *
284
- * @param {function(module:sap/ui/core/Theming$AppliedEvent)} fnCallback The event handler
285
- * @private
286
- * @ui5-restricted sap.ui.core
287
- */
288
- _attachThemeApplied: function (fnCallback) {
289
- oEventing.attachEvent("applied", fnCallback);
290
- },
291
- /**
292
- * Detach from the theme applied event
293
- *
294
- * @param {function(module:sap/ui/core/Theming$AppliedEvent)} fnCallback The event handler
295
- * @private
296
- * @ui5-restricted sap.ui.core
297
- */
298
- _detachThemeApplied: function (fnCallback) {
299
- oEventing.detachEvent("applied", fnCallback);
300
- },
301
- /**
302
- * Notify theme change
303
- *
304
- * @private
305
- * @ui5-restricted sap.ui.core
306
- */
307
- fireThemeApplied: function () {
308
- ThemeHelper.reset();
309
- // special hook for resetting theming parameters before the controls get
310
- // notified (lightweight coupling to static Parameters module)
311
- var ThemeParameters = sap.ui.require("sap/ui/core/theming/Parameters");
312
- if (ThemeParameters) {
313
- ThemeParameters._reset(/* bOnlyWhenNecessary= */ true);
314
- }
315
-
316
- oEventing.fireEvent("applied", {
317
- theme: Theming.getTheme()
293
+ const pCssLoaded = libInfo.getUrl(theme).urlPromise.then((sUrl) => {
294
+ if (sUrl) {
295
+ Log.debug(`Add new CSS for library ${libInfo.id} with URL: ${sUrl}`, undefined, MODULE_NAME);
296
+ return includeStylesheet({
297
+ url: force ? sOldUrl : sUrl,
298
+ id: libInfo.linkId
299
+ });
300
+ } else {
301
+ // If there is no URL, a theme fallback must be detected first.
302
+ // We reject here because and add only a placeholder link element to the DOM.
303
+ // The handleThemeFailed function will process this rejection and apply the fallback
304
+ // theme for the library once it has been detected.
305
+ const oLink = document.createElement("link");
306
+ oLink.setAttribute("id", libInfo.linkId);
307
+ oLink.setAttribute("rel", "stylesheet");
308
+ if (libInfo.cssLinkElement) {
309
+ libInfo.cssLinkElement.parentNode.replaceChild(oLink, libInfo.cssLinkElement);
310
+ } else {
311
+ document.head.insertBefore(oLink, document.getElementById(CUSTOM_ID));
312
+ }
313
+ libInfo.cssLinkElement = oLink;
314
+ return Promise.reject();
315
+ }
318
316
  });
319
- }
320
- };
321
317
 
318
+ if (libInfo.cssLoaded) {
319
+ libInfo.cssLoaded.aborted = true;
320
+ }
322
321
 
323
- function checkTheme() {
324
- var sThemeName = Theming.getTheme();
325
- var sPath = ThemeManager._getThemePath("sap.ui.core", sThemeName) + "custom.css";
326
- var bIsStandardTheme = ThemeHelper.isStandardTheme(Theming.getTheme());
327
- var res = true;
328
-
329
- var aFailedLibs = [];
330
-
331
- if (_customCSSAdded && _themeCheckedForCustom === sThemeName) {
332
- // include custom style sheet here because it has already been added using sap/ui/dom/includeStyleSheet
333
- // hence, needs to be checked for successful inclusion, too
334
- mAllLoadedLibraries[_CUSTOMID] = {};
322
+ includeStyleSheetPostProcessing(libInfo, pCssLoaded, suppressFOUC);
335
323
  }
324
+ }
336
325
 
337
- function checkLib(lib) {
338
- var currentRes = ThemeHelper.checkAndRemoveStyle({ prefix: _THEME_PREFIX, id: lib });
339
-
340
- res = res && currentRes;
341
- if (res) {
342
-
343
- /* as soon as css has been loaded, look if there is a flag for custom css inclusion inside, but only
344
- * if this has not been checked successfully before for the same theme
345
- */
346
- // Only need to adjust custom css in case the theme changed or we have no custom.css yet
347
- if (!_customCSSAdded || _themeCheckedForCustom != sThemeName) {
348
- // custom css is only supported for custom themes
349
- if (!bIsStandardTheme && checkCustom(lib)) {
350
- // load custom css available at sap/ui/core/themename/custom.css
351
- var sCustomCssPath = sPath;
352
-
353
- // check for configured query parameters and add them if available
354
- var sLibCssQueryParams = getLibraryCssQueryParams(mAllLoadedLibraries["sap.ui.core"]);
355
- if (sLibCssQueryParams) {
356
- sCustomCssPath += sLibCssQueryParams;
357
- }
358
-
359
- includeStylesheet(sCustomCssPath, _CUSTOMID);
360
- _customCSSAdded = true;
361
- Log.debug("ThemeManager: delivered custom CSS needs to be loaded, Theme not yet applied");
362
- _themeCheckedForCustom = sThemeName;
363
- res = false;
364
- return false;
365
- // only remove custom css in case a custom.css was added
366
- } else if (_customCSSAdded) {
367
- // remove stylesheet once the particular class is not available (e.g. after theme switch)
368
- /*check for custom theme was not successful, so we need to make sure there are no custom style sheets attached*/
369
- var oCustomCssLink = document.querySelector("LINK[id='" + _CUSTOMID + "']");
370
- if (oCustomCssLink) {
371
- oCustomCssLink.remove();
372
- Log.debug("ThemeManager: Custom CSS removed");
326
+ /**
327
+ * Handles post-processing of CSS link elements after they have been requested.
328
+ *
329
+ * This function manages the lifecycle of CSS loading for a library by attaching handlers to the CSS loading promise.
330
+ * It handles success and failure cases, as well as generic post-processing that occurs regardless of the request status.
331
+ * The function is responsible for:
332
+ *
333
+ * 1. Managing the loading state of the CSS for the library
334
+ * 2. Removing FOUC (Flash of Unstyled Content) markers when loading completes
335
+ * 3. Updating references to the CSS link element
336
+ * 4. Triggering appropriate theme lifecycle events (success, failure, completion)
337
+ * 5. Updating the global CSS request promise collection
338
+ * 6. Managing the global theme loaded state
339
+ * 7. Firing the "applied" event when all CSS requests have completed
340
+ *
341
+ * The function uses promise chaining to ensure proper sequencing of operations and to handle
342
+ * both successful and failed CSS loading scenarios. It also includes an abort mechanism to
343
+ * prevent stale CSS requests from affecting the UI when a new request supersedes them.
344
+ *
345
+ * @param {object} libInfo - The library info object containing metadata about the library and its CSS
346
+ * @param {Promise} cssLoadededPromise - The promise that resolves when the CSS has been loaded
347
+ * @param {boolean} suppressFOUC - Whether to suppress Flash of Unstyled Content during theme changes
348
+ */
349
+ function includeStyleSheetPostProcessing(libInfo, cssLoadededPromise, suppressFOUC) {
350
+ libInfo.cssLoaded = cssLoadededPromise.finally(function() {
351
+ if (!libInfo.cssLoaded.aborted) {
352
+ libInfo.finishedLoading = true;
353
+ document.querySelector(`link[data-sap-ui-foucmarker='${libInfo.linkId}']`)?.remove();
354
+ libInfo.cssLinkElement = document.getElementById(`${libInfo.linkId}`);
355
+ Log.debug(`New stylesheet loaded and old stylesheet removed for library: ${libInfo.id}`, undefined, MODULE_NAME);
356
+ }
357
+ }).then(function() {
358
+ if (!libInfo.cssLoaded.aborted) {
359
+ handleThemeSucceeded(libInfo.id);
360
+ }
361
+ }).catch(function() {
362
+ if (!libInfo.cssLoaded.aborted) {
363
+ handleThemeFailed(libInfo.id);
364
+ }
365
+ }).finally(function() {
366
+ if (!libInfo.cssLoaded.aborted) {
367
+ handleThemeFinished(libInfo.id);
368
+ pAllCssRequests = Promise.allSettled([...mAllLoadedLibraries.values()].map((libInfo) => libInfo.cssLoaded));
369
+ pAllCssRequests.finally(function() {
370
+ if (this === pAllCssRequests) {
371
+ Log.debug("Theme change finished", undefined, MODULE_NAME);
372
+ // Even if suppressFOUC is not set, we must fire the event if themeLoaded was previously set to false,
373
+ // because this indicates that at least one theme change was caused by a theming-relevant trigger.
374
+ if (suppressFOUC || !ThemeManager.themeLoaded) {
375
+ ThemeManager.themeLoaded = true;
376
+ oEventing.fireEvent("applied", {
377
+ theme: Theming.getTheme()
378
+ });
373
379
  }
374
- _customCSSAdded = false;
375
380
  }
376
-
377
- }
378
- }
379
-
380
- // Collect all libs that failed to load and no fallback has been applied, yet.
381
- // The fallback relies on custom theme metadata, so it is not done for standard themes
382
- if (!bIsStandardTheme && currentRes && !_mThemeFallback[lib]) {
383
- var oStyle = document.getElementById(`${_THEME_PREFIX}${lib}`);
384
- // Check for error marker (data-sap-ui-ready=false) and that there are no rules
385
- // to be sure the stylesheet couldn't be loaded at all.
386
- // E.g. in case an @import within the stylesheet fails, the error marker will
387
- // also be set, but in this case no fallback should be done as there is a (broken) theme
388
- if (oStyle && oStyle.getAttribute("data-sap-ui-ready") === "false" &&
389
- !(oStyle.sheet && ThemeHelper.hasSheetCssRules(oStyle.sheet))
390
- ) {
391
- aFailedLibs.push(lib);
392
- }
381
+ }.bind(pAllCssRequests));
393
382
  }
383
+ });
384
+ }
394
385
 
386
+ /**
387
+ * Updates all existing CSS link elements to reflect the provided theme.
388
+ *
389
+ * This function iterates over all loaded library info objects and updates their CSS link elements
390
+ * to ensure they point to the correct theme resources. It guarantees that all CSS links are up-to-date
391
+ * with respect to the given theme, RTL mode, SAP UI5 distribution version, and theme roots.
392
+ *
393
+ * @param {string} themeName - The name of the theme to apply.
394
+ * @param {boolean} suppressFOUC - Whether to suppress Flash of Unstyled Content (FOUC) handling.
395
+ */
396
+ function updateThemeUrls(themeName, suppressFOUC) {
397
+ for (const [, libInfo] of mAllLoadedLibraries) {
398
+ updateThemeUrl({libInfo, themeName, suppressFOUC});
395
399
  }
400
+ }
396
401
 
397
- each(mAllLoadedLibraries, checkLib);
398
-
399
- // Try to load a fallback theme for all libs that couldn't be loaded
400
- if (aFailedLibs.length > 0) {
401
- // Only retrieve the fallback theme once per ThemeManager cycle
402
- if (!_sFallbackTheme) {
403
- for (var sLib in mAllLoadedLibraries) {
404
- var oThemeMetaData = ThemeHelper.getMetadata(sLib);
405
- if (oThemeMetaData && oThemeMetaData.Extends && oThemeMetaData.Extends[0]) {
406
- _sFallbackTheme = oThemeMetaData.Extends[0];
407
- } else {
408
- const sThemeRoot = Theming.getThemeRoot(sThemeName, sLib);
409
- if (sThemeRoot) {
410
- const rBaseTheme = /~v=[^\/]+\(([a-zA-Z0-9_]+)\)/;
411
- // base theme should be matched in the first capturing group
412
- _sFallbackTheme = rBaseTheme.exec(sThemeRoot)?.[1];
413
- // pass derived fallback theme through our default theme handling
414
- // in case the fallback theme is not supported anymore, we fall up to the latest default theme
415
- if (_sFallbackTheme) {
416
- _sFallbackTheme = ThemeHelper.validateAndFallbackTheme(_sFallbackTheme);
417
- }
418
- }
419
- }
402
+ /**
403
+ * Handles post-processing after a CSS request for a library has finished loading and was not aborted.
404
+ *
405
+ * This function checks if custom CSS needs to be added or updated for the current theme and performs the necessary actions.
406
+ * It also attempts to derive a fallback theme from the theme root if the requested theme could not be loaded,
407
+ * and applies the fallback theme for the affected library if available.
408
+ *
409
+ * @param {string} libId - The ID of the library whose CSS request has finished.
410
+ */
411
+ function handleThemeFinished(libId) {
412
+ const sThemeName = Theming.getTheme();
413
+ const oLibThemingInfo = mAllLoadedLibraries.get(libId);
414
+ ThemeHelper.reset();
415
+
416
+ if (!_customCSSAdded || _themeCheckedForCustom != sThemeName) {
417
+ if (!ThemeHelper.isStandardTheme(sThemeName) && checkCustom(libId)) {
418
+ const oCustomLibInfo = getLibraryInfo({
419
+ id: CUSTOM_ID
420
+ });
421
+ updateThemeUrl({
422
+ libInfo: oCustomLibInfo,
423
+ suppressFOUC: true
424
+ });
425
+ _customCSSAdded = true;
426
+ _themeCheckedForCustom = sThemeName;
427
+ Log.debug("Delivered custom CSS needs to be loaded, Theme not yet applied", undefined, MODULE_NAME);
428
+ } else if (_customCSSAdded) {
429
+ // remove stylesheet once the particular class is not available (e.g. after theme switch)
430
+ // check for custom theme was not successful, so we need to make sure there are no custom style sheets attached
431
+ document.querySelector(`LINK[id='${CUSTOM_ID}']`)?.remove();
432
+ mAllLoadedLibraries.delete(CUSTOM_ID);
433
+ Log.debug("Custom CSS removed", undefined, MODULE_NAME);
434
+ _customCSSAdded = false;
435
+ }
436
+ }
420
437
 
421
- if (_sFallbackTheme) {
422
- break;
423
- }
438
+ // Only retrieve the fallback theme once per ThemeManager cycle
439
+ if (!_sFallbackThemeFromThemeRoot) {
440
+ const sThemeRoot = Theming.getThemeRoot(sThemeName, libId);
441
+ if (sThemeRoot) {
442
+ const rBaseTheme = /~v=[^\/]+\(([a-zA-Z0-9_]+)\)/;
443
+ // base theme should be matched in the first capturing group
444
+ _sFallbackThemeFromThemeRoot = rBaseTheme.exec(sThemeRoot)?.[1];
445
+
446
+ // pass derived fallback theme through our default theme handling
447
+ // in case the fallback theme is not supported anymore, we fall up to the latest default theme
448
+ if (_sFallbackThemeFromThemeRoot) {
449
+ _sFallbackThemeFromThemeRoot = ThemeHelper.validateAndFallbackTheme(_sFallbackThemeFromThemeRoot);
424
450
  }
425
451
  }
452
+ }
426
453
 
427
- if (_sFallbackTheme) {
428
- aFailedLibs.forEach(function(lib) {
429
- const oStyle = document.getElementById(`${_THEME_PREFIX}${lib}`);
430
-
431
- Log.warning(
432
- "ThemeManager: Custom theme '" + sThemeName + "' could not be loaded for library '" + lib + "'. " +
433
- "Falling back to its base theme '" + _sFallbackTheme + "'."
434
- );
454
+ const sFallbackTheme = _sFallbackThemeFromMetadata || _sFallbackThemeFromThemeRoot;
455
+ if (sFallbackTheme) {
456
+ for (const [sLibId, oLib] of mAllLoadedLibraries) {
457
+ if (oLib.failed) {
458
+ Log.warning(`Custom theme '${sThemeName}' could not be loaded for library '${sLibId}'. Falling back to its base theme '${sFallbackTheme}'.`, undefined, MODULE_NAME);
435
459
 
436
460
  // Change the URL to load the fallback theme
437
- updateThemeUrl(oStyle, _sFallbackTheme);
461
+ updateThemeUrl({
462
+ libInfo: oLib,
463
+ theme: sFallbackTheme,
464
+ suppressFOUC: true
465
+ });
438
466
 
439
467
  // remember the lib to prevent doing the fallback multiple times
440
468
  // (if the fallback also can't be loaded)
441
- _mThemeFallback[lib] = true;
442
- });
469
+ oLibThemingInfo.themeFallback = true;
470
+ }
471
+ }
472
+ }
473
+ }
443
474
 
444
- // Make sure to wait for the fallback themes to be loaded
445
- res = false;
475
+ /**
476
+ * Handles post-processing after a CSS request for a library has successfully finished loading and was not aborted.
477
+ *
478
+ * This function attempts to derive a fallback theme from the theme metadata if the requested theme could not be loaded.
479
+ * The fallback theme is determined from the "Extends" property in the theme metadata.
480
+ *
481
+ * @param {string} libId - The ID of the library whose CSS request has successfully finished.
482
+ */
483
+ function handleThemeSucceeded(libId) {
484
+ if (!_sFallbackThemeFromMetadata) {
485
+ const oThemeMetaData = ThemeHelper.getMetadata(libId);
486
+ if (oThemeMetaData && oThemeMetaData.Extends && oThemeMetaData.Extends[0]) {
487
+ _sFallbackThemeFromMetadata = oThemeMetaData.Extends[0];
446
488
  }
447
489
  }
490
+ }
448
491
 
449
- if (!res) {
450
- Log.debug("ThemeManager: Theme not yet applied.");
451
- } else {
452
- _themeCheckedForCustom = sThemeName;
492
+ /**
493
+ * Handles post-processing after a CSS request for a library has failed and was not aborted.
494
+ *
495
+ * This function detects whether the fallback theme should be requested for the library,
496
+ * based on the current theme and the loading state of the CSS link element.
497
+ *
498
+ * @param {string} libId - The ID of the library whose CSS request has failed.
499
+ */
500
+ function handleThemeFailed(libId) {
501
+ const oLibThemingInfo = getLibraryInfo({id: libId});
502
+ // Collect all libs that failed to load and no fallback has been applied, yet.
503
+ // The fallback relies on custom theme metadata, so it is not done for standard themes
504
+ if (!ThemeHelper.isStandardTheme(Theming.getTheme()) && !oLibThemingInfo.themeFallback) {
505
+ // Check for error marker (data-sap-ui-ready=false) and that there are no rules
506
+ // to be sure the stylesheet couldn't be loaded at all.
507
+ // E.g. in case an @import within the stylesheet fails, the error marker will
508
+ // also be set, but in this case no fallback should be done as there is a (broken) theme
509
+ if (oLibThemingInfo.cssLinkElement && !(oLibThemingInfo.cssLinkElement.sheet && hasSheetCssRules(oLibThemingInfo.cssLinkElement.sheet))) {
510
+ oLibThemingInfo.failed = true;
511
+ }
453
512
  }
454
- return res;
455
513
  }
456
514
 
457
515
  /**
@@ -462,7 +520,7 @@ sap.ui.define([
462
520
  */
463
521
  function checkCustom(lib) {
464
522
 
465
- var cssFile = window.document.getElementById(`${_THEME_PREFIX}${lib}`);
523
+ const cssFile = window.document.getElementById(`${THEME_PREFIX}${lib}`);
466
524
 
467
525
  if (!cssFile) {
468
526
  return false;
@@ -472,28 +530,12 @@ sap.ui.define([
472
530
  Check if custom.css indication rule is applied to <link> element
473
531
  The rule looks like this:
474
532
 
475
- link[id^="sap-ui-theme-"]::after,
476
- .sapUiThemeDesignerCustomCss {
477
- content: '{"customcss" : true}';
478
- }
533
+ link[id^="sap-ui-theme-"]::after
479
534
 
480
- First selector is to apply it to the <link> elements,
481
- the second one for the Safari workaround (see below).
535
+ Selector is to apply it to the <link> elements.
482
536
  */
483
- var style = window.getComputedStyle(cssFile, ':after');
484
- var content = style ? style.getPropertyValue('content') : null;
485
-
486
- if (!content && Device.browser.safari) {
487
-
488
- // Safari has a bug which prevents reading properties of hidden pseudo elements
489
- // As a workaround: Add "sapUiThemeDesignerCustomCss" class on html element
490
- // in order to get the computed "content" value and remove it again.
491
- var html = document.documentElement;
492
-
493
- html.classList.add("sapUiThemeDesignerCustomCss");
494
- content = window.getComputedStyle(html, ":after").getPropertyValue("content");
495
- html.classList.remove("sapUiThemeDesignerCustomCss");
496
- }
537
+ const style = window.getComputedStyle(cssFile, ':after');
538
+ let content = style ? style.getPropertyValue('content') : null;
497
539
 
498
540
  if (content && content !== "none") {
499
541
  try {
@@ -520,16 +562,16 @@ sap.ui.define([
520
562
  * checks if a particular class is available at the beginning of the stylesheet
521
563
  */
522
564
 
523
- var aRules = cssFile.sheet ? ThemeHelper.safeAccessSheetCssRules(cssFile.sheet) : null;
565
+ const aRules = cssFile.sheet ? safeAccessSheetCssRules(cssFile.sheet) : null;
524
566
 
525
567
  if (!aRules || aRules.length === 0) {
526
- Log.warning("Custom check: Failed retrieving a CSS rule from stylesheet " + lib);
568
+ Log.warning(`Custom check: Failed retrieving a CSS rule from stylesheet ${lib}`, undefined, MODULE_NAME);
527
569
  return false;
528
570
  }
529
571
 
530
572
  // we should now have some rule name ==> try to match against custom check
531
- for (var i = 0; (i < 2 && i < aRules.length) ; i++) {
532
- if (CUSTOMCSSCHECK.test(aRules[i].selectorText)) {
573
+ for (let i = 0; (i < 2 && i < aRules.length) ; i++) {
574
+ if (CUSTOM_CSS_CHECK.test(aRules[i].selectorText)) {
533
575
  return true;
534
576
  }
535
577
  }
@@ -537,38 +579,9 @@ sap.ui.define([
537
579
  return false;
538
580
  }
539
581
 
540
- function delayedCheckTheme(bFirst) {
541
- _iCount++;
542
-
543
- var bEmergencyExit = _iCount > maxThemeCheckCycles;
544
-
545
- if (!checkTheme() && !bEmergencyExit) {
546
- // Use dynamic delay to have a fast check for most use cases
547
- // but not cause too much CPU usage for long running css requests
548
- var iDelay;
549
- if (_iCount <= 100) {
550
- iDelay = 2; // 1. Initial interval
551
- } else if (_iCount <= 110) {
552
- iDelay = 500; // 2. After 100 cycles
553
- } else {
554
- iDelay = 1000; // 3. After another 10 cycles (about 5 seconds)
555
- }
556
- _sThemeCheckId = setTimeout(delayedCheckTheme, iDelay);
557
- } else if (!bFirst) {
558
- ThemeManager.reset();
559
- ThemeManager.themeLoaded = true;
560
- ThemeManager.fireThemeApplied();
561
- if (bEmergencyExit) {
562
- future.errorThrows("ThemeManager: max. check cycles reached.");
563
- }
564
- } else {
565
- ThemeManager.themeLoaded = true;
566
- }
567
- }
568
-
569
582
  // helper to add the FOUC marker to the CSS for the given id
570
583
  function fnAddFoucmarker(sLinkId) {
571
- var oLink = document.getElementById(sLinkId);
584
+ const oLink = document.getElementById(sLinkId);
572
585
  if (oLink) {
573
586
  oLink.dataset.sapUiFoucmarker = sLinkId;
574
587
  }
@@ -592,146 +605,142 @@ sap.ui.define([
592
605
  * @param {object} oTheme Theme object containing the old and the new theme
593
606
  * @param {string} oTheme.new Name of the new theme
594
607
  * @param {string} oTheme.old Name of the previous theme
595
- *
596
- * @private
597
608
  */
598
609
  function applyTheme(oTheme) {
599
- var html = document.documentElement;
600
- var sTheme = oTheme.new;
601
- ThemeManager._updateThemeUrls(sTheme, /* bSuppressFOUC */ true);
602
-
603
- // modify the <html> tag's CSS class with the theme name
604
- html.classList.remove("sapUiTheme-" + oTheme.old);
605
- html.classList.add("sapUiTheme-" + sTheme);
606
-
607
- // notify the listeners
608
- ThemeManager.checkThemeApplied();
609
- }
610
-
610
+ const html = document.documentElement;
611
+ const sTheme = oTheme.new;
611
612
 
612
- /**
613
- * Makes sure to register the correct module path for the given library and theme
614
- * in case a themeRoot has been defined.
615
- *
616
- * @param {string} sLibName Library name (dot separated)
617
- * @param {string} sThemeName Theme name
618
- * @private
619
- */
620
- function _ensureThemeRoot(sLibName, sThemeName) {
621
- var sThemeRoot = Theming.getThemeRoot(sThemeName, sLibName);
622
- if (sThemeRoot) {
623
- // check whether for this combination (theme+lib) a URL is registered or for this theme a default location is registered
624
- sThemeRoot = sThemeRoot + (sThemeRoot.slice( -1) == "/" ? "" : "/") + sLibName.replace(/\./g, "/") + "/themes/" + sThemeName + "/";
625
- LoaderExtensions.registerResourcePath((sLibName + ".themes." + sThemeName).replace(/\./g, "/"), sThemeRoot);
613
+ for (const [, oLibInfo] of mAllLoadedLibraries) {
614
+ delete oLibInfo.themeFallback;
626
615
  }
627
- }
616
+ _sFallbackThemeFromMetadata = _sFallbackThemeFromThemeRoot = null;
628
617
 
629
- // this function is also used by "sap.ui.core.theming.ThemeManager" to load a fallback theme for a single library
630
- function updateThemeUrl(oLink, sThemeName, bSuppressFOUC) {
631
- var sLibName,
632
- iQueryIndex = oLink.href.search(/[?#]/),
633
- sLibFileName,
634
- sQuery,
635
- sStandardLibFilePrefix = "library",
636
- sRTL = Localization.getRTL() ? "-RTL" : "",
637
- sHref,
638
- pos;
639
-
640
- // derive lib name from id via regex
641
- var mLinkId = new RegExp(`^${_THEME_PREFIX}(.*)$`, "i").exec(oLink.id);
642
- if (Array.isArray(mLinkId)) {
643
- sLibName = mLinkId[1];
644
- } else {
645
- // fallback to legacy logic
646
- sLibName = oLink.id.slice(_THEME_PREFIX.length);
647
- }
618
+ Log.debug(`ThemeManager: Theme changed from ${oTheme.old} to ${sTheme}`, undefined, MODULE_NAME);
619
+ updateThemeUrls(sTheme, /* bSuppressFOUC */ true);
648
620
 
649
- mAllLoadedLibraries[sLibName] = mAllLoadedLibraries[sLibName] || {};
621
+ // modify the <html> tag's CSS class with the theme name
622
+ html.classList.remove(`sapUiTheme-${oTheme.old}`);
623
+ html.classList.add(`sapUiTheme-${sTheme}`);
624
+ }
650
625
 
651
- if (iQueryIndex > -1) {
652
- // Split href on query and/or fragment to check for the standard lib file prefix
653
- sLibFileName = oLink.href.substring(0, iQueryIndex);
654
- sQuery = oLink.href.substring(iQueryIndex);
655
- } else {
656
- sLibFileName = oLink.href;
657
- sQuery = "";
626
+ function safeAccessSheetCssRules(sheet) {
627
+ try {
628
+ return sheet.cssRules;
629
+ } catch (e) {
630
+ // Firefox throws a SecurityError or InvalidAccessError if "sheet.cssRules"
631
+ // is accessed on a stylesheet with 404 response code.
632
+ // Most browsers also throw when accessing from a different origin (CORS).
633
+ return null;
658
634
  }
635
+ }
659
636
 
660
- // Get basename of stylesheet (e.g. "library.css")
661
- sLibFileName = sLibFileName.substring(sLibFileName.lastIndexOf("/") + 1);
637
+ function hasSheetCssRules(sheet) {
638
+ const aCssRules = safeAccessSheetCssRules(sheet);
639
+ return !!aCssRules && aCssRules.length > 0;
640
+ }
662
641
 
663
- // handle 'variants'
664
- if ((pos = sLibName.indexOf("-[")) > 0) { // assumes that "-[" does not occur as part of a library name
665
- sStandardLibFilePrefix += sLibName.slice(pos + 2, -1); // 2=length of "-]"
666
- sLibName = sLibName.slice(0, pos);
667
- }
642
+ // Collect all UI5 relevant CSS files which have been added upfront
643
+ // and add them to UI5 theming lifecycle
644
+ document.querySelectorAll(`link[id^=${THEME_PREFIX}]`).forEach(function(cssLinkElement) {
645
+ let bPreloadedCssReady = true;
646
+ const sLinkId = cssLinkElement.getAttribute("id");
647
+ const [,libName, variant] = (sLinkId.match(LINK_ID_WITH_VARIANT_CHECK) || sLinkId.match(LINK_ID_CHECK));
648
+ const oLibInfo = getLibraryInfo({
649
+ libName,
650
+ variant,
651
+ linkId: sLinkId
652
+ });
653
+
654
+ Log.info(`Preloaded CSS for library ${libName + (variant ? ` with variant ${variant} ` : "")} detected: ${cssLinkElement.href}`, undefined, MODULE_NAME);
655
+
656
+ const { promise: cssLoaded, resolve, reject } = Promise.withResolvers();
657
+ const handleReady = function(bError) {
658
+ if (bError) {
659
+ reject();
660
+ } else {
661
+ resolve();
662
+ }
663
+ };
668
664
 
669
- // try to distinguish "our" library css from custom css included with the ':' notation in includeLibraryTheme
670
- if ( sLibFileName === (sStandardLibFilePrefix + ".css") || sLibFileName === (sStandardLibFilePrefix + "-RTL.css") ) {
671
- sLibFileName = sStandardLibFilePrefix + sRTL + ".css";
672
- }
665
+ try {
666
+ bPreloadedCssReady = !!(cssLinkElement.sheet?.href === cssLinkElement.href && cssLinkElement.sheet?.cssRules);
673
667
 
674
- // Transform to URL in order to ensure comparison against the fully resolved URL
675
- sHref = new URL(ThemeManager._getThemePath(sLibName, sThemeName) + sLibFileName + sQuery, document.baseURI).toString();
676
- if ( sHref != oLink.href ) {
677
- // sap/ui/dom/includeStylesheet has a special FOUC handling
678
- // which is activated once the attribute data-sap-ui-foucmarker is
679
- // present on the link to be replaced (usage of the Promise
680
- // API is not sufficient as it will change the sync behavior)
681
- if (bSuppressFOUC) {
682
- oLink.dataset.sapUiFoucmarker = oLink.id;
668
+ if (!bPreloadedCssReady) {
669
+ ThemeManager.themeLoaded = bPreloadedCssReady;
670
+ cssLinkElement.addEventListener("load", () => {
671
+ handleReady(false);
672
+ });
673
+ cssLinkElement.addEventListener("error", () => {
674
+ handleReady(true);
675
+ });
676
+ } else {
677
+ handleReady(!(cssLinkElement.sheet.cssRules.length > 0));
683
678
  }
684
- // Replace the current <link> tag with a new one.
685
- // Changing "oLink.href" would also trigger loading the new stylesheet but
686
- // the load/error handlers would not get called which causes issues with the ThemeManager
687
- // as the "data-sap-ui-ready" attribute won't be set.
688
- includeStylesheet(sHref, oLink.id);
689
- }
690
- }
679
+ includeStyleSheetPostProcessing(oLibInfo, cssLoaded, true);
680
+ } catch (e) {
681
+ // If the stylesheet is cross-origin and throws a security error, we can't verify directly
682
+ Log.info("Could not detect ready state of preloaded CSS. Request stylesheet again to verify the response status", undefined, MODULE_NAME);
691
683
 
692
- /**
693
- * Returns a string containing query parameters for theme specific files.
694
- *
695
- * Used in Core#initLibrary and ThemeManager#checkStyle.
696
- *
697
- * @param {object} oLibInfo Library info object (containing a "version" property)
698
- * @returns {string|undefined} query parameters or undefined if "versionedLibCss" config is "false"
699
- * @private
700
- */
701
- function getLibraryCssQueryParams(oLibInfo) {
702
- var sQuery;
703
- if (oLibInfo) {
704
- sQuery = "?version=" + oLibInfo.version;
705
-
706
- // distribution version may not be available (will be loaded in Core constructor syncpoint2)
707
- if (VersionInfo._content) {
708
- sQuery += "&sap-ui-dist-version=" + VersionInfo._content.version;
709
- }
684
+ ThemeManager.themeLoaded = false;
685
+
686
+ updateThemeUrl({
687
+ libInfo: oLibInfo,
688
+ suppressFOUC: true,
689
+ force: true
690
+ });
710
691
  }
711
- return sQuery;
712
- }
692
+ });
713
693
 
714
694
  // set CSS class for the theme name
715
695
  document.documentElement.classList.add("sapUiTheme-" + Theming.getTheme());
716
- Log.info("Declared theme " + Theming.getTheme(), null);
696
+ Log.info(`Declared theme ${Theming.getTheme()}`, undefined, MODULE_NAME);
717
697
 
718
- Theming.attachChange(function(oEvent) {
698
+ attachChange(function(oEvent) {
719
699
  var mThemeRoots = oEvent.themeRoots;
720
700
  var oTheme = oEvent.theme;
701
+ var oLib = oEvent.library;
721
702
  if (mThemeRoots && mThemeRoots.forceUpdate) {
722
- ThemeManager._updateThemeUrls(Theming.getTheme());
703
+ updateThemeUrls(Theming.getTheme());
723
704
  }
724
705
  if (oTheme) {
725
706
  applyTheme(oTheme);
726
707
  }
708
+ if (oLib) {
709
+ includeLibraryTheme(oLib);
710
+ }
727
711
  });
728
712
 
729
- Theming.registerThemeManager(ThemeManager);
713
+ // handle RTL changes
714
+ Localization.attachChange(function(oEvent){
715
+ const bRTL = oEvent.rtl;
716
+ if (bRTL !== undefined) {
717
+ updateThemeUrls(Theming.getTheme());
718
+ }
719
+ });
730
720
 
731
- // Start polling in case preloaded CSS have been detected
732
- if (!ThemeManager.themeLoaded) {
733
- ThemeManager.checkThemeApplied();
734
- }
721
+ registerThemeManager(ThemeManager, (fireApplied) => {
722
+ oEventing.attachEvent("applied", fireApplied);
723
+ });
724
+
725
+ OwnStatics.set(ThemeManager, {
726
+ /**
727
+ * Returns libraryInfoObject
728
+ *
729
+ * @param {string} libInfoId The ID of the libraryInfo object
730
+ * @returns {Map<string, object>|object|undefined} A map with all available libraryInfoObjects, a specific libraryInfoObject
731
+ * or undefined in case a specific libraryInfoObject was requested but does not exists
732
+ * @private
733
+ * @ui5-restricted sap.ui.core.theming.Parameters
734
+ */
735
+ getAllLibraryInfoObjects: (libInfoId) => {
736
+ if (libInfoId) {
737
+ return mAllLoadedLibraries.get(libInfoId);
738
+ }
739
+ const mAllInfoObjects = new Map(mAllLoadedLibraries);
740
+ mAllInfoObjects.delete(CUSTOM_ID);
741
+ return mAllInfoObjects;
742
+ }
743
+ });
735
744
 
736
745
  return ThemeManager;
737
746
  });