1
0
mirror of https://github.com/chylex/TweetDuck.git synced 2025-05-05 02:34:07 +02:00

Add more safety checks to code.js

This commit is contained in:
chylex 2018-07-05 09:05:20 +02:00
parent 41bbe7c51b
commit 20b1b3c895

View File

@ -1,4 +1,4 @@
(function($, $TD, $TDX, TD){ (function($TD, $TDX, $, TD){
// //
// Variable: Current highlighted column jQuery & data objects. // Variable: Current highlighted column jQuery & data objects.
// //
@ -22,7 +22,7 @@
// //
// Variable: DOM object containing the main app element. // Variable: DOM object containing the main app element.
// //
const app = $(document.body).children(".js-app"); const app = typeof $ === "function" && $(document.body).children(".js-app");
// //
// Constant: Column icon classes mapped to their titles. // Constant: Column icon classes mapped to their titles.
@ -65,11 +65,12 @@
}; };
// //
// Function: Returns true if an object has a specified property, otherwise returns false without throwing an error. // Function: Returns true if an object has a specified property, otherwise returns false with a debug-only error message.
// //
const ensurePropertyExists = function(obj, ...chain){ const ensurePropertyExists = function(obj, ...chain){
for(let index = 0; index < chain.length; index++){ for(let index = 0; index < chain.length; index++){
if (!obj.hasOwnProperty(chain[index])){ if (!obj.hasOwnProperty(chain[index])){
debugger;
$TD.crashDebug("Missing property "+chain[index]+" in chain [obj]."+chain.join(".")); $TD.crashDebug("Missing property "+chain[index]+" in chain [obj]."+chain.join("."));
return false; return false;
} }
@ -80,6 +81,20 @@
return true; return true;
}; };
//
// Function: Returns a jQuery object but also shows a debug-only error message if no elements are found.
//
const $$ = function(selector, context){
let result = $(selector, context);
if (!result.length){
debugger;
$TD.crashDebug("No elements were found for selector "+selector);
}
return result;
};
// //
// Function: Retrieves a property of an element with a specified class. // Function: Retrieves a property of an element with a specified class.
// //
@ -101,10 +116,10 @@
$(document).on("uiColumnRendered", function(e, data){ $(document).on("uiColumnRendered", function(e, data){
let icon = data.$column.find(".column-type-icon").first(); let icon = data.$column.find(".column-type-icon").first();
return if icon.length !== 1; return if icon.length !== 1;
let name = Array.prototype.find.call(icon[0].classList, cls => cls.startsWith("icon-")); let name = Array.prototype.find.call(icon[0].classList, cls => cls.startsWith("icon-"));
return if !name; return if !name;
data.$column.attr("data-td-icon", name); data.$column.attr("data-td-icon", name);
data.column._tduck_icon = name; data.column._tduck_icon = name;
}); });
@ -277,6 +292,11 @@
// Function: Shows tweet detail, used in notification context menu. // Function: Shows tweet detail, used in notification context menu.
// //
(function(){ (function(){
return if !ensurePropertyExists(TD, "ui", "updates", "showDetailView");
return if !ensurePropertyExists(TD, "controller", "columnManager", "showColumn");
return if !ensurePropertyExists(TD, "controller", "columnManager", "getByApiid");
return if !ensurePropertyExists(TD, "controller", "clients", "getPreferredClient");
const showTweetDetailInternal = function(column, chirp){ const showTweetDetailInternal = function(column, chirp){
TD.ui.updates.showDetailView(column, chirp, column.findChirp(chirp) || chirp); TD.ui.updates.showDetailView(column, chirp, column.findChirp(chirp) || chirp);
TD.controller.columnManager.showColumn(column.model.privateState.key); TD.controller.columnManager.showColumn(column.model.privateState.key);
@ -393,7 +413,7 @@
// Block: Add TweetDuck buttons to the settings menu. // Block: Add TweetDuck buttons to the settings menu.
// //
onAppReady.push(function(){ onAppReady.push(function(){
$("[data-action='settings-menu']").click(function(){ $$("[data-action='settings-menu']").click(function(){
setTimeout(function(){ setTimeout(function(){
let menu = $(".js-dropdown-content").children("ul").first(); let menu = $(".js-dropdown-content").children("ul").first();
return if menu.length === 0; return if menu.length === 0;
@ -627,6 +647,9 @@
// Block: Update highlighted column and tweet for context menu and other functionality. // Block: Update highlighted column and tweet for context menu and other functionality.
// //
(function(){ (function(){
return if !ensurePropertyExists(TD, "controller", "columnManager", "get");
return if !ensurePropertyExists(TD, "services", "ChirpBase", "TWEET");
const updateHighlightedColumn = function(ele){ const updateHighlightedColumn = function(ele){
highlightedColumnEle = ele; highlightedColumnEle = ele;
highlightedColumnObj = ele ? TD.controller.columnManager.get(ele.attr("data-column")) : null; highlightedColumnObj = ele ? TD.controller.columnManager.get(ele.attr("data-column")) : null;
@ -877,22 +900,28 @@
// //
// Block: Fix scheduled tweets not showing up sometimes. // Block: Fix scheduled tweets not showing up sometimes.
// //
$(document).on("dataTweetSent", function(e, data){ (function(){
if (data.response.state && data.response.state === "scheduled"){ return if !ensurePropertyExists(TD, "controller", "columnManager", "getAll");
let column = Object.values(TD.controller.columnManager.getAll()).find(column => column.model.state.type === "scheduled");
$(document).on("dataTweetSent", function(e, data){
if (data.response.state && data.response.state === "scheduled"){
let column = Object.values(TD.controller.columnManager.getAll()).find(column => column.model.state.type === "scheduled");
if (column){ if (column){
setTimeout(function(){ setTimeout(function(){
column.reloadTweets(); column.reloadTweets();
}, 1000); }, 1000);
}
} }
} });
}); })();
// //
// Block: Hold Shift to restore cleared column. // Block: Hold Shift to restore cleared column.
// //
(function(){ (function(){
return if !ensurePropertyExists(TD, "vo", "Column", "prototype", "clear");
var holdingShift = false; var holdingShift = false;
const updateShiftState = (pressed) => { const updateShiftState = (pressed) => {
@ -916,8 +945,6 @@
} }
}); });
return if !ensurePropertyExists(TD, "vo", "Column", "prototype", "clear");
TD.vo.Column.prototype.clear = prependToFunction(TD.vo.Column.prototype.clear, function(){ TD.vo.Column.prototype.clear = prependToFunction(TD.vo.Column.prototype.clear, function(){
window.setTimeout(resetActiveFocus, 0); // unfocuses the Clear button, otherwise it steals keyboard input window.setTimeout(resetActiveFocus, 0); // unfocuses the Clear button, otherwise it steals keyboard input
@ -933,11 +960,13 @@
// Block: Refocus the textbox after switching accounts. // Block: Refocus the textbox after switching accounts.
// //
onAppReady.push(function(){ onAppReady.push(function(){
const composeInput = $$(".js-compose-text", ".js-docked-compose");
const refocusInput = function(){ const refocusInput = function(){
$(".js-compose-text", ".js-docked-compose").focus(); composeInput.focus();
}; };
$(".js-account-list", ".js-docked-compose").delegate(".js-account-item", "click", function(e){ $$(".js-account-list", ".js-docked-compose").delegate(".js-account-item", "click", function(e){
setTimeout(refocusInput, 0); setTimeout(refocusInput, 0);
}); });
}); });
@ -1048,7 +1077,7 @@
default: throw "Invalid mustache injection operation. Only 'replace', 'append', 'prepend' are supported."; default: throw "Invalid mustache injection operation. Only 'replace', 'append', 'prepend' are supported.";
} }
let prev = TD.mustaches[name]; let prev = TD.mustaches && TD.mustaches[name];
if (!prev){ if (!prev){
$TD.crashDebug("Mustache injection is referencing an invalid mustache: "+name); $TD.crashDebug("Mustache injection is referencing an invalid mustache: "+name);
@ -1141,9 +1170,9 @@
TD.mustaches["media/native_video.mustache"] = '<div class="js-media-gif-container media-item nbfc is-video" style="background-image:url({{imageSrc}})"><video class="js-media-gif media-item-gif full-width block {{#isPossiblySensitive}}is-invisible{{/isPossiblySensitive}}" loop src="{{videoUrl}}"></video><a class="js-gif-play pin-all is-actionable">{{> media/video_overlay}}</a></div>'; TD.mustaches["media/native_video.mustache"] = '<div class="js-media-gif-container media-item nbfc is-video" style="background-image:url({{imageSrc}})"><video class="js-media-gif media-item-gif full-width block {{#isPossiblySensitive}}is-invisible{{/isPossiblySensitive}}" loop src="{{videoUrl}}"></video><a class="js-gif-play pin-all is-actionable">{{> media/video_overlay}}</a></div>';
if (!ensurePropertyExists(TD, "components", "MediaGallery", "prototype", "_loadTweet") || return if !ensurePropertyExists(TD, "components", "MediaGallery", "prototype", "_loadTweet");
!ensurePropertyExists(TD, "components", "BaseModal", "prototype", "setAndShowContainer") || return if !ensurePropertyExists(TD, "components", "BaseModal", "prototype", "setAndShowContainer");
!ensurePropertyExists(TD, "ui", "Column", "prototype", "playGifIfNotManuallyPaused"))return; return if !ensurePropertyExists(TD, "ui", "Column", "prototype", "playGifIfNotManuallyPaused");
var cancelModal = false; var cancelModal = false;
@ -1172,10 +1201,10 @@
if (ensurePropertyExists(TD, "services", "TwitterMedia")){ if (ensurePropertyExists(TD, "services", "TwitterMedia")){
let media = TD.services.TwitterMedia; let media = TD.services.TwitterMedia;
if (!ensurePropertyExists(media, "YOUTUBE_TINY_RE") || return if !ensurePropertyExists(media, "YOUTUBE_TINY_RE");
!ensurePropertyExists(media, "YOUTUBE_LONG_RE") || return if !ensurePropertyExists(media, "YOUTUBE_LONG_RE");
!ensurePropertyExists(media, "YOUTUBE_RE") || return if !ensurePropertyExists(media, "YOUTUBE_RE");
!ensurePropertyExists(media, "SERVICES", "youtube"))return; return if !ensurePropertyExists(media, "SERVICES", "youtube");
media.YOUTUBE_TINY_RE = new RegExp(media.YOUTUBE_TINY_RE.source.replace("http:", "https?:")); media.YOUTUBE_TINY_RE = new RegExp(media.YOUTUBE_TINY_RE.source.replace("http:", "https?:"));
media.YOUTUBE_RE = new RegExp(media.YOUTUBE_LONG_RE.source+"|"+media.YOUTUBE_TINY_RE.source); media.YOUTUBE_RE = new RegExp(media.YOUTUBE_LONG_RE.source+"|"+media.YOUTUBE_TINY_RE.source);
@ -1187,12 +1216,11 @@
// //
onAppReady.push(function(){ onAppReady.push(function(){
let ele = $(`<svg id="td-compose-drawer-pin" viewBox="0 0 24 24" class="icon js-show-tip" data-original-title="Stay open" data-tooltip-position="left"> let ele = $(`<svg id="td-compose-drawer-pin" viewBox="0 0 24 24" class="icon js-show-tip" data-original-title="Stay open" data-tooltip-position="left">
<path d="M9.884,16.959l3.272,0.001l-0.82,4.568l-1.635,0l-0.817,-4.569Z"/> <path d="M9.884,16.959l3.272,0.001l-0.82,4.568l-1.635,0l-0.817,-4.569Z"/>
<rect x="8.694" y="7.208" width="5.652" height="7.445"/> <rect x="8.694" y="7.208" width="5.652" height="7.445"/>
<path d="M16.877,17.448c0,-1.908 -1.549,-3.456 -3.456,-3.456l-3.802,0c-1.907,0 -3.456,1.548 -3.456,3.456l10.714,0Z"/> <path d="M16.877,17.448c0,-1.908 -1.549,-3.456 -3.456,-3.456l-3.802,0c-1.907,0 -3.456,1.548 -3.456,3.456l10.714,0Z"/>
<path d="M6.572,5.676l2.182,2.183l5.532,0l2.182,-2.183l0,-1.455l-9.896,0l0,1.455Z"/> <path d="M6.572,5.676l2.182,2.183l5.532,0l2.182,-2.183l0,-1.455l-9.896,0l0,1.455Z"/>
</svg>` </svg>`).appendTo(".js-docked-compose .js-compose-header");
).appendTo(".js-docked-compose .js-compose-header");
ele.click(function(){ ele.click(function(){
if (TD.settings.getComposeStayOpen()){ if (TD.settings.getComposeStayOpen()){
@ -1213,26 +1241,31 @@
// //
// Block: Make temporary search column appear as the first one and clear the input box. // Block: Make temporary search column appear as the first one and clear the input box.
// //
$(document).on("uiSearchNoTemporaryColumn", function(e, data){ (function(){
if (data.query && data.searchScope !== "users" && !data.columnKey){ return if !ensurePropertyExists(TD, "controller", "columnManager", "_columnOrder");
if ($TDX.openSearchInFirstColumn){ return if !ensurePropertyExists(TD, "controller", "columnManager", "move");
let order = TD.controller.columnManager._columnOrder;
$(document).on("uiSearchNoTemporaryColumn", function(e, data){
if (order.length > 1){ if (data.query && data.searchScope !== "users" && !data.columnKey){
let columnKey = order[order.length-1]; if ($TDX.openSearchInFirstColumn){
let order = TD.controller.columnManager._columnOrder;
order.splice(order.length-1, 1);
order.splice(1, 0, columnKey); if (order.length > 1){
TD.controller.columnManager.move(columnKey, "left"); let columnKey = order[order.length-1];
order.splice(order.length-1, 1);
order.splice(1, 0, columnKey);
TD.controller.columnManager.move(columnKey, "left");
}
}
if (!("tweetduck" in data)){
$(".js-app-search-input").val("");
$(".js-perform-search").blur();
} }
} }
});
if (!("tweetduck" in data)){ })();
$(".js-app-search-input").val("");
$(".js-perform-search").blur();
}
}
});
// //
// Block: Setup global function to add a search column with the specified query. // Block: Setup global function to add a search column with the specified query.
@ -1250,9 +1283,9 @@
// //
onAppReady.push(function(){ onAppReady.push(function(){
let container = $(".js-search-in-popover"); let container = $(".js-search-in-popover");
let hashtags = $(".js-typeahead-topic-list", container); let hashtags = $$(".js-typeahead-topic-list", container);
$(".js-typeahead-user-list", container).insertBefore(hashtags); $$(".js-typeahead-user-list", container).insertBefore(hashtags);
hashtags.addClass("list-divider"); hashtags.addClass("list-divider");
}); });
@ -1269,17 +1302,17 @@
app.click(); // unfocus everything app.click(); // unfocus everything
}; };
$(".js-app-search-input").keydown(function(e){ $$(".js-app-search-input").keydown(function(e){
(e.ctrlKey && e.keyCode === 13) && openSearchExternally(e, $(this)); // enter (e.ctrlKey && e.keyCode === 13) && openSearchExternally(e, $(this)); // enter
}); });
$(".js-perform-search").on("click auxclick", function(e){ $$(".js-perform-search").on("click auxclick", function(e){
(e.ctrlKey || e.button === 1) && openSearchExternally(e, $(".js-app-search-input:visible")); (e.ctrlKey || e.button === 1) && openSearchExternally(e, $(".js-app-search-input:visible"));
}).each(function(){ }).each(function(){
window.TDGF_prioritizeNewestEvent($(this)[0], "click"); window.TDGF_prioritizeNewestEvent($(this)[0], "click");
}); });
$("[data-action='show-search']").on("click auxclick", function(e){ $$("[data-action='show-search']").on("click auxclick", function(e){
(e.ctrlKey || e.button === 1) && openSearchExternally(e, $()); (e.ctrlKey || e.button === 1) && openSearchExternally(e, $());
}); });
}); });
@ -1460,14 +1493,19 @@
// Block: Custom reload function with memory cleanup. // Block: Custom reload function with memory cleanup.
// //
window.TDGF_reload = function(){ window.TDGF_reload = function(){
let session = TD.storage.feedController.getAll() try{
.filter(feed => !!feed.getTopSortIndex()) let session = TD.storage.feedController.getAll()
.reduce((obj, feed) => (obj[feed.privateState.key] = feed.getTopSortIndex(), obj), {}); .filter(feed => !!feed.getTopSortIndex())
.reduce((obj, feed) => (obj[feed.privateState.key] = feed.getTopSortIndex(), obj), {});
$TD.setSessionData("gc", JSON.stringify(session)).then(() => {
window.gc && window.gc(); $TD.setSessionData("gc", JSON.stringify(session)).then(() => {
window.gc && window.gc();
window.location.reload();
});
}catch(err){
$TD.crashDebug("Error saving session during a reload");
window.location.reload(); window.location.reload();
}); }
window.TDGF_reload = function(){}; // redefine to prevent reloading multiple times window.TDGF_reload = function(){}; // redefine to prevent reloading multiple times
}; };
@ -1482,7 +1520,7 @@
state = {}; state = {};
} }
var showMissedNotifications = function(){ const showMissedNotifications = function(){
let tweets = []; let tweets = [];
let columns = {}; let columns = {};
@ -1510,18 +1548,20 @@
} }
}; };
$(document).one("dataColumnsLoaded", function(){ if (ensurePropertyExists(TD, "controller", "columnManager", "getAll")){
let columns = Object.values(TD.controller.columnManager.getAll()); $(document).one("dataColumnsLoaded", function(){
let remaining = columns.length; let columns = Object.values(TD.controller.columnManager.getAll());
let remaining = columns.length;
for(let column of columns){ for(let column of columns){
column.ui.getChirpContainer().one("dataColumnFeedUpdated", () => { column.ui.getChirpContainer().one("dataColumnFeedUpdated", () => {
if (--remaining === 0){ if (--remaining === 0){
setTimeout(showMissedNotifications, 1); setTimeout(showMissedNotifications, 1);
} }
}); });
} }
}); });
}
} }
// //
@ -1571,4 +1611,4 @@
location.href = "https://twitter.com/login?hide_message=true&redirect_after_login=https%3A%2F%2Ftweetdeck.twitter.com%2F%3Fvia_twitter_login%3Dtrue"; location.href = "https://twitter.com/login?hide_message=true&redirect_after_login=https%3A%2F%2Ftweetdeck.twitter.com%2F%3Fvia_twitter_login%3Dtrue";
}; };
} }
})($, $TD, $TDX, TD); })($TD, $TDX, window.$, window.TD || {});