From 1e94a9e2a40ae1445d749ea976e10db2b30ff00a Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Wed, 1 Feb 2017 16:02:16 -0600 Subject: [PATCH] serious role position stuff (#1159) * serious role position stuff * kill meh * Update Role.js * Update Guild.js * Update Role.js --- src/client/actions/GuildRoleCreate.js | 1 + src/structures/Guild.js | 27 +++++++-------------------- src/structures/Role.js | 17 ++++++++++++++--- src/util/MoveElementInArray.js | 17 +++++++++++++++++ 4 files changed, 39 insertions(+), 23 deletions(-) create mode 100644 src/util/MoveElementInArray.js diff --git a/src/client/actions/GuildRoleCreate.js b/src/client/actions/GuildRoleCreate.js index 82ea19a3b..0fa07a0fd 100644 --- a/src/client/actions/GuildRoleCreate.js +++ b/src/client/actions/GuildRoleCreate.js @@ -12,6 +12,7 @@ class GuildRoleCreate extends Action { const role = new Role(guild, data.role); guild.roles.set(role.id, role); if (!already) client.emit(Constants.Events.GUILD_ROLE_CREATE, role); + return { role, }; diff --git a/src/structures/Guild.js b/src/structures/Guild.js index 2c4c93b22..e8cc450b1 100644 --- a/src/structures/Guild.js +++ b/src/structures/Guild.js @@ -7,6 +7,7 @@ const Constants = require('../util/Constants'); const Collection = require('../util/Collection'); const cloneObject = require('../util/CloneObject'); const arraysEqual = require('../util/ArraysEqual'); +const moveElementInArray = require('../util/MoveElementInArray'); /** * Represents a guild (or a server) on Discord. @@ -643,9 +644,10 @@ class Guild { * Set the position of a role in this guild * @param {string|Role} role the role to edit, can be a role object or a role ID. * @param {number} position the new position of the role + * @param {boolean} [relative=false] Position moves the role relative to its current position * @returns {Promise} */ - setRolePosition(role, position) { + setRolePosition(role, position, relative = false) { if (typeof role === 'string') { role = this.roles.get(role); if (!role) return Promise.reject(new Error('Supplied role is not a role or string.')); @@ -654,27 +656,12 @@ class Guild { position = Number(position); if (isNaN(position)) return Promise.reject(new Error('Supplied position is not a number.')); - const lowestAffected = Math.min(role.position, position); - const highestAffected = Math.max(role.position, position); + let updatedRoles = Object.assign([], this.roles.array() + .sort((r1, r2) => r1.position !== r2.position ? r1.position - r2.position : r1.id - r2.id)); - const rolesToUpdate = this.roles.filter(r => r.position >= lowestAffected && r.position <= highestAffected); - - // stop role positions getting stupidly inflated - if (position > role.position) { - position = rolesToUpdate.first().position; - } else { - position = rolesToUpdate.last().position; - } - - const updatedRoles = []; - - for (const uRole of rolesToUpdate.values()) { - updatedRoles.push({ - id: uRole.id, - position: uRole.id === role.id ? position : uRole.position + (position < role.position ? 1 : -1), - }); - } + moveElementInArray(updatedRoles, role, position, relative); + updatedRoles = updatedRoles.map((r, i) => ({ id: r.id, position: i })); return this.client.rest.methods.setRolePositions(this.id, updatedRoles); } diff --git a/src/structures/Role.js b/src/structures/Role.js index 92759b552..e0319d896 100644 --- a/src/structures/Role.js +++ b/src/structures/Role.js @@ -48,7 +48,7 @@ class Role { this.hoist = data.hoist; /** - * The position of the role in the role manager + * The position of the role from the API * @type {number} */ this.position = data.position; @@ -122,6 +122,16 @@ class Role { return clientMember.highestRole.comparePositionTo(this) > 0; } + /** + * The position of the role in the role manager + * @type {number} + */ + get calculatedPosition() { + const sorted = this.guild.roles.array() + .sort((r1, r2) => r1.position !== r2.position ? r1.position - r2.position : r1.id - r2.id); + return sorted.indexOf(sorted.find(r => r.id === this.id)); + } + /** * Get an object mapping permission names to whether or not the role enables that permission * @returns {Object} @@ -246,6 +256,7 @@ class Role { /** * Set the position of the role * @param {number} position The position of the role + * @param {boolean} [relative=false] Move the position relative to its current value * @returns {Promise} * @example * // set the position of the role @@ -253,8 +264,8 @@ class Role { * .then(r => console.log(`Role position: ${r.position}`)) * .catch(console.error); */ - setPosition(position) { - return this.guild.setRolePosition(this, position).then(() => this); + setPosition(position, relative) { + return this.guild.setRolePosition(this, position, relative).then(() => this); } /** diff --git a/src/util/MoveElementInArray.js b/src/util/MoveElementInArray.js new file mode 100644 index 000000000..24c4a59ae --- /dev/null +++ b/src/util/MoveElementInArray.js @@ -0,0 +1,17 @@ +/** + * Moves an element in an array *in place* + * @param {Array} array Array to modify + * @param {*} element Element to move + * @param {number} newIndex Index or offset to move the element to + * @param {boolean} [offset=false] Move the element by an offset amount rather than to a set index + * @returns {Array} + */ +module.exports = function moveElementInArray(array, element, newIndex, offset = false) { + const index = array.indexOf(element); + newIndex = (offset ? index : 0) + newIndex; + if (newIndex > -1 && newIndex < array.length) { + const removedElement = array.splice(index, 1)[0]; + array.splice(newIndex, 0, removedElement); + } + return array; +};