SecureTemplates.lua

SecureTemplates.lua (8.3.0.32218; unchanged since 8.1.5.29701)
  1. -- The "modified attribute" takes the form of: modifier-name-button
  2. -- The modifier is one of "shift-", "ctrl-", "alt-", and the button is a number from 1 through 5.
  3. --
  4. -- For example, you could set an action that is used for unmodified left click like this:
  5. -- self:SetAttribute("action1", value);
  6. -- You could set an action that is used for shift-right-click like this:
  7. -- self:SetAttribute("shift-action2", value);
  8. --
  9. -- You can also use a wildcard in the place of the modifier or button to denote an attribute
  10. -- that is used for any modifier or any button.
  11. --
  12. -- For example, you could set an action that is used for any left click like this:
  13. -- self:SetAttribute("*action1", value);
  14. -- You could set an action that is used for shift-click with any button like this:
  15. -- self:SetAttribute("shift-action*", value);
  16. --
  17. ATTRIBUTE_NOOP = "";
  18. -- You can exclude an action by explicitly setting its value to ATTRIBUTE_NOOP
  19. --
  20. -- For example, you could set an action that was used for all clicks except ctrl-left-click:
  21. -- self:SetAttribute("*action*", value);
  22. -- self:SetAttribute("shift-action1", ATTRIBUTE_NOOP);
  23. --
  24. -- Setting the attribute by itself is equivalent to *attribute*
  25. -- Internal helper function for modifier parsing
  26. local strsplit = strsplit;
  27. local function ParseSplitModifierString(...)
  28. for i=1, select('#', ...) do
  29. local mod, rep = strsplit(':', (select(i, ...)));
  30. if ( IsModifiedClick(mod) ) then
  31. return rep or mod:lower();
  32. end
  33. end
  34. end
  35. -- Given a modifier string which consists of one or more modifier
  36. -- clauses separated by commas, return the id of the first matching
  37. -- clause. If no modifiers match then nil is returned.
  38. --
  39. -- A modifier clause is of the form MODIFIER or the form MODIFIER:prefix
  40. --
  41. -- e.g.
  42. --
  43. -- "SELFCAST:self,CTRL"
  44. --
  45. -- will return 'self' if the self cast modifier is held down, or 'ctrl' if
  46. -- the control key is held down
  47. function SecureButton_ParseModifierString(msg)
  48. return ParseSplitModifierString(strsplit(',', msg));
  49. end
  50. -- Get the current modifier prefix for a frame (optional), if the frame has
  51. -- a modifiers attribute defined, then it will be parsed using
  52. -- SecureButton_ParseModifiersString and used as the prefix.
  53. --
  54. -- If no frame is specified, or the frame has no modifiers property, then
  55. -- the old style prefix functionality is used.
  56. function SecureButton_GetModifierPrefix(frame)
  57. -- Handle optional frame modifiers attribute
  58. if ( frame ) then
  59. local modlist = frame:GetAttribute("modifiers");
  60. if ( modlist ) then
  61. local prefix = SecureButton_ParseModifierString(modlist);
  62. if ( prefix ) then
  63. return prefix .. "-";
  64. end
  65. end
  66. end
  67. local prefix = "";
  68. if ( IsShiftKeyDown() ) then
  69. prefix = "shift-"..prefix;
  70. end
  71. if ( IsControlKeyDown() ) then
  72. prefix = "ctrl-"..prefix;
  73. end
  74. if ( IsAltKeyDown() ) then
  75. prefix = "alt-"..prefix;
  76. end
  77. return prefix;
  78. end
  79. -- Build lookup table for less common buttons
  80. local BUTTON_LOOKUP_TABLE = {};
  81. for n = 4, 31 do
  82. BUTTON_LOOKUP_TABLE["Button" .. n] = tostring(n);
  83. end
  84. function SecureButton_GetButtonSuffix(button)
  85. if ( button == "LeftButton" ) then
  86. return "1";
  87. elseif ( button == "RightButton" ) then
  88. return "2";
  89. elseif ( button == "MiddleButton" ) then
  90. return "3";
  91. elseif (button and button ~= "") then
  92. local lookup = BUTTON_LOOKUP_TABLE[button];
  93. if ( lookup ) then
  94. return lookup
  95. else
  96. return "-" .. tostring(button);
  97. end
  98. end
  99. return "";
  100. end
  101. function SecureButton_GetModifiedAttribute(frame, name, button, prefix, suffix)
  102. if ( not prefix ) then
  103. prefix = SecureButton_GetModifierPrefix(frame);
  104. end
  105. if ( not suffix ) then
  106. suffix = SecureButton_GetButtonSuffix(button);
  107. end
  108. local value = frame:GetAttribute(prefix, name, suffix);
  109. if ( not value and (frame:GetAttribute("useparent-"..name) or
  110. frame:GetAttribute("useparent*")) ) then
  111. local parent = frame:GetParent();
  112. if ( parent ) then
  113. value = SecureButton_GetModifiedAttribute(parent, name, button, prefix, suffix);
  114. end
  115. end
  116. if ( value == ATTRIBUTE_NOOP ) then
  117. value = nil;
  118. end
  119. return value;
  120. end
  121. function SecureButton_GetAttribute(frame, name)
  122. return SecureButton_GetModifiedAttribute(frame, name, nil, "", "");
  123. end
  124. function SecureButton_GetModifiedUnit(self, button)
  125. local unit = SecureButton_GetModifiedAttribute(self, "unit", button);
  126. if ( unit ) then
  127. local unitsuffix = SecureButton_GetModifiedAttribute(self, "unitsuffix", button);
  128. if ( unitsuffix ) then
  129. unit = unit .. unitsuffix;
  130. -- map raid1pet to raidpet1
  131. unit = gsub(unit, "^([^%d]+)([%d]+)[pP][eE][tT]", "%1pet%2");
  132. unit = gsub(unit, "^[pP][lL][aA][yY][eE][rR][pP][eE][tT]", "pet");
  133. end
  134. local noPet, hadPet = unit:gsub("[pP][eE][tT](%d)", "%1");
  135. if ( hadPet == 0 ) then
  136. noPet, hadPet = unit:gsub("^[pP][eE][tT]", "player");
  137. end
  138. local noPetNoTarget, hadTarget = noPet:gsub("[tT][aA][rR][gG][eE][tT]", "");
  139. if ( UnitHasVehicleUI(noPetNoTarget) and
  140. SecureButton_GetModifiedAttribute(self, "toggleForVehicle", button) and
  141. (noPetNoTarget == noPetNoTarget:gsub("^[mM][oO][uU][sS][eE][oO][vV][eE][rR]", "")
  142. :gsub("^[fF][oO][cC][uU][sS]", "")
  143. :gsub("^[aA][rR][eE][nN][aA]%d", ""))
  144. -- NOTE: using these 3 gsubs is faster than a :lower() call and a table lookup
  145. -- "target" is not included in the above check because it is already filtered out earlier on
  146. ) then
  147. if ( hadPet ~= 0 ) then
  148. unit = noPet;
  149. elseif ( (hadTarget == 0) or SecureButton_GetModifiedAttribute(self, "allowVehicleTarget", button) ) then
  150. unit = unit:gsub("^[pP][lL][aA][yY][eE][rR]", "pet"):gsub("^([%a]+)([%d]+)", "%1pet%2");
  151. end
  152. end
  153. return unit;
  154. end
  155. if ( SecureButton_GetModifiedAttribute(self, "checkselfcast", button) ) then
  156. if ( IsModifiedClick("SELFCAST") ) then
  157. return "player";
  158. end
  159. end
  160. if ( SecureButton_GetModifiedAttribute(self, "checkfocuscast", button) ) then
  161. if ( IsModifiedClick("FOCUSCAST") ) then
  162. return "focus";
  163. end
  164. end
  165. end
  166. function SecureButton_GetUnit(self)
  167. local unit = SecureButton_GetAttribute(self, "unit");
  168. if ( unit ) then
  169. local unitsuffix = SecureButton_GetAttribute(self, "unitsuffix");
  170. if ( unitsuffix ) then
  171. unit = unit .. unitsuffix;
  172. -- map raid1pet to raidpet1
  173. unit = gsub(unit, "^([^%d]+)([%d]+)[pP][eE][tT]", "%1pet%2");
  174. end
  175. return unit;
  176. end
  177. end
  178. function SecureButton_GetEffectiveButton(self)
  179. -- We will be returning to implement this later
  180. return "LeftButton";
  181. end
  182. -- Open a dropdown menu without tainting it in the process
  183. local secureDropdown;
  184. local InitializeSecureMenu = function(self)
  185. local unit = self.unit;
  186. if( not unit ) then return end
  187. local unitType = string.match(unit, "^([a-z]+)[0-9]+$") or unit;
  188. -- Mimic the default UI and prefer the relevant units menu when possible
  189. local menu;
  190. if( unitType == "party" ) then
  191. menu = "PARTY";
  192. elseif( unitType == "boss" ) then
  193. menu = "BOSS";
  194. elseif( unitType == "focus" ) then
  195. menu = "FOCUS";
  196. elseif( unitType == "arenapet" or unitType == "arena" ) then
  197. menu = "ARENAENEMY";
  198. -- Then try and detect the unit type and show the most relevant menu we can find
  199. elseif( UnitIsUnit(unit, "player") ) then
  200. menu = "SELF";
  201. elseif( UnitIsUnit(unit, "vehicle") ) then
  202. menu = "VEHICLE";
  203. elseif( UnitIsUnit(unit, "pet") ) then
  204. menu = "PET";
  205. elseif( UnitIsOtherPlayersBattlePet(unit) ) then
  206. menu = "OTHERBATTLEPET";
  207. elseif( UnitIsOtherPlayersPet(unit) ) then
  208. menu = "OTHERPET";
  209. -- Last ditch checks
  210. elseif( UnitIsPlayer(unit) ) then
  211. if( UnitInRaid(unit) ) then
  212. menu = "RAID_PLAYER";
  213. elseif( UnitInParty(unit) ) then
  214. menu = "PARTY";
  215. else
  216. menu = "PLAYER";
  217. end
  218. elseif( UnitIsUnit(unit, "target") ) then
  219. menu = "TARGET";
  220. end
  221. if( menu ) then
  222. UnitPopup_ShowMenu(self, menu, unit);
  223. end
  224. end
  225. --
  226. -- SecureActionButton
  227. --
  228. -- SecureActionButtons allow you to map different combinations of modifiers and buttons into
  229. -- actions which are executed when the button is clicked.
  230. --
  231. -- For example, you could set up the button to respond to left clicks by targeting the focus:
  232. -- self:SetAttribute("unit", "focus");
  233. -- self:SetAttribute("type1", "target");
  234. --
  235. -- You could set up all other buttons to bring up a menu like this:
  236. -- self:SetAttribute("type*", "menu");
  237. -- self.showmenu = menufunc;
  238. --
  239. -- SecureActionButtons are also able to perform different actions depending on whether you can
  240. -- attack the unit or assist the unit associated with the action button. It does so by mapping
  241. -- mouse buttons into "virtual buttons" based on the state of the unit. For example, you can use
  242. -- the following to cast "Mind Blast" on a left click and "Shadow Word: Death" on a right click
  243. -- if the unit can be attacked:
  244. -- self:SetAttribute("harmbutton1", "nuke1");
  245. -- self:SetAttribute("type-nuke1", "spell");
  246. -- self:SetAttribute("spell-nuke1", "Mind Blast");
  247. -- self:SetAttribute("harmbutton2", "nuke2");
  248. -- self:SetAttribute("type-nuke2", "spell");
  249. -- self:SetAttribute("spell-nuke2", "Shadow Word: Death");
  250. --
  251. -- In this example, we use the special attribute "harmbutton" which is used to map a virtual
  252. -- button when the unit is attackable. We also have the attribute "helpbutton" which is used
  253. -- when the unit can be assisted.
  254. --
  255. -- Although it may not be immediately obvious, we are able to use this new virtual button
  256. -- to set up very complex click behaviors on buttons. For example, we can define a new "heal"
  257. -- virtual button for all friendly left clicks, and then set the button to cast "Flash Heal"
  258. -- on an unmodified left click and "Renew" on a ctrl left click:
  259. -- self:SetAttribute("*helpbutton1", "heal");
  260. -- self:SetAttribute("*type-heal", "spell");
  261. -- self:SetAttribute("spell-heal", "Flash Heal");
  262. -- self:SetAttribute("ctrl-spell-heal", "Renew");
  263. --
  264. -- This system is very powerful, and provides a good layer of abstraction for setting up
  265. -- a button's click behaviors.
  266. local forceinsecure = forceinsecure;
  267. -- Table of supported action functions
  268. local SECURE_ACTIONS = {};
  269. SECURE_ACTIONS.togglemenu = function(self, unit, button)
  270. -- Load the dropdown
  271. if( not secureDropdown ) then
  272. secureDropdown = CreateFrame("Frame", "SecureTemplatesDropdown", nil, "UIDropDownMenuTemplate");
  273. secureDropdown:SetID(1);
  274. UIDropDownMenu_Initialize(secureDropdown, InitializeSecureMenu, "MENU");
  275. end
  276. -- Since we use one dropdown menu for all secure menu actions, if we open a menu on A then click B
  277. -- it will close the menu rather than closing A and opening it on B.
  278. -- This fixes that so it opens it on B while still preserving toggling to close.
  279. if( secureDropdown.openedFor and secureDropdown.openedFor ~= self ) then
  280. CloseDropDownMenus();
  281. end
  282. secureDropdown.unit = string.lower(unit);
  283. secureDropdown.openedFor = self;
  284. ToggleDropDownMenu(1, nil, secureDropdown, "cursor");
  285. end
  286. SECURE_ACTIONS.actionbar =
  287. function (self, unit, button)
  288. local action = SecureButton_GetModifiedAttribute(self, "action", button);
  289. if ( action == "increment" ) then
  290. ActionBar_PageUp();
  291. elseif ( action == "decrement" ) then
  292. ActionBar_PageDown();
  293. elseif ( tonumber(action) ) then
  294. ChangeActionBarPage(action);
  295. else
  296. local a, b = strmatch(action, "^(%d+),%s*(%d+)$");
  297. if ( GetActionBarPage() == tonumber(a) ) then
  298. ChangeActionBarPage(b);
  299. else
  300. ChangeActionBarPage(a);
  301. end
  302. end
  303. end;
  304. SECURE_ACTIONS.action =
  305. function (self, unit, button)
  306. local action = ActionButton_CalculateAction(self, button);
  307. if ( action ) then
  308. -- Save macros in case the one for this action is being edited
  309. securecall("MacroFrame_SaveMacro");
  310. local actionType, flyoutId = GetActionInfo(action);
  311. local cursorType = GetCursorInfo();
  312. if ( actionType == "flyout" and not cursorType ) then
  313. local direction = SecureButton_GetModifiedAttribute(self, "flyoutDirection", button);
  314. SpellFlyout:Toggle(flyoutId, self, direction, 3, true);
  315. else
  316. SpellFlyout:Hide();
  317. UseAction(action, unit, button);
  318. end
  319. end
  320. end;
  321. SECURE_ACTIONS.pet =
  322. function (self, unit, button)
  323. local action =
  324. SecureButton_GetModifiedAttribute(self, "action", button);
  325. if ( action ) then
  326. CastPetAction(action, unit);
  327. end
  328. end;
  329. SECURE_ACTIONS.flyout =
  330. function (self, unit, button)
  331. local flyoutId = SecureButton_GetModifiedAttribute(self, "spell", button);
  332. local direction = SecureButton_GetModifiedAttribute(self, "flyoutDirection", button);
  333. SpellFlyout:Toggle(flyoutId, self, direction, 3, true);
  334. end;
  335. SECURE_ACTIONS.multispell =
  336. function (self, unit, button)
  337. local action = ActionButton_CalculateAction(self, button);
  338. local spell = SecureButton_GetModifiedAttribute(self, "spell", button);
  339. if ( action and spell ) then
  340. SetMultiCastSpell(action, tonumber(spell) or spell);
  341. end
  342. end;
  343. SECURE_ACTIONS.spell =
  344. function (self, unit, button)
  345. local spell = SecureButton_GetModifiedAttribute(self, "spell", button);
  346. local spellID = tonumber(spell);
  347. if ( spellID ) then
  348. CastSpellByID(spellID, unit);
  349. elseif ( spell ) then
  350. CastSpellByName(spell, unit);
  351. end
  352. end;
  353. SECURE_ACTIONS.toy =
  354. function (self, unit, button)
  355. local toy = SecureButton_GetModifiedAttribute(self, "toy", button);
  356. local toyID = tonumber(toy);
  357. if ( toyID ) then
  358. UseToy(toyID);
  359. elseif ( toy ) then
  360. UseToyByName(toy);
  361. end
  362. end;
  363. SECURE_ACTIONS.item =
  364. function (self, unit, button)
  365. local item = SecureButton_GetModifiedAttribute(self, "item", button);
  366. if ( not item ) then
  367. -- Backwards compatibility code, deprecated but still handled for now.
  368. local bag = SecureButton_GetModifiedAttribute(self, "bag", button);
  369. local slot = SecureButton_GetModifiedAttribute(self, "slot", button);
  370. if ( bag and slot ) then
  371. item = bag.." "..slot;
  372. else
  373. item = slot;
  374. end
  375. end
  376. if ( item ) then
  377. local name, bag, slot = SecureCmdItemParse(item);
  378. if ( IsEquippableItem(name) and not IsEquippedItem(name) ) then
  379. EquipItemByName(name);
  380. else
  381. SecureCmdUseItem(name, bag, slot, unit);
  382. end
  383. end
  384. end;
  385. SECURE_ACTIONS.equipmentset =
  386. function (self, unit, button)
  387. local setName = SecureButton_GetModifiedAttribute(self, "equipmentset", button);
  388. local setID = setName and C_EquipmentSet.GetEquipmentSetID(setName);
  389. if ( setID ) then
  390. C_EquipmentSet.UseEquipmentSet(setID);
  391. end
  392. end;
  393. SECURE_ACTIONS.macro =
  394. function (self, unit, button)
  395. local macro = SecureButton_GetModifiedAttribute(self, "macro", button);
  396. if ( macro ) then
  397. -- Save macros in case the one for this action is being edited
  398. securecall("MacroFrame_SaveMacro");
  399. RunMacro(macro, button);
  400. else
  401. local text =
  402. SecureButton_GetModifiedAttribute(self, "macrotext", button);
  403. if ( text ) then
  404. RunMacroText(text, button);
  405. end
  406. end
  407. end;
  408. local CANCELABLE_ITEMS = {
  409. [GetInventorySlotInfo("MainHandSlot")] = 1, -- main hand slot
  410. [GetInventorySlotInfo("SecondaryHandSlot")] = 2, -- off-hand slot
  411. };
  412. SECURE_ACTIONS.cancelaura =
  413. function (self, unit, button)
  414. local spell = SecureButton_GetModifiedAttribute(self, "spell", button);
  415. if ( spell ) then
  416. CancelSpellByName(spell);
  417. else
  418. local slot = tonumber(SecureButton_GetModifiedAttribute(self, "target-slot", button));
  419. if ( slot and CANCELABLE_ITEMS[slot] ) then
  420. CancelItemTempEnchantment(CANCELABLE_ITEMS[slot]);
  421. else
  422. local index = SecureButton_GetModifiedAttribute(self, "index", button) or self:GetID();
  423. if ( index ) then
  424. CancelUnitBuff("player", index, SecureButton_GetModifiedAttribute(self, "filter", button));
  425. end
  426. end
  427. end
  428. end;
  429. SECURE_ACTIONS.leavevehicle =
  430. function (self, unit, button)
  431. VehicleExit();
  432. end;
  433. SECURE_ACTIONS.destroytotem =
  434. function(self, unit, button)
  435. DestroyTotem(SecureButton_GetModifiedAttribute(self, "totem-slot", button));
  436. end;
  437. SECURE_ACTIONS.stop =
  438. function (self, unit, button)
  439. if ( SpellIsTargeting() ) then
  440. SpellStopTargeting();
  441. end
  442. end;
  443. SECURE_ACTIONS.target =
  444. function (self, unit, button)
  445. if ( unit ) then
  446. if ( unit == "none" ) then
  447. ClearTarget();
  448. elseif ( SpellIsTargeting() ) then
  449. SpellTargetUnit(unit);
  450. elseif ( CursorHasItem() ) then
  451. DropItemOnUnit(unit);
  452. else
  453. TargetUnit(unit);
  454. end
  455. end
  456. end;
  457. SECURE_ACTIONS.focus =
  458. function (self, unit, button)
  459. return FocusUnit(unit);
  460. end;
  461. SECURE_ACTIONS.assist =
  462. function (self, unit, button)
  463. return AssistUnit(unit);
  464. end;
  465. local function SecureAction_ManageAssignment(assignment, action, unit)
  466. if ( not action or action == "set" ) then
  467. SetPartyAssignment(assignment, unit);
  468. elseif ( action == "clear" ) then
  469. ClearPartyAssignment(assignment, unit);
  470. elseif ( action == "toggle" ) then
  471. if ( GetPartyAssignment(assignment, unit) ) then
  472. ClearPartyAssignment(assignment, unit);
  473. else
  474. SetPartyAssignment(assignment, unit);
  475. end
  476. end
  477. end
  478. SECURE_ACTIONS.maintank =
  479. function (self, unit, button)
  480. local action = SecureButton_GetModifiedAttribute(self, "action", button);
  481. SecureAction_ManageAssignment("maintank", action, unit);
  482. end;
  483. SECURE_ACTIONS.mainassist =
  484. function (self, unit, button)
  485. local action = SecureButton_GetModifiedAttribute(self, "action", button);
  486. SecureAction_ManageAssignment("mainassist", action, unit);
  487. end;
  488. SECURE_ACTIONS.click =
  489. function (self, unit, button)
  490. local delegate =
  491. SecureButton_GetModifiedAttribute(self, "clickbutton", button);
  492. if ( delegate and not delegate:IsForbidden() ) then
  493. delegate:Click(button);
  494. end
  495. end;
  496. SECURE_ACTIONS.attribute =
  497. function (self, unit, button)
  498. local frame =
  499. SecureButton_GetModifiedAttribute(self, "attribute-frame", button);
  500. if ( not frame ) then
  501. frame = self;
  502. end
  503. local name =
  504. SecureButton_GetModifiedAttribute(self, "attribute-name", button);
  505. local value =
  506. SecureButton_GetModifiedAttribute(self, "attribute-value", button);
  507. if ( name ) then
  508. frame:SetAttribute(name, value);
  509. end
  510. end;
  511. SECURE_ACTIONS.worldmarker =
  512. function(self, unit, button)
  513. local marker = tonumber(SecureButton_GetModifiedAttribute(self, "marker", button));
  514. local action = SecureButton_GetModifiedAttribute(self, "action", button) or "toggle";
  515. if ( action == "set" ) then
  516. PlaceRaidMarker(marker or 1);
  517. elseif ( action == "clear" ) then
  518. ClearRaidMarker(marker);
  519. elseif ( action == "toggle" ) then
  520. marker = marker or 1;
  521. if ( IsRaidMarkerActive(marker) ) then
  522. ClearRaidMarker(marker);
  523. else
  524. PlaceRaidMarker(marker);
  525. end
  526. end
  527. end;
  528. function SecureActionButton_OnClick(self, button, down)
  529. -- TODO check with Tom etc if this is kosher
  530. if (down) then
  531. -- remap the button if desired for up-down behaviors. This behavior may not be safe and has been deferred.
  532. button = SecureButton_GetModifiedAttribute(self, "downbutton", button) or button
  533. end
  534. -- Lookup the unit, based on the modifiers and button
  535. local unit = SecureButton_GetModifiedUnit(self, button);
  536. -- Remap button suffixes based on the disposition of the unit (contributed by Iriel and Cladhaire)
  537. if ( unit ) then
  538. local origButton = button;
  539. if ( UnitCanAttack("player", unit) )then
  540. button = SecureButton_GetModifiedAttribute(self, "harmbutton", button) or button;
  541. elseif ( UnitCanAssist("player", unit) )then
  542. button = SecureButton_GetModifiedAttribute(self, "helpbutton", button) or button;
  543. end
  544. -- The unit may have changed based on button remapping
  545. if ( button ~= origButton ) then
  546. unit = SecureButton_GetModifiedUnit(self, button);
  547. end
  548. end
  549. -- Don't do anything if our unit doesn't exist
  550. if ( unit and unit ~= "none" and not UnitExists(unit) ) then
  551. return;
  552. end
  553. -- Lookup the action type, based on the modifiers and button
  554. local actionType = SecureButton_GetModifiedAttribute(self, "type", button);
  555. -- Perform the requested action!
  556. if ( actionType ) then
  557. local atRisk = false;
  558. local handler = SECURE_ACTIONS[actionType]
  559. if ( not handler ) then
  560. atRisk = true; -- user-provided function, be careful
  561. -- GMA call allows generic click handler snippets
  562. handler = SecureButton_GetModifiedAttribute(self, "_"..actionType, button);
  563. end
  564. if ( not handler ) then
  565. atRisk = false;
  566. -- functions retrieved from table keys carry their own taint
  567. handler = rawget(self, actionType);
  568. end
  569. if ( type(handler) == 'function' ) then
  570. if ( atRisk ) then
  571. forceinsecure();
  572. end
  573. -- actionType arg removed for 4,0
  574. handler(self, unit, button);
  575. elseif ( type(handler) == 'string' ) then
  576. SecureHandler_OnClick(self, "_"..actionType, button, down);
  577. end
  578. end
  579. -- Target predefined item, if we just cast a spell that targets an item
  580. if ( SpellCanTargetItem() or SpellCanTargetItemID() ) then
  581. local bag = SecureButton_GetModifiedAttribute(self, "target-bag", button);
  582. local slot = SecureButton_GetModifiedAttribute(self, "target-slot", button);
  583. if ( slot ) then
  584. if ( bag ) then
  585. UseContainerItem(bag, slot);
  586. else
  587. UseInventoryItem(slot);
  588. end
  589. else
  590. local item = SecureButton_GetModifiedAttribute(self, "target-item", button);
  591. if ( item ) then
  592. SpellTargetItem(item);
  593. end
  594. end
  595. end
  596. end
  597. function SecureUnitButton_OnLoad(self, unit, menufunc)
  598. self:SetAttribute("*type1", "target");
  599. self:SetAttribute("*type2", "menu");
  600. self:SetAttribute("unit", unit);
  601. self.menu = menufunc;
  602. end
  603. function SecureUnitButton_OnClick(self, button)
  604. local type = SecureButton_GetModifiedAttribute(self, "type", button);
  605. if ( type == "menu" or type == "togglemenu" ) then
  606. if ( SpellIsTargeting() ) then
  607. SpellStopTargeting();
  608. return;
  609. end
  610. end
  611. SecureActionButton_OnClick(self, button);
  612. end