Compare commits
128 Commits
Author | SHA1 | Date | |
---|---|---|---|
746eba185b | |||
82dec92510 | |||
2edc93df47 | |||
c5a6738199 | |||
dfd578165b | |||
285d400f69 | |||
47a3444ace | |||
0ec227da52 | |||
f9cf582306 | |||
b0883229bf | |||
31b5d9a4c0 | |||
6841a78556 | |||
9d2089a8ce | |||
6d6bb79199 | |||
937c8e22c4 | |||
34c8d44dfe | |||
2dbf778e56 | |||
873fe2b393 | |||
0c53bc6f32 | |||
fa407e150b | |||
4e52102c5c | |||
0355a5c646 | |||
377d9c3554 | |||
20b1b3c895 | |||
41bbe7c51b | |||
27fa6aefd3 | |||
a63c3232da | |||
146908a115 | |||
48b0f35fee | |||
6c435ebe26 | |||
b8d0b721a2 | |||
a6d5957f46 | |||
9e5f676e23 | |||
414f3a1f9d | |||
fedf9c60ee | |||
b6385d9622 | |||
76d25a712d | |||
2c6d935273 | |||
830d98a101 | |||
d7378bd75a | |||
0f41cb9dbc | |||
77bc922d93 | |||
c91b635132 | |||
e5521de34a | |||
7c0f8d0f24 | |||
f60d5f650f | |||
ca67f2fe0a | |||
16cce8be1d | |||
770619d948 | |||
cfedb7d6b1 | |||
738557b3a2 | |||
38b01deec1 | |||
1a31e69ec9 | |||
e065983c95 | |||
30a169171a | |||
8d1900362e | |||
e154189de1 | |||
b0f147de24 | |||
979b3548db | |||
05d6c578b3 | |||
a117559063 | |||
f87c649b09 | |||
6504dc9184 | |||
25a8ddffd4 | |||
fa0f9b89cf | |||
4d00a67891 | |||
bd2c43e1f4 | |||
c7279eaa34 | |||
fd523e552c | |||
cb877b8b23 | |||
ed1bee8b89 | |||
a8e1492056 | |||
5587216c01 | |||
86569261ad | |||
4a9049c7aa | |||
75d60a8182 | |||
14d4dc2ed9 | |||
fd0e1740a5 | |||
70ca890bef | |||
b9318dfd8e | |||
995642a719 | |||
d14de4ac9e | |||
b7f325a241 | |||
27c55718c2 | |||
421ff0654b | |||
ed947458f9 | |||
9cdb20ba84 | |||
d8774b735f | |||
adcb42695f | |||
dd77b5bcbb | |||
d2445be155 | |||
10254c8af7 | |||
d7e830badf | |||
b445a3a9b8 | |||
97f42ead66 | |||
03730fafb9 | |||
0be9465dca | |||
d7f1df4995 | |||
3cb0f90706 | |||
a3e9b15a8a | |||
00bfa68a57 | |||
c311e24f08 | |||
1cdd4e4455 | |||
8078c0081a | |||
a867e1fc40 | |||
61da36ac1c | |||
720ca2a018 | |||
b39c593552 | |||
c808952a45 | |||
b468d7a766 | |||
28578f60be | |||
92a39e2527 | |||
1bce5e4342 | |||
68f586e104 | |||
d27a66202e | |||
07de2f450c | |||
3c03726634 | |||
6fb2643063 | |||
5eef6c8196 | |||
829c332e13 | |||
47eec14bca | |||
e7ee1d6be7 | |||
e41b5e5ff7 | |||
ba1bacd08c | |||
1029ea5840 | |||
339eaf0195 | |||
aa1e1549d8 | |||
1f8ae9ef80 |
@@ -6,6 +6,8 @@ namespace TweetDuck.Configuration{
|
|||||||
// public args
|
// public args
|
||||||
public const string ArgDataFolder = "-datafolder";
|
public const string ArgDataFolder = "-datafolder";
|
||||||
public const string ArgLogging = "-log";
|
public const string ArgLogging = "-log";
|
||||||
|
public const string ArgIgnoreGDPR = "-nogdpr";
|
||||||
|
public const string ArgNotificationScrollWA = "-nscrollwa";
|
||||||
|
|
||||||
// internal args
|
// internal args
|
||||||
public const string ArgRestart = "-restart";
|
public const string ArgRestart = "-restart";
|
||||||
|
@@ -1,28 +1,17 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using TweetDuck.Data.Serialization;
|
using TweetDuck.Data.Serialization;
|
||||||
|
|
||||||
namespace TweetDuck.Configuration{
|
namespace TweetDuck.Configuration{
|
||||||
sealed class SystemConfig{
|
sealed class SystemConfig{
|
||||||
private static readonly FileSerializer<SystemConfig> Serializer = new FileSerializer<SystemConfig>();
|
private static readonly FileSerializer<SystemConfig> Serializer = new FileSerializer<SystemConfig>();
|
||||||
|
|
||||||
public static readonly bool IsHardwareAccelerationSupported = File.Exists(Path.Combine(Program.ProgramPath, "libEGL.dll")) &&
|
|
||||||
File.Exists(Path.Combine(Program.ProgramPath, "libGLESv2.dll"));
|
|
||||||
|
|
||||||
// CONFIGURATION DATA
|
// CONFIGURATION DATA
|
||||||
|
|
||||||
private bool _hardwareAcceleration = true;
|
public bool HardwareAcceleration { get; set; } = true;
|
||||||
|
|
||||||
public bool ClearCacheAutomatically { get; set; } = true;
|
public bool ClearCacheAutomatically { get; set; } = true;
|
||||||
public int ClearCacheThreshold { get; set; } = 250;
|
public int ClearCacheThreshold { get; set; } = 250;
|
||||||
|
|
||||||
// SPECIAL PROPERTIES
|
|
||||||
|
|
||||||
public bool HardwareAcceleration{
|
|
||||||
get => _hardwareAcceleration && IsHardwareAccelerationSupported;
|
|
||||||
set => _hardwareAcceleration = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// END OF CONFIG
|
// END OF CONFIG
|
||||||
|
|
||||||
private readonly string file;
|
private readonly string file;
|
||||||
|
@@ -51,6 +51,10 @@ namespace TweetDuck.Core.Bridge{
|
|||||||
form.InvokeAsyncSafe(form.OpenContextMenu);
|
form.InvokeAsyncSafe(form.OpenContextMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OpenProfileImport(){
|
||||||
|
form.InvokeAsyncSafe(form.OpenProfileImport);
|
||||||
|
}
|
||||||
|
|
||||||
public void OnIntroductionClosed(bool showGuide, bool allowDataCollection){
|
public void OnIntroductionClosed(bool showGuide, bool allowDataCollection){
|
||||||
form.InvokeAsyncSafe(() => {
|
form.InvokeAsyncSafe(() => {
|
||||||
form.OnIntroductionClosed(showGuide, allowDataCollection);
|
form.OnIntroductionClosed(showGuide, allowDataCollection);
|
||||||
@@ -64,6 +68,10 @@ namespace TweetDuck.Core.Bridge{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetRightClickedLink(string type, string url){
|
||||||
|
ContextInfo.SetLink(type, url);
|
||||||
|
}
|
||||||
|
|
||||||
public void SetRightClickedChirp(string tweetUrl, string quoteUrl, string chirpAuthors, string chirpImages){
|
public void SetRightClickedChirp(string tweetUrl, string quoteUrl, string chirpAuthors, string chirpImages){
|
||||||
ContextInfo.SetChirp(tweetUrl, quoteUrl, chirpAuthors, chirpImages);
|
ContextInfo.SetChirp(tweetUrl, quoteUrl, chirpAuthors, chirpImages);
|
||||||
}
|
}
|
||||||
@@ -99,10 +107,6 @@ namespace TweetDuck.Core.Bridge{
|
|||||||
|
|
||||||
// Global
|
// Global
|
||||||
|
|
||||||
public void SetLastRightClickInfo(string type, string url){
|
|
||||||
ContextInfo.SetLink(type, url);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnTweetPopup(string columnId, string chirpId, string columnName, string tweetHtml, int tweetCharacters, string tweetUrl, string quoteUrl){
|
public void OnTweetPopup(string columnId, string chirpId, string columnName, string tweetHtml, int tweetCharacters, string tweetUrl, string quoteUrl){
|
||||||
notification.InvokeAsyncSafe(() => {
|
notification.InvokeAsyncSafe(() => {
|
||||||
form.OnTweetNotification();
|
form.OnTweetNotification();
|
||||||
|
6
Core/FormBrowser.Designer.cs
generated
@@ -39,17 +39,17 @@
|
|||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
this.BackColor = TweetDuck.Core.Utils.TwitterUtils.BackgroundColor;
|
this.BackColor = TweetDuck.Core.Utils.TwitterUtils.BackgroundColor;
|
||||||
this.ClientSize = new System.Drawing.Size(400, 386);
|
this.ClientSize = new System.Drawing.Size(1008, 730);
|
||||||
this.Icon = Properties.Resources.icon;
|
this.Icon = Properties.Resources.icon;
|
||||||
this.Location = TweetDuck.Core.Controls.ControlExtensions.InvisibleLocation;
|
this.Location = TweetDuck.Core.Controls.ControlExtensions.InvisibleLocation;
|
||||||
this.MinimumSize = new System.Drawing.Size(416, 424);
|
this.MinimumSize = new System.Drawing.Size(348, 424);
|
||||||
this.Name = "FormBrowser";
|
this.Name = "FormBrowser";
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
|
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
|
||||||
this.Activated += new System.EventHandler(this.FormBrowser_Activated);
|
this.Activated += new System.EventHandler(this.FormBrowser_Activated);
|
||||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormBrowser_FormClosing);
|
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormBrowser_FormClosing);
|
||||||
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FormBrowser_FormClosed);
|
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FormBrowser_FormClosed);
|
||||||
this.LocationChanged += new System.EventHandler(this.FormBrowser_LocationChanged);
|
|
||||||
this.ResizeEnd += new System.EventHandler(this.FormBrowser_ResizeEnd);
|
this.ResizeEnd += new System.EventHandler(this.FormBrowser_ResizeEnd);
|
||||||
|
this.LocationChanged += new System.EventHandler(this.FormBrowser_LocationChanged);
|
||||||
this.Resize += new System.EventHandler(this.FormBrowser_Resize);
|
this.Resize += new System.EventHandler(this.FormBrowser_Resize);
|
||||||
this.ResumeLayout(false);
|
this.ResumeLayout(false);
|
||||||
|
|
||||||
|
@@ -5,11 +5,13 @@ using TweetDuck.Configuration;
|
|||||||
using TweetDuck.Core.Bridge;
|
using TweetDuck.Core.Bridge;
|
||||||
using TweetDuck.Core.Controls;
|
using TweetDuck.Core.Controls;
|
||||||
using TweetDuck.Core.Handling;
|
using TweetDuck.Core.Handling;
|
||||||
|
using TweetDuck.Core.Handling.General;
|
||||||
using TweetDuck.Core.Management;
|
using TweetDuck.Core.Management;
|
||||||
using TweetDuck.Core.Notification;
|
using TweetDuck.Core.Notification;
|
||||||
using TweetDuck.Core.Notification.Screenshot;
|
using TweetDuck.Core.Notification.Screenshot;
|
||||||
using TweetDuck.Core.Other;
|
using TweetDuck.Core.Other;
|
||||||
using TweetDuck.Core.Other.Analytics;
|
using TweetDuck.Core.Other.Analytics;
|
||||||
|
using TweetDuck.Core.Other.Settings.Dialogs;
|
||||||
using TweetDuck.Core.Utils;
|
using TweetDuck.Core.Utils;
|
||||||
using TweetDuck.Plugins;
|
using TweetDuck.Plugins;
|
||||||
using TweetDuck.Plugins.Enums;
|
using TweetDuck.Plugins.Enums;
|
||||||
@@ -72,7 +74,7 @@ namespace TweetDuck.Core{
|
|||||||
this.browser = new TweetDeckBrowser(this, new TweetDeckBridge.Browser(this, notification));
|
this.browser = new TweetDeckBrowser(this, new TweetDeckBridge.Browser(this, notification));
|
||||||
this.contextMenu = ContextMenuBrowser.CreateMenu(this);
|
this.contextMenu = ContextMenuBrowser.CreateMenu(this);
|
||||||
|
|
||||||
this.plugins.Register(browser, PluginEnvironment.Browser, true);
|
this.plugins.Register(browser, PluginEnvironment.Browser, this, true);
|
||||||
|
|
||||||
Controls.Add(new MenuStrip{ Visible = false }); // fixes Alt freezing the program in Win 10 Anniversary Update
|
Controls.Add(new MenuStrip{ Visible = false }); // fixes Alt freezing the program in Win 10 Anniversary Update
|
||||||
|
|
||||||
@@ -95,7 +97,11 @@ namespace TweetDuck.Core{
|
|||||||
this.trayIcon.ClickClose += trayIcon_ClickClose;
|
this.trayIcon.ClickClose += trayIcon_ClickClose;
|
||||||
Config.TrayBehaviorChanged += Config_TrayBehaviorChanged;
|
Config.TrayBehaviorChanged += Config_TrayBehaviorChanged;
|
||||||
|
|
||||||
UpdateTrayIcon();
|
UpdateTray();
|
||||||
|
|
||||||
|
if (Config.MuteNotifications){
|
||||||
|
UpdateFormIcon();
|
||||||
|
}
|
||||||
|
|
||||||
this.updates = new UpdateHandler(browser, Program.InstallerPath);
|
this.updates = new UpdateHandler(browser, Program.InstallerPath);
|
||||||
this.updates.CheckFinished += updates_CheckFinished;
|
this.updates.CheckFinished += updates_CheckFinished;
|
||||||
@@ -127,7 +133,11 @@ namespace TweetDuck.Core{
|
|||||||
isLoaded = true;
|
isLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateTrayIcon(){
|
private void UpdateFormIcon(){ // TODO fix to show icon in taskbar too
|
||||||
|
Icon = Config.MuteNotifications ? Properties.Resources.icon_muted : Properties.Resources.icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateTray(){
|
||||||
trayIcon.Visible = Config.TrayBehavior.ShouldDisplayIcon();
|
trayIcon.Visible = Config.TrayBehavior.ShouldDisplayIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,18 +212,19 @@ namespace TweetDuck.Core{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void Config_MuteToggled(object sender, EventArgs e){
|
private void Config_MuteToggled(object sender, EventArgs e){
|
||||||
|
UpdateFormIcon();
|
||||||
AnalyticsFile.NotificationMutes.Trigger();
|
AnalyticsFile.NotificationMutes.Trigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Config_TrayBehaviorChanged(object sender, EventArgs e){
|
private void Config_TrayBehaviorChanged(object sender, EventArgs e){
|
||||||
UpdateTrayIcon();
|
UpdateTray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void trayIcon_ClickRestore(object sender, EventArgs e){
|
private void trayIcon_ClickRestore(object sender, EventArgs e){
|
||||||
Show();
|
Show();
|
||||||
RestoreWindow();
|
RestoreWindow();
|
||||||
Activate();
|
Activate();
|
||||||
UpdateTrayIcon();
|
UpdateTray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void trayIcon_ClickClose(object sender, EventArgs e){
|
private void trayIcon_ClickClose(object sender, EventArgs e){
|
||||||
@@ -360,6 +371,10 @@ namespace TweetDuck.Core{
|
|||||||
AnalyticsFile.UsedROT13.Trigger();
|
AnalyticsFile.UsedROT13.Trigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OpenDevTools(){
|
||||||
|
browser.OpenDevTools();
|
||||||
|
}
|
||||||
|
|
||||||
// callback handlers
|
// callback handlers
|
||||||
|
|
||||||
public void OnIntroductionClosed(bool showGuide, bool allowDataCollection){
|
public void OnIntroductionClosed(bool showGuide, bool allowDataCollection){
|
||||||
@@ -447,6 +462,18 @@ namespace TweetDuck.Core{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OpenProfileImport(){
|
||||||
|
FormManager.TryFind<FormSettings>()?.Close();
|
||||||
|
|
||||||
|
using(DialogSettingsManage dialog = new DialogSettingsManage(plugins, true)){
|
||||||
|
if (dialog.ShowDialog() == DialogResult.OK && !dialog.IsRestarting){
|
||||||
|
BrowserProcessHandler.UpdatePrefs();
|
||||||
|
FormManager.TryFind<FormPlugins>()?.Close();
|
||||||
|
plugins.Reload(); // also reloads the browser
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void OnTweetNotification(){ // may be called multiple times, once for each type of notification
|
public void OnTweetNotification(){ // may be called multiple times, once for each type of notification
|
||||||
if (Config.EnableTrayHighlight && !ContainsFocus){
|
if (Config.EnableTrayHighlight && !ContainsFocus){
|
||||||
trayIcon.HasNotifications = true;
|
trayIcon.HasNotifications = true;
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Core.Other;
|
|
||||||
|
|
||||||
namespace TweetDuck.Core{
|
namespace TweetDuck.Core{
|
||||||
static class FormManager{
|
static class FormManager{
|
||||||
@@ -18,12 +17,14 @@ namespace TweetDuck.Core{
|
|||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool HasAnyDialogs => Application.OpenForms.OfType<IAppDialog>().Any();
|
||||||
|
|
||||||
public static void CloseAllDialogs(){
|
public static void CloseAllDialogs(){
|
||||||
foreach(Form form in Application.OpenForms.Cast<Form>().Reverse()){
|
foreach(IAppDialog dialog in Application.OpenForms.OfType<IAppDialog>().Reverse()){
|
||||||
if (form is FormSettings || form is FormPlugins || form is FormAbout || form is FormGuide){
|
((Form)dialog).Close();
|
||||||
form.Close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface IAppDialog{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,8 +15,6 @@ using TweetDuck.Resources;
|
|||||||
|
|
||||||
namespace TweetDuck.Core.Handling{
|
namespace TweetDuck.Core.Handling{
|
||||||
abstract class ContextMenuBase : IContextMenuHandler{
|
abstract class ContextMenuBase : IContextMenuHandler{
|
||||||
public static readonly bool HasDevTools = File.Exists(Path.Combine(Program.ProgramPath, "devtools_resources.pak"));
|
|
||||||
|
|
||||||
private static TwitterUtils.ImageQuality ImageQuality => Program.UserConfig.TwitterImageQuality;
|
private static TwitterUtils.ImageQuality ImageQuality => Program.UserConfig.TwitterImageQuality;
|
||||||
|
|
||||||
private const CefMenuCommand MenuOpenLinkUrl = (CefMenuCommand)26500;
|
private const CefMenuCommand MenuOpenLinkUrl = (CefMenuCommand)26500;
|
||||||
@@ -28,6 +26,7 @@ namespace TweetDuck.Core.Handling{
|
|||||||
private const CefMenuCommand MenuSaveMedia = (CefMenuCommand)26506;
|
private const CefMenuCommand MenuSaveMedia = (CefMenuCommand)26506;
|
||||||
private const CefMenuCommand MenuSaveTweetImages = (CefMenuCommand)26507;
|
private const CefMenuCommand MenuSaveTweetImages = (CefMenuCommand)26507;
|
||||||
private const CefMenuCommand MenuSearchInBrowser = (CefMenuCommand)26508;
|
private const CefMenuCommand MenuSearchInBrowser = (CefMenuCommand)26508;
|
||||||
|
private const CefMenuCommand MenuReadApplyROT13 = (CefMenuCommand)26509;
|
||||||
private const CefMenuCommand MenuOpenDevTools = (CefMenuCommand)26599;
|
private const CefMenuCommand MenuOpenDevTools = (CefMenuCommand)26599;
|
||||||
|
|
||||||
protected ContextInfo.LinkInfo LastLink { get; private set; }
|
protected ContextInfo.LinkInfo LastLink { get; private set; }
|
||||||
@@ -57,6 +56,8 @@ namespace TweetDuck.Core.Handling{
|
|||||||
if (parameters.TypeFlags.HasFlag(ContextMenuType.Selection) && !parameters.TypeFlags.HasFlag(ContextMenuType.Editable)){
|
if (parameters.TypeFlags.HasFlag(ContextMenuType.Selection) && !parameters.TypeFlags.HasFlag(ContextMenuType.Editable)){
|
||||||
model.AddItem(MenuSearchInBrowser, "Search in browser");
|
model.AddItem(MenuSearchInBrowser, "Search in browser");
|
||||||
model.AddSeparator();
|
model.AddSeparator();
|
||||||
|
model.AddItem(MenuReadApplyROT13, "Apply ROT13");
|
||||||
|
model.AddSeparator();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasTweetImage = LastLink.IsImage;
|
bool hasTweetImage = LastLink.IsImage;
|
||||||
@@ -126,7 +127,7 @@ namespace TweetDuck.Core.Handling{
|
|||||||
SetClipboardText(control, TwitterUtils.GetMediaLink(LastLink.GetMediaSource(parameters), ImageQuality));
|
SetClipboardText(control, TwitterUtils.GetMediaLink(LastLink.GetMediaSource(parameters), ImageQuality));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MenuViewImage:
|
case MenuViewImage: {
|
||||||
void ViewImage(string path){
|
void ViewImage(string path){
|
||||||
string ext = Path.GetExtension(path);
|
string ext = Path.GetExtension(path);
|
||||||
|
|
||||||
@@ -141,11 +142,12 @@ namespace TweetDuck.Core.Handling{
|
|||||||
string url = LastLink.GetMediaSource(parameters);
|
string url = LastLink.GetMediaSource(parameters);
|
||||||
string file = Path.Combine(BrowserCache.CacheFolder, TwitterUtils.GetImageFileName(url) ?? Path.GetRandomFileName());
|
string file = Path.Combine(BrowserCache.CacheFolder, TwitterUtils.GetImageFileName(url) ?? Path.GetRandomFileName());
|
||||||
|
|
||||||
|
control.InvokeAsyncSafe(() => {
|
||||||
if (File.Exists(file)){
|
if (File.Exists(file)){
|
||||||
ViewImage(file);
|
ViewImage(file);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
control.InvokeAsyncSafe(analytics.AnalyticsFile.ViewedImages.Trigger);
|
analytics.AnalyticsFile.ViewedImages.Trigger();
|
||||||
|
|
||||||
BrowserUtils.DownloadFileAsync(TwitterUtils.GetMediaLink(url, ImageQuality), file, () => {
|
BrowserUtils.DownloadFileAsync(TwitterUtils.GetMediaLink(url, ImageQuality), file, () => {
|
||||||
ViewImage(file);
|
ViewImage(file);
|
||||||
@@ -153,25 +155,47 @@ namespace TweetDuck.Core.Handling{
|
|||||||
FormMessage.Error("Image Download", "An error occurred while downloading the image: "+ex.Message, FormMessage.OK);
|
FormMessage.Error("Image Download", "An error occurred while downloading the image: "+ex.Message, FormMessage.OK);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case MenuSaveMedia:
|
case MenuSaveMedia: {
|
||||||
if (LastLink.IsVideo){
|
bool isVideo = LastLink.IsVideo;
|
||||||
control.InvokeAsyncSafe(analytics.AnalyticsFile.DownloadedVideos.Trigger);
|
string url = LastLink.GetMediaSource(parameters);
|
||||||
TwitterUtils.DownloadVideo(LastLink.GetMediaSource(parameters), LastChirp.Authors.LastOrDefault());
|
string username = LastChirp.Authors.LastOrDefault();
|
||||||
|
|
||||||
|
control.InvokeAsyncSafe(() => {
|
||||||
|
if (isVideo){
|
||||||
|
TwitterUtils.DownloadVideo(url, username);
|
||||||
|
analytics.AnalyticsFile.DownloadedVideos.Trigger();
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
control.InvokeAsyncSafe(analytics.AnalyticsFile.DownloadedImages.Trigger);
|
TwitterUtils.DownloadImage(url, username, ImageQuality);
|
||||||
TwitterUtils.DownloadImage(LastLink.GetMediaSource(parameters), LastChirp.Authors.LastOrDefault(), ImageQuality);
|
analytics.AnalyticsFile.DownloadedImages.Trigger();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
case MenuSaveTweetImages: {
|
||||||
|
string[] urls = LastChirp.Images;
|
||||||
|
string username = LastChirp.Authors.LastOrDefault();
|
||||||
|
|
||||||
|
control.InvokeAsyncSafe(() => {
|
||||||
|
TwitterUtils.DownloadImages(urls, username, ImageQuality);
|
||||||
|
analytics.AnalyticsFile.DownloadedImages.Trigger();
|
||||||
|
});
|
||||||
|
|
||||||
case MenuSaveTweetImages:
|
|
||||||
control.InvokeAsyncSafe(analytics.AnalyticsFile.DownloadedImages.Trigger);
|
|
||||||
TwitterUtils.DownloadImages(LastChirp.Images, LastChirp.Authors.LastOrDefault(), ImageQuality);
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MenuReadApplyROT13:
|
||||||
|
string selection = parameters.SelectionText;
|
||||||
|
control.InvokeAsyncSafe(() => FormMessage.Information("ROT13", StringUtils.ConvertRot13(selection), FormMessage.OK));
|
||||||
|
control.InvokeAsyncSafe(analytics.AnalyticsFile.UsedROT13.Trigger);
|
||||||
|
return true;
|
||||||
|
|
||||||
case MenuSearchInBrowser:
|
case MenuSearchInBrowser:
|
||||||
string query = parameters.SelectionText;
|
string query = parameters.SelectionText;
|
||||||
@@ -195,15 +219,15 @@ namespace TweetDuck.Core.Handling{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void DeselectAll(IFrame frame){
|
protected static void DeselectAll(IFrame frame){
|
||||||
ScriptLoader.ExecuteScript(frame, "window.getSelection().removeAllRanges()", "gen:deselect");
|
ScriptLoader.ExecuteScript(frame, "window.getSelection().removeAllRanges()", "gen:deselect");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void OpenBrowser(Control control, string url){
|
protected static void OpenBrowser(Control control, string url){
|
||||||
control.InvokeAsyncSafe(() => BrowserUtils.OpenExternalBrowser(url));
|
control.InvokeAsyncSafe(() => BrowserUtils.OpenExternalBrowser(url));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SetClipboardText(Control control, string text){
|
protected static void SetClipboardText(Control control, string text){
|
||||||
control.InvokeAsyncSafe(() => WindowsUtils.SetClipboard(text, TextDataFormat.UnicodeText));
|
control.InvokeAsyncSafe(() => WindowsUtils.SetClipboard(text, TextDataFormat.UnicodeText));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,8 +236,11 @@ namespace TweetDuck.Core.Handling{
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected static void AddDebugMenuItems(IMenuModel model){
|
protected static void AddDebugMenuItems(IMenuModel model){
|
||||||
|
if (BrowserUtils.HasDevTools){
|
||||||
|
AddSeparator(model);
|
||||||
model.AddItem(MenuOpenDevTools, "Open dev tools");
|
model.AddItem(MenuOpenDevTools, "Open dev tools");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected static void RemoveSeparatorIfLast(IMenuModel model){
|
protected static void RemoveSeparatorIfLast(IMenuModel model){
|
||||||
if (model.Count > 0 && model.GetTypeAt(model.Count-1) == MenuItemType.Separator){
|
if (model.Count > 0 && model.GetTypeAt(model.Count-1) == MenuItemType.Separator){
|
||||||
|
@@ -16,7 +16,7 @@ namespace TweetDuck.Core.Handling{
|
|||||||
private const CefMenuCommand MenuOpenQuotedTweetUrl = (CefMenuCommand)26612;
|
private const CefMenuCommand MenuOpenQuotedTweetUrl = (CefMenuCommand)26612;
|
||||||
private const CefMenuCommand MenuCopyQuotedTweetUrl = (CefMenuCommand)26613;
|
private const CefMenuCommand MenuCopyQuotedTweetUrl = (CefMenuCommand)26613;
|
||||||
private const CefMenuCommand MenuScreenshotTweet = (CefMenuCommand)26614;
|
private const CefMenuCommand MenuScreenshotTweet = (CefMenuCommand)26614;
|
||||||
private const CefMenuCommand MenuInputApplyROT13 = (CefMenuCommand)26615;
|
private const CefMenuCommand MenuWriteApplyROT13 = (CefMenuCommand)26615;
|
||||||
private const CefMenuCommand MenuSearchInColumn = (CefMenuCommand)26616;
|
private const CefMenuCommand MenuSearchInColumn = (CefMenuCommand)26616;
|
||||||
|
|
||||||
private const string TitleReloadBrowser = "Reload browser";
|
private const string TitleReloadBrowser = "Reload browser";
|
||||||
@@ -44,7 +44,7 @@ namespace TweetDuck.Core.Handling{
|
|||||||
if (isSelecting){
|
if (isSelecting){
|
||||||
if (isEditing){
|
if (isEditing){
|
||||||
model.AddSeparator();
|
model.AddSeparator();
|
||||||
model.AddItem(MenuInputApplyROT13, "Apply ROT13");
|
model.AddItem(MenuWriteApplyROT13, "Apply ROT13");
|
||||||
}
|
}
|
||||||
|
|
||||||
model.AddSeparator();
|
model.AddSeparator();
|
||||||
@@ -84,11 +84,8 @@ namespace TweetDuck.Core.Handling{
|
|||||||
globalMenu.AddItem(MenuPlugins, TitlePlugins);
|
globalMenu.AddItem(MenuPlugins, TitlePlugins);
|
||||||
globalMenu.AddItem(MenuAbout, TitleAboutProgram);
|
globalMenu.AddItem(MenuAbout, TitleAboutProgram);
|
||||||
|
|
||||||
if (HasDevTools){
|
|
||||||
globalMenu.AddSeparator();
|
|
||||||
AddDebugMenuItems(globalMenu);
|
AddDebugMenuItems(globalMenu);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
RemoveSeparatorIfLast(model);
|
RemoveSeparatorIfLast(model);
|
||||||
|
|
||||||
@@ -141,7 +138,7 @@ namespace TweetDuck.Core.Handling{
|
|||||||
SetClipboardText(form, LastChirp.QuoteUrl);
|
SetClipboardText(form, LastChirp.QuoteUrl);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case MenuInputApplyROT13:
|
case MenuWriteApplyROT13:
|
||||||
form.InvokeAsyncSafe(form.ApplyROT13);
|
form.InvokeAsyncSafe(form.ApplyROT13);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@@ -8,11 +8,7 @@ namespace TweetDuck.Core.Handling{
|
|||||||
public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
|
public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
|
||||||
model.Clear();
|
model.Clear();
|
||||||
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
|
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
|
||||||
|
|
||||||
if (HasDevTools){
|
|
||||||
AddSeparator(model);
|
|
||||||
AddDebugMenuItems(model);
|
AddDebugMenuItems(model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -47,11 +47,7 @@ namespace TweetDuck.Core.Handling{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HasDevTools){
|
|
||||||
AddSeparator(model);
|
|
||||||
AddDebugMenuItems(model);
|
AddDebugMenuItems(model);
|
||||||
}
|
|
||||||
|
|
||||||
RemoveSeparatorIfLast(model);
|
RemoveSeparatorIfLast(model);
|
||||||
|
|
||||||
form.InvokeAsyncSafe(() => {
|
form.InvokeAsyncSafe(() => {
|
||||||
|
@@ -1,13 +1,22 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
|
using CefSharp.Enums;
|
||||||
|
|
||||||
namespace TweetDuck.Core.Handling{
|
namespace TweetDuck.Core.Handling{
|
||||||
sealed class DragHandlerBrowser : IDragHandler{
|
sealed class DragHandlerBrowser : IDragHandler{
|
||||||
|
private readonly RequestHandlerBrowser requestHandler;
|
||||||
|
|
||||||
|
public DragHandlerBrowser(RequestHandlerBrowser requestHandler){
|
||||||
|
this.requestHandler = requestHandler;
|
||||||
|
}
|
||||||
|
|
||||||
public bool OnDragEnter(IWebBrowser browserControl, IBrowser browser, IDragData dragData, DragOperationsMask mask){
|
public bool OnDragEnter(IWebBrowser browserControl, IBrowser browser, IDragData dragData, DragOperationsMask mask){
|
||||||
void TriggerDragStart(string type, string data = null){
|
void TriggerDragStart(string type, string data = null){
|
||||||
browserControl.ExecuteScriptAsync("window.TDGF_onGlobalDragStart", type, data);
|
browserControl.ExecuteScriptAsync("window.TDGF_onGlobalDragStart", type, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
requestHandler.BlockNextUserNavUrl = dragData.LinkUrl; // empty if not a link
|
||||||
|
|
||||||
if (dragData.IsLink){
|
if (dragData.IsLink){
|
||||||
TriggerDragStart("link", dragData.LinkUrl);
|
TriggerDragStart("link", dragData.LinkUrl);
|
||||||
}
|
}
|
||||||
|
72
Core/Handling/Filters/ResponseFilterBase.cs
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using CefSharp;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Handling.Filters{
|
||||||
|
abstract class ResponseFilterBase : IResponseFilter{
|
||||||
|
private enum State{
|
||||||
|
Reading, Writing, Done
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Encoding encoding;
|
||||||
|
private byte[] responseData;
|
||||||
|
|
||||||
|
private State state;
|
||||||
|
private int offset;
|
||||||
|
|
||||||
|
protected ResponseFilterBase(int totalBytes, Encoding encoding){
|
||||||
|
this.responseData = new byte[totalBytes];
|
||||||
|
this.encoding = encoding;
|
||||||
|
this.state = State.Reading;
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterStatus IResponseFilter.Filter(Stream dataIn, out long dataInRead, Stream dataOut, out long dataOutWritten){
|
||||||
|
int responseLength = responseData.Length;
|
||||||
|
|
||||||
|
if (state == State.Reading){
|
||||||
|
int bytesToRead = Math.Min(responseLength-offset, (int)Math.Min(dataIn.Length, int.MaxValue));
|
||||||
|
|
||||||
|
dataIn.Read(responseData, offset, bytesToRead);
|
||||||
|
offset += bytesToRead;
|
||||||
|
|
||||||
|
dataInRead = bytesToRead;
|
||||||
|
dataOutWritten = 0;
|
||||||
|
|
||||||
|
if (offset >= responseLength){
|
||||||
|
responseData = encoding.GetBytes(ProcessResponse(encoding.GetString(responseData)));
|
||||||
|
state = State.Writing;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FilterStatus.NeedMoreData;
|
||||||
|
}
|
||||||
|
else if (state == State.Writing){
|
||||||
|
int bytesToWrite = Math.Min(responseLength-offset, (int)Math.Min(dataOut.Length, int.MaxValue));
|
||||||
|
|
||||||
|
if (bytesToWrite > 0){
|
||||||
|
dataOut.Write(responseData, offset, bytesToWrite);
|
||||||
|
offset += bytesToWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataOutWritten = bytesToWrite;
|
||||||
|
dataInRead = 0;
|
||||||
|
|
||||||
|
if (offset < responseLength){
|
||||||
|
return FilterStatus.NeedMoreData;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
state = State.Done;
|
||||||
|
return FilterStatus.Done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
throw new InvalidOperationException("This resource filter cannot be reused.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract bool InitFilter();
|
||||||
|
protected abstract string ProcessResponse(string text);
|
||||||
|
public abstract void Dispose();
|
||||||
|
}
|
||||||
|
}
|
20
Core/Handling/Filters/ResponseFilterVendor.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Handling.Filters{
|
||||||
|
sealed class ResponseFilterVendor : ResponseFilterBase{
|
||||||
|
private static readonly Regex RegexRestoreJQuery = new Regex(@"(\w+)\.fn=\1\.prototype", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
public ResponseFilterVendor(int totalBytes) : base(totalBytes, Encoding.UTF8){}
|
||||||
|
|
||||||
|
public override bool InitFilter(){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string ProcessResponse(string text){
|
||||||
|
return RegexRestoreJQuery.Replace(text, "window.$$=$1;$&", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Dispose(){}
|
||||||
|
}
|
||||||
|
}
|
@@ -7,16 +7,14 @@ using CefSharp;
|
|||||||
|
|
||||||
namespace TweetDuck.Core.Handling.General{
|
namespace TweetDuck.Core.Handling.General{
|
||||||
sealed class FileDialogHandler : IDialogHandler{
|
sealed class FileDialogHandler : IDialogHandler{
|
||||||
public bool OnFileDialog(IWebBrowser browserControl, IBrowser browser, CefFileDialogMode mode, string title, string defaultFilePath, List<string> acceptFilters, int selectedAcceptFilter, IFileDialogCallback callback){
|
public bool OnFileDialog(IWebBrowser browserControl, IBrowser browser, CefFileDialogMode mode, CefFileDialogFlags flags, string title, string defaultFilePath, List<string> acceptFilters, int selectedAcceptFilter, IFileDialogCallback callback){
|
||||||
CefFileDialogMode dialogType = mode & CefFileDialogMode.TypeMask;
|
if (mode == CefFileDialogMode.Open || mode == CefFileDialogMode.OpenMultiple){
|
||||||
|
|
||||||
if (dialogType == CefFileDialogMode.Open || dialogType == CefFileDialogMode.OpenMultiple){
|
|
||||||
string allFilters = string.Join(";", acceptFilters.Select(filter => "*"+filter));
|
string allFilters = string.Join(";", acceptFilters.Select(filter => "*"+filter));
|
||||||
|
|
||||||
using(OpenFileDialog dialog = new OpenFileDialog{
|
using(OpenFileDialog dialog = new OpenFileDialog{
|
||||||
AutoUpgradeEnabled = true,
|
AutoUpgradeEnabled = true,
|
||||||
DereferenceLinks = true,
|
DereferenceLinks = true,
|
||||||
Multiselect = dialogType == CefFileDialogMode.OpenMultiple,
|
Multiselect = mode == CefFileDialogMode.OpenMultiple,
|
||||||
Title = "Open Files",
|
Title = "Open Files",
|
||||||
Filter = $"All Supported Formats ({allFilters})|{allFilters}|All Files (*.*)|*.*"
|
Filter = $"All Supported Formats ({allFilters})|{allFilters}|All Files (*.*)|*.*"
|
||||||
}){
|
}){
|
||||||
|
@@ -2,15 +2,22 @@
|
|||||||
using CefSharp;
|
using CefSharp;
|
||||||
using CefSharp.Handler;
|
using CefSharp.Handler;
|
||||||
using TweetDuck.Core.Handling.General;
|
using TweetDuck.Core.Handling.General;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
|
||||||
namespace TweetDuck.Core.Handling{
|
namespace TweetDuck.Core.Handling{
|
||||||
class RequestHandlerBase : DefaultRequestHandler{
|
class RequestHandlerBase : DefaultRequestHandler{
|
||||||
|
private readonly bool autoReload;
|
||||||
|
|
||||||
|
public RequestHandlerBase(bool autoReload){
|
||||||
|
this.autoReload = autoReload;
|
||||||
|
}
|
||||||
|
|
||||||
public override bool OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture){
|
public override bool OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture){
|
||||||
return LifeSpanHandler.HandleLinkClick(browserControl, targetDisposition, targetUrl);
|
return LifeSpanHandler.HandleLinkClick(browserControl, targetDisposition, targetUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback){
|
public override CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback){
|
||||||
if (ContextMenuBase.HasDevTools){
|
if (BrowserUtils.HasDevTools){
|
||||||
NameValueCollection headers = request.Headers;
|
NameValueCollection headers = request.Headers;
|
||||||
headers.Remove("x-devtools-emulate-network-conditions-client-id");
|
headers.Remove("x-devtools-emulate-network-conditions-client-id");
|
||||||
request.Headers = headers;
|
request.Headers = headers;
|
||||||
@@ -18,5 +25,11 @@ namespace TweetDuck.Core.Handling{
|
|||||||
|
|
||||||
return base.OnBeforeResourceLoad(browserControl, browser, frame, request, callback);
|
return base.OnBeforeResourceLoad(browserControl, browser, frame, request, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status){
|
||||||
|
if (autoReload){
|
||||||
|
browser.Reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,21 @@
|
|||||||
using CefSharp;
|
// Uncomment to force TweetDeck to load a predefined version of the vendor/bundle scripts
|
||||||
|
// #define FREEZE_TWEETDECK_SCRIPTS
|
||||||
|
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using CefSharp;
|
||||||
|
using TweetDuck.Core.Handling.Filters;
|
||||||
using TweetDuck.Core.Utils;
|
using TweetDuck.Core.Utils;
|
||||||
|
|
||||||
|
#if FREEZE_TWEETDECK_SCRIPTS
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace TweetDuck.Core.Handling{
|
namespace TweetDuck.Core.Handling{
|
||||||
sealed class RequestHandlerBrowser : RequestHandlerBase{
|
sealed class RequestHandlerBrowser : RequestHandlerBase{
|
||||||
public override void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status){
|
public string BlockNextUserNavUrl { get; set; }
|
||||||
browser.Reload();
|
|
||||||
}
|
public RequestHandlerBrowser() : base(true){}
|
||||||
|
|
||||||
public override CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback){
|
public override CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback){
|
||||||
if (request.ResourceType == ResourceType.Script && request.Url.Contains("analytics.")){
|
if (request.ResourceType == ResourceType.Script && request.Url.Contains("analytics.")){
|
||||||
@@ -16,13 +26,71 @@ namespace TweetDuck.Core.Handling{
|
|||||||
return base.OnBeforeResourceLoad(browserControl, browser, frame, request, callback);
|
return base.OnBeforeResourceLoad(browserControl, browser, frame, request, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect){
|
||||||
|
if (userGesture && request.TransitionType == TransitionType.LinkClicked){
|
||||||
|
bool block = request.Url == BlockNextUserNavUrl;
|
||||||
|
BlockNextUserNavUrl = string.Empty;
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.OnBeforeBrowse(browserControl, browser, frame, request, userGesture, isRedirect);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if FREEZE_TWEETDECK_SCRIPTS
|
||||||
|
private static readonly Regex TweetDeckScriptUrl = new Regex(@"/dist/(.*?)\.(.*?)\.js$", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
private static readonly SortedList<string, string> TweetDeckHashes = new SortedList<string, string>(2){
|
||||||
|
{ "vendor", "942c0a20e8" },
|
||||||
|
{ "bundle", "1bd75b5854" }
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
public override bool OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response){
|
public override bool OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response){
|
||||||
if (request.ResourceType == ResourceType.Image && request.Url.Contains("backgrounds/spinner_blue")){
|
if (request.ResourceType == ResourceType.Image && request.Url.Contains("/backgrounds/spinner_blue")){
|
||||||
request.Url = TwitterUtils.LoadingSpinner.Url;
|
request.Url = TwitterUtils.LoadingSpinner.Url;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#if FREEZE_TWEETDECK_SCRIPTS
|
||||||
|
else if (request.ResourceType == ResourceType.Script){
|
||||||
|
Match match = TweetDeckScriptUrl.Match(request.Url);
|
||||||
|
|
||||||
|
if (match.Success && TweetDeckHashes.TryGetValue(match.Groups[1].Value, out string hash)){
|
||||||
|
if (match.Groups[2].Value == hash){
|
||||||
|
System.Diagnostics.Debug.WriteLine($"accepting {request.Url}");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
System.Diagnostics.Debug.WriteLine($"rewriting {request.Url} to {hash}");
|
||||||
|
request.Url = TweetDeckScriptUrl.Replace(request.Url, "/dist/$1."+hash+".js");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return base.OnResourceResponse(browserControl, browser, frame, request, response);
|
return base.OnResourceResponse(browserControl, browser, frame, request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override IResponseFilter GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response){
|
||||||
|
if (request.ResourceType == ResourceType.Script && request.Url.Contains("/dist/vendor")){
|
||||||
|
NameValueCollection headers = response.ResponseHeaders;
|
||||||
|
|
||||||
|
if (int.TryParse(headers["x-ton-expected-size"], out int totalBytes)){
|
||||||
|
return new ResponseFilterVendor(totalBytes);
|
||||||
|
}
|
||||||
|
#if DEBUG
|
||||||
|
else{
|
||||||
|
System.Diagnostics.Debug.WriteLine($"Missing uncompressed size header in {request.Url}");
|
||||||
|
|
||||||
|
foreach(string key in headers){
|
||||||
|
System.Diagnostics.Debug.WriteLine($" {key}: {headers[key]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
System.Diagnostics.Debugger.Break();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.GetResourceResponseFilter(browserControl, browser, frame, request, response);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
using System.Windows.Forms;
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using CefSharp;
|
||||||
using TweetDuck.Core.Controls;
|
using TweetDuck.Core.Controls;
|
||||||
using TweetDuck.Plugins;
|
using TweetDuck.Plugins;
|
||||||
using TweetDuck.Resources;
|
using TweetDuck.Resources;
|
||||||
@@ -21,10 +23,14 @@ namespace TweetDuck.Core.Notification.Example{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public event EventHandler Ready;
|
||||||
|
|
||||||
private readonly TweetNotification exampleNotification;
|
private readonly TweetNotification exampleNotification;
|
||||||
|
|
||||||
public FormNotificationExample(FormBrowser owner, PluginManager pluginManager) : base(owner, pluginManager, false){
|
public FormNotificationExample(FormBrowser owner, PluginManager pluginManager) : base(owner, pluginManager, false){
|
||||||
string exampleTweetHTML = ScriptLoader.LoadResource("pages/example.html", true)?.Replace("{avatar}", TweetNotification.AppLogo.Url) ?? string.Empty;
|
browser.LoadingStateChanged += browser_LoadingStateChanged;
|
||||||
|
|
||||||
|
string exampleTweetHTML = ScriptLoader.LoadResourceSilent("pages/example.html")?.Replace("{avatar}", TweetNotification.AppLogo.Url) ?? string.Empty;
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
exampleTweetHTML = exampleTweetHTML.Replace("</p>", @"</p><div style='margin-top:256px'>Scrollbar test padding...</div>");
|
exampleTweetHTML = exampleTweetHTML.Replace("</p>", @"</p><div style='margin-top:256px'>Scrollbar test padding...</div>");
|
||||||
@@ -33,6 +39,13 @@ namespace TweetDuck.Core.Notification.Example{
|
|||||||
exampleNotification = TweetNotification.Example(exampleTweetHTML, 176);
|
exampleNotification = TweetNotification.Example(exampleTweetHTML, 176);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e){
|
||||||
|
if (!e.IsLoading){
|
||||||
|
Ready?.Invoke(this, EventArgs.Empty);
|
||||||
|
browser.LoadingStateChanged -= browser_LoadingStateChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override void HideNotification(){
|
public override void HideNotification(){
|
||||||
Location = ControlExtensions.InvisibleLocation;
|
Location = ControlExtensions.InvisibleLocation;
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
using CefSharp;
|
using CefSharp.WinForms;
|
||||||
using CefSharp.WinForms;
|
|
||||||
using System;
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Configuration;
|
using TweetDuck.Configuration;
|
||||||
@@ -65,7 +63,7 @@ namespace TweetDuck.Core.Notification{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsNotificationVisible => Location != ControlExtensions.InvisibleLocation;
|
protected bool IsNotificationVisible => Location != ControlExtensions.InvisibleLocation;
|
||||||
protected virtual bool CanDragWindow => true;
|
protected virtual bool CanDragWindow => true;
|
||||||
|
|
||||||
public new Point Location{
|
public new Point Location{
|
||||||
@@ -109,15 +107,13 @@ namespace TweetDuck.Core.Notification{
|
|||||||
public string CurrentQuoteUrl => currentNotification?.QuoteUrl;
|
public string CurrentQuoteUrl => currentNotification?.QuoteUrl;
|
||||||
|
|
||||||
public bool CanViewDetail => currentNotification != null && !string.IsNullOrEmpty(currentNotification.ColumnId) && !string.IsNullOrEmpty(currentNotification.ChirpId);
|
public bool CanViewDetail => currentNotification != null && !string.IsNullOrEmpty(currentNotification.ColumnId) && !string.IsNullOrEmpty(currentNotification.ChirpId);
|
||||||
public bool IsPaused => pauseCounter > 0;
|
|
||||||
|
|
||||||
|
protected bool IsPaused => pauseCounter > 0;
|
||||||
protected bool IsCursorOverBrowser => browser.Bounds.Contains(PointToClient(Cursor.Position));
|
protected bool IsCursorOverBrowser => browser.Bounds.Contains(PointToClient(Cursor.Position));
|
||||||
|
|
||||||
public bool FreezeTimer { get; set; }
|
public bool FreezeTimer { get; set; }
|
||||||
public bool ContextMenuOpen { get; set; }
|
public bool ContextMenuOpen { get; set; }
|
||||||
|
|
||||||
public event EventHandler Initialized;
|
|
||||||
|
|
||||||
protected FormNotificationBase(FormBrowser owner, bool enableContextMenu){
|
protected FormNotificationBase(FormBrowser owner, bool enableContextMenu){
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
@@ -128,12 +124,11 @@ namespace TweetDuck.Core.Notification{
|
|||||||
MenuHandler = new ContextMenuNotification(this, enableContextMenu),
|
MenuHandler = new ContextMenuNotification(this, enableContextMenu),
|
||||||
JsDialogHandler = new JavaScriptDialogHandler(),
|
JsDialogHandler = new JavaScriptDialogHandler(),
|
||||||
LifeSpanHandler = new LifeSpanHandler(),
|
LifeSpanHandler = new LifeSpanHandler(),
|
||||||
RequestHandler = new RequestHandlerBase()
|
RequestHandler = new RequestHandlerBase(false)
|
||||||
};
|
};
|
||||||
|
|
||||||
this.browser.Dock = DockStyle.None;
|
this.browser.Dock = DockStyle.None;
|
||||||
this.browser.ClientSize = ClientSize;
|
this.browser.ClientSize = ClientSize;
|
||||||
this.browser.IsBrowserInitializedChanged += browser_IsBrowserInitializedChanged;
|
|
||||||
|
|
||||||
browser.SetupResourceHandler(TwitterUtils.TweetDeckURL, this.resourceHandler);
|
browser.SetupResourceHandler(TwitterUtils.TweetDeckURL, this.resourceHandler);
|
||||||
browser.SetupResourceHandler(TweetNotification.AppLogo);
|
browser.SetupResourceHandler(TweetNotification.AppLogo);
|
||||||
@@ -165,12 +160,6 @@ namespace TweetDuck.Core.Notification{
|
|||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void browser_IsBrowserInitializedChanged(object sender, IsBrowserInitializedChangedEventArgs e){
|
|
||||||
if (e.IsBrowserInitialized){
|
|
||||||
Initialized?.Invoke(this, EventArgs.Empty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// notification methods
|
// notification methods
|
||||||
|
|
||||||
public virtual void HideNotification(){
|
public virtual void HideNotification(){
|
||||||
@@ -196,7 +185,7 @@ namespace TweetDuck.Core.Notification{
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected virtual string GetTweetHTML(TweetNotification tweet){
|
protected virtual string GetTweetHTML(TweetNotification tweet){
|
||||||
return tweet.GenerateHtml(IsCursorOverBrowser ? "td-notification td-hover" : "td-notification");
|
return tweet.GenerateHtml(IsCursorOverBrowser ? "td-notification td-hover" : "td-notification", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void LoadTweet(TweetNotification tweet){
|
protected virtual void LoadTweet(TweetNotification tweet){
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Configuration;
|
||||||
using TweetDuck.Core.Bridge;
|
using TweetDuck.Core.Bridge;
|
||||||
using TweetDuck.Core.Controls;
|
using TweetDuck.Core.Controls;
|
||||||
using TweetDuck.Core.Handling;
|
using TweetDuck.Core.Handling;
|
||||||
@@ -14,11 +15,6 @@ using TweetDuck.Resources;
|
|||||||
|
|
||||||
namespace TweetDuck.Core.Notification{
|
namespace TweetDuck.Core.Notification{
|
||||||
abstract partial class FormNotificationMain : FormNotificationBase, ITweetDeckBrowser{
|
abstract partial class FormNotificationMain : FormNotificationBase, ITweetDeckBrowser{
|
||||||
private const string NotificationScriptFile = "notification.js";
|
|
||||||
|
|
||||||
private static readonly string NotificationScriptIdentifier = ScriptLoader.GetRootIdentifier(NotificationScriptFile);
|
|
||||||
private static readonly string NotificationJS = ScriptLoader.LoadResource(NotificationScriptFile);
|
|
||||||
|
|
||||||
private readonly PluginManager plugins;
|
private readonly PluginManager plugins;
|
||||||
private readonly int timerBarHeight;
|
private readonly int timerBarHeight;
|
||||||
|
|
||||||
@@ -65,7 +61,7 @@ namespace TweetDuck.Core.Notification{
|
|||||||
get{
|
get{
|
||||||
switch(Program.UserConfig.NotificationSize){
|
switch(Program.UserConfig.NotificationSize){
|
||||||
default:
|
default:
|
||||||
return BrowserUtils.Scale(122, SizeScale*(1.0+0.075*FontSizeLevel));
|
return BrowserUtils.Scale(122, SizeScale*(1.0+0.08*FontSizeLevel));
|
||||||
|
|
||||||
case TweetNotification.Size.Custom:
|
case TweetNotification.Size.Custom:
|
||||||
return Program.UserConfig.CustomNotificationSize.Height;
|
return Program.UserConfig.CustomNotificationSize.Height;
|
||||||
@@ -87,7 +83,7 @@ namespace TweetDuck.Core.Notification{
|
|||||||
browser.LoadingStateChanged += Browser_LoadingStateChanged;
|
browser.LoadingStateChanged += Browser_LoadingStateChanged;
|
||||||
browser.FrameLoadEnd += Browser_FrameLoadEnd;
|
browser.FrameLoadEnd += Browser_FrameLoadEnd;
|
||||||
|
|
||||||
plugins.Register(this, PluginEnvironment.Notification);
|
plugins.Register(this, PluginEnvironment.Notification, this);
|
||||||
|
|
||||||
mouseHookDelegate = MouseHookProc;
|
mouseHookDelegate = MouseHookProc;
|
||||||
Disposed += (sender, args) => StopMouseHook(true);
|
Disposed += (sender, args) => StopMouseHook(true);
|
||||||
@@ -105,7 +101,7 @@ namespace TweetDuck.Core.Notification{
|
|||||||
browser.FrameLoadEnd += (sender, args) => {
|
browser.FrameLoadEnd += (sender, args) => {
|
||||||
IFrame frame = args.Frame;
|
IFrame frame = args.Frame;
|
||||||
|
|
||||||
if (frame.IsMain && NotificationJS != null && browser.Address != "about:blank"){
|
if (frame.IsMain && browser.Address != "about:blank"){
|
||||||
callback(frame);
|
callback(frame);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -136,7 +132,14 @@ namespace TweetDuck.Core.Notification{
|
|||||||
int eventType = wParam.ToInt32();
|
int eventType = wParam.ToInt32();
|
||||||
|
|
||||||
if (eventType == NativeMethods.WM_MOUSEWHEEL && IsCursorOverBrowser){
|
if (eventType == NativeMethods.WM_MOUSEWHEEL && IsCursorOverBrowser){
|
||||||
|
if (Arguments.HasFlag(Arguments.ArgNotificationScrollWA)){
|
||||||
|
int delta = BrowserUtils.Scale(NativeMethods.GetMouseHookData(lParam), Program.UserConfig.NotificationScrollSpeed*0.01);
|
||||||
|
browser.ExecuteScriptAsync("window.scrollBy", 0, -Math.Round(delta/0.72));
|
||||||
|
}
|
||||||
|
else{
|
||||||
browser.SendMouseWheelEvent(0, 0, 0, BrowserUtils.Scale(NativeMethods.GetMouseHookData(lParam), Program.UserConfig.NotificationScrollSpeed*0.01), CefEventFlags.None);
|
browser.SendMouseWheelEvent(0, 0, 0, BrowserUtils.Scale(NativeMethods.GetMouseHookData(lParam), Program.UserConfig.NotificationScrollSpeed*0.01), CefEventFlags.None);
|
||||||
|
}
|
||||||
|
|
||||||
return NativeMethods.HOOK_HANDLED;
|
return NativeMethods.HOOK_HANDLED;
|
||||||
}
|
}
|
||||||
else if (eventType == NativeMethods.WM_XBUTTONDOWN && DesktopBounds.Contains(Cursor.Position)){
|
else if (eventType == NativeMethods.WM_XBUTTONDOWN && DesktopBounds.Contains(Cursor.Position)){
|
||||||
@@ -186,9 +189,9 @@ namespace TweetDuck.Core.Notification{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
||||||
if (e.Frame.IsMain && NotificationJS != null && browser.Address != "about:blank"){
|
if (e.Frame.IsMain && browser.Address != "about:blank"){
|
||||||
e.Frame.ExecuteJavaScriptAsync(PropertyBridge.GenerateScript(PropertyBridge.Environment.Notification));
|
e.Frame.ExecuteJavaScriptAsync(PropertyBridge.GenerateScript(PropertyBridge.Environment.Notification));
|
||||||
ScriptLoader.ExecuteScript(e.Frame, NotificationJS, NotificationScriptIdentifier);
|
ScriptLoader.ExecuteScript(e.Frame, ScriptLoader.LoadResource("notification.js", this), "root:notification");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +258,7 @@ namespace TweetDuck.Core.Notification{
|
|||||||
string html = base.GetTweetHTML(tweet);
|
string html = base.GetTweetHTML(tweet);
|
||||||
|
|
||||||
foreach(InjectedHTML injection in plugins.NotificationInjections){
|
foreach(InjectedHTML injection in plugins.NotificationInjections){
|
||||||
html = injection.Inject(html);
|
html = injection.InjectInto(html);
|
||||||
}
|
}
|
||||||
|
|
||||||
return html;
|
return html;
|
||||||
|
@@ -20,6 +20,8 @@ namespace TweetDuck.Core.Notification.Screenshot{
|
|||||||
public FormNotificationScreenshotable(Action callback, FormBrowser owner, PluginManager pluginManager, string html, int width) : base(owner, false){
|
public FormNotificationScreenshotable(Action callback, FormBrowser owner, PluginManager pluginManager, string html, int width) : base(owner, false){
|
||||||
this.plugins = pluginManager;
|
this.plugins = pluginManager;
|
||||||
|
|
||||||
|
int realWidth = BrowserUtils.Scale(width, DpiScale);
|
||||||
|
|
||||||
browser.RegisterAsyncJsObject("$TD_NotificationScreenshot", new ScreenshotBridge(this, SetScreenshotHeight, callback));
|
browser.RegisterAsyncJsObject("$TD_NotificationScreenshot", new ScreenshotBridge(this, SetScreenshotHeight, callback));
|
||||||
|
|
||||||
browser.LoadingStateChanged += (sender, args) => {
|
browser.LoadingStateChanged += (sender, args) => {
|
||||||
@@ -27,7 +29,7 @@ namespace TweetDuck.Core.Notification.Screenshot{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string script = ScriptLoader.LoadResource("screenshot.js", true);
|
string script = ScriptLoader.LoadResourceSilent("screenshot.js");
|
||||||
|
|
||||||
if (script == null){
|
if (script == null){
|
||||||
this.InvokeAsyncSafe(callback);
|
this.InvokeAsyncSafe(callback);
|
||||||
@@ -35,19 +37,19 @@ namespace TweetDuck.Core.Notification.Screenshot{
|
|||||||
}
|
}
|
||||||
|
|
||||||
using(IFrame frame = args.Browser.MainFrame){
|
using(IFrame frame = args.Browser.MainFrame){
|
||||||
ScriptLoader.ExecuteScript(frame, script.Replace("{width}", BrowserUtils.Scale(width, DpiScale).ToString()), "screenshot");
|
ScriptLoader.ExecuteScript(frame, script.Replace("{width}", realWidth.ToString()).Replace("{frames}", TweetScreenshotManager.WaitFrames.ToString()), "gen:screenshot");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
SetNotificationSize(width, 1024);
|
SetNotificationSize(realWidth, 1024);
|
||||||
LoadTweet(new TweetNotification(string.Empty, string.Empty, string.Empty, html, 0, string.Empty, string.Empty));
|
LoadTweet(new TweetNotification(string.Empty, string.Empty, string.Empty, html, 0, string.Empty, string.Empty));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string GetTweetHTML(TweetNotification tweet){
|
protected override string GetTweetHTML(TweetNotification tweet){
|
||||||
string html = tweet.GenerateHtml("td-screenshot");
|
string html = tweet.GenerateHtml("td-screenshot", this);
|
||||||
|
|
||||||
foreach(InjectedHTML injection in plugins.NotificationInjections){
|
foreach(InjectedHTML injection in plugins.NotificationInjections){
|
||||||
html = injection.Inject(html);
|
html = injection.InjectInto(html);
|
||||||
}
|
}
|
||||||
|
|
||||||
return html;
|
return html;
|
||||||
@@ -69,6 +71,10 @@ namespace TweetDuck.Core.Notification.Screenshot{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!WindowsUtils.IsAeroEnabled){
|
||||||
|
MoveToVisibleLocation(); // TODO make this look nicer I guess
|
||||||
|
}
|
||||||
|
|
||||||
IntPtr context = NativeMethods.GetDC(this.Handle);
|
IntPtr context = NativeMethods.GetDC(this.Handle);
|
||||||
|
|
||||||
if (context == IntPtr.Zero){
|
if (context == IntPtr.Zero){
|
||||||
|
@@ -27,6 +27,10 @@ namespace TweetDuck.Core.Notification.Screenshot{
|
|||||||
#if GEN_SCREENSHOT_FRAMES
|
#if GEN_SCREENSHOT_FRAMES
|
||||||
private readonly Timer debugger;
|
private readonly Timer debugger;
|
||||||
private int frameCounter;
|
private int frameCounter;
|
||||||
|
|
||||||
|
public const int WaitFrames = 60;
|
||||||
|
#else
|
||||||
|
public const int WaitFrames = 5;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private FormNotificationScreenshotable screenshot;
|
private FormNotificationScreenshotable screenshot;
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Windows.Forms;
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
using TweetDuck.Core.Bridge;
|
using TweetDuck.Core.Bridge;
|
||||||
using TweetDuck.Data;
|
using TweetDuck.Data;
|
||||||
@@ -7,8 +8,7 @@ using TweetDuck.Resources;
|
|||||||
|
|
||||||
namespace TweetDuck.Core.Notification{
|
namespace TweetDuck.Core.Notification{
|
||||||
sealed class TweetNotification{
|
sealed class TweetNotification{
|
||||||
private const string DefaultHeadLayout = @"<html id='tduck' class='os-windows txt-size--14' data-td-font='medium' data-td-theme='dark'><head><meta charset='utf-8'><meta http-equiv='X-UA-Compatible' content='chrome=1'><link rel='stylesheet' href='https://ton.twimg.com/tweetdeck-web/web/css/font.5ef884f9f9.css'><link rel='stylesheet' href='https://ton.twimg.com/tweetdeck-web/web/css/app-dark.5631e0dd42.css'><style type='text/css'>body{background:#222426}</style>";
|
private const string DefaultHeadLayout = @"<html class=""scroll-v os-windows dark txt-size--14"" lang=""en-US"" id=""tduck"" data-td-font=""medium"" data-td-theme=""dark""><head><meta charset=""utf-8""><link href=""https://ton.twimg.com/tweetdeck-web/web/dist/bundle.4b1f87e09d.css"" rel=""stylesheet""><style type='text/css'>body { background: rgb(34, 36, 38) !important }</style>";
|
||||||
private static readonly string CustomCSS = ScriptLoader.LoadResource("styles/notification.css") ?? string.Empty;
|
|
||||||
public static readonly ResourceLink AppLogo = new ResourceLink("https://ton.twimg.com/tduck/avatar", ResourceHandler.FromByteArray(Properties.Resources.avatar, "image/png"));
|
public static readonly ResourceLink AppLogo = new ResourceLink("https://ton.twimg.com/tduck/avatar", ResourceHandler.FromByteArray(Properties.Resources.avatar, "image/png"));
|
||||||
|
|
||||||
public static TweetNotification Example(string html, int characters){
|
public static TweetNotification Example(string html, int characters){
|
||||||
@@ -53,11 +53,11 @@ namespace TweetDuck.Core.Notification{
|
|||||||
return 2000+Math.Max(1000, value*characters);
|
return 2000+Math.Max(1000, value*characters);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GenerateHtml(string bodyClasses){
|
public string GenerateHtml(string bodyClasses, Control sync){
|
||||||
StringBuilder build = new StringBuilder();
|
StringBuilder build = new StringBuilder();
|
||||||
build.Append("<!DOCTYPE html>");
|
build.Append("<!DOCTYPE html>");
|
||||||
build.Append(TweetDeckBridge.NotificationHeadLayout ?? DefaultHeadLayout);
|
build.Append(TweetDeckBridge.NotificationHeadLayout ?? DefaultHeadLayout);
|
||||||
build.Append("<style type='text/css'>").Append(CustomCSS).Append("</style>");
|
build.Append("<style type='text/css'>").Append(ScriptLoader.LoadResource("styles/notification.css", sync) ?? string.Empty).Append("</style>");
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Program.UserConfig.CustomNotificationCSS)){
|
if (!string.IsNullOrEmpty(Program.UserConfig.CustomNotificationCSS)){
|
||||||
build.Append("<style type='text/css'>").Append(Program.UserConfig.CustomNotificationCSS).Append("</style>");
|
build.Append("<style type='text/css'>").Append(Program.UserConfig.CustomNotificationCSS).Append("</style>");
|
||||||
@@ -70,7 +70,7 @@ namespace TweetDuck.Core.Notification{
|
|||||||
build.Append(' ').Append(bodyClasses);
|
build.Append(' ').Append(bodyClasses);
|
||||||
}
|
}
|
||||||
|
|
||||||
build.Append('\'').Append(isExample ? " td-example-notification" : "").Append("><div class='column' style='width:100%!important;height:auto!important;overflow:initial!important;'>");
|
build.Append('\'').Append(isExample ? " td-example-notification" : "").Append("><div class='column' style='width:100%!important;min-height:100vh!important;height:auto!important;overflow:initial!important;'>");
|
||||||
build.Append(html);
|
build.Append(html);
|
||||||
build.Append("</div></body>");
|
build.Append("</div></body>");
|
||||||
build.Append("</html>");
|
build.Append("</html>");
|
||||||
|
@@ -8,7 +8,6 @@ using TweetDuck.Configuration;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Management;
|
using System.Management;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using TweetDuck.Core.Handling;
|
|
||||||
using TweetDuck.Core.Notification;
|
using TweetDuck.Core.Notification;
|
||||||
using TweetDuck.Core.Utils;
|
using TweetDuck.Core.Utils;
|
||||||
using TweetDuck.Plugins;
|
using TweetDuck.Plugins;
|
||||||
@@ -22,7 +21,7 @@ namespace TweetDuck.Core.Other.Analytics{
|
|||||||
return new AnalyticsReport{
|
return new AnalyticsReport{
|
||||||
{ "App Version" , Program.VersionTag },
|
{ "App Version" , Program.VersionTag },
|
||||||
{ "App Type" , Program.IsPortable ? "portable" : "installed" },
|
{ "App Type" , Program.IsPortable ? "portable" : "installed" },
|
||||||
{ "App Dev Tools" , Bool(ContextMenuBase.HasDevTools) },
|
{ "App Dev Tools" , Bool(BrowserUtils.HasDevTools) },
|
||||||
0,
|
0,
|
||||||
{ "System Name" , SystemName },
|
{ "System Name" , SystemName },
|
||||||
{ "System Edition" , SystemEdition },
|
{ "System Edition" , SystemEdition },
|
||||||
@@ -42,7 +41,6 @@ namespace TweetDuck.Core.Other.Analytics{
|
|||||||
{ "Clear Cache Threshold" , Exact(SysConfig.ClearCacheThreshold) },
|
{ "Clear Cache Threshold" , Exact(SysConfig.ClearCacheThreshold) },
|
||||||
0,
|
0,
|
||||||
{ "Expand Links" , Bool(UserConfig.ExpandLinksOnHover) },
|
{ "Expand Links" , Bool(UserConfig.ExpandLinksOnHover) },
|
||||||
{ "Switch Account Selectors" , Bool(false) }, // TODO remove in next major update
|
|
||||||
{ "Search In First Column" , Bool(UserConfig.OpenSearchInFirstColumn) },
|
{ "Search In First Column" , Bool(UserConfig.OpenSearchInFirstColumn) },
|
||||||
{ "Keep Like Follow Dialogs Open" , Bool(UserConfig.KeepLikeFollowDialogsOpen) },
|
{ "Keep Like Follow Dialogs Open" , Bool(UserConfig.KeepLikeFollowDialogsOpen) },
|
||||||
{ "Best Image Quality" , Bool(UserConfig.BestImageQuality) },
|
{ "Best Image Quality" , Bool(UserConfig.BestImageQuality) },
|
||||||
|
@@ -5,7 +5,7 @@ using System.Windows.Forms;
|
|||||||
using TweetDuck.Core.Utils;
|
using TweetDuck.Core.Utils;
|
||||||
|
|
||||||
namespace TweetDuck.Core.Other{
|
namespace TweetDuck.Core.Other{
|
||||||
sealed partial class FormAbout : Form{
|
sealed partial class FormAbout : Form, FormManager.IAppDialog{
|
||||||
private const string TipsLink = "https://github.com/chylex/TweetDuck/wiki";
|
private const string TipsLink = "https://github.com/chylex/TweetDuck/wiki";
|
||||||
private const string IssuesLink = "https://github.com/chylex/TweetDuck/issues";
|
private const string IssuesLink = "https://github.com/chylex/TweetDuck/issues";
|
||||||
|
|
||||||
|
@@ -12,7 +12,7 @@ using TweetDuck.Data;
|
|||||||
using TweetDuck.Resources;
|
using TweetDuck.Resources;
|
||||||
|
|
||||||
namespace TweetDuck.Core.Other{
|
namespace TweetDuck.Core.Other{
|
||||||
sealed partial class FormGuide : Form{
|
sealed partial class FormGuide : Form, FormManager.IAppDialog{
|
||||||
private const string GuideUrl = "https://tweetduck.chylex.com/guide/v2/";
|
private const string GuideUrl = "https://tweetduck.chylex.com/guide/v2/";
|
||||||
private const string GuidePathRegex = @"^guide(?:/v\d+)?(?:/(#.*))?";
|
private const string GuidePathRegex = @"^guide(?:/v\d+)?(?:/(#.*))?";
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ namespace TweetDuck.Core.Other{
|
|||||||
MenuHandler = new ContextMenuGuide(owner),
|
MenuHandler = new ContextMenuGuide(owner),
|
||||||
JsDialogHandler = new JavaScriptDialogHandler(),
|
JsDialogHandler = new JavaScriptDialogHandler(),
|
||||||
LifeSpanHandler = new LifeSpanHandler(),
|
LifeSpanHandler = new LifeSpanHandler(),
|
||||||
RequestHandler = new RequestHandlerBrowser()
|
RequestHandler = new RequestHandlerBase(true)
|
||||||
};
|
};
|
||||||
|
|
||||||
browser.LoadingStateChanged += browser_LoadingStateChanged;
|
browser.LoadingStateChanged += browser_LoadingStateChanged;
|
||||||
|
@@ -7,7 +7,7 @@ using TweetDuck.Plugins;
|
|||||||
using TweetDuck.Plugins.Controls;
|
using TweetDuck.Plugins.Controls;
|
||||||
|
|
||||||
namespace TweetDuck.Core.Other{
|
namespace TweetDuck.Core.Other{
|
||||||
sealed partial class FormPlugins : Form{
|
sealed partial class FormPlugins : Form, FormManager.IAppDialog{
|
||||||
private readonly PluginManager pluginManager;
|
private readonly PluginManager pluginManager;
|
||||||
|
|
||||||
public FormPlugins(){
|
public FormPlugins(){
|
||||||
|
@@ -13,7 +13,7 @@ using TweetDuck.Plugins;
|
|||||||
using TweetDuck.Updates;
|
using TweetDuck.Updates;
|
||||||
|
|
||||||
namespace TweetDuck.Core.Other{
|
namespace TweetDuck.Core.Other{
|
||||||
sealed partial class FormSettings : Form{
|
sealed partial class FormSettings : Form, FormManager.IAppDialog{
|
||||||
private readonly FormBrowser browser;
|
private readonly FormBrowser browser;
|
||||||
private readonly PluginManager plugins;
|
private readonly PluginManager plugins;
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ namespace TweetDuck.Core.Other{
|
|||||||
AddButton("Notifications", () => new TabSettingsNotifications(new FormNotificationExample(this.browser, this.plugins)));
|
AddButton("Notifications", () => new TabSettingsNotifications(new FormNotificationExample(this.browser, this.plugins)));
|
||||||
AddButton("Sounds", () => new TabSettingsSounds(this.browser.PlaySoundNotification));
|
AddButton("Sounds", () => new TabSettingsSounds(this.browser.PlaySoundNotification));
|
||||||
AddButton("Feedback", () => new TabSettingsFeedback(analytics, AnalyticsReportGenerator.ExternalInfo.From(this.browser), this.plugins));
|
AddButton("Feedback", () => new TabSettingsFeedback(analytics, AnalyticsReportGenerator.ExternalInfo.From(this.browser), this.plugins));
|
||||||
AddButton("Advanced", () => new TabSettingsAdvanced(this.browser.ReinjectCustomCSS));
|
AddButton("Advanced", () => new TabSettingsAdvanced(this.browser.ReinjectCustomCSS, this.browser.OpenDevTools));
|
||||||
|
|
||||||
SelectTab(tabs[startTab ?? typeof(TabSettingsGeneral)]);
|
SelectTab(tabs[startTab ?? typeof(TabSettingsGeneral)]);
|
||||||
}
|
}
|
||||||
|
@@ -63,10 +63,10 @@
|
|||||||
this.labelInfo.Location = new System.Drawing.Point(12, 9);
|
this.labelInfo.Location = new System.Drawing.Point(12, 9);
|
||||||
this.labelInfo.Margin = new System.Windows.Forms.Padding(3, 0, 3, 3);
|
this.labelInfo.Margin = new System.Windows.Forms.Padding(3, 0, 3, 3);
|
||||||
this.labelInfo.Name = "labelInfo";
|
this.labelInfo.Name = "labelInfo";
|
||||||
this.labelInfo.Size = new System.Drawing.Size(431, 30);
|
this.labelInfo.Size = new System.Drawing.Size(434, 30);
|
||||||
this.labelInfo.TabIndex = 0;
|
this.labelInfo.TabIndex = 0;
|
||||||
this.labelInfo.Text = "When enabled, this data will be sent over a secure network roughly twice a week.\r" +
|
this.labelInfo.Text = "When enabled, this data will be sent over a secure network roughly every 14 days." +
|
||||||
"\nSome numbers in the report were made imprecise on purpose.";
|
"\r\nSome numbers in the report were made imprecise on purpose.";
|
||||||
//
|
//
|
||||||
// DialogSettingsAnalytics
|
// DialogSettingsAnalytics
|
||||||
//
|
//
|
||||||
|
@@ -27,33 +27,30 @@
|
|||||||
this.textBoxBrowserCSS = new System.Windows.Forms.TextBox();
|
this.textBoxBrowserCSS = new System.Windows.Forms.TextBox();
|
||||||
this.btnCancel = new System.Windows.Forms.Button();
|
this.btnCancel = new System.Windows.Forms.Button();
|
||||||
this.btnApply = new System.Windows.Forms.Button();
|
this.btnApply = new System.Windows.Forms.Button();
|
||||||
this.splitContainer = new System.Windows.Forms.SplitContainer();
|
|
||||||
this.labelBrowser = new System.Windows.Forms.Label();
|
|
||||||
this.labelNotification = new System.Windows.Forms.Label();
|
|
||||||
this.textBoxNotificationCSS = new System.Windows.Forms.TextBox();
|
this.textBoxNotificationCSS = new System.Windows.Forms.TextBox();
|
||||||
this.labelWarning = new System.Windows.Forms.Label();
|
this.btnOpenDevTools = new System.Windows.Forms.Button();
|
||||||
this.btnOpenWiki = new System.Windows.Forms.Button();
|
|
||||||
this.timerTestBrowser = new System.Windows.Forms.Timer(this.components);
|
this.timerTestBrowser = new System.Windows.Forms.Timer(this.components);
|
||||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
|
this.tabPanel = new System.Windows.Forms.TabControl();
|
||||||
this.splitContainer.Panel1.SuspendLayout();
|
this.tabPageBrowser = new System.Windows.Forms.TabPage();
|
||||||
this.splitContainer.Panel2.SuspendLayout();
|
this.tabPageNotification = new System.Windows.Forms.TabPage();
|
||||||
this.splitContainer.SuspendLayout();
|
this.tabPanel.SuspendLayout();
|
||||||
|
this.tabPageBrowser.SuspendLayout();
|
||||||
|
this.tabPageNotification.SuspendLayout();
|
||||||
this.SuspendLayout();
|
this.SuspendLayout();
|
||||||
//
|
//
|
||||||
// textBoxBrowserCSS
|
// textBoxBrowserCSS
|
||||||
//
|
//
|
||||||
this.textBoxBrowserCSS.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
this.textBoxBrowserCSS.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
| System.Windows.Forms.AnchorStyles.Left)
|
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
this.textBoxBrowserCSS.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
this.textBoxBrowserCSS.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
this.textBoxBrowserCSS.Location = new System.Drawing.Point(0, 16);
|
this.textBoxBrowserCSS.Location = new System.Drawing.Point(3, 3);
|
||||||
this.textBoxBrowserCSS.Margin = new System.Windows.Forms.Padding(0, 3, 0, 0);
|
this.textBoxBrowserCSS.Margin = new System.Windows.Forms.Padding(0, 3, 0, 0);
|
||||||
this.textBoxBrowserCSS.Multiline = true;
|
this.textBoxBrowserCSS.Multiline = true;
|
||||||
this.textBoxBrowserCSS.Name = "textBoxBrowserCSS";
|
this.textBoxBrowserCSS.Name = "textBoxBrowserCSS";
|
||||||
this.textBoxBrowserCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
this.textBoxBrowserCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||||
this.textBoxBrowserCSS.Size = new System.Drawing.Size(378, 251);
|
this.textBoxBrowserCSS.Size = new System.Drawing.Size(426, 332);
|
||||||
this.textBoxBrowserCSS.TabIndex = 1;
|
this.textBoxBrowserCSS.TabIndex = 0;
|
||||||
this.textBoxBrowserCSS.WordWrap = false;
|
this.textBoxBrowserCSS.WordWrap = false;
|
||||||
|
this.textBoxBrowserCSS.KeyDown += new System.Windows.Forms.KeyEventHandler(this.textBoxCSS_KeyDown);
|
||||||
this.textBoxBrowserCSS.KeyUp += new System.Windows.Forms.KeyEventHandler(this.textBoxBrowserCSS_KeyUp);
|
this.textBoxBrowserCSS.KeyUp += new System.Windows.Forms.KeyEventHandler(this.textBoxBrowserCSS_KeyUp);
|
||||||
//
|
//
|
||||||
// btnCancel
|
// btnCancel
|
||||||
@@ -61,7 +58,7 @@
|
|||||||
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.btnCancel.AutoSize = true;
|
this.btnCancel.AutoSize = true;
|
||||||
this.btnCancel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
this.btnCancel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
this.btnCancel.Location = new System.Drawing.Point(657, 285);
|
this.btnCancel.Location = new System.Drawing.Point(337, 384);
|
||||||
this.btnCancel.Name = "btnCancel";
|
this.btnCancel.Name = "btnCancel";
|
||||||
this.btnCancel.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
|
this.btnCancel.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
|
||||||
this.btnCancel.Size = new System.Drawing.Size(57, 25);
|
this.btnCancel.Size = new System.Drawing.Size(57, 25);
|
||||||
@@ -75,7 +72,7 @@
|
|||||||
this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.btnApply.AutoSize = true;
|
this.btnApply.AutoSize = true;
|
||||||
this.btnApply.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
this.btnApply.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
this.btnApply.Location = new System.Drawing.Point(720, 285);
|
this.btnApply.Location = new System.Drawing.Point(400, 384);
|
||||||
this.btnApply.Name = "btnApply";
|
this.btnApply.Name = "btnApply";
|
||||||
this.btnApply.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
|
this.btnApply.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
|
||||||
this.btnApply.Size = new System.Drawing.Size(52, 25);
|
this.btnApply.Size = new System.Drawing.Size(52, 25);
|
||||||
@@ -84,117 +81,94 @@
|
|||||||
this.btnApply.UseVisualStyleBackColor = true;
|
this.btnApply.UseVisualStyleBackColor = true;
|
||||||
this.btnApply.Click += new System.EventHandler(this.btnApply_Click);
|
this.btnApply.Click += new System.EventHandler(this.btnApply_Click);
|
||||||
//
|
//
|
||||||
// splitContainer
|
|
||||||
//
|
|
||||||
this.splitContainer.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
|
||||||
| System.Windows.Forms.AnchorStyles.Left)
|
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
this.splitContainer.Location = new System.Drawing.Point(12, 12);
|
|
||||||
this.splitContainer.Name = "splitContainer";
|
|
||||||
//
|
|
||||||
// splitContainer.Panel1
|
|
||||||
//
|
|
||||||
this.splitContainer.Panel1.Controls.Add(this.labelBrowser);
|
|
||||||
this.splitContainer.Panel1.Controls.Add(this.textBoxBrowserCSS);
|
|
||||||
this.splitContainer.Panel1MinSize = 64;
|
|
||||||
//
|
|
||||||
// splitContainer.Panel2
|
|
||||||
//
|
|
||||||
this.splitContainer.Panel2.Controls.Add(this.labelNotification);
|
|
||||||
this.splitContainer.Panel2.Controls.Add(this.textBoxNotificationCSS);
|
|
||||||
this.splitContainer.Panel2MinSize = 64;
|
|
||||||
this.splitContainer.Size = new System.Drawing.Size(760, 267);
|
|
||||||
this.splitContainer.SplitterDistance = 378;
|
|
||||||
this.splitContainer.SplitterWidth = 5;
|
|
||||||
this.splitContainer.TabIndex = 0;
|
|
||||||
//
|
|
||||||
// labelBrowser
|
|
||||||
//
|
|
||||||
this.labelBrowser.AutoSize = true;
|
|
||||||
this.labelBrowser.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
|
||||||
this.labelBrowser.Location = new System.Drawing.Point(-3, 0);
|
|
||||||
this.labelBrowser.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
|
|
||||||
this.labelBrowser.Name = "labelBrowser";
|
|
||||||
this.labelBrowser.Size = new System.Drawing.Size(49, 15);
|
|
||||||
this.labelBrowser.TabIndex = 0;
|
|
||||||
this.labelBrowser.Text = "Browser";
|
|
||||||
//
|
|
||||||
// labelNotification
|
|
||||||
//
|
|
||||||
this.labelNotification.AutoSize = true;
|
|
||||||
this.labelNotification.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
|
||||||
this.labelNotification.Location = new System.Drawing.Point(-3, 0);
|
|
||||||
this.labelNotification.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
|
|
||||||
this.labelNotification.Name = "labelNotification";
|
|
||||||
this.labelNotification.Size = new System.Drawing.Size(70, 15);
|
|
||||||
this.labelNotification.TabIndex = 0;
|
|
||||||
this.labelNotification.Text = "Notification";
|
|
||||||
//
|
|
||||||
// textBoxNotificationCSS
|
// textBoxNotificationCSS
|
||||||
//
|
//
|
||||||
this.textBoxNotificationCSS.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
this.textBoxNotificationCSS.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
| System.Windows.Forms.AnchorStyles.Left)
|
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
this.textBoxNotificationCSS.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
this.textBoxNotificationCSS.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
this.textBoxNotificationCSS.Location = new System.Drawing.Point(0, 16);
|
this.textBoxNotificationCSS.Location = new System.Drawing.Point(3, 3);
|
||||||
this.textBoxNotificationCSS.Margin = new System.Windows.Forms.Padding(0, 3, 0, 0);
|
this.textBoxNotificationCSS.Margin = new System.Windows.Forms.Padding(0, 3, 0, 0);
|
||||||
this.textBoxNotificationCSS.Multiline = true;
|
this.textBoxNotificationCSS.Multiline = true;
|
||||||
this.textBoxNotificationCSS.Name = "textBoxNotificationCSS";
|
this.textBoxNotificationCSS.Name = "textBoxNotificationCSS";
|
||||||
this.textBoxNotificationCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
this.textBoxNotificationCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||||
this.textBoxNotificationCSS.Size = new System.Drawing.Size(372, 251);
|
this.textBoxNotificationCSS.Size = new System.Drawing.Size(426, 332);
|
||||||
this.textBoxNotificationCSS.TabIndex = 1;
|
this.textBoxNotificationCSS.TabIndex = 0;
|
||||||
this.textBoxNotificationCSS.WordWrap = false;
|
this.textBoxNotificationCSS.WordWrap = false;
|
||||||
|
this.textBoxNotificationCSS.KeyDown += new System.Windows.Forms.KeyEventHandler(this.textBoxCSS_KeyDown);
|
||||||
//
|
//
|
||||||
// labelWarning
|
// btnOpenDevTools
|
||||||
//
|
//
|
||||||
this.labelWarning.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
this.btnOpenDevTools.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
this.labelWarning.AutoSize = true;
|
this.btnOpenDevTools.AutoSize = true;
|
||||||
this.labelWarning.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
this.btnOpenDevTools.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
this.labelWarning.Location = new System.Drawing.Point(94, 290);
|
this.btnOpenDevTools.Location = new System.Drawing.Point(12, 384);
|
||||||
this.labelWarning.Name = "labelWarning";
|
this.btnOpenDevTools.Name = "btnOpenDevTools";
|
||||||
this.labelWarning.Size = new System.Drawing.Size(373, 15);
|
this.btnOpenDevTools.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
|
||||||
this.labelWarning.TabIndex = 3;
|
this.btnOpenDevTools.Size = new System.Drawing.Size(104, 25);
|
||||||
this.labelWarning.Text = "The code is not validated, please make sure there are no syntax errors.";
|
this.btnOpenDevTools.TabIndex = 3;
|
||||||
//
|
this.btnOpenDevTools.Text = "Open Dev Tools";
|
||||||
// btnOpenWiki
|
this.btnOpenDevTools.UseVisualStyleBackColor = true;
|
||||||
//
|
this.btnOpenDevTools.Click += new System.EventHandler(this.btnOpenDevTools_Click);
|
||||||
this.btnOpenWiki.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
|
||||||
this.btnOpenWiki.AutoSize = true;
|
|
||||||
this.btnOpenWiki.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
|
||||||
this.btnOpenWiki.Location = new System.Drawing.Point(12, 285);
|
|
||||||
this.btnOpenWiki.Name = "btnOpenWiki";
|
|
||||||
this.btnOpenWiki.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
|
|
||||||
this.btnOpenWiki.Size = new System.Drawing.Size(76, 25);
|
|
||||||
this.btnOpenWiki.TabIndex = 4;
|
|
||||||
this.btnOpenWiki.Text = "Open Wiki";
|
|
||||||
this.btnOpenWiki.UseVisualStyleBackColor = true;
|
|
||||||
this.btnOpenWiki.Click += new System.EventHandler(this.btnOpenWiki_Click);
|
|
||||||
//
|
//
|
||||||
// timerTestBrowser
|
// timerTestBrowser
|
||||||
//
|
//
|
||||||
this.timerTestBrowser.Interval = 500;
|
this.timerTestBrowser.Interval = 400;
|
||||||
this.timerTestBrowser.Tick += new System.EventHandler(this.timerTestBrowser_Tick);
|
this.timerTestBrowser.Tick += new System.EventHandler(this.timerTestBrowser_Tick);
|
||||||
//
|
//
|
||||||
|
// tabPanel
|
||||||
|
//
|
||||||
|
this.tabPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.tabPanel.Controls.Add(this.tabPageBrowser);
|
||||||
|
this.tabPanel.Controls.Add(this.tabPageNotification);
|
||||||
|
this.tabPanel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
|
this.tabPanel.Location = new System.Drawing.Point(12, 12);
|
||||||
|
this.tabPanel.Name = "tabPanel";
|
||||||
|
this.tabPanel.SelectedIndex = 0;
|
||||||
|
this.tabPanel.Size = new System.Drawing.Size(440, 366);
|
||||||
|
this.tabPanel.TabIndex = 0;
|
||||||
|
this.tabPanel.SelectedIndexChanged += new System.EventHandler(this.tabPanel_SelectedIndexChanged);
|
||||||
|
//
|
||||||
|
// tabPageBrowser
|
||||||
|
//
|
||||||
|
this.tabPageBrowser.Controls.Add(this.textBoxBrowserCSS);
|
||||||
|
this.tabPageBrowser.Location = new System.Drawing.Point(4, 24);
|
||||||
|
this.tabPageBrowser.Name = "tabPageBrowser";
|
||||||
|
this.tabPageBrowser.Padding = new System.Windows.Forms.Padding(3);
|
||||||
|
this.tabPageBrowser.Size = new System.Drawing.Size(432, 338);
|
||||||
|
this.tabPageBrowser.TabIndex = 0;
|
||||||
|
this.tabPageBrowser.Text = "Browser";
|
||||||
|
this.tabPageBrowser.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// tabPageNotification
|
||||||
|
//
|
||||||
|
this.tabPageNotification.Controls.Add(this.textBoxNotificationCSS);
|
||||||
|
this.tabPageNotification.Location = new System.Drawing.Point(4, 24);
|
||||||
|
this.tabPageNotification.Name = "tabPageNotification";
|
||||||
|
this.tabPageNotification.Padding = new System.Windows.Forms.Padding(3);
|
||||||
|
this.tabPageNotification.Size = new System.Drawing.Size(432, 338);
|
||||||
|
this.tabPageNotification.TabIndex = 1;
|
||||||
|
this.tabPageNotification.Text = "Notification";
|
||||||
|
this.tabPageNotification.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
// DialogSettingsCSS
|
// DialogSettingsCSS
|
||||||
//
|
//
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
this.ClientSize = new System.Drawing.Size(784, 322);
|
this.ClientSize = new System.Drawing.Size(464, 421);
|
||||||
this.Controls.Add(this.btnOpenWiki);
|
this.Controls.Add(this.tabPanel);
|
||||||
this.Controls.Add(this.labelWarning);
|
this.Controls.Add(this.btnOpenDevTools);
|
||||||
this.Controls.Add(this.splitContainer);
|
|
||||||
this.Controls.Add(this.btnApply);
|
this.Controls.Add(this.btnApply);
|
||||||
this.Controls.Add(this.btnCancel);
|
this.Controls.Add(this.btnCancel);
|
||||||
this.MinimumSize = new System.Drawing.Size(620, 160);
|
this.MinimumSize = new System.Drawing.Size(320, 240);
|
||||||
this.Name = "DialogSettingsCSS";
|
this.Name = "DialogSettingsCSS";
|
||||||
this.ShowIcon = false;
|
this.ShowIcon = false;
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||||
this.splitContainer.Panel1.ResumeLayout(false);
|
this.tabPanel.ResumeLayout(false);
|
||||||
this.splitContainer.Panel1.PerformLayout();
|
this.tabPageBrowser.ResumeLayout(false);
|
||||||
this.splitContainer.Panel2.ResumeLayout(false);
|
this.tabPageBrowser.PerformLayout();
|
||||||
this.splitContainer.Panel2.PerformLayout();
|
this.tabPageNotification.ResumeLayout(false);
|
||||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit();
|
this.tabPageNotification.PerformLayout();
|
||||||
this.splitContainer.ResumeLayout(false);
|
|
||||||
this.ResumeLayout(false);
|
this.ResumeLayout(false);
|
||||||
this.PerformLayout();
|
this.PerformLayout();
|
||||||
|
|
||||||
@@ -205,12 +179,11 @@
|
|||||||
private System.Windows.Forms.TextBox textBoxBrowserCSS;
|
private System.Windows.Forms.TextBox textBoxBrowserCSS;
|
||||||
private System.Windows.Forms.Button btnCancel;
|
private System.Windows.Forms.Button btnCancel;
|
||||||
private System.Windows.Forms.Button btnApply;
|
private System.Windows.Forms.Button btnApply;
|
||||||
private System.Windows.Forms.SplitContainer splitContainer;
|
|
||||||
private System.Windows.Forms.TextBox textBoxNotificationCSS;
|
private System.Windows.Forms.TextBox textBoxNotificationCSS;
|
||||||
private System.Windows.Forms.Label labelBrowser;
|
private System.Windows.Forms.Button btnOpenDevTools;
|
||||||
private System.Windows.Forms.Label labelNotification;
|
|
||||||
private System.Windows.Forms.Label labelWarning;
|
|
||||||
private System.Windows.Forms.Button btnOpenWiki;
|
|
||||||
private System.Windows.Forms.Timer timerTestBrowser;
|
private System.Windows.Forms.Timer timerTestBrowser;
|
||||||
|
private System.Windows.Forms.TabControl tabPanel;
|
||||||
|
private System.Windows.Forms.TabPage tabPageBrowser;
|
||||||
|
private System.Windows.Forms.TabPage tabPageNotification;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,4 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Core.Controls;
|
using TweetDuck.Core.Controls;
|
||||||
using TweetDuck.Core.Utils;
|
using TweetDuck.Core.Utils;
|
||||||
@@ -9,19 +11,108 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
|
|||||||
public string NotificationCSS => textBoxNotificationCSS.Text;
|
public string NotificationCSS => textBoxNotificationCSS.Text;
|
||||||
|
|
||||||
private readonly Action<string> reinjectBrowserCSS;
|
private readonly Action<string> reinjectBrowserCSS;
|
||||||
|
private readonly Action openDevTools;
|
||||||
|
|
||||||
public DialogSettingsCSS(Action<string> reinjectBrowserCSS){ // TODO high dpi breaks scaling of things inside the panel...
|
public DialogSettingsCSS(Action<string> reinjectBrowserCSS, Action openDevTools){
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Text = Program.BrandName+" Options - CSS";
|
Text = Program.BrandName+" Options - CSS";
|
||||||
|
|
||||||
this.reinjectBrowserCSS = reinjectBrowserCSS;
|
this.reinjectBrowserCSS = reinjectBrowserCSS;
|
||||||
|
this.openDevTools = openDevTools;
|
||||||
|
|
||||||
textBoxBrowserCSS.EnableMultilineShortcuts();
|
textBoxBrowserCSS.EnableMultilineShortcuts();
|
||||||
textBoxBrowserCSS.Text = Program.UserConfig.CustomBrowserCSS ?? "";
|
textBoxBrowserCSS.Text = Program.UserConfig.CustomBrowserCSS ?? "";
|
||||||
|
|
||||||
textBoxNotificationCSS.EnableMultilineShortcuts();
|
textBoxNotificationCSS.EnableMultilineShortcuts();
|
||||||
textBoxNotificationCSS.Text = Program.UserConfig.CustomNotificationCSS ?? "";
|
textBoxNotificationCSS.Text = Program.UserConfig.CustomNotificationCSS ?? "";
|
||||||
|
|
||||||
|
if (!BrowserUtils.HasDevTools){
|
||||||
|
btnOpenDevTools.Enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ActiveControl = textBoxBrowserCSS;
|
||||||
|
textBoxBrowserCSS.Select(textBoxBrowserCSS.TextLength, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tabPanel_SelectedIndexChanged(object sender, EventArgs e){
|
||||||
|
TextBox tb = tabPanel.SelectedTab.Controls.OfType<TextBox>().FirstOrDefault();
|
||||||
|
|
||||||
|
if (tb != null){
|
||||||
|
tb.Focus();
|
||||||
|
tb.Select(tb.TextLength, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void textBoxCSS_KeyDown(object sender, KeyEventArgs e){
|
||||||
|
TextBox tb = (TextBox)sender;
|
||||||
|
string text = tb.Text;
|
||||||
|
|
||||||
|
if (e.KeyCode == Keys.Back && e.Modifiers == Keys.Control){
|
||||||
|
e.SuppressKeyPress = true;
|
||||||
|
|
||||||
|
int deleteTo = tb.SelectionStart;
|
||||||
|
|
||||||
|
if (deleteTo > 0){
|
||||||
|
char initialChar = text[--deleteTo];
|
||||||
|
bool shouldDeleteAlphanumeric = char.IsLetterOrDigit(initialChar);
|
||||||
|
|
||||||
|
while(--deleteTo >= 0){
|
||||||
|
if ((shouldDeleteAlphanumeric && !char.IsLetterOrDigit(text[deleteTo])) ||
|
||||||
|
(!shouldDeleteAlphanumeric && text[deleteTo] != initialChar)){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(deleteTo < text.Length-1 && text[deleteTo] == '\r' && text[deleteTo+1] == '\n')){
|
||||||
|
++deleteTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
tb.Select(deleteTo, tb.SelectionLength+tb.SelectionStart-deleteTo);
|
||||||
|
tb.SelectedText = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (e.KeyCode == Keys.Back && e.Modifiers == Keys.None){
|
||||||
|
int deleteTo = tb.SelectionStart;
|
||||||
|
|
||||||
|
if (deleteTo > 1 && text[deleteTo-1] == ' ' && text[deleteTo-2] == ' '){
|
||||||
|
e.SuppressKeyPress = true;
|
||||||
|
|
||||||
|
tb.Select(deleteTo-2, 2);
|
||||||
|
tb.SelectedText = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (e.KeyCode == Keys.Enter && e.Modifiers == Keys.None && tb.SelectionLength == 0){
|
||||||
|
int insertAt = tb.SelectionStart, cursorOffset = 0;
|
||||||
|
string insertText;
|
||||||
|
|
||||||
|
if (insertAt == 0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (text[insertAt-1] == '{'){
|
||||||
|
insertText = Environment.NewLine+" ";
|
||||||
|
|
||||||
|
int nextBracket = insertAt < text.Length ? text.IndexOfAny(new char[]{ '{', '}' }, insertAt+1) : -1;
|
||||||
|
|
||||||
|
if (nextBracket == -1 || text[nextBracket] == '{'){
|
||||||
|
string insertExtra = Environment.NewLine+"}";
|
||||||
|
insertText += insertExtra;
|
||||||
|
cursorOffset -= insertExtra.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
int lineStart = text.LastIndexOf('\n', tb.SelectionStart-1);
|
||||||
|
|
||||||
|
Match match = Regex.Match(text.Substring(lineStart == -1 ? 0 : lineStart+1), "^([ \t]+)");
|
||||||
|
insertText = match.Success ? Environment.NewLine+match.Groups[1].Value : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(insertText)){
|
||||||
|
e.SuppressKeyPress = true;
|
||||||
|
tb.Text = text.Insert(insertAt, insertText);
|
||||||
|
tb.SelectionStart = insertAt+cursorOffset+insertText.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void textBoxBrowserCSS_KeyUp(object sender, KeyEventArgs e){
|
private void textBoxBrowserCSS_KeyUp(object sender, KeyEventArgs e){
|
||||||
@@ -34,8 +125,8 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
|
|||||||
timerTestBrowser.Stop();
|
timerTestBrowser.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnOpenWiki_Click(object sender, EventArgs e){
|
private void btnOpenDevTools_Click(object sender, EventArgs e){
|
||||||
BrowserUtils.OpenExternalBrowser("https://github.com/chylex/TweetDuck/wiki");
|
openDevTools();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnApply_Click(object sender, EventArgs e){
|
private void btnApply_Click(object sender, EventArgs e){
|
||||||
|
@@ -34,7 +34,7 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
|
|||||||
|
|
||||||
private ProfileManager.Items _selectedItems = ProfileManager.Items.None;
|
private ProfileManager.Items _selectedItems = ProfileManager.Items.None;
|
||||||
|
|
||||||
public DialogSettingsManage(PluginManager plugins){
|
public DialogSettingsManage(PluginManager plugins, bool openImportImmediately = false){
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.plugins = plugins;
|
this.plugins = plugins;
|
||||||
@@ -44,6 +44,11 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
|
|||||||
this.checkBoxMap[cbSystemConfig] = ProfileManager.Items.SystemConfig;
|
this.checkBoxMap[cbSystemConfig] = ProfileManager.Items.SystemConfig;
|
||||||
this.checkBoxMap[cbSession] = ProfileManager.Items.Session;
|
this.checkBoxMap[cbSession] = ProfileManager.Items.Session;
|
||||||
this.checkBoxMap[cbPluginData] = ProfileManager.Items.PluginData;
|
this.checkBoxMap[cbPluginData] = ProfileManager.Items.PluginData;
|
||||||
|
|
||||||
|
if (openImportImmediately){
|
||||||
|
radioImport.Checked = true;
|
||||||
|
btnContinue_Click(null, EventArgs.Empty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void radioDecision_CheckedChanged(object sender, EventArgs e){
|
private void radioDecision_CheckedChanged(object sender, EventArgs e){
|
||||||
|
@@ -13,18 +13,20 @@ namespace TweetDuck.Core.Other.Settings{
|
|||||||
private static SystemConfig SysConfig => Program.SystemConfig;
|
private static SystemConfig SysConfig => Program.SystemConfig;
|
||||||
|
|
||||||
private readonly Action<string> reinjectBrowserCSS;
|
private readonly Action<string> reinjectBrowserCSS;
|
||||||
|
private readonly Action openDevTools;
|
||||||
|
|
||||||
public TabSettingsAdvanced(Action<string> reinjectBrowserCSS){
|
public TabSettingsAdvanced(Action<string> reinjectBrowserCSS, Action openDevTools){
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.reinjectBrowserCSS = reinjectBrowserCSS;
|
this.reinjectBrowserCSS = reinjectBrowserCSS;
|
||||||
|
this.openDevTools = openDevTools;
|
||||||
|
|
||||||
toolTip.SetToolTip(btnOpenAppFolder, "Opens the folder where the app is located.");
|
toolTip.SetToolTip(btnOpenAppFolder, "Opens the folder where the app is located.");
|
||||||
toolTip.SetToolTip(btnOpenDataFolder, "Opens the folder where your profile data is located.");
|
toolTip.SetToolTip(btnOpenDataFolder, "Opens the folder where your profile data is located.");
|
||||||
toolTip.SetToolTip(btnRestart, "Restarts the program using the same command\r\nline arguments that were used at launch.");
|
toolTip.SetToolTip(btnRestart, "Restarts the program using the same command\r\nline arguments that were used at launch.");
|
||||||
toolTip.SetToolTip(btnRestartArgs, "Restarts the program with customizable\r\ncommand line arguments.");
|
toolTip.SetToolTip(btnRestartArgs, "Restarts the program with customizable\r\ncommand line arguments.");
|
||||||
|
|
||||||
toolTip.SetToolTip(checkHardwareAcceleration, "Uses graphics card to improve performance. Disable if you experience\r\nvisual glitches. This option will not be exported in a profile.");
|
toolTip.SetToolTip(checkHardwareAcceleration, "Uses graphics card to improve performance. Disable if you experience visual glitches, or to save a small amount of RAM.");
|
||||||
|
|
||||||
toolTip.SetToolTip(btnClearCache, "Clearing cache will free up space taken by downloaded images and other resources.");
|
toolTip.SetToolTip(btnClearCache, "Clearing cache will free up space taken by downloaded images and other resources.");
|
||||||
toolTip.SetToolTip(checkClearCacheAuto, "Automatically clears cache when its size exceeds the set threshold. Note that cache can only be cleared when closing TweetDuck.");
|
toolTip.SetToolTip(checkClearCacheAuto, "Automatically clears cache when its size exceeds the set threshold. Note that cache can only be cleared when closing TweetDuck.");
|
||||||
@@ -32,13 +34,7 @@ namespace TweetDuck.Core.Other.Settings{
|
|||||||
toolTip.SetToolTip(btnEditCefArgs, "Set custom command line arguments for Chromium Embedded Framework.");
|
toolTip.SetToolTip(btnEditCefArgs, "Set custom command line arguments for Chromium Embedded Framework.");
|
||||||
toolTip.SetToolTip(btnEditCSS, "Set custom CSS for browser and notification windows.");
|
toolTip.SetToolTip(btnEditCSS, "Set custom CSS for browser and notification windows.");
|
||||||
|
|
||||||
if (SystemConfig.IsHardwareAccelerationSupported){
|
|
||||||
checkHardwareAcceleration.Checked = SysConfig.HardwareAcceleration;
|
checkHardwareAcceleration.Checked = SysConfig.HardwareAcceleration;
|
||||||
}
|
|
||||||
else{
|
|
||||||
checkHardwareAcceleration.Enabled = false;
|
|
||||||
checkHardwareAcceleration.Checked = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
checkClearCacheAuto.Checked = SysConfig.ClearCacheAutomatically;
|
checkClearCacheAuto.Checked = SysConfig.ClearCacheAutomatically;
|
||||||
numClearCacheThreshold.Enabled = checkClearCacheAuto.Checked;
|
numClearCacheThreshold.Enabled = checkClearCacheAuto.Checked;
|
||||||
@@ -109,7 +105,7 @@ namespace TweetDuck.Core.Other.Settings{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void btnEditCSS_Click(object sender, EventArgs e){
|
private void btnEditCSS_Click(object sender, EventArgs e){
|
||||||
DialogSettingsCSS form = new DialogSettingsCSS(reinjectBrowserCSS);
|
DialogSettingsCSS form = new DialogSettingsCSS(reinjectBrowserCSS, openDevTools);
|
||||||
|
|
||||||
form.VisibleChanged += (sender2, args2) => {
|
form.VisibleChanged += (sender2, args2) => {
|
||||||
form.MoveToCenter(ParentForm);
|
form.MoveToCenter(ParentForm);
|
||||||
|
@@ -15,7 +15,7 @@ namespace TweetDuck.Core.Other.Settings{
|
|||||||
|
|
||||||
this.notification = notification;
|
this.notification = notification;
|
||||||
|
|
||||||
this.notification.Initialized += (sender, args) => {
|
this.notification.Ready += (sender, args) => {
|
||||||
this.InvokeAsyncSafe(() => {
|
this.InvokeAsyncSafe(() => {
|
||||||
this.notification.ShowExampleNotification(true);
|
this.notification.ShowExampleNotification(true);
|
||||||
this.notification.Move += notification_Move;
|
this.notification.Move += notification_Move;
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Configuration;
|
||||||
|
using Res = TweetDuck.Properties.Resources;
|
||||||
|
|
||||||
namespace TweetDuck.Core.Other{
|
namespace TweetDuck.Core.Other{
|
||||||
sealed partial class TrayIcon : Component{
|
sealed partial class TrayIcon : Component{
|
||||||
@@ -8,6 +10,8 @@ namespace TweetDuck.Core.Other{
|
|||||||
Disabled, DisplayOnly, MinimizeToTray, CloseToTray, Combined
|
Disabled, DisplayOnly, MinimizeToTray, CloseToTray, Combined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static UserConfig Config => Program.UserConfig;
|
||||||
|
|
||||||
public event EventHandler ClickRestore;
|
public event EventHandler ClickRestore;
|
||||||
public event EventHandler ClickClose;
|
public event EventHandler ClickClose;
|
||||||
|
|
||||||
@@ -17,12 +21,9 @@ namespace TweetDuck.Core.Other{
|
|||||||
}
|
}
|
||||||
|
|
||||||
set{
|
set{
|
||||||
if (value){
|
|
||||||
notifyIcon.Icon = Properties.Resources.icon_tray;
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyIcon.Visible = value;
|
notifyIcon.Visible = value;
|
||||||
hasNotifications = false;
|
hasNotifications = false;
|
||||||
|
UpdateIcon();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,9 +33,9 @@ namespace TweetDuck.Core.Other{
|
|||||||
}
|
}
|
||||||
|
|
||||||
set{
|
set{
|
||||||
if (hasNotifications != value && Visible){
|
if (hasNotifications != value){
|
||||||
notifyIcon.Icon = value ? Properties.Resources.icon_tray_new : Properties.Resources.icon_tray;
|
|
||||||
hasNotifications = value;
|
hasNotifications = value;
|
||||||
|
UpdateIcon();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,14 +54,26 @@ namespace TweetDuck.Core.Other{
|
|||||||
|
|
||||||
this.notifyIcon.ContextMenu = contextMenu;
|
this.notifyIcon.ContextMenu = contextMenu;
|
||||||
this.notifyIcon.Text = Program.BrandName;
|
this.notifyIcon.Text = Program.BrandName;
|
||||||
|
|
||||||
|
Config.MuteToggled += Config_MuteToggled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TrayIcon(IContainer container) : this(){
|
public TrayIcon(IContainer container) : this(){
|
||||||
container.Add(this);
|
container.Add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateIcon(){
|
||||||
|
if (Visible){
|
||||||
|
notifyIcon.Icon = hasNotifications ? Res.icon_tray_new : Config.MuteNotifications ? Res.icon_tray_muted : Res.icon_tray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// event handlers
|
// event handlers
|
||||||
|
|
||||||
|
private void Config_MuteToggled(object sender, EventArgs e){
|
||||||
|
UpdateIcon();
|
||||||
|
}
|
||||||
|
|
||||||
private void trayIcon_MouseClick(object sender, MouseEventArgs e){
|
private void trayIcon_MouseClick(object sender, MouseEventArgs e){
|
||||||
if (e.Button == MouseButtons.Left){
|
if (e.Button == MouseButtons.Left){
|
||||||
menuItemRestore_Click(sender, e);
|
menuItemRestore_Click(sender, e);
|
||||||
@@ -68,7 +81,7 @@ namespace TweetDuck.Core.Other{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void contextMenu_Popup(object sender, EventArgs e){
|
private void contextMenu_Popup(object sender, EventArgs e){
|
||||||
contextMenu.MenuItems[1].Checked = Program.UserConfig.MuteNotifications;
|
contextMenu.MenuItems[1].Checked = Config.MuteNotifications;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void menuItemRestore_Click(object sender, EventArgs e){
|
private void menuItemRestore_Click(object sender, EventArgs e){
|
||||||
@@ -76,8 +89,8 @@ namespace TweetDuck.Core.Other{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void menuItemMuteNotifications_Click(object sender, EventArgs e){
|
private void menuItemMuteNotifications_Click(object sender, EventArgs e){
|
||||||
Program.UserConfig.MuteNotifications = !contextMenu.MenuItems[1].Checked;
|
Config.MuteNotifications = !contextMenu.MenuItems[1].Checked;
|
||||||
Program.UserConfig.Save();
|
Config.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void menuItemClose_Click(object sender, EventArgs e){
|
private void menuItemClose_Click(object sender, EventArgs e){
|
||||||
|
@@ -4,10 +4,12 @@ using System.Text;
|
|||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
using CefSharp.WinForms;
|
using CefSharp.WinForms;
|
||||||
|
using TweetDuck.Configuration;
|
||||||
using TweetDuck.Core.Bridge;
|
using TweetDuck.Core.Bridge;
|
||||||
using TweetDuck.Core.Controls;
|
using TweetDuck.Core.Controls;
|
||||||
using TweetDuck.Core.Handling;
|
using TweetDuck.Core.Handling;
|
||||||
using TweetDuck.Core.Handling.General;
|
using TweetDuck.Core.Handling.General;
|
||||||
|
using TweetDuck.Core.Management;
|
||||||
using TweetDuck.Core.Notification;
|
using TweetDuck.Core.Notification;
|
||||||
using TweetDuck.Core.Other.Interfaces;
|
using TweetDuck.Core.Other.Interfaces;
|
||||||
using TweetDuck.Core.Utils;
|
using TweetDuck.Core.Utils;
|
||||||
@@ -39,14 +41,16 @@ namespace TweetDuck.Core{
|
|||||||
private string prevSoundNotificationPath = null;
|
private string prevSoundNotificationPath = null;
|
||||||
|
|
||||||
public TweetDeckBrowser(FormBrowser owner, TweetDeckBridge bridge){
|
public TweetDeckBrowser(FormBrowser owner, TweetDeckBridge bridge){
|
||||||
|
RequestHandlerBrowser requestHandler = new RequestHandlerBrowser();
|
||||||
|
|
||||||
this.browser = new ChromiumWebBrowser(TwitterUtils.TweetDeckURL){
|
this.browser = new ChromiumWebBrowser(TwitterUtils.TweetDeckURL){
|
||||||
DialogHandler = new FileDialogHandler(),
|
DialogHandler = new FileDialogHandler(),
|
||||||
DragHandler = new DragHandlerBrowser(),
|
DragHandler = new DragHandlerBrowser(requestHandler),
|
||||||
MenuHandler = new ContextMenuBrowser(owner),
|
MenuHandler = new ContextMenuBrowser(owner),
|
||||||
JsDialogHandler = new JavaScriptDialogHandler(),
|
JsDialogHandler = new JavaScriptDialogHandler(),
|
||||||
KeyboardHandler = new KeyboardHandlerBrowser(owner),
|
KeyboardHandler = new KeyboardHandlerBrowser(owner),
|
||||||
LifeSpanHandler = new LifeSpanHandler(),
|
LifeSpanHandler = new LifeSpanHandler(),
|
||||||
RequestHandler = new RequestHandlerBrowser()
|
RequestHandler = requestHandler
|
||||||
};
|
};
|
||||||
|
|
||||||
this.browser.LoadingStateChanged += browser_LoadingStateChanged;
|
this.browser.LoadingStateChanged += browser_LoadingStateChanged;
|
||||||
@@ -154,6 +158,10 @@ namespace TweetDuck.Core{
|
|||||||
|
|
||||||
TweetDeckBridge.ResetStaticProperties();
|
TweetDeckBridge.ResetStaticProperties();
|
||||||
|
|
||||||
|
if (Arguments.HasFlag(Arguments.ArgIgnoreGDPR)){
|
||||||
|
ScriptLoader.ExecuteScript(frame, "TD.storage.Account.prototype.requiresConsent = function(){ return false; }", "gen:gdpr");
|
||||||
|
}
|
||||||
|
|
||||||
if (Program.UserConfig.FirstRun){
|
if (Program.UserConfig.FirstRun){
|
||||||
ScriptLoader.ExecuteFile(frame, "introduction.js", browser);
|
ScriptLoader.ExecuteFile(frame, "introduction.js", browser);
|
||||||
}
|
}
|
||||||
@@ -166,7 +174,7 @@ namespace TweetDuck.Core{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!e.FailedUrl.StartsWith("http://td/", StringComparison.Ordinal)){
|
if (!e.FailedUrl.StartsWith("http://td/", StringComparison.Ordinal)){
|
||||||
string errorPage = ScriptLoader.LoadResource("pages/error.html", true);
|
string errorPage = ScriptLoader.LoadResourceSilent("pages/error.html");
|
||||||
|
|
||||||
if (errorPage != null){
|
if (errorPage != null){
|
||||||
browser.LoadHtml(errorPage.Replace("{err}", BrowserUtils.GetErrorName(e.ErrorCode)), "http://td/error");
|
browser.LoadHtml(errorPage.Replace("{err}", BrowserUtils.GetErrorName(e.ErrorCode)), "http://td/error");
|
||||||
@@ -215,7 +223,7 @@ namespace TweetDuck.Core{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void InjectBrowserCSS(){
|
public void InjectBrowserCSS(){
|
||||||
browser.ExecuteScriptAsync("TDGF_injectBrowserCSS", ScriptLoader.LoadResource("styles/browser.css", false, browser)?.TrimEnd() ?? string.Empty);
|
browser.ExecuteScriptAsync("TDGF_injectBrowserCSS", ScriptLoader.LoadResource("styles/browser.css", browser)?.TrimEnd() ?? string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReinjectCustomCSS(string css){
|
public void ReinjectCustomCSS(string css){
|
||||||
@@ -253,5 +261,9 @@ namespace TweetDuck.Core{
|
|||||||
public void ShowUpdateNotification(string versionTag, string releaseNotes){
|
public void ShowUpdateNotification(string versionTag, string releaseNotes){
|
||||||
browser.ExecuteScriptAsync("TDUF_displayNotification", versionTag, Convert.ToBase64String(Encoding.GetEncoding("iso-8859-1").GetBytes(releaseNotes)));
|
browser.ExecuteScriptAsync("TDUF_displayNotification", versionTag, Convert.ToBase64String(Encoding.GetEncoding("iso-8859-1").GetBytes(releaseNotes)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OpenDevTools(){
|
||||||
|
browser.ShowDevTools();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,8 @@ namespace TweetDuck.Core.Utils{
|
|||||||
public static string UserAgentVanilla => Program.BrandName+" "+Application.ProductVersion;
|
public static string UserAgentVanilla => Program.BrandName+" "+Application.ProductVersion;
|
||||||
public static string UserAgentChrome => "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/"+Cef.ChromiumVersion+" Safari/537.36";
|
public static string UserAgentChrome => "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/"+Cef.ChromiumVersion+" Safari/537.36";
|
||||||
|
|
||||||
|
public static readonly bool HasDevTools = File.Exists(Path.Combine(Program.ProgramPath, "devtools_resources.pak"));
|
||||||
|
|
||||||
public static void SetupCefArgs(IDictionary<string, string> args){
|
public static void SetupCefArgs(IDictionary<string, string> args){
|
||||||
if (!Program.SystemConfig.HardwareAcceleration){
|
if (!Program.SystemConfig.HardwareAcceleration){
|
||||||
args["disable-gpu"] = "1";
|
args["disable-gpu"] = "1";
|
||||||
|
@@ -71,6 +71,9 @@ namespace TweetDuck.Core.Utils{
|
|||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
private static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop);
|
private static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop);
|
||||||
|
|
||||||
|
[DllImport("dwmapi.dll")]
|
||||||
|
public static extern int DwmIsCompositionEnabled(out bool enabled);
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
[DllImport("user32.dll")]
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
public static extern bool ShowScrollBar(IntPtr hWnd, int wBar, bool bShow);
|
public static extern bool ShowScrollBar(IntPtr hWnd, int wBar, bool bShow);
|
||||||
|
@@ -19,11 +19,23 @@ namespace TweetDuck.Core.Utils{
|
|||||||
return Regex.Replace(str, @"(\p{Ll})(\P{Ll})|(\P{Ll})(\P{Ll}\p{Ll})", "$1$3_$2$4").ToUpper();
|
return Regex.Replace(str, @"(\p{Ll})(\P{Ll})|(\P{Ll})(\P{Ll}\p{Ll})", "$1$3_$2$4").ToUpper();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string ConvertRot13(string str){
|
||||||
|
return Regex.Replace(str, @"[a-zA-Z]", match => {
|
||||||
|
int code = match.Value[0];
|
||||||
|
int start = code <= 90 ? 65 : 97;
|
||||||
|
return ((char)(start+(code-start+13)%26)).ToString();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public static int CountOccurrences(string source, string substring){
|
public static int CountOccurrences(string source, string substring){
|
||||||
int count = 0, index = 0;
|
if (substring.Length == 0){
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(substring), "Searched substring must not be empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = 0, index = 0, length = substring.Length;
|
||||||
|
|
||||||
while((index = source.IndexOf(substring, index)) != -1){
|
while((index = source.IndexOf(substring, index)) != -1){
|
||||||
index += substring.Length;
|
index += length;
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -15,10 +15,12 @@ namespace TweetDuck.Core.Utils{
|
|||||||
private static readonly Lazy<Regex> RegexStripHtmlStyles = new Lazy<Regex>(() => new Regex(@"\s?(?:style|class)="".*?"""), false);
|
private static readonly Lazy<Regex> RegexStripHtmlStyles = new Lazy<Regex>(() => new Regex(@"\s?(?:style|class)="".*?"""), false);
|
||||||
private static readonly Lazy<Regex> RegexOffsetClipboardHtml = new Lazy<Regex>(() => new Regex(@"(?<=EndHTML:|EndFragment:)(\d+)"), false);
|
private static readonly Lazy<Regex> RegexOffsetClipboardHtml = new Lazy<Regex>(() => new Regex(@"(?<=EndHTML:|EndFragment:)(\d+)"), false);
|
||||||
|
|
||||||
|
private static readonly bool IsWindows8OrNewer;
|
||||||
|
private static bool HasMicrosoftBeenBroughtTo2008Yet;
|
||||||
|
|
||||||
public static int CurrentProcessID { get; }
|
public static int CurrentProcessID { get; }
|
||||||
public static bool ShouldAvoidToolWindow { get; }
|
public static bool ShouldAvoidToolWindow { get; }
|
||||||
|
public static bool IsAeroEnabled => IsWindows8OrNewer || (NativeMethods.DwmIsCompositionEnabled(out bool isCompositionEnabled) == 0 && isCompositionEnabled);
|
||||||
private static bool HasMicrosoftBeenBroughtTo2008Yet;
|
|
||||||
|
|
||||||
static WindowsUtils(){
|
static WindowsUtils(){
|
||||||
using(Process me = Process.GetCurrentProcess()){
|
using(Process me = Process.GetCurrentProcess()){
|
||||||
@@ -26,7 +28,9 @@ namespace TweetDuck.Core.Utils{
|
|||||||
}
|
}
|
||||||
|
|
||||||
Version ver = Environment.OSVersion.Version;
|
Version ver = Environment.OSVersion.Version;
|
||||||
ShouldAvoidToolWindow = ver.Major == 6 && ver.Minor == 2; // windows 8/10
|
IsWindows8OrNewer = ver.Major == 6 && ver.Minor == 2; // windows 8/10
|
||||||
|
|
||||||
|
ShouldAvoidToolWindow = IsWindows8OrNewer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void EnsureTLS12(){
|
public static void EnsureTLS12(){
|
||||||
|
@@ -16,7 +16,7 @@ namespace TweetDuck.Data{
|
|||||||
this.html = html;
|
this.html = html;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Inject(string targetHTML){
|
public string InjectInto(string targetHTML){
|
||||||
int index = targetHTML.IndexOf(search, StringComparison.Ordinal);
|
int index = targetHTML.IndexOf(search, StringComparison.Ordinal);
|
||||||
|
|
||||||
if (index == -1){
|
if (index == -1){
|
||||||
|
@@ -24,15 +24,6 @@ namespace TweetDuck.Plugins.Enums{
|
|||||||
return environment == PluginEnvironment.Browser;
|
return environment == PluginEnvironment.Browser;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetScriptIdentifier(this PluginEnvironment environment){
|
|
||||||
switch(environment){
|
|
||||||
case PluginEnvironment.None: return "root:plugins";
|
|
||||||
case PluginEnvironment.Browser: return "root:plugins.browser";
|
|
||||||
case PluginEnvironment.Notification: return "root:plugins.notification";
|
|
||||||
default: return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetPluginScriptFile(this PluginEnvironment environment){
|
public static string GetPluginScriptFile(this PluginEnvironment environment){
|
||||||
switch(environment){
|
switch(environment){
|
||||||
case PluginEnvironment.Browser: return "browser.js";
|
case PluginEnvironment.Browser: return "browser.js";
|
||||||
|
@@ -84,14 +84,20 @@ namespace TweetDuck.Plugins{
|
|||||||
|
|
||||||
try{
|
try{
|
||||||
string folderPathName = new DirectoryInfo(rootFolder).FullName;
|
string folderPathName = new DirectoryInfo(rootFolder).FullName;
|
||||||
DirectoryInfo currentInfo = new DirectoryInfo(fullPath);
|
DirectoryInfo currentInfo = new DirectoryInfo(fullPath); // initially points to the file, which is convenient for the Attributes check below
|
||||||
|
DirectoryInfo parentInfo = currentInfo.Parent;
|
||||||
|
|
||||||
while(currentInfo.Parent != null){
|
while(parentInfo != null){
|
||||||
if (currentInfo.Parent.FullName == folderPathName){
|
if (currentInfo.Exists && currentInfo.Attributes.HasFlag(FileAttributes.ReparsePoint)){
|
||||||
|
return string.Empty; // no reason why a plugin should have files/folders with symlinks, junctions, or any other crap
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentInfo.FullName == folderPathName){
|
||||||
return fullPath;
|
return fullPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentInfo = currentInfo.Parent;
|
currentInfo = parentInfo;
|
||||||
|
parentInfo = currentInfo.Parent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch{
|
catch{
|
||||||
|
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Core.Other.Interfaces;
|
using TweetDuck.Core.Other.Interfaces;
|
||||||
using TweetDuck.Data;
|
using TweetDuck.Data;
|
||||||
using TweetDuck.Plugins.Enums;
|
using TweetDuck.Plugins.Enums;
|
||||||
@@ -12,15 +13,7 @@ using TweetDuck.Resources;
|
|||||||
|
|
||||||
namespace TweetDuck.Plugins{
|
namespace TweetDuck.Plugins{
|
||||||
sealed class PluginManager{
|
sealed class PluginManager{
|
||||||
private static IReadOnlyDictionary<PluginEnvironment, string> LoadSetupScripts(){
|
private static readonly IReadOnlyDictionary<PluginEnvironment, string> PluginSetupScriptNames = PluginEnvironmentExtensions.Map(null, "plugins.browser.js", "plugins.notification.js");
|
||||||
return PluginEnvironmentExtensions.Map(
|
|
||||||
ScriptLoader.LoadResource("plugins.js"),
|
|
||||||
ScriptLoader.LoadResource("plugins.browser.js"),
|
|
||||||
ScriptLoader.LoadResource("plugins.notification.js")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly IReadOnlyDictionary<PluginEnvironment, string> PluginSetupScripts = LoadSetupScripts();
|
|
||||||
|
|
||||||
public string PathOfficialPlugins => Path.Combine(rootPath, "official");
|
public string PathOfficialPlugins => Path.Combine(rootPath, "official");
|
||||||
public string PathCustomPlugins => Path.Combine(rootPath, "user");
|
public string PathCustomPlugins => Path.Combine(rootPath, "user");
|
||||||
@@ -54,8 +47,8 @@ namespace TweetDuck.Plugins{
|
|||||||
Config.PluginChangedState += Config_PluginChangedState;
|
Config.PluginChangedState += Config_PluginChangedState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Register(ITweetDeckBrowser browser, PluginEnvironment environment, bool asMainBrowser = false){
|
public void Register(ITweetDeckBrowser browser, PluginEnvironment environment, Control sync, bool asMainBrowser = false){
|
||||||
browser.OnFrameLoaded(frame => ExecutePlugins(frame, environment));
|
browser.OnFrameLoaded(frame => ExecutePlugins(frame, environment, sync));
|
||||||
browser.RegisterBridge("$TDP", bridge);
|
browser.RegisterBridge("$TDP", bridge);
|
||||||
|
|
||||||
if (asMainBrowser){
|
if (asMainBrowser){
|
||||||
@@ -152,14 +145,11 @@ namespace TweetDuck.Plugins{
|
|||||||
Reloaded?.Invoke(this, new PluginErrorEventArgs(loadErrors));
|
Reloaded?.Invoke(this, new PluginErrorEventArgs(loadErrors));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExecutePlugins(IFrame frame, PluginEnvironment environment){
|
private void ExecutePlugins(IFrame frame, PluginEnvironment environment, Control sync){
|
||||||
if (!HasAnyPlugin(environment)){
|
if (!HasAnyPlugin(environment) || !ScriptLoader.ExecuteFile(frame, PluginSetupScriptNames[environment], sync)){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptLoader.ExecuteScript(frame, PluginSetupScripts[environment], environment.GetScriptIdentifier());
|
|
||||||
ScriptLoader.ExecuteScript(frame, PluginSetupScripts[PluginEnvironment.None], PluginEnvironment.None.GetScriptIdentifier());
|
|
||||||
|
|
||||||
bool includeDisabled = environment.IncludesDisabledPlugins();
|
bool includeDisabled = environment.IncludesDisabledPlugins();
|
||||||
|
|
||||||
if (includeDisabled){
|
if (includeDisabled){
|
||||||
|
@@ -19,7 +19,7 @@ namespace TweetDuck{
|
|||||||
public const string BrandName = "TweetDuck";
|
public const string BrandName = "TweetDuck";
|
||||||
public const string Website = "https://tweetduck.chylex.com";
|
public const string Website = "https://tweetduck.chylex.com";
|
||||||
|
|
||||||
public const string VersionTag = "1.13.6";
|
public const string VersionTag = "1.15";
|
||||||
|
|
||||||
public static readonly string ProgramPath = AppDomain.CurrentDomain.BaseDirectory;
|
public static readonly string ProgramPath = AppDomain.CurrentDomain.BaseDirectory;
|
||||||
public static readonly bool IsPortable = File.Exists(Path.Combine(ProgramPath, "makeportable"));
|
public static readonly bool IsPortable = File.Exists(Path.Combine(ProgramPath, "makeportable"));
|
||||||
@@ -157,7 +157,7 @@ namespace TweetDuck{
|
|||||||
ExitCleanup();
|
ExitCleanup();
|
||||||
|
|
||||||
// ProgramPath has a trailing backslash
|
// ProgramPath has a trailing backslash
|
||||||
string updaterArgs = "/SP- /SILENT /CLOSEAPPLICATIONS /UPDATEPATH=\""+ProgramPath+"\" /RUNARGS=\""+Arguments.GetCurrentForInstallerCmd()+"\""+(IsPortable ? " /PORTABLE=1" : "");
|
string updaterArgs = "/SP- /SILENT /FORCECLOSEAPPLICATIONS /UPDATEPATH=\""+ProgramPath+"\" /RUNARGS=\""+Arguments.GetCurrentForInstallerCmd()+"\""+(IsPortable ? " /PORTABLE=1" : "");
|
||||||
bool runElevated = !IsPortable || !WindowsUtils.CheckFolderWritePermission(ProgramPath);
|
bool runElevated = !IsPortable || !WindowsUtils.CheckFolderWritePermission(ProgramPath);
|
||||||
|
|
||||||
if (WindowsUtils.OpenAssociatedProgram(mainForm.UpdateInstallerPath, updaterArgs, runElevated)){
|
if (WindowsUtils.OpenAssociatedProgram(mainForm.UpdateInstallerPath, updaterArgs, runElevated)){
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Resources;
|
using System.Resources;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@@ -42,5 +42,6 @@ using TweetDuck;
|
|||||||
[assembly: CLSCompliant(true)]
|
[assembly: CLSCompliant(true)]
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("UnitTests")]
|
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("TweetTest.System")]
|
||||||
|
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("TweetTest.Unit")]
|
||||||
#endif
|
#endif
|
||||||
|
20
Properties/Resources.Designer.cs
generated
@@ -80,6 +80,16 @@ namespace TweetDuck.Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
||||||
|
/// </summary>
|
||||||
|
internal static System.Drawing.Icon icon_muted {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("icon_muted", resourceCulture);
|
||||||
|
return ((System.Drawing.Icon)(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -90,6 +100,16 @@ namespace TweetDuck.Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
||||||
|
/// </summary>
|
||||||
|
internal static System.Drawing.Icon icon_tray_muted {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("icon_tray_muted", resourceCulture);
|
||||||
|
return ((System.Drawing.Icon)(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -119,18 +119,24 @@
|
|||||||
</resheader>
|
</resheader>
|
||||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||||
<data name="avatar" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="avatar" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\avatar.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>..\Resources\Images\avatar.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="icon" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="icon" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\icon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\Images\icon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
|
</data>
|
||||||
|
<data name="icon_muted" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\Resources\Images\icon-muted.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="icon_tray" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="icon_tray" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\icon-tray.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\Images\icon-tray.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
|
</data>
|
||||||
|
<data name="icon_tray_muted" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\Resources\Images\icon-tray-muted.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="icon_tray_new" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="icon_tray_new" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\icon-tray-new.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\Images\icon-tray-new.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="spinner" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="spinner" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\spinner.apng;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>..\Resources\Images\spinner.apng;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
47
README.md
@@ -9,53 +9,48 @@
|
|||||||
The program was built using Visual Studio 2017. Before opening the solution, please make sure you have the following workloads and components installed (optional components that are not listed can be deselected to save space):
|
The program was built using Visual Studio 2017. Before opening the solution, please make sure you have the following workloads and components installed (optional components that are not listed can be deselected to save space):
|
||||||
* **.NET desktop development**
|
* **.NET desktop development**
|
||||||
* .NET Framework 4 – 4.6 development tools
|
* .NET Framework 4 – 4.6 development tools
|
||||||
|
* F# desktop language support
|
||||||
* **Desktop development with C++**
|
* **Desktop development with C++**
|
||||||
* VC++ 2017 v141 toolset
|
* VC++ 2017 latest v141 tools
|
||||||
|
|
||||||
After opening the solution, download the following NuGet packages by right-clicking on the solution and selecting **Restore NuGet Packages**, or manually running this command in the **Package Manager Console**:
|
After opening the solution, right-click the solution and select **Restore NuGet Packages**, or manually run this command in the **Package Manager Console**:
|
||||||
```
|
```
|
||||||
PM> Install-Package CefSharp.WinForms -Version 64.0.0-CI2508 -Source https://www.myget.org/F/cefsharp/api/v3/index.json
|
PM> Install-Package CefSharp.WinForms -Version 67.0.0-CI2662 -Source https://www.myget.org/F/cefsharp/api/v3/index.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that some pre-release builds of CefSharp are not available on NuGet. To correctly restore packages in that case, open **Package Manager Settings**, and add `https://www.myget.org/F/cefsharp/api/v3/index.json` to the list of package sources.
|
Note that some pre-release builds of CefSharp are not available on NuGet. To correctly restore packages in that case, open **Package Manager Settings**, and add `https://www.myget.org/F/cefsharp/api/v3/index.json` to the list of package sources.
|
||||||
|
|
||||||
### Debug
|
### Debug
|
||||||
|
|
||||||
It is recommended to create a separate data folder for debugging, otherwise you will not be able to run TweetDuck while debugging the solution.
|
The `Debug` configuration uses a separate data folder by default (`%LOCALAPPDATA%\TweetDuckDebug`) to avoid affecting an existing installation of TweetDuck. You can modify this by opening **TweetDuck Properties** in Visual Studio, clicking the **Debug** tab, and changing the **Command line arguments** field.
|
||||||
|
|
||||||
To do that, open **TweetDuck Properties**, click the **Debug** tab, make sure your **Configuration** is set to `Active (Debug)` (or just `Debug`), and insert this into the **Command line arguments** field:
|
While debugging, opening the main menu and clicking **Reload browser** automatically rebuilds all resources in the `Resources/Scripts` and `Resources/Plugins` folders. This allows editing HTML/CSS/JS files and applying the changes without restarting the program, but it will cause a short delay between browser reloads.
|
||||||
```
|
|
||||||
-datafolder TweetDuckDebug
|
|
||||||
```
|
|
||||||
|
|
||||||
### Build
|
### Release
|
||||||
|
|
||||||
To make a release build of TweetDuck, open **Batch Build**, tick all `Release` configurations except for the `UnitTest` project (otherwise the build will fail), and click **Rebuild**. Check the status bar to make sure it says **Rebuild All succeeded**; if not, see the [Troubleshooting](#troubleshooting) section.
|
Open **Batch Build**, tick all `Release` configurations with `x86` platform, and click **Rebuild**. Check the status bar to make sure it says **Rebuild All succeeded**; if not, see the [Troubleshooting](#troubleshooting) section.
|
||||||
|
|
||||||
After the build succeeds, the `bin/x86/Release` folder will contain files intended for distribution (no debug symbols or other unnecessary files). You may package these files yourself, or see the [Installers](#installers) section for automated installer generation.
|
After the build succeeds, the `bin/x86/Release` folder will contain files intended for distribution (no debug symbols or other unnecessary files). You may package these files yourself, or see the [Installers](#installers) section for automated installer generation.
|
||||||
|
|
||||||
If you decide to release a custom version publicly, please make it clear that it is not an official release of TweetDuck.
|
The `Release` configuration omits debug symbols and other unnecessary files. You can modify this behavior by opening `TweetDuck.csproj`, and editing the `<Target Name="AfterBuild" Condition="$(ConfigurationName) == Release">` section.
|
||||||
|
|
||||||
|
If you decide to publicly release a custom version, please make it clear that it is not an official release of TweetDuck. There are many references to the official website and this repository, especially in the update system, so search for `chylex.com` and `github.com` in all files and replace them appropriately.
|
||||||
|
|
||||||
### Troubleshooting
|
### Troubleshooting
|
||||||
|
|
||||||
There are a few quirks in the build process that may catch you off guard:
|
#### Error: The command (...) exited with code 1
|
||||||
|
- This indicates a failed post-build event, open the **Output** tab for logs
|
||||||
- **Plugin files are not updated automatically**
|
- Determine if there was an IO error from the `rmdir` commands, or whether the error was in the **PostBuild.ps1** script (`Encountered an error while running PostBuild.ps1 on line <xyz>`)
|
||||||
- Since official plugins (`Resources/Plugins`) are not included in the project, Visual Studio will not automatically detect changes in the files
|
- Some files are checked for invalid characters:
|
||||||
- To ensure plugins are updated when testing the app, click **Rebuild Solution** before clicking **Start**
|
|
||||||
- **Error: The command (...) exited with code 1**
|
|
||||||
- If the post-build event fails, open the **Output** tab and look for the cause
|
|
||||||
- Determine if there was an IO error while copying files or modifying folders, or whether the final .ps1 script failed (`Encountered an error while running PostBuild.ps1 on line xyz`)
|
|
||||||
- Some files are checked for invalid characters:
|
|
||||||
- `Resources/Plugins/emoji-keyboard/emoji-ordering.txt` line endings must be LF (line feed); any CR (carriage return) in the file will cause a failed build, and you will need to ensure correct line endings in your text editor
|
- `Resources/Plugins/emoji-keyboard/emoji-ordering.txt` line endings must be LF (line feed); any CR (carriage return) in the file will cause a failed build, and you will need to ensure correct line endings in your text editor
|
||||||
|
|
||||||
### Installers
|
### Installers
|
||||||
|
|
||||||
TweetDuck uses **Inno Setup** to automate the creation of installers. First, download and install [InnoSetup QuickStart Pack](http://www.jrsoftware.org/isdl.php) (non-unicode; editor and encryption support not required) and the [Inno Download Plugin](https://code.google.com/archive/p/inno-download-plugin).
|
TweetDuck uses **Inno Setup** for installers and updates. First, download and install [InnoSetup QuickStart Pack](http://www.jrsoftware.org/isdl.php) (non-unicode; editor and encryption support not required) and the [Inno Download Plugin](https://code.google.com/archive/p/inno-download-plugin).
|
||||||
|
|
||||||
Next, add the Inno Setup installation folder (usually `C:\Program Files (x86)\Inno Setup 5`) into your **PATH** environment variable. You may need to restart File Explorer for the change to take place.
|
Next, add the Inno Setup installation folder (usually `C:\Program Files (x86)\Inno Setup 5`) into your **PATH** environment variable. You may need to restart File Explorer for the change to take place.
|
||||||
|
|
||||||
Now you can generate installers after a build by running `bld/RUN BUILD.bat`. Note that despite the name, this will only package the files, you still need to run the [build](#build) in Visual Studio!
|
Now you can generate installers after a build by running `bld/RUN BUILD.bat`. Note that this will only package the files, you still need to run the [release build](#release) in Visual Studio!
|
||||||
|
|
||||||
After the window closes, three installers will be generated inside the `bld/Output` folder:
|
After the window closes, three installers will be generated inside the `bld/Output` folder:
|
||||||
* **TweetDuck.exe**
|
* **TweetDuck.exe**
|
||||||
@@ -67,8 +62,10 @@ After the window closes, three installers will be generated inside the `bld/Outp
|
|||||||
* This is a portable installer that does not need administrator privileges
|
* This is a portable installer that does not need administrator privileges
|
||||||
* It automatically creates a `makeportable` file in the program folder, which forces TweetDuck to run in portable mode
|
* It automatically creates a `makeportable` file in the program folder, which forces TweetDuck to run in portable mode
|
||||||
|
|
||||||
Note: There is a small chance you will see a resource error when running `RUN BUILD.bat`. If that happens, close the console window (which will terminate all Inno Setup processes and leave corrupted installer files in the output folder), and run it again.
|
#### Notes
|
||||||
|
|
||||||
### Code Notes
|
> When opening **Batch Build**, you will also see `x64` and `AnyCPU` configurations. These are visible due to what I consider a Visual Studio bug, and will not work without significant changes to the project. Manually running the `Resources/PostCefUpdate.ps1` PowerShell script modifies the downloaded CefSharp packages, and removes the invalid configurations.
|
||||||
|
|
||||||
There are many references to the official TweetDuck website and this repository in the code and installers, so if you plan to release your own version, make sure to search for `tweetduck.chylex.com` and `github.com` in the whole repository and replace them appropriately.
|
> There is a small chance running `RUN BUILD.bat` immediately shows a resource error. If that happens, close the console window (which terminates all Inno Setup processes and leaves corrupted installers in the output folder), and run it again.
|
||||||
|
|
||||||
|
> Running `RUN BUILD.bat` uses about 400 MB of RAM due to high compression. You can lower this to about 140 MB by opening `gen_full.iss` and `gen_port.iss`, and changing `LZMADictionarySize=15360` to `LZMADictionarySize=4096`.
|
||||||
|
13
Reporter.cs
@@ -47,7 +47,8 @@ namespace TweetDuck{
|
|||||||
public void HandleException(string caption, string message, bool canIgnore, Exception e){
|
public void HandleException(string caption, string message, bool canIgnore, Exception e){
|
||||||
bool loggedSuccessfully = Log(e.ToString());
|
bool loggedSuccessfully = Log(e.ToString());
|
||||||
|
|
||||||
FormMessage form = new FormMessage(caption, message+"\nError: "+e.Message, canIgnore ? MessageBoxIcon.Warning : MessageBoxIcon.Error);
|
string exceptionText = e is ExpandedLogException ? e.Message+"\n\nDetails with potentially sensitive information are in the Error Log." : e.Message;
|
||||||
|
FormMessage form = new FormMessage(caption, message+"\nError: "+exceptionText, canIgnore ? MessageBoxIcon.Warning : MessageBoxIcon.Error);
|
||||||
|
|
||||||
Button btnExit = form.AddButton(FormMessage.Exit);
|
Button btnExit = form.AddButton(FormMessage.Exit);
|
||||||
Button btnIgnore = form.AddButton(FormMessage.Ignore, DialogResult.Ignore, ControlType.Cancel);
|
Button btnIgnore = form.AddButton(FormMessage.Ignore, DialogResult.Ignore, ControlType.Cancel);
|
||||||
@@ -95,5 +96,15 @@ namespace TweetDuck{
|
|||||||
Environment.FailFast(message, new Exception(message));
|
Environment.FailFast(message, new Exception(message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed class ExpandedLogException : Exception{
|
||||||
|
private readonly string details;
|
||||||
|
|
||||||
|
public ExpandedLogException(Exception source, string details) : base(source.Message, source){
|
||||||
|
this.details = details;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => base.ToString()+"\r\n"+details;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
20
Resources/..code-workspace
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"name": "Installers",
|
||||||
|
"path": "..\\bld"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Resources",
|
||||||
|
"path": "."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"settings": {
|
||||||
|
"editor.tabSize": 2,
|
||||||
|
"javascript.validate.enable": false,
|
||||||
|
"files.autoGuessEncoding": false,
|
||||||
|
"files.insertFinalNewline": true,
|
||||||
|
"files.trimFinalNewlines": true,
|
||||||
|
"files.encoding": "utf8",
|
||||||
|
}
|
||||||
|
}
|
BIN
Resources/Design/app_logos_large.afdesign
Normal file
BIN
Resources/Design/app_logos_small.afdesign
Normal file
BIN
Resources/Design/icon_pushpin.afdesign
Normal file
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
BIN
Resources/Images/icon-muted.ico
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
Resources/Images/icon-small.ico
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
Resources/Images/icon-tray-muted.ico
Normal file
After Width: | Height: | Size: 9.4 KiB |
BIN
Resources/Images/icon-tray-new.ico
Normal file
After Width: | Height: | Size: 9.4 KiB |
BIN
Resources/Images/icon-tray.ico
Normal file
After Width: | Height: | Size: 9.4 KiB |
BIN
Resources/Images/icon.ico
Normal file
After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -2,6 +2,7 @@ enabled(){
|
|||||||
this.isDebugging = false;
|
this.isDebugging = false;
|
||||||
|
|
||||||
this.onKeyDown = (e) => {
|
this.onKeyDown = (e) => {
|
||||||
|
|
||||||
// ==========================
|
// ==========================
|
||||||
// F4 key - toggle debug mode
|
// F4 key - toggle debug mode
|
||||||
// ==========================
|
// ==========================
|
||||||
@@ -11,8 +12,6 @@ enabled(){
|
|||||||
$(".nav-user-info").first().css("background-color", this.isDebugging ? "#5A6B75" : "#292F33");
|
$(".nav-user-info").first().css("background-color", this.isDebugging ? "#5A6B75" : "#292F33");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug mode handling
|
|
||||||
|
|
||||||
else if (this.isDebugging){
|
else if (this.isDebugging){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
@@ -22,15 +21,16 @@ enabled(){
|
|||||||
// ===================================
|
// ===================================
|
||||||
|
|
||||||
if (e.keyCode === 78 || e.keyCode === 83){
|
if (e.keyCode === 78 || e.keyCode === 83){
|
||||||
var col = TD.controller.columnManager.getAllOrdered()[0];
|
let col = TD.controller.columnManager.getAllOrdered()[0];
|
||||||
|
let model = col.model;
|
||||||
|
|
||||||
var prevPopup = col.model.getHasNotification();
|
let prevPopup = model.getHasNotification();
|
||||||
var prevSound = col.model.getHasSound();
|
let prevSound = model.getHasSound();
|
||||||
|
|
||||||
col.model.setHasNotification(e.keyCode === 78);
|
model.setHasNotification(e.keyCode === 78);
|
||||||
col.model.setHasSound(e.keyCode === 83);
|
model.setHasSound(e.keyCode === 83);
|
||||||
|
|
||||||
$.publish("/notifications/new",[{
|
$.publish("/notifications/new", [{
|
||||||
column: col,
|
column: col,
|
||||||
items: [
|
items: [
|
||||||
col.updateArray[Math.floor(Math.random()*col.updateArray.length)]
|
col.updateArray[Math.floor(Math.random()*col.updateArray.length)]
|
||||||
@@ -38,8 +38,8 @@ enabled(){
|
|||||||
}]);
|
}]);
|
||||||
|
|
||||||
setTimeout(function(){
|
setTimeout(function(){
|
||||||
col.model.setHasNotification(prevPopup);
|
model.setHasNotification(prevPopup);
|
||||||
col.model.setHasSound(prevSound);
|
model.setHasSound(prevSound);
|
||||||
}, 1);
|
}, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,33 +1,22 @@
|
|||||||
constructor(){
|
|
||||||
super({
|
|
||||||
requiresPageReload: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
enabled(){
|
enabled(){
|
||||||
// prepare variables and functions
|
const clearColumn = (columnName) => {
|
||||||
var clearColumn = (columnName) => {
|
|
||||||
TD.controller.columnManager.get(columnName).clear();
|
TD.controller.columnManager.get(columnName).clear();
|
||||||
TD.controller.stats.columnActionClick("clear");
|
TD.controller.stats.columnActionClick("clear");
|
||||||
};
|
};
|
||||||
|
|
||||||
var resetColumn = (columnName) => {
|
const resetColumn = (columnName) => {
|
||||||
let col = TD.controller.columnManager.get(columnName);
|
let col = TD.controller.columnManager.get(columnName);
|
||||||
col.model.setClearedTimestamp(0);
|
col.model.setClearedTimestamp(0);
|
||||||
col.reloadTweets();
|
col.reloadTweets();
|
||||||
};
|
};
|
||||||
|
|
||||||
var forEachColumn = (func) => {
|
const forEachColumn = (func) => {
|
||||||
Object.keys(TD.controller.columnManager.getAll()).forEach(func);
|
Object.keys(TD.controller.columnManager.getAll()).forEach(func);
|
||||||
};
|
};
|
||||||
|
|
||||||
var replaceMustache = (key, search, replace) => {
|
let wasShiftPressed = false;
|
||||||
TD.mustaches[key] = TD.mustaches[key].replace(search, replace);
|
|
||||||
};
|
|
||||||
|
|
||||||
var wasShiftPressed = false;
|
const updateShiftState = (pressed) => {
|
||||||
|
|
||||||
var updateShiftState = (pressed) => {
|
|
||||||
if (pressed != wasShiftPressed){
|
if (pressed != wasShiftPressed){
|
||||||
wasShiftPressed = pressed;
|
wasShiftPressed = pressed;
|
||||||
|
|
||||||
@@ -42,10 +31,17 @@ enabled(){
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// prepare event handlers
|
// event handlers
|
||||||
this.eventClickSingle = function(e){
|
|
||||||
var name = $(this).closest(".js-column").attr("data-column");
|
this.eventClickOneCapture = function(e){
|
||||||
|
if (e.target.getAttribute("data-action") === "td-clearcolumns-dosingle"){
|
||||||
|
let name = $(e.target).closest(".js-column").attr("data-column");
|
||||||
e.shiftKey ? resetColumn(name) : clearColumn(name);
|
e.shiftKey ? resetColumn(name) : clearColumn(name);
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.eventClickAll = function(e){
|
this.eventClickAll = function(e){
|
||||||
@@ -62,10 +58,10 @@ enabled(){
|
|||||||
forEachColumn(e.shiftKey ? resetColumn : clearColumn);
|
forEachColumn(e.shiftKey ? resetColumn : clearColumn);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
var focusedColumn = $(".js-column.is-focused");
|
let focusedColumn = $(".js-column.is-focused");
|
||||||
|
|
||||||
if (focusedColumn.length){
|
if (focusedColumn.length){
|
||||||
var name = focusedColumn.attr("data-column");
|
let name = focusedColumn.attr("data-column");
|
||||||
e.shiftKey ? resetColumn(name) : clearColumn(name);
|
e.shiftKey ? resetColumn(name) : clearColumn(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,63 +74,86 @@ enabled(){
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// setup clear all button
|
this.eventKeyboardShortcuts = function(e){
|
||||||
|
$(".keyboard-shortcut-list").first().append(`
|
||||||
|
<dd class="keyboard-shortcut-definition" style="white-space:nowrap">
|
||||||
|
<span class="text-like-keyboard-key">1</span> … <span class="text-like-keyboard-key">9</span> + <span class="text-like-keyboard-key">Del</span> Clear column 1-9
|
||||||
|
</dd>
|
||||||
|
<dd class="keyboard-shortcut-definition">
|
||||||
|
<span class="text-like-keyboard-key">Alt</span> + <span class="text-like-keyboard-key">Del</span> Clear all columns
|
||||||
|
</dd>`);
|
||||||
|
};
|
||||||
|
|
||||||
|
// update UI
|
||||||
|
|
||||||
this.btnClearAllHTML = `
|
this.btnClearAllHTML = `
|
||||||
<a class="clear-columns-btn-all-parent js-header-action link-clean cf app-nav-link padding-h--10" data-title="Clear columns (hold Shift to restore)" data-action="td-clearcolumns-doall">
|
<a class="clear-columns-btn-all-parent js-header-action link-clean cf app-nav-link padding-h--10" data-title="Clear columns (hold Shift to restore)" data-action="td-clearcolumns-doall">
|
||||||
<div class="obj-left margin-l--2"><i class="icon icon-medium icon-clear-timeline"></i></div>
|
<div class="obj-left margin-l--2"><i class="icon icon-medium icon-clear-timeline"></i></div>
|
||||||
<div class="clear-columns-btn-all nbfc padding-ts hide-condensed txt-size--16 app-nav-link-text">Clear columns</div>
|
<div class="clear-columns-btn-all nbfc padding-ts hide-condensed txt-size--16 app-nav-link-text">Clear columns</div>
|
||||||
</a>`;
|
</a>`;
|
||||||
|
|
||||||
// add column buttons and keyboard shortcut info to UI
|
this.btnClearOneHTML = `
|
||||||
replaceMustache("column/column_header.mustache", "</header>", `
|
<a class="js-action-header-button column-header-link" href="#" data-action="td-clearcolumns-dosingle">
|
||||||
{{^isTemporary}}
|
<i class="icon icon-clear-timeline js-show-tip" data-placement="bottom" data-original-title="Clear column (hold Shift to restore)" data-action="td-clearcolumns-dosingle"></i>
|
||||||
<a class="column-header-link td-clear-column-shortcut" href="#" data-action="td-clearcolumns-dosingle" style="right:34px">
|
</a>`;
|
||||||
<i class="icon icon-clear-timeline js-show-tip" data-placement="bottom" data-original-title="Clear column (hold Shift to restore)"></i>
|
|
||||||
</a>
|
|
||||||
{{/isTemporary}}
|
|
||||||
</header>`);
|
|
||||||
|
|
||||||
replaceMustache("keyboard_shortcut_list.mustache", "</dl> <dl", `
|
this.prevNavMenuMustache = TD.mustaches["menus/column_nav_menu.mustache"];
|
||||||
<dd class="keyboard-shortcut-definition" style="white-space:nowrap">
|
window.TDPF_injectMustache("menus/column_nav_menu.mustache", "replace", "{{_i}}Add column{{/i}}</div> </a> </div>", `{{_i}}Add column{{/i}}</div></a>${this.btnClearAllHTML}</div>`);
|
||||||
<span class="text-like-keyboard-key">1</span> … <span class="text-like-keyboard-key">9</span> + <span class="text-like-keyboard-key">Del</span> Clear column 1-9
|
|
||||||
</dd><dd class="keyboard-shortcut-definition">
|
|
||||||
<span class="text-like-keyboard-key">Alt</span> + <span class="text-like-keyboard-key">Del</span> Clear all columns
|
|
||||||
</dd></dl><dl`);
|
|
||||||
|
|
||||||
replaceMustache("menus/column_nav_menu.mustache", "{{_i}}Add column{{/i}}</div> </a> </div>", `{{_i}}Add column{{/i}}</div></a>${this.btnClearAllHTML}</div>`)
|
this.prevColumnHeaderMustache = TD.mustaches["column/column_header.mustache"];
|
||||||
|
window.TDPF_injectMustache("column/column_header.mustache", "prepend", "<a data-testid=\"optionsToggle\"", this.btnClearOneHTML);
|
||||||
|
|
||||||
// load custom style
|
if (TD.ready){
|
||||||
var css = window.TDPF_createCustomStyle(this);
|
$(".js-header-add-column").after(this.btnClearAllHTML);
|
||||||
css.insert(".js-app-add-column.is-hidden + .clear-columns-btn-all-parent { display: none; }");
|
$("a[data-testid='optionsToggle']", ".js-column-header").before(this.btnClearOneHTML);
|
||||||
css.insert(".column-navigator-overflow .clear-columns-btn-all-parent { display: none !important; }");
|
}
|
||||||
css.insert(".column-navigator-overflow { bottom: 224px !important; }");
|
|
||||||
css.insert(".column-title { margin-right: 60px !important; }");
|
// styles
|
||||||
css.insert(".mark-all-read-link { right: 59px !important; }");
|
|
||||||
css.insert(".open-compose-dm-link { right: 90px !important; }");
|
this.css = window.TDPF_createCustomStyle(this);
|
||||||
css.insert("button[data-action='clear'].btn-options-tray { display: none !important; }");
|
this.css.insert(".js-app-add-column.is-hidden + .clear-columns-btn-all-parent { display: none; }");
|
||||||
css.insert("[data-td-icon='icon-message'] .column-title { margin-right: 115px !important; }");
|
this.css.insert(".column-header-links { min-width: 51px !important; }");
|
||||||
css.insert("[data-td-icon='icon-schedule'] .td-clear-column-shortcut { display: none; }");
|
this.css.insert("[data-td-icon='icon-message'] .column-header-links { min-width: 110px !important; }");
|
||||||
css.insert("[data-td-icon='icon-custom-timeline'] .td-clear-column-shortcut { display: none; }");
|
this.css.insert(".column-navigator-overflow .clear-columns-btn-all-parent { display: none !important; }");
|
||||||
|
this.css.insert(".column-navigator-overflow { bottom: 224px !important; }");
|
||||||
|
this.css.insert("[data-action='td-clearcolumns-dosingle'] { padding: 3px 0 !important; }");
|
||||||
|
this.css.insert("[data-action='clear'].btn-options-tray { display: none !important; }");
|
||||||
|
this.css.insert("[data-td-icon='icon-schedule'] .td-clear-column-shortcut { display: none; }");
|
||||||
|
this.css.insert("[data-td-icon='icon-custom-timeline'] .td-clear-column-shortcut { display: none; }");
|
||||||
}
|
}
|
||||||
|
|
||||||
ready(){
|
ready(){
|
||||||
// setup events
|
document.addEventListener("click", this.eventClickOneCapture, true);
|
||||||
$(document).on("click", "[data-action='td-clearcolumns-dosingle']", this.eventClickSingle);
|
|
||||||
$(document).on("click", "[data-action='td-clearcolumns-doall']", this.eventClickAll);
|
$(document).on("click", "[data-action='td-clearcolumns-doall']", this.eventClickAll);
|
||||||
$(document).on("keydown", this.eventKeyDown);
|
$(document).on("keydown", this.eventKeyDown);
|
||||||
$(document).on("keyup", this.eventKeyUp);
|
$(document).on("keyup", this.eventKeyUp);
|
||||||
|
$(document).on("uiShowKeyboardShortcutList", this.eventKeyboardShortcuts);
|
||||||
|
|
||||||
// setup clear all button for nav overflow
|
|
||||||
$(".js-app-add-column").first().after(this.btnClearAllHTML);
|
$(".js-app-add-column").first().after(this.btnClearAllHTML);
|
||||||
|
|
||||||
// setup tooltip handling
|
// fix tooltip
|
||||||
var tooltipEvents = $._data($(".js-header-action")[0]).events;
|
|
||||||
|
let tooltipEvents = $._data($(".js-header-action")[0], "events");
|
||||||
|
|
||||||
if (tooltipEvents.mouseover && tooltipEvents.mouseover.length && tooltipEvents.mouseout && tooltipEvents.mouseout.length){
|
if (tooltipEvents.mouseover && tooltipEvents.mouseover.length && tooltipEvents.mouseout && tooltipEvents.mouseout.length){
|
||||||
$(".clear-columns-btn-all-parent").on("mouseover", tooltipEvents.mouseover[0].handler).on("mouseout", tooltipEvents.mouseout[0].handler);
|
$(".clear-columns-btn-all-parent").on({
|
||||||
|
mouseover: tooltipEvents.mouseover[0].handler,
|
||||||
|
mouseout: tooltipEvents.mouseout[0].handler
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
disabled(){
|
disabled(){
|
||||||
// not needed, plugin reloads the page when enabled or disabled
|
this.css.remove();
|
||||||
|
|
||||||
|
document.removeEventListener("click", this.eventClickOneCapture);
|
||||||
|
$(document).off("click", "[data-action='td-clearcolumns-doall']", this.eventClickAll);
|
||||||
|
$(document).off("keydown", this.eventKeyDown);
|
||||||
|
$(document).off("keyup", this.eventKeyUp);
|
||||||
|
$(document).off("uiShowKeyboardShortcutList", this.eventKeyboardShortcuts);
|
||||||
|
|
||||||
|
TD.mustaches["menus/column_nav_menu.mustache"] = this.prevNavMenuMustache;
|
||||||
|
TD.mustaches["column/column_header.mustache"] = this.prevColumnHeaderMustache;
|
||||||
|
|
||||||
|
$("[data-action^='td-clearcolumns-']").remove();
|
||||||
}
|
}
|
||||||
|
@@ -21,7 +21,7 @@ enabled(){
|
|||||||
avatarRadius: 2
|
avatarRadius: 2
|
||||||
};
|
};
|
||||||
|
|
||||||
var prepareDefaultConfig = () => {
|
const prepareDefaultConfig = () => {
|
||||||
this.defaultConfig._theme = TD.settings.getTheme();
|
this.defaultConfig._theme = TD.settings.getTheme();
|
||||||
|
|
||||||
switch(TD.settings.getColumnWidth()){
|
switch(TD.settings.getColumnWidth()){
|
||||||
@@ -39,7 +39,7 @@ enabled(){
|
|||||||
|
|
||||||
this.firstTimeLoad = null;
|
this.firstTimeLoad = null;
|
||||||
|
|
||||||
var me = this;
|
const me = this;
|
||||||
|
|
||||||
// modal dialog loading
|
// modal dialog loading
|
||||||
$TDP.readFileRoot(this.$token, "modal.html").then(contents => {
|
$TDP.readFileRoot(this.$token, "modal.html").then(contents => {
|
||||||
@@ -72,7 +72,7 @@ enabled(){
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var loadConfigObject = obj => {
|
const loadConfigObject = obj => {
|
||||||
this.tmpConfig = obj || {};
|
this.tmpConfig = obj || {};
|
||||||
this.firstTimeLoad = obj === null;
|
this.firstTimeLoad = obj === null;
|
||||||
|
|
||||||
@@ -139,7 +139,7 @@ enabled(){
|
|||||||
};
|
};
|
||||||
|
|
||||||
// modal dialog setup
|
// modal dialog setup
|
||||||
var updateKey = function(key, value){
|
const updateKey = function(key, value){
|
||||||
me.config[key] = value;
|
me.config[key] = value;
|
||||||
|
|
||||||
setTimeout(function(){
|
setTimeout(function(){
|
||||||
@@ -396,8 +396,10 @@ enabled(){
|
|||||||
switch(currentTheme){
|
switch(currentTheme){
|
||||||
case "black":
|
case "black":
|
||||||
this.css.insert(".app-content, .app-columns-container { background-color: #444448 !important }");
|
this.css.insert(".app-content, .app-columns-container { background-color: #444448 !important }");
|
||||||
|
this.css.insert(".column-header-temp { background-color: transparent !important }");
|
||||||
this.css.insert(".column-drag-handle { opacity: 0.5 !important }");
|
this.css.insert(".column-drag-handle { opacity: 0.5 !important }");
|
||||||
this.css.insert(".column-drag-handle:hover { opacity: 1 !important }");
|
this.css.insert(".column-drag-handle:hover { opacity: 1 !important }");
|
||||||
|
this.css.insert(".column-message.is-actionable span:hover > .icon-small-valigned { filter: saturate(20) }");
|
||||||
this.css.insert(".scroll-styled-v:not(.scroll-alt)::-webkit-scrollbar-thumb:not(:hover), .scroll-styled-h:not(.scroll-alt)::-webkit-scrollbar-thumb:not(:hover) { background-color: #666 !important }");
|
this.css.insert(".scroll-styled-v:not(.scroll-alt)::-webkit-scrollbar-thumb:not(:hover), .scroll-styled-h:not(.scroll-alt)::-webkit-scrollbar-thumb:not(:hover) { background-color: #666 !important }");
|
||||||
notificationScrollbarColor = "666";
|
notificationScrollbarColor = "666";
|
||||||
break;
|
break;
|
||||||
@@ -539,8 +541,8 @@ ${iconData.map(entry => `#tduck .icon-${entry[0]}:before{content:\"\\f0${entry[1
|
|||||||
#tduck .js-docked-compose .js-drawer-close { margin: 20px 0 0 !important }
|
#tduck .js-docked-compose .js-drawer-close { margin: 20px 0 0 !important }
|
||||||
#tduck .search-input-control .icon { font-size: 20px !important; top: -4px !important }
|
#tduck .search-input-control .icon { font-size: 20px !important; top: -4px !important }
|
||||||
|
|
||||||
.column-header .column-type-icon { bottom: 26px !important }
|
.js-column-header .column-type-icon { margin-top: -1px !important }
|
||||||
.is-options-open .column-type-icon { bottom: 25px !important }
|
.inline-reply .pull-left .Button--link { margin-top: 3px !important }
|
||||||
|
|
||||||
.tweet-action-item .icon-favorite-toggle { font-size: 16px !important; }
|
.tweet-action-item .icon-favorite-toggle { font-size: 16px !important; }
|
||||||
.tweet-action-item .heartsprite { top: -260% !important; left: -260% !important; transform: scale(0.4, 0.39) translateY(0.5px) !important; }
|
.tweet-action-item .heartsprite { top: -260% !important; left: -260% !important; transform: scale(0.4, 0.39) translateY(0.5px) !important; }
|
||||||
@@ -561,7 +563,7 @@ ${iconData.map(entry => `#tduck .icon-${entry[0]}:before{content:\"\\f0${entry[1
|
|||||||
if (this.config.columnWidth[0] === '/'){
|
if (this.config.columnWidth[0] === '/'){
|
||||||
let cols = this.config.columnWidth.slice(1);
|
let cols = this.config.columnWidth.slice(1);
|
||||||
|
|
||||||
this.css.insert(".column { width: calc((100vw - 205px) / "+cols+" - 6px) !important }");
|
this.css.insert(".column { width: calc((100vw - 205px) / "+cols+" - 6px) !important; min-width: 160px }");
|
||||||
this.css.insert(".is-condensed .column { width: calc((100vw - 55px) / "+cols+" - 6px) !important }");
|
this.css.insert(".is-condensed .column { width: calc((100vw - 55px) / "+cols+" - 6px) !important }");
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
@@ -641,7 +643,7 @@ ready(){
|
|||||||
$(".js-app").append('<div id="td-design-plugin-modal" class="js-modal settings-modal ovl scroll-v scroll-styled-v"></div>');
|
$(".js-app").append('<div id="td-design-plugin-modal" class="js-modal settings-modal ovl scroll-v scroll-styled-v"></div>');
|
||||||
|
|
||||||
// global settings override
|
// global settings override
|
||||||
var me = this;
|
const me = this;
|
||||||
|
|
||||||
this.prevFuncSettingsGetInfo = TD.components.GlobalSettings.prototype.getInfo;
|
this.prevFuncSettingsGetInfo = TD.components.GlobalSettings.prototype.getInfo;
|
||||||
this.prevFuncSettingsSwitchTab = TD.components.GlobalSettings.prototype.switchTab;
|
this.prevFuncSettingsSwitchTab = TD.components.GlobalSettings.prototype.switchTab;
|
||||||
|
@@ -44,6 +44,8 @@
|
|||||||
</optgroup>
|
</optgroup>
|
||||||
<option disabled></option>
|
<option disabled></option>
|
||||||
<optgroup label="Dynamic width">
|
<optgroup label="Dynamic width">
|
||||||
|
<option value="/1">1 column on screen</option>
|
||||||
|
<option value="/2">2 columns on screen</option>
|
||||||
<option value="/3">3 columns on screen</option>
|
<option value="/3">3 columns on screen</option>
|
||||||
<option value="/4">4 columns on screen</option>
|
<option value="/4">4 columns on screen</option>
|
||||||
<option value="/5">5 columns on screen</option>
|
<option value="/5">5 columns on screen</option>
|
||||||
@@ -151,8 +153,7 @@
|
|||||||
<!-- END -->
|
<!-- END -->
|
||||||
</div>
|
</div>
|
||||||
<footer class="padding-vxl txt-center">
|
<footer class="padding-vxl txt-center">
|
||||||
<button class="js-dismiss btn btn-positive pull-right">
|
<button class="js-dismiss Button--primary pull-right">
|
||||||
<i class="icon icon-check icon-small padding-rs"></i>
|
|
||||||
<span class="label">Done</span>
|
<span class="label">Done</span>
|
||||||
</button>
|
</button>
|
||||||
</footer>
|
</footer>
|
||||||
|
@@ -13,7 +13,6 @@ html.dark .color-twitter-blue{color:#1DA1F2}
|
|||||||
html.dark .color-twitter-red{color:#E0245E}
|
html.dark .color-twitter-red{color:#E0245E}
|
||||||
html.dark .color-twitter-deep-red{color:#A01744}
|
html.dark .color-twitter-deep-red{color:#A01744}
|
||||||
html.dark .color-twitter-green{color:#17BF63}
|
html.dark .color-twitter-green{color:#17BF63}
|
||||||
html.dark .color-twitter-deep-green{color:#008951}
|
|
||||||
html.dark .color-twitter-deep-black{color:#14171A}
|
html.dark .color-twitter-deep-black{color:#14171A}
|
||||||
html.dark .color-twitter-dark-black{color:#292F33}
|
html.dark .color-twitter-dark-black{color:#292F33}
|
||||||
html.dark .color-twitter-dark-gray{color:#8899A6}
|
html.dark .color-twitter-dark-gray{color:#8899A6}
|
||||||
@@ -22,7 +21,6 @@ html.dark .color-twitter-yellow{color:#FFAD1F}
|
|||||||
html.dark .bg-color-twitter-white{background-color:#fff}
|
html.dark .bg-color-twitter-white{background-color:#fff}
|
||||||
html.dark .bg-color-twitter-blue{background-color:#1DA1F2}
|
html.dark .bg-color-twitter-blue{background-color:#1DA1F2}
|
||||||
html.dark .bg-color-twitter-medium-blue{background-color:#1DA1F2}
|
html.dark .bg-color-twitter-medium-blue{background-color:#1DA1F2}
|
||||||
html.dark .bg-color-twitter-faded-yellow{background-color:#FFE8B6}
|
|
||||||
html.dark .bg-color-twitter-deep-black{background-color:#292F33}
|
html.dark .bg-color-twitter-deep-black{background-color:#292F33}
|
||||||
html.dark .bg-color-twitter-lightest-gray{background-color:#F5F8FA}
|
html.dark .bg-color-twitter-lightest-gray{background-color:#F5F8FA}
|
||||||
html.dark .link-hover-override:hover .link-hover-target{color:#8bd}
|
html.dark .link-hover-override:hover .link-hover-target{color:#8bd}
|
||||||
@@ -113,9 +111,6 @@ html.dark .btn-on-blue[disabled],html.dark .btn-on-blue[disabled]:hover,html.dar
|
|||||||
html.dark .btn-options-tray{color:#e1e8ed}
|
html.dark .btn-options-tray{color:#e1e8ed}
|
||||||
html.dark .btn-options-tray:hover,html.dark .btn-options-tray:focus{color:#8bd}
|
html.dark .btn-options-tray:hover,html.dark .btn-options-tray:focus{color:#8bd}
|
||||||
html.dark .btn-options-tray[disabled],html.dark .btn-options-tray[disabled]:hover,html.dark .btn-options-tray[disabled]:active,html.dark .btn-options-tray.is-disabled,html.dark .btn-options-tray.is-disabled:hover,html.dark .btn-options-tray.is-disabled:focus,html.dark .btn-options-tray.is-disabled:active{color:#8bd}
|
html.dark .btn-options-tray[disabled],html.dark .btn-options-tray[disabled]:hover,html.dark .btn-options-tray[disabled]:active,html.dark .btn-options-tray.is-disabled,html.dark .btn-options-tray.is-disabled:hover,html.dark .btn-options-tray.is-disabled:focus,html.dark .btn-options-tray.is-disabled:active{color:#8bd}
|
||||||
html.dark .btn-bg-positive{background-color:rgba(102,117,127,0.5)}
|
|
||||||
html.dark .btn-bg-positive:hover,html.dark .btn-bg-positive:focus{background-color:rgba(102,117,127,0.5)}
|
|
||||||
html.dark .btn-bg-positive[disabled],html.dark .btn-bg-positive[disabled]:hover,html.dark .btn-bg-positive[disabled]:active,html.dark .btn-bg-positive.is-disabled,html.dark .btn-bg-positive.is-disabled:hover,html.dark .btn-bg-positive.is-disabled:focus,html.dark .btn-bg-positive.is-disabled:active{background-color:rgba(102,117,127,0.5)}
|
|
||||||
html.dark .follow-btn .icon,html.dark .follow-btn .Icon{color:#1DA1F2}
|
html.dark .follow-btn .icon,html.dark .follow-btn .Icon{color:#1DA1F2}
|
||||||
html.dark .account-profile-header{background-color:#1DA1F2}
|
html.dark .account-profile-header{background-color:#1DA1F2}
|
||||||
html.dark .account-settings-bt{border-top:1px solid #e1e8ed}
|
html.dark .account-settings-bt{border-top:1px solid #e1e8ed}
|
||||||
@@ -190,8 +185,6 @@ html.dark .is-touch-search .list-item:hover,html.dark .is-touch-search .list-ite
|
|||||||
html.dark .is-touch-search .list-item:hover .list-icon,html.dark .is-touch-search .list-item:active .list-icon,html.dark .is-touch-search .list-item.is-selected .list-icon{color:#fff}
|
html.dark .is-touch-search .list-item:hover .list-icon,html.dark .is-touch-search .list-item:active .list-icon,html.dark .is-touch-search .list-item.is-selected .list-icon{color:#fff}
|
||||||
html.dark .avatar-border--2{border:2px solid #fff;background-color:#fff}
|
html.dark .avatar-border--2{border:2px solid #fff;background-color:#fff}
|
||||||
html.dark .account-link{color:#e1e8ed}
|
html.dark .account-link{color:#e1e8ed}
|
||||||
.on-blue html.dark .account-link{color:#fff}
|
|
||||||
.compose .quoted-tweet html.dark .account-link{color:#66757f}
|
|
||||||
html.dark .media-badge{border:1px solid #292F33;color:#999}
|
html.dark .media-badge{border:1px solid #292F33;color:#999}
|
||||||
html.dark .media-badge:hover{background-color:#14171A}
|
html.dark .media-badge:hover{background-color:#14171A}
|
||||||
html.dark .media-size-large-height::after,html.dark .media-item.media-size-large::after{background-image:linear-gradient(rgba(17,17,17,0.25),rgba(17,17,17,0))}
|
html.dark .media-size-large-height::after,html.dark .media-item.media-size-large::after{background-image:linear-gradient(rgba(17,17,17,0.25),rgba(17,17,17,0))}
|
||||||
@@ -219,7 +212,7 @@ html.dark .is-minimalist .tweet-img{background:#292F33}
|
|||||||
html.dark .is-selected-tweet{background:#292F33}
|
html.dark .is-selected-tweet{background:#292F33}
|
||||||
html.dark .in-tweet-divider:before{background:#292F33}
|
html.dark .in-tweet-divider:before{background:#292F33}
|
||||||
html.dark .tweet-translation-original-text{color:#8899a6}
|
html.dark .tweet-translation-original-text{color:#8899a6}
|
||||||
html.dark .quoted-tweet{border:1px solid #E1E8ED;color:#66757f;border-color:#292F33;color:#999}
|
html.dark .quoted-tweet{border-color:#292F33;color:#999}
|
||||||
html.dark .scheduled-tweet{border:1px solid #292F33;color:#8899A6}
|
html.dark .scheduled-tweet{border:1px solid #292F33;color:#8899A6}
|
||||||
html.dark .stream-item .icon-edit,html.dark .stream-item .icon-trash{color:#657786}
|
html.dark .stream-item .icon-edit,html.dark .stream-item .icon-trash{color:#657786}
|
||||||
html.dark .stream-item .icon-edit:hover,html.dark .stream-item .icon-trash:hover{color:#8899A6}
|
html.dark .stream-item .icon-edit:hover,html.dark .stream-item .icon-trash:hover{color:#8899A6}
|
||||||
@@ -435,7 +428,7 @@ html.dark .list-account .username{color:#8899a6}
|
|||||||
html.dark .list-listmember .username{color:#8899a6}
|
html.dark .list-listmember .username{color:#8899a6}
|
||||||
html.dark .list-listmember .bio{color:#657786}
|
html.dark .list-listmember .bio{color:#657786}
|
||||||
html.dark .divider-bar{background-color:#ddd}
|
html.dark .divider-bar{background-color:#ddd}
|
||||||
html.dark select{background-image:url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='18' height='8' viewBox='0 0 18 8'><path fill='#aaa' d='M9.82875,0.840168025 C9.59875,0.608328018 9.22625,0.608328018 8.99625,0.840168025 L5.00125,4.86964815 L1.00375,0.840168025 C0.77375,0.608328018 0.40125,0.608328018 0.17125,0.840168025 C-0.05875,1.07200803 -0.05625,1.44748804 0.17125,1.67932805 L4.58375,6.12712819 C4.69875,6.24304819 4.84875,6.30100819 5.00125,6.30100819 C5.15125,6.30100819 5.30125,6.24304819 5.41625,6.12712819 L9.82875,1.67932805 C10.05875,1.44748804 10.05875,1.07200803 9.82875,0.840168025'></path></svg>");background-color:#fff}
|
html.dark select{background-color:#fff}
|
||||||
html.dark input,html.dark textarea,html.dark select{color:#111;border:1px solid #e1e8ed}
|
html.dark input,html.dark textarea,html.dark select{color:#111;border:1px solid #e1e8ed}
|
||||||
html.dark input:disabled{background-color:#eaeaea;border-color:#e1e8ed}
|
html.dark input:disabled{background-color:#eaeaea;border-color:#e1e8ed}
|
||||||
html.dark select:disabled{background-color:#f5f8fa}
|
html.dark select:disabled{background-color:#f5f8fa}
|
||||||
@@ -613,46 +606,45 @@ html.dark .Dropdown-divider{background-color:#ccd6dd}
|
|||||||
html.dark .Dropdown-menuItem .Dropdown-menuItemContent,html.dark .Dropdown-menuGroupLabel{color:#14171a}
|
html.dark .Dropdown-menuItem .Dropdown-menuItemContent,html.dark .Dropdown-menuGroupLabel{color:#14171a}
|
||||||
html.dark .Dropdown-menuItem .Dropdown-menuItemContent .Icon--check{color:#1da1f2}
|
html.dark .Dropdown-menuItem .Dropdown-menuItemContent .Icon--check{color:#1da1f2}
|
||||||
html.dark .Dropdown-menuItem.is-focus{background-color:#1da1f2}
|
html.dark .Dropdown-menuItem.is-focus{background-color:#1da1f2}
|
||||||
html.dark .Dropdown-menuItem.is-focus .User .Icon--verified::before{color:#1da1f2}
|
|
||||||
html.dark .Dropdown-menuGroupLabel{color:#657786}
|
html.dark .Dropdown-menuGroupLabel{color:#657786}
|
||||||
html.dark .ButtonGroup>.Button.is-selected,html.dark .ButtonGroup>.Button.is-selected:visited{background-color:#1da1f2;border:1px solid #1da1f2}
|
html.dark .ButtonGroup>.Button.is-selected,html.dark .ButtonGroup>.Button.is-selected:visited{background-color:#1da1f2;border:1px solid #1da1f2}
|
||||||
html.dark .ButtonGroup>.Button.is-selected:focus,html.dark .ButtonGroup>.Button.is-selected.is-focus{box-shadow:0 0 0 2px white,0 0 0 4px #71c9f8;background:#1da1f2;border-color:#1da1f2}
|
html.dark .ButtonGroup>.Button.is-selected:focus,html.dark .ButtonGroup>.Button.is-selected.is-focus{box-shadow:0 0 0 2px #fff,0 0 0 4px #71c9f8;background:#1da1f2;border-color:#1da1f2}
|
||||||
html.dark .ButtonGroup>.Button.is-selected:hover,html.dark .ButtonGroup>.Button.is-selected.is-hover{background-color:#1da1f2;border-color:#1da1f2}
|
html.dark .ButtonGroup>.Button.is-selected:hover,html.dark .ButtonGroup>.Button.is-selected.is-hover{background-color:#1da1f2;border-color:#1da1f2}
|
||||||
html.dark .ButtonGroup>.Button.is-selected:active,html.dark .ButtonGroup>.Button.is-selected.is-active{box-shadow:0 0 0 2px white,0 0 0 4px #1da1f2;background-color:#1da1f2;border-color:#1da1f2}
|
html.dark .ButtonGroup>.Button.is-selected:active,html.dark .ButtonGroup>.Button.is-selected.is-active{box-shadow:0 0 0 2px #fff,0 0 0 4px #1da1f2;background-color:#1da1f2;border-color:#1da1f2}
|
||||||
html.dark .ButtonGroup>.Button.is-selected[disabled],html.dark .ButtonGroup>.Button.is-selected.is-disabled,html.dark fieldset[disabled] .ButtonGroup>.Button.is-selected{background-color:#1da1f2;border-color:#1da1f2}
|
html.dark .ButtonGroup>.Button.is-selected[disabled],html.dark .ButtonGroup>.Button.is-selected.is-disabled,html.dark fieldset[disabled] .ButtonGroup>.Button.is-selected{background-color:#1da1f2;border-color:#1da1f2}
|
||||||
html.dark .ButtonGroup--tertiary>.Button.is-selected,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected,html.dark .ButtonGroup--tertiary>.Button.is-selected:visited,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected:visited{background-color:#657786;border:1px solid #657786}
|
html.dark .ButtonGroup--tertiary>.Button.is-selected,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected,html.dark .ButtonGroup--tertiary>.Button.is-selected:visited,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected:visited{background-color:#657786;border:1px solid #657786}
|
||||||
html.dark .ButtonGroup--tertiary>.Button.is-selected:focus,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected:focus,html.dark .ButtonGroup--tertiary>.Button.is-selected.is-focus,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected.is-focus{box-shadow:0 0 0 2px white,0 0 0 4px #ccd6dd;background:#657786;border-color:#657786}
|
html.dark .ButtonGroup--tertiary>.Button.is-selected:focus,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected:focus,html.dark .ButtonGroup--tertiary>.Button.is-selected.is-focus,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected.is-focus{box-shadow:0 0 0 2px #fff,0 0 0 4px #ccd6dd;background:#657786;border-color:#657786}
|
||||||
html.dark .ButtonGroup--tertiary>.Button.is-selected:hover,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected:hover,html.dark .ButtonGroup--tertiary>.Button.is-selected.is-hover,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected.is-hover{background-color:#657786;border-color:#657786}
|
html.dark .ButtonGroup--tertiary>.Button.is-selected:hover,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected:hover,html.dark .ButtonGroup--tertiary>.Button.is-selected.is-hover,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected.is-hover{background-color:#657786;border-color:#657786}
|
||||||
html.dark .ButtonGroup--tertiary>.Button.is-selected:active,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected:active,html.dark .ButtonGroup--tertiary>.Button.is-selected.is-active,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected.is-active{box-shadow:0 0 0 2px white,0 0 0 4px #aab8c2;background-color:#657786;border-color:#657786}
|
html.dark .ButtonGroup--tertiary>.Button.is-selected:active,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected:active,html.dark .ButtonGroup--tertiary>.Button.is-selected.is-active,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected.is-active{box-shadow:0 0 0 2px #fff,0 0 0 4px #aab8c2;background-color:#657786;border-color:#657786}
|
||||||
html.dark .ButtonGroup--tertiary>.Button.is-selected[disabled],html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected[disabled],html.dark .ButtonGroup--tertiary>.Button.is-selected.is-disabled,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected.is-disabled,html.dark fieldset[disabled] .ButtonGroup--tertiary>.Button.is-selected,html.dark fieldset[disabled] .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected{background-color:#657786;border-color:#657786}
|
html.dark .ButtonGroup--tertiary>.Button.is-selected[disabled],html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected[disabled],html.dark .ButtonGroup--tertiary>.Button.is-selected.is-disabled,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected.is-disabled,html.dark fieldset[disabled] .ButtonGroup--tertiary>.Button.is-selected,html.dark fieldset[disabled] .ButtonGroup--tertiary>.ButtonGroup>.Button.is-selected{background-color:#657786;border-color:#657786}
|
||||||
html.dark .Button,html.dark .Button:visited,html.dark .Button.is-visited{border:1px solid #1da1f2;color:#1da1f2}
|
html.dark .Button,html.dark .Button:visited,html.dark .Button.is-visited{border:1px solid #1da1f2;color:#1da1f2}
|
||||||
html.dark .Button:focus,html.dark .Button.is-focus{box-shadow:0 0 0 2px white,0 0 0 4px #71c9f8;border-color:#1da1f2;color:#1da1f2}
|
html.dark .Button:focus,html.dark .Button.is-focus{box-shadow:0 0 0 2px #fff,0 0 0 4px #71c9f8;border-color:#1da1f2;color:#1da1f2}
|
||||||
html.dark .Button:hover,html.dark .Button.is-hover{background-color:#eaf5fd;color:#1da1f2}
|
html.dark .Button:hover,html.dark .Button.is-hover{background-color:#eaf5fd;color:#1da1f2}
|
||||||
html.dark .Button:active,html.dark .Button.is-active{box-shadow:0 0 0 2px white,0 0 0 4px #1da1f2;background:#eaf5fd;border-color:#1da1f2;color:#1da1f2}
|
html.dark .Button:active,html.dark .Button.is-active{box-shadow:0 0 0 2px #fff,0 0 0 4px #1da1f2;background:#eaf5fd;border-color:#1da1f2;color:#1da1f2}
|
||||||
html.dark .Button.Button--primary,html.dark .Button.Button--primary:visited,html.dark .ButtonGroup--primary>.Button,html.dark .ButtonGroup--primary>.Button:visited,html.dark .ButtonGroup--primary>.ButtonGroup>.Button,html.dark .ButtonGroup--primary>.ButtonGroup>.Button:visited{background-color:#1da1f2;border:1px solid #1da1f2}
|
html.dark .Button.Button--primary,html.dark .Button.Button--primary:visited,html.dark .ButtonGroup--primary>.Button,html.dark .ButtonGroup--primary>.Button:visited,html.dark .ButtonGroup--primary>.ButtonGroup>.Button,html.dark .ButtonGroup--primary>.ButtonGroup>.Button:visited{background-color:#1da1f2;border:1px solid #1da1f2}
|
||||||
html.dark .Button.Button--primary:focus,html.dark .Button.Button--primary.is-focus,html.dark .ButtonGroup--primary>.Button:focus,html.dark .ButtonGroup--primary>.Button.is-focus,html.dark .ButtonGroup--primary>.ButtonGroup>.Button:focus,html.dark .ButtonGroup--primary>.ButtonGroup>.Button.is-focus{box-shadow:0 0 0 2px white,0 0 0 4px #71c9f8;background:#1da1f2;border-color:#1da1f2}
|
html.dark .Button.Button--primary:focus,html.dark .Button.Button--primary.is-focus,html.dark .ButtonGroup--primary>.Button:focus,html.dark .ButtonGroup--primary>.Button.is-focus,html.dark .ButtonGroup--primary>.ButtonGroup>.Button:focus,html.dark .ButtonGroup--primary>.ButtonGroup>.Button.is-focus{box-shadow:0 0 0 2px #fff,0 0 0 4px #71c9f8;background:#1da1f2;border-color:#1da1f2}
|
||||||
html.dark .Button.Button--primary:hover,html.dark .Button.Button--primary.is-hover,html.dark .ButtonGroup--primary>.Button:hover,html.dark .ButtonGroup--primary>.Button.is-hover,html.dark .ButtonGroup--primary>.ButtonGroup>.Button:hover,html.dark .ButtonGroup--primary>.ButtonGroup>.Button.is-hover{background-color:#005fd1;border-color:#005fd1}
|
html.dark .Button.Button--primary:hover,html.dark .Button.Button--primary.is-hover,html.dark .ButtonGroup--primary>.Button:hover,html.dark .ButtonGroup--primary>.Button.is-hover,html.dark .ButtonGroup--primary>.ButtonGroup>.Button:hover,html.dark .ButtonGroup--primary>.ButtonGroup>.Button.is-hover{background-color:#005fd1;border-color:#005fd1}
|
||||||
html.dark .Button.Button--primary:active,html.dark .Button.Button--primary.is-active,html.dark .ButtonGroup--primary>.Button:active,html.dark .ButtonGroup--primary>.Button.is-active,html.dark .ButtonGroup--primary>.ButtonGroup>.Button:active,html.dark .ButtonGroup--primary>.ButtonGroup>.Button.is-active{box-shadow:0 0 0 2px white,0 0 0 4px #1da1f2;background-color:#005fd1;border-color:#005fd1}
|
html.dark .Button.Button--primary:active,html.dark .Button.Button--primary.is-active,html.dark .ButtonGroup--primary>.Button:active,html.dark .ButtonGroup--primary>.Button.is-active,html.dark .ButtonGroup--primary>.ButtonGroup>.Button:active,html.dark .ButtonGroup--primary>.ButtonGroup>.Button.is-active{box-shadow:0 0 0 2px #fff,0 0 0 4px #1da1f2;background-color:#005fd1;border-color:#005fd1}
|
||||||
html.dark .Button.Button--primary[disabled],html.dark .Button.Button--primary.is-disabled,html.dark fieldset[disabled] .Button.Button--primary,html.dark .ButtonGroup--primary>.Button[disabled],html.dark .ButtonGroup--primary>.Button.is-disabled,html.dark fieldset[disabled] .ButtonGroup--primary>.Button,html.dark .ButtonGroup--primary>.ButtonGroup>.Button[disabled],html.dark .ButtonGroup--primary>.ButtonGroup>.Button.is-disabled,html.dark fieldset[disabled] .ButtonGroup--primary>.ButtonGroup>.Button{background-color:#1da1f2;border-color:#1da1f2}
|
html.dark .Button.Button--primary[disabled],html.dark .Button.Button--primary.is-disabled,html.dark fieldset[disabled] .Button.Button--primary,html.dark .ButtonGroup--primary>.Button[disabled],html.dark .ButtonGroup--primary>.Button.is-disabled,html.dark fieldset[disabled] .ButtonGroup--primary>.Button,html.dark .ButtonGroup--primary>.ButtonGroup>.Button[disabled],html.dark .ButtonGroup--primary>.ButtonGroup>.Button.is-disabled,html.dark fieldset[disabled] .ButtonGroup--primary>.ButtonGroup>.Button{background-color:#1da1f2;border-color:#1da1f2}
|
||||||
html.dark .Button.Button--tertiary,html.dark .Button.Button--tertiary:visited,html.dark .ButtonGroup--tertiary>.Button,html.dark .ButtonGroup--tertiary>.Button:visited,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button:visited{border:1px solid #657786;color:#657786}
|
html.dark .Button.Button--tertiary,html.dark .Button.Button--tertiary:visited,html.dark .ButtonGroup--tertiary>.Button,html.dark .ButtonGroup--tertiary>.Button:visited,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button:visited{border:1px solid #657786;color:#657786}
|
||||||
html.dark .Button.Button--tertiary:focus,html.dark .Button.Button--tertiary.is-focus,html.dark .ButtonGroup--tertiary>.Button:focus,html.dark .ButtonGroup--tertiary>.Button.is-focus,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button:focus,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-focus{box-shadow:0 0 0 2px white,0 0 0 4px #ccd6dd;border-color:#657786;color:#657786}
|
html.dark .Button.Button--tertiary:focus,html.dark .Button.Button--tertiary.is-focus,html.dark .ButtonGroup--tertiary>.Button:focus,html.dark .ButtonGroup--tertiary>.Button.is-focus,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button:focus,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-focus{box-shadow:0 0 0 2px #fff,0 0 0 4px #ccd6dd;border-color:#657786;color:#657786}
|
||||||
html.dark .Button.Button--tertiary:hover,html.dark .Button.Button--tertiary.is-hover,html.dark .ButtonGroup--tertiary>.Button:hover,html.dark .ButtonGroup--tertiary>.Button.is-hover,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button:hover,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-hover{background-color:#f5f8fa;border-color:#657786;color:#657786}
|
html.dark .Button.Button--tertiary:hover,html.dark .Button.Button--tertiary.is-hover,html.dark .ButtonGroup--tertiary>.Button:hover,html.dark .ButtonGroup--tertiary>.Button.is-hover,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button:hover,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-hover{background-color:#f5f8fa;border-color:#657786;color:#657786}
|
||||||
html.dark .Button.Button--tertiary:active,html.dark .Button.Button--tertiary.is-active,html.dark .ButtonGroup--tertiary>.Button:active,html.dark .ButtonGroup--tertiary>.Button.is-active,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button:active,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-active{box-shadow:0 0 0 2px white,0 0 0 4px #657786;background-color:#f5f8fa;border-color:#657786;color:#657786}
|
html.dark .Button.Button--tertiary:active,html.dark .Button.Button--tertiary.is-active,html.dark .ButtonGroup--tertiary>.Button:active,html.dark .ButtonGroup--tertiary>.Button.is-active,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button:active,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-active{box-shadow:0 0 0 2px #fff,0 0 0 4px #657786;background-color:#f5f8fa;border-color:#657786;color:#657786}
|
||||||
html.dark .Button.Button--tertiary[disabled],html.dark .Button.Button--tertiary.is-disabled,html.dark fieldset[disabled] .Button.Button--tertiary,html.dark .ButtonGroup--tertiary>.Button[disabled],html.dark .ButtonGroup--tertiary>.Button.is-disabled,html.dark fieldset[disabled] .ButtonGroup--tertiary>.Button,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button[disabled],html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-disabled,html.dark fieldset[disabled] .ButtonGroup--tertiary>.ButtonGroup>.Button{border-color:#657786}
|
html.dark .Button.Button--tertiary[disabled],html.dark .Button.Button--tertiary.is-disabled,html.dark fieldset[disabled] .Button.Button--tertiary,html.dark .ButtonGroup--tertiary>.Button[disabled],html.dark .ButtonGroup--tertiary>.Button.is-disabled,html.dark fieldset[disabled] .ButtonGroup--tertiary>.Button,html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button[disabled],html.dark .ButtonGroup--tertiary>.ButtonGroup>.Button.is-disabled,html.dark fieldset[disabled] .ButtonGroup--tertiary>.ButtonGroup>.Button{border-color:#657786}
|
||||||
html.dark .Button.Button--success,html.dark .Button.Button--success:visited{background-color:#17bf63;border:1px solid #17bf63}
|
html.dark .Button.Button--success,html.dark .Button.Button--success:visited{background-color:#17bf63;border:1px solid #17bf63}
|
||||||
html.dark .Button.Button--success:focus,html.dark .Button.Button--success.is-focus{box-shadow:0 0 0 2px white,0 0 0 4px #68e090;background:#17bf63;border-color:#17bf63}
|
html.dark .Button.Button--success:focus,html.dark .Button.Button--success.is-focus{box-shadow:0 0 0 2px #fff,0 0 0 4px #68e090;background:#17bf63;border-color:#17bf63}
|
||||||
html.dark .Button.Button--success:hover,html.dark .Button.Button--success.is-hover{background-color:#008951;border-color:#008951}
|
html.dark .Button.Button--success:hover,html.dark .Button.Button--success.is-hover{background-color:#008951;border-color:#008951}
|
||||||
html.dark .Button.Button--success:active,html.dark .Button.Button--success.is-active{box-shadow:0 0 0 2px white,0 0 0 4px #17bf63;background-color:#008951;border-color:#008951}
|
html.dark .Button.Button--success:active,html.dark .Button.Button--success.is-active{box-shadow:0 0 0 2px #fff,0 0 0 4px #17bf63;background-color:#008951;border-color:#008951}
|
||||||
html.dark .Button.Button--success[disabled],html.dark .Button.Button--success.is-disabled,html.dark fieldset[disabled] .Button.Button--success{background-color:#17bf63;border-color:#17bf63}
|
html.dark .Button.Button--success[disabled],html.dark .Button.Button--success.is-disabled,html.dark fieldset[disabled] .Button.Button--success{background-color:#17bf63;border-color:#17bf63}
|
||||||
html.dark .Button.Button--warning,html.dark .Button.Button--warning:visited{background-color:#ffad1f;border:1px solid #ffad1f}
|
html.dark .Button.Button--warning,html.dark .Button.Button--warning:visited{background-color:#ffad1f;border:1px solid #ffad1f}
|
||||||
html.dark .Button.Button--warning:focus,html.dark .Button.Button--warning.is-focus{box-shadow:0 0 0 2px white,0 0 0 4px #ffd03f;background:#ffad1f;border-color:#ffad1f}
|
html.dark .Button.Button--warning:focus,html.dark .Button.Button--warning.is-focus{box-shadow:0 0 0 2px #fff,0 0 0 4px #ffd03f;background:#ffad1f;border-color:#ffad1f}
|
||||||
html.dark .Button.Button--warning:hover,html.dark .Button.Button--warning.is-hover{background-color:#f98e00;border-color:#f98e00}
|
html.dark .Button.Button--warning:hover,html.dark .Button.Button--warning.is-hover{background-color:#f98e00;border-color:#f98e00}
|
||||||
html.dark .Button.Button--warning:active,html.dark .Button.Button--warning.is-active{box-shadow:0 0 0 2px white,0 0 0 4px #ffad1f;background-color:#f98e00;border-color:#f98e00}
|
html.dark .Button.Button--warning:active,html.dark .Button.Button--warning.is-active{box-shadow:0 0 0 2px #fff,0 0 0 4px #ffad1f;background-color:#f98e00;border-color:#f98e00}
|
||||||
html.dark .Button.Button--warning[disabled],html.dark .Button.Button--warning.is-disabled,html.dark fieldset[disabled] .Button.Button--warning{background-color:#ffad1f;border-color:#ffad1f}
|
html.dark .Button.Button--warning[disabled],html.dark .Button.Button--warning.is-disabled,html.dark fieldset[disabled] .Button.Button--warning{background-color:#ffad1f;border-color:#ffad1f}
|
||||||
html.dark .Button.Button--danger,html.dark .Button.Button--danger:visited{background-color:#e0245e;border:1px solid #e0245e}
|
html.dark .Button.Button--danger,html.dark .Button.Button--danger:visited{background-color:#e0245e;border:1px solid #e0245e}
|
||||||
html.dark .Button.Button--danger:focus,html.dark .Button.Button--danger.is-focus{box-shadow:0 0 0 2px white,0 0 0 4px #f6809a;background:#e0245e;border-color:#e0245e}
|
html.dark .Button.Button--danger:focus,html.dark .Button.Button--danger.is-focus{box-shadow:0 0 0 2px #fff,0 0 0 4px #f6809a;background:#e0245e;border-color:#e0245e}
|
||||||
html.dark .Button.Button--danger:hover,html.dark .Button.Button--danger.is-hover{background-color:#a01744;border-color:#a01744}
|
html.dark .Button.Button--danger:hover,html.dark .Button.Button--danger.is-hover{background-color:#a01744;border-color:#a01744}
|
||||||
html.dark .Button.Button--danger:active,html.dark .Button.Button--danger.is-active{box-shadow:0 0 0 2px white,0 0 0 4px #e0245e;background-color:#a01744;border-color:#a01744}
|
html.dark .Button.Button--danger:active,html.dark .Button.Button--danger.is-active{box-shadow:0 0 0 2px #fff,0 0 0 4px #e0245e;background-color:#a01744;border-color:#a01744}
|
||||||
html.dark .Button.Button--danger[disabled],html.dark .Button.Button--danger.is-disabled,html.dark fieldset[disabled] .Button.Button--danger{background-color:#e0245e;border-color:#e0245e}
|
html.dark .Button.Button--danger[disabled],html.dark .Button.Button--danger.is-disabled,html.dark fieldset[disabled] .Button.Button--danger{background-color:#e0245e;border-color:#e0245e}
|
||||||
html.dark .Button.Button--link{color:#1b95e0}
|
html.dark .Button.Button--link{color:#1b95e0}
|
||||||
html.dark .Button.Button--dangerLink{color:#e0245e}
|
html.dark .Button.Button--dangerLink{color:#e0245e}
|
||||||
@@ -730,8 +722,8 @@ html.dark .DateRange[dir='rtl'] .DateRange-pickersRow:first-child .DateRange-pic
|
|||||||
html.dark .PillGroup .Pill.is-selected{background:#005fd1}
|
html.dark .PillGroup .Pill.is-selected{background:#005fd1}
|
||||||
html.dark .PillGroup .Pill>a,html.dark .PillGroup .Pill>button{color:#1b95e0}
|
html.dark .PillGroup .Pill>a,html.dark .PillGroup .Pill>button{color:#1b95e0}
|
||||||
html.dark .PillGroup .Pill>a:hover,html.dark .PillGroup .Pill>button:hover{background:#eaf5fd}
|
html.dark .PillGroup .Pill>a:hover,html.dark .PillGroup .Pill>button:hover{background:#eaf5fd}
|
||||||
html.dark .PillGroup .Pill>a:focus,html.dark .PillGroup .Pill>button:focus{box-shadow:0 0 0 2px white,0 0 0 4px #71c9f8}
|
html.dark .PillGroup .Pill>a:focus,html.dark .PillGroup .Pill>button:focus{box-shadow:0 0 0 2px #fff,0 0 0 4px #71c9f8}
|
||||||
html.dark .PillGroup .Pill>a:active,html.dark .PillGroup .Pill>button:active{box-shadow:0 0 0 2px white,0 0 0 4px #1da1f2}
|
html.dark .PillGroup .Pill>a:active,html.dark .PillGroup .Pill>button:active{box-shadow:0 0 0 2px #fff,0 0 0 4px #1da1f2}
|
||||||
html.dark .PillGroup .Pill.is-selected>a,html.dark .PillGroup .Pill.is-selected>button{color:#FFF}
|
html.dark .PillGroup .Pill.is-selected>a,html.dark .PillGroup .Pill.is-selected>button{color:#FFF}
|
||||||
html.dark .FormInput,html.dark .FormTextarea{border:1px solid #ccd6dd;color:#14171a}
|
html.dark .FormInput,html.dark .FormTextarea{border:1px solid #ccd6dd;color:#14171a}
|
||||||
html.dark .FormInput-characterCount{color:#ccd6dd}
|
html.dark .FormInput-characterCount{color:#ccd6dd}
|
||||||
@@ -751,51 +743,51 @@ html.dark .FormInputWrapper-startAdornment,html.dark .FormInputWrapper-endAdornm
|
|||||||
html.dark .FormField.is-invalid .FormField-validationMessage{color:#e0245e}
|
html.dark .FormField.is-invalid .FormField-validationMessage{color:#e0245e}
|
||||||
html.dark .FormField.is-valid .FormField-validationMessage{color:#008951}
|
html.dark .FormField.is-valid .FormField-validationMessage{color:#008951}
|
||||||
html.dark .FormField-description{color:#657786}
|
html.dark .FormField-description{color:#657786}
|
||||||
html.dark .Token-checkbox input[type="checkbox"]:focus+.Icon{box-shadow:0 0 0 5px white,0 0 0 7px #71c9f8}
|
html.dark .Token-checkbox input[type="checkbox"]:focus+.Icon{box-shadow:0 0 0 5px #fff,0 0 0 7px #71c9f8}
|
||||||
html.dark .Token--small .Token-trigger input[type="checkbox"]:focus+.Icon,html.dark .TokenGroup--small>.Token .Token-trigger input[type="checkbox"]:focus+.Icon,html.dark .TokenGroup--small>.TokenGroup>.Token .Token-trigger input[type="checkbox"]:focus+.Icon{box-shadow:0 0 0 3px white,0 0 0 5px #71c9f8}
|
html.dark .Token--small .Token-trigger input[type="checkbox"]:focus+.Icon,html.dark .TokenGroup--small>.Token .Token-trigger input[type="checkbox"]:focus+.Icon,html.dark .TokenGroup--small>.TokenGroup>.Token .Token-trigger input[type="checkbox"]:focus+.Icon{box-shadow:0 0 0 3px #fff,0 0 0 5px #71c9f8}
|
||||||
html.dark .Token--xsmall .Token-trigger input[type="checkbox"]:focus+.Icon,html.dark .TokenGroup--xsmall>.Token .Token-trigger input[type="checkbox"]:focus+.Icon,html.dark .TokenGroup--xsmall>.TokenGroup>.Token .Token-trigger input[type="checkbox"]:focus+.Icon{box-shadow:0 0 0 0 white,0 0 0 2px #71c9f8}
|
html.dark .Token--xsmall .Token-trigger input[type="checkbox"]:focus+.Icon,html.dark .TokenGroup--xsmall>.Token .Token-trigger input[type="checkbox"]:focus+.Icon,html.dark .TokenGroup--xsmall>.TokenGroup>.Token .Token-trigger input[type="checkbox"]:focus+.Icon{box-shadow:0 0 0 0 #fff,0 0 0 2px #71c9f8}
|
||||||
html.dark .Token,html.dark .Token--blue{border-color:#1da1f2;color:#1da1f2}
|
html.dark .Token,html.dark .Token--blue{border-color:#1da1f2;color:#1da1f2}
|
||||||
html.dark .Token .Token-adornment,html.dark .Token--blue .Token-adornment{background-color:#1da1f2}
|
html.dark .Token .Token-adornment,html.dark .Token--blue .Token-adornment{background-color:#1da1f2}
|
||||||
html.dark .Token:hover,html.dark .Token--blue:hover{background-color:#97e3ff;color:#005fd1}
|
html.dark .Token:hover,html.dark .Token--blue:hover{background-color:#97e3ff;color:#005fd1}
|
||||||
html.dark .Token.is-selected,html.dark .Token--blue.is-selected{background-color:#1da1f2}
|
html.dark .Token.is-selected,html.dark .Token--blue.is-selected{background-color:#1da1f2}
|
||||||
html.dark .Token.is-selected .Token-adornment,html.dark .Token--blue.is-selected .Token-adornment{color:#1da1f2}
|
html.dark .Token.is-selected .Token-adornment,html.dark .Token--blue.is-selected .Token-adornment{color:#1da1f2}
|
||||||
html.dark .Token.is-selected:hover,html.dark .Token--blue.is-selected:hover{background-color:#005fd1;border-color:#005fd1}
|
html.dark .Token.is-selected:hover,html.dark .Token--blue.is-selected:hover{background-color:#005fd1;border-color:#005fd1}
|
||||||
html.dark .Token:focus,html.dark .Token--blue:focus,html.dark .Token.is-focused,html.dark .Token--blue.is-focused{box-shadow:0 0 0 1px white,0 0 0 3px #71c9f8}
|
html.dark .Token:focus,html.dark .Token--blue:focus,html.dark .Token.is-focused,html.dark .Token--blue.is-focused{box-shadow:0 0 0 1px #fff,0 0 0 3px #71c9f8}
|
||||||
html.dark .Token--green{border-color:#17bf63;color:#17bf63}
|
html.dark .Token--green{border-color:#17bf63;color:#17bf63}
|
||||||
html.dark .Token--green .Token-adornment{background-color:#17bf63}
|
html.dark .Token--green .Token-adornment{background-color:#17bf63}
|
||||||
html.dark .Token--green:hover{background-color:#a5f2aa;color:#008951}
|
html.dark .Token--green:hover{background-color:#a5f2aa;color:#008951}
|
||||||
html.dark .Token--green.is-selected{background-color:#17bf63}
|
html.dark .Token--green.is-selected{background-color:#17bf63}
|
||||||
html.dark .Token--green.is-selected .Token-adornment{color:#17bf63}
|
html.dark .Token--green.is-selected .Token-adornment{color:#17bf63}
|
||||||
html.dark .Token--green.is-selected:hover{background-color:#008951;border-color:#008951}
|
html.dark .Token--green.is-selected:hover{background-color:#008951;border-color:#008951}
|
||||||
html.dark .Token--green:focus,html.dark .Token--green.is-focused{box-shadow:0 0 0 1px white,0 0 0 3px #68e090}
|
html.dark .Token--green:focus,html.dark .Token--green.is-focused{box-shadow:0 0 0 1px #fff,0 0 0 3px #68e090}
|
||||||
html.dark .Token--red{border-color:#e0245e;color:#e0245e}
|
html.dark .Token--red{border-color:#e0245e;color:#e0245e}
|
||||||
html.dark .Token--red .Token-adornment{background-color:#e0245e}
|
html.dark .Token--red .Token-adornment{background-color:#e0245e}
|
||||||
html.dark .Token--red:hover{background-color:#ffb8c2;color:#a01744}
|
html.dark .Token--red:hover{background-color:#ffb8c2;color:#a01744}
|
||||||
html.dark .Token--red.is-selected{background-color:#e0245e}
|
html.dark .Token--red.is-selected{background-color:#e0245e}
|
||||||
html.dark .Token--red.is-selected .Token-adornment{color:#e0245e}
|
html.dark .Token--red.is-selected .Token-adornment{color:#e0245e}
|
||||||
html.dark .Token--red.is-selected:hover{background-color:#a01744;border-color:#a01744}
|
html.dark .Token--red.is-selected:hover{background-color:#a01744;border-color:#a01744}
|
||||||
html.dark .Token--red:focus,html.dark .Token--red.is-focused{box-shadow:0 0 0 1px white,0 0 0 3px #f6809a}
|
html.dark .Token--red:focus,html.dark .Token--red.is-focused{box-shadow:0 0 0 1px #fff,0 0 0 3px #f6809a}
|
||||||
html.dark .Token--purple{border-color:#794bc4;color:#794bc4}
|
html.dark .Token--purple{border-color:#794bc4;color:#794bc4}
|
||||||
html.dark .Token--purple .Token-adornment{background-color:#794bc4}
|
html.dark .Token--purple .Token-adornment{background-color:#794bc4}
|
||||||
html.dark .Token--purple:hover{background-color:#c7b4fa;color:#4f0299}
|
html.dark .Token--purple:hover{background-color:#c7b4fa;color:#4f0299}
|
||||||
html.dark .Token--purple.is-selected{background-color:#794bc4}
|
html.dark .Token--purple.is-selected{background-color:#794bc4}
|
||||||
html.dark .Token--purple.is-selected .Token-adornment{color:#794bc4}
|
html.dark .Token--purple.is-selected .Token-adornment{color:#794bc4}
|
||||||
html.dark .Token--purple.is-selected:hover{background-color:#4f0299;border-color:#4f0299}
|
html.dark .Token--purple.is-selected:hover{background-color:#4f0299;border-color:#4f0299}
|
||||||
html.dark .Token--purple:focus,html.dark .Token--purple.is-focused{box-shadow:0 0 0 1px white,0 0 0 3px #a37ced}
|
html.dark .Token--purple:focus,html.dark .Token--purple.is-focused{box-shadow:0 0 0 1px #fff,0 0 0 3px #a37ced}
|
||||||
html.dark .Token--yellow{border-color:#ffad1f;color:#ffad1f}
|
html.dark .Token--yellow{border-color:#ffad1f;color:#ffad1f}
|
||||||
html.dark .Token--yellow .Token-adornment{background-color:#ffad1f}
|
html.dark .Token--yellow .Token-adornment{background-color:#ffad1f}
|
||||||
html.dark .Token--yellow:hover{background-color:#ffe76e;color:#f98e00}
|
html.dark .Token--yellow:hover{background-color:#ffe76e;color:#f98e00}
|
||||||
html.dark .Token--yellow.is-selected{background-color:#ffad1f}
|
html.dark .Token--yellow.is-selected{background-color:#ffad1f}
|
||||||
html.dark .Token--yellow.is-selected .Token-adornment{color:#ffad1f}
|
html.dark .Token--yellow.is-selected .Token-adornment{color:#ffad1f}
|
||||||
html.dark .Token--yellow.is-selected:hover{background-color:#f98e00;border-color:#f98e00}
|
html.dark .Token--yellow.is-selected:hover{background-color:#f98e00;border-color:#f98e00}
|
||||||
html.dark .Token--yellow:focus,html.dark .Token--yellow.is-focused{box-shadow:0 0 0 1px white,0 0 0 3px #ffd03f}
|
html.dark .Token--yellow:focus,html.dark .Token--yellow.is-focused{box-shadow:0 0 0 1px #fff,0 0 0 3px #ffd03f}
|
||||||
html.dark .Token--gray{border-color:#657786;color:#657786}
|
html.dark .Token--gray{border-color:#657786;color:#657786}
|
||||||
html.dark .Token--gray .Token-adornment{background-color:#657786}
|
html.dark .Token--gray .Token-adornment{background-color:#657786}
|
||||||
html.dark .Token--gray:hover{background-color:#e6ecf0;color:#657786}
|
html.dark .Token--gray:hover{background-color:#e6ecf0;color:#657786}
|
||||||
html.dark .Token--gray.is-selected{background-color:#657786}
|
html.dark .Token--gray.is-selected{background-color:#657786}
|
||||||
html.dark .Token--gray.is-selected .Token-adornment{color:#657786}
|
html.dark .Token--gray.is-selected .Token-adornment{color:#657786}
|
||||||
html.dark .Token--gray.is-selected:hover{background-color:#aab8c2;border-color:#aab8c2}
|
html.dark .Token--gray.is-selected:hover{background-color:#aab8c2;border-color:#aab8c2}
|
||||||
html.dark .Token--gray:focus,html.dark .Token--gray.is-focused{box-shadow:0 0 0 1px white,0 0 0 3px #aab8c2}
|
html.dark .Token--gray:focus,html.dark .Token--gray.is-focused{box-shadow:0 0 0 1px #fff,0 0 0 3px #aab8c2}
|
||||||
html.dark .FormTokenInput-input::-webkit-input-placeholder{color:#aab8c2}
|
html.dark .FormTokenInput-input::-webkit-input-placeholder{color:#aab8c2}
|
||||||
html.dark .DataPoint .DataPoint-label{color:#657786}
|
html.dark .DataPoint .DataPoint-label{color:#657786}
|
||||||
html.dark .DataPoint .DataPoint-info{color:#14171a}
|
html.dark .DataPoint .DataPoint-info{color:#14171a}
|
||||||
@@ -805,7 +797,7 @@ html.dark .DataPoint--withBottomBorder{border-bottom:1px solid #ccd6dd}
|
|||||||
html.dark .FormTokenInput.FormTextarea::-webkit-input-placeholder{color:#8899A6}
|
html.dark .FormTokenInput.FormTextarea::-webkit-input-placeholder{color:#8899A6}
|
||||||
html.dark .FormTokenInput.FormTextarea::placeholder{color:#8899A6}
|
html.dark .FormTokenInput.FormTextarea::placeholder{color:#8899A6}
|
||||||
html.dark .DatePicker.date-unselected .is-rangeStart,html.dark .DatePicker.date-unselected .is-rangeEnd{color:#14171a}
|
html.dark .DatePicker.date-unselected .is-rangeStart,html.dark .DatePicker.date-unselected .is-rangeEnd{color:#14171a}
|
||||||
html.dark .DatePicker.date-unselected .is-rangeStart:hover,html.dark .DatePicker.date-unselected .is-rangeEnd:hover{background-color:#005091;color:#ffffff}
|
html.dark .DatePicker.date-unselected .is-rangeStart:hover,html.dark .DatePicker.date-unselected .is-rangeEnd:hover{background-color:#005091;color:#fff}
|
||||||
html.dark .NotificationList .Notification-body{color:#14171A}
|
html.dark .NotificationList .Notification-body{color:#14171A}
|
||||||
html.dark .DrawerModal{color:#14171A}
|
html.dark .DrawerModal{color:#14171A}
|
||||||
/* fixes */
|
/* fixes */
|
||||||
|
@@ -26,7 +26,7 @@ enabled(){
|
|||||||
this.emojiData3 = []; // no skin tones, appended
|
this.emojiData3 = []; // no skin tones, appended
|
||||||
this.emojiNames = [];
|
this.emojiNames = [];
|
||||||
|
|
||||||
var me = this;
|
const me = this;
|
||||||
|
|
||||||
// styles
|
// styles
|
||||||
|
|
||||||
@@ -51,12 +51,12 @@ enabled(){
|
|||||||
|
|
||||||
// layout
|
// layout
|
||||||
|
|
||||||
var buttonHTML = '<button class="needsclick btn btn-on-blue txt-left padding-v--6 padding-h--8 emoji-keyboard-popup-btn"><i class="icon icon-heart"></i></button>';
|
let buttonHTML = '<button class="needsclick btn btn-on-blue txt-left padding-v--6 padding-h--8 emoji-keyboard-popup-btn"><i class="icon icon-heart"></i></button>';
|
||||||
|
|
||||||
this.prevComposeMustache = TD.mustaches["compose/docked_compose.mustache"];
|
this.prevComposeMustache = TD.mustaches["compose/docked_compose.mustache"];
|
||||||
TD.mustaches["compose/docked_compose.mustache"] = TD.mustaches["compose/docked_compose.mustache"].replace('<div class="cf margin-t--12 margin-b--30">', '<div class="cf margin-t--12 margin-b--30">'+buttonHTML);
|
window.TDPF_injectMustache("compose/docked_compose.mustache", "append", '<div class="cf margin-t--12 margin-b--30">', buttonHTML);
|
||||||
|
|
||||||
var maybeDockedComposePanel = $(".js-docked-compose");
|
let maybeDockedComposePanel = $(".js-docked-compose");
|
||||||
|
|
||||||
if (maybeDockedComposePanel.length){
|
if (maybeDockedComposePanel.length){
|
||||||
maybeDockedComposePanel.find(".cf.margin-t--12.margin-b--30").first().append(buttonHTML);
|
maybeDockedComposePanel.find(".cf.margin-t--12.margin-b--30").first().append(buttonHTML);
|
||||||
@@ -67,10 +67,10 @@ enabled(){
|
|||||||
this.currentKeyboard = null;
|
this.currentKeyboard = null;
|
||||||
this.currentSpanner = null;
|
this.currentSpanner = null;
|
||||||
|
|
||||||
var wasSearchFocused = false;
|
let wasSearchFocused = false;
|
||||||
var lastEmojiKeyword, lastEmojiPosition, lastEmojiLength;
|
let lastEmojiKeyword, lastEmojiPosition, lastEmojiLength;
|
||||||
|
|
||||||
var hideKeyboard = (refocus) => {
|
const hideKeyboard = (refocus) => {
|
||||||
$(this.currentKeyboard).remove();
|
$(this.currentKeyboard).remove();
|
||||||
this.currentKeyboard = null;
|
this.currentKeyboard = null;
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ enabled(){
|
|||||||
lastEmojiKeyword = null;
|
lastEmojiKeyword = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
var generateEmojiHTML = skinTone => {
|
const generateEmojiHTML = skinTone => {
|
||||||
let index = 0;
|
let index = 0;
|
||||||
let html = [ "<p style='font-size:13px;color:#444;margin:4px;text-align:center'>Please, note that some emoji may not show up correctly in the text box above, but they will display in the tweet.</p>" ];
|
let html = [ "<p style='font-size:13px;color:#444;margin:4px;text-align:center'>Please, note that some emoji may not show up correctly in the text box above, but they will display in the tweet.</p>" ];
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ enabled(){
|
|||||||
return html.join("");
|
return html.join("");
|
||||||
};
|
};
|
||||||
|
|
||||||
var updateFilters = () => {
|
const updateFilters = () => {
|
||||||
let keywords = this.currentKeywords;
|
let keywords = this.currentKeywords;
|
||||||
let container = $(this.currentKeyboard.children[1]);
|
let container = $(this.currentKeyboard.children[1]);
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ enabled(){
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var selectSkinTone = skinTone => {
|
const selectSkinTone = skinTone => {
|
||||||
let selectedEle = this.currentKeyboard.children[2].querySelector("[data-tone='"+this.selectedSkinTone+"']");
|
let selectedEle = this.currentKeyboard.children[2].querySelector("[data-tone='"+this.selectedSkinTone+"']");
|
||||||
selectedEle && selectedEle.classList.remove("sel");
|
selectedEle && selectedEle.classList.remove("sel");
|
||||||
|
|
||||||
@@ -146,12 +146,12 @@ enabled(){
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.generateKeyboard = (left, top) => {
|
this.generateKeyboard = (left, top) => {
|
||||||
var outer = document.createElement("div");
|
let outer = document.createElement("div");
|
||||||
outer.classList.add("emoji-keyboard");
|
outer.classList.add("emoji-keyboard");
|
||||||
outer.style.left = left+"px";
|
outer.style.left = left+"px";
|
||||||
outer.style.top = top+"px";
|
outer.style.top = top+"px";
|
||||||
|
|
||||||
var keyboard = document.createElement("div");
|
let keyboard = document.createElement("div");
|
||||||
keyboard.classList.add("emoji-keyboard-list");
|
keyboard.classList.add("emoji-keyboard-list");
|
||||||
|
|
||||||
keyboard.addEventListener("click", function(e){
|
keyboard.addEventListener("click", function(e){
|
||||||
@@ -164,11 +164,11 @@ enabled(){
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
});
|
});
|
||||||
|
|
||||||
var search = document.createElement("div");
|
let search = document.createElement("div");
|
||||||
search.innerHTML = "<input type='text' placeholder='Search...'>";
|
search.innerHTML = "<input type='text' placeholder='Search...'>";
|
||||||
search.classList.add("emoji-keyboard-search");
|
search.classList.add("emoji-keyboard-search");
|
||||||
|
|
||||||
var skintones = document.createElement("div");
|
let skintones = document.createElement("div");
|
||||||
skintones.innerHTML = me.skinToneData.map(entry => "<div data-tone='"+entry[0]+"' style='background-color:"+entry[1]+"'></div>").join("");
|
skintones.innerHTML = me.skinToneData.map(entry => "<div data-tone='"+entry[0]+"' style='background-color:"+entry[1]+"'></div>").join("");
|
||||||
skintones.classList.add("emoji-keyboard-skintones");
|
skintones.classList.add("emoji-keyboard-skintones");
|
||||||
|
|
||||||
@@ -189,7 +189,7 @@ enabled(){
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
});
|
});
|
||||||
|
|
||||||
var searchInput = search.children[0];
|
let searchInput = search.children[0];
|
||||||
searchInput.focus();
|
searchInput.focus();
|
||||||
|
|
||||||
wasSearchFocused = false;
|
wasSearchFocused = false;
|
||||||
@@ -232,12 +232,12 @@ enabled(){
|
|||||||
this.composePanelScroller.trigger("scroll");
|
this.composePanelScroller.trigger("scroll");
|
||||||
};
|
};
|
||||||
|
|
||||||
var getKeyboardTop = () => {
|
const getKeyboardTop = () => {
|
||||||
let button = $(".emoji-keyboard-popup-btn");
|
let button = $(".emoji-keyboard-popup-btn");
|
||||||
return button.offset().top+button.outerHeight()+me.composePanelScroller.scrollTop()+8;
|
return button.offset().top+button.outerHeight()+me.composePanelScroller.scrollTop()+8;
|
||||||
};
|
};
|
||||||
|
|
||||||
var insertEmoji = (src, alt) => {
|
const insertEmoji = (src, alt) => {
|
||||||
let input = this.composeInput;
|
let input = this.composeInput;
|
||||||
|
|
||||||
let val = input.val();
|
let val = input.val();
|
||||||
@@ -418,7 +418,7 @@ ready(){
|
|||||||
|
|
||||||
// HTML generation
|
// HTML generation
|
||||||
|
|
||||||
var convUnicode = function(codePt){
|
const convUnicode = function(codePt){
|
||||||
if (codePt > 0xFFFF){
|
if (codePt > 0xFFFF){
|
||||||
codePt -= 0x10000;
|
codePt -= 0x10000;
|
||||||
return String.fromCharCode(0xD800+(codePt>>10), 0xDC00+(codePt&0x3FF));
|
return String.fromCharCode(0xD800+(codePt>>10), 0xDC00+(codePt&0x3FF));
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
enabled(){
|
enabled(){
|
||||||
var configuration = { defaultAccount: "#preferred" };
|
let configuration = { defaultAccount: "#preferred" };
|
||||||
|
|
||||||
window.TDPF_loadConfigurationFile(this, "configuration.js", "configuration.default.js", obj => configuration = obj);
|
window.TDPF_loadConfigurationFile(this, "configuration.js", "configuration.default.js", obj => configuration = obj);
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ enabled(){
|
|||||||
this.uiComposeTweetEvent = (e, data) => {
|
this.uiComposeTweetEvent = (e, data) => {
|
||||||
return if !(data.type === "reply" || (data.type === "tweet" && "quotedTweet" in data)) || data.popFromInline || !("element" in data);
|
return if !(data.type === "reply" || (data.type === "tweet" && "quotedTweet" in data)) || data.popFromInline || !("element" in data);
|
||||||
|
|
||||||
var query;
|
let query;
|
||||||
|
|
||||||
if (configuration.useAdvancedSelector){
|
if (configuration.useAdvancedSelector){
|
||||||
if (configuration.customSelector){
|
if (configuration.customSelector){
|
||||||
@@ -23,25 +23,34 @@ enabled(){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var section = data.element.closest("section.js-column");
|
let section = data.element.closest("section.js-column");
|
||||||
|
let column = TD.controller.columnManager.get(section.attr("data-column"));
|
||||||
|
|
||||||
var column = TD.controller.columnManager.get(section.attr("data-column"));
|
let feeds = column.getFeeds();
|
||||||
var header = $(".column-title", section);
|
let accountText = "";
|
||||||
var title = header.children(".column-head-title");
|
|
||||||
|
|
||||||
var columnTitle, columnAccount;
|
if (feeds.length === 1){
|
||||||
|
let metadata = feeds[0].getMetadata();
|
||||||
|
let id = metadata.ownerId || metadata.id;
|
||||||
|
|
||||||
if (title.length){
|
if (id){
|
||||||
columnTitle = title.text();
|
accountText = TD.cache.names.getScreenName(id);
|
||||||
columnAccount = header.children(".attribution").text();
|
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
columnTitle = header.children(".column-title-edit-box").val();
|
let account = TD.storage.accountController.get(feeds[0].getAccountKey());
|
||||||
columnAccount = "";
|
|
||||||
|
if (account){
|
||||||
|
accountText = "@"+account.getUsername();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let header = $(".column-header-title", section);
|
||||||
|
let title = header.children(".column-heading");
|
||||||
|
let titleText = title.length ? title.text() : header.children(".column-title-edit-box").val();
|
||||||
|
|
||||||
try{
|
try{
|
||||||
query = configuration.customSelector(columnTitle, columnAccount, column, section.hasClass("column-temp"));
|
query = configuration.customSelector(titleText, accountText, column, section.hasClass("column-temp"));
|
||||||
}catch(e){
|
}catch(e){
|
||||||
$TD.alert("warning", "Plugin reply-account has invalid configuration: customSelector threw an error: "+e.message);
|
$TD.alert("warning", "Plugin reply-account has invalid configuration: customSelector threw an error: "+e.message);
|
||||||
return;
|
return;
|
||||||
@@ -79,7 +88,7 @@ enabled(){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var identifier = null;
|
let identifier = null;
|
||||||
|
|
||||||
switch(query){
|
switch(query){
|
||||||
case "#preferred":
|
case "#preferred":
|
||||||
@@ -97,7 +106,7 @@ enabled(){
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
if (query[0] === '@'){
|
if (query[0] === '@'){
|
||||||
var obj = TD.storage.accountController.getAccountFromUsername(query.substring(1));
|
let obj = TD.storage.accountController.getAccountFromUsername(query.substring(1));
|
||||||
|
|
||||||
if (obj.length === 0){
|
if (obj.length === 0){
|
||||||
$TD.alert("warning", "Plugin reply-account has invalid configuration: requested account not found: "+query);
|
$TD.alert("warning", "Plugin reply-account has invalid configuration: requested account not found: "+query);
|
||||||
@@ -117,7 +126,7 @@ enabled(){
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.onSelectedAccountChanged = () => {
|
this.onSelectedAccountChanged = () => {
|
||||||
var selected = $(".js-account-item.is-selected", ".js-account-list");
|
let selected = $(".js-account-item.is-selected", ".js-account-list");
|
||||||
this.lastSelectedAccount = selected.length === 1 ? selected.attr("data-account-key") : null;
|
this.lastSelectedAccount = selected.length === 1 ? selected.attr("data-account-key") : null;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -32,62 +32,32 @@ enabled(){
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// setup
|
||||||
|
|
||||||
|
this.htmlModal = null;
|
||||||
|
|
||||||
|
$TDP.readFileRoot(this.$token, "modal.html").then(contents => {
|
||||||
|
this.htmlModal = contents;
|
||||||
|
}).catch(err => {
|
||||||
|
$TD.alert("error", "Problem loading data for the template plugin: "+err.message);
|
||||||
|
});
|
||||||
|
|
||||||
// button
|
// button
|
||||||
|
|
||||||
var buttonHTML = '<button class="manage-templates-btn needsclick btn btn-on-blue full-width txt-left margin-b--12 padding-v--6 padding-h--12"><i class="icon icon-bookmark"></i><span class="label padding-ls">Manage templates</span></button>';
|
let buttonHTML = '<button class="manage-templates-btn needsclick btn btn-on-blue full-width txt-left margin-b--12 padding-v--6 padding-h--12"><i class="icon icon-bookmark"></i><span class="label padding-ls">Manage templates</span></button>';
|
||||||
|
|
||||||
this.prevComposeMustache = TD.mustaches["compose/docked_compose.mustache"];
|
this.prevComposeMustache = TD.mustaches["compose/docked_compose.mustache"];
|
||||||
TD.mustaches["compose/docked_compose.mustache"] = TD.mustaches["compose/docked_compose.mustache"].replace('<div class="js-tweet-type-button">', buttonHTML+'<div class="js-tweet-type-button">');
|
window.TDPF_injectMustache("compose/docked_compose.mustache", "prepend", '<div class="js-tweet-type-button">', buttonHTML);
|
||||||
|
|
||||||
var dockedComposePanel = $(".js-docked-compose");
|
let dockedComposePanel = $(".js-docked-compose");
|
||||||
|
|
||||||
if (dockedComposePanel.length){
|
if (dockedComposePanel.length){
|
||||||
dockedComposePanel.find(".js-tweet-type-button").first().before(buttonHTML);
|
dockedComposePanel.find(".js-tweet-type-button").first().before(buttonHTML);
|
||||||
}
|
}
|
||||||
|
|
||||||
// css
|
|
||||||
|
|
||||||
this.css = window.TDPF_createCustomStyle(this);
|
|
||||||
this.css.insert(".manage-templates-btn.active { color: #fff; box-shadow: 0 0 2px 3px #50a5e6; outline: 0; }");
|
|
||||||
|
|
||||||
this.css.insert("#templates-modal-wrap { width: 100%; height: 100%; padding: 49px; position: absolute; z-index: 999; box-sizing: border-box; background-color: rgba(0, 0, 0, 0.5); }");
|
|
||||||
this.css.insert("#templates-modal { width: 100%; height: 100%; background-color: #fff; display: flex; }");
|
|
||||||
this.css.insert("#templates-modal > div { display: flex; flex-direction: column; }");
|
|
||||||
|
|
||||||
this.css.insert(".templates-modal-bottom { flex: 0 0 auto; padding: 16px; }");
|
|
||||||
this.css.insert("#template-list .templates-modal-bottom { display: flex; justify-content: space-between; }");
|
|
||||||
this.css.insert("#template-editor .templates-modal-bottom { text-align: right; }");
|
|
||||||
|
|
||||||
this.css.insert("#template-list { height: 100%; flex: 1 1 auto; }");
|
|
||||||
this.css.insert("#template-list ul { list-style-type: none; font-size: 24px; color: #222; flex: 1 1 auto; padding: 12px; overflow-y: auto; }");
|
|
||||||
this.css.insert("#template-list li { display: block; width: 100%; padding: 4px 8px; box-sizing: border-box; }");
|
|
||||||
this.css.insert("#template-list li[data-template] { cursor: pointer; }");
|
|
||||||
this.css.insert("#template-list li[data-template]:hover { background-color: #d8d8d8; }");
|
|
||||||
this.css.insert("#template-list li span { white-space: nowrap; }");
|
|
||||||
this.css.insert("#template-list li .icon { opacity: 0.6; margin-left: 4px; padding: 3px; }");
|
|
||||||
this.css.insert("#template-list li .icon:hover { opacity: 1; }");
|
|
||||||
this.css.insert("#template-list li .template-actions { float: right; }");
|
|
||||||
|
|
||||||
this.css.insert("#template-editor { height: 100%; flex: 0 0 auto; width: 25vw; min-width: 150px; max-width: 400px; background-color: #485865; }");
|
|
||||||
this.css.insert(".template-editor-form { flex: 1 1 auto; padding: 12px 16px; font-size: 14px; overflow-y: auto; }");
|
|
||||||
this.css.insert(".template-editor-form .compose-text-title { margin: 24px 0 9px; }");
|
|
||||||
this.css.insert(".template-editor-form .compose-text-title:first-child { margin-top: 0; }");
|
|
||||||
this.css.insert(".template-editor-form input, .template-editor-form textarea { color: #111; background-color: #fff; border: none; border-radius: 0; }");
|
|
||||||
this.css.insert(".template-editor-form input:focus, .template-editor-form textarea:focus { box-shadow: inset 0 1px 3px rgba(17, 17, 17, 0.1), 0 0 8px rgba(80, 165, 230, 0.6); }");
|
|
||||||
this.css.insert(".template-editor-form textarea { height: 146px; font-size: 14px; padding: 10px; resize: none; }");
|
|
||||||
this.css.insert(".template-editor-form .template-editor-tips-button { cursor: pointer; }");
|
|
||||||
this.css.insert(".template-editor-form .template-editor-tips-button .icon { font-size: 12px; vertical-align: -5%; margin-left: 4px; }");
|
|
||||||
this.css.insert(".template-editor-form .template-editor-tips { display: none; }");
|
|
||||||
this.css.insert(".template-editor-form .template-editor-tips p { margin: 10px 0; }");
|
|
||||||
this.css.insert(".template-editor-form .template-editor-tips p:first-child { margin-top: 0; }");
|
|
||||||
this.css.insert(".template-editor-form .template-editor-tips li:nth-child(2n+1) { margin-top: 5px; padding-left: 6px; font-family: monospace; }");
|
|
||||||
this.css.insert(".template-editor-form .template-editor-tips li:nth-child(2n) { margin-top: 1px; padding-left: 14px; opacity: 0.66; }");
|
|
||||||
|
|
||||||
this.css.insert(".invisible { display: none !important; }");
|
|
||||||
|
|
||||||
// template implementation
|
// template implementation
|
||||||
|
|
||||||
var readTemplateTokens = (contents, tokenData) => {
|
const readTemplateTokens = (contents, tokenData) => {
|
||||||
let startIndex = -1;
|
let startIndex = -1;
|
||||||
let endIndex = -1;
|
let endIndex = -1;
|
||||||
|
|
||||||
@@ -155,7 +125,7 @@ enabled(){
|
|||||||
return [ contents, data ];
|
return [ contents, data ];
|
||||||
};
|
};
|
||||||
|
|
||||||
var doAjaxRequest = (index, url, evaluator) => {
|
const doAjaxRequest = (index, url, evaluator) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!url){
|
if (!url){
|
||||||
resolve([ index, "{ajax}" ]);
|
resolve([ index, "{ajax}" ]);
|
||||||
@@ -175,7 +145,7 @@ enabled(){
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var useTemplate = (contents, append) => {
|
const useTemplate = (contents, append) => {
|
||||||
let ele = $(".js-compose-text");
|
let ele = $(".js-compose-text");
|
||||||
return if ele.length === 0;
|
return if ele.length === 0;
|
||||||
|
|
||||||
@@ -257,68 +227,19 @@ enabled(){
|
|||||||
|
|
||||||
this.editingTemplate = null;
|
this.editingTemplate = null;
|
||||||
|
|
||||||
var showTemplateModal = () => {
|
const showTemplateModal = () => {
|
||||||
$(".manage-templates-btn").addClass("active");
|
$(".js-app-content").prepend(this.htmlModal);
|
||||||
|
|
||||||
let html = `
|
/* TODO possibly implement this later
|
||||||
<div id="templates-modal-wrap">
|
|
||||||
<div id="templates-modal">
|
|
||||||
<div id="template-list">
|
|
||||||
<ul></ul>
|
|
||||||
|
|
||||||
<div class="templates-modal-bottom">
|
<li>{paste}</li>
|
||||||
<button data-action="close" class="btn"><i class="icon icon-close icon-small padding-rs"></i><span class="label">Close</span></button>
|
<li>Paste text or an image from clipboard</li>
|
||||||
<button data-action="new-template" class="btn btn-positive"><i class="icon icon-plus icon-small padding-rs"></i><span class="label">New Template</span></button>
|
<li>{paste#text}</li>
|
||||||
</div>
|
<li>Paste only if clipboard has text</li>
|
||||||
</div>
|
<li>{paste#image}</li>
|
||||||
|
<li>Paste only if clipboard has an image</li>
|
||||||
|
|
||||||
<div id="template-editor" class="invisible">
|
*/
|
||||||
<div class="template-editor-form">
|
|
||||||
<div class="compose-text-title">Template Name</div>
|
|
||||||
<input name="template-name" type="text">
|
|
||||||
|
|
||||||
<div class="compose-text-title">Contents</div>
|
|
||||||
<textarea name="template-contents" class="compose-text scroll-v scroll-styled-v scroll-styled-h scroll-alt"></textarea>
|
|
||||||
|
|
||||||
<div class="compose-text-title template-editor-tips-button">Advanced <i class="icon icon-arrow-d"></i></div>
|
|
||||||
<div class="template-editor-tips">
|
|
||||||
<p>You can use the following tokens. All tokens except for <span style="font-family: monospace">{ajax}</span> can only be used once.</p>
|
|
||||||
<ul>
|
|
||||||
<li>{cursor}</li>
|
|
||||||
<li>Location where the cursor is placed</li>
|
|
||||||
<li>{cursor#<selectionlength>}</li>
|
|
||||||
<li>Places cursor and selects a set amount of characters</li>
|
|
||||||
<li>{ajax#<url>}</li>
|
|
||||||
<li>Replaced with the result of a cross-origin ajax request</li>
|
|
||||||
<li>{ajax#<eval>#<url>}</li>
|
|
||||||
<li>Allows parsing the ajax request using <span style="font-family: monospace">$</span> as the placeholder for the result<br>Example: <span style="font-family: monospace">$.substring(0,5)</span></li>
|
|
||||||
</ul>
|
|
||||||
<p>To use special characters in the tweet text, escape them with a backslash:
|
|
||||||
<br><span style="font-family: monospace"> \\{ \\} \\# \\\\</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="templates-modal-bottom">
|
|
||||||
<button data-action="editor-cancel" class="btn"><i class="icon icon-close icon-small padding-rs"></i><span class="label">Cancel</span></button>
|
|
||||||
<button data-action="editor-confirm" class="btn btn-positive" style="margin-left:4px"><i class="icon icon-check icon-small padding-rs"></i><span class="label">Confirm</span></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
/* TODO possibly implement this later
|
|
||||||
|
|
||||||
<li>{paste}</li>
|
|
||||||
<li>Paste text or an image from clipboard</li>
|
|
||||||
<li>{paste#text}</li>
|
|
||||||
<li>Paste only if clipboard has text</li>
|
|
||||||
<li>{paste#image}</li>
|
|
||||||
<li>Paste only if clipboard has an image</li>
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
$(".js-app-content").prepend(html);
|
|
||||||
|
|
||||||
let ele = $("#templates-modal-wrap").first();
|
let ele = $("#templates-modal-wrap").first();
|
||||||
|
|
||||||
@@ -407,12 +328,11 @@ enabled(){
|
|||||||
onTemplatesUpdated(false);
|
onTemplatesUpdated(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
var hideTemplateModal = function(){
|
const hideTemplateModal = () => {
|
||||||
$("#templates-modal-wrap").remove();
|
$("#templates-modal-wrap").remove();
|
||||||
$(".manage-templates-btn").removeClass("active");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var toggleEditor = function(){
|
const toggleEditor = () => {
|
||||||
let editor = $("#template-editor");
|
let editor = $("#template-editor");
|
||||||
$("[name]", editor).val("");
|
$("[name]", editor).val("");
|
||||||
|
|
||||||
@@ -421,7 +341,7 @@ enabled(){
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var onTemplatesUpdated = (save) => {
|
const onTemplatesUpdated = (save) => {
|
||||||
let eles = [];
|
let eles = [];
|
||||||
|
|
||||||
for(let identifier of Object.keys(this.config.templates)){
|
for(let identifier of Object.keys(this.config.templates)){
|
||||||
@@ -468,8 +388,6 @@ ready(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
disabled(){
|
disabled(){
|
||||||
this.css.remove();
|
|
||||||
|
|
||||||
$(".manage-templates-btn").remove();
|
$(".manage-templates-btn").remove();
|
||||||
$("#templates-modal-wrap").remove();
|
$("#templates-modal-wrap").remove();
|
||||||
|
|
||||||
|
227
Resources/Plugins/templates/modal.html
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
<div id="templates-modal-wrap" class="scroll-v scroll-styled-v">
|
||||||
|
<div id="templates-modal">
|
||||||
|
<div id="template-list">
|
||||||
|
<ul></ul>
|
||||||
|
|
||||||
|
<div class="templates-modal-bottom">
|
||||||
|
<button data-action="close" class="Button--secondary"><i class="icon icon-close icon-small padding-rs"></i><span class="label">Close</span></button>
|
||||||
|
<button data-action="new-template" class="Button--primary"><i class="icon icon-plus icon-small padding-rs"></i><span class="label">New Template</span></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="template-editor" class="invisible">
|
||||||
|
<div class="template-editor-form">
|
||||||
|
<div class="compose-text-title">Template Name</div>
|
||||||
|
<input name="template-name" type="text">
|
||||||
|
|
||||||
|
<div class="compose-text-title">Contents</div>
|
||||||
|
<textarea name="template-contents" class="compose-text scroll-v scroll-styled-v scroll-styled-h scroll-alt"></textarea>
|
||||||
|
|
||||||
|
<div class="compose-text-title template-editor-tips-button">Advanced <i class="icon icon-arrow-d"></i></div>
|
||||||
|
<div class="template-editor-tips">
|
||||||
|
<p>You can use the following tokens. All tokens except for <span style="font-family: monospace">{ajax}</span> can only be used once.</p>
|
||||||
|
<ul>
|
||||||
|
<li>{cursor}</li>
|
||||||
|
<li>Location where the cursor is placed</li>
|
||||||
|
<li>{cursor#<selectionlength>}</li>
|
||||||
|
<li>Places cursor and selects a set amount of characters</li>
|
||||||
|
<li>{ajax#<url>}</li>
|
||||||
|
<li>Replaced with the result of a cross-origin ajax request</li>
|
||||||
|
<li>{ajax#<eval>#<url>}</li>
|
||||||
|
<li>Allows parsing the ajax request using <span style="font-family: monospace">$</span> as the placeholder for the result<br>Example: <span style="font-family: monospace">$.substring(0,5)</span></li>
|
||||||
|
</ul>
|
||||||
|
<p>To use special characters in the tweet text, escape them with a backslash:
|
||||||
|
<br><span style="font-family: monospace"> \{ \} \# \\</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="templates-modal-bottom">
|
||||||
|
<button data-action="editor-cancel" class="Button--secondary"><i class="icon icon-close icon-small padding-rs"></i><span class="label">Cancel</span></button>
|
||||||
|
<button data-action="editor-confirm" class="Button--primary" style="margin-left:4px"><i class="icon icon-check icon-small padding-rs"></i><span class="label">Confirm</span></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
/* General */
|
||||||
|
|
||||||
|
#templates-modal-wrap {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 49px;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 999;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
#templates-modal {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
min-width: 500px;
|
||||||
|
background-color: #fff;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#templates-modal > div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.templates-modal-bottom {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#template-list .templates-modal-bottom {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
#template-editor .templates-modal-bottom {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manage-templates-btn {
|
||||||
|
/* modifies the Manage Templates button while open */
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 0 2px 3px #50a5e6;
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Template list */
|
||||||
|
|
||||||
|
#template-list {
|
||||||
|
height: 100%;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#template-list ul {
|
||||||
|
list-style-type: none;
|
||||||
|
font-size: 24px;
|
||||||
|
color: #222;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
padding: 12px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#template-list li {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 4px 8px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
#template-list li[data-template] {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#template-list li[data-template]:hover {
|
||||||
|
background-color: #d8d8d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
#template-list li span {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
#template-list li .icon {
|
||||||
|
opacity: 0.6;
|
||||||
|
margin-left: 4px;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#template-list li .icon:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#template-list li .template-actions {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Template editor */
|
||||||
|
|
||||||
|
#template-editor {
|
||||||
|
height: 100%;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
width: 25vw;
|
||||||
|
min-width: 225px;
|
||||||
|
max-width: 400px;
|
||||||
|
background-color: #485865;
|
||||||
|
}
|
||||||
|
|
||||||
|
#template-editor.invisible {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-editor-form {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
padding: 12px 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-editor-form .compose-text-title {
|
||||||
|
margin: 24px 0 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-editor-form .compose-text-title:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-editor-form input, .template-editor-form textarea {
|
||||||
|
color: #111;
|
||||||
|
background-color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-editor-form input:focus, .template-editor-form textarea:focus {
|
||||||
|
box-shadow: inset 0 1px 3px rgba(17, 17, 17, 0.1), 0 0 8px rgba(80, 165, 230, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-editor-form textarea {
|
||||||
|
height: 146px;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 10px;
|
||||||
|
resize: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Template tips */
|
||||||
|
|
||||||
|
.template-editor-form .template-editor-tips-button {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-editor-form .template-editor-tips-button .icon {
|
||||||
|
font-size: 12px;
|
||||||
|
vertical-align: -5%;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-editor-form .template-editor-tips {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-editor-form .template-editor-tips p {
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-editor-form .template-editor-tips p:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-editor-form .template-editor-tips li:nth-child(2n+1) {
|
||||||
|
margin-top: 5px;
|
||||||
|
padding-left: 6px;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-editor-form .template-editor-tips li:nth-child(2n) {
|
||||||
|
margin-top: 1px;
|
||||||
|
padding-left: 14px;
|
||||||
|
opacity: 0.66;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</div>
|
@@ -38,7 +38,7 @@ enabled(){
|
|||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
|
|
||||||
var funcs = {
|
const funcs = {
|
||||||
TwitterStatus: TD.services.TwitterStatus.prototype.render,
|
TwitterStatus: TD.services.TwitterStatus.prototype.render,
|
||||||
TwitterActionOnTweet: TD.services.TwitterActionOnTweet.prototype.render,
|
TwitterActionOnTweet: TD.services.TwitterActionOnTweet.prototype.render,
|
||||||
TweetDetailView: TD.components.TweetDetailView.prototype._renderChirp
|
TweetDetailView: TD.components.TweetDetailView.prototype._renderChirp
|
||||||
|
@@ -9,14 +9,13 @@ $ErrorActionPreference = "Stop"
|
|||||||
|
|
||||||
try{
|
try{
|
||||||
$sw = [Diagnostics.Stopwatch]::StartNew()
|
$sw = [Diagnostics.Stopwatch]::StartNew()
|
||||||
Write-Host "--------------------------"
|
|
||||||
|
|
||||||
if ($version.Equals("")){
|
if ($version.Equals("")){
|
||||||
$version = (Get-Item (Join-Path $targetDir "TweetDuck.exe")).VersionInfo.FileVersion
|
$version = (Get-Item (Join-Path $targetDir "TweetDuck.exe")).VersionInfo.FileVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Write-Host "--------------------------"
|
||||||
Write-Host "TweetDuck version" $version
|
Write-Host "TweetDuck version" $version
|
||||||
|
|
||||||
Write-Host "--------------------------"
|
Write-Host "--------------------------"
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
@@ -27,8 +26,7 @@ try{
|
|||||||
|
|
||||||
# Copy resources
|
# Copy resources
|
||||||
|
|
||||||
Copy-Item (Join-Path $projectDir "bld\Resources\CEFSHARP-LICENSE.txt") -Destination $targetDir -Force
|
Copy-Item (Join-Path $projectDir "bld\Resources\LICENSES.txt") -Destination $targetDir -Force
|
||||||
Copy-Item (Join-Path $projectDir "LICENSE.md") -Destination (Join-Path $targetDir "LICENSE.txt") -Force
|
|
||||||
|
|
||||||
New-Item -ItemType directory -Path $targetDir -Name "scripts" | Out-Null
|
New-Item -ItemType directory -Path $targetDir -Name "scripts" | Out-Null
|
||||||
New-Item -ItemType directory -Path $targetDir -Name "plugins" | Out-Null
|
New-Item -ItemType directory -Path $targetDir -Name "plugins" | Out-Null
|
||||||
@@ -45,76 +43,122 @@ try{
|
|||||||
|
|
||||||
# Helper functions
|
# Helper functions
|
||||||
|
|
||||||
function Check-Carriage-Return{
|
function Remove-Empty-Lines{
|
||||||
Param(
|
Param([Parameter(Mandatory = $True, Position = 1)] $lines)
|
||||||
[Parameter(Mandatory = $True, Position = 1)] $fname
|
|
||||||
)
|
|
||||||
|
|
||||||
$file = @(Get-ChildItem -Path $targetDir -Include $fname -Recurse)[0]
|
foreach($line in $lines){
|
||||||
|
if ($line -ne ''){
|
||||||
if ((Get-Content -Path $file.FullName -Raw).Contains("`r")){
|
$line
|
||||||
Throw "$fname cannot contain carriage return"
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Host "Verified" $file.FullName.Substring($targetDir.Length)
|
function Check-Carriage-Return{
|
||||||
|
Param([Parameter(Mandatory = $True, Position = 1)] $file)
|
||||||
|
|
||||||
|
if (!(Test-Path $file)){
|
||||||
|
Throw "$file does not exist"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Get-Content -Path $file -Raw).Contains("`r")){
|
||||||
|
Throw "$file must not have any carriage return characters"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Verified" $file.Substring($targetDir.Length)
|
||||||
}
|
}
|
||||||
|
|
||||||
function Rewrite-File{
|
function Rewrite-File{
|
||||||
[CmdletBinding()]
|
Param([Parameter(Mandatory = $True, Position = 1)] $file,
|
||||||
Param(
|
[Parameter(Mandatory = $True, Position = 2)] $lines,
|
||||||
[Parameter(Mandatory = $True, Position = 1)] $file,
|
[Parameter(Mandatory = $True, Position = 3)] $imports)
|
||||||
[Parameter(Mandatory = $True, Position = 2)] $lines
|
|
||||||
)
|
|
||||||
|
|
||||||
|
$lines = Remove-Empty-Lines($lines)
|
||||||
$relativePath = $file.FullName.Substring($targetDir.Length)
|
$relativePath = $file.FullName.Substring($targetDir.Length)
|
||||||
|
|
||||||
|
foreach($line in $lines){
|
||||||
|
if ($line.Contains('#import ')){
|
||||||
|
$imports.Add($file.FullName)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($relativePath.StartsWith("scripts\")){
|
if ($relativePath.StartsWith("scripts\")){
|
||||||
$lines = (,("#" + $version) + $lines)
|
$lines = (,("#" + $version) + $lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
$lines = $lines | Where { $_ -ne '' }
|
|
||||||
|
|
||||||
[IO.File]::WriteAllLines($file.FullName, $lines)
|
[IO.File]::WriteAllLines($file.FullName, $lines)
|
||||||
Write-Host "Processed" $relativePath
|
Write-Host "Processed" $relativePath
|
||||||
}
|
}
|
||||||
|
|
||||||
# Post processing
|
# Validation
|
||||||
|
|
||||||
Check-Carriage-Return("emoji-ordering.txt")
|
Check-Carriage-Return(Join-Path $targetDir "plugins\official\emoji-keyboard\emoji-ordering.txt")
|
||||||
|
|
||||||
ForEach($file in Get-ChildItem -Path $targetDir -Filter "*.js" -Exclude "configuration.default.js" -Recurse){
|
# Processing
|
||||||
|
|
||||||
|
$imports = New-Object "System.Collections.Generic.List[string]"
|
||||||
|
|
||||||
|
foreach($file in Get-ChildItem -Path $targetDir -Filter "*.js" -Exclude "configuration.default.js" -Recurse){
|
||||||
$lines = [IO.File]::ReadLines($file.FullName)
|
$lines = [IO.File]::ReadLines($file.FullName)
|
||||||
$lines = $lines | % { $_.TrimStart() }
|
$lines = $lines | ForEach-Object { $_.TrimStart() }
|
||||||
$lines = $lines -Replace '^(.*?)((?<=^|[;{}()])\s?//(?:\s.*|$))?$', '$1'
|
$lines = $lines -Replace '^(.*?)((?<=^|[;{}()])\s?//(?:\s.*|$))?$', '$1'
|
||||||
$lines = $lines -Replace '(?<!\w)return(\s.*?)? if (.*?);', 'if ($2)return$1;'
|
$lines = $lines -Replace '(?<!\w)(return|throw)(\s.*?)? if (.*?);', 'if ($3)$1$2;'
|
||||||
Rewrite-File $file $lines
|
Rewrite-File $file $lines $imports
|
||||||
}
|
}
|
||||||
|
|
||||||
ForEach($file in Get-ChildItem -Path $targetDir -Filter "*.css" -Recurse){
|
foreach($file in Get-ChildItem -Path $targetDir -Filter "*.css" -Recurse){
|
||||||
$lines = [IO.File]::ReadLines($file.FullName)
|
$lines = [IO.File]::ReadLines($file.FullName)
|
||||||
$lines = $lines -Replace '\s*/\*.*?\*/', ''
|
$lines = $lines -Replace '\s*/\*.*?\*/', ''
|
||||||
$lines = $lines -Replace '^\s+(.+):\s?(.+?)(?:\s?(!important))?;$', '$1:$2$3;'
|
$lines = $lines -Replace '^(\S.*) {$', '$1{'
|
||||||
$lines = $lines -Replace '^(\S.*?) {$', '$1{'
|
$lines = $lines -Replace '^\s+(.+?):\s*(.+?)(?:\s*(!important))?;$', '$1:$2$3;'
|
||||||
$lines = @(($lines | Where { $_ -ne '' }) -Join ' ')
|
$lines = @((Remove-Empty-Lines($lines)) -Join ' ')
|
||||||
Rewrite-File $file $lines
|
$lines = $lines -Replace '([{};])\s', '$1'
|
||||||
|
$lines = $lines -Replace ';}', '}'
|
||||||
|
Rewrite-File $file $lines $imports
|
||||||
}
|
}
|
||||||
|
|
||||||
ForEach($file in Get-ChildItem -Path $targetDir -Filter "*.html" -Recurse){
|
foreach($file in Get-ChildItem -Path $targetDir -Filter "*.html" -Recurse){
|
||||||
$lines = [IO.File]::ReadLines($file.FullName)
|
$lines = [IO.File]::ReadLines($file.FullName)
|
||||||
$lines = $lines | % { $_.TrimStart() }
|
$lines = $lines | ForEach-Object { $_.TrimStart() }
|
||||||
Rewrite-File $file $lines
|
Rewrite-File $file $lines $imports
|
||||||
}
|
}
|
||||||
|
|
||||||
ForEach($file in Get-ChildItem -Path (Join-Path $targetDir "plugins") -Filter "*.meta" -Recurse){
|
foreach($file in Get-ChildItem -Path (Join-Path $targetDir "plugins") -Filter "*.meta" -Recurse){
|
||||||
$lines = [IO.File]::ReadLines($file.FullName)
|
$lines = [IO.File]::ReadLines($file.FullName)
|
||||||
$lines = $lines -Replace '\{version\}', $version
|
$lines = $lines -Replace '\{version\}', $version
|
||||||
Rewrite-File $file $lines
|
Rewrite-File $file $lines $imports
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Host "------------------"
|
# Imports
|
||||||
|
|
||||||
|
$importFolder = Join-Path $targetDir "scripts\imports"
|
||||||
|
|
||||||
|
foreach($path in $imports){
|
||||||
|
$text = [IO.File]::ReadAllText($path)
|
||||||
|
$text = [Regex]::Replace($text, '#import "(.*?)"', {
|
||||||
|
$importPath = Join-Path $importFolder ($args[0].Groups[1].Value.Trim())
|
||||||
|
$importStr = [IO.File]::ReadAllText($importPath).TrimEnd()
|
||||||
|
|
||||||
|
if ($importStr[0] -eq '#'){
|
||||||
|
$importStr = $importStr.Substring($importStr.IndexOf("`n") + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return $importStr
|
||||||
|
}, [System.Text.RegularExpressions.RegexOptions]::MultiLine)
|
||||||
|
|
||||||
|
[IO.File]::WriteAllText($path, $text)
|
||||||
|
Write-Host "Resolved" $path.Substring($targetDir.Length)
|
||||||
|
}
|
||||||
|
|
||||||
|
[IO.Directory]::Delete($importFolder, $True)
|
||||||
|
|
||||||
|
# Finished
|
||||||
|
|
||||||
$sw.Stop()
|
$sw.Stop()
|
||||||
|
Write-Host "------------------"
|
||||||
Write-Host "Finished in" $([math]::Round($sw.Elapsed.TotalMilliseconds)) "ms"
|
Write-Host "Finished in" $([math]::Round($sw.Elapsed.TotalMilliseconds)) "ms"
|
||||||
Write-Host ------------------
|
Write-Host "------------------"
|
||||||
|
|
||||||
}catch{
|
}catch{
|
||||||
Write-Host "Encountered an error while running PostBuild.ps1 on line" $_.InvocationInfo.ScriptLineNumber
|
Write-Host "Encountered an error while running PostBuild.ps1 on line" $_.InvocationInfo.ScriptLineNumber
|
||||||
Write-Host $_
|
Write-Host $_
|
||||||
|
60
Resources/PostCefUpdate.ps1
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
try{
|
||||||
|
$mainProj = "..\TweetDuck.csproj"
|
||||||
|
$browserProj = "..\subprocess\TweetDuck.Browser.csproj"
|
||||||
|
|
||||||
|
$cefMatch = Select-String -Path $mainProj '<Import Project="packages\\cef\.redist\.x86\.(.*?)\\'
|
||||||
|
$cefVersion = $cefMatch.Matches[0].Groups[1].Value
|
||||||
|
|
||||||
|
$sharpMatch = Select-String -Path $mainProj '<Import Project="packages\\CefSharp\.Common\.(.*?)\\'
|
||||||
|
$sharpVersion = $sharpMatch.Matches[0].Groups[1].Value
|
||||||
|
|
||||||
|
$propsFiles = "..\packages\CefSharp.Common.${sharpVersion}\build\CefSharp.Common.props",
|
||||||
|
"..\packages\CefSharp.WinForms.${sharpVersion}\build\CefSharp.WinForms.props"
|
||||||
|
|
||||||
|
# Greetings
|
||||||
|
|
||||||
|
$title = "CEF ${cefVersion}, CefSharp ${sharpVersion}"
|
||||||
|
|
||||||
|
Write-Host ("-" * $title.Length)
|
||||||
|
Write-Host $title
|
||||||
|
Write-Host ("-" * $title.Length)
|
||||||
|
|
||||||
|
# Perform update
|
||||||
|
|
||||||
|
Write-Host "Copying dev tools to repository..."
|
||||||
|
|
||||||
|
Copy-Item "..\packages\cef.redist.x86.${cefVersion}\CEF\devtools_resources.pak" -Destination "..\bld\Resources\" -Force
|
||||||
|
|
||||||
|
Write-Host "Updating browser subprocess reference..."
|
||||||
|
|
||||||
|
$contents = [IO.File]::ReadAllText($browserProj)
|
||||||
|
$contents = $contents -Replace '(?<=<HintPath>\.\.\\packages\\CefSharp\.Common\.)(.*?)(?=\\)', $sharpVersion
|
||||||
|
$contents = $contents -Replace '(?<=<Reference Include="CefSharp\.BrowserSubprocess\.Core, Version=)(\d+)', $sharpVersion.Split(".")[0]
|
||||||
|
|
||||||
|
[IO.File]::WriteAllText($browserProj, $contents)
|
||||||
|
|
||||||
|
Write-Host "Removing x64 and AnyCPU from CefSharp props..."
|
||||||
|
|
||||||
|
foreach($file in $propsFiles){
|
||||||
|
$contents = [IO.File]::ReadAllText($file)
|
||||||
|
$contents = $contents -Replace '(?<=<When Condition=")(''\$\(Platform\)'' == ''(AnyCPU|x64)'')(?=">)', 'false'
|
||||||
|
|
||||||
|
[IO.File]::WriteAllText($file, $contents)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Finished
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Finished. Exiting in 6 seconds..."
|
||||||
|
Start-Sleep -Seconds 6
|
||||||
|
|
||||||
|
}catch{
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Encountered an error while running PostBuild.ps1 on line" $_.InvocationInfo.ScriptLineNumber
|
||||||
|
Write-Host $_
|
||||||
|
|
||||||
|
$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||||
|
Exit 1
|
||||||
|
}
|
@@ -1,10 +1,12 @@
|
|||||||
using CefSharp;
|
using CefSharp;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Core.Controls;
|
using TweetDuck.Core.Controls;
|
||||||
using TweetDuck.Core.Other;
|
using TweetDuck.Core.Other;
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@@ -14,8 +16,17 @@ using TweetDuck.Plugins;
|
|||||||
|
|
||||||
namespace TweetDuck.Resources{
|
namespace TweetDuck.Resources{
|
||||||
static class ScriptLoader{
|
static class ScriptLoader{
|
||||||
public static string LoadResource(string name, bool silent = false, Control sync = null){
|
private static readonly Dictionary<string, string> CachedData = new Dictionary<string, string>(16);
|
||||||
try{
|
|
||||||
|
public static string LoadResourceSilent(string name){
|
||||||
|
return LoadResource(name, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string LoadResource(string name, Control sync){
|
||||||
|
if (CachedData.TryGetValue(name, out string resourceData)){
|
||||||
|
return resourceData;
|
||||||
|
}
|
||||||
|
|
||||||
string path = Program.ScriptPath;
|
string path = Program.ScriptPath;
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
@@ -25,6 +36,9 @@ namespace TweetDuck.Resources{
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
string resource;
|
||||||
|
|
||||||
|
try{
|
||||||
string contents = File.ReadAllText(Path.Combine(path, name), Encoding.UTF8);
|
string contents = File.ReadAllText(Path.Combine(path, name), Encoding.UTF8);
|
||||||
int separator;
|
int separator;
|
||||||
|
|
||||||
@@ -33,7 +47,7 @@ namespace TweetDuck.Resources{
|
|||||||
// #<version>\n
|
// #<version>\n
|
||||||
|
|
||||||
if (contents[0] != '#'){
|
if (contents[0] != '#'){
|
||||||
ShowLoadError(silent, sync, $"File {name} appears to be corrupted, please try reinstalling the app.");
|
ShowLoadError(sync, $"File {name} appears to be corrupted, please try reinstalling the app.");
|
||||||
separator = 0;
|
separator = 0;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
@@ -41,44 +55,33 @@ namespace TweetDuck.Resources{
|
|||||||
string fileVersion = contents.Substring(1, separator-1).TrimEnd();
|
string fileVersion = contents.Substring(1, separator-1).TrimEnd();
|
||||||
|
|
||||||
if (fileVersion != Program.VersionTag){
|
if (fileVersion != Program.VersionTag){
|
||||||
ShowLoadError(silent, sync, $"File {name} is made for a different version of TweetDuck ({fileVersion}) and may not function correctly in this version, please try reinstalling the app.");
|
ShowLoadError(sync, $"File {name} is made for a different version of TweetDuck ({fileVersion}) and may not function correctly in this version, please try reinstalling the app.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return contents.Substring(separator).TrimStart();
|
resource = contents.Substring(separator).TrimStart();
|
||||||
}catch(Exception ex){
|
}catch(Exception ex){
|
||||||
ShowLoadError(silent, sync, $"Could not load {name}. The program will continue running with limited functionality.\n\n{ex.Message}");
|
ShowLoadError(sync, $"Could not load {name}. The program will continue running with limited functionality.\n\n{ex.Message}");
|
||||||
return null;
|
resource = null;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool ExecuteFile(IFrame frame, string file, Control sync = null){
|
return CachedData[name] = resource;
|
||||||
string script = LoadResource(file, sync == null, sync);
|
}
|
||||||
ExecuteScript(frame, script, GetRootIdentifier(file));
|
|
||||||
|
public static bool ExecuteFile(IFrame frame, string file, Control sync){
|
||||||
|
string script = LoadResource(file, sync);
|
||||||
|
ExecuteScript(frame, script, "root:"+Path.GetFileNameWithoutExtension(file));
|
||||||
return script != null;
|
return script != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ExecuteScript(IFrame frame, string script, string identifier){
|
public static void ExecuteScript(IFrame frame, string script, string identifier){
|
||||||
if (script != null){
|
if (script != null){
|
||||||
frame.ExecuteJavaScriptAsync(script, "td:"+identifier, 1);
|
frame.ExecuteJavaScriptAsync(script, identifier, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetRootIdentifier(string file){
|
private static void ShowLoadError(Control sync, string message){
|
||||||
return "root:"+Path.GetFileNameWithoutExtension(file);
|
sync?.InvokeSafe(() => FormMessage.Error("Resource Error", message, FormMessage.OK));
|
||||||
}
|
|
||||||
|
|
||||||
private static void ShowLoadError(bool silent, Control sync, string message){
|
|
||||||
if (silent){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sync == null){
|
|
||||||
FormMessage.Error("Resource Error", message, FormMessage.OK);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
sync.InvokeSafe(() => FormMessage.Error("Resource Error", message, FormMessage.OK));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
@@ -88,7 +91,7 @@ namespace TweetDuck.Resources{
|
|||||||
|
|
||||||
static ScriptLoader(){
|
static ScriptLoader(){
|
||||||
if (File.Exists(HotSwapRebuildScript)){
|
if (File.Exists(HotSwapRebuildScript)){
|
||||||
Debug.WriteLine("Activating resource hot swap");
|
Debug.WriteLine("Activating resource hot swap...");
|
||||||
|
|
||||||
ResetHotSwap();
|
ResetHotSwap();
|
||||||
Application.ApplicationExit += (sender, args) => ResetHotSwap();
|
Application.ApplicationExit += (sender, args) => ResetHotSwap();
|
||||||
@@ -104,6 +107,8 @@ namespace TweetDuck.Resources{
|
|||||||
ResetHotSwap();
|
ResetHotSwap();
|
||||||
Directory.CreateDirectory(HotSwapTargetDir);
|
Directory.CreateDirectory(HotSwapTargetDir);
|
||||||
|
|
||||||
|
Stopwatch sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
using(Process process = Process.Start(new ProcessStartInfo{
|
using(Process process = Process.Start(new ProcessStartInfo{
|
||||||
FileName = "powershell",
|
FileName = "powershell",
|
||||||
Arguments = $"-ExecutionPolicy Unrestricted -File \"{HotSwapRebuildScript}\" \"{HotSwapTargetDir}\\\" \"{HotSwapProjectRoot}\\\" \"Debug\" \"{Program.VersionTag}\"",
|
Arguments = $"-ExecutionPolicy Unrestricted -File \"{HotSwapRebuildScript}\" \"{HotSwapTargetDir}\\\" \"{HotSwapProjectRoot}\\\" \"Debug\" \"{Program.VersionTag}\"",
|
||||||
@@ -120,20 +125,21 @@ namespace TweetDuck.Resources{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sw.Stop();
|
||||||
|
Debug.WriteLine("Finished rebuild script in "+sw.ElapsedMilliseconds+" ms");
|
||||||
|
|
||||||
|
CachedData.Clear();
|
||||||
|
|
||||||
// Force update plugin manager setup scripts
|
// Force update plugin manager setup scripts
|
||||||
|
|
||||||
string newPluginRoot = Path.Combine(HotSwapTargetDir, "plugins");
|
string newPluginRoot = Path.Combine(HotSwapTargetDir, "plugins");
|
||||||
|
|
||||||
const BindingFlags flagsInstance = BindingFlags.Instance | BindingFlags.NonPublic;
|
const BindingFlags flagsInstance = BindingFlags.Instance | BindingFlags.NonPublic;
|
||||||
const BindingFlags flagsStatic = BindingFlags.Static | BindingFlags.NonPublic;
|
|
||||||
|
|
||||||
Type typePluginManager = typeof(PluginManager);
|
Type typePluginManager = typeof(PluginManager);
|
||||||
Type typeFormBrowser = typeof(FormBrowser);
|
Type typeFormBrowser = typeof(FormBrowser);
|
||||||
|
|
||||||
// ReSharper disable PossibleNullReferenceException
|
// ReSharper disable PossibleNullReferenceException
|
||||||
object pluginSetupScripts = typePluginManager.GetMethod("LoadSetupScripts", flagsStatic).Invoke(null, new object[0]);
|
|
||||||
typePluginManager.GetField("PluginSetupScripts", flagsStatic).SetValue(null, pluginSetupScripts);
|
|
||||||
|
|
||||||
object instPluginManager = typeFormBrowser.GetField("plugins", flagsInstance).GetValue(FormManager.TryFind<FormBrowser>());
|
object instPluginManager = typeFormBrowser.GetField("plugins", flagsInstance).GetValue(FormManager.TryFind<FormBrowser>());
|
||||||
typePluginManager.GetField("rootPath", flagsInstance).SetValue(instPluginManager, newPluginRoot);
|
typePluginManager.GetField("rootPath", flagsInstance).SetValue(instPluginManager, newPluginRoot);
|
||||||
|
|
||||||
|
@@ -1,18 +1,18 @@
|
|||||||
(function($, $TD, $TDX, TD){
|
(function($TD, $TDX, $, TD){
|
||||||
//
|
//
|
||||||
// Variable: Current highlighted column jQuery & data objects.
|
// Variable: Current highlighted column jQuery & data objects.
|
||||||
//
|
//
|
||||||
var highlightedColumnEle, highlightedColumnObj;
|
let highlightedColumnEle, highlightedColumnObj;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Variable: Currently highlighted tweet jQuery & data objects.
|
// Variable: Currently highlighted tweet jQuery & data objects.
|
||||||
//
|
//
|
||||||
var highlightedTweetEle, highlightedTweetObj;
|
let highlightedTweetEle, highlightedTweetObj;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Variable: Array of functions called after the website app is loaded.
|
// Variable: Array of functions called after the website app is loaded.
|
||||||
//
|
//
|
||||||
var onAppReady = [];
|
let onAppReady = [];
|
||||||
|
|
||||||
//
|
//
|
||||||
// Variable: DOM HTML element.
|
// Variable: DOM HTML element.
|
||||||
@@ -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,36 @@
|
|||||||
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: Executes a function inside a try-catch to stop it from crashing everything.
|
||||||
|
//
|
||||||
|
const execSafe = function(func, fail){
|
||||||
|
try{
|
||||||
|
func();
|
||||||
|
}catch(err){
|
||||||
|
console.error(err);
|
||||||
|
|
||||||
|
debugger;
|
||||||
|
$TD.crashDebug("Caught error in function "+func.name)
|
||||||
|
|
||||||
|
fail && fail();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Function: Retrieves a property of an element with a specified class.
|
// Function: Retrieves a property of an element with a specified class.
|
||||||
//
|
//
|
||||||
@@ -98,6 +129,7 @@
|
|||||||
//
|
//
|
||||||
// Block: Fix columns missing any identifiable attributes to allow individual styles.
|
// Block: Fix columns missing any identifiable attributes to allow individual styles.
|
||||||
//
|
//
|
||||||
|
execSafe(function setupColumnAttrIdentifiers(){
|
||||||
$(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;
|
||||||
@@ -108,6 +140,7 @@
|
|||||||
data.$column.attr("data-td-icon", name);
|
data.$column.attr("data-td-icon", name);
|
||||||
data.column._tduck_icon = name;
|
data.column._tduck_icon = name;
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Setup global function to retrieve the column name.
|
// Block: Setup global function to retrieve the column name.
|
||||||
@@ -124,17 +157,17 @@
|
|||||||
let recentTweets = new Set();
|
let recentTweets = new Set();
|
||||||
let recentTweetTimer = null;
|
let recentTweetTimer = null;
|
||||||
|
|
||||||
let resetRecentTweets = () => {
|
const resetRecentTweets = () => {
|
||||||
recentTweetTimer = null;
|
recentTweetTimer = null;
|
||||||
recentTweets.clear();
|
recentTweets.clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
let startRecentTweetTimer = () => {
|
const startRecentTweetTimer = () => {
|
||||||
recentTweetTimer && window.clearTimeout(recentTweetTimer);
|
recentTweetTimer && window.clearTimeout(recentTweetTimer);
|
||||||
recentTweetTimer = window.setTimeout(resetRecentTweets, 20000);
|
recentTweetTimer = window.setTimeout(resetRecentTweets, 20000);
|
||||||
};
|
};
|
||||||
|
|
||||||
let checkTweetCache = (set, id) => {
|
const checkTweetCache = (set, id) => {
|
||||||
return true if set.has(id);
|
return true if set.has(id);
|
||||||
|
|
||||||
if (set.size > 50){
|
if (set.size > 50){
|
||||||
@@ -145,8 +178,21 @@
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
let fixMedia = (html, media) => {
|
const isSensitive = (tweet) => {
|
||||||
return html.find(".js-media a[data-media-entity-id='"+media.mediaId+"']").css("background-image", 'url("'+media.small()+'")').removeClass("is-zoomable");
|
let main = tweet.getMainTweet && tweet.getMainTweet();
|
||||||
|
return true if main && main.possiblySensitive; // TODO these don't show media badges when hiding sensitive media
|
||||||
|
|
||||||
|
let related = tweet.getRelatedTweet && tweet.getRelatedTweet();
|
||||||
|
return true if related && related.possiblySensitive;
|
||||||
|
|
||||||
|
let quoted = tweet.quotedTweet;
|
||||||
|
return true if quoted && quoted.possiblySensitive;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fixMedia = (html, media) => {
|
||||||
|
return html.find("a[data-media-entity-id='"+media.mediaId+"'], .media-item").first().removeClass("is-zoomable").css("background-image", 'url("'+media.small()+'")');
|
||||||
};
|
};
|
||||||
|
|
||||||
return function(column, tweet){
|
return function(column, tweet){
|
||||||
@@ -160,7 +206,7 @@
|
|||||||
startRecentTweetTimer();
|
startRecentTweetTimer();
|
||||||
|
|
||||||
if (column.model.getHasNotification()){
|
if (column.model.getHasNotification()){
|
||||||
let sensitive = (tweet.getRelatedTweet() && tweet.getRelatedTweet().possiblySensitive || (tweet.quotedTweet && tweet.quotedTweet.possiblySensitive));
|
let sensitive = isSensitive(tweet);
|
||||||
let previews = $TDX.notificationMediaPreviews && (!sensitive || TD.settings.getDisplaySensitiveMedia());
|
let previews = $TDX.notificationMediaPreviews && (!sensitive || TD.settings.getDisplaySensitiveMedia());
|
||||||
|
|
||||||
let html = $(tweet.render({
|
let html = $(tweet.render({
|
||||||
@@ -172,7 +218,8 @@
|
|||||||
isMediaPreviewLarge: false,
|
isMediaPreviewLarge: false,
|
||||||
isMediaPreviewCompact: false,
|
isMediaPreviewCompact: false,
|
||||||
isMediaPreviewInQuoted: previews,
|
isMediaPreviewInQuoted: previews,
|
||||||
thumbSizeClass: "media-size-medium"
|
thumbSizeClass: "media-size-medium",
|
||||||
|
mediaPreviewSize: "medium"
|
||||||
}));
|
}));
|
||||||
|
|
||||||
html.find("footer").last().remove(); // apparently withTweetActions breaks for certain tweets, nice
|
html.find("footer").last().remove(); // apparently withTweetActions breaks for certain tweets, nice
|
||||||
@@ -181,13 +228,15 @@
|
|||||||
if (previews){
|
if (previews){
|
||||||
html.find(".reverse-image-search").remove();
|
html.find(".reverse-image-search").remove();
|
||||||
|
|
||||||
|
let container = html.find(".js-media");
|
||||||
|
|
||||||
for(let media of tweet.getMedia()){
|
for(let media of tweet.getMedia()){
|
||||||
fixMedia(html, media);
|
fixMedia(container, media);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tweet.quotedTweet){
|
if (tweet.quotedTweet){
|
||||||
for(let media of tweet.quotedTweet.getMedia()){
|
for(let media of tweet.quotedTweet.getMedia()){
|
||||||
fixMedia(html, media).addClass("media-size-medium");
|
fixMedia(container, media).addClass("media-size-medium");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -195,6 +244,10 @@
|
|||||||
html.find(".js-media").remove();
|
html.find(".js-media").remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html.find("a[data-full-url]").each(function(){ // bypass t.co on all links
|
||||||
|
this.href = this.getAttribute("data-full-url");
|
||||||
|
});
|
||||||
|
|
||||||
html.find("a[href='#']").each(function(){ // remove <a> tags around links that don't lead anywhere (such as account names the tweet replied to)
|
html.find("a[href='#']").each(function(){ // remove <a> tags around links that don't lead anywhere (such as account names the tweet replied to)
|
||||||
this.outerHTML = this.innerHTML;
|
this.outerHTML = this.innerHTML;
|
||||||
});
|
});
|
||||||
@@ -211,6 +264,12 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (tweet.quotedTweet){
|
||||||
|
html.find("p.txt-mute").filter(function(){
|
||||||
|
return $(this).text() === "Show this thread";
|
||||||
|
}).first().remove();
|
||||||
|
}
|
||||||
|
|
||||||
let type = tweet.getChirpType();
|
let type = tweet.getChirpType();
|
||||||
|
|
||||||
if (type === "follow"){
|
if (type === "follow"){
|
||||||
@@ -250,7 +309,12 @@
|
|||||||
//
|
//
|
||||||
// Function: Shows tweet detail, used in notification context menu.
|
// Function: Shows tweet detail, used in notification context menu.
|
||||||
//
|
//
|
||||||
(function(){
|
execSafe(function setupShowTweetDetail(){
|
||||||
|
throw 1 if !ensurePropertyExists(TD, "ui", "updates", "showDetailView");
|
||||||
|
throw 2 if !ensurePropertyExists(TD, "controller", "columnManager", "showColumn");
|
||||||
|
throw 3 if !ensurePropertyExists(TD, "controller", "columnManager", "getByApiid");
|
||||||
|
throw 4 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);
|
||||||
@@ -292,12 +356,21 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
}, function(){
|
||||||
|
window.TDGF_showTweetDetail = function(){
|
||||||
|
alert("error|This feature is not available due to an internal error.");
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Hook into settings object to detect when the settings change, and update html attributes and notification layout.
|
// Block: Hook into settings object to detect when the settings change, and update html attributes and notification layout.
|
||||||
//
|
//
|
||||||
(function(){
|
execSafe(function hookTweetDeckSettings(){
|
||||||
|
throw 1 if !ensurePropertyExists(TD, "settings", "getFontSize");
|
||||||
|
throw 2 if !ensurePropertyExists(TD, "settings", "setFontSize");
|
||||||
|
throw 3 if !ensurePropertyExists(TD, "settings", "getTheme");
|
||||||
|
throw 4 if !ensurePropertyExists(TD, "settings", "setTheme");
|
||||||
|
|
||||||
const refreshSettings = function(){
|
const refreshSettings = function(){
|
||||||
let fontSizeName = TD.settings.getFontSize();
|
let fontSizeName = TD.settings.getFontSize();
|
||||||
let themeName = TD.settings.getTheme();
|
let themeName = TD.settings.getTheme();
|
||||||
@@ -328,7 +401,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
onAppReady.push(refreshSettings);
|
onAppReady.push(refreshSettings);
|
||||||
})();
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Fix OS name and add ID to the document for priority CSS selectors.
|
// Block: Fix OS name and add ID to the document for priority CSS selectors.
|
||||||
@@ -347,7 +420,9 @@
|
|||||||
//
|
//
|
||||||
// Block: Enable popup notifications.
|
// Block: Enable popup notifications.
|
||||||
//
|
//
|
||||||
if (ensurePropertyExists(TD, "controller", "notifications")){
|
execSafe(function hookDesktopNotifications(){
|
||||||
|
throw 1 if !ensurePropertyExists(TD, "controller", "notifications");
|
||||||
|
|
||||||
TD.controller.notifications.hasNotifications = function(){
|
TD.controller.notifications.hasNotifications = function(){
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@@ -355,19 +430,19 @@
|
|||||||
TD.controller.notifications.isPermissionGranted = function(){
|
TD.controller.notifications.isPermissionGranted = function(){
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
$.subscribe("/notifications/new", function(obj){
|
$.subscribe("/notifications/new", function(obj){
|
||||||
for(let index = obj.items.length-1; index >= 0; index--){
|
for(let index = obj.items.length-1; index >= 0; index--){
|
||||||
onNewTweet(obj.column, obj.items[index]);
|
onNewTweet(obj.column, obj.items[index]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Add TweetDuck buttons to the settings menu.
|
// Block: Add TweetDuck buttons to the settings menu.
|
||||||
//
|
//
|
||||||
onAppReady.push(function(){
|
onAppReady.push(function setupSettingsDropdown(){
|
||||||
$("[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;
|
||||||
@@ -391,9 +466,9 @@
|
|||||||
//
|
//
|
||||||
// Block: Expand shortened links on hover or display tooltip.
|
// Block: Expand shortened links on hover or display tooltip.
|
||||||
//
|
//
|
||||||
(function(){
|
execSafe(function setupLinkExpansionOrTooltip(){
|
||||||
var prevMouseX = -1, prevMouseY = -1;
|
let prevMouseX = -1, prevMouseY = -1;
|
||||||
var tooltipTimer, tooltipDisplayed;
|
let tooltipTimer, tooltipDisplayed;
|
||||||
|
|
||||||
$(document.body).delegate("a[data-full-url]", {
|
$(document.body).delegate("a[data-full-url]", {
|
||||||
mouseenter: function(){
|
mouseenter: function(){
|
||||||
@@ -438,11 +513,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})();
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Bypass t.co when clicking/dragging links and media.
|
// Block: Bypass t.co when clicking/dragging links and media.
|
||||||
//
|
//
|
||||||
|
execSafe(function setupShortenerBypass(){
|
||||||
$(document.body).delegate("a[data-full-url]", "click auxclick", function(e){
|
$(document.body).delegate("a[data-full-url]", "click auxclick", function(e){
|
||||||
if (e.button === 0 || e.button === 1){ // event.which seems to be borked in auxclick
|
if (e.button === 0 || e.button === 1){ // event.which seems to be borked in auxclick
|
||||||
$TD.openBrowser($(this).attr("data-full-url"));
|
$TD.openBrowser($(this).attr("data-full-url"));
|
||||||
@@ -478,11 +554,12 @@
|
|||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Bypass t.co in user profiles and setup a top tier account bamboozle scheme.
|
// Block: Bypass t.co in user profiles and setup a top tier account bamboozle scheme.
|
||||||
//
|
//
|
||||||
(function(){
|
execSafe(function setupAccountLoadHook(){
|
||||||
const realDisplayName = "TweetDuck";
|
const realDisplayName = "TweetDuck";
|
||||||
const realAvatar = "https://ton.twimg.com/tduck/avatar";
|
const realAvatar = "https://ton.twimg.com/tduck/avatar";
|
||||||
const accountId = "957608948189880320";
|
const accountId = "957608948189880320";
|
||||||
@@ -500,6 +577,7 @@
|
|||||||
obj.profileImageURL = realAvatar;
|
obj.profileImageURL = realAvatar;
|
||||||
obj.url = "https://tweetduck.chylex.com";
|
obj.url = "https://tweetduck.chylex.com";
|
||||||
|
|
||||||
|
if (obj.entities && obj.entities.url){
|
||||||
obj.entities.url.urls = [{
|
obj.entities.url.urls = [{
|
||||||
url: obj.url,
|
url: obj.url,
|
||||||
expanded_url: obj.url,
|
expanded_url: obj.url,
|
||||||
@@ -507,6 +585,7 @@
|
|||||||
indices: [ 0, 23 ]
|
indices: [ 0, 23 ]
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (e && e.url && e.url.urls && e.url.urls.length && e.url.urls[0].expanded_url){
|
else if (e && e.url && e.url.urls && e.url.urls.length && e.url.urls[0].expanded_url){
|
||||||
obj.url = e.url.urls[0].expanded_url;
|
obj.url = e.url.urls[0].expanded_url;
|
||||||
}
|
}
|
||||||
@@ -537,11 +616,12 @@
|
|||||||
}, onError);
|
}, onError);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
})();
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Include additional information in context menus.
|
// Block: Include additional information in context menus.
|
||||||
//
|
//
|
||||||
|
execSafe(function setupContextMenuInfo(){
|
||||||
$(document.body).delegate("a", "contextmenu", function(){
|
$(document.body).delegate("a", "contextmenu", function(){
|
||||||
let me = $(this)[0];
|
let me = $(this)[0];
|
||||||
|
|
||||||
@@ -550,19 +630,20 @@
|
|||||||
let media = tweet.getMedia().find(media => media.mediaId === me.getAttribute("data-media-entity-id"));
|
let media = tweet.getMedia().find(media => media.mediaId === me.getAttribute("data-media-entity-id"));
|
||||||
|
|
||||||
if ((media.isVideo && media.service === "twitter") || media.isAnimatedGif){
|
if ((media.isVideo && media.service === "twitter") || media.isAnimatedGif){
|
||||||
$TD.setLastRightClickInfo("video", media.chooseVideoVariant().url);
|
$TD.setRightClickedLink("video", media.chooseVideoVariant().url);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
$TD.setLastRightClickInfo("image", media.large());
|
$TD.setRightClickedLink("image", media.large());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (me.classList.contains("js-gif-play")){
|
else if (me.classList.contains("js-gif-play")){
|
||||||
$TD.setLastRightClickInfo("video", $(this).closest(".js-media-gif-container").find("video").attr("src"));
|
$TD.setRightClickedLink("video", $(this).closest(".js-media-gif-container").find("video").attr("src"));
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
$TD.setLastRightClickInfo("link", me.getAttribute("data-full-url"));
|
$TD.setRightClickedLink("link", me.getAttribute("data-full-url"));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Hook into the notification sound effect.
|
// Block: Hook into the notification sound effect.
|
||||||
@@ -598,7 +679,10 @@
|
|||||||
//
|
//
|
||||||
// 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(){
|
execSafe(function setupHighlightedColumn(){
|
||||||
|
throw 1 if !ensurePropertyExists(TD, "controller", "columnManager", "get");
|
||||||
|
throw 2 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;
|
||||||
@@ -654,12 +738,12 @@
|
|||||||
updateHighlightedTweet(null, null);
|
updateHighlightedTweet(null, null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})();
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Screenshot tweet to clipboard.
|
// Block: Screenshot tweet to clipboard.
|
||||||
//
|
//
|
||||||
(function(){
|
execSafe(function setupTweetScreenshot(){
|
||||||
window.TDGF_triggerScreenshot = function(){
|
window.TDGF_triggerScreenshot = function(){
|
||||||
return if !highlightedTweetObj || !highlightedColumnObj;
|
return if !highlightedTweetObj || !highlightedColumnObj;
|
||||||
|
|
||||||
@@ -680,9 +764,9 @@
|
|||||||
html.find("footer").last().remove(); // apparently withTweetActions breaks for certain tweets, nice
|
html.find("footer").last().remove(); // apparently withTweetActions breaks for certain tweets, nice
|
||||||
html.find(".td-screenshot-remove").remove();
|
html.find(".td-screenshot-remove").remove();
|
||||||
|
|
||||||
html.find("p.link-complex-target").filter(function(){
|
html.find("p.link-complex-target,p.txt-mute").filter(function(){
|
||||||
return $(this).text() === "Show this thread";
|
return $(this).text() === "Show this thread";
|
||||||
}).first().remove();
|
}).remove();
|
||||||
|
|
||||||
html.addClass($(document.documentElement).attr("class"));
|
html.addClass($(document.documentElement).attr("class"));
|
||||||
html.addClass($(document.body).attr("class"));
|
html.addClass($(document.body).attr("class"));
|
||||||
@@ -699,6 +783,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let gif = html.find(".js-media-gif-container");
|
||||||
|
|
||||||
|
if (gif.length){
|
||||||
|
gif.css("background-image", 'url("'+chirp.getMedia()[0].small()+'")');
|
||||||
|
}
|
||||||
|
|
||||||
let type = chirp.getChirpType();
|
let type = chirp.getChirpType();
|
||||||
|
|
||||||
if ((type.startsWith("favorite") || type.startsWith("retweet")) && chirp.isAboutYou()){
|
if ((type.startsWith("favorite") || type.startsWith("retweet")) && chirp.isAboutYou()){
|
||||||
@@ -707,12 +797,16 @@
|
|||||||
|
|
||||||
$TD.screenshotTweet(html[0].outerHTML, columnWidth);
|
$TD.screenshotTweet(html[0].outerHTML, columnWidth);
|
||||||
};
|
};
|
||||||
})();
|
}, function(){
|
||||||
|
window.TDGF_triggerScreenshot = function(){
|
||||||
|
alert("error|This feature is not available due to an internal error.");
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Paste images when tweeting.
|
// Block: Paste images when tweeting.
|
||||||
//
|
//
|
||||||
onAppReady.push(function(){
|
onAppReady.push(function supportImagePaste(){
|
||||||
const uploader = $._data(document, "events")["uiComposeAddImageClick"][0].handler.context;
|
const uploader = $._data(document, "events")["uiComposeAddImageClick"][0].handler.context;
|
||||||
|
|
||||||
app.delegate(".js-compose-text,.js-reply-tweetbox,.td-detect-image-paste", "paste", function(e){
|
app.delegate(".js-compose-text,.js-reply-tweetbox,.td-detect-image-paste", "paste", function(e){
|
||||||
@@ -750,7 +844,7 @@
|
|||||||
//
|
//
|
||||||
// Block: Support for extra mouse buttons.
|
// Block: Support for extra mouse buttons.
|
||||||
//
|
//
|
||||||
(function(){
|
execSafe(function supportExtraMouseButtons(){
|
||||||
const tryClickSelector = function(selector, parent){
|
const tryClickSelector = function(selector, parent){
|
||||||
return $(selector, parent).click().length;
|
return $(selector, parent).click().length;
|
||||||
};
|
};
|
||||||
@@ -790,12 +884,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Allow drag & drop behavior for dropping links on columns to open their detail view.
|
// Block: Allow drag & drop behavior for dropping links on columns to open their detail view.
|
||||||
//
|
//
|
||||||
(function(){
|
execSafe(function supportDragDropOverColumns(){
|
||||||
const tweetRegex = /^https?:\/\/twitter\.com\/[A-Za-z0-9_]+\/status\/(\d+)\/?\??/;
|
const tweetRegex = /^https?:\/\/twitter\.com\/[A-Za-z0-9_]+\/status\/(\d+)\/?\??/;
|
||||||
const selector = "section.js-column";
|
const selector = "section.js-column";
|
||||||
|
|
||||||
@@ -838,11 +932,14 @@
|
|||||||
app.undelegate(selector, events);
|
app.undelegate(selector, events);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Fix scheduled tweets not showing up sometimes.
|
// Block: Fix scheduled tweets not showing up sometimes.
|
||||||
//
|
//
|
||||||
|
execSafe(function fixScheduledTweets(){
|
||||||
|
throw 1 if !ensurePropertyExists(TD, "controller", "columnManager", "getAll");
|
||||||
|
|
||||||
$(document).on("dataTweetSent", function(e, data){
|
$(document).on("dataTweetSent", function(e, data){
|
||||||
if (data.response.state && data.response.state === "scheduled"){
|
if (data.response.state && data.response.state === "scheduled"){
|
||||||
let column = Object.values(TD.controller.columnManager.getAll()).find(column => column.model.state.type === "scheduled");
|
let column = Object.values(TD.controller.columnManager.getAll()).find(column => column.model.state.type === "scheduled");
|
||||||
@@ -854,12 +951,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Hold Shift to restore cleared column.
|
// Block: Hold Shift to restore cleared column.
|
||||||
//
|
//
|
||||||
(function(){
|
execSafe(function supportShiftToClearColumn(){
|
||||||
var holdingShift = false;
|
throw 1 if !ensurePropertyExists(TD, "vo", "Column", "prototype", "clear");
|
||||||
|
|
||||||
|
let holdingShift = false;
|
||||||
|
|
||||||
const updateShiftState = (pressed) => {
|
const updateShiftState = (pressed) => {
|
||||||
if (pressed != holdingShift){
|
if (pressed != holdingShift){
|
||||||
@@ -882,8 +982,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
|
||||||
|
|
||||||
@@ -893,17 +991,19 @@
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})();
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Refocus the textbox after switching accounts.
|
// Block: Refocus the textbox after switching accounts.
|
||||||
//
|
//
|
||||||
onAppReady.push(function(){
|
onAppReady.push(function setupAccountSwitchRefocus(){
|
||||||
|
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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -911,6 +1011,7 @@
|
|||||||
//
|
//
|
||||||
// Block: Make middle click on tweet reply icon open the compose drawer, retweet icon trigger a quote, and favorite icon open a 'Like from accounts...' modal.
|
// Block: Make middle click on tweet reply icon open the compose drawer, retweet icon trigger a quote, and favorite icon open a 'Like from accounts...' modal.
|
||||||
//
|
//
|
||||||
|
execSafe(function supportMiddleClickTweetActions(){
|
||||||
app.delegate(".tweet-action,.tweet-detail-action", "auxclick", function(e){
|
app.delegate(".tweet-action,.tweet-detail-action", "auxclick", function(e){
|
||||||
return if e.which !== 2;
|
return if e.which !== 2;
|
||||||
|
|
||||||
@@ -967,18 +1068,19 @@
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Work around clipboard HTML formatting.
|
// Block: Work around clipboard HTML formatting.
|
||||||
//
|
//
|
||||||
$(document).on("copy", function(e){
|
document.addEventListener("copy", function(){
|
||||||
window.setTimeout($TD.fixClipboard, 0);
|
window.setTimeout($TD.fixClipboard, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Inject custom CSS and layout into the page.
|
// Block: Inject custom CSS and layout into the page.
|
||||||
//
|
//
|
||||||
(function(){
|
execSafe(function setupStyleInjection(){
|
||||||
const createStyle = function(id, styles){
|
const createStyle = function(id, styles){
|
||||||
let ele = document.createElement("style");
|
let ele = document.createElement("style");
|
||||||
ele.id = id;
|
ele.id = id;
|
||||||
@@ -999,12 +1101,42 @@
|
|||||||
createStyle("tweetduck-custom-css", styles);
|
createStyle("tweetduck-custom-css", styles);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
});
|
||||||
|
|
||||||
|
//
|
||||||
|
// Block: Setup global function to inject custom HTML into mustache templates.
|
||||||
|
//
|
||||||
|
window.TDGF_injectMustache = function(name, operation, search, custom){
|
||||||
|
let replacement;
|
||||||
|
|
||||||
|
switch(operation){
|
||||||
|
case "replace": replacement = custom; break;
|
||||||
|
case "append": replacement = search+custom; break;
|
||||||
|
case "prepend": replacement = custom+search; break;
|
||||||
|
default: throw "Invalid mustache injection operation. Only 'replace', 'append', 'prepend' are supported.";
|
||||||
|
}
|
||||||
|
|
||||||
|
let prev = TD.mustaches && TD.mustaches[name];
|
||||||
|
|
||||||
|
if (!prev){
|
||||||
|
$TD.crashDebug("Mustache injection is referencing an invalid mustache: "+name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TD.mustaches[name] = prev.replace(search, replacement);
|
||||||
|
|
||||||
|
if (prev === TD.mustaches[name]){
|
||||||
|
$TD.crashDebug("Mustache injection had no effect: "+name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Let's make retweets lowercase again.
|
// Block: Let's make retweets lowercase again.
|
||||||
//
|
//
|
||||||
TD.mustaches["status/tweet_single.mustache"] = TD.mustaches["status/tweet_single.mustache"].replace("{{_i}} Retweeted{{/i}}", "{{_i}} retweeted{{/i}}");
|
window.TDGF_injectMustache("status/tweet_single.mustache", "replace", "{{_i}} Retweeted{{/i}}", "{{_i}} retweeted{{/i}}");
|
||||||
|
|
||||||
if (ensurePropertyExists(TD, "services", "TwitterActionRetweet", "prototype", "generateText")){
|
if (ensurePropertyExists(TD, "services", "TwitterActionRetweet", "prototype", "generateText")){
|
||||||
TD.services.TwitterActionRetweet.prototype.generateText = appendToFunction(TD.services.TwitterActionRetweet.prototype.generateText, function(){
|
TD.services.TwitterActionRetweet.prototype.generateText = appendToFunction(TD.services.TwitterActionRetweet.prototype.generateText, function(){
|
||||||
@@ -1022,7 +1154,7 @@
|
|||||||
//
|
//
|
||||||
// Block: Setup video player hooks.
|
// Block: Setup video player hooks.
|
||||||
//
|
//
|
||||||
(function(){
|
execSafe(function setupVideoPlayer(){
|
||||||
window.TDGF_playVideo = function(url, username){
|
window.TDGF_playVideo = function(url, username){
|
||||||
$('<div id="td-video-player-overlay" class="ovl" style="display:block"></div>').on("click contextmenu", function(){
|
$('<div id="td-video-player-overlay" class="ovl" style="display:block"></div>').on("click contextmenu", function(){
|
||||||
$TD.playVideo(null, null);
|
$TD.playVideo(null, null);
|
||||||
@@ -1039,11 +1171,11 @@
|
|||||||
let parent = obj.closest(".js-tweet").first();
|
let parent = obj.closest(".js-tweet").first();
|
||||||
let link = (parent.hasClass("tweet-detail") ? parent.find("a[rel='url']") : parent.find("time").first().children("a")).first();
|
let link = (parent.hasClass("tweet-detail") ? parent.find("a[rel='url']") : parent.find("time").first().children("a")).first();
|
||||||
return link.attr("href");
|
return link.attr("href");
|
||||||
}
|
};
|
||||||
|
|
||||||
const getUsername = function(tweet){
|
const getUsername = function(tweet){
|
||||||
return tweet && (tweet.quotedTweet || tweet).getMainUser().screenName;
|
return tweet && (tweet.quotedTweet || tweet).getMainUser().screenName;
|
||||||
}
|
};
|
||||||
|
|
||||||
app.delegate(".js-gif-play", {
|
app.delegate(".js-gif-play", {
|
||||||
click: function(e){
|
click: function(e){
|
||||||
@@ -1073,14 +1205,15 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
TD.mustaches["status/media_thumb.mustache"] = TD.mustaches["status/media_thumb.mustache"].replace("is-gif", "is-gif is-paused");
|
window.TDGF_injectMustache("status/media_thumb.mustache", "append", "is-gif", " is-paused");
|
||||||
|
|
||||||
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") ||
|
throw 1 if !ensurePropertyExists(TD, "components", "MediaGallery", "prototype", "_loadTweet");
|
||||||
!ensurePropertyExists(TD, "components", "BaseModal", "prototype", "setAndShowContainer") ||
|
throw 2 if !ensurePropertyExists(TD, "components", "BaseModal", "prototype", "setAndShowContainer");
|
||||||
!ensurePropertyExists(TD, "ui", "Column", "prototype", "playGifIfNotManuallyPaused"))return;
|
throw 3 if !ensurePropertyExists(TD, "ui", "Column", "prototype", "playGifIfNotManuallyPaused");
|
||||||
|
|
||||||
var cancelModal = false;
|
let cancelModal = false;
|
||||||
|
|
||||||
TD.components.MediaGallery.prototype._loadTweet = appendToFunction(TD.components.MediaGallery.prototype._loadTweet, function(){
|
TD.components.MediaGallery.prototype._loadTweet = appendToFunction(TD.components.MediaGallery.prototype._loadTweet, function(){
|
||||||
let media = this.chirp.getMedia().find(media => media.mediaId === this.clickedMediaEntityId);
|
let media = this.chirp.getMedia().find(media => media.mediaId === this.clickedMediaEntityId);
|
||||||
@@ -1099,7 +1232,11 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
TD.ui.Column.prototype.playGifIfNotManuallyPaused = function(){};
|
TD.ui.Column.prototype.playGifIfNotManuallyPaused = function(){};
|
||||||
})();
|
}, function(){
|
||||||
|
window.TDGF_playVideo = function(){
|
||||||
|
alert("error|This feature is not available due to an internal error.");
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Fix youtu.be previews not showing up for https links.
|
// Block: Fix youtu.be previews not showing up for https links.
|
||||||
@@ -1107,10 +1244,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);
|
||||||
@@ -1120,14 +1257,14 @@
|
|||||||
//
|
//
|
||||||
// Block: Add a pin icon to make tweet compose drawer stay open.
|
// Block: Add a pin icon to make tweet compose drawer stay open.
|
||||||
//
|
//
|
||||||
onAppReady.push(function(){
|
onAppReady.push(function setupStayOpenPin(){
|
||||||
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()){
|
||||||
@@ -1148,6 +1285,10 @@
|
|||||||
//
|
//
|
||||||
// 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.
|
||||||
//
|
//
|
||||||
|
execSafe(function setupSearchColumnHook(){
|
||||||
|
throw 1 if !ensurePropertyExists(TD, "controller", "columnManager", "_columnOrder");
|
||||||
|
throw 2 if !ensurePropertyExists(TD, "controller", "columnManager", "move");
|
||||||
|
|
||||||
$(document).on("uiSearchNoTemporaryColumn", function(e, data){
|
$(document).on("uiSearchNoTemporaryColumn", function(e, data){
|
||||||
if (data.query && data.searchScope !== "users" && !data.columnKey){
|
if (data.query && data.searchScope !== "users" && !data.columnKey){
|
||||||
if ($TDX.openSearchInFirstColumn){
|
if ($TDX.openSearchInFirstColumn){
|
||||||
@@ -1168,33 +1309,38 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// 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.
|
||||||
//
|
//
|
||||||
onAppReady.push(function(){
|
onAppReady.push(() => execSafe(function setupSearchFunction(){
|
||||||
let context = $._data(document, "events")["uiSearchInputSubmit"][0].handler.context;
|
let context = $._data(document, "events")["uiSearchInputSubmit"][0].handler.context;
|
||||||
|
|
||||||
window.TDGF_performSearch = function(query){
|
window.TDGF_performSearch = function(query){
|
||||||
context.performSearch({ query, tweetduck: true });
|
context.performSearch({ query, tweetduck: true });
|
||||||
};
|
};
|
||||||
});
|
}, function(){
|
||||||
|
window.TDGF_performSearch = function(){
|
||||||
|
alert("error|This feature is not available due to an internal error.");
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Reorder search results to move accounts above hashtags.
|
// Block: Reorder search results to move accounts above hashtags.
|
||||||
//
|
//
|
||||||
onAppReady.push(function(){
|
onAppReady.push(function reorderSearchResults(){
|
||||||
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");
|
||||||
});
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Make submitting search queries while holding Ctrl or middle-clicking the search icon open the search externally.
|
// Block: Make submitting search queries while holding Ctrl or middle-clicking the search icon open the search externally.
|
||||||
//
|
//
|
||||||
onAppReady.push(function(){
|
onAppReady.push(function setupSearchTriggerHook(){
|
||||||
const openSearchExternally = function(event, input){
|
const openSearchExternally = function(event, input){
|
||||||
$TD.openBrowser("https://twitter.com/search/?q="+encodeURIComponent(input.val() || ""));
|
$TD.openBrowser("https://twitter.com/search/?q="+encodeURIComponent(input.val() || ""));
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -1204,17 +1350,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, $());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1233,9 +1379,14 @@
|
|||||||
//
|
//
|
||||||
// Block: Setup global function to refresh all columns.
|
// Block: Setup global function to refresh all columns.
|
||||||
//
|
//
|
||||||
|
if (ensurePropertyExists(TD, "controller", "columnManager", "getAll")){
|
||||||
window.TDGF_reloadColumns = function(){
|
window.TDGF_reloadColumns = function(){
|
||||||
Object.values(TD.controller.columnManager.getAll()).forEach(column => column.reloadTweets());
|
Object.values(TD.controller.columnManager.getAll()).forEach(column => column.reloadTweets());
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
window.TDGF_reloadColumns = function(){};
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Allow applying ROT13 to input selection.
|
// Block: Allow applying ROT13 to input selection.
|
||||||
@@ -1257,7 +1408,7 @@
|
|||||||
//
|
//
|
||||||
// Block: Revert Like/Follow dialogs being closed after clicking an action.
|
// Block: Revert Like/Follow dialogs being closed after clicking an action.
|
||||||
//
|
//
|
||||||
(function(){
|
execSafe(function setupLikeFollowDialogRevert(){
|
||||||
const prevSetTimeout = window.setTimeout;
|
const prevSetTimeout = window.setTimeout;
|
||||||
|
|
||||||
const overrideState = function(){
|
const overrideState = function(){
|
||||||
@@ -1302,7 +1453,7 @@
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
})();
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Fix DM reply input box not getting focused after opening a conversation.
|
// Block: Fix DM reply input box not getting focused after opening a conversation.
|
||||||
@@ -1329,11 +1480,37 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Remove column mouse wheel handler, which allows smooth scrolling inside columns, and horizontally scrolling column container when holding Shift.
|
// Block: Limit amount of loaded DMs to avoid massive lag from re-opening them several times.
|
||||||
|
//
|
||||||
|
if (ensurePropertyExists(TD, "services", "TwitterConversation", "prototype", "renderThread")){
|
||||||
|
const prevFunc = TD.services.TwitterConversation.prototype.renderThread;
|
||||||
|
|
||||||
|
TD.services.TwitterConversation.prototype.renderThread = function(){
|
||||||
|
let prevMessages = this.messages;
|
||||||
|
|
||||||
|
this.messages = prevMessages.slice(0, 100);
|
||||||
|
let result = prevFunc.apply(this, arguments);
|
||||||
|
this.messages = prevMessages;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Block: Fix broken horizontal scrolling of column container when holding Shift. TODO Fix broken smooth scrolling.
|
||||||
//
|
//
|
||||||
if (ensurePropertyExists(TD, "ui", "columns", "setupColumnScrollListeners")){
|
if (ensurePropertyExists(TD, "ui", "columns", "setupColumnScrollListeners")){
|
||||||
TD.ui.columns.setupColumnScrollListeners = appendToFunction(TD.ui.columns.setupColumnScrollListeners, function(e){
|
TD.ui.columns.setupColumnScrollListeners = appendToFunction(TD.ui.columns.setupColumnScrollListeners, function(column){
|
||||||
$(".js-column[data-column='"+e.model.getKey()+"']").off("mousewheel onmousewheel");
|
let ele = $(".js-column[data-column='"+column.model.getKey()+"']");
|
||||||
|
return if !ele.length;
|
||||||
|
|
||||||
|
ele.off("onmousewheel").on("mousewheel", ".scroll-v", function(e){
|
||||||
|
if (e.shiftKey){
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.TDGF_prioritizeNewestEvent(ele[0], "mousewheel");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1341,7 +1518,7 @@
|
|||||||
// Block: Detect and notify about connection issues.
|
// Block: Detect and notify about connection issues.
|
||||||
//
|
//
|
||||||
(function(){
|
(function(){
|
||||||
let onConnectionError = function(){
|
const onConnectionError = function(){
|
||||||
return if $("#tweetduck-conn-issues").length;
|
return if $("#tweetduck-conn-issues").length;
|
||||||
|
|
||||||
let ele = $(`
|
let ele = $(`
|
||||||
@@ -1355,15 +1532,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>`).appendTo(document.body);
|
||||||
`).appendTo(document.body);
|
|
||||||
|
|
||||||
ele.find("button").click(function(){
|
ele.find("button").click(function(){
|
||||||
ele.fadeOut(200);
|
ele.fadeOut(200);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
let onConnectionFine = function(){
|
const onConnectionFine = function(){
|
||||||
let ele = $("#tweetduck-conn-issues");
|
let ele = $("#tweetduck-conn-issues");
|
||||||
|
|
||||||
ele.fadeOut(200, function(){
|
ele.fadeOut(200, function(){
|
||||||
@@ -1379,6 +1555,7 @@
|
|||||||
// Block: Custom reload function with memory cleanup.
|
// Block: Custom reload function with memory cleanup.
|
||||||
//
|
//
|
||||||
window.TDGF_reload = function(){
|
window.TDGF_reload = function(){
|
||||||
|
try{
|
||||||
let session = TD.storage.feedController.getAll()
|
let session = TD.storage.feedController.getAll()
|
||||||
.filter(feed => !!feed.getTopSortIndex())
|
.filter(feed => !!feed.getTopSortIndex())
|
||||||
.reduce((obj, feed) => (obj[feed.privateState.key] = feed.getTopSortIndex(), obj), {});
|
.reduce((obj, feed) => (obj[feed.privateState.key] = feed.getTopSortIndex(), obj), {});
|
||||||
@@ -1387,12 +1564,16 @@
|
|||||||
window.gc && window.gc();
|
window.gc && window.gc();
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
});
|
});
|
||||||
|
}catch(err){
|
||||||
|
$TD.crashDebug("Error saving session during a reload");
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
window.TDGF_reload = function(){}; // redefine to prevent reloading multiple times
|
window.TDGF_reload = function(){}; // redefine to prevent reloading multiple times
|
||||||
};
|
};
|
||||||
|
|
||||||
if (window.TD_SESSION && window.TD_SESSION.gc){
|
if (window.TD_SESSION && window.TD_SESSION.gc){
|
||||||
var state;
|
let state;
|
||||||
|
|
||||||
try{
|
try{
|
||||||
state = JSON.parse(window.TD_SESSION.gc);
|
state = JSON.parse(window.TD_SESSION.gc);
|
||||||
@@ -1401,7 +1582,7 @@
|
|||||||
state = {};
|
state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
var showMissedNotifications = function(){
|
const showMissedNotifications = function(){
|
||||||
let tweets = [];
|
let tweets = [];
|
||||||
let columns = {};
|
let columns = {};
|
||||||
|
|
||||||
@@ -1429,6 +1610,9 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
execSafe(function showMissedNotifications(){
|
||||||
|
throw 1 if !ensurePropertyExists(TD, "controller", "columnManager", "getAll");
|
||||||
|
|
||||||
$(document).one("dataColumnsLoaded", function(){
|
$(document).one("dataColumnsLoaded", function(){
|
||||||
let columns = Object.values(TD.controller.columnManager.getAll());
|
let columns = Object.values(TD.controller.columnManager.getAll());
|
||||||
let remaining = columns.length;
|
let remaining = columns.length;
|
||||||
@@ -1441,14 +1625,16 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Disable default TweetDeck update notification.
|
// Block: Disable default TweetDeck update notification.
|
||||||
//
|
//
|
||||||
onAppReady.push(function(){
|
execSafe(function disableTweetDeckUpdates(){
|
||||||
let events = $._data(document, "events");
|
$(document).on("uiSuggestRefreshToggle", function(e){
|
||||||
delete events["uiSuggestRefreshToggle"];
|
e.stopImmediatePropagation();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -1463,7 +1649,7 @@
|
|||||||
TD.metrics.send = noop;
|
TD.metrics.send = noop;
|
||||||
}
|
}
|
||||||
|
|
||||||
onAppReady.push(function(){
|
onAppReady.push(function disableMetrics(){
|
||||||
let data = $._data(window);
|
let data = $._data(window);
|
||||||
delete data.events["metric"];
|
delete data.events["metric"];
|
||||||
delete data.events["metricsFlush"];
|
delete data.events["metricsFlush"];
|
||||||
@@ -1473,7 +1659,7 @@
|
|||||||
// Block: Register the TD.ready event, finish initialization, and load plugins.
|
// Block: Register the TD.ready event, finish initialization, and load plugins.
|
||||||
//
|
//
|
||||||
$(document).one("TD.ready", function(){
|
$(document).one("TD.ready", function(){
|
||||||
onAppReady.forEach(func => func());
|
onAppReady.forEach(func => execSafe(func));
|
||||||
onAppReady = null;
|
onAppReady = null;
|
||||||
|
|
||||||
delete window.TD_SESSION;
|
delete window.TD_SESSION;
|
||||||
@@ -1491,4 +1677,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 || {});
|
||||||
|
26
Resources/Scripts/imports/markup/introduction.html
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<div id="td-introduction-modal" class="ovl scroll-v scroll-styled-v">
|
||||||
|
<div class="mdl is-inverted-dark">
|
||||||
|
<header class="mdl-header">
|
||||||
|
<h3 class="mdl-header-title">Welcome to TweetDuck</h3>
|
||||||
|
<a href="#" class="mdl-dismiss link-normal-dark"><i class="icon icon-close"></i></a>
|
||||||
|
</header>
|
||||||
|
<div class="mdl-inner">
|
||||||
|
<div class="mdl-content">
|
||||||
|
<p>Thank you for downloading TweetDuck!</p>
|
||||||
|
<p><a id="td-introduction-follow" href="#">Follow @TryMyAwesomeApp</a> for latest news and updates about the app.</p>
|
||||||
|
<div class="main-menu"></div>
|
||||||
|
<p><strong>Right-click anywhere</strong> or click <strong>Settings – TweetDuck</strong> in the left panel to open the main menu. You can also right-click links, tweets, images and videos, and desktop notifications to access their respective context menus.</p>
|
||||||
|
<p>Click <strong>Show Guide</strong> to see awesome features TweetDuck offers, or view the guide later by going to <strong>About TweetDuck</strong> and clicking the help button on top.</p>
|
||||||
|
</div>
|
||||||
|
<footer class="txt-right">
|
||||||
|
<div class="anondata">
|
||||||
|
<input id="td-anonymous-data" type="checkbox" checked>
|
||||||
|
<label for="td-anonymous-data">Send anonymous usage data</label>
|
||||||
|
<label> (<a href="https://github.com/chylex/TweetDuck/wiki/Send-anonymous-data" rel="nofollow">learn more</a>)</label>
|
||||||
|
</div>
|
||||||
|
<button class="Button--primary" data-guide><span class="label">Show Guide</span></button>
|
||||||
|
<button class="Button--secondary"><span class="label">Close</span></button>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@@ -3,14 +3,14 @@
|
|||||||
// Block: Setup a simple JavaScript object configuration loader.
|
// Block: Setup a simple JavaScript object configuration loader.
|
||||||
//
|
//
|
||||||
window.TDPF_loadConfigurationFile = function(pluginObject, fileNameUser, fileNameDefault, onSuccess, onFailure){
|
window.TDPF_loadConfigurationFile = function(pluginObject, fileNameUser, fileNameDefault, onSuccess, onFailure){
|
||||||
var identifier = pluginObject.$id;
|
let identifier = pluginObject.$id;
|
||||||
var token = pluginObject.$token;
|
let token = pluginObject.$token;
|
||||||
|
|
||||||
$TDP.checkFileExists(token, fileNameUser).then(exists => {
|
$TDP.checkFileExists(token, fileNameUser).then(exists => {
|
||||||
var fileName = exists ? fileNameUser : fileNameDefault;
|
let fileName = exists ? fileNameUser : fileNameDefault;
|
||||||
|
|
||||||
(exists ? $TDP.readFile(token, fileName, true) : $TDP.readFileRoot(token, fileName)).then(contents => {
|
(exists ? $TDP.readFile(token, fileName, true) : $TDP.readFileRoot(token, fileName)).then(contents => {
|
||||||
var obj;
|
let obj;
|
||||||
|
|
||||||
try{
|
try{
|
||||||
obj = eval("("+contents+")");
|
obj = eval("("+contents+")");
|
||||||
@@ -39,16 +39,14 @@
|
|||||||
// Block: Setup a function to add/remove custom CSS.
|
// Block: Setup a function to add/remove custom CSS.
|
||||||
//
|
//
|
||||||
window.TDPF_createCustomStyle = function(pluginObject){
|
window.TDPF_createCustomStyle = function(pluginObject){
|
||||||
var element = document.createElement("style");
|
let element = document.createElement("style");
|
||||||
element.id = "plugin-"+pluginObject.$id+"-"+Math.random().toString(36).substring(2, 7);
|
element.id = "plugin-"+pluginObject.$id+"-"+Math.random().toString(36).substring(2, 7);
|
||||||
document.head.appendChild(element);
|
document.head.appendChild(element);
|
||||||
|
|
||||||
var obj = {
|
return {
|
||||||
insert: (rule) => element.sheet.insertRule(rule, 0),
|
insert: (rule) => element.sheet.insertRule(rule, 0),
|
||||||
remove: () => $(element).remove()
|
remove: () => element.remove(),
|
||||||
|
element: element
|
||||||
};
|
};
|
||||||
|
|
||||||
obj.element = element;
|
|
||||||
return obj;
|
|
||||||
};
|
};
|
||||||
})($TDP);
|
})($TDP);
|
69
Resources/Scripts/imports/styles/introduction.css
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#td-introduction-modal {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#td-introduction-modal .mdl {
|
||||||
|
width: 90%;
|
||||||
|
min-width: 515px;
|
||||||
|
max-width: 835px;
|
||||||
|
height: 328px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#td-introduction-modal .mdl-inner {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#td-introduction-modal .mdl-header-title {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
#td-introduction-modal .mdl-content {
|
||||||
|
padding: 4px 16px 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#td-introduction-modal p {
|
||||||
|
margin: 12px 0;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#td-introduction-modal p strong {
|
||||||
|
font-weight: normal;
|
||||||
|
text-shadow: 0 0 #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#td-introduction-modal .main-menu {
|
||||||
|
float: left;
|
||||||
|
width: 187px;
|
||||||
|
height: 124px;
|
||||||
|
margin-right: 12px;
|
||||||
|
box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.33);
|
||||||
|
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALsAAAB8CAMAAAAGozFUAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACZUExURQAAAAAANgAAYQA2YQA2iABhYQBhrDYAADYANjYAYTY2ADY2NjY2YTY2iDZhrDaIiDaIz2EAAGEANmEAYWE2NmE2iGFhNmFhYWGs8og2AIg2Nog2YYiIYYisiIjPrIjPz4jP8qxhAKxhNqzPiKzyrKzy8szMzM+INs/PiM/yrM/yz8/y8tfX1/Dw8PKsYfLPiPLyrPLyz/Ly8nG9GIQAAARDSURBVHja7ZyPd9IwEMdDxbI5cemcWJjbWrWrDi2Q//+PM7m7pOGHfcORlD6v7w1ok2wfwqXkvrs78TTcQzypoR6DZ//dcTA7szM7s8dgX2dCiJxGrG+Kvd+C1w619M+uoZqkGiy7AxvivI+XajURSWVO9AtjQ6UQqTIn18R+PxFSP82SCnuUOYxdfdjMzSmNn9mPMJa9p/QWpH5cZ5rjgqbanNQjOMnGS315nWl+7NGkqrmSqpb6hRuvm+PO++qygtkWKZ2YOW2EGBWr6dK3mTKHmcYeuu3r/fR5UawmUrXjY9tMLRFItez6abPYYd/MffbN4uHT89033UPVInfje1ir+Glbm7msGjKR1mbg/UFv7KFqYzGfwUhq6cbHZle1Jp3QZ65fjMwcize3hbEcu1ZnZkVCb+wBq8L86D4JGl1sm+E9AbMzO7MzO7MzO7Mze586QQqdcav7ggO3juMfF8Whlsj+6hXuzx17x0aWmswO/nBLbPaZ8RqatzdHsO/36In94WOltAOnXSZwoR7A+Qa3H5q/CEH+aA5+OfaQ6ASCYGAuZq3nAi4KjML2oH6T9qxX05+W3T5pt5+WQ5NUpA1s99jMpZt05zpiPxzVpOF1gukSFACPDN3+1p0l/3qbHf1rVBQO9gMFISz7ZnE/Xe6wX3oqXzc7KgoH+4GCEFoXA8VL20CuGprCTG6xkzZwyGZIUTjUDxSEwOybu4regzC3mxLXqm8zVhsoYUXai2aF5qQolL7KQB1QQeDvVWZndmZndmZn9nNn/3WuB9sMszM7szM7sw+WXXvEQgYTRYOyNxA9IEMJiyHZjSijWi1pUOxIDcqWiao6uSgalN0E70BYT7YncJ1CFI0074Uvg55KFI1i715U1SlF0bD3maRSGH4nfbn0VKJo+Pt77qKqTi2KRvlePZObI7PzXozZmZ3ZmZ3Zmf1/YjdO3qjY3xH0rBW8PN9jvDyv3cyR+R7DZvdCNq7pQk8iwfE243l7NUTR9CYSHLNWk8qPRsKcJu9CdJHgmHlXqos9vkhwPLsNuWptpi+R4Hh2G3KF+Vgte3yR4FXfq620Orw9QTleDpLd3M6Tvqed95HMzuzMzuzMzuw9sJep6v7XQSnEXsyBd0AZmN3WVzrAL2Rfvb8t/vK3OgukKM/ddelpkdlraVyLV7LvbZujsLuyG1CkxcURtGlalsQVbaHELfP43YYfeP9WRmGBfPWw7Bpc47dFWnaTsBy7K9ri6r3Q4w47BrSsbx7neeh5NwZTp7ZIy34ik2P3iraYxK22aguyb+c46RfvZGibgZsElfzRc9fB7oq2uJysHXvfZs+u0tDspl4RhqBgOAHGEXhpWu3Ks0VbqF6Lq9piC7vQIGszRSkDs+MfqFMbTkBJWF6almO3RVsocQsfS0yihOxXGgQpW2D4/+728p6A2Zmd2Zmd2c+SfaCHZh/u8QdspaeBZ15I7gAAAABJRU5ErkJggg==);
|
||||||
|
}
|
||||||
|
|
||||||
|
#td-introduction-modal .main-menu + p {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#td-introduction-modal footer {
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#td-introduction-modal button {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#td-introduction-modal .anondata {
|
||||||
|
float: left;
|
||||||
|
margin: 5px 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#td-introduction-modal .anondata input {
|
||||||
|
vertical-align: -10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#td-introduction-modal .anondata label {
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
67
Resources/Scripts/imports/styles/twitter.base.css
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/*********************/
|
||||||
|
/* Center everything */
|
||||||
|
/*********************/
|
||||||
|
|
||||||
|
#doc {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
position: absolute;
|
||||||
|
display: table;
|
||||||
|
}
|
||||||
|
|
||||||
|
#page-outer {
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
#page-container {
|
||||||
|
padding: 0 20px !important;
|
||||||
|
width: 100% !important;
|
||||||
|
box-sizing: border-box !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-canvas {
|
||||||
|
margin: 0 auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************/
|
||||||
|
/* General styling */
|
||||||
|
/*******************/
|
||||||
|
|
||||||
|
body {
|
||||||
|
/* remove scrollbar */
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-canvas {
|
||||||
|
/* tweak page shadow */
|
||||||
|
box-shadow: 0 0 150px rgba(255, 255, 255, 0.3) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar {
|
||||||
|
/* hide top bar */
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-canvas, .buttons, .btn, input {
|
||||||
|
/* sharpen borders */
|
||||||
|
border-radius: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
/* tweak input padding */
|
||||||
|
padding: 5px 8px 4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
button[type='submit'] {
|
||||||
|
/* style buttons */
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.3) !important;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tweetduck-helper {
|
||||||
|
/* custom login text */
|
||||||
|
margin-top: 15px !important;
|
||||||
|
font-weight: bold !important;
|
||||||
|
}
|
38
Resources/Scripts/imports/styles/twitter.logout.css
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*****************************/
|
||||||
|
/* Fix min width and margins */
|
||||||
|
/*****************************/
|
||||||
|
|
||||||
|
.page-canvas {
|
||||||
|
width: auto !important;
|
||||||
|
max-width: 888px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.signout-wrapper {
|
||||||
|
width: auto !important;
|
||||||
|
margin: 0 auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.signout {
|
||||||
|
margin: 60px 0 54px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
padding-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************/
|
||||||
|
/* General styling */
|
||||||
|
/*******************/
|
||||||
|
|
||||||
|
.aside {
|
||||||
|
/* hide elements around dialog */
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons button, .buttons a {
|
||||||
|
/* style buttons */
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0 4px !important;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.3) !important;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
}
|
126
Resources/Scripts/imports/styles/update.css
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#tweetduck-update {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
width: 200px;
|
||||||
|
height: 178px;
|
||||||
|
z-index: 9999;
|
||||||
|
color: #fff;
|
||||||
|
background-color: rgb(32, 94, 138);
|
||||||
|
text-align: center;
|
||||||
|
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
|
||||||
|
transition: transform 400ms cubic-bezier(.02, .01, .47, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#tweetduck-update.hidden-below {
|
||||||
|
transform: translateY(178px);
|
||||||
|
}
|
||||||
|
|
||||||
|
#tweetduck-update .tdu-title {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 8px 0 2px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tweetduck-update .tdu-info {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 14px;
|
||||||
|
margin: 3px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tweetduck-update .tdu-showlog {
|
||||||
|
text-decoration: underline;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tweetduck-update .tdu-buttons button {
|
||||||
|
display: block;
|
||||||
|
margin: 7px auto 0;
|
||||||
|
padding: 4px 10px;
|
||||||
|
width: 80%;
|
||||||
|
height: 30px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 1px;
|
||||||
|
outline: none;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #419de0;
|
||||||
|
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
|
||||||
|
box-shadow: 1px 1px 1px rgba(17, 17, 17, 0.5) !important;
|
||||||
|
transition: box-shadow 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tweetduck-update .tdu-buttons button:hover {
|
||||||
|
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.75);
|
||||||
|
box-shadow: 1px 1px 1px rgba(17, 17, 17, 0.75), 0 -2px 0 rgba(17, 17, 17, 0.33) inset !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tweetduck-update .tdu-buttons button.tdu-btn-ignore, .tdu-buttons button.tdu-btn-later {
|
||||||
|
background-color: #607a8e;
|
||||||
|
color: #dfdfdf;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tweetduck-changelog {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: 9998;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tweetduck-changelog-box {
|
||||||
|
position: absolute;
|
||||||
|
width: 60%;
|
||||||
|
height: 75%;
|
||||||
|
max-width: calc(90% - 200px);
|
||||||
|
max-height: 90%;
|
||||||
|
left: calc(50% + 100px);
|
||||||
|
top: 50%;
|
||||||
|
padding: 12px;
|
||||||
|
overflow-y: auto;
|
||||||
|
transform: translateX(-50%) translateY(-50%);
|
||||||
|
font-size: 14px;
|
||||||
|
color: #000;
|
||||||
|
background-color: #fff;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tweetduck-changelog h2 {
|
||||||
|
margin: 0 0 7px;
|
||||||
|
font-size: 23px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tweetduck-changelog h2 + br {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tweetduck-changelog h3 {
|
||||||
|
margin: 0 0 5px 7px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tweetduck-changelog p {
|
||||||
|
margin: 8px 8px 0 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tweetduck-changelog p.li {
|
||||||
|
margin: 0 8px 2px 30px;
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tweetduck-changelog p.l2 {
|
||||||
|
margin-left: 50px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tweetduck-changelog a {
|
||||||
|
color: #247fbb;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tweetduck-changelog code {
|
||||||
|
padding: 0 4px;
|
||||||
|
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||||
|
color: #24292e;
|
||||||
|
background-color: rgba(27, 31, 35, 0.05);
|
||||||
|
}
|
@@ -1,104 +1,7 @@
|
|||||||
(function($, $TD){
|
(function($, $TD){
|
||||||
$(document).one("TD.ready", function(){
|
$(document).one("TD.ready", function(){
|
||||||
let css = $(`
|
let css = $(`<style>#import "styles/introduction.css"</style>`).appendTo(document.head);
|
||||||
<style>
|
let ele = $(`#import "markup/introduction.html"`).appendTo(".js-app");
|
||||||
#td-introduction-modal {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
#td-introduction-modal .mdl {
|
|
||||||
width: 90%;
|
|
||||||
max-width: 830px;
|
|
||||||
height: 328px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#td-introduction-modal .mdl-inner {
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#td-introduction-modal .mdl-header-title {
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
#td-introduction-modal .mdl-content {
|
|
||||||
padding: 4px 16px 0;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#td-introduction-modal p {
|
|
||||||
margin: 12px 0;
|
|
||||||
font-size: 1.4rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#td-introduction-modal p strong {
|
|
||||||
font-weight: normal;
|
|
||||||
text-shadow: 0 0 #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
#td-introduction-modal .main-menu {
|
|
||||||
float: left;
|
|
||||||
width: 187px;
|
|
||||||
height: 124px;
|
|
||||||
margin-right: 12px;
|
|
||||||
box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.33);
|
|
||||||
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALsAAAB8CAMAAAAGozFUAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACZUExURQAAAAAANgAAYQA2YQA2iABhYQBhrDYAADYANjYAYTY2ADY2NjY2YTY2iDZhrDaIiDaIz2EAAGEANmEAYWE2NmE2iGFhNmFhYWGs8og2AIg2Nog2YYiIYYisiIjPrIjPz4jP8qxhAKxhNqzPiKzyrKzy8szMzM+INs/PiM/yrM/yz8/y8tfX1/Dw8PKsYfLPiPLyrPLyz/Ly8nG9GIQAAARDSURBVHja7ZyPd9IwEMdDxbI5cemcWJjbWrWrDi2Q//+PM7m7pOGHfcORlD6v7w1ok2wfwqXkvrs78TTcQzypoR6DZ//dcTA7szM7s8dgX2dCiJxGrG+Kvd+C1w619M+uoZqkGiy7AxvivI+XajURSWVO9AtjQ6UQqTIn18R+PxFSP82SCnuUOYxdfdjMzSmNn9mPMJa9p/QWpH5cZ5rjgqbanNQjOMnGS315nWl+7NGkqrmSqpb6hRuvm+PO++qygtkWKZ2YOW2EGBWr6dK3mTKHmcYeuu3r/fR5UawmUrXjY9tMLRFItez6abPYYd/MffbN4uHT89033UPVInfje1ir+Glbm7msGjKR1mbg/UFv7KFqYzGfwUhq6cbHZle1Jp3QZ65fjMwcize3hbEcu1ZnZkVCb+wBq8L86D4JGl1sm+E9AbMzO7MzO7MzO7Mze586QQqdcav7ggO3juMfF8Whlsj+6hXuzx17x0aWmswO/nBLbPaZ8RqatzdHsO/36In94WOltAOnXSZwoR7A+Qa3H5q/CEH+aA5+OfaQ6ASCYGAuZq3nAi4KjML2oH6T9qxX05+W3T5pt5+WQ5NUpA1s99jMpZt05zpiPxzVpOF1gukSFACPDN3+1p0l/3qbHf1rVBQO9gMFISz7ZnE/Xe6wX3oqXzc7KgoH+4GCEFoXA8VL20CuGprCTG6xkzZwyGZIUTjUDxSEwOybu4regzC3mxLXqm8zVhsoYUXai2aF5qQolL7KQB1QQeDvVWZndmZndmZn9nNn/3WuB9sMszM7szM7sw+WXXvEQgYTRYOyNxA9IEMJiyHZjSijWi1pUOxIDcqWiao6uSgalN0E70BYT7YncJ1CFI0074Uvg55KFI1i715U1SlF0bD3maRSGH4nfbn0VKJo+Pt77qKqTi2KRvlePZObI7PzXozZmZ3ZmZ3Zmf1/YjdO3qjY3xH0rBW8PN9jvDyv3cyR+R7DZvdCNq7pQk8iwfE243l7NUTR9CYSHLNWk8qPRsKcJu9CdJHgmHlXqos9vkhwPLsNuWptpi+R4Hh2G3KF+Vgte3yR4FXfq620Orw9QTleDpLd3M6Tvqed95HMzuzMzuzMzuw9sJep6v7XQSnEXsyBd0AZmN3WVzrAL2Rfvb8t/vK3OgukKM/ddelpkdlraVyLV7LvbZujsLuyG1CkxcURtGlalsQVbaHELfP43YYfeP9WRmGBfPWw7Bpc47dFWnaTsBy7K9ri6r3Q4w47BrSsbx7neeh5NwZTp7ZIy34ik2P3iraYxK22aguyb+c46RfvZGibgZsElfzRc9fB7oq2uJysHXvfZs+u0tDspl4RhqBgOAHGEXhpWu3Ks0VbqF6Lq9piC7vQIGszRSkDs+MfqFMbTkBJWF6almO3RVsocQsfS0yihOxXGgQpW2D4/+728p6A2Zmd2Zmd2c+SfaCHZh/u8QdspaeBZ15I7gAAAABJRU5ErkJggg==);
|
|
||||||
}
|
|
||||||
|
|
||||||
#td-introduction-modal .main-menu + p {
|
|
||||||
margin-top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#td-introduction-modal footer {
|
|
||||||
padding: 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#td-introduction-modal button {
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#td-introduction-modal .anondata {
|
|
||||||
float: left;
|
|
||||||
margin: 5px 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#td-introduction-modal .anondata input {
|
|
||||||
vertical-align: -10%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#td-introduction-modal .anondata label {
|
|
||||||
cursor: pointer;
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
</style>`).appendTo(document.head);
|
|
||||||
|
|
||||||
let ele = $(`
|
|
||||||
<div id="td-introduction-modal" class="ovl">
|
|
||||||
<div class="mdl is-inverted-dark">
|
|
||||||
<header class="mdl-header">
|
|
||||||
<h3 class="mdl-header-title">Welcome to TweetDuck</h3>
|
|
||||||
<a href="#" class="mdl-dismiss link-normal-dark"><i class="icon icon-close"></i></a>
|
|
||||||
</header>
|
|
||||||
<div class="mdl-inner">
|
|
||||||
<div class="mdl-content">
|
|
||||||
<p>Thank you for downloading TweetDuck!</p>
|
|
||||||
<p><a id="td-introduction-follow" href="#">Follow @TryMyAwesomeApp</a> for latest news and updates about the app.</p>
|
|
||||||
<div class="main-menu"></div>
|
|
||||||
<p><strong>Right-click anywhere</strong> or click <strong>Settings – TweetDuck</strong> in the left panel to open the main menu. You can also right-click links, tweets, images and videos, and desktop notifications to access their respective context menus.</p>
|
|
||||||
<p>Click <strong>Show Guide</strong> to see awesome features TweetDuck offers, or view the guide later by going to <strong>About TweetDuck</strong> and clicking the help button on top.</p>
|
|
||||||
</div>
|
|
||||||
<footer class="txt-right">
|
|
||||||
<div class="anondata">
|
|
||||||
<input id="td-anonymous-data" type="checkbox" checked>
|
|
||||||
<label for="td-anonymous-data">Send anonymous usage data</label>
|
|
||||||
<label> (<a href="https://github.com/chylex/TweetDuck/wiki/Send-anonymous-data" rel="nofollow">learn more</a>)</label>
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-positive" data-guide><span class="label">Show Guide</span></button>
|
|
||||||
<button class="btn btn-positive"><span class="label">Close</span</button>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`).appendTo(".js-app"); /* TODO btn-positive is removed, check all files again */
|
|
||||||
|
|
||||||
let tdUser = null;
|
let tdUser = null;
|
||||||
let loadTweetDuckUser = (onSuccess, onError) => {
|
let loadTweetDuckUser = (onSuccess, onError) => {
|
||||||
|
@@ -2,26 +2,26 @@
|
|||||||
//
|
//
|
||||||
// Variable: Collection of all <a> tags.
|
// Variable: Collection of all <a> tags.
|
||||||
//
|
//
|
||||||
var links = document.getElementsByTagName("A");
|
const links = document.getElementsByTagName("A");
|
||||||
|
|
||||||
//
|
//
|
||||||
// Function: Adds an event listener to all elements in the array or collection.
|
// Function: Adds an event listener to all elements in the array or collection.
|
||||||
//
|
//
|
||||||
var addEventListener = function(collection, type, listener){
|
const addEventListener = function(collection, type, listener){
|
||||||
for(let index = 0; index < collection.length; index++){
|
for(let ele of collection){
|
||||||
collection[index].addEventListener(type, listener);
|
ele.addEventListener(type, listener);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Hook into links to bypass default open function and t.co, and handle skipping notification when opening links.
|
// Block: Hook into links to bypass default open function, and handle skipping notification when opening links.
|
||||||
//
|
//
|
||||||
(function(){
|
(function(){
|
||||||
const onLinkClick = function(e){
|
const onLinkClick = function(e){
|
||||||
if (e.button === 0 || e.button === 1){
|
if (e.button === 0 || e.button === 1){
|
||||||
let ele = e.currentTarget;
|
let ele = e.currentTarget;
|
||||||
|
|
||||||
$TD.openBrowser(ele.hasAttribute("data-full-url") ? ele.getAttribute("data-full-url") : ele.getAttribute("href"));
|
$TD.openBrowser(ele.href);
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if ($TDX.skipOnLinkClick){
|
if ($TDX.skipOnLinkClick){
|
||||||
@@ -38,27 +38,20 @@
|
|||||||
addEventListener(links, "auxclick", onLinkClick);
|
addEventListener(links, "auxclick", onLinkClick);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
//
|
|
||||||
// Block: Allow bypassing of t.co in context menus.
|
|
||||||
//
|
|
||||||
addEventListener(links, "contextmenu", function(e){
|
|
||||||
$TD.setLastRightClickInfo("link", e.currentTarget.getAttribute("data-full-url"));
|
|
||||||
});
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Expand shortened links on hover or display tooltip.
|
// Block: Expand shortened links on hover or display tooltip.
|
||||||
//
|
//
|
||||||
(function(){
|
(function(){
|
||||||
var prevMouseX = -1, prevMouseY = -1;
|
let prevMouseX = -1, prevMouseY = -1;
|
||||||
var tooltipTimer, tooltipDisplayed;
|
let tooltipTimer, tooltipDisplayed;
|
||||||
|
|
||||||
addEventListener(links, "mouseenter", function(e){
|
addEventListener(links, "mouseenter", function(e){
|
||||||
var me = e.currentTarget;
|
let me = e.currentTarget;
|
||||||
|
|
||||||
var url = me.getAttribute("data-full-url");
|
let url = me.getAttribute("data-full-url");
|
||||||
return if !url;
|
return if !url;
|
||||||
|
|
||||||
var text = me.textContent;
|
let text = me.textContent;
|
||||||
return if text.charCodeAt(text.length-1) !== 8230 && text.charCodeAt(0) !== 8230; // horizontal ellipsis
|
return if text.charCodeAt(text.length-1) !== 8230 && text.charCodeAt(0) !== 8230; // horizontal ellipsis
|
||||||
|
|
||||||
if ($TDX.expandLinksOnHover){
|
if ($TDX.expandLinksOnHover){
|
||||||
@@ -79,7 +72,7 @@
|
|||||||
return if !e.currentTarget.hasAttribute("data-full-url");
|
return if !e.currentTarget.hasAttribute("data-full-url");
|
||||||
|
|
||||||
if ($TDX.expandLinksOnHover){
|
if ($TDX.expandLinksOnHover){
|
||||||
var prevText = e.currentTarget.getAttribute("td-prev-text");
|
let prevText = e.currentTarget.getAttribute("td-prev-text");
|
||||||
|
|
||||||
if (prevText){
|
if (prevText){
|
||||||
e.currentTarget.innerHTML = prevText;
|
e.currentTarget.innerHTML = prevText;
|
||||||
@@ -96,7 +89,7 @@
|
|||||||
|
|
||||||
addEventListener(links, "mousemove", function(e){
|
addEventListener(links, "mousemove", function(e){
|
||||||
if (tooltipDisplayed && (prevMouseX !== e.clientX || prevMouseY !== e.clientY)){
|
if (tooltipDisplayed && (prevMouseX !== e.clientX || prevMouseY !== e.clientY)){
|
||||||
var url = e.currentTarget.getAttribute("data-full-url");
|
let url = e.currentTarget.getAttribute("data-full-url");
|
||||||
return if !url;
|
return if !url;
|
||||||
|
|
||||||
$TD.displayTooltip(url);
|
$TD.displayTooltip(url);
|
||||||
@@ -117,7 +110,7 @@
|
|||||||
// Block: Setup a handler for 'Show this thread'.
|
// Block: Setup a handler for 'Show this thread'.
|
||||||
//
|
//
|
||||||
(function(){
|
(function(){
|
||||||
var btn = document.getElementById("tduck-show-thread");
|
let btn = document.getElementById("tduck-show-thread");
|
||||||
return if !btn;
|
return if !btn;
|
||||||
|
|
||||||
btn.addEventListener("click", function(){
|
btn.addEventListener("click", function(){
|
||||||
@@ -129,11 +122,10 @@
|
|||||||
// Block: Setup a skip button.
|
// Block: Setup a skip button.
|
||||||
//
|
//
|
||||||
if (!document.body.hasAttribute("td-example-notification")){
|
if (!document.body.hasAttribute("td-example-notification")){
|
||||||
document.body.insertAdjacentHTML("afterbegin", `
|
document.body.children[0].insertAdjacentHTML("beforeend", `
|
||||||
<svg id="td-skip" width="10" height="17" viewBox="0 0 350 600">
|
<svg id="td-skip" width="10" height="17" viewBox="0 0 350 600">
|
||||||
<path fill="#888" d="M0,151.656l102.208-102.22l247.777,247.775L102.208,544.986L0,442.758l145.546-145.547">
|
<path fill="#888" d="M0,151.656l102.208-102.22l247.777,247.775L102.208,544.986L0,442.758l145.546-145.547">
|
||||||
</svg>
|
</svg>`);
|
||||||
`);
|
|
||||||
|
|
||||||
document.getElementById("td-skip").addEventListener("click", function(){
|
document.getElementById("td-skip").addEventListener("click", function(){
|
||||||
$TD.loadNextNotification();
|
$TD.loadNextNotification();
|
||||||
@@ -150,4 +142,9 @@
|
|||||||
document.body.addEventListener("mouseleave", function(){
|
document.body.addEventListener("mouseleave", function(){
|
||||||
document.body.classList.remove("td-hover");
|
document.body.classList.remove("td-hover");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//
|
||||||
|
// Block: Force a reset of scroll position on every load.
|
||||||
|
//
|
||||||
|
history.scrollRestoration = "manual";
|
||||||
})($TD, $TDX);
|
})($TD, $TDX);
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
(function(){
|
(function(){
|
||||||
var isReloading = false;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Class: Abstract plugin base class.
|
// Class: Abstract plugin base class.
|
||||||
//
|
//
|
||||||
@@ -107,12 +105,16 @@
|
|||||||
//
|
//
|
||||||
// Block: Setup a function to reload the page.
|
// Block: Setup a function to reload the page.
|
||||||
//
|
//
|
||||||
|
(function(){
|
||||||
|
let isReloading = false;
|
||||||
|
|
||||||
window.TDPF_requestReload = function(){
|
window.TDPF_requestReload = function(){
|
||||||
if (!isReloading){
|
if (!isReloading){
|
||||||
window.setTimeout(window.TDGF_reload, 1);
|
window.setTimeout(window.TDGF_reload, 1);
|
||||||
isReloading = true;
|
isReloading = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Setup bridges to global functions.
|
// Block: Setup bridges to global functions.
|
||||||
@@ -121,4 +123,7 @@
|
|||||||
window.TDPF_playVideo = window.TDGF_playVideo;
|
window.TDPF_playVideo = window.TDGF_playVideo;
|
||||||
window.TDPF_reloadColumns = window.TDGF_reloadColumns;
|
window.TDPF_reloadColumns = window.TDGF_reloadColumns;
|
||||||
window.TDPF_prioritizeNewestEvent = window.TDGF_prioritizeNewestEvent;
|
window.TDPF_prioritizeNewestEvent = window.TDGF_prioritizeNewestEvent;
|
||||||
|
window.TDPF_injectMustache = window.TDGF_injectMustache;
|
||||||
|
|
||||||
|
#import "scripts/plugins.base.js"
|
||||||
})();
|
})();
|
||||||
|
@@ -14,3 +14,5 @@ window.TD_PLUGINS = {
|
|||||||
plugin.obj.run();
|
plugin.obj.run();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#import "scripts/plugins.base.js"
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
let avatarBottom = avatar ? avatar.getBoundingClientRect().bottom : 0;
|
let avatarBottom = avatar ? avatar.getBoundingClientRect().bottom : 0;
|
||||||
|
|
||||||
$TD.setHeight(Math.floor(Math.max(contentHeight, avatarBottom+9))).then(() => {
|
$TD.setHeight(Math.floor(Math.max(contentHeight, avatarBottom+9))).then(() => {
|
||||||
let framesLeft = 5; // basic render is done in 1 frame, large media take longer
|
let framesLeft = {frames}; // basic render is done in 1 frame, large media take longer
|
||||||
|
|
||||||
let onNextFrame = function(){
|
let onNextFrame = function(){
|
||||||
if (--framesLeft < 0){
|
if (--framesLeft < 0){
|
||||||
|
@@ -150,6 +150,7 @@ button {
|
|||||||
|
|
||||||
.activity-header .icon-user-filled {
|
.activity-header .icon-user-filled {
|
||||||
vertical-align: sub !important;
|
vertical-align: sub !important;
|
||||||
|
margin-right: 4px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
html[data-td-theme='light'] .stream-item:not(:hover) .js-user-actions-menu {
|
html[data-td-theme='light'] .stream-item:not(:hover) .js-user-actions-menu {
|
||||||
@@ -220,6 +221,50 @@ a[data-full-url] {
|
|||||||
bottom: 0 !important;
|
bottom: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**********************************************************/
|
||||||
|
/* Prevent column icons from being hidden by column title */
|
||||||
|
/**********************************************************/
|
||||||
|
|
||||||
|
.column-header-title {
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-heading {
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-header-links {
|
||||||
|
max-width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-td-icon="icon-message"] .column-header-links {
|
||||||
|
min-width: 86px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************/
|
||||||
|
/* Fix modal dialogs breaking when window size is too small */
|
||||||
|
/************************************************************/
|
||||||
|
|
||||||
|
.ovl:before, .overlay:before {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ovl, .overlay {
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ovl[style="display: block;"] {
|
||||||
|
display: flex !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tduck .overlay {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************/
|
/*******************************************/
|
||||||
/* Fix general visual issues or annoyances */
|
/* Fix general visual issues or annoyances */
|
||||||
/*******************************************/
|
/*******************************************/
|
||||||
@@ -234,6 +279,37 @@ a[data-full-url] {
|
|||||||
vertical-align: -10% !important;
|
vertical-align: -10% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.column-title {
|
||||||
|
/* fix alignment of everything in column headers */
|
||||||
|
padding-top: 1px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-title .attribution {
|
||||||
|
/* fix alignment of usernames in column headers */
|
||||||
|
margin: 0 0 0 6px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-navigator .tooltip {
|
||||||
|
/* fix tooltips in navigation */
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-header-links .icon {
|
||||||
|
/* fix tooltips in column headers */
|
||||||
|
height: calc(1em + 8px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-header-temp:not(.js-column-header) {
|
||||||
|
/* fix missing column header padding in Edit List dialog */
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-column-options .btn-options-tray {
|
||||||
|
/* fix underline on buttons in column options */
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
#tduck .nav-user-info .hide-condensed {
|
#tduck .nav-user-info .hide-condensed {
|
||||||
/* move login account info */
|
/* move login account info */
|
||||||
margin: 0px !important;
|
margin: 0px !important;
|
||||||
@@ -241,7 +317,7 @@ a[data-full-url] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
html[data-td-font='smallest'] .sprite-verified-mini {
|
html[data-td-font='smallest'] .sprite-verified-mini {
|
||||||
/* fix cut off badge when zoomed in */
|
/* fix cut off badge in timelines */
|
||||||
width: 13px !important;
|
width: 13px !important;
|
||||||
height: 13px !important;
|
height: 13px !important;
|
||||||
background-position: -223px -99px !important;
|
background-position: -223px -99px !important;
|
||||||
@@ -261,11 +337,21 @@ html[data-td-font='smallest'] .tweet-detail-wrapper .badge-verified:before {
|
|||||||
background-position: -223px -97px !important;
|
background-position: -223px -97px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html[data-td-font='smallest'] .fullname-badged:before, html[data-td-font='small'] .fullname-badged:before {
|
||||||
|
/* fix cut off badge in follow chirps */
|
||||||
|
margin-top: -7px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.keyboard-shortcut-list {
|
.keyboard-shortcut-list {
|
||||||
/* fix keyboard navigation alignment */
|
/* fix keyboard navigation alignment */
|
||||||
vertical-align: top !important;
|
vertical-align: top !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.column-message.is-actionable span:hover > .icon-small-valigned {
|
||||||
|
/* add a visual response when hovering individual filter icons; black theme uses a value of 20 */
|
||||||
|
filter: saturate(10);
|
||||||
|
}
|
||||||
|
|
||||||
.tweet-detail-wrapper .js-media-gif-container {
|
.tweet-detail-wrapper .js-media-gif-container {
|
||||||
/* GIFs in detail view don't trigger the pointer cursor */
|
/* GIFs in detail view don't trigger the pointer cursor */
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -290,9 +376,9 @@ html[data-td-font='smallest'] .tweet-detail-wrapper .badge-verified:before {
|
|||||||
/* Fix glaring visual issues that twitter hasn't fixed yet smh */
|
/* Fix glaring visual issues that twitter hasn't fixed yet smh */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|
||||||
.column-nav-link .attribution {
|
.js-column-nav-list .attribution {
|
||||||
/* fix cut off account names */
|
/* fix cut off account names */
|
||||||
position: absolute !important;
|
line-height: 1.1 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#tduck .js-docked-compose .js-drawer-close {
|
#tduck .js-docked-compose .js-drawer-close {
|
||||||
@@ -311,25 +397,6 @@ html[data-td-font='smallest'] .tweet-detail-wrapper .badge-verified:before {
|
|||||||
vertical-align: -15% !important;
|
vertical-align: -15% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************/
|
|
||||||
/* Fix tooltips in navigation and column header */
|
|
||||||
/************************************************/
|
|
||||||
|
|
||||||
.app-navigator .tooltip {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-column-header .column-header-link {
|
|
||||||
padding: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-column-header .column-header-link .icon {
|
|
||||||
width: calc(1em + 8px);
|
|
||||||
height: 100%;
|
|
||||||
padding: 9px 4px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************/
|
/*******************************************/
|
||||||
/* Fix one pixel space below column header */
|
/* Fix one pixel space below column header */
|
||||||
/*******************************************/
|
/*******************************************/
|
||||||
@@ -342,10 +409,6 @@ html[data-td-font='smallest'] .tweet-detail-wrapper .badge-verified:before {
|
|||||||
border-bottom: none !important;
|
border-bottom: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-options-open .column-type-icon {
|
|
||||||
bottom: 27px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************/
|
/********************************************/
|
||||||
/* Fix cut off usernames in Messages column */
|
/* Fix cut off usernames in Messages column */
|
||||||
/********************************************/
|
/********************************************/
|
||||||
|
@@ -2,7 +2,9 @@
|
|||||||
/* General */
|
/* General */
|
||||||
/***********/
|
/***********/
|
||||||
|
|
||||||
body.td-notification {
|
html, body {
|
||||||
|
height: auto !important;
|
||||||
|
overflow-x: hidden !important;
|
||||||
overflow-y: auto !important;
|
overflow-y: auto !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,13 +61,25 @@ a[data-full-url] {
|
|||||||
/* Fix general visual issues or annoyances */
|
/* Fix general visual issues or annoyances */
|
||||||
/*******************************************/
|
/*******************************************/
|
||||||
|
|
||||||
|
html[data-td-font='smallest'] .sprite-verified-mini {
|
||||||
|
/* fix cut off badge in timelines */
|
||||||
|
width: 13px !important;
|
||||||
|
height: 13px !important;
|
||||||
|
background-position: -223px -99px !important;
|
||||||
|
}
|
||||||
|
|
||||||
html[data-td-font='smallest'] .badge-verified:before {
|
html[data-td-font='smallest'] .badge-verified:before {
|
||||||
/* fix cut off badge icon */
|
/* fix cut off badge in notifications */
|
||||||
width: 13px !important;
|
width: 13px !important;
|
||||||
height: 13px !important;
|
height: 13px !important;
|
||||||
background-position: -223px -98px !important;
|
background-position: -223px -98px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html[data-td-font='smallest'] .fullname-badged:before, html[data-td-font='small'] .fullname-badged:before {
|
||||||
|
/* fix cut off badge in follow chirps */
|
||||||
|
margin-top: -7px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.account-inline .username {
|
.account-inline .username {
|
||||||
vertical-align: 10% !important;
|
vertical-align: 10% !important;
|
||||||
}
|
}
|
||||||
@@ -88,6 +102,7 @@ html[data-td-font='smallest'] .badge-verified:before {
|
|||||||
|
|
||||||
.activity-header .icon-user-filled {
|
.activity-header .icon-user-filled {
|
||||||
vertical-align: sub !important;
|
vertical-align: sub !important;
|
||||||
|
margin-right: 4px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.td-notification-padded .item-img {
|
.td-notification-padded .item-img {
|
||||||
@@ -136,7 +151,7 @@ html[data-td-font='smallest'] .badge-verified:before {
|
|||||||
|
|
||||||
#td-skip {
|
#td-skip {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 30px;
|
left: 29px;
|
||||||
bottom: 10px;
|
bottom: 10px;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@@ -2,40 +2,21 @@
|
|||||||
//
|
//
|
||||||
// Function: Inject custom CSS into the page.
|
// Function: Inject custom CSS into the page.
|
||||||
//
|
//
|
||||||
var injectCSS = function(){
|
const injectCSS = function(){
|
||||||
if (!document.head){
|
if (!document.head){
|
||||||
setTimeout(injectCSS, 5);
|
setTimeout(injectCSS, 5);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var style = document.createElement("style");
|
let style = document.createElement("style");
|
||||||
document.head.appendChild(style);
|
|
||||||
|
|
||||||
let addRule = (rule) => {
|
style.innerText = `#import "styles/twitter.base.css"`;
|
||||||
style.sheet.insertRule(rule, 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
addRule("body { overflow: hidden !important; }"); // remove scrollbar
|
|
||||||
addRule(".page-canvas { box-shadow: 0 0 150px rgba(255, 255, 255, 0.3) !important; }"); // change page box shadow
|
|
||||||
addRule(".topbar { display: none !important; }"); // hide top bar
|
|
||||||
|
|
||||||
addRule(".page-canvas, .buttons, .btn, input { border-radius: 0 !important; }"); // sharpen borders
|
|
||||||
addRule("input { padding: 5px 8px 4px !important; }"); // tweak input padding
|
|
||||||
addRule("button[type='submit'] { border: 1px solid rgba(0, 0, 0, 0.3) !important; border-radius: 0 !important; }"); // style buttons
|
|
||||||
|
|
||||||
addRule("#doc { width: 100%; height: 100%; margin: 0; position: absolute; display: table; }"); // center everything
|
|
||||||
addRule("#page-outer { display: table-cell; vertical-align: middle; }"); // center everything
|
|
||||||
addRule("#page-container { padding: 0 20px !important; width: 100% !important; box-sizing: border-box !important; }"); // center everything
|
|
||||||
addRule(".page-canvas { margin: 0 auto !important; }"); // center everything
|
|
||||||
|
|
||||||
if (location.pathname === "/logout"){
|
if (location.pathname === "/logout"){
|
||||||
addRule(".page-canvas { width: auto !important; max-width: 888px; }"); // fix min width
|
style.innerText += `#import "styles/twitter.logout.css"`;
|
||||||
addRule(".signout-wrapper { width: auto !important; margin: 0 auto !important; }"); // fix min width and margins
|
|
||||||
addRule(".signout { margin: 60px 0 54px !important; }"); // fix dialog margins
|
|
||||||
addRule(".buttons { padding-bottom: 0 !important; }"); // fix dialog margins
|
|
||||||
addRule(".aside { display: none; }"); // hide elements around logout dialog
|
|
||||||
addRule(".buttons button, .buttons a { display: inline-block; margin: 0 4px !important; border: 1px solid rgba(0, 0, 0, 0.3) !important; border-radius: 0 !important; }"); // style buttons
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.head.appendChild(style);
|
||||||
};
|
};
|
||||||
|
|
||||||
setTimeout(injectCSS, 1);
|
setTimeout(injectCSS, 1);
|
||||||
@@ -45,7 +26,7 @@
|
|||||||
//
|
//
|
||||||
if (location.pathname === "/login"){
|
if (location.pathname === "/login"){
|
||||||
document.addEventListener("DOMContentLoaded", function(){
|
document.addEventListener("DOMContentLoaded", function(){
|
||||||
let openLinkExternally = function(e){
|
const openLinkExternally = function(e){
|
||||||
let href = e.currentTarget.getAttribute("href");
|
let href = e.currentTarget.getAttribute("href");
|
||||||
$TD.openBrowser(href[0] === '/' ? location.origin+href : href);
|
$TD.openBrowser(href[0] === '/' ? location.origin+href : href);
|
||||||
|
|
||||||
@@ -53,10 +34,30 @@
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
let links = document.getElementsByTagName("A");
|
for(let link of document.getElementsByTagName("A")){
|
||||||
|
link.addEventListener("click", openLinkExternally);
|
||||||
|
}
|
||||||
|
|
||||||
for(let index = 0; index < links.length; index++){
|
let texts = document.querySelector(".page-canvas > div:last-child");
|
||||||
links[index].addEventListener("click", openLinkExternally);
|
|
||||||
|
if (texts){
|
||||||
|
texts.insertAdjacentHTML("beforeend", `<p class="tweetduck-helper">Used the TweetDuck app before? <a href="#">Import your profile »</a></p>`);
|
||||||
|
|
||||||
|
texts.querySelector(".tweetduck-helper > a").addEventListener("click", function(){
|
||||||
|
$TD.openProfileImport();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Block: Fix broken Cancel button on logout page.
|
||||||
|
//
|
||||||
|
else if (location.pathname === "/logout"){
|
||||||
|
document.addEventListener("DOMContentLoaded", function(){
|
||||||
|
let cancel = document.querySelector(".buttons .cancel");
|
||||||
|
|
||||||
|
if (cancel && cancel.tagName === "A"){
|
||||||
|
cancel.href = "https://tweetdeck.twitter.com/";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -1,215 +1,110 @@
|
|||||||
(function($, $TDU){
|
(function($TDU){
|
||||||
//
|
//
|
||||||
// Function: Creates the update notification element. Removes the old one if already exists.
|
// Function: Creates the update notification element. Removes the old one if already exists.
|
||||||
//
|
//
|
||||||
var displayNotification = function(version, changelog){
|
const displayNotification = function(version, changelog){
|
||||||
|
|
||||||
// styles
|
// styles
|
||||||
var css = $("#tweetduck-update-css");
|
let css = document.getElementById("tweetduck-update-css");
|
||||||
|
|
||||||
if (!css.length){
|
if (!css){
|
||||||
css = $(`
|
css = document.createElement("style");
|
||||||
<style id='tweetduck-update-css'>
|
css.id = "tweetduck-update-css";
|
||||||
#tweetduck-update {
|
css.innerText = `#import "styles/update.css"`;
|
||||||
position: absolute;
|
document.head.appendChild(css);
|
||||||
bottom: 0;
|
|
||||||
width: 200px;
|
|
||||||
height: 178px;
|
|
||||||
z-index: 9999;
|
|
||||||
color: #fff;
|
|
||||||
background-color: rgb(32, 94, 138);
|
|
||||||
text-align: center;
|
|
||||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
#tweetduck-update .tdu-title {
|
|
||||||
font-size: 15px;
|
|
||||||
font-weight: bold;
|
|
||||||
margin: 8px 0 2px;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tweetduck-update .tdu-info {
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 14px;
|
|
||||||
margin: 3px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tweetduck-update .tdu-showlog {
|
|
||||||
text-decoration: underline;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tweetduck-update .tdu-buttons button {
|
|
||||||
display: block;
|
|
||||||
margin: 7px auto 0;
|
|
||||||
padding: 4px 10px;
|
|
||||||
width: 80%;
|
|
||||||
height: 30px;
|
|
||||||
border: 0;
|
|
||||||
border-radius: 1px;
|
|
||||||
outline: none;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #fff;
|
|
||||||
background-color: #419de0;
|
|
||||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
|
|
||||||
box-shadow: 1px 1px 1px rgba(17, 17, 17, 0.5) !important;
|
|
||||||
transition: box-shadow 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tweetduck-update .tdu-buttons button:hover {
|
|
||||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.75);
|
|
||||||
box-shadow: 1px 1px 1px rgba(17, 17, 17, 0.75), 0 -2px 0 rgba(17, 17, 17, 0.33) inset !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tweetduck-update .tdu-buttons button.tdu-btn-ignore, .tdu-buttons button.tdu-btn-later {
|
|
||||||
background-color: #607a8e;
|
|
||||||
color: #dfdfdf;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tweetduck-changelog {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
z-index: 9998;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tweetduck-changelog-box {
|
|
||||||
position: absolute;
|
|
||||||
width: 60%;
|
|
||||||
height: 75%;
|
|
||||||
max-width: calc(90% - 200px);
|
|
||||||
max-height: 90%;
|
|
||||||
left: calc(50% + 100px);
|
|
||||||
top: 50%;
|
|
||||||
padding: 12px;
|
|
||||||
overflow-y: auto;
|
|
||||||
transform: translateX(-50%) translateY(-50%);
|
|
||||||
font-size: 14px;
|
|
||||||
color: #000;
|
|
||||||
background-color: #fff;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tweetduck-changelog h2 {
|
|
||||||
margin: 0 0 7px;
|
|
||||||
font-size: 23px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tweetduck-changelog h2 + br {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tweetduck-changelog h3 {
|
|
||||||
margin: 0 0 5px 7px;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tweetduck-changelog p {
|
|
||||||
margin: 8px 8px 0 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tweetduck-changelog p.li {
|
|
||||||
margin: 0 8px 2px 30px;
|
|
||||||
display: list-item;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tweetduck-changelog p.l2 {
|
|
||||||
margin-left: 50px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tweetduck-changelog a {
|
|
||||||
color: #247fbb;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tweetduck-changelog code {
|
|
||||||
padding: 0 4px;
|
|
||||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
|
||||||
color: #24292e;
|
|
||||||
background-color: rgba(27, 31, 35, 0.05);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
`).appendTo(document.head);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// changelog
|
// changelog
|
||||||
var log = $("#tweetduck-changelog");
|
let log = document.getElementById("tweetduck-changelog");
|
||||||
|
|
||||||
if (!log.length){
|
if (!log){
|
||||||
var log = $(`
|
log = document.createElement("div");
|
||||||
<div id='tweetduck-changelog'>
|
log.id = "tweetduck-changelog";
|
||||||
<div id='tweetduck-changelog-box'>
|
log.style.display = "none";
|
||||||
|
log.innerHTML = `
|
||||||
|
<div id='tweetduck-changelog-box'>
|
||||||
<h2>TweetDuck Update ${version}</h2>
|
<h2>TweetDuck Update ${version}</h2>
|
||||||
${markdown(atob(changelog))}
|
${markdown(atob(changelog))}
|
||||||
</div>
|
</div>`;
|
||||||
</div>
|
|
||||||
`).appendTo(document.body).css("display", "none");
|
document.body.appendChild(log);
|
||||||
}
|
}
|
||||||
|
|
||||||
// notification
|
// notification
|
||||||
var ele = $("#tweetduck-update");
|
let ele = document.getElementById("tweetduck-update");
|
||||||
var existed = ele.length > 0;
|
let existed = !!ele;
|
||||||
|
|
||||||
if (existed){
|
if (existed){
|
||||||
ele.remove();
|
ele.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
ele = $(`
|
ele = document.createElement("div");
|
||||||
<div id='tweetduck-update'>
|
ele.id = "tweetduck-update";
|
||||||
<p class='tdu-title'>T weetDuck Update ${version}</p>
|
ele.innerHTML = `
|
||||||
<p class='tdu-info tdu-showlog'>View update information</p>
|
<p class='tdu-title'>T weetDuck Update ${version}</p>
|
||||||
<div class='tdu-buttons'>
|
<p class='tdu-info tdu-showlog'>View update information</p>
|
||||||
|
<div class='tdu-buttons'>
|
||||||
<button class='tdu-btn-download'>Update now</button>
|
<button class='tdu-btn-download'>Update now</button>
|
||||||
<button class='tdu-btn-later'>Remind me later</button>
|
<button class='tdu-btn-later'>Remind me later</button>
|
||||||
<button class='tdu-btn-ignore'>Ignore this update</button>
|
<button class='tdu-btn-ignore'>Ignore this update</button>
|
||||||
</div>
|
</div>`;
|
||||||
</div>
|
|
||||||
`).appendTo(document.body).css("display", existed ? "block" : "none");
|
|
||||||
|
|
||||||
// ui logic
|
if (!existed){
|
||||||
var hide = function(){
|
ele.classList.add("hidden-below");
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.appendChild(ele);
|
||||||
|
|
||||||
|
// ui functions
|
||||||
|
const exitNow = function(){
|
||||||
ele.remove();
|
ele.remove();
|
||||||
log.remove();
|
log.remove();
|
||||||
css.remove();
|
css.remove();
|
||||||
};
|
};
|
||||||
|
|
||||||
var slide = function(){
|
const exitSlide = function(){
|
||||||
log.hide();
|
log.style.display = "none";
|
||||||
ele.slideUp(hide);
|
|
||||||
|
ele.classList.add("hidden-below");
|
||||||
|
setTimeout(exitNow, 400);
|
||||||
};
|
};
|
||||||
|
|
||||||
ele.children(".tdu-showlog").click(function(){
|
const onClick = function(element, callback){
|
||||||
log.toggle();
|
element.addEventListener("click", callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ui listeners
|
||||||
|
onClick(ele.querySelector(".tdu-showlog"), function(){
|
||||||
|
log.style.display = window.getComputedStyle(log).display === "none" ? "block" : "none";
|
||||||
});
|
});
|
||||||
|
|
||||||
log.click(function(){
|
onClick(log, function(){
|
||||||
log.hide();
|
log.style.display = "none";
|
||||||
}).children().first().click(function(e){
|
});
|
||||||
|
|
||||||
|
onClick(log.children[0], function(e){
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
});
|
});
|
||||||
|
|
||||||
var buttonDiv = ele.children(".tdu-buttons").first();
|
onClick(ele.querySelector(".tdu-btn-download"), function(){
|
||||||
|
exitNow();
|
||||||
buttonDiv.children(".tdu-btn-download").click(function(){
|
|
||||||
hide();
|
|
||||||
$TDU.onUpdateAccepted();
|
$TDU.onUpdateAccepted();
|
||||||
});
|
});
|
||||||
|
|
||||||
buttonDiv.children(".tdu-btn-later").click(function(){
|
onClick(ele.querySelector(".tdu-btn-later"), function(){
|
||||||
$TDU.onUpdateDelayed();
|
$TDU.onUpdateDelayed();
|
||||||
slide();
|
exitSlide();
|
||||||
});
|
});
|
||||||
|
|
||||||
buttonDiv.children(".tdu-btn-ignore").click(function(){
|
onClick(ele.querySelector(".tdu-btn-ignore"), function(){
|
||||||
$TDU.onUpdateDismissed();
|
$TDU.onUpdateDismissed();
|
||||||
slide();
|
exitSlide();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// finalize notification
|
||||||
if (!existed){
|
if (!existed){
|
||||||
ele.slideDown();
|
ele.getBoundingClientRect(); // reflow
|
||||||
|
ele.classList.remove("hidden-below");
|
||||||
}
|
}
|
||||||
|
|
||||||
return ele;
|
return ele;
|
||||||
@@ -218,7 +113,7 @@
|
|||||||
//
|
//
|
||||||
// Function: Ghetto-converts markdown to HTML.
|
// Function: Ghetto-converts markdown to HTML.
|
||||||
//
|
//
|
||||||
var markdown = function(md){
|
const markdown = function(md){
|
||||||
return md.replace(/&/g, "&")
|
return md.replace(/&/g, "&")
|
||||||
.replace(/</g, "<")
|
.replace(/</g, "<")
|
||||||
.replace(/>/g, ">")
|
.replace(/>/g, ">")
|
||||||
@@ -237,12 +132,17 @@
|
|||||||
//
|
//
|
||||||
// Block: Check updates on startup.
|
// Block: Check updates on startup.
|
||||||
//
|
//
|
||||||
|
if ("$" in window && typeof $._data === "function" && "TD" in $._data(document, "events")){
|
||||||
$(document).one("TD.ready", function(){
|
$(document).one("TD.ready", function(){
|
||||||
$TDU.triggerUpdateCheck();
|
$TDU.triggerUpdateCheck();
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$TDU.triggerUpdateCheck();
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Setup global functions.
|
// Block: Setup global functions.
|
||||||
//
|
//
|
||||||
window.TDUF_displayNotification = displayNotification;
|
window.TDUF_displayNotification = displayNotification;
|
||||||
})($, $TDU);
|
})($TDU);
|
||||||
|
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 31 KiB |
139
TweetDuck.csproj
@@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<Import Project="packages\CefSharp.WinForms.64.0.0-CI2508\build\CefSharp.WinForms.props" Condition="Exists('packages\CefSharp.WinForms.64.0.0-CI2508\build\CefSharp.WinForms.props')" />
|
<Import Project="packages\CefSharp.WinForms.67.0.0-CI2662\build\CefSharp.WinForms.props" Condition="Exists('packages\CefSharp.WinForms.67.0.0-CI2662\build\CefSharp.WinForms.props')" />
|
||||||
<Import Project="packages\CefSharp.Common.64.0.0-CI2508\build\CefSharp.Common.props" Condition="Exists('packages\CefSharp.Common.64.0.0-CI2508\build\CefSharp.Common.props')" />
|
<Import Project="packages\CefSharp.Common.67.0.0-CI2662\build\CefSharp.Common.props" Condition="Exists('packages\CefSharp.Common.67.0.0-CI2662\build\CefSharp.Common.props')" />
|
||||||
<Import Project="packages\cef.redist.x86.3.3282.1731\build\cef.redist.x86.props" Condition="Exists('packages\cef.redist.x86.3.3282.1731\build\cef.redist.x86.props')" />
|
<Import Project="packages\cef.redist.x86.3.3396.1777\build\cef.redist.x86.props" Condition="Exists('packages\cef.redist.x86.3.3396.1777\build\cef.redist.x86.props')" />
|
||||||
<Import Project="packages\cef.redist.x64.3.3282.1731\build\cef.redist.x64.props" Condition="Exists('packages\cef.redist.x64.3.3282.1731\build\cef.redist.x64.props')" />
|
<Import Project="packages\cef.redist.x64.3.3396.1777\build\cef.redist.x64.props" Condition="Exists('packages\cef.redist.x64.3.3396.1777\build\cef.redist.x64.props')" />
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
@@ -15,25 +15,13 @@
|
|||||||
<AssemblyName>TweetDuck</AssemblyName>
|
<AssemblyName>TweetDuck</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<ApplicationIcon>Resources\Images\icon.ico</ApplicationIcon>
|
||||||
<NuGetPackageImportStamp>
|
<NuGetPackageImportStamp>
|
||||||
</NuGetPackageImportStamp>
|
</NuGetPackageImportStamp>
|
||||||
<TargetFrameworkProfile>
|
</PropertyGroup>
|
||||||
</TargetFrameworkProfile>
|
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
|
||||||
<PublishUrl>publish\</PublishUrl>
|
<StartArguments>-datafolder TweetDuckDebug</StartArguments>
|
||||||
<Install>true</Install>
|
|
||||||
<InstallFrom>Disk</InstallFrom>
|
|
||||||
<UpdateEnabled>false</UpdateEnabled>
|
|
||||||
<UpdateMode>Foreground</UpdateMode>
|
|
||||||
<UpdateInterval>7</UpdateInterval>
|
|
||||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
|
||||||
<UpdatePeriodically>false</UpdatePeriodically>
|
|
||||||
<UpdateRequired>false</UpdateRequired>
|
|
||||||
<MapFileExtensions>true</MapFileExtensions>
|
|
||||||
<ApplicationRevision>0</ApplicationRevision>
|
|
||||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
|
||||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
|
||||||
<UseApplicationTrust>false</UseApplicationTrust>
|
|
||||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
@@ -44,23 +32,15 @@
|
|||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<Prefer32Bit>false</Prefer32Bit>
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
|
||||||
<LangVersion>7</LangVersion>
|
<LangVersion>7</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
|
||||||
<ApplicationIcon>Resources\icon.ico</ApplicationIcon>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||||
<OutputPath>bin\x86\Release\</OutputPath>
|
<OutputPath>bin\x86\Release\</OutputPath>
|
||||||
<Optimize>true</Optimize>
|
<Optimize>true</Optimize>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
|
||||||
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
||||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<DefineConstants>
|
|
||||||
</DefineConstants>
|
|
||||||
<Prefer32Bit>false</Prefer32Bit>
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
<LangVersion>7</LangVersion>
|
<LangVersion>7</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -94,6 +74,8 @@
|
|||||||
<Compile Include="Core\FormManager.cs" />
|
<Compile Include="Core\FormManager.cs" />
|
||||||
<Compile Include="Core\Handling\ContextMenuGuide.cs" />
|
<Compile Include="Core\Handling\ContextMenuGuide.cs" />
|
||||||
<Compile Include="Core\Handling\DragHandlerBrowser.cs" />
|
<Compile Include="Core\Handling\DragHandlerBrowser.cs" />
|
||||||
|
<Compile Include="Core\Handling\Filters\ResponseFilterBase.cs" />
|
||||||
|
<Compile Include="Core\Handling\Filters\ResponseFilterVendor.cs" />
|
||||||
<Compile Include="Core\Handling\General\BrowserProcessHandler.cs" />
|
<Compile Include="Core\Handling\General\BrowserProcessHandler.cs" />
|
||||||
<Compile Include="Core\Handling\ContextMenuBase.cs" />
|
<Compile Include="Core\Handling\ContextMenuBase.cs" />
|
||||||
<Compile Include="Core\Handling\ContextMenuBrowser.cs" />
|
<Compile Include="Core\Handling\ContextMenuBrowser.cs" />
|
||||||
@@ -327,11 +309,6 @@
|
|||||||
<Compile Include="Updates\Events\UpdateEventArgs.cs" />
|
<Compile Include="Updates\Events\UpdateEventArgs.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<BootstrapperPackage Include=".NETFramework,Version=v4.0,Profile=Client">
|
|
||||||
<Visible>False</Visible>
|
|
||||||
<ProductName>Microsoft .NET Framework 4 Client Profile %28x86 and x64%29</ProductName>
|
|
||||||
<Install>true</Install>
|
|
||||||
</BootstrapperPackage>
|
|
||||||
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||||
<Visible>False</Visible>
|
<Visible>False</Visible>
|
||||||
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
|
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
|
||||||
@@ -342,11 +319,6 @@
|
|||||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||||
<Install>false</Install>
|
<Install>false</Install>
|
||||||
</BootstrapperPackage>
|
</BootstrapperPackage>
|
||||||
<BootstrapperPackage Include="Microsoft.Windows.Installer.4.5">
|
|
||||||
<Visible>False</Visible>
|
|
||||||
<ProductName>Windows Installer 4.5</ProductName>
|
|
||||||
<Install>true</Install>
|
|
||||||
</BootstrapperPackage>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="Core\FormBrowser.resx">
|
<EmbeddedResource Include="Core\FormBrowser.resx">
|
||||||
@@ -359,36 +331,54 @@
|
|||||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<ContentWithTargetPath Include="Resources\icon.ico">
|
|
||||||
<TargetPath>icon.ico</TargetPath>
|
|
||||||
</ContentWithTargetPath>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
<None Include="Resources\icon-small.ico" />
|
<None Include="Resources\Images\avatar.png" />
|
||||||
<None Include="Resources\icon-tray-new.ico" />
|
<None Include="Resources\Images\icon.ico" />
|
||||||
<None Include="Resources\icon-tray.ico" />
|
<None Include="Resources\Images\icon-tray-muted.ico" />
|
||||||
|
<None Include="Resources\Images\icon-muted.ico" />
|
||||||
|
<None Include="Resources\Images\icon-small.ico" />
|
||||||
|
<None Include="Resources\Images\icon-tray-new.ico" />
|
||||||
|
<None Include="Resources\Images\icon-tray.ico" />
|
||||||
|
<None Include="Resources\Images\spinner.apng" />
|
||||||
<None Include="Resources\PostBuild.ps1" />
|
<None Include="Resources\PostBuild.ps1" />
|
||||||
<None Include="Resources\spinner.apng" />
|
<None Include="Resources\Plugins\.debug\.meta" />
|
||||||
</ItemGroup>
|
<None Include="Resources\Plugins\.debug\browser.js" />
|
||||||
<ItemGroup>
|
<None Include="Resources\Plugins\clear-columns\.meta" />
|
||||||
<Folder Include="Resources\Plugins\" />
|
<None Include="Resources\Plugins\clear-columns\browser.js" />
|
||||||
</ItemGroup>
|
<None Include="Resources\Plugins\edit-design\.meta" />
|
||||||
<ItemGroup>
|
<None Include="Resources\Plugins\edit-design\browser.js" />
|
||||||
<Content Include="Resources\avatar.png" />
|
<None Include="Resources\Plugins\edit-design\modal.html" />
|
||||||
<Content Include="Resources\Scripts\code.js" />
|
<None Include="Resources\Plugins\edit-design\theme.black.css" />
|
||||||
<Content Include="Resources\Scripts\introduction.js" />
|
<None Include="Resources\Plugins\emoji-keyboard\.meta" />
|
||||||
<Content Include="Resources\Scripts\notification.js" />
|
<None Include="Resources\Plugins\emoji-keyboard\browser.js" />
|
||||||
<Content Include="Resources\Scripts\pages\error.html" />
|
<None Include="Resources\Plugins\emoji-keyboard\emoji-instructions.txt" />
|
||||||
<Content Include="Resources\Scripts\pages\example.html" />
|
<None Include="Resources\Plugins\emoji-keyboard\emoji-ordering.txt" />
|
||||||
<Content Include="Resources\Scripts\plugins.browser.js" />
|
<None Include="Resources\Plugins\reply-account\.meta" />
|
||||||
<Content Include="Resources\Scripts\plugins.js" />
|
<None Include="Resources\Plugins\reply-account\browser.js" />
|
||||||
<Content Include="Resources\Scripts\plugins.notification.js" />
|
<None Include="Resources\Plugins\reply-account\configuration.default.js" />
|
||||||
<Content Include="Resources\Scripts\styles\browser.css" />
|
<None Include="Resources\Plugins\templates\.meta" />
|
||||||
<Content Include="Resources\Scripts\styles\notification.css" />
|
<None Include="Resources\Plugins\templates\browser.js" />
|
||||||
<Content Include="Resources\Scripts\twitter.js" />
|
<None Include="Resources\Plugins\templates\modal.html" />
|
||||||
<Content Include="Resources\Scripts\update.js" />
|
<None Include="Resources\Plugins\timeline-polls\.meta" />
|
||||||
|
<None Include="Resources\Plugins\timeline-polls\browser.js" />
|
||||||
|
<None Include="Resources\Scripts\code.js" />
|
||||||
|
<None Include="Resources\Scripts\imports\scripts\plugins.base.js" />
|
||||||
|
<None Include="Resources\Scripts\imports\styles\introduction.css" />
|
||||||
|
<None Include="Resources\Scripts\imports\styles\twitter.base.css" />
|
||||||
|
<None Include="Resources\Scripts\imports\styles\twitter.logout.css" />
|
||||||
|
<None Include="Resources\Scripts\imports\styles\update.css" />
|
||||||
|
<None Include="Resources\Scripts\introduction.js" />
|
||||||
|
<None Include="Resources\Scripts\notification.js" />
|
||||||
|
<None Include="Resources\Scripts\pages\error.html" />
|
||||||
|
<None Include="Resources\Scripts\pages\example.html" />
|
||||||
|
<None Include="Resources\Scripts\plugins.browser.js" />
|
||||||
|
<None Include="Resources\Scripts\plugins.notification.js" />
|
||||||
|
<None Include="Resources\Scripts\screenshot.js" />
|
||||||
|
<None Include="Resources\Scripts\styles\browser.css" />
|
||||||
|
<None Include="Resources\Scripts\styles\notification.css" />
|
||||||
|
<None Include="Resources\Scripts\twitter.js" />
|
||||||
|
<None Include="Resources\Scripts\update.js" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="subprocess\TweetDuck.Browser.csproj">
|
<ProjectReference Include="subprocess\TweetDuck.Browser.csproj">
|
||||||
@@ -420,6 +410,7 @@ powershell -ExecutionPolicy Unrestricted -File "$(ProjectDir)Resources\PostBuild
|
|||||||
<Exec Command="del "$(TargetDir)*.xml"" />
|
<Exec Command="del "$(TargetDir)*.xml"" />
|
||||||
<Delete Files="$(TargetDir)CefSharp.BrowserSubprocess.exe" />
|
<Delete Files="$(TargetDir)CefSharp.BrowserSubprocess.exe" />
|
||||||
<Delete Files="$(TargetDir)widevinecdmadapter.dll" />
|
<Delete Files="$(TargetDir)widevinecdmadapter.dll" />
|
||||||
|
<Exec Command=""$(ProjectDir)bld\UPDATE ONLY.bat"" WorkingDirectory="$(ProjectDir)bld\" IgnoreExitCode="true" />
|
||||||
</Target>
|
</Target>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PreBuildEvent>powershell Get-Process TweetDuck.Browser -ErrorAction SilentlyContinue ^| Where-Object {$_.Path -eq '$(TargetDir)TweetDuck.Browser.exe'} ^| Stop-Process; Exit 0</PreBuildEvent>
|
<PreBuildEvent>powershell Get-Process TweetDuck.Browser -ErrorAction SilentlyContinue ^| Where-Object {$_.Path -eq '$(TargetDir)TweetDuck.Browser.exe'} ^| Stop-Process; Exit 0</PreBuildEvent>
|
||||||
@@ -428,13 +419,11 @@ powershell -ExecutionPolicy Unrestricted -File "$(ProjectDir)Resources\PostBuild
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Error Condition="!Exists('packages\cef.redist.x64.3.3282.1731\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\cef.redist.x64.3.3282.1731\build\cef.redist.x64.props'))" />
|
<Error Condition="!Exists('packages\cef.redist.x64.3.3396.1777\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\cef.redist.x64.3.3396.1777\build\cef.redist.x64.props'))" />
|
||||||
<Error Condition="!Exists('packages\cef.redist.x86.3.3282.1731\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\cef.redist.x86.3.3282.1731\build\cef.redist.x86.props'))" />
|
<Error Condition="!Exists('packages\cef.redist.x86.3.3396.1777\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\cef.redist.x86.3.3396.1777\build\cef.redist.x86.props'))" />
|
||||||
<Error Condition="!Exists('packages\CefSharp.Common.64.0.0-CI2508\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.64.0.0-CI2508\build\CefSharp.Common.props'))" />
|
<Error Condition="!Exists('packages\CefSharp.Common.67.0.0-CI2662\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.67.0.0-CI2662\build\CefSharp.Common.props'))" />
|
||||||
<Error Condition="!Exists('packages\CefSharp.Common.64.0.0-CI2508\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.64.0.0-CI2508\build\CefSharp.Common.targets'))" />
|
<Error Condition="!Exists('packages\CefSharp.Common.67.0.0-CI2662\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.67.0.0-CI2662\build\CefSharp.Common.targets'))" />
|
||||||
<Error Condition="!Exists('packages\CefSharp.WinForms.64.0.0-CI2508\build\CefSharp.WinForms.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.WinForms.64.0.0-CI2508\build\CefSharp.WinForms.props'))" />
|
<Error Condition="!Exists('packages\CefSharp.WinForms.67.0.0-CI2662\build\CefSharp.WinForms.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.WinForms.67.0.0-CI2662\build\CefSharp.WinForms.props'))" />
|
||||||
<Error Condition="!Exists('packages\CefSharp.WinForms.64.0.0-CI2508\build\CefSharp.WinForms.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.WinForms.64.0.0-CI2508\build\CefSharp.WinForms.targets'))" />
|
|
||||||
</Target>
|
</Target>
|
||||||
<Import Project="packages\CefSharp.Common.64.0.0-CI2508\build\CefSharp.Common.targets" Condition="Exists('packages\CefSharp.Common.64.0.0-CI2508\build\CefSharp.Common.targets')" />
|
<Import Project="packages\CefSharp.Common.67.0.0-CI2662\build\CefSharp.Common.targets" Condition="Exists('packages\CefSharp.Common.67.0.0-CI2662\build\CefSharp.Common.targets')" />
|
||||||
<Import Project="packages\CefSharp.WinForms.64.0.0-CI2508\build\CefSharp.WinForms.targets" Condition="Exists('packages\CefSharp.WinForms.64.0.0-CI2508\build\CefSharp.WinForms.targets')" />
|
|
||||||
</Project>
|
</Project>
|
@@ -6,12 +6,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TweetDuck", "TweetDuck.cspr
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TweetDuck.Browser", "subprocess\TweetDuck.Browser.csproj", "{B10B0017-819E-4F71-870F-8256B36A26AA}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TweetDuck.Browser", "subprocess\TweetDuck.Browser.csproj", "{B10B0017-819E-4F71-870F-8256B36A26AA}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "tests\UnitTests.csproj", "{A958FA7A-4A2C-42A7-BFA0-159343483F4E}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TweetDuck.Video", "video\TweetDuck.Video.csproj", "{278B2D11-402D-44B6-B6A1-8FA67DB65565}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TweetDuck.Video", "video\TweetDuck.Video.csproj", "{278B2D11-402D-44B6-B6A1-8FA67DB65565}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TweetLib.Communication", "lib\TweetLib.Communication\TweetLib.Communication.csproj", "{72473763-4B9D-4FB6-A923-9364B2680F06}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TweetLib.Communication", "lib\TweetLib.Communication\TweetLib.Communication.csproj", "{72473763-4B9D-4FB6-A923-9364B2680F06}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TweetTest.System", "lib\TweetTest.System\TweetTest.System.csproj", "{A958FA7A-4A2C-42A7-BFA0-159343483F4E}"
|
||||||
|
EndProject
|
||||||
|
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "TweetTest.Unit", "lib\TweetTest.Unit\TweetTest.Unit.fsproj", "{EEE1071A-28FA-48B1-82A1-9CBDC5C3F2C3}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|x86 = Debug|x86
|
Debug|x86 = Debug|x86
|
||||||
@@ -26,9 +28,6 @@ Global
|
|||||||
{B10B0017-819E-4F71-870F-8256B36A26AA}.Debug|x86.Build.0 = Debug|x86
|
{B10B0017-819E-4F71-870F-8256B36A26AA}.Debug|x86.Build.0 = Debug|x86
|
||||||
{B10B0017-819E-4F71-870F-8256B36A26AA}.Release|x86.ActiveCfg = Release|x86
|
{B10B0017-819E-4F71-870F-8256B36A26AA}.Release|x86.ActiveCfg = Release|x86
|
||||||
{B10B0017-819E-4F71-870F-8256B36A26AA}.Release|x86.Build.0 = Release|x86
|
{B10B0017-819E-4F71-870F-8256B36A26AA}.Release|x86.Build.0 = Release|x86
|
||||||
{A958FA7A-4A2C-42A7-BFA0-159343483F4E}.Debug|x86.ActiveCfg = Debug|x86
|
|
||||||
{A958FA7A-4A2C-42A7-BFA0-159343483F4E}.Debug|x86.Build.0 = Debug|x86
|
|
||||||
{A958FA7A-4A2C-42A7-BFA0-159343483F4E}.Release|x86.ActiveCfg = Release|x86
|
|
||||||
{278B2D11-402D-44B6-B6A1-8FA67DB65565}.Debug|x86.ActiveCfg = Debug|x86
|
{278B2D11-402D-44B6-B6A1-8FA67DB65565}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
{278B2D11-402D-44B6-B6A1-8FA67DB65565}.Debug|x86.Build.0 = Debug|x86
|
{278B2D11-402D-44B6-B6A1-8FA67DB65565}.Debug|x86.Build.0 = Debug|x86
|
||||||
{278B2D11-402D-44B6-B6A1-8FA67DB65565}.Release|x86.ActiveCfg = Release|x86
|
{278B2D11-402D-44B6-B6A1-8FA67DB65565}.Release|x86.ActiveCfg = Release|x86
|
||||||
@@ -37,6 +36,12 @@ Global
|
|||||||
{72473763-4B9D-4FB6-A923-9364B2680F06}.Debug|x86.Build.0 = Debug|x86
|
{72473763-4B9D-4FB6-A923-9364B2680F06}.Debug|x86.Build.0 = Debug|x86
|
||||||
{72473763-4B9D-4FB6-A923-9364B2680F06}.Release|x86.ActiveCfg = Release|x86
|
{72473763-4B9D-4FB6-A923-9364B2680F06}.Release|x86.ActiveCfg = Release|x86
|
||||||
{72473763-4B9D-4FB6-A923-9364B2680F06}.Release|x86.Build.0 = Release|x86
|
{72473763-4B9D-4FB6-A923-9364B2680F06}.Release|x86.Build.0 = Release|x86
|
||||||
|
{A958FA7A-4A2C-42A7-BFA0-159343483F4E}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{A958FA7A-4A2C-42A7-BFA0-159343483F4E}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{A958FA7A-4A2C-42A7-BFA0-159343483F4E}.Release|x86.ActiveCfg = Debug|x86
|
||||||
|
{EEE1071A-28FA-48B1-82A1-9CBDC5C3F2C3}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{EEE1071A-28FA-48B1-82A1-9CBDC5C3F2C3}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{EEE1071A-28FA-48B1-82A1-9CBDC5C3F2C3}.Release|x86.ActiveCfg = Debug|x86
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web.Script.Serialization;
|
using System.Web.Script.Serialization;
|
||||||
using TweetDuck.Core.Utils;
|
using TweetDuck.Core.Utils;
|
||||||
@@ -28,7 +30,7 @@ namespace TweetDuck.Updates{
|
|||||||
result.SetCanceled();
|
result.SetCanceled();
|
||||||
}
|
}
|
||||||
else if (task.IsFaulted){
|
else if (task.IsFaulted){
|
||||||
result.SetException(task.Exception.InnerException);
|
result.SetException(ExpandWebException(task.Exception.InnerException));
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
try{
|
try{
|
||||||
@@ -59,5 +61,20 @@ namespace TweetDuck.Updates{
|
|||||||
|
|
||||||
return new UpdateInfo(versionTag, releaseNotes, downloadUrl, installerFolder);
|
return new UpdateInfo(versionTag, releaseNotes, downloadUrl, installerFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Exception ExpandWebException(Exception e){
|
||||||
|
if (e is WebException we && we.Response is HttpWebResponse response){
|
||||||
|
try{
|
||||||
|
using(Stream stream = response.GetResponseStream())
|
||||||
|
using(StreamReader reader = new StreamReader(stream, Encoding.GetEncoding(response.CharacterSet ?? "utf-8"))){
|
||||||
|
return new Reporter.ExpandedLogException(e, reader.ReadToEnd());
|
||||||
|
}
|
||||||
|
}catch{
|
||||||
|
// whatever
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,7 +22,7 @@ namespace TweetDuck.Updates{
|
|||||||
|
|
||||||
this.VersionTag = versionTag;
|
this.VersionTag = versionTag;
|
||||||
this.ReleaseNotes = releaseNotes;
|
this.ReleaseNotes = releaseNotes;
|
||||||
this.InstallerPath = Path.Combine(installerFolder, $"TweetDuck.{versionTag}.exe");;
|
this.InstallerPath = Path.Combine(installerFolder, $"TweetDuck.{versionTag}.exe");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BeginSilentDownload(){
|
public void BeginSilentDownload(){
|
||||||
|
@@ -1,30 +0,0 @@
|
|||||||
// Copyright <20> 2010-2016 The CefSharp Authors
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are
|
|
||||||
// met:
|
|
||||||
//
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
//
|
|
||||||
// * Redistributions in binary form must reproduce the above
|
|
||||||
// copyright notice, this list of conditions and the following disclaimer
|
|
||||||
// in the documentation and/or other materials provided with the
|
|
||||||
// distribution.
|
|
||||||
//
|
|
||||||
// * Neither the name of Google Inc. nor the name Chromium Embedded
|
|
||||||
// Framework nor the name CefSharp nor the names of its contributors
|
|
||||||
// may be used to endorse or promote products derived from this software
|
|
||||||
// without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|