vrtc / chorus (public) (License: CC0) (since 2023-08-12) (hash sha1)
World of Warcraft add-on stub. The overall goal is to create a specialized raid frame.
List of commits:
Subject Hash Author Date (UTC)
fix: unify aura button logic 52c88f27f978e6ae528e4d04507f8c73184f904c Vladyslav Bondarenko 2025-01-27 17:50:00
feat!: extend huge unit with more aura buttons 36bba5e5bb7170758410ca3d7e3b619a68591937 Vladyslav Bondarenko 2025-01-17 14:58:43
fix: update TOT aura more frequently 29751221b920518b14a51c9bf1b486f5a177ad4f Vladyslav Bondarenko 2024-12-23 16:59:12
feat: change aura collapse button graphics 7085558a5afbcd942f3a9e368fdb617083304c5d Vladyslav Bondarenko 2024-12-20 22:45:32
fix: bump version 24da29749a723ae0a9025d23974d4ba5edfae720 Vladyslav Bondarenko 2024-12-04 03:43:51
fix: role widget toggle visibility correctly c8393fa228fc07c892993228f4a0b91b06cab319 Vladyslav Bondarenko 2024-12-03 08:00:46
fix: prepare release 0.11.0 c60fa1b56310a13399d60992f8334b0f88490fd1 Vladyslav Bondarenko 2024-12-03 03:56:40
fix: typo in aura frame initializator be11f220fc2d2e009a0be0258c23855993b71f2b Vladyslav Bondarenko 2024-12-02 12:12:55
fix: remove redundant initialization 611d5ec779272d3fcceefdc18852ee0de320e19d Vladyslav Bondarenko 2024-12-02 11:49:28
fix: adjust frames for all resolutions d378a6b25a5e8c87af367e199f57dc4b7781b26f Vladyslav Bondarenko 2024-12-02 11:13:10
fix: adjust buff priorities bfa198b18dfdfaab3db2d0f31e3b794eb52c9b9b Vladyslav Bondarenko 2024-12-02 10:32:14
fix!: remove all taint from aura buttons 198dcbb367596370de36e6ebbcde3c9a1887b657 Vladyslav Bondarenko 2024-07-14 23:21:37
fix: show death knight rune frame at player frame 9949a0bafac5d0f1ccbcd3f80b301977d4fa4e0f Vladyslav Bondarenko 2024-07-14 15:46:33
feat: prepare release 0.10.0 7b12ee714c95d94d9d34dd034fe7c1b27b29fa0e Vladyslav Bondarenko 2024-06-27 12:54:18
fix: raid profile toggle robustness 9cba01bac77db4d383c159136f904fec00f57d43 Vladyslav Bondarenko 2024-06-25 07:11:38
fix: cast bar update robustness e2e7910e0d96eb65aea9a2a3337fa50cecccc45f Vladyslav Bondarenko 2024-06-25 07:11:07
fix!: toggle raid frame 59503ee6ec8744f057e959c026cacb0e39ee62db Vladyslav Bondarenko 2024-06-23 07:58:42
feat!: prepare release 0.9.0 6b15c2a4567dae6b363d69fa84348aa2dbca7b74 Vladyslav Bondarenko 2024-06-18 22:41:56
fix: add UnitIsTapped to known globals list 9536f6ae6bb9f2e4ce1a668f3a55c2ad0a225cb7 Vladyslav Bondarenko 2024-06-18 22:40:45
feat: upgrade cast bar f050d4444480983bfe7475bdafbfeb2c291c3472 Vladyslav Bondarenko 2024-06-18 18:11:20
Commit 52c88f27f978e6ae528e4d04507f8c73184f904c - fix: unify aura button logic
Recently, aura buttons were specialized into two different templates.
Clean up the code to be as explicit and non-redundant as possible.
Author: Vladyslav Bondarenko
Author date (UTC): 2025-01-27 17:50
Committer name: Vladyslav Bondarenko
Committer date (UTC): 2025-01-27 17:50
Parent(s): c7d901fb79e18ba2cfd7181d97c7e9e284ed2036
Signer:
Signing key: EFF9624877D25D02
Signing status: E
Tree: 4f6dc22d2d9ce5acce614aaa6ed563c34b5d92a1
File Lines added Lines deleted
src/ChorusAuraButtonTemplate.lua 155 208
src/ChorusAuraFrameTemplate.lua 7 6
File src/ChorusAuraButtonTemplate.lua changed (mode: 100644) (index 921ac56..427c8ea)
... ... local GameTooltip = GameTooltip
26 26
27 27 local SecureButton_GetUnit = Chorus.test.SecureButton_GetUnit or SecureButton_GetUnit local SecureButton_GetUnit = Chorus.test.SecureButton_GetUnit or SecureButton_GetUnit
28 28
29 --[[--
30 Check given aura button is configured as expected by the rest of the template.
31
32 @function auraButtonValidate
33 @raise assertion exception
34 @tparam frame auraButton aura button
35 @return when successful, nothing; when failed, assertion exception;
36 ]]
37 local function auraButtonValidate(auraButton)
38 assert(auraButton ~= nil)
39
40 assert(auraButton.artwork ~= nil)
41 assert(auraButton.label ~= nil)
42 assert(auraButton.overlay ~= nil)
43 end
44
45 29 --[[-- --[[--
46 30 Render pictogram artwork for this aura button. Render pictogram artwork for this aura button.
47 31
 
... ... That is, when `artworkFile` is `nil`.
55 39 @tparam string artworkFile pathname in Windows format with escape characters; @tparam string artworkFile pathname in Windows format with escape characters;
56 40 ]] ]]
57 41 local function applyArtwork(auraButton, artworkFile) local function applyArtwork(auraButton, artworkFile)
58 auraButtonValidate(auraButton)
42 assert(auraButton ~= nil)
59 43
60 44 if not artworkFile then if not artworkFile then
61 45 artworkFile = "Interface\\Icons\\INV_Misc_QuestionMark" artworkFile = "Interface\\Icons\\INV_Misc_QuestionMark"
62 46 end end
63 assert(artworkFile ~= nil)
64 assert('string' == type(artworkFile))
65 artworkFile = strtrim(artworkFile)
66 assert(string.len(artworkFile) >= 1)
67 assert(string.len(artworkFile) <= 8192)
68 47
69 48 local artwork = auraButton.artwork local artwork = auraButton.artwork
70 49 assert(artwork ~= nil) assert(artwork ~= nil)
 
... ... color coding; in reality, either `player` or `nil`
88 67 @return nothing @return nothing
89 68 ]] ]]
90 69 local function applyOverlay(auraButton, category, owner) local function applyOverlay(auraButton, category, owner)
91 auraButtonValidate(auraButton)
92
93 70 if not category then if not category then
94 71 --[[ Empty string is equivalent to 'none' by default for DebuffTypeColor. ]]-- --[[ Empty string is equivalent to 'none' by default for DebuffTypeColor. ]]--
95 72 category = '' category = ''
 
... ... GetTime`, the instance when the aura effect ends
178 155 @return nothing @return nothing
179 156 ]] ]]
180 157 local function applyDuration(auraButton, now, totalDurationSec, expirationInstance) local function applyDuration(auraButton, now, totalDurationSec, expirationInstance)
181 auraButtonValidate(auraButton)
182
183 158 assert(now ~= nil) assert(now ~= nil)
184 159 assert('number' == type(now)) assert('number' == type(now))
185 160 assert(now >= 0) assert(now >= 0)
 
... ... charges (stacks) of the aura
233 208 @return nothing @return nothing
234 209 ]] ]]
235 210 local function applyChargeQuantity(auraButton, chargeQuantity) local function applyChargeQuantity(auraButton, chargeQuantity)
236 auraButtonValidate(auraButton)
237
238 211 local label = auraButton.label2 local label = auraButton.label2
239 212 assert (label ~= nil) assert (label ~= nil)
240 213
 
... ... local function auraButtonUpdateProcessor(self)
300 273 applyChargeQuantity(self, chargeQuantity) applyChargeQuantity(self, chargeQuantity)
301 274 end end
302 275
303 --[[--
304 Obscure the aura button to the user's eye, without toggling frame visibility
305 mechanically.
306
307 Toggling visibility of a frame is a restricted action. That is, it can only be
308 done in combat by trusted or secure frames. The aura buttons, for the sake of
309 their core features, are not secure or trusted frames. Therefore, they must
310 never be toggled with `Show` or `Hide` frame methods.
311
312 This implementation must also leave to traces in the taint log.
313 (Logs/taint.log)
314
315 @see InCombatLockdown
316 @see issecure
317
318 @function unapply
319 @tparam frame auraButton this aura button
320 @return nothing, only side effects
321 ]]
322 local function unapply(auraButton)
323 assert(auraButton ~= nil)
324
325 auraButton.index = nil
326 auraButton.spell = nil
327
328 local artwork = auraButton.artwork
329 assert(artwork ~= nil)
330 artwork:SetTexture(artwork)
331 artwork:SetAlpha(1)
332
333 --[[ Remaining duration ]]--
334 local label = auraButton.label
335 assert (label ~= nil)
336 label:SetText(nil)
337
338 --[[ Remaining charge quantity ]]--
339 local label2 = auraButton.label2
340 assert (label2 ~= nil)
341 label2:SetText(nil)
342
343 local overlay = auraButton.overlay
344 assert(overlay ~= nil)
345 overlay:SetAlpha(0)
346 end
347
348 --[[--
349 Request relevant aura details, then apply them to the aura button.
350
351 @function apply
352
353 @see auraButtonUpdateProcessor
354
355 @tparam frame auraButton
356
357 @tparam string unitDesignation corresponding unit
358
359 @tparam integer auraIndex positive integer and not zero, sequantial number of a
360 single aura from the list relevant to the unit
361
362 @tparam string filter usually either BUFF or DEBUFF, mutually exclusive
363
364 @return nothing
365 ]]
366 local function apply(auraButton, unitDesignation, auraIndex, filter)
367 auraButtonValidate(auraButton)
368
369 assert(unitDesignation ~= nil)
370 assert('string' == type(unitDesignation))
371 unitDesignation = string.lower(strtrim(unitDesignation))
372 assert(string.len(unitDesignation) >= 1)
373 assert(string.len(unitDesignation) <= 256)
374
375 assert(auraIndex ~= nil)
376 assert('number' == type(auraIndex))
377 auraIndex = math.min(math.max(0, math.abs(math.floor(auraIndex))), 8192)
378
379 assert(filter ~= nil)
380 assert('string' == type(filter))
381 filter = string.upper(strtrim(filter))
382 assert(string.len(filter) >= 1)
383 assert(string.len(filter) <= 256)
384
385 if not UnitExists(unitDesignation) or not UnitIsConnected(unitDesignation) then
386 unapply(auraButton)
387 return
388 end
389
390 local name, _, artworkFile, chargeQuantity, category, durationSec, expirationInstance,
391 owner = UnitAura(unitDesignation, auraIndex, filter)
392 if not name then
393 unapply(auraButton)
394 return
395 end
396
397 applyArtwork(auraButton, artworkFile)
398 applyDuration(auraButton, GetTime(), durationSec, expirationInstance)
399 applyOverlay(auraButton, category, owner)
400 applyChargeQuantity(auraButton, chargeQuantity)
401 end
402
403 276 local function saneUnit(frame) local function saneUnit(frame)
404 277 assert(frame ~= nil) assert(frame ~= nil)
405 278
 
... ... local function saneEvent(eventCategory)
456 329 return eventCategory return eventCategory
457 330 end end
458 331
459 --[[--
460 Process stream of events, filter events only relevant to the aura button.
332 local function auraLargeButtonApply(auraLargeButton, ...)
461 333
462 When aura is added or removed from a unit, given the aura button is assigned to
463 watch that unit, then apply relevant changes to the aura button.
334 assert(auraLargeButton ~= nil)
464 335
465 @function auraButtonEventProcessor
466 @see FrameXML/SecureTemplates.lua:function SecureButton_GetUnit
467 @see apply
468 @tparam frame self the aura button
469 @tparam string eventCategory event category designation of the given event
470 @param unitDesignation vararg, given `UNIT_AURA`, the relevant unit
471 @return nothing
472 ]]
473 function Chorus.auraButtonEventProcessor(self, eventCategory, ...)
474 auraButtonValidate(self)
336 local artworkFile = select(3, ...)
337 local durationSec = select(6, ...)
338 local expirationInstance = select(7, ...)
339 local category = select(5, ...)
340 local owner = select(8, ...)
341 local chargeQuantity = select(4, ...)
475 342
476 local thisUnit = SecureButton_GetUnit(self) or 'none'
477 assert(thisUnit ~= nil)
478 assert('string' == type(thisUnit))
479 thisUnit = string.lower(strtrim(thisUnit))
480 assert(string.len(thisUnit) >= 1)
481 assert(string.len(thisUnit) <= 256)
343 applyArtwork(auraLargeButton, artworkFile)
344 applyDuration(auraLargeButton, GetTime(), durationSec, expirationInstance)
345 applyOverlay(auraLargeButton, category, owner)
346 applyChargeQuantity(auraLargeButton, chargeQuantity)
347 end
482 348
483 assert(eventCategory ~= nil)
484 assert('string' == type(eventCategory))
485 eventCategory = string.upper(strtrim(eventCategory))
486 assert(string.len(eventCategory) >= 1)
487 assert(string.len(eventCategory) <= 256)
349 local function auraTinyButtonApply(auraTinyButton, ...)
350 assert(auraTinyButton ~= nil)
488 351
352 local artworkFile = select(3, ...)
489 353
490 if 'ADDON_LOADED' == tostring(eventCategory) then
491 --[[-- @warning Hardcoded addon name here.
492 ]]
354 applyArtwork(auraTinyButton, artworkFile)
355 end
493 356
494 local loadedAddonName = select(1, ...)
495 local thisAddonName = 'chorus'
496 if thisAddonName ~= tostring(loadedAddonName) then
497 return
498 end
499 elseif 'UNIT_AURA' == tostring(eventCategory) then
500 local otherUnit = select(1, ...)
501 if not UnitIsUnit(thisUnit, otherUnit) then
502 return
503 end
504 end
357 --[[--
358 Change properties of given aura button according to given arguments.
505 359
506 if not UnitExists(thisUnit) or not UnitIsConnected(thisUnit) then
507 unapply(self)
508 return
509 end
360 Use values returned by `UnitAura` for arguments. Assumes sane arguments. Does
361 not check arguments for validity. May produce widget that does not accurately
362 represent game state. Sanity properties should be handled elsewhere.
510 363
511 --[[ Do work. ]]--
512 local i = self.index or 0
513 assert(i ~= nil)
514 assert('number' == type(i))
515 i = math.min(math.max(0, math.abs(math.floor(i))), 8192)
364 The function may ignore some arguments and interpret others differently
365 depending on context.
516 366
517 local filter = SecureButton_GetAttribute(self, 'filter')
518 assert(filter ~= nil)
519 assert('string' == type(filter))
520 filter = string.upper(strtrim(filter))
521 assert(string.len(filter) >= 1)
522 assert(string.len(filter) <= 256)
367 @function auraButtonApply
368 @see auraButtonRefresh
369 @see auraButtonUnapply
370 ]]
371 local function auraButtonApply(auraButton, ...)
372 assert(auraButton ~= nil)
373
374 local strategy = auraButton.strategy
523 375
524 apply(self, thisUnit, i, filter)
376 if 'ChorusAuraLargeButtonTemplate' == strategy then
377 auraLargeButtonApply(auraButton, ...)
378 elseif 'ChorusAuraTinyButtonTemplate' == strategy then
379 auraTinyButtonApply(auraButton, ...)
380 else
381 error('ChorusAuraButtonTemplate.lua: invalid enum: ' ..
382 'unknown aura rendering strategy')
383 end
525 384 end end
526 385
527 local function auraTinyButtonApply(auraTinyButton, artworkFile)
528 assert(auraTinyButton ~= nil)
386 local function auraLargeButtonUnapply(auraLargeButton)
387 assert(auraLargeButton ~= nil)
529 388
530 artworkFile = artworkFile or "Interface\\Icons\\INV_Misc_QuestionMark"
531 assert(artworkFile ~= nil)
389 auraLargeButton.index = nil
390 auraLargeButton.spell = nil
532 391
533 local artwork = auraTinyButton.artwork
392 local artwork = auraLargeButton.artwork
534 393 assert(artwork ~= nil) assert(artwork ~= nil)
394 artwork:SetTexture(artwork)
395 artwork:SetAlpha(1)
535 396
536 artwork:SetTexture(artworkFile)
397 --[[ Remaining duration ]]--
398 local label = auraLargeButton.label
399 assert (label ~= nil)
400 label:SetText(nil)
401
402 --[[ Remaining charge quantity ]]--
403 local label2 = auraLargeButton.label2
404 assert (label2 ~= nil)
405 label2:SetText(nil)
406
407 local overlay = auraLargeButton.overlay
408 assert(overlay ~= nil)
409 overlay:SetAlpha(0)
537 410 end end
538 411
539 412 local function auraTinyButtonUnapply(auraTinyButton) local function auraTinyButtonUnapply(auraTinyButton)
 
... ... local function auraTinyButtonUnapply(auraTinyButton)
549 422 end end
550 423 end end
551 424
552 local function auraTinyButtonRefresh(auraTinyButton)
553 assert(auraTinyButton ~= nil)
425 --[[--
426 Obscure the aura button to the user's eye, without toggling frame visibility
427 mechanically.
428
429 Toggling visibility of a frame is a restricted action. That is, it can only be
430 done in combat by trusted or secure frames. The aura buttons, for the sake of
431 their core features, are not secure or trusted frames. Therefore, they must
432 never be toggled with `Show` or `Hide` frame methods.
433
434 This implementation must also leave to traces in the taint log.
435 (Logs/taint.log)
436
437 @see InCombatLockdown
438 @see issecure
439 @see auraButtonApply
440 @see auraButtonRefresh
441
442 @function auraButtonUnapply
443 @tparam frame auraButton this aura button
444 @return nothing, only side effects
445 ]]
446 local function auraButtonUnapply(auraButton)
447 assert(auraButton ~= nil)
448
449 local strategy = auraButton.strategy
450
451 if 'ChorusAuraLargeButtonTemplate' == strategy then
452 auraLargeButtonUnapply(auraButton)
453 elseif 'ChorusAuraTinyButtonTemplate' == strategy then
454 auraTinyButtonUnapply(auraButton)
455 else
456 error('ChorusAuraButtonTemplate.lua: invalid enum: ' ..
457 'unknown aura rendering strategy')
458 end
459 end
460
461 --[[--
462 Query game state and attempt to update this aura button appropriately.
463
464 May toggle button visibility.
465
466 @see auraButtonApply
467 @see auraButtonUnapply
554 468
555 local u = saneUnit(auraTinyButton)
556 local filter = saneUnitAuraFilter(auraTinyButton)
557 local i = saneUnitAuraIndex(auraTinyButton)
469 @function auraButtonRefresh
470 @tparam frame auraButton this aura button
471 @return nothing, produces side effects
472 ]]
473 local function auraButtonRefresh(auraButton)
474 assert(auraButton ~= nil)
558 475
559 local auraName, _, artworkFile = UnitAura(u, i, filter)
476 local u = saneUnit(auraButton)
477 local filter = saneUnitAuraFilter(auraButton)
478 local i = saneUnitAuraIndex(auraButton)
479
480 local auraName, rank, artworkFile, chargeQuantity, category,
481 durationSec, expirationInstance, owner = UnitAura(u, i, filter)
560 482
561 483 if UnitExists(u) and UnitIsConnected(u) and auraName then if UnitExists(u) and UnitIsConnected(u) and auraName then
562 auraTinyButtonApply(auraTinyButton, artworkFile)
484 auraButtonApply(auraButton, auraName, rank, artworkFile,
485 chargeQuantity, category, durationSec, expirationInstance,
486 owner)
563 487 else else
564 auraTinyButtonUnapply(auraTinyButton)
488 auraButtonUnapply(auraButton)
565 489 end end
566 490 end end
567 491
568 local function auraTinyButtonEventProcessor(auraTinyButton, eventCategory, ...)
569 assert(auraTinyButton ~= nil)
492 --[[--
493 Process stream of events, filter events only relevant to the aura button.
494
495 When aura is added or removed from a unit, given the aura button is assigned to
496 watch that unit, then apply relevant changes to the aura button.
497
498 @function auraButtonEventProcessor
499 @see FrameXML/SecureTemplates.lua:function SecureButton_GetUnit
500 @see auraButtonRefresh
501 @tparam frame auraButton the aura button
502 @tparam string eventCategory event category designation of the given event
503 @param unitDesignation vararg, given `UNIT_AURA`, the relevant unit
504 @return nothing
505 ]]
506 local function auraButtonEventProcessor(auraButton, eventCategory, ...)
507 assert(auraButton ~= nil)
508
509 local e = saneEvent(eventCategory)
570 510
571 511 --[[ Only refresh for the relevant unit. ]]-- --[[ Only refresh for the relevant unit. ]]--
572 512
573 if 'UNIT_AURA' == eventCategory then
513 if 'UNIT_AURA' == e then
574 514 local eventUnit = select(1, ...) local eventUnit = select(1, ...)
575 local thisUnit = saneUnit(auraTinyButton)
515 local thisUnit = saneUnit(auraButton)
576 516 if UnitIsUnit(thisUnit, eventUnit) then if UnitIsUnit(thisUnit, eventUnit) then
577 auraTinyButtonRefresh(auraTinyButton)
517 auraButtonRefresh(auraButton)
578 518 end end
579 519 else else
580 auraTinyButtonRefresh(auraTinyButton)
520 auraButtonRefresh(auraButton)
581 521 end end
582 522 end end
583 523
 
... ... function Chorus.auraLargeButtonMain(self)
652 592 self.label2 = _G[n .. 'Text2'] self.label2 = _G[n .. 'Text2']
653 593 self.overlay = _G[n .. 'Overlay'] self.overlay = _G[n .. 'Overlay']
654 594 end end
655 self:SetScript('OnEvent', Chorus.auraButtonEventProcessor)
595
596 self.strategy = 'ChorusAuraLargeButtonTemplate'
597 self:SetScript('OnEvent', auraButtonEventProcessor)
656 598 self:SetScript('OnUpdate', auraButtonUpdateProcessor) self:SetScript('OnUpdate', auraButtonUpdateProcessor)
657 599 self:RegisterEvent('PLAYER_ENTERING_WORLD') self:RegisterEvent('PLAYER_ENTERING_WORLD')
658 600 self:RegisterEvent('PLAYER_LOGIN') self:RegisterEvent('PLAYER_LOGIN')
659 601 self:RegisterEvent('UNIT_AURA') self:RegisterEvent('UNIT_AURA')
660 auraButtonValidate(self)
661 602
662 603 auraButtonTextScale(self) auraButtonTextScale(self)
663 604 end end
 
... ... function Chorus.auraTinyButtonMain(auraTinyButton)
680 621
681 622 b.artwork = artwork b.artwork = artwork
682 623
624 b.strategy = 'ChorusAuraTinyButtonTemplate'
683 625 b:RegisterEvent('UNIT_AURA') b:RegisterEvent('UNIT_AURA')
684 626 b:RegisterEvent('PLAYER_ENTERING_WORLD') b:RegisterEvent('PLAYER_ENTERING_WORLD')
685 627
686 --[[-- @todo Clean up large and tiny aura button event processors, to
687 reuse code. ]]
628 b:SetScript('OnEvent', auraButtonEventProcessor)
629 end
630
631 function Chorus.auraButtonRefresh(...)
632 return auraButtonRefresh(...)
633 end
688 634
689 b:SetScript('OnEvent', auraTinyButtonEventProcessor)
635 function Chorus.auraButtonEventProcessor(...)
636 return auraButtonEventProcessor(...)
690 637 end end
File src/ChorusAuraFrameTemplate.lua changed (mode: 100644) (index b396732..f4ca424)
... ... buttons are handled by `ChorusAuraButtonTemplate`.
6 6 ]] ]]
7 7
8 8 local Chorus = Chorus local Chorus = Chorus
9 local auraButtonRefresh = Chorus.auraButtonRefresh
9 10
10 11 local SecureButton_GetUnit = Chorus.test.SecureButton_GetUnit or SecureButton_GetUnit local SecureButton_GetUnit = Chorus.test.SecureButton_GetUnit or SecureButton_GetUnit
11 12
 
... ... local function auraFrameEventProcessor(self, eventCategory, ...)
127 128 assert(k >= 0) assert(k >= 0)
128 129 b.index = k b.index = k
129 130
130 local callback = b:GetScript('OnEvent')
131 assert(callback ~= nil)
132 callback(b, eventCategory, ...)
131 --[[ @note Use concrete function instead of `GetScript`
132 callback to hopefully improve performance. Additionally, this
133 approach helps the code to remain simple and explicit. ]]--
134
135 auraButtonRefresh(b)
133 136 end end
134 137
135 138 while (i < #t) do while (i < #t) do
 
... ... local function auraFrameEventProcessor(self, eventCategory, ...)
138 141 assert(b ~= nil) assert(b ~= nil)
139 142 b.index = 0 b.index = 0
140 143
141 local callback = b:GetScript('OnEvent')
142 assert(callback ~= nil)
143 callback(b, eventCategory, ...)
144 auraButtonRefresh(b)
144 145 end end
145 146 end end
146 147
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/vrtc/chorus

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/vrtc/chorus

Clone this repository using git:
git clone git://git.rocketgit.com/user/vrtc/chorus

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main