REFACTOR: Remove $.cookie in favor of a local library based on it (#10548)

This helps us out in a few ways:

1. It lessens our reliance on jQuery
2. It's slightly less code because it omits options we don't use
3. It is one less library to import and put into ES6 modules
This commit is contained in:
Robin Ward 2020-08-27 14:07:51 -04:00 committed by GitHub
parent a8502ae1c4
commit c172f2068d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 145 additions and 150 deletions

View File

@ -1,12 +1,14 @@
import Component from "@ember/component"; import Component from "@ember/component";
import cookie from "discourse/lib/cookie";
export default Component.extend({ export default Component.extend({
classNames: ["create-account"], classNames: ["create-account"],
didInsertElement() { didInsertElement() {
this._super(...arguments); this._super(...arguments);
if ($.cookie("email")) { if (cookie("email")) {
this.set("email", $.cookie("email")); this.set("email", cookie("email"));
} }
$(this.element).on("keydown.discourse-create-account", e => { $(this.element).on("keydown.discourse-create-account", e => {

View File

@ -4,6 +4,7 @@ import I18n from "I18n";
import Component from "@ember/component"; import Component from "@ember/component";
import LogsNotice from "discourse/services/logs-notice"; import LogsNotice from "discourse/services/logs-notice";
import EmberObject, { computed } from "@ember/object"; import EmberObject, { computed } from "@ember/object";
import cookie, { removeCookie } from "discourse/lib/cookie";
const _pluginNotices = []; const _pluginNotices = [];
@ -67,8 +68,8 @@ export default Component.extend({
function() { function() {
let notices = []; let notices = [];
if ($.cookie("dosp") === "1") { if (cookie("dosp") === "1") {
$.removeCookie("dosp", { path: "/" }); removeCookie("dosp", { path: "/" });
notices.push( notices.push(
Notice.create({ Notice.create({
text: I18n.t("forced_anonymous"), text: I18n.t("forced_anonymous"),

View File

@ -4,6 +4,7 @@ import discourseComputed from "discourse-common/utils/decorators";
import { popupAjaxError } from "discourse/lib/ajax-error"; import { popupAjaxError } from "discourse/lib/ajax-error";
import showModal from "discourse/lib/show-modal"; import showModal from "discourse/lib/show-modal";
import bootbox from "bootbox"; import bootbox from "bootbox";
import cookie from "discourse/lib/cookie";
export default Component.extend({ export default Component.extend({
classNames: ["group-membership-button"], classNames: ["group-membership-button"],
@ -30,7 +31,7 @@ export default Component.extend({
_showLoginModal() { _showLoginModal() {
this.showLogin(); this.showLogin();
$.cookie("destination_url", window.location.href); cookie("destination_url", window.location.href);
}, },
removeFromGroup() { removeFromGroup() {

View File

@ -1,5 +1,7 @@
import { schedule } from "@ember/runloop"; import { schedule } from "@ember/runloop";
import Component from "@ember/component"; import Component from "@ember/component";
import cookie from "discourse/lib/cookie";
export default Component.extend({ export default Component.extend({
didInsertElement() { didInsertElement() {
this._super(...arguments); this._super(...arguments);
@ -11,8 +13,8 @@ export default Component.extend({
"loginPassword", "loginPassword",
$("#hidden-login-form input[name=password]").val() $("#hidden-login-form input[name=password]").val()
); );
} else if ($.cookie("email")) { } else if (cookie("email")) {
this.set("loginName", $.cookie("email")); this.set("loginName", cookie("email"));
} }
schedule("afterRender", () => { schedule("afterRender", () => {

View File

@ -21,6 +21,7 @@ import { findAll } from "discourse/models/login-method";
import EmberObject from "@ember/object"; import EmberObject from "@ember/object";
import User from "discourse/models/user"; import User from "discourse/models/user";
import { Promise } from "rsvp"; import { Promise } from "rsvp";
import cookie, { removeCookie } from "discourse/lib/cookie";
export default Controller.extend( export default Controller.extend(
ModalFunctionality, ModalFunctionality,
@ -270,7 +271,7 @@ export default Controller.extend(
const destinationUrl = this.get("authOptions.destination_url"); const destinationUrl = this.get("authOptions.destination_url");
if (!isEmpty(destinationUrl)) { if (!isEmpty(destinationUrl)) {
$.cookie("destination_url", destinationUrl, { path: "/" }); cookie("destination_url", destinationUrl, { path: "/" });
} }
// Add the userfields to the data // Add the userfields to the data
@ -326,12 +327,12 @@ export default Controller.extend(
this.rejectedPasswords.pushObject(attrs.accountPassword); this.rejectedPasswords.pushObject(attrs.accountPassword);
} }
this.set("formSubmitted", false); this.set("formSubmitted", false);
$.removeCookie("destination_url"); removeCookie("destination_url");
} }
}, },
() => { () => {
this.set("formSubmitted", false); this.set("formSubmitted", false);
$.removeCookie("destination_url"); removeCookie("destination_url");
return this.flash(I18n.t("create_account.failed"), "error"); return this.flash(I18n.t("create_account.failed"), "error");
} }
); );

View File

@ -7,6 +7,7 @@ import ModalFunctionality from "discourse/mixins/modal-functionality";
import { escapeExpression } from "discourse/lib/utilities"; import { escapeExpression } from "discourse/lib/utilities";
import { extractError } from "discourse/lib/ajax-error"; import { extractError } from "discourse/lib/ajax-error";
import getURL from "discourse-common/lib/get-url"; import getURL from "discourse-common/lib/get-url";
import cookie from "discourse/lib/cookie";
export default Controller.extend(ModalFunctionality, { export default Controller.extend(ModalFunctionality, {
offerHelp: null, offerHelp: null,
@ -18,8 +19,8 @@ export default Controller.extend(ModalFunctionality, {
}, },
onShow() { onShow() {
if ($.cookie("email")) { if (cookie("email")) {
this.set("accountEmailOrUsername", $.cookie("email")); this.set("accountEmailOrUsername", cookie("email"));
} }
}, },

View File

@ -17,6 +17,7 @@ import { extractError } from "discourse/lib/ajax-error";
import { SECOND_FACTOR_METHODS } from "discourse/models/user"; import { SECOND_FACTOR_METHODS } from "discourse/models/user";
import { getWebauthnCredential } from "discourse/lib/webauthn"; import { getWebauthnCredential } from "discourse/lib/webauthn";
import bootbox from "bootbox"; import bootbox from "bootbox";
import cookie, { removeCookie } from "discourse/lib/cookie";
// This is happening outside of the app via popup // This is happening outside of the app via popup
const AuthErrors = [ const AuthErrors = [
@ -187,19 +188,19 @@ export default Controller.extend(ModalFunctionality, {
hiddenLoginForm.querySelector(`input[name=${key}]`).value = value; hiddenLoginForm.querySelector(`input[name=${key}]`).value = value;
}; };
const destinationUrl = $.cookie("destination_url"); const destinationUrl = cookie("destination_url");
const ssoDestinationUrl = $.cookie("sso_destination_url"); const ssoDestinationUrl = cookie("sso_destination_url");
applyHiddenFormInputValue(this.loginName, "username"); applyHiddenFormInputValue(this.loginName, "username");
applyHiddenFormInputValue(this.loginPassword, "password"); applyHiddenFormInputValue(this.loginPassword, "password");
if (ssoDestinationUrl) { if (ssoDestinationUrl) {
$.removeCookie("sso_destination_url"); removeCookie("sso_destination_url");
window.location.assign(ssoDestinationUrl); window.location.assign(ssoDestinationUrl);
return; return;
} else if (destinationUrl) { } else if (destinationUrl) {
// redirect client to the original URL // redirect client to the original URL
$.removeCookie("destination_url"); removeCookie("destination_url");
applyHiddenFormInputValue(destinationUrl, "redirect"); applyHiddenFormInputValue(destinationUrl, "redirect");
} else { } else {
@ -369,10 +370,10 @@ export default Controller.extend(ModalFunctionality, {
// Reload the page if we're authenticated // Reload the page if we're authenticated
if (options.authenticated) { if (options.authenticated) {
const destinationUrl = const destinationUrl =
$.cookie("destination_url") || options.destination_url; cookie("destination_url") || options.destination_url;
if (destinationUrl) { if (destinationUrl) {
// redirect client to the original URL // redirect client to the original URL
$.removeCookie("destination_url"); removeCookie("destination_url");
window.location.href = destinationUrl; window.location.href = destinationUrl;
} else if (window.location.pathname === getURL("/login")) { } else if (window.location.pathname === getURL("/login")) {
window.location = getURL("/"); window.location = getURL("/");

View File

@ -0,0 +1,99 @@
import deprecated from "discourse-common/lib/deprecated";
const pluses = /\+/g;
function parseCookieValue(s) {
if (s.indexOf('"') === 0) {
// This is a quoted cookie as according to RFC2068, unescape...
s = s
.slice(1, -1)
.replace(/\\"/g, '"')
.replace(/\\\\/g, "\\");
}
try {
// Replace server-side written pluses with spaces.
// If we can't decode the cookie, ignore it, it's unusable.
// If we can't parse the cookie, ignore it, it's unusable.
s = decodeURIComponent(s.replace(pluses, " "));
return s;
} catch (e) {}
}
function cookie(key, value, options) {
// Write
if (value !== undefined) {
options = Object.assign({}, options || {});
if (typeof options.expires === "number") {
let days = options.expires,
t = (options.expires = new Date());
t.setTime(+t + days * 864e5);
}
return (document.cookie = [
encodeURIComponent(key),
"=",
encodeURIComponent(String(value)),
options.expires ? "; expires=" + options.expires.toUTCString() : "", // use expires attribute, max-age is not supported by IE
options.path ? "; path=" + options.path : "",
options.domain ? "; domain=" + options.domain : "",
options.secure ? "; secure" : ""
].join(""));
}
// Read
let result = key ? undefined : {};
// To prevent the for loop in the first place assign an empty array
// in case there are no cookies at all. Also prevents odd result when
// calling cookie().
let cookies = document.cookie ? document.cookie.split("; ") : [];
for (let i = 0, l = cookies.length; i < l; i++) {
let parts = cookies[i].split("=");
let name = decodeURIComponent(parts.shift());
let c = parts.join("=");
if (key && key === name) {
result = parseCookieValue(c);
break;
}
// Prevent storing a cookie that we couldn't decode.
if (!key && (c = parseCookieValue(c)) !== undefined) {
result[name] = c;
}
}
return result;
}
export function removeCookie(key, options) {
if (cookie(key) === undefined) {
return false;
}
// Must not alter options, thus extending a fresh object...
cookie(key, "", Object.assign({}, options || {}, { expires: -1 }));
return !cookie(key);
}
if (window && window.$) {
const depOpts = { since: "2.6.0", dropFrom: "2.7.0" };
window.$.cookie = function() {
deprecated(
"$.cookie is being removed from Discourse. Please import our cookie module and use that instead.",
depOpts
);
return cookie(...arguments);
};
window.$.removeCookie = function() {
deprecated(
"$.removeCookie is being removed from Discourse. Please import our cookie module and use that instead.",
depOpts
);
return removeCookie(...arguments);
};
}
export default cookie;

View File

@ -1,5 +1,6 @@
import I18n from "I18n"; import I18n from "I18n";
import deprecated from "discourse-common/lib/deprecated"; import deprecated from "discourse-common/lib/deprecated";
import cookie, { removeCookie } from "discourse/lib/cookie";
const keySelector = "meta[name=discourse_theme_ids]"; const keySelector = "meta[name=discourse_theme_ids]";
@ -34,12 +35,12 @@ export function currentThemeId() {
export function setLocalTheme(ids, themeSeq) { export function setLocalTheme(ids, themeSeq) {
ids = ids.reject(id => !id); ids = ids.reject(id => !id);
if (ids && ids.length > 0) { if (ids && ids.length > 0) {
$.cookie("theme_ids", `${ids.join(",")}|${themeSeq}`, { cookie("theme_ids", `${ids.join(",")}|${themeSeq}`, {
path: "/", path: "/",
expires: 9999 expires: 9999
}); });
} else { } else {
$.removeCookie("theme_ids", { path: "/", expires: 1 }); removeCookie("theme_ids", { path: "/", expires: 1 });
} }
} }

View File

@ -31,6 +31,7 @@ import Site from "discourse/models/site";
import { NotificationLevels } from "discourse/lib/notification-levels"; import { NotificationLevels } from "discourse/lib/notification-levels";
import { escapeExpression } from "discourse/lib/utilities"; import { escapeExpression } from "discourse/lib/utilities";
import { getOwner } from "discourse-common/lib/get-owner"; import { getOwner } from "discourse-common/lib/get-owner";
import cookie, { removeCookie } from "discourse/lib/cookie";
export const SECOND_FACTOR_METHODS = { export const SECOND_FACTOR_METHODS = {
TOTP: 1, TOTP: 1,
@ -874,8 +875,8 @@ const User = RestModel.extend({
@discourseComputed("user_option.text_size_seq", "user_option.text_size") @discourseComputed("user_option.text_size_seq", "user_option.text_size")
currentTextSize(serverSeq, serverSize) { currentTextSize(serverSeq, serverSize) {
if ($.cookie("text_size")) { if (cookie("text_size")) {
const [cookieSize, cookieSeq] = $.cookie("text_size").split("|"); const [cookieSize, cookieSeq] = cookie("text_size").split("|");
if (cookieSeq >= serverSeq) { if (cookieSeq >= serverSeq) {
return cookieSize; return cookieSize;
} }
@ -886,12 +887,12 @@ const User = RestModel.extend({
updateTextSizeCookie(newSize) { updateTextSizeCookie(newSize) {
if (newSize) { if (newSize) {
const seq = this.get("user_option.text_size_seq"); const seq = this.get("user_option.text_size_seq");
$.cookie("text_size", `${newSize}|${seq}`, { cookie("text_size", `${newSize}|${seq}`, {
path: "/", path: "/",
expires: 9999 expires: 9999
}); });
} else { } else {
$.removeCookie("text_size", { path: "/", expires: 1 }); removeCookie("text_size", { path: "/", expires: 1 });
} }
}, },

View File

@ -4,6 +4,7 @@ import DiscourseRoute from "discourse/routes/discourse";
import User from "discourse/models/user"; import User from "discourse/models/user";
import Group from "discourse/models/group"; import Group from "discourse/models/group";
import bootbox from "bootbox"; import bootbox from "bootbox";
import cookie from "discourse/lib/cookie";
export default DiscourseRoute.extend({ export default DiscourseRoute.extend({
beforeModel(transition) { beforeModel(transition) {
@ -58,7 +59,7 @@ export default DiscourseRoute.extend({
} }
}); });
} else { } else {
$.cookie("destination_url", window.location.href); cookie("destination_url", window.location.href);
this.replaceWith("login"); this.replaceWith("login");
} }
} }

View File

@ -1,6 +1,7 @@
import { next } from "@ember/runloop"; import { next } from "@ember/runloop";
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
import Category from "discourse/models/category"; import Category from "discourse/models/category";
import cookie from "discourse/lib/cookie";
export default DiscourseRoute.extend({ export default DiscourseRoute.extend({
beforeModel(transition) { beforeModel(transition) {
@ -58,7 +59,7 @@ export default DiscourseRoute.extend({
} }
} else { } else {
// User is not logged in // User is not logged in
$.cookie("destination_url", window.location.href); cookie("destination_url", window.location.href);
this.replaceWith("login"); this.replaceWith("login");
} }
}, },

View File

@ -13,7 +13,6 @@
//= require favcount.js //= require favcount.js
//= require jquery.ba-resize.js //= require jquery.ba-resize.js
//= require jquery.color.js //= require jquery.color.js
//= require jquery.cookie.js
//= require jquery.fileupload.js //= require jquery.fileupload.js
//= require jquery.iframe-transport.js //= require jquery.iframe-transport.js
//= require jquery.tagsinput.js //= require jquery.tagsinput.js

View File

@ -2,6 +2,7 @@ import I18n from "I18n";
import { acceptance, updateCurrentUser } from "helpers/qunit-helpers"; import { acceptance, updateCurrentUser } from "helpers/qunit-helpers";
import selectKit from "helpers/select-kit-helper"; import selectKit from "helpers/select-kit-helper";
import User from "discourse/models/user"; import User from "discourse/models/user";
import cookie, { removeCookie } from "discourse/lib/cookie";
function preferencesPretender(server, helper) { function preferencesPretender(server, helper) {
server.post("/u/second_factors.json", () => { server.post("/u/second_factors.json", () => {
@ -122,7 +123,7 @@ QUnit.test("update some fields", async assert => {
}); });
QUnit.test("font size change", async assert => { QUnit.test("font size change", async assert => {
$.removeCookie("text_size"); removeCookie("text_size");
const savePreferences = async () => { const savePreferences = async () => {
assert.ok(!exists(".saved"), "it hasn't been saved yet"); assert.ok(!exists(".saved"), "it hasn't been saved yet");
@ -142,12 +143,12 @@ QUnit.test("font size change", async assert => {
await selectKit(".text-size .combobox").selectRowByValue("largest"); await selectKit(".text-size .combobox").selectRowByValue("largest");
assert.ok(document.documentElement.classList.contains("text-size-largest")); assert.ok(document.documentElement.classList.contains("text-size-largest"));
assert.equal($.cookie("text_size"), null, "cookie is not set"); assert.equal(cookie("text_size"), null, "cookie is not set");
// Click save (by default this sets for all browsers, no cookie) // Click save (by default this sets for all browsers, no cookie)
await savePreferences(); await savePreferences();
assert.equal($.cookie("text_size"), null, "cookie is not set"); assert.equal(cookie("text_size"), null, "cookie is not set");
await selectKit(".text-size .combobox").expand(); await selectKit(".text-size .combobox").expand();
await selectKit(".text-size .combobox").selectRowByValue("larger"); await selectKit(".text-size .combobox").selectRowByValue("larger");
@ -155,15 +156,15 @@ QUnit.test("font size change", async assert => {
await savePreferences(); await savePreferences();
assert.equal($.cookie("text_size"), "larger|1", "cookie is set"); assert.equal(cookie("text_size"), "larger|1", "cookie is set");
await click(".text-size input[type=checkbox]"); await click(".text-size input[type=checkbox]");
await selectKit(".text-size .combobox").expand(); await selectKit(".text-size .combobox").expand();
await selectKit(".text-size .combobox").selectRowByValue("largest"); await selectKit(".text-size .combobox").selectRowByValue("largest");
await savePreferences(); await savePreferences();
assert.equal($.cookie("text_size"), null, "cookie is removed"); assert.equal(cookie("text_size"), null, "cookie is removed");
$.removeCookie("text_size"); removeCookie("text_size");
}); });
QUnit.test("username", async assert => { QUnit.test("username", async assert => {

View File

@ -1,117 +0,0 @@
/*!
* jQuery Cookie Plugin v1.4.1
* https://github.com/carhartl/jquery-cookie
*
* Copyright 2013 Klaus Hartl
* Released under the MIT license
*/
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// CommonJS
factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
var pluses = /\+/g;
function encode(s) {
return config.raw ? s : encodeURIComponent(s);
}
function decode(s) {
return config.raw ? s : decodeURIComponent(s);
}
function stringifyCookieValue(value) {
return encode(config.json ? JSON.stringify(value) : String(value));
}
function parseCookieValue(s) {
if (s.indexOf('"') === 0) {
// This is a quoted cookie as according to RFC2068, unescape...
s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
}
try {
// Replace server-side written pluses with spaces.
// If we can't decode the cookie, ignore it, it's unusable.
// If we can't parse the cookie, ignore it, it's unusable.
s = decodeURIComponent(s.replace(pluses, ' '));
return config.json ? JSON.parse(s) : s;
} catch(e) {}
}
function read(s, converter) {
var value = config.raw ? s : parseCookieValue(s);
return $.isFunction(converter) ? converter(value) : value;
}
var config = $.cookie = function (key, value, options) {
// Write
if (value !== undefined && !$.isFunction(value)) {
options = $.extend({}, config.defaults, options);
if (typeof options.expires === 'number') {
var days = options.expires, t = options.expires = new Date();
t.setTime(+t + days * 864e+5);
}
return (document.cookie = [
encode(key), '=', stringifyCookieValue(value),
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
options.path ? '; path=' + options.path : '',
options.domain ? '; domain=' + options.domain : '',
options.secure ? '; secure' : ''
].join(''));
}
// Read
var result = key ? undefined : {};
// To prevent the for loop in the first place assign an empty array
// in case there are no cookies at all. Also prevents odd result when
// calling $.cookie().
var cookies = document.cookie ? document.cookie.split('; ') : [];
for (var i = 0, l = cookies.length; i < l; i++) {
var parts = cookies[i].split('=');
var name = decode(parts.shift());
var cookie = parts.join('=');
if (key && key === name) {
// If second argument (value) is a function it's a converter...
result = read(cookie, value);
break;
}
// Prevent storing a cookie that we couldn't decode.
if (!key && (cookie = read(cookie)) !== undefined) {
result[name] = cookie;
}
}
return result;
};
config.defaults = {};
$.removeCookie = function (key, options) {
if ($.cookie(key) === undefined) {
return false;
}
// Must not alter options, thus extending a fresh object...
$.cookie(key, '', $.extend({}, options, { expires: -1 }));
return !$.cookie(key);
};
}));