Module:UI/Core

local loader = require('Module:Loader')

local makeClass, yesno, inventorySlot, random = loader.require('Class', 'Yesno', 'Inventory slot', 'Random') local colorData = loader.loadData('Color/Data') local slot = inventorySlot.slot

local backslashSubstitute = function(s) -- substitute every '\ ' but those that have special meaning for tooltips generation, e.g. '\&' s = s:gsub('\\\\', '\254'):gsub('\\([^&/])', '%1'):gsub('\254', '\\\\') return s end local backslashSubstituteStrict = function (s) -- substitute all '\ ' s = s:gsub('\\\\', '\254'):gsub('\\(.)', '%1'):gsub('\254', '\\\\') return s end

- -- Main Interface Class - local Interface = makeClass('Interface', {	aprilFools = false,	-	-- constructor(topText: string, id?: string, goBack?: table, hide?: boolean, fill?: boolean, rows?: number, cols?: number)	-- 	-- Constructor function for the methods provided. Creates the actual UI.	-	constructor = function (self, ...)		local topText, id, goBack, hide, fill, rows, cols, noarrow, noclose, arrow_, close_		if type(({...})[1]) == 'table' then			local u = ({...})[1]			topText, id, goBack, hide, fill, rows, cols, noarrow, noclose, arrow_, close_ =				u.topText or u[1],				u.id,				type(u.goBack) == 'table' and u.goBack or {					text = u.return_text or u.goback_text or u['return'] or u.goback,					link = u.return_link or u.goback_link,					id = u.return_id or u.goback_id,				},				u.hide,				u.fill,				u.rows,				u.cols,				u.noarrow,				u.noclose,				u.arrow or u.arrow_,				u.close or u.close_		else			topText, id, goBack, hide, fill, rows, cols, noarrow, noclose, arrow_, close_ = ... end goBack = goBack or {} rows, cols = tonumber(rows) or 6, tonumber(cols) or 9 fill, noarrow, noclose = yesno(fill, true), yesno(noarrow, false), yesno(noclose, false) local arrowX, arrowY, closeX, closeY self.randomColor = colorData.MCColors[random.number{16}] -- for april fools only self.hide = yesno(hide) self.id = id		self.slots = {} self.custom = {} self.wt = mw.html.create('table') :attr{ class='mcui mcui-Crafting_Table pixel-image' } :css{ ['margin'] = '0 auto', ['display'] = 'table', }			:tag('tr') :css{ ['position'] = 'absolute', ['margin-top'] = '-8px', }				:tag('td') :attr{ colspan = cols, class = 'noselect', ['data-font-size'] = 14 } :css{ ['font-family'] = 'minecraft', ['color'] = '#2B2D2F', ['font-size'] = '14px', ['letter-spacing'] = '.2px', }					:wikitext(backslashSubstituteStrict(topText)) :done :done if arrow_ then if yesno(arrow_) or arrow_:match('[Nn]one') then noarrow = true else if arrow_:match('^%d+%s*,%s*%d+$') then arrowX, arrowY = arrow_:match('^(%d+)%s*,%s*(%d+)$') end end end arrowX = tonumber(arrowX) or rows arrowY = tonumber(arrowY) or 4 if close_ then if yesno(close_) or close_:match('[Nn]one') then noclose = true else if close_:match('^%d+%s*,%s*%d+$') then closeX, closeY = close_:match('^(%d+)%s*,%s*(%d+)$') end end end closeX = tonumber(closeX) or rows closeY = tonumber(closeY) or 5 for x = 1, rows, 1 do			self.slots[x] = {} self.custom[x] = {} for y = 1, cols, 1 do				if not noarrow and x == arrowX and y == arrowY then self:setSlot(x, y, {						'Go Back',						text = goBack.text,						link = goBack.link or 'none',						title = '&aGo Back',						class = goBack.id and 'goto-'..goBack.id:gsub('^goto%-', ''),					}) elseif not noclose and x == closeX and y == closeY then self:setSlot(x, y, { 'Close' }) else if not fill then self:setEmptySlot(x, y)					else self:setBlankSlot(x, y)					end end end end end, -	-- setSlot(x: number, y: number, args: table, isCustom?: boolean) -- 	-- Sets a slot according to the `x` and `y` parameters provided, with the arguments -- to the parser as `args`. -	setSlot = function (self, x, y, args, isCustom) checkType(1, x, 'number') checkType(2, y, 'number') checkType(3, args, { 'table', 'string' }) local tp = type(args) if tp == 'table' or (tp == 'string' and args:match('.-')) then self.slots[x] = self.slots[x] or {} self.custom[x] = self.custom[x] or {} self.slots[x][y] = args self.custom[x][y] = not not isCustom elseif tp == 'string' then assertTrue(self.slots[x] and self.slots[x][y], 'slot in posistion (%d, %d) does not exist', 2, x, y)[args] = isCustom end return self end, -	-- getSlot(x: number, y: number, prop?: string) -- 	-- Gets a slot according to the `x` and `y` parameters provided, with an option parameter -- of `prop` to get a particular slot property. -	getSlot = function (self, x, y, prop) if prop then return assertTrue(self.slots[x] and self.slots[x][y], 'slot in posistion (%d, %d) does not exist', 2, x, y)[prop] else return self.slots[x][y] end end, -	-- hasSlot(x: number, y: number) -- 	-- Checks if the UI has a specific slot based on `x` and `y`. -	hasSlot = function (self, x, y)		return not not self.slots[x][y] end, -	-- isEmptySlot(x: number, y: number) -- 	-- Checks if a slot based on `x` and `y` is not blank. -	isEmptySlot = function (x, y)		return self.slots[x][y] and self.slots[x][y] ~= '' and self.slots[x][y] ~= 'Blank' end, -	-- setBlankSlot(x: number, y: number) -- 	-- Sets a blank slot according to the `x` and `y` parameters provided. -	setBlankSlot = function (self, x, y)		if self.aprilFools then return self:setSlot(x, y, { ('Blank (%s)'):format(self.randomColor) }) end return self:setSlot(x, y, { 'Blank' }) end, -	-- setEmptySlot(x: number, y: number) -- 	-- Sets a empty slot according to the `x` and `y` parameters provided. -	setEmptySlot = function (self, x, y)		return self:setSlot(x, y, { '' }) end, -	-- __tostring -- 	-- __tostring metamethod for the class. Parses the `slots` to an acual string. -	__tostring = function (self) for x, xValue in ipairs(self.slots) do			local row = self.wt:tag('tr') :addClass('mcui-row') :css{ ['margin-top'] = x == 1 and '24px' or nil }			for y, yValue in ipairs(xValue) do				row:tag('td') :wikitext(backslashSubstitute(self.custom[x][y] and yValue or slot(yValue))) :done end row:done end return self.id			and tostring(mw.html.create('div')				:node(self.wt)				:attr{ 					id = self.id and 'ui-' .. self.id:gsub('^ui%-', ''), 					class = self.id and 'sbw-ui-tab-content', 					style = self.hide and 'display: none;' or nil,				} 			:done) or tostring(self.wt) end, })

return Interface