From 29ba1c66cf1105ce577659e3abae27ea0c5bb3a9 Mon Sep 17 00:00:00 2001 From: Daniel van Noord Date: Sat, 23 Jan 2021 22:36:26 +0100 Subject: [PATCH 001/145] Moved most replace tooltip funcs to Main.js --- CookieMonster.js | 132 ++++++++++++++++++++++++----------------------- src/Disp.js | 56 +------------------- src/Main.js | 76 +++++++++++++++++++++++---- 3 files changed, 136 insertions(+), 128 deletions(-) diff --git a/CookieMonster.js b/CookieMonster.js index e07907d..dde6bfb 100644 --- a/CookieMonster.js +++ b/CookieMonster.js @@ -2352,31 +2352,10 @@ CM.Disp.CreateSimpleTooltip = function(placeholder, text, minWidth) { CM.Disp[placeholder].appendChild(desc); } -/** - * This function replaces the original .onmouseover functions of buildings so that it calls CM.Disp.Tooltip() - * CM.Disp.Tooltip() sets the tooltip type to 'b' - * It is called by CM.DelayInit() - * TODO: Place all ReplaceTooltip functions either under CM.DelayInit() or CM.ReplaceNative() - * TODO: Move this code to Main.js file - */ -CM.Disp.ReplaceTooltipBuild = function() { - CM.Disp.TooltipBuildBackup = []; - for (var i in Game.Objects) { - var me = Game.Objects[i]; - if (l('product' + me.id).onmouseover != null) { - CM.Disp.TooltipBuildBackup[i] = l('product' + me.id).onmouseover; - eval('l(\'product\' + me.id).onmouseover = function() {Game.tooltip.dynamic = 1; Game.tooltip.draw(this, function() {return CM.Disp.Tooltip(\'b\', \'' + i + '\');}, \'store\'); Game.tooltip.wobble();}'); - } - } -} - /** * This function replaces the original .onmouseover functions of upgrades so that it calls CM.Disp.Tooltip() * CM.Disp.Tooltip() sets the tooltip type to 'u' - * It is called by CM.ReplaceNative() - * TODO: Place all ReplaceTooltip functions either under CM.DelayInit() or CM.ReplaceNative() - * TODO: Move this code to Main.js file - * + * It is called by Game.RebuildUpgrades() through CM.ReplaceNative() and is therefore not permanent like the other ReplaceTooltip functions */ CM.Disp.ReplaceTooltipUpgrade = function() { CM.Disp.TooltipUpgradeBackup = []; @@ -2389,39 +2368,6 @@ CM.Disp.ReplaceTooltipUpgrade = function() { } } -/** - * This function replaces the original .onmouseover functions of the Grimoire minigame so that it calls CM.Disp.Tooltip() - * CM.Disp.Tooltip() sets the tooltip type to 'g' - * The function is called by CM.DelayInit() - * TODO: Place all ReplaceTooltip functions either under CM.DelayInit() or CM.ReplaceNative() - * TODO: Move this code to Main.js file - */ -CM.Disp.ReplaceTooltipGrimoire = function() { - if (Game.Objects['Wizard tower'].minigameLoaded) { - CM.Disp.TooltipGrimoireBackup = []; - for (var i in Game.Objects['Wizard tower'].minigame.spellsById) { - if (l('grimoireSpell' + i).onmouseover != null) { - CM.Disp.TooltipGrimoireBackup[i] = l('grimoireSpell' + i).onmouseover; - eval('l(\'grimoireSpell\' + i).onmouseover = function() {Game.tooltip.dynamic = 1; Game.tooltip.draw(this, function() {return CM.Disp.Tooltip(\'g\', \'' + i + '\');}, \'this\'); Game.tooltip.wobble();}'); - } - } - } -} - -/** - * This function replaces the original .onmouseover functions of sugar lumps so that it calls CM.Disp.Tooltip() - * CM.Disp.Tooltip() sets the tooltip type to 's' - * The function is called by CM.DelayInit() - * TODO: Place all ReplaceTooltip functions either under CM.DelayInit() or CM.ReplaceNative() - * TODO: Move this code to Main.js file - */ -CM.Disp.ReplaceTooltipLump = function() { - if (Game.canLumps()) { - CM.Disp.TooltipLumpBackup = l('lumps').onmouseover; - eval('l(\'lumps\').onmouseover = function() {Game.tooltip.dynamic = 1; Game.tooltip.draw(this, function() {return CM.Disp.Tooltip(\'s\', \'Lump\');}, \'this\'); Game.tooltip.wobble();}'); - } -}; - /** * This function enhance the standard tooltips by creating and changing l('tooltip') * The function is called by .onmouseover events that have replaced original code to use CM.Disp.Tooltip() @@ -4094,12 +4040,10 @@ CM.ReplaceNative = function() { CM.Backup.scriptLoaded = Game.scriptLoaded; Game.scriptLoaded = function(who, script) { CM.Backup.scriptLoaded(who, script); - CM.Disp.ReplaceTooltipGrimoire() + CM.Main.ReplaceTooltipGrimoire() CM.ReplaceNativeGrimoire(); } - // TODO: Move this ReplaceTooltip function too other ReplaceTooltip functions - // OR: Move all other into this function CM.Backup.RebuildUpgrades = Game.RebuildUpgrades; Game.RebuildUpgrades = function() { CM.Backup.RebuildUpgrades(); @@ -4107,7 +4051,6 @@ CM.ReplaceNative = function() { Game.CalculateGains(); } - CM.Backup.DescribeDragonAura = Game.DescribeDragonAura; /** * This functions adds the function CM.Disp.AddAuraInfo() to Game.DescribeDragonAura() @@ -4171,7 +4114,7 @@ CM.ReplaceNativeGrimoireLaunch = function() { eval('CM.Backup.GrimoireLaunchMod = ' + minigame.launch.toString().split('=this').join('= Game.Objects[\'Wizard tower\'].minigame')); Game.Objects['Wizard tower'].minigame.launch = function() { CM.Backup.GrimoireLaunchMod(); - CM.Disp.ReplaceTooltipGrimoire(); + CM.Main.ReplaceTooltipGrimoire(); CM.HasReplaceNativeGrimoireDraw = false; CM.ReplaceNativeGrimoireDraw(); } @@ -4286,9 +4229,7 @@ CM.DelayInit = function() { CM.Disp.CreateSimpleTooltip(CM.Disp.TooltipText[i][0], CM.Disp.TooltipText[i][1], CM.Disp.TooltipText[i][2]); } CM.Disp.CreateWrinklerButtons(); - CM.Disp.ReplaceTooltipBuild(); - CM.Disp.ReplaceTooltipGrimoire(); - CM.Disp.ReplaceTooltipLump(); + CM.Main.ReplaceTooltips(); CM.Main.AddWrinklerAreaDetect(); CM.Cache.InitCookiesDiff(); CM.ReplaceNative(); @@ -4313,6 +4254,69 @@ CM.DelayInit = function() { Game.Win('Third-party'); } +/******** + * Section: Functions related to first initizalition of CM */ + +/** + * This function call all functions that replace Game-tooltips with CM-enhanced tooltips + * It is called by CM.DelayInit() + */ +CM.Main.ReplaceTooltips = function() { + CM.Main.ReplaceTooltipBuild(); + CM.Main.ReplaceTooltipGrimoire(); + CM.Main.ReplaceTooltipLump(); +} + +/******** + * Section: Functions related to replacing tooltips */ + + +/** + * This function replaces the original .onmouseover functions of buildings so that it calls CM.Disp.Tooltip() + * CM.Disp.Tooltip() sets the tooltip type to 'b' + * It is called by CM.Main.ReplaceTooltips() + */ +CM.Main.ReplaceTooltipBuild = function() { + CM.Main.TooltipBuildBackup = []; + for (var i in Game.Objects) { + var me = Game.Objects[i]; + if (l('product' + me.id).onmouseover != null) { + CM.Main.TooltipBuildBackup[i] = l('product' + me.id).onmouseover; + eval('l(\'product\' + me.id).onmouseover = function() {Game.tooltip.dynamic = 1; Game.tooltip.draw(this, function() {return CM.Disp.Tooltip(\'b\', \'' + i + '\');}, \'store\'); Game.tooltip.wobble();}'); + } + } +} + +/** + * This function replaces the original .onmouseover functions of the Grimoire minigame so that it calls CM.Disp.Tooltip() + * CM.Disp.Tooltip() sets the tooltip type to 'g' + * It is called by CM.Main.ReplaceTooltips() + */ +CM.Main.ReplaceTooltipGrimoire = function() { + if (Game.Objects['Wizard tower'].minigameLoaded) { + CM.Main.TooltipGrimoireBackup = []; + for (var i in Game.Objects['Wizard tower'].minigame.spellsById) { + if (l('grimoireSpell' + i).onmouseover != null) { + CM.Main.TooltipGrimoireBackup[i] = l('grimoireSpell' + i).onmouseover; + eval('l(\'grimoireSpell\' + i).onmouseover = function() {Game.tooltip.dynamic = 1; Game.tooltip.draw(this, function() {return CM.Disp.Tooltip(\'g\', \'' + i + '\');}, \'this\'); Game.tooltip.wobble();}'); + } + } + } +} + +/** + * This function replaces the original .onmouseover functions of sugar lumps so that it calls CM.Disp.Tooltip() + * CM.Disp.Tooltip() sets the tooltip type to 's' + * It is called by CM.Main.ReplaceTooltips() + */ +CM.Main.ReplaceTooltipLump = function() { + if (Game.canLumps()) { + CM.Main.TooltipLumpBackup = l('lumps').onmouseover; + eval('l(\'lumps\').onmouseover = function() {Game.tooltip.dynamic = 1; Game.tooltip.draw(this, function() {return CM.Disp.Tooltip(\'s\', \'Lump\');}, \'this\'); Game.tooltip.wobble();}'); + } +}; + + /******** * Section: Functions related to checking for changes in Minigames/GC's/Ticker * TODO: Possibly move this section */ @@ -4478,7 +4482,7 @@ CM.Main.CheckWrinklerCount = function() { * This function creates .onmouseover/out events that determine if the mouse is hovering-over a Wrinkler * It is called by CM.DelayInit * TODO: The system for displaying wrinklers should ideally use a similar system as other tooltips - * Thus, writing a CM.Disp.ReplaceTooltipWrinkler function etc. + * Thus, writing a CM.Main.ReplaceTooltipWrinkler function etc. */ CM.Main.AddWrinklerAreaDetect = function() { l('backgroundLeftCanvas').onmouseover = function() {CM.Disp.TooltipWrinklerArea = 1;}; diff --git a/src/Disp.js b/src/Disp.js index 102f600..b900572 100644 --- a/src/Disp.js +++ b/src/Disp.js @@ -1171,31 +1171,10 @@ CM.Disp.CreateSimpleTooltip = function(placeholder, text, minWidth) { CM.Disp[placeholder].appendChild(desc); } -/** - * This function replaces the original .onmouseover functions of buildings so that it calls CM.Disp.Tooltip() - * CM.Disp.Tooltip() sets the tooltip type to 'b' - * It is called by CM.DelayInit() - * TODO: Place all ReplaceTooltip functions either under CM.DelayInit() or CM.ReplaceNative() - * TODO: Move this code to Main.js file - */ -CM.Disp.ReplaceTooltipBuild = function() { - CM.Disp.TooltipBuildBackup = []; - for (var i in Game.Objects) { - var me = Game.Objects[i]; - if (l('product' + me.id).onmouseover != null) { - CM.Disp.TooltipBuildBackup[i] = l('product' + me.id).onmouseover; - eval('l(\'product\' + me.id).onmouseover = function() {Game.tooltip.dynamic = 1; Game.tooltip.draw(this, function() {return CM.Disp.Tooltip(\'b\', \'' + i + '\');}, \'store\'); Game.tooltip.wobble();}'); - } - } -} - /** * This function replaces the original .onmouseover functions of upgrades so that it calls CM.Disp.Tooltip() * CM.Disp.Tooltip() sets the tooltip type to 'u' - * It is called by CM.ReplaceNative() - * TODO: Place all ReplaceTooltip functions either under CM.DelayInit() or CM.ReplaceNative() - * TODO: Move this code to Main.js file - * + * It is called by Game.RebuildUpgrades() through CM.ReplaceNative() and is therefore not permanent like the other ReplaceTooltip functions */ CM.Disp.ReplaceTooltipUpgrade = function() { CM.Disp.TooltipUpgradeBackup = []; @@ -1208,39 +1187,6 @@ CM.Disp.ReplaceTooltipUpgrade = function() { } } -/** - * This function replaces the original .onmouseover functions of the Grimoire minigame so that it calls CM.Disp.Tooltip() - * CM.Disp.Tooltip() sets the tooltip type to 'g' - * The function is called by CM.DelayInit() - * TODO: Place all ReplaceTooltip functions either under CM.DelayInit() or CM.ReplaceNative() - * TODO: Move this code to Main.js file - */ -CM.Disp.ReplaceTooltipGrimoire = function() { - if (Game.Objects['Wizard tower'].minigameLoaded) { - CM.Disp.TooltipGrimoireBackup = []; - for (var i in Game.Objects['Wizard tower'].minigame.spellsById) { - if (l('grimoireSpell' + i).onmouseover != null) { - CM.Disp.TooltipGrimoireBackup[i] = l('grimoireSpell' + i).onmouseover; - eval('l(\'grimoireSpell\' + i).onmouseover = function() {Game.tooltip.dynamic = 1; Game.tooltip.draw(this, function() {return CM.Disp.Tooltip(\'g\', \'' + i + '\');}, \'this\'); Game.tooltip.wobble();}'); - } - } - } -} - -/** - * This function replaces the original .onmouseover functions of sugar lumps so that it calls CM.Disp.Tooltip() - * CM.Disp.Tooltip() sets the tooltip type to 's' - * The function is called by CM.DelayInit() - * TODO: Place all ReplaceTooltip functions either under CM.DelayInit() or CM.ReplaceNative() - * TODO: Move this code to Main.js file - */ -CM.Disp.ReplaceTooltipLump = function() { - if (Game.canLumps()) { - CM.Disp.TooltipLumpBackup = l('lumps').onmouseover; - eval('l(\'lumps\').onmouseover = function() {Game.tooltip.dynamic = 1; Game.tooltip.draw(this, function() {return CM.Disp.Tooltip(\'s\', \'Lump\');}, \'this\'); Game.tooltip.wobble();}'); - } -}; - /** * This function enhance the standard tooltips by creating and changing l('tooltip') * The function is called by .onmouseover events that have replaced original code to use CM.Disp.Tooltip() diff --git a/src/Main.js b/src/Main.js index caa11b2..17ac29e 100644 --- a/src/Main.js +++ b/src/Main.js @@ -45,12 +45,10 @@ CM.ReplaceNative = function() { CM.Backup.scriptLoaded = Game.scriptLoaded; Game.scriptLoaded = function(who, script) { CM.Backup.scriptLoaded(who, script); - CM.Disp.ReplaceTooltipGrimoire() + CM.Main.ReplaceTooltipGrimoire() CM.ReplaceNativeGrimoire(); } - // TODO: Move this ReplaceTooltip function too other ReplaceTooltip functions - // OR: Move all other into this function CM.Backup.RebuildUpgrades = Game.RebuildUpgrades; Game.RebuildUpgrades = function() { CM.Backup.RebuildUpgrades(); @@ -58,7 +56,6 @@ CM.ReplaceNative = function() { Game.CalculateGains(); } - CM.Backup.DescribeDragonAura = Game.DescribeDragonAura; /** * This functions adds the function CM.Disp.AddAuraInfo() to Game.DescribeDragonAura() @@ -122,7 +119,7 @@ CM.ReplaceNativeGrimoireLaunch = function() { eval('CM.Backup.GrimoireLaunchMod = ' + minigame.launch.toString().split('=this').join('= Game.Objects[\'Wizard tower\'].minigame')); Game.Objects['Wizard tower'].minigame.launch = function() { CM.Backup.GrimoireLaunchMod(); - CM.Disp.ReplaceTooltipGrimoire(); + CM.Main.ReplaceTooltipGrimoire(); CM.HasReplaceNativeGrimoireDraw = false; CM.ReplaceNativeGrimoireDraw(); } @@ -237,9 +234,7 @@ CM.DelayInit = function() { CM.Disp.CreateSimpleTooltip(CM.Disp.TooltipText[i][0], CM.Disp.TooltipText[i][1], CM.Disp.TooltipText[i][2]); } CM.Disp.CreateWrinklerButtons(); - CM.Disp.ReplaceTooltipBuild(); - CM.Disp.ReplaceTooltipGrimoire(); - CM.Disp.ReplaceTooltipLump(); + CM.Main.ReplaceTooltips(); CM.Main.AddWrinklerAreaDetect(); CM.Cache.InitCookiesDiff(); CM.ReplaceNative(); @@ -264,6 +259,69 @@ CM.DelayInit = function() { Game.Win('Third-party'); } +/******** + * Section: Functions related to first initizalition of CM */ + +/** + * This function call all functions that replace Game-tooltips with CM-enhanced tooltips + * It is called by CM.DelayInit() + */ +CM.Main.ReplaceTooltips = function() { + CM.Main.ReplaceTooltipBuild(); + CM.Main.ReplaceTooltipGrimoire(); + CM.Main.ReplaceTooltipLump(); +} + +/******** + * Section: Functions related to replacing tooltips */ + + +/** + * This function replaces the original .onmouseover functions of buildings so that it calls CM.Disp.Tooltip() + * CM.Disp.Tooltip() sets the tooltip type to 'b' + * It is called by CM.Main.ReplaceTooltips() + */ +CM.Main.ReplaceTooltipBuild = function() { + CM.Main.TooltipBuildBackup = []; + for (var i in Game.Objects) { + var me = Game.Objects[i]; + if (l('product' + me.id).onmouseover != null) { + CM.Main.TooltipBuildBackup[i] = l('product' + me.id).onmouseover; + eval('l(\'product\' + me.id).onmouseover = function() {Game.tooltip.dynamic = 1; Game.tooltip.draw(this, function() {return CM.Disp.Tooltip(\'b\', \'' + i + '\');}, \'store\'); Game.tooltip.wobble();}'); + } + } +} + +/** + * This function replaces the original .onmouseover functions of the Grimoire minigame so that it calls CM.Disp.Tooltip() + * CM.Disp.Tooltip() sets the tooltip type to 'g' + * It is called by CM.Main.ReplaceTooltips() + */ +CM.Main.ReplaceTooltipGrimoire = function() { + if (Game.Objects['Wizard tower'].minigameLoaded) { + CM.Main.TooltipGrimoireBackup = []; + for (var i in Game.Objects['Wizard tower'].minigame.spellsById) { + if (l('grimoireSpell' + i).onmouseover != null) { + CM.Main.TooltipGrimoireBackup[i] = l('grimoireSpell' + i).onmouseover; + eval('l(\'grimoireSpell\' + i).onmouseover = function() {Game.tooltip.dynamic = 1; Game.tooltip.draw(this, function() {return CM.Disp.Tooltip(\'g\', \'' + i + '\');}, \'this\'); Game.tooltip.wobble();}'); + } + } + } +} + +/** + * This function replaces the original .onmouseover functions of sugar lumps so that it calls CM.Disp.Tooltip() + * CM.Disp.Tooltip() sets the tooltip type to 's' + * It is called by CM.Main.ReplaceTooltips() + */ +CM.Main.ReplaceTooltipLump = function() { + if (Game.canLumps()) { + CM.Main.TooltipLumpBackup = l('lumps').onmouseover; + eval('l(\'lumps\').onmouseover = function() {Game.tooltip.dynamic = 1; Game.tooltip.draw(this, function() {return CM.Disp.Tooltip(\'s\', \'Lump\');}, \'this\'); Game.tooltip.wobble();}'); + } +}; + + /******** * Section: Functions related to checking for changes in Minigames/GC's/Ticker * TODO: Possibly move this section */ @@ -429,7 +487,7 @@ CM.Main.CheckWrinklerCount = function() { * This function creates .onmouseover/out events that determine if the mouse is hovering-over a Wrinkler * It is called by CM.DelayInit * TODO: The system for displaying wrinklers should ideally use a similar system as other tooltips - * Thus, writing a CM.Disp.ReplaceTooltipWrinkler function etc. + * Thus, writing a CM.Main.ReplaceTooltipWrinkler function etc. */ CM.Main.AddWrinklerAreaDetect = function() { l('backgroundLeftCanvas').onmouseover = function() {CM.Disp.TooltipWrinklerArea = 1;}; From c64f42bcfae1d74061c025c8fda446dac186151b Mon Sep 17 00:00:00 2001 From: Daniel van Noord Date: Sat, 23 Jan 2021 22:55:39 +0100 Subject: [PATCH 002/145] Start work on Garden Tooltip --- CookieMonster.js | 16 ++++++++++++++++ src/Main.js | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/CookieMonster.js b/CookieMonster.js index dde6bfb..b164909 100644 --- a/CookieMonster.js +++ b/CookieMonster.js @@ -4265,6 +4265,7 @@ CM.Main.ReplaceTooltips = function() { CM.Main.ReplaceTooltipBuild(); CM.Main.ReplaceTooltipGrimoire(); CM.Main.ReplaceTooltipLump(); + CM.Main.ReplaceTooltipGarden(); } /******** @@ -4316,6 +4317,21 @@ CM.Main.ReplaceTooltipLump = function() { } }; +/** + * This function replaces the original .onmouseover functions of sugar lumps so that it calls CM.Disp.Tooltip() + * CM.Disp.Tooltip() sets the tooltip type to '?' + * It is called by CM.Main.ReplaceTooltips() + */ +CM.Main.ReplaceTooltipGarden = function() { + if (Game.Objects['Farm'].minigameLoaded) { + CM.Main.TooltipGardenBackup = []; + for (var i in Game.Objects['Farm'].minigame.plot) { + for (var j in i) { + //console.log(j, i) + } + } + } +}; /******** * Section: Functions related to checking for changes in Minigames/GC's/Ticker diff --git a/src/Main.js b/src/Main.js index 17ac29e..ed34fd0 100644 --- a/src/Main.js +++ b/src/Main.js @@ -270,6 +270,7 @@ CM.Main.ReplaceTooltips = function() { CM.Main.ReplaceTooltipBuild(); CM.Main.ReplaceTooltipGrimoire(); CM.Main.ReplaceTooltipLump(); + CM.Main.ReplaceTooltipGarden(); } /******** @@ -321,6 +322,21 @@ CM.Main.ReplaceTooltipLump = function() { } }; +/** + * This function replaces the original .onmouseover functions of sugar lumps so that it calls CM.Disp.Tooltip() + * CM.Disp.Tooltip() sets the tooltip type to '?' + * It is called by CM.Main.ReplaceTooltips() + */ +CM.Main.ReplaceTooltipGarden = function() { + if (Game.Objects['Farm'].minigameLoaded) { + CM.Main.TooltipGardenBackup = []; + for (var i in Game.Objects['Farm'].minigame.plot) { + for (var j in i) { + //console.log(j, i) + } + } + } +}; /******** * Section: Functions related to checking for changes in Minigames/GC's/Ticker From d958fc08bfd7254fe0b83fce1600d4eeb89f8e56 Mon Sep 17 00:00:00 2001 From: PneuJai <53138480+Rjlintkh@users.noreply.github.com> Date: Tue, 26 Jan 2021 20:41:22 +0800 Subject: [PATCH 003/145] Added two options They are options to show/hide mysterious achievements, and they dont need functions cuz CM.Disp.ReplaceCrateTooltipAchievements will check for them --- src/Data.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Data.js b/src/Data.js index 63dc624..14888f0 100644 --- a/src/Data.js +++ b/src/Data.js @@ -211,6 +211,8 @@ CM.ConfigData.ScaleCutoff = {type: 'numscale', group: 'Notation', label: 'Notati CM.ConfigData.GCTimer = {type: 'bool', group: 'Miscellaneous', label: ['Golden Cookie Timer OFF', 'Golden Cookie Timer ON'], desc: 'A timer on the Golden Cookie when it has been spawned', toggle: true, func: function() {CM.Disp.ToggleGCTimer();}}; CM.ConfigData.Favicon = {type: 'bool', group: 'Miscellaneous', label: ['Favicon OFF', 'Favicon ON'], desc: 'Update favicon with Golden/Wrath Cookie', toggle: true, func: function() {CM.Disp.UpdateFavicon();}}; CM.ConfigData.WrinklerButtons = {type: 'bool', group: 'Miscellaneous', label: ['Extra Buttons OFF', 'Extra Buttons ON'], desc: 'Show buttons for popping wrinklers at bottom of cookie section', toggle: true, func: function() {CM.Disp.UpdateWrinklerButtons();}}; +CM.ConfigData.ShowMysteriousAchievements = {type: 'bool', group: 'Miscellaneous', label: ['Show Mysterious Achievements OFF', 'Show Mysterious Achievements ON'], desc: 'Show mysterious achievemennts in stats', toggle: true, func: function() {}}; +CM.ConfigData.ShowMysteriousShadowAchievements = {type: 'bool', group: 'Miscellaneous', label: ['Show Mysterious Shadow Achievements OFF', 'Show Mysterious Shadow Achievements ON'], desc: 'Show mysterious shadow achievemennts in stats', toggle: true, func: function() {}}; /** From abfeabf08f423bab96b996bf359e45e072e17644 Mon Sep 17 00:00:00 2001 From: PneuJai <53138480+Rjlintkh@users.noreply.github.com> Date: Tue, 26 Jan 2021 20:42:17 +0800 Subject: [PATCH 004/145] Added default values for those two options --- src/Data.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Data.js b/src/Data.js index 14888f0..bff9b1e 100644 --- a/src/Data.js +++ b/src/Data.js @@ -296,6 +296,8 @@ CM.Data.ConfigDefault = { GCTimer: 1, Favicon: 1, WrinklerButtons: 1, + ShowMysteriousAchievements: 0, + ShowShadowMysteriousAchievements: 0, Header: {BarsColors: 1, Calculation: 1, Notification: 1, NotificationGC: 1, NotificationFC: 1, NotificationSea: 1, NotificationGard: 1, NotificationMagi: 1, NotificationWrink: 1, NotificationWrinkMax: 1, Tooltip: 1, Statistics: 1, Notation: 1, Miscellaneous: 1, Lucky: 1, Spells: 1, Chain: 1, Prestige: 1, Wrink: 1, Sea: 1, Misc: 1}, }; From e5bd08c0c4355cb5dcc2dd29f2e4f6cc44c82e0e Mon Sep 17 00:00:00 2001 From: PneuJai <53138480+Rjlintkh@users.noreply.github.com> Date: Tue, 26 Jan 2021 20:44:48 +0800 Subject: [PATCH 005/145] Added CM.Disp.ReplaceCrateTooltipAchievements CM.Disp.ReplaceCrateTooltipAchievements will backup and replace Game.crate and Game.crateTooltip and edit their outputs to show mysterious achievements Also this will check for CM.Options.ShowMysteriousAchievements and CM.Options.ShowMysteriousShadowAchievements --- src/Disp.js | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/Disp.js b/src/Disp.js index f55a4e7..5c1ab60 100644 --- a/src/Disp.js +++ b/src/Disp.js @@ -1249,6 +1249,49 @@ CM.Disp.ReplaceTooltipLump = function() { } }; +/** + * This function replaces the original Game.crate and Game.crateTooltip functions of stats page + */ +CM.Disp.ReplaceCrateTooltipAchievements = function() { + CM.Disp.CrateTooltipAchievementsBackup = [Game.crate, Game.crateTooltip]; + Game.crate = function(me,context,forceClickStr,id) { + let output; + if (me.type === 'achievement') { + let icon = me.icon; + if (CM.Options.ShowMysteriousShadowAchievements && me.pool === 'shadow') { + me.pool = 'normal'; + me.isShadow = true; + } + output = CM.Disp.CrateTooltipAchievementsBackup[0](me,context,forceClickStr,id); + if (CM.Options.ShowMysteriousAchievements && me.pool === 'normal' && !me.isShadow) output = output.replace('background-position:0px -336px', 'background-position:'+(-icon[0]*48)+'px '+(-icon[1]*48)+'px'); + if (CM.Options.ShowMysteriousShadowAchievements && me.isShadow) { + me.pool = 'shadow'; + output = output.replace('background-position:0px -336px', 'background-position:'+(-icon[0]*48)+'px '+(-icon[1]*48)+'px'); + } + } else { + output = CM.Disp.CrateTooltipAchievementsBackup[0](me,context,forceClickStr,id); + } + return output; + } + Game.crateTooltip = function(me,context) { + let output; + if (me.type === 'achievement') { + output = CM.Disp.CrateTooltipAchievementsBackup[1](me,context); + if (CM.Options.ShowMysteriousAchievements && me.pool === 'normal') { + output = output.replace('
???
', '
'+me.name+'
'); + output = output.replace('
???
', '
'+me.desc+'
'); + } + if (CM.Options.ShowMysteriousShadowAchievements && me.pool === 'shadow') { + output = output.replace('
???
', '
'+me.name+'
'); + output = output.replace('
???
', '
'+me.desc+'
'); + } + } else { + output = CM.Disp.CrateTooltipAchievementsBackup[1](me,context); + } + return output; + } +} + /** * This function enhance the standard tooltips by creating and changing l('tooltip') * The function is called by .onmouseover events that have replaced original code to use CM.Disp.Tooltip() From 125113133a324443afba8bd130649e2de2f155d8 Mon Sep 17 00:00:00 2001 From: PneuJai <53138480+Rjlintkh@users.noreply.github.com> Date: Tue, 26 Jan 2021 20:45:37 +0800 Subject: [PATCH 006/145] Added CM.Disp.ReplaceCrateTooltipAchievements() into init --- src/Main.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Main.js b/src/Main.js index caa11b2..f039658 100644 --- a/src/Main.js +++ b/src/Main.js @@ -240,6 +240,7 @@ CM.DelayInit = function() { CM.Disp.ReplaceTooltipBuild(); CM.Disp.ReplaceTooltipGrimoire(); CM.Disp.ReplaceTooltipLump(); + CM.Disp.ReplaceCrateTooltipAchievements(); CM.Main.AddWrinklerAreaDetect(); CM.Cache.InitCookiesDiff(); CM.ReplaceNative(); From 23f19b4d6249f241d76b7c2b1c1366a26c56b042 Mon Sep 17 00:00:00 2001 From: Daniel van Noord Date: Tue, 26 Jan 2021 14:57:59 +0100 Subject: [PATCH 007/145] Created (empty) tooltip for garden plots --- CookieMonster.js | 29 ++++++++++++++++++++--------- src/Disp.js | 15 ++++++++++++++- src/Main.js | 14 ++++++-------- 3 files changed, 40 insertions(+), 18 deletions(-) diff --git a/CookieMonster.js b/CookieMonster.js index 0f8c20e..bd905c3 100644 --- a/CookieMonster.js +++ b/CookieMonster.js @@ -2416,9 +2416,10 @@ CM.Disp.Tooltip = function(type, name) { } else if (type === 's') l('tooltip').innerHTML = Game.lumpTooltip(); // Sugar Lumps else if (type === 'g') l('tooltip').innerHTML = Game.Objects['Wizard tower'].minigame.spellTooltip(name)(); // Grimoire + else if (type == 'p') l('tooltip').innerHTML = Game.ObjectsById[2].minigame.tileTooltip(name[0], name[1])(); // Garden plots // Adds area for extra tooltip-sections - if ((type == 'b' && Game.buyMode == 1) || type == 'u' || type == 's' || type == 'g') { + if ((type == 'b' && Game.buyMode == 1) || type == 'u' || type == 's' || type == 'g' || type == 'p') { var area = document.createElement('div'); area.id = 'CMTooltipArea'; l('tooltip').appendChild(area); @@ -2583,6 +2584,9 @@ CM.Disp.UpdateTooltip = function() { else if (CM.Disp.tooltipType === 'g') { CM.Disp.UpdateTooltipGrimoire(); } + else if (CM.Disp.tooltipType === 'p') { + CM.Disp.UpdateTooltipGardenPlots(); + } CM.Disp.UpdateTooltipWarnings(); } else if (l('CMTooltipArea') == null) { // Remove warnings if its a basic tooltip @@ -2779,6 +2783,15 @@ CM.Disp.UpdateTooltipGrimoire = function() { } } +/** + * This function adds extra info to the Garden plots tooltips + * It is called when Garden plots tooltips are created or refreshed by CM.Disp.UpdateTooltip() + * It adds to the additional information to l('CMTooltipArea') + */ +CM.Disp.UpdateTooltipGardenPlots = function() { + var minigame = Game.Objects['Farm'].minigame; +} + /** * This function updates the warnings section of the building and upgrade tooltips * It is called by CM.Disp.UpdateTooltip() @@ -4335,18 +4348,16 @@ CM.Main.ReplaceTooltipLump = function() { }; /** - * This function replaces the original .onmouseover functions of sugar lumps so that it calls CM.Disp.Tooltip() - * CM.Disp.Tooltip() sets the tooltip type to '?' + * This function replaces the original .onmouseover functions of all garden plants so that it calls CM.Disp.Tooltip() + * CM.Disp.Tooltip() sets the tooltip type to 'p' * It is called by CM.Main.ReplaceTooltips() */ CM.Main.ReplaceTooltipGarden = function() { if (Game.Objects['Farm'].minigameLoaded) { - CM.Main.TooltipGardenBackup = []; - for (var i in Game.Objects['Farm'].minigame.plot) { - for (var j in i) { - //console.log(j, i) - } - } + Array.from(l('gardenPlot').children).forEach((child, index) => { + var coords = child.id.slice(-3,); + child.onmouseover = function() {Game.tooltip.dynamic=1; Game.tooltip.draw(this, function() {return CM.Disp.Tooltip('p', [`${coords[0]}`,`${coords[2]}`]);}, 'this'); Game.tooltip.wobble();}; + }); } }; diff --git a/src/Disp.js b/src/Disp.js index 5b55a01..e96b144 100644 --- a/src/Disp.js +++ b/src/Disp.js @@ -1233,9 +1233,10 @@ CM.Disp.Tooltip = function(type, name) { } else if (type === 's') l('tooltip').innerHTML = Game.lumpTooltip(); // Sugar Lumps else if (type === 'g') l('tooltip').innerHTML = Game.Objects['Wizard tower'].minigame.spellTooltip(name)(); // Grimoire + else if (type == 'p') l('tooltip').innerHTML = Game.ObjectsById[2].minigame.tileTooltip(name[0], name[1])(); // Garden plots // Adds area for extra tooltip-sections - if ((type == 'b' && Game.buyMode == 1) || type == 'u' || type == 's' || type == 'g') { + if ((type == 'b' && Game.buyMode == 1) || type == 'u' || type == 's' || type == 'g' || type == 'p') { var area = document.createElement('div'); area.id = 'CMTooltipArea'; l('tooltip').appendChild(area); @@ -1400,6 +1401,9 @@ CM.Disp.UpdateTooltip = function() { else if (CM.Disp.tooltipType === 'g') { CM.Disp.UpdateTooltipGrimoire(); } + else if (CM.Disp.tooltipType === 'p') { + CM.Disp.UpdateTooltipGardenPlots(); + } CM.Disp.UpdateTooltipWarnings(); } else if (l('CMTooltipArea') == null) { // Remove warnings if its a basic tooltip @@ -1596,6 +1600,15 @@ CM.Disp.UpdateTooltipGrimoire = function() { } } +/** + * This function adds extra info to the Garden plots tooltips + * It is called when Garden plots tooltips are created or refreshed by CM.Disp.UpdateTooltip() + * It adds to the additional information to l('CMTooltipArea') + */ +CM.Disp.UpdateTooltipGardenPlots = function() { + var minigame = Game.Objects['Farm'].minigame; +} + /** * This function updates the warnings section of the building and upgrade tooltips * It is called by CM.Disp.UpdateTooltip() diff --git a/src/Main.js b/src/Main.js index ed34fd0..9a8e75e 100644 --- a/src/Main.js +++ b/src/Main.js @@ -323,18 +323,16 @@ CM.Main.ReplaceTooltipLump = function() { }; /** - * This function replaces the original .onmouseover functions of sugar lumps so that it calls CM.Disp.Tooltip() - * CM.Disp.Tooltip() sets the tooltip type to '?' + * This function replaces the original .onmouseover functions of all garden plants so that it calls CM.Disp.Tooltip() + * CM.Disp.Tooltip() sets the tooltip type to 'p' * It is called by CM.Main.ReplaceTooltips() */ CM.Main.ReplaceTooltipGarden = function() { if (Game.Objects['Farm'].minigameLoaded) { - CM.Main.TooltipGardenBackup = []; - for (var i in Game.Objects['Farm'].minigame.plot) { - for (var j in i) { - //console.log(j, i) - } - } + Array.from(l('gardenPlot').children).forEach((child, index) => { + var coords = child.id.slice(-3,); + child.onmouseover = function() {Game.tooltip.dynamic=1; Game.tooltip.draw(this, function() {return CM.Disp.Tooltip('p', [`${coords[0]}`,`${coords[2]}`]);}, 'this'); Game.tooltip.wobble();}; + }); } }; From cdfb35aa1b663bda8e90ac275664973319352c7f Mon Sep 17 00:00:00 2001 From: PneuJai <53138480+Rjlintkh@users.noreply.github.com> Date: Tue, 26 Jan 2021 22:23:06 +0800 Subject: [PATCH 008/145] rename ShowMysteriousAchievements to MissingAchievements also moved to stats group --- src/Data.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Data.js b/src/Data.js index bff9b1e..12cb819 100644 --- a/src/Data.js +++ b/src/Data.js @@ -196,6 +196,8 @@ CM.ConfigData.DragonAuraInfo = {type: 'bool', group: 'Tooltip', label: ['Extra D // Statistics CM.ConfigData.Stats = {type: 'bool', group: 'Statistics', label: ['Statistics OFF', 'Statistics ON'], desc: 'Extra Cookie Monster statistics!', toggle: true}; CM.ConfigData.MissingUpgrades = {type: 'bool', group: 'Statistics', label: ['Missing Upgrades OFF', 'Missing Upgrades ON'], desc: 'Shows Missing upgrades in Stats Menu. This feature can be laggy for users with a low amount of unlocked achievements.', toggle: true}; +CM.ConfigData.MissingAchievements = {type: 'bool', group: 'Statistics', label: ['Missing Achievements OFF', 'Missing Achievements ON'], desc: 'Shows Missing achievements in Stats Menu.', toggle: true}; +CM.ConfigData.MissingShadowAchievements = {type: 'bool', group: 'Statistics', label: ['Missing Shadow Achievements OFF', 'Missing Achievements ON'], desc: 'Shows Missing shadow achievements in Stats Menu.', toggle: true}; CM.ConfigData.UpStats = {type: 'bool', group: 'Statistics', label: ['Statistics Update Rate (Default)', 'Statistics Update Rate (1s)'], desc: 'Default Game rate is once every 5 seconds', toggle: false}; CM.ConfigData.TimeFormat = {type: 'bool', group: 'Statistics', label: ['Time XXd, XXh, XXm, XXs', 'Time XX:XX:XX:XX:XX'], desc: 'Change the time format', toggle: false}; CM.ConfigData.DetailedTime = {type: 'bool', group: 'Statistics', label: ['Detailed Time OFF', 'Detailed Time ON'], desc: 'Change how time is displayed in certain statistics and tooltips', toggle: true, func: function() {CM.Disp.ToggleDetailedTime();}}; @@ -211,8 +213,6 @@ CM.ConfigData.ScaleCutoff = {type: 'numscale', group: 'Notation', label: 'Notati CM.ConfigData.GCTimer = {type: 'bool', group: 'Miscellaneous', label: ['Golden Cookie Timer OFF', 'Golden Cookie Timer ON'], desc: 'A timer on the Golden Cookie when it has been spawned', toggle: true, func: function() {CM.Disp.ToggleGCTimer();}}; CM.ConfigData.Favicon = {type: 'bool', group: 'Miscellaneous', label: ['Favicon OFF', 'Favicon ON'], desc: 'Update favicon with Golden/Wrath Cookie', toggle: true, func: function() {CM.Disp.UpdateFavicon();}}; CM.ConfigData.WrinklerButtons = {type: 'bool', group: 'Miscellaneous', label: ['Extra Buttons OFF', 'Extra Buttons ON'], desc: 'Show buttons for popping wrinklers at bottom of cookie section', toggle: true, func: function() {CM.Disp.UpdateWrinklerButtons();}}; -CM.ConfigData.ShowMysteriousAchievements = {type: 'bool', group: 'Miscellaneous', label: ['Show Mysterious Achievements OFF', 'Show Mysterious Achievements ON'], desc: 'Show mysterious achievemennts in stats', toggle: true, func: function() {}}; -CM.ConfigData.ShowMysteriousShadowAchievements = {type: 'bool', group: 'Miscellaneous', label: ['Show Mysterious Shadow Achievements OFF', 'Show Mysterious Shadow Achievements ON'], desc: 'Show mysterious shadow achievemennts in stats', toggle: true, func: function() {}}; /** @@ -282,6 +282,8 @@ CM.Data.ConfigDefault = { DragonAuraInfo: 1, Stats: 1, MissingUpgrades: 1, + MissingAchievements: 1, + MissingShadowAchievements: 1, UpStats: 1, TimeFormat: 0, DetailedTime: 1, @@ -296,8 +298,6 @@ CM.Data.ConfigDefault = { GCTimer: 1, Favicon: 1, WrinklerButtons: 1, - ShowMysteriousAchievements: 0, - ShowShadowMysteriousAchievements: 0, Header: {BarsColors: 1, Calculation: 1, Notification: 1, NotificationGC: 1, NotificationFC: 1, NotificationSea: 1, NotificationGard: 1, NotificationMagi: 1, NotificationWrink: 1, NotificationWrinkMax: 1, Tooltip: 1, Statistics: 1, Notation: 1, Miscellaneous: 1, Lucky: 1, Spells: 1, Chain: 1, Prestige: 1, Wrink: 1, Sea: 1, Misc: 1}, }; From 8a3eac78d4997663ad7dab70f856d36a5df10e5c Mon Sep 17 00:00:00 2001 From: PneuJai <53138480+Rjlintkh@users.noreply.github.com> Date: Tue, 26 Jan 2021 22:35:00 +0800 Subject: [PATCH 009/145] Merge MissingShadowAchievements and MissingAchievements --- src/Data.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Data.js b/src/Data.js index 12cb819..fb28e4d 100644 --- a/src/Data.js +++ b/src/Data.js @@ -196,8 +196,7 @@ CM.ConfigData.DragonAuraInfo = {type: 'bool', group: 'Tooltip', label: ['Extra D // Statistics CM.ConfigData.Stats = {type: 'bool', group: 'Statistics', label: ['Statistics OFF', 'Statistics ON'], desc: 'Extra Cookie Monster statistics!', toggle: true}; CM.ConfigData.MissingUpgrades = {type: 'bool', group: 'Statistics', label: ['Missing Upgrades OFF', 'Missing Upgrades ON'], desc: 'Shows Missing upgrades in Stats Menu. This feature can be laggy for users with a low amount of unlocked achievements.', toggle: true}; -CM.ConfigData.MissingAchievements = {type: 'bool', group: 'Statistics', label: ['Missing Achievements OFF', 'Missing Achievements ON'], desc: 'Shows Missing achievements in Stats Menu.', toggle: true}; -CM.ConfigData.MissingShadowAchievements = {type: 'bool', group: 'Statistics', label: ['Missing Shadow Achievements OFF', 'Missing Achievements ON'], desc: 'Shows Missing shadow achievements in Stats Menu.', toggle: true}; +CM.ConfigData.MissingAchievements = {type: 'bool', group: 'Statistics', label: ['Show Normal Missing Achievements', 'Show Shadow Missing Achievements', 'Show All Missing Achievements', 'Hide Missing Achievements'], desc: 'Shows Missing normal or shadow achievements in Stats Menu.', toggle: false}; CM.ConfigData.UpStats = {type: 'bool', group: 'Statistics', label: ['Statistics Update Rate (Default)', 'Statistics Update Rate (1s)'], desc: 'Default Game rate is once every 5 seconds', toggle: false}; CM.ConfigData.TimeFormat = {type: 'bool', group: 'Statistics', label: ['Time XXd, XXh, XXm, XXs', 'Time XX:XX:XX:XX:XX'], desc: 'Change the time format', toggle: false}; CM.ConfigData.DetailedTime = {type: 'bool', group: 'Statistics', label: ['Detailed Time OFF', 'Detailed Time ON'], desc: 'Change how time is displayed in certain statistics and tooltips', toggle: true, func: function() {CM.Disp.ToggleDetailedTime();}}; @@ -283,7 +282,6 @@ CM.Data.ConfigDefault = { Stats: 1, MissingUpgrades: 1, MissingAchievements: 1, - MissingShadowAchievements: 1, UpStats: 1, TimeFormat: 0, DetailedTime: 1, From cd90b15fa33d95441d0038d0a8d13ccf31076680 Mon Sep 17 00:00:00 2001 From: PneuJai <53138480+Rjlintkh@users.noreply.github.com> Date: Tue, 26 Jan 2021 22:39:17 +0800 Subject: [PATCH 010/145] Adapt to new option MissingAchievements --- src/Disp.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Disp.js b/src/Disp.js index 5c1ab60..466a0ab 100644 --- a/src/Disp.js +++ b/src/Disp.js @@ -1253,18 +1253,25 @@ CM.Disp.ReplaceTooltipLump = function() { * This function replaces the original Game.crate and Game.crateTooltip functions of stats page */ CM.Disp.ReplaceCrateTooltipAchievements = function() { + let options = {normal: false, shadow: false}; + switch (CM.ConfigData.MissingAchievements) { + case 0: options.normal = true; options.shadow = false; break; + case 1: options.normal = false; options.shadow = true; break; + case 2: options.normal = true; options.shadow = true; break; + case 3: options.normal = false; options.shadow = false; break; + } CM.Disp.CrateTooltipAchievementsBackup = [Game.crate, Game.crateTooltip]; Game.crate = function(me,context,forceClickStr,id) { let output; if (me.type === 'achievement') { let icon = me.icon; - if (CM.Options.ShowMysteriousShadowAchievements && me.pool === 'shadow') { + if (options.shadow && me.pool === 'shadow') { me.pool = 'normal'; me.isShadow = true; } output = CM.Disp.CrateTooltipAchievementsBackup[0](me,context,forceClickStr,id); - if (CM.Options.ShowMysteriousAchievements && me.pool === 'normal' && !me.isShadow) output = output.replace('background-position:0px -336px', 'background-position:'+(-icon[0]*48)+'px '+(-icon[1]*48)+'px'); - if (CM.Options.ShowMysteriousShadowAchievements && me.isShadow) { + if (options.normal && me.pool === 'normal' && !me.isShadow) output = output.replace('background-position:0px -336px', 'background-position:'+(-icon[0]*48)+'px '+(-icon[1]*48)+'px'); + if (options.shadow && me.isShadow) { me.pool = 'shadow'; output = output.replace('background-position:0px -336px', 'background-position:'+(-icon[0]*48)+'px '+(-icon[1]*48)+'px'); } @@ -1277,11 +1284,11 @@ CM.Disp.ReplaceCrateTooltipAchievements = function() { let output; if (me.type === 'achievement') { output = CM.Disp.CrateTooltipAchievementsBackup[1](me,context); - if (CM.Options.ShowMysteriousAchievements && me.pool === 'normal') { + if (options.normal && me.pool === 'normal') { output = output.replace('
???
', '
'+me.name+'
'); output = output.replace('
???
', '
'+me.desc+'
'); } - if (CM.Options.ShowMysteriousShadowAchievements && me.pool === 'shadow') { + if (options.shadow && me.pool === 'shadow') { output = output.replace('
???
', '
'+me.name+'
'); output = output.replace('
???
', '
'+me.desc+'
'); } From f450ae98ae0dd014b73accea0801e9f8e360f4a9 Mon Sep 17 00:00:00 2001 From: PneuJai <53138480+Rjlintkh@users.noreply.github.com> Date: Tue, 26 Jan 2021 23:26:35 +0800 Subject: [PATCH 011/145] Fixed the default value for MissingAchievements --- src/Data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data.js b/src/Data.js index fb28e4d..a9191ec 100644 --- a/src/Data.js +++ b/src/Data.js @@ -281,7 +281,7 @@ CM.Data.ConfigDefault = { DragonAuraInfo: 1, Stats: 1, MissingUpgrades: 1, - MissingAchievements: 1, + MissingAchievements: 2, UpStats: 1, TimeFormat: 0, DetailedTime: 1, From 91a2edf3486d8d3bee746121dc04c7b3eec9054a Mon Sep 17 00:00:00 2001 From: PneuJai <53138480+Rjlintkh@users.noreply.github.com> Date: Tue, 26 Jan 2021 23:27:31 +0800 Subject: [PATCH 012/145] Fixed typos of ReplaceCrateTooltipAchievements --- src/Disp.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/Disp.js b/src/Disp.js index 466a0ab..cde51e6 100644 --- a/src/Disp.js +++ b/src/Disp.js @@ -1253,17 +1253,17 @@ CM.Disp.ReplaceTooltipLump = function() { * This function replaces the original Game.crate and Game.crateTooltip functions of stats page */ CM.Disp.ReplaceCrateTooltipAchievements = function() { - let options = {normal: false, shadow: false}; - switch (CM.ConfigData.MissingAchievements) { - case 0: options.normal = true; options.shadow = false; break; - case 1: options.normal = false; options.shadow = true; break; - case 2: options.normal = true; options.shadow = true; break; - case 3: options.normal = false; options.shadow = false; break; - } CM.Disp.CrateTooltipAchievementsBackup = [Game.crate, Game.crateTooltip]; Game.crate = function(me,context,forceClickStr,id) { let output; if (me.type === 'achievement') { + let options = {normal: false, shadow: false}; + switch (CM.Options.MissingAchievements) { + case 0: options.normal = true; options.shadow = false; break; + case 1: options.normal = false; options.shadow = true; break; + case 2: options.normal = true; options.shadow = true; break; + case 3: options.normal = false; options.shadow = false; break; + } let icon = me.icon; if (options.shadow && me.pool === 'shadow') { me.pool = 'normal'; @@ -1283,6 +1283,13 @@ CM.Disp.ReplaceCrateTooltipAchievements = function() { Game.crateTooltip = function(me,context) { let output; if (me.type === 'achievement') { + let options = {normal: false, shadow: false}; + switch (CM.Options.MissingAchievements) { + case 0: options.normal = true; options.shadow = false; break; + case 1: options.normal = false; options.shadow = true; break; + case 2: options.normal = true; options.shadow = true; break; + case 3: options.normal = false; options.shadow = false; break; + } output = CM.Disp.CrateTooltipAchievementsBackup[1](me,context); if (options.normal && me.pool === 'normal') { output = output.replace('
???
', '
'+me.name+'
'); From a9dfcaab751bea7ff9f6f6ae0d4581823102038c Mon Sep 17 00:00:00 2001 From: Daniel van Noord Date: Tue, 26 Jan 2021 22:18:21 +0100 Subject: [PATCH 013/145] Tooltip with curr/max reward for plants #183 --- CookieMonster.js | 22 ++++++++++++++++++++++ src/Disp.js | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/CookieMonster.js b/CookieMonster.js index bd905c3..0ef00f2 100644 --- a/CookieMonster.js +++ b/CookieMonster.js @@ -2790,6 +2790,28 @@ CM.Disp.UpdateTooltipGrimoire = function() { */ CM.Disp.UpdateTooltipGardenPlots = function() { var minigame = Game.Objects['Farm'].minigame; + if (minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] != 0) { + var mature = minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][1] > minigame.plantsById[minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] - 1].matureBase; + var plantName = minigame.plantsById[minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] - 1].name; + l('CMTooltipBorder').appendChild(CM.Disp.TooltipCreateHeader('Reward (Current / Maximum)')); + var reward = document.createElement('div'); + reward.id = 'CMTooltipPlantReward'; + l('CMTooltipBorder').appendChild(reward); + if (plantName == "Bakeberry") { + l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 30)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 30); + } + else if (plantName == "Chocoroot" || plantName == "White chocoroot") { + l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 3)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 3); + } + else if (plantName == "Queenbeet") { + l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.04, Game.cookiesPs * 60 * 60)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 60); + } + else if (plantName == "Duketater") { + l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.08, Game.cookiesPs * 60 * 120)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 120); + } + else l('CMTooltipArea').style.display = "none"; + } + else l('CMTooltipArea').style.display = "none"; } /** diff --git a/src/Disp.js b/src/Disp.js index e96b144..91c757c 100644 --- a/src/Disp.js +++ b/src/Disp.js @@ -1607,6 +1607,28 @@ CM.Disp.UpdateTooltipGrimoire = function() { */ CM.Disp.UpdateTooltipGardenPlots = function() { var minigame = Game.Objects['Farm'].minigame; + if (minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] != 0) { + var mature = minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][1] > minigame.plantsById[minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] - 1].matureBase; + var plantName = minigame.plantsById[minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] - 1].name; + l('CMTooltipBorder').appendChild(CM.Disp.TooltipCreateHeader('Reward (Current / Maximum)')); + var reward = document.createElement('div'); + reward.id = 'CMTooltipPlantReward'; + l('CMTooltipBorder').appendChild(reward); + if (plantName == "Bakeberry") { + l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 30)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 30); + } + else if (plantName == "Chocoroot" || plantName == "White chocoroot") { + l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 3)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 3); + } + else if (plantName == "Queenbeet") { + l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.04, Game.cookiesPs * 60 * 60)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 60); + } + else if (plantName == "Duketater") { + l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.08, Game.cookiesPs * 60 * 120)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 120); + } + else l('CMTooltipArea').style.display = "none"; + } + else l('CMTooltipArea').style.display = "none"; } /** From ffa664c4762d3d9f4b21b266b390eb3c24fb27ae Mon Sep 17 00:00:00 2001 From: Daniel van Noord Date: Tue, 26 Jan 2021 22:21:17 +0100 Subject: [PATCH 014/145] Added option foor plot tooltip --- CookieMonster.js | 44 ++++++++++++++++++++++++-------------------- src/Data.js | 2 ++ src/Disp.js | 42 ++++++++++++++++++++++-------------------- 3 files changed, 48 insertions(+), 40 deletions(-) diff --git a/CookieMonster.js b/CookieMonster.js index 0ef00f2..bc24ec1 100644 --- a/CookieMonster.js +++ b/CookieMonster.js @@ -1075,6 +1075,7 @@ CM.ConfigData.ToolWarnPos = {type: 'bool', group: 'Tooltip', label: ['Tooltip Wa CM.ConfigData.TooltipGrim = {type: 'bool', group: 'Tooltip', label: ['Grimoire Tooltip Information OFF', 'Grimoire Tooltip Information ON'], desc: 'Extra information in tooltip for grimoire', toggle: true}; CM.ConfigData.ToolWrink = {type: 'bool', group: 'Tooltip', label: ['Wrinkler Tooltip OFF', 'Wrinkler Tooltip ON'], desc: 'Shows the amount of cookies a wrinkler will give when popping it', toggle: true}; CM.ConfigData.TooltipLump = {type: 'bool', group: 'Tooltip', label: ['Sugar Lump Tooltip OFF', 'Sugar Lump Tooltip ON'], desc: 'Shows the current Sugar Lump type in Sugar lump tooltip.', toggle: true}; +CM.ConfigData.TooltipPlots = {type: 'bool', group: 'Tooltip', label: ['Garden Plots Tooltip OFF', 'Garden Plots Tooltip ON'], desc: 'Shows a tooltip for plants that have a cookie reward.', toggle: true}; CM.ConfigData.DragonAuraInfo = {type: 'bool', group: 'Tooltip', label: ['Extra Dragon Aura Info OFF', 'Extra Dragon Aura Info ON'], desc: 'Shows information about changes in CPS and costs in the dragon aura interface.', toggle: true}; // Statistics @@ -1161,6 +1162,7 @@ CM.Data.ConfigDefault = { TooltipGrim:1, ToolWrink: 1, TooltipLump: 1, + TooltipPlots: 1, DragonAuraInfo: 1, Stats: 1, MissingUpgrades: 1, @@ -2789,27 +2791,29 @@ CM.Disp.UpdateTooltipGrimoire = function() { * It adds to the additional information to l('CMTooltipArea') */ CM.Disp.UpdateTooltipGardenPlots = function() { - var minigame = Game.Objects['Farm'].minigame; - if (minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] != 0) { - var mature = minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][1] > minigame.plantsById[minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] - 1].matureBase; - var plantName = minigame.plantsById[minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] - 1].name; - l('CMTooltipBorder').appendChild(CM.Disp.TooltipCreateHeader('Reward (Current / Maximum)')); - var reward = document.createElement('div'); - reward.id = 'CMTooltipPlantReward'; - l('CMTooltipBorder').appendChild(reward); - if (plantName == "Bakeberry") { - l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 30)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 30); - } - else if (plantName == "Chocoroot" || plantName == "White chocoroot") { - l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 3)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 3); + if (CM.Options.TooltipLump) { + var minigame = Game.Objects['Farm'].minigame; + if (minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] != 0) { + var mature = minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][1] > minigame.plantsById[minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] - 1].matureBase; + var plantName = minigame.plantsById[minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] - 1].name; + l('CMTooltipBorder').appendChild(CM.Disp.TooltipCreateHeader('Reward (Current / Maximum)')); + var reward = document.createElement('div'); + reward.id = 'CMTooltipPlantReward'; + l('CMTooltipBorder').appendChild(reward); + if (plantName == "Bakeberry") { + l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 30)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 30); + } + else if (plantName == "Chocoroot" || plantName == "White chocoroot") { + l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 3)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 3); + } + else if (plantName == "Queenbeet") { + l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.04, Game.cookiesPs * 60 * 60)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 60); + } + else if (plantName == "Duketater") { + l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.08, Game.cookiesPs * 60 * 120)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 120); + } + else l('CMTooltipArea').style.display = "none"; } - else if (plantName == "Queenbeet") { - l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.04, Game.cookiesPs * 60 * 60)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 60); - } - else if (plantName == "Duketater") { - l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.08, Game.cookiesPs * 60 * 120)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 120); - } - else l('CMTooltipArea').style.display = "none"; } else l('CMTooltipArea').style.display = "none"; } diff --git a/src/Data.js b/src/Data.js index 63dc624..7aa4ae2 100644 --- a/src/Data.js +++ b/src/Data.js @@ -191,6 +191,7 @@ CM.ConfigData.ToolWarnPos = {type: 'bool', group: 'Tooltip', label: ['Tooltip Wa CM.ConfigData.TooltipGrim = {type: 'bool', group: 'Tooltip', label: ['Grimoire Tooltip Information OFF', 'Grimoire Tooltip Information ON'], desc: 'Extra information in tooltip for grimoire', toggle: true}; CM.ConfigData.ToolWrink = {type: 'bool', group: 'Tooltip', label: ['Wrinkler Tooltip OFF', 'Wrinkler Tooltip ON'], desc: 'Shows the amount of cookies a wrinkler will give when popping it', toggle: true}; CM.ConfigData.TooltipLump = {type: 'bool', group: 'Tooltip', label: ['Sugar Lump Tooltip OFF', 'Sugar Lump Tooltip ON'], desc: 'Shows the current Sugar Lump type in Sugar lump tooltip.', toggle: true}; +CM.ConfigData.TooltipPlots = {type: 'bool', group: 'Tooltip', label: ['Garden Plots Tooltip OFF', 'Garden Plots Tooltip ON'], desc: 'Shows a tooltip for plants that have a cookie reward.', toggle: true}; CM.ConfigData.DragonAuraInfo = {type: 'bool', group: 'Tooltip', label: ['Extra Dragon Aura Info OFF', 'Extra Dragon Aura Info ON'], desc: 'Shows information about changes in CPS and costs in the dragon aura interface.', toggle: true}; // Statistics @@ -277,6 +278,7 @@ CM.Data.ConfigDefault = { TooltipGrim:1, ToolWrink: 1, TooltipLump: 1, + TooltipPlots: 1, DragonAuraInfo: 1, Stats: 1, MissingUpgrades: 1, diff --git a/src/Disp.js b/src/Disp.js index 91c757c..dd5d21d 100644 --- a/src/Disp.js +++ b/src/Disp.js @@ -1606,27 +1606,29 @@ CM.Disp.UpdateTooltipGrimoire = function() { * It adds to the additional information to l('CMTooltipArea') */ CM.Disp.UpdateTooltipGardenPlots = function() { - var minigame = Game.Objects['Farm'].minigame; - if (minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] != 0) { - var mature = minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][1] > minigame.plantsById[minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] - 1].matureBase; - var plantName = minigame.plantsById[minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] - 1].name; - l('CMTooltipBorder').appendChild(CM.Disp.TooltipCreateHeader('Reward (Current / Maximum)')); - var reward = document.createElement('div'); - reward.id = 'CMTooltipPlantReward'; - l('CMTooltipBorder').appendChild(reward); - if (plantName == "Bakeberry") { - l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 30)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 30); - } - else if (plantName == "Chocoroot" || plantName == "White chocoroot") { - l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 3)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 3); + if (CM.Options.TooltipLump) { + var minigame = Game.Objects['Farm'].minigame; + if (minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] != 0) { + var mature = minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][1] > minigame.plantsById[minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] - 1].matureBase; + var plantName = minigame.plantsById[minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] - 1].name; + l('CMTooltipBorder').appendChild(CM.Disp.TooltipCreateHeader('Reward (Current / Maximum)')); + var reward = document.createElement('div'); + reward.id = 'CMTooltipPlantReward'; + l('CMTooltipBorder').appendChild(reward); + if (plantName == "Bakeberry") { + l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 30)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 30); + } + else if (plantName == "Chocoroot" || plantName == "White chocoroot") { + l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 3)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 3); + } + else if (plantName == "Queenbeet") { + l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.04, Game.cookiesPs * 60 * 60)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 60); + } + else if (plantName == "Duketater") { + l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.08, Game.cookiesPs * 60 * 120)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 120); + } + else l('CMTooltipArea').style.display = "none"; } - else if (plantName == "Queenbeet") { - l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.04, Game.cookiesPs * 60 * 60)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 60); - } - else if (plantName == "Duketater") { - l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.08, Game.cookiesPs * 60 * 120)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 120); - } - else l('CMTooltipArea').style.display = "none"; } else l('CMTooltipArea').style.display = "none"; } From 52cfd9ddc220b5cfd8b4d52daa439d88620fb390 Mon Sep 17 00:00:00 2001 From: Daniel van Noord Date: Tue, 26 Jan 2021 22:22:32 +0100 Subject: [PATCH 015/145] Renamed ToolWrink to TooltipWrink --- CookieMonster.js | 8 ++++---- src/Data.js | 4 ++-- src/Disp.js | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CookieMonster.js b/CookieMonster.js index bc24ec1..d9c15ff 100644 --- a/CookieMonster.js +++ b/CookieMonster.js @@ -1073,7 +1073,7 @@ CM.ConfigData.ToolWarnConjureFrenzy = {type: 'bool', group: 'Tooltip', label: [' CM.ConfigData.ToolWarnEdifice = {type: 'bool', group: 'Tooltip', label: ['Tooltip Edifice Warning OFF', 'Tooltip Edifice Warning ON'], desc: 'A warning when buying if it will put the bank under the amount needed for "Spontaneous Edifice" to possibly give you your most expensive building', toggle: true}; CM.ConfigData.ToolWarnPos = {type: 'bool', group: 'Tooltip', label: ['Tooltip Warning Position (Left)', 'Tooltip Warning Position (Bottom)'], desc: 'Placement of the warning boxes', toggle: false, func: function() {CM.Disp.ToggleToolWarnPos();}}; CM.ConfigData.TooltipGrim = {type: 'bool', group: 'Tooltip', label: ['Grimoire Tooltip Information OFF', 'Grimoire Tooltip Information ON'], desc: 'Extra information in tooltip for grimoire', toggle: true}; -CM.ConfigData.ToolWrink = {type: 'bool', group: 'Tooltip', label: ['Wrinkler Tooltip OFF', 'Wrinkler Tooltip ON'], desc: 'Shows the amount of cookies a wrinkler will give when popping it', toggle: true}; +CM.ConfigData.TooltipWrink = {type: 'bool', group: 'Tooltip', label: ['Wrinkler Tooltip OFF', 'Wrinkler Tooltip ON'], desc: 'Shows the amount of cookies a wrinkler will give when popping it', toggle: true}; CM.ConfigData.TooltipLump = {type: 'bool', group: 'Tooltip', label: ['Sugar Lump Tooltip OFF', 'Sugar Lump Tooltip ON'], desc: 'Shows the current Sugar Lump type in Sugar lump tooltip.', toggle: true}; CM.ConfigData.TooltipPlots = {type: 'bool', group: 'Tooltip', label: ['Garden Plots Tooltip OFF', 'Garden Plots Tooltip ON'], desc: 'Shows a tooltip for plants that have a cookie reward.', toggle: true}; CM.ConfigData.DragonAuraInfo = {type: 'bool', group: 'Tooltip', label: ['Extra Dragon Aura Info OFF', 'Extra Dragon Aura Info ON'], desc: 'Shows information about changes in CPS and costs in the dragon aura interface.', toggle: true}; @@ -1160,7 +1160,7 @@ CM.Data.ConfigDefault = { ToolWarnEdifice: 1, ToolWarnPos: 1, TooltipGrim:1, - ToolWrink: 1, + TooltipWrink: 1, TooltipLump: 1, TooltipPlots: 1, DragonAuraInfo: 1, @@ -2937,7 +2937,7 @@ CM.Disp.ToggleToolWarnPos = function() { * TODO: Change this code to be the same as other tooltips. (i.d., create tooltip with type "w") */ CM.Disp.CheckWrinklerTooltip = function() { - if (CM.Options.ToolWrink == 1 && CM.Disp.TooltipWrinklerArea == 1) { // Latter is set by CM.Main.AddWrinklerAreaDetect + if (CM.Options.TooltipWrink == 1 && CM.Disp.TooltipWrinklerArea == 1) { // Latter is set by CM.Main.AddWrinklerAreaDetect var showingTooltip = false; for (var i in Game.wrinklers) { var me = Game.wrinklers[i]; @@ -2975,7 +2975,7 @@ CM.Disp.CheckWrinklerTooltip = function() { * TODO: Change this code to be the same as other tooltips. Fit this into CM.Disp.UpdateTooltip() */ CM.Disp.UpdateWrinklerTooltip = function() { - if (CM.Options.ToolWrink == 1 && l('CMTooltipWrinkler') != null) { + if (CM.Options.TooltipWrink == 1 && l('CMTooltipWrinkler') != null) { var sucked = Game.wrinklers[CM.Disp.TooltipWrinkler].sucked; var toSuck = 1.1; if (Game.Has('Sacrilegious corruption')) toSuck *= 1.05; diff --git a/src/Data.js b/src/Data.js index 7aa4ae2..13d9d22 100644 --- a/src/Data.js +++ b/src/Data.js @@ -189,7 +189,7 @@ CM.ConfigData.ToolWarnConjureFrenzy = {type: 'bool', group: 'Tooltip', label: [' CM.ConfigData.ToolWarnEdifice = {type: 'bool', group: 'Tooltip', label: ['Tooltip Edifice Warning OFF', 'Tooltip Edifice Warning ON'], desc: 'A warning when buying if it will put the bank under the amount needed for "Spontaneous Edifice" to possibly give you your most expensive building', toggle: true}; CM.ConfigData.ToolWarnPos = {type: 'bool', group: 'Tooltip', label: ['Tooltip Warning Position (Left)', 'Tooltip Warning Position (Bottom)'], desc: 'Placement of the warning boxes', toggle: false, func: function() {CM.Disp.ToggleToolWarnPos();}}; CM.ConfigData.TooltipGrim = {type: 'bool', group: 'Tooltip', label: ['Grimoire Tooltip Information OFF', 'Grimoire Tooltip Information ON'], desc: 'Extra information in tooltip for grimoire', toggle: true}; -CM.ConfigData.ToolWrink = {type: 'bool', group: 'Tooltip', label: ['Wrinkler Tooltip OFF', 'Wrinkler Tooltip ON'], desc: 'Shows the amount of cookies a wrinkler will give when popping it', toggle: true}; +CM.ConfigData.TooltipWrink = {type: 'bool', group: 'Tooltip', label: ['Wrinkler Tooltip OFF', 'Wrinkler Tooltip ON'], desc: 'Shows the amount of cookies a wrinkler will give when popping it', toggle: true}; CM.ConfigData.TooltipLump = {type: 'bool', group: 'Tooltip', label: ['Sugar Lump Tooltip OFF', 'Sugar Lump Tooltip ON'], desc: 'Shows the current Sugar Lump type in Sugar lump tooltip.', toggle: true}; CM.ConfigData.TooltipPlots = {type: 'bool', group: 'Tooltip', label: ['Garden Plots Tooltip OFF', 'Garden Plots Tooltip ON'], desc: 'Shows a tooltip for plants that have a cookie reward.', toggle: true}; CM.ConfigData.DragonAuraInfo = {type: 'bool', group: 'Tooltip', label: ['Extra Dragon Aura Info OFF', 'Extra Dragon Aura Info ON'], desc: 'Shows information about changes in CPS and costs in the dragon aura interface.', toggle: true}; @@ -276,7 +276,7 @@ CM.Data.ConfigDefault = { ToolWarnEdifice: 1, ToolWarnPos: 1, TooltipGrim:1, - ToolWrink: 1, + TooltipWrink: 1, TooltipLump: 1, TooltipPlots: 1, DragonAuraInfo: 1, diff --git a/src/Disp.js b/src/Disp.js index dd5d21d..dc0b6a0 100644 --- a/src/Disp.js +++ b/src/Disp.js @@ -1752,7 +1752,7 @@ CM.Disp.ToggleToolWarnPos = function() { * TODO: Change this code to be the same as other tooltips. (i.d., create tooltip with type "w") */ CM.Disp.CheckWrinklerTooltip = function() { - if (CM.Options.ToolWrink == 1 && CM.Disp.TooltipWrinklerArea == 1) { // Latter is set by CM.Main.AddWrinklerAreaDetect + if (CM.Options.TooltipWrink == 1 && CM.Disp.TooltipWrinklerArea == 1) { // Latter is set by CM.Main.AddWrinklerAreaDetect var showingTooltip = false; for (var i in Game.wrinklers) { var me = Game.wrinklers[i]; @@ -1790,7 +1790,7 @@ CM.Disp.CheckWrinklerTooltip = function() { * TODO: Change this code to be the same as other tooltips. Fit this into CM.Disp.UpdateTooltip() */ CM.Disp.UpdateWrinklerTooltip = function() { - if (CM.Options.ToolWrink == 1 && l('CMTooltipWrinkler') != null) { + if (CM.Options.TooltipWrink == 1 && l('CMTooltipWrinkler') != null) { var sucked = Game.wrinklers[CM.Disp.TooltipWrinkler].sucked; var toSuck = 1.1; if (Game.Has('Sacrilegious corruption')) toSuck *= 1.05; From 80e3ac746a7f13c4e6e4fa717844e849f7d9e10e Mon Sep 17 00:00:00 2001 From: Daniel van Noord Date: Tue, 26 Jan 2021 22:26:46 +0100 Subject: [PATCH 016/145] Fixed CM.Options.TooltipBuildUpgrade #523 --- CookieMonster.js | 17 +++++++++-------- src/Data.js | 4 ++-- src/Disp.js | 13 +++++++------ 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/CookieMonster.js b/CookieMonster.js index d9c15ff..09212f3 100644 --- a/CookieMonster.js +++ b/CookieMonster.js @@ -1064,7 +1064,7 @@ CM.ConfigData.WrinklerMaxSoundURL = {type: 'url', group: 'NotificationWrinkMax', CM.ConfigData.Title = {type: 'bool', group: 'Notification', label: ['Title OFF', 'Title ON', 'Title Pinned Tab Highlight'], desc: 'Update title with Golden Cookie/Season Popup timers; pinned tab highlight only changes the title when a Golden Cookie/Season Popup spawns', toggle: true}; // Tooltip -CM.ConfigData.TooltipInfo = {type: 'bool', group: 'Tooltip', label: ['Extra Tooltip Information OFF', 'Extra Tooltip Information ON'], desc: 'Extra information in tooltips', toggle: true}; +CM.ConfigData.TooltipBuildUpgrade = {type: 'bool', group: 'Tooltip', label: ['Extra Tooltip Information OFF', 'Extra Tooltip Information ON'], desc: 'Extra information in tooltips', toggle: true}; CM.ConfigData.TooltipAmor = {type: 'bool', group: 'Tooltip', label: ['Buildings Tooltip Amortization Information OFF', 'Buildings Tooltip Amortization Information ON'], desc: 'Add amortization information to buildings tooltip', toggle: true}; CM.ConfigData.ToolWarnLucky = {type: 'bool', group: 'Tooltip', label: ['Tooltip Lucky Warning OFF', 'Tooltip Lucky Warning ON'], desc: 'A warning when buying if it will put the bank under the amount needed for max "Lucky!" rewards', toggle: true}; CM.ConfigData.ToolWarnLuckyFrenzy = {type: 'bool', group: 'Tooltip', label: ['Tooltip Lucky Frenzy Warning OFF', 'Tooltip Lucky Frenzy Warning ON'], desc: 'A warning when buying if it will put the bank under the amount needed for max "Lucky!" (Frenzy) rewards', toggle: true}; @@ -1151,7 +1151,7 @@ CM.Data.ConfigDefault = { WrinklerMaxVolume: 100, WrinklerMaxSoundURL: 'https://freesound.org/data/previews/152/152743_15663-lq.mp3', Title: 1, - TooltipInfo: 1, + TooltipBuildUpgrade: 1, TooltipAmor: 0, ToolWarnLucky: 1, ToolWarnLuckyFrenzy: 1, @@ -2567,9 +2567,6 @@ CM.Disp.TooltipCreateWarningSection = function() { CM.Disp.UpdateTooltip = function() { CM.Sim.CopyData(); if (l('tooltipAnchor').style.display != 'none' && l('CMTooltipArea')) { - if (CM.Options.TooltipInfo == 0) { - l('CMTooltipArea').style.display = "none"; - } l('CMTooltipArea').innerHTML = ''; tooltipBox = CM.Disp.TooltipCreateTooltipBox(); l('CMTooltipArea').appendChild(tooltipBox); @@ -2603,7 +2600,7 @@ CM.Disp.UpdateTooltip = function() { * It is called when Building tooltips are created or refreshed by CM.Disp.UpdateTooltip() */ CM.Disp.UpdateTooltipBuilding = function() { - if (CM.Options.TooltipInfo == 1 && Game.buyMode == 1) { + if (CM.Options.TooltipBuildUpgrade == 1 && Game.buyMode == 1) { tooltipBox = l('CMTooltipBorder'); CM.Disp.TooltipCreateCalculationSection(tooltipBox); @@ -2618,7 +2615,7 @@ CM.Disp.UpdateTooltipBuilding = function() { CM.Disp.TooltipBonusIncome = CM.Cache[target][CM.Disp.tooltipName].bonus; - if (CM.Options.TooltipInfo == 1 && Game.buyMode == 1) { + if (CM.Options.TooltipBuildUpgrade == 1 && Game.buyMode == 1) { l('CMTooltipIncome').textContent = Beautify(CM.Disp.TooltipBonusIncome, 2); var increase = Math.round(CM.Disp.TooltipBonusIncome / Game.cookiesPs * 10000); if (isFinite(increase) && increase != 0) { @@ -2654,6 +2651,7 @@ CM.Disp.UpdateTooltipBuilding = function() { l('CMTooltipTime').style.marginBottom = '0px'; } } + else l('CMTooltipArea').style.display = "none"; } /** @@ -2668,7 +2666,7 @@ CM.Disp.UpdateTooltipUpgrade = function() { CM.Disp.TooltipPrice = Game.Upgrades[Game.UpgradesInStore[CM.Disp.tooltipName].name].getPrice(); CM.Disp.TooltipBonusMouse = CM.Cache.Upgrades[Game.UpgradesInStore[CM.Disp.tooltipName].name].bonusMouse - if (CM.Options.TooltipInfo == 1) { + if (CM.Options.TooltipBuildUpgrade == 1) { l('CMTooltipIncome').textContent = Beautify(CM.Disp.TooltipBonusIncome, 2); var increase = Math.round(CM.Disp.TooltipBonusIncome / Game.cookiesPs * 10000); if (isFinite(increase) && increase != 0) { @@ -2708,6 +2706,7 @@ CM.Disp.UpdateTooltipUpgrade = function() { l('CMTooltipBorder').appendChild(chocolate); } } + else l('CMTooltipArea').style.display = "none"; } /** @@ -2728,6 +2727,7 @@ CM.Disp.UpdateTooltipSugarLump = function() { lumpType.textContent = lumpColor.text; lumpType.className = CM.Disp.colorTextPre + lumpColor.color; } + else l('CMTooltipArea').style.display = "none"; } /** @@ -2783,6 +2783,7 @@ CM.Disp.UpdateTooltipGrimoire = function() { l('CMTooltipArea').appendChild(tooltipBox); } + else l('CMTooltipArea').style.display = "none"; } /** diff --git a/src/Data.js b/src/Data.js index 13d9d22..e481133 100644 --- a/src/Data.js +++ b/src/Data.js @@ -180,7 +180,7 @@ CM.ConfigData.WrinklerMaxSoundURL = {type: 'url', group: 'NotificationWrinkMax', CM.ConfigData.Title = {type: 'bool', group: 'Notification', label: ['Title OFF', 'Title ON', 'Title Pinned Tab Highlight'], desc: 'Update title with Golden Cookie/Season Popup timers; pinned tab highlight only changes the title when a Golden Cookie/Season Popup spawns', toggle: true}; // Tooltip -CM.ConfigData.TooltipInfo = {type: 'bool', group: 'Tooltip', label: ['Extra Tooltip Information OFF', 'Extra Tooltip Information ON'], desc: 'Extra information in tooltips', toggle: true}; +CM.ConfigData.TooltipBuildUpgrade = {type: 'bool', group: 'Tooltip', label: ['Building/Upgrade Tooltip Information OFF', 'Building/Upgrade Tooltip Information ON'], desc: 'Extra information in Building/Upgrade tooltips', toggle: true}; CM.ConfigData.TooltipAmor = {type: 'bool', group: 'Tooltip', label: ['Buildings Tooltip Amortization Information OFF', 'Buildings Tooltip Amortization Information ON'], desc: 'Add amortization information to buildings tooltip', toggle: true}; CM.ConfigData.ToolWarnLucky = {type: 'bool', group: 'Tooltip', label: ['Tooltip Lucky Warning OFF', 'Tooltip Lucky Warning ON'], desc: 'A warning when buying if it will put the bank under the amount needed for max "Lucky!" rewards', toggle: true}; CM.ConfigData.ToolWarnLuckyFrenzy = {type: 'bool', group: 'Tooltip', label: ['Tooltip Lucky Frenzy Warning OFF', 'Tooltip Lucky Frenzy Warning ON'], desc: 'A warning when buying if it will put the bank under the amount needed for max "Lucky!" (Frenzy) rewards', toggle: true}; @@ -267,7 +267,7 @@ CM.Data.ConfigDefault = { WrinklerMaxVolume: 100, WrinklerMaxSoundURL: 'https://freesound.org/data/previews/152/152743_15663-lq.mp3', Title: 1, - TooltipInfo: 1, + TooltipBuildUpgrade: 1, TooltipAmor: 0, ToolWarnLucky: 1, ToolWarnLuckyFrenzy: 1, diff --git a/src/Disp.js b/src/Disp.js index dc0b6a0..b424616 100644 --- a/src/Disp.js +++ b/src/Disp.js @@ -1382,9 +1382,6 @@ CM.Disp.TooltipCreateWarningSection = function() { CM.Disp.UpdateTooltip = function() { CM.Sim.CopyData(); if (l('tooltipAnchor').style.display != 'none' && l('CMTooltipArea')) { - if (CM.Options.TooltipInfo == 0) { - l('CMTooltipArea').style.display = "none"; - } l('CMTooltipArea').innerHTML = ''; tooltipBox = CM.Disp.TooltipCreateTooltipBox(); l('CMTooltipArea').appendChild(tooltipBox); @@ -1418,7 +1415,7 @@ CM.Disp.UpdateTooltip = function() { * It is called when Building tooltips are created or refreshed by CM.Disp.UpdateTooltip() */ CM.Disp.UpdateTooltipBuilding = function() { - if (CM.Options.TooltipInfo == 1 && Game.buyMode == 1) { + if (CM.Options.TooltipBuildUpgrade == 1 && Game.buyMode == 1) { tooltipBox = l('CMTooltipBorder'); CM.Disp.TooltipCreateCalculationSection(tooltipBox); @@ -1433,7 +1430,7 @@ CM.Disp.UpdateTooltipBuilding = function() { CM.Disp.TooltipBonusIncome = CM.Cache[target][CM.Disp.tooltipName].bonus; - if (CM.Options.TooltipInfo == 1 && Game.buyMode == 1) { + if (CM.Options.TooltipBuildUpgrade == 1 && Game.buyMode == 1) { l('CMTooltipIncome').textContent = Beautify(CM.Disp.TooltipBonusIncome, 2); var increase = Math.round(CM.Disp.TooltipBonusIncome / Game.cookiesPs * 10000); if (isFinite(increase) && increase != 0) { @@ -1469,6 +1466,7 @@ CM.Disp.UpdateTooltipBuilding = function() { l('CMTooltipTime').style.marginBottom = '0px'; } } + else l('CMTooltipArea').style.display = "none"; } /** @@ -1483,7 +1481,7 @@ CM.Disp.UpdateTooltipUpgrade = function() { CM.Disp.TooltipPrice = Game.Upgrades[Game.UpgradesInStore[CM.Disp.tooltipName].name].getPrice(); CM.Disp.TooltipBonusMouse = CM.Cache.Upgrades[Game.UpgradesInStore[CM.Disp.tooltipName].name].bonusMouse - if (CM.Options.TooltipInfo == 1) { + if (CM.Options.TooltipBuildUpgrade == 1) { l('CMTooltipIncome').textContent = Beautify(CM.Disp.TooltipBonusIncome, 2); var increase = Math.round(CM.Disp.TooltipBonusIncome / Game.cookiesPs * 10000); if (isFinite(increase) && increase != 0) { @@ -1523,6 +1521,7 @@ CM.Disp.UpdateTooltipUpgrade = function() { l('CMTooltipBorder').appendChild(chocolate); } } + else l('CMTooltipArea').style.display = "none"; } /** @@ -1543,6 +1542,7 @@ CM.Disp.UpdateTooltipSugarLump = function() { lumpType.textContent = lumpColor.text; lumpType.className = CM.Disp.colorTextPre + lumpColor.color; } + else l('CMTooltipArea').style.display = "none"; } /** @@ -1598,6 +1598,7 @@ CM.Disp.UpdateTooltipGrimoire = function() { l('CMTooltipArea').appendChild(tooltipBox); } + else l('CMTooltipArea').style.display = "none"; } /** From 45c3df2d4be75cd8b5e29eff6f599d022289169b Mon Sep 17 00:00:00 2001 From: Daniel van Noord Date: Tue, 26 Jan 2021 22:30:27 +0100 Subject: [PATCH 017/145] Fixed plant tooltips --- CookieMonster.js | 8 +++----- src/Disp.js | 6 ++---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/CookieMonster.js b/CookieMonster.js index 09212f3..0ec298e 100644 --- a/CookieMonster.js +++ b/CookieMonster.js @@ -1064,7 +1064,7 @@ CM.ConfigData.WrinklerMaxSoundURL = {type: 'url', group: 'NotificationWrinkMax', CM.ConfigData.Title = {type: 'bool', group: 'Notification', label: ['Title OFF', 'Title ON', 'Title Pinned Tab Highlight'], desc: 'Update title with Golden Cookie/Season Popup timers; pinned tab highlight only changes the title when a Golden Cookie/Season Popup spawns', toggle: true}; // Tooltip -CM.ConfigData.TooltipBuildUpgrade = {type: 'bool', group: 'Tooltip', label: ['Extra Tooltip Information OFF', 'Extra Tooltip Information ON'], desc: 'Extra information in tooltips', toggle: true}; +CM.ConfigData.TooltipBuildUpgrade = {type: 'bool', group: 'Tooltip', label: ['Building/Upgrade Tooltip Information OFF', 'Building/Upgrade Tooltip Information ON'], desc: 'Extra information in Building/Upgrade tooltips', toggle: true}; CM.ConfigData.TooltipAmor = {type: 'bool', group: 'Tooltip', label: ['Buildings Tooltip Amortization Information OFF', 'Buildings Tooltip Amortization Information ON'], desc: 'Add amortization information to buildings tooltip', toggle: true}; CM.ConfigData.ToolWarnLucky = {type: 'bool', group: 'Tooltip', label: ['Tooltip Lucky Warning OFF', 'Tooltip Lucky Warning ON'], desc: 'A warning when buying if it will put the bank under the amount needed for max "Lucky!" rewards', toggle: true}; CM.ConfigData.ToolWarnLuckyFrenzy = {type: 'bool', group: 'Tooltip', label: ['Tooltip Lucky Frenzy Warning OFF', 'Tooltip Lucky Frenzy Warning ON'], desc: 'A warning when buying if it will put the bank under the amount needed for max "Lucky!" (Frenzy) rewards', toggle: true}; @@ -2792,9 +2792,8 @@ CM.Disp.UpdateTooltipGrimoire = function() { * It adds to the additional information to l('CMTooltipArea') */ CM.Disp.UpdateTooltipGardenPlots = function() { - if (CM.Options.TooltipLump) { - var minigame = Game.Objects['Farm'].minigame; - if (minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] != 0) { + var minigame = Game.Objects['Farm'].minigame; + if (CM.Options.TooltipLump && minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] != 0) { var mature = minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][1] > minigame.plantsById[minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] - 1].matureBase; var plantName = minigame.plantsById[minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] - 1].name; l('CMTooltipBorder').appendChild(CM.Disp.TooltipCreateHeader('Reward (Current / Maximum)')); @@ -2814,7 +2813,6 @@ CM.Disp.UpdateTooltipGardenPlots = function() { l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.08, Game.cookiesPs * 60 * 120)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 120); } else l('CMTooltipArea').style.display = "none"; - } } else l('CMTooltipArea').style.display = "none"; } diff --git a/src/Disp.js b/src/Disp.js index b424616..019439a 100644 --- a/src/Disp.js +++ b/src/Disp.js @@ -1607,9 +1607,8 @@ CM.Disp.UpdateTooltipGrimoire = function() { * It adds to the additional information to l('CMTooltipArea') */ CM.Disp.UpdateTooltipGardenPlots = function() { - if (CM.Options.TooltipLump) { - var minigame = Game.Objects['Farm'].minigame; - if (minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] != 0) { + var minigame = Game.Objects['Farm'].minigame; + if (CM.Options.TooltipLump && minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] != 0) { var mature = minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][1] > minigame.plantsById[minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] - 1].matureBase; var plantName = minigame.plantsById[minigame.plot[CM.Disp.tooltipName[1]][CM.Disp.tooltipName[0]][0] - 1].name; l('CMTooltipBorder').appendChild(CM.Disp.TooltipCreateHeader('Reward (Current / Maximum)')); @@ -1629,7 +1628,6 @@ CM.Disp.UpdateTooltipGardenPlots = function() { l('CMTooltipPlantReward').textContent = (mature ? CM.Disp.Beautify(Math.min(Game.cookies * 0.08, Game.cookiesPs * 60 * 120)) : "0") + " / " + CM.Disp.Beautify(Game.cookiesPs * 60 * 120); } else l('CMTooltipArea').style.display = "none"; - } } else l('CMTooltipArea').style.display = "none"; } From 94ba7487b114838f649840ce1d7139756d2f3a60 Mon Sep 17 00:00:00 2001 From: DanielNoord Date: Tue, 26 Jan 2021 23:17:59 +0100 Subject: [PATCH 018/145] Create main.yml --- .github/workflows/main.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..9508eb0 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,11 @@ +name: CI +on: pull_request +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install modules + run: yarn + - name: Run ESLint + run: eslint . --ext .js From 1d639a972105450b839693d194163aee96fa9d88 Mon Sep 17 00:00:00 2001 From: DanielNoord Date: Tue, 26 Jan 2021 23:20:39 +0100 Subject: [PATCH 019/145] Update main.yml --- .github/workflows/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9508eb0..fd5f60a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,6 +6,8 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install modules - run: yarn + run: yarn init + run: yarn add eslint --dev + run: yarn run eslint --init - name: Run ESLint run: eslint . --ext .js From 30f6ecf8f2c1d4ce13f778ad816d3f60a2a928a3 Mon Sep 17 00:00:00 2001 From: DanielNoord Date: Tue, 26 Jan 2021 23:23:05 +0100 Subject: [PATCH 020/145] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fd5f60a..73bb6a7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,5 +1,5 @@ name: CI -on: pull_request +on: [push, pull_request] jobs: build: runs-on: ubuntu-latest From 1d51a36ccdcc911b31610d88bd8b321c2911b199 Mon Sep 17 00:00:00 2001 From: DanielNoord Date: Tue, 26 Jan 2021 23:28:24 +0100 Subject: [PATCH 021/145] Update main.yml --- .github/workflows/main.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 73bb6a7..8217e21 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,8 +6,9 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install modules - run: yarn init - run: yarn add eslint --dev - run: yarn run eslint --init + run: + yarn init + yarn add eslint --dev + yarn run eslint --init - name: Run ESLint run: eslint . --ext .js From 3b137aa8826223c3230e68a959c35b04c965976f Mon Sep 17 00:00:00 2001 From: DanielNoord Date: Tue, 26 Jan 2021 23:30:01 +0100 Subject: [PATCH 022/145] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8217e21..f4ed5ff 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,7 +6,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install modules - run: + run: | yarn init yarn add eslint --dev yarn run eslint --init From 93e50181fe6367e1e2a175583f46217845d2b218 Mon Sep 17 00:00:00 2001 From: DanielNoord Date: Tue, 26 Jan 2021 23:31:49 +0100 Subject: [PATCH 023/145] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f4ed5ff..59aad9a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,7 +7,7 @@ jobs: - uses: actions/checkout@v2 - name: Install modules run: | - yarn init + yarn yarn add eslint --dev yarn run eslint --init - name: Run ESLint From cb91c913218b66d4cd0f0b72689178666f293d02 Mon Sep 17 00:00:00 2001 From: DanielNoord Date: Tue, 26 Jan 2021 23:33:42 +0100 Subject: [PATCH 024/145] Update main.yml --- .github/workflows/main.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 59aad9a..570e595 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,9 +6,6 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install modules - run: | - yarn - yarn add eslint --dev - yarn run eslint --init - - name: Run ESLint - run: eslint . --ext .js + run: yarn + - name: Lint + run: eslint . From d30a064c69c96befebea4a0125178ea385bd467f Mon Sep 17 00:00:00 2001 From: DanielNoord Date: Tue, 26 Jan 2021 23:38:03 +0100 Subject: [PATCH 025/145] Update main.yml --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 570e595..afeca94 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,6 +5,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + - uses: actions/setup-node - name: Install modules run: yarn - name: Lint From 6dd4022a8098cbc4e525cc2f0593408bfedaa356 Mon Sep 17 00:00:00 2001 From: DanielNoord Date: Tue, 26 Jan 2021 23:39:01 +0100 Subject: [PATCH 026/145] Update main.yml --- .github/workflows/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index afeca94..3a34bb1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,7 +5,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: actions/setup-node + - uses: actions/setup-node@v2 + with: + node-version: '12' - name: Install modules run: yarn - name: Lint From b4cb0fee523a8518abecd03f36efb52c609c5086 Mon Sep 17 00:00:00 2001 From: DanielNoord Date: Tue, 26 Jan 2021 23:43:08 +0100 Subject: [PATCH 027/145] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3a34bb1..cbb5fb4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,6 +9,6 @@ jobs: with: node-version: '12' - name: Install modules - run: yarn + run: yarn install - name: Lint run: eslint . From 31ea583edbf093db8f0af2ffb1c1874943e0d497 Mon Sep 17 00:00:00 2001 From: DanielNoord Date: Tue, 26 Jan 2021 23:47:49 +0100 Subject: [PATCH 028/145] Update main.yml --- .github/workflows/main.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cbb5fb4..ba98d64 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,7 +8,12 @@ jobs: - uses: actions/setup-node@v2 with: node-version: '12' - - name: Install modules - run: yarn install + - name: Install dependencies + run: + yarn init + yarn add eslint --dev + yarn install - name: Lint - run: eslint . + run: + yarn run eslint --init + eslint . From 1aa6d3797ba417756c1bfbded25336dddad97cad Mon Sep 17 00:00:00 2001 From: DanielNoord Date: Tue, 26 Jan 2021 23:48:51 +0100 Subject: [PATCH 029/145] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ba98d64..f732c8e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,7 +9,7 @@ jobs: with: node-version: '12' - name: Install dependencies - run: + run: | yarn init yarn add eslint --dev yarn install From 1a73fb8a2d1da063055e8fdd69026dd318fe7c80 Mon Sep 17 00:00:00 2001 From: DanielNoord Date: Tue, 26 Jan 2021 23:50:02 +0100 Subject: [PATCH 030/145] Update main.yml --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f732c8e..73744a5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,10 +10,10 @@ jobs: node-version: '12' - name: Install dependencies run: | - yarn init - yarn add eslint --dev yarn install + yarn add eslint --dev - name: Lint - run: + run: | + yarn init yarn run eslint --init eslint . From 843bb00f34e30f6ae7aef4f95b4c3aeed85b49d3 Mon Sep 17 00:00:00 2001 From: DanielNoord Date: Tue, 26 Jan 2021 23:50:52 +0100 Subject: [PATCH 031/145] Update main.yml --- .github/workflows/main.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 73744a5..a3e499b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,6 +14,5 @@ jobs: yarn add eslint --dev - name: Lint run: | - yarn init yarn run eslint --init eslint . From e6728157b374aab94616260dd6a55fbb51172b64 Mon Sep 17 00:00:00 2001 From: DanielNoord Date: Tue, 26 Jan 2021 23:52:25 +0100 Subject: [PATCH 032/145] Update main.yml --- .github/workflows/main.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a3e499b..0eb0ebf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,8 +11,7 @@ jobs: - name: Install dependencies run: | yarn install - yarn add eslint --dev - name: Lint run: | yarn run eslint --init - eslint . + yarn run eslint . --ext .js From 7186be028bef8dc15d3a019ab5ec9a3da331492a Mon Sep 17 00:00:00 2001 From: DanielNoord Date: Tue, 26 Jan 2021 23:54:49 +0100 Subject: [PATCH 033/145] Update main.yml --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0eb0ebf..52bb6eb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,5 +13,6 @@ jobs: yarn install - name: Lint run: | + yarn init yarn run eslint --init yarn run eslint . --ext .js From 4649ab87c6428fb276008b510540af38637261f4 Mon Sep 17 00:00:00 2001 From: DanielNoord Date: Tue, 26 Jan 2021 23:58:53 +0100 Subject: [PATCH 034/145] Update main.yml --- .github/workflows/main.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 52bb6eb..929f60c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,9 +10,9 @@ jobs: node-version: '12' - name: Install dependencies run: | - yarn install + npm install eslint --save-dev + npm init - name: Lint run: | - yarn init - yarn run eslint --init - yarn run eslint . --ext .js + npx eslint --init + npx eslint . --ext .js From 61fc4aaaef1d35841bc862e9e042f85d5bb3fd24 Mon Sep 17 00:00:00 2001 From: DanielNoord Date: Wed, 27 Jan 2021 00:00:29 +0100 Subject: [PATCH 035/145] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 929f60c..4052a36 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,8 +10,8 @@ jobs: node-version: '12' - name: Install dependencies run: | - npm install eslint --save-dev npm init + npm install eslint --save-dev - name: Lint run: | npx eslint --init From abc7dce047572f3640922b087988eb7febc1614a Mon Sep 17 00:00:00 2001 From: DanielNoord Date: Wed, 27 Jan 2021 00:05:42 +0100 Subject: [PATCH 036/145] Delete .github/workflows directory --- .github/workflows/main.yml | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 4052a36..0000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: CI -on: [push, pull_request] -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 - with: - node-version: '12' - - name: Install dependencies - run: | - npm init - npm install eslint --save-dev - - name: Lint - run: | - npx eslint --init - npx eslint . --ext .js From 235900c82614c0f66fbd644f6a9953e881415c5c Mon Sep 17 00:00:00 2001 From: PneuJai <53138480+Rjlintkh@users.noreply.github.com> Date: Wed, 27 Jan 2021 15:12:17 +0800 Subject: [PATCH 037/145] rename labels of MissingAchievements --- src/Data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data.js b/src/Data.js index a9191ec..f1122d3 100644 --- a/src/Data.js +++ b/src/Data.js @@ -196,7 +196,7 @@ CM.ConfigData.DragonAuraInfo = {type: 'bool', group: 'Tooltip', label: ['Extra D // Statistics CM.ConfigData.Stats = {type: 'bool', group: 'Statistics', label: ['Statistics OFF', 'Statistics ON'], desc: 'Extra Cookie Monster statistics!', toggle: true}; CM.ConfigData.MissingUpgrades = {type: 'bool', group: 'Statistics', label: ['Missing Upgrades OFF', 'Missing Upgrades ON'], desc: 'Shows Missing upgrades in Stats Menu. This feature can be laggy for users with a low amount of unlocked achievements.', toggle: true}; -CM.ConfigData.MissingAchievements = {type: 'bool', group: 'Statistics', label: ['Show Normal Missing Achievements', 'Show Shadow Missing Achievements', 'Show All Missing Achievements', 'Hide Missing Achievements'], desc: 'Shows Missing normal or shadow achievements in Stats Menu.', toggle: false}; +CM.ConfigData.MissingAchievements = {type: 'bool', group: 'Statistics', label: ['Missing Normal Achievements ON', 'Missing Shadow Achievements ON', 'All Missing Achievements ON', 'Missing Achievements OFF'], desc: 'Shows Missing normal or shadow achievements in Stats Menu.', toggle: false}; CM.ConfigData.UpStats = {type: 'bool', group: 'Statistics', label: ['Statistics Update Rate (Default)', 'Statistics Update Rate (1s)'], desc: 'Default Game rate is once every 5 seconds', toggle: false}; CM.ConfigData.TimeFormat = {type: 'bool', group: 'Statistics', label: ['Time XXd, XXh, XXm, XXs', 'Time XX:XX:XX:XX:XX'], desc: 'Change the time format', toggle: false}; CM.ConfigData.DetailedTime = {type: 'bool', group: 'Statistics', label: ['Detailed Time OFF', 'Detailed Time ON'], desc: 'Change how time is displayed in certain statistics and tooltips', toggle: true, func: function() {CM.Disp.ToggleDetailedTime();}}; From 00c513798abc73859ee5a172a2e89fbf84a6124f Mon Sep 17 00:00:00 2001 From: Daniel van Noord Date: Wed, 27 Jan 2021 21:20:22 +0100 Subject: [PATCH 038/145] Make Garden tooltip load on LoadMinigames --- CookieMonster.js | 11 +++++++++-- src/Main.js | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CookieMonster.js b/CookieMonster.js index 0ec298e..709f3aa 100644 --- a/CookieMonster.js +++ b/CookieMonster.js @@ -4092,6 +4092,7 @@ CM.ReplaceNative = function() { l('bigCookie').addEventListener('click', function() { CM.Main.FixMouseY(Game.ClickCookie); }, false); // Probably better to load per minigame + // TODO! CM.Backup.scriptLoaded = Game.scriptLoaded; Game.scriptLoaded = function(who, script) { CM.Backup.scriptLoaded(who, script); @@ -4318,9 +4319,15 @@ CM.DelayInit = function() { */ CM.Main.ReplaceTooltips = function() { CM.Main.ReplaceTooltipBuild(); - CM.Main.ReplaceTooltipGrimoire(); CM.Main.ReplaceTooltipLump(); - CM.Main.ReplaceTooltipGarden(); + CM.Main.ReplaceTooltipGrimoire(); + + CM.Backup.LoadMinigames = Game.LoadMinigames; + Game.LoadMinigames = function() { + CM.Backup.LoadMinigames(); + CM.Main.ReplaceTooltipGarden(); + } + Game.LoadMinigames(); } /******** diff --git a/src/Main.js b/src/Main.js index 9a8e75e..011f8cf 100644 --- a/src/Main.js +++ b/src/Main.js @@ -42,6 +42,7 @@ CM.ReplaceNative = function() { l('bigCookie').addEventListener('click', function() { CM.Main.FixMouseY(Game.ClickCookie); }, false); // Probably better to load per minigame + // TODO! CM.Backup.scriptLoaded = Game.scriptLoaded; Game.scriptLoaded = function(who, script) { CM.Backup.scriptLoaded(who, script); @@ -268,9 +269,15 @@ CM.DelayInit = function() { */ CM.Main.ReplaceTooltips = function() { CM.Main.ReplaceTooltipBuild(); - CM.Main.ReplaceTooltipGrimoire(); CM.Main.ReplaceTooltipLump(); - CM.Main.ReplaceTooltipGarden(); + CM.Main.ReplaceTooltipGrimoire(); + + CM.Backup.LoadMinigames = Game.LoadMinigames; + Game.LoadMinigames = function() { + CM.Backup.LoadMinigames(); + CM.Main.ReplaceTooltipGarden(); + } + Game.LoadMinigames(); } /******** From 0171732e7066128018f830ce7c74301604588e2d Mon Sep 17 00:00:00 2001 From: Daniel van Noord Date: Wed, 27 Jan 2021 21:30:50 +0100 Subject: [PATCH 039/145] Made Grimoire tooltip always launch --- CookieMonster.js | 11 ++--------- src/Main.js | 18 ++++++------------ 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/CookieMonster.js b/CookieMonster.js index 709f3aa..3048252 100644 --- a/CookieMonster.js +++ b/CookieMonster.js @@ -4091,15 +4091,6 @@ CM.ReplaceNative = function() { l('bigCookie').removeEventListener('click', Game.ClickCookie, false); l('bigCookie').addEventListener('click', function() { CM.Main.FixMouseY(Game.ClickCookie); }, false); - // Probably better to load per minigame - // TODO! - CM.Backup.scriptLoaded = Game.scriptLoaded; - Game.scriptLoaded = function(who, script) { - CM.Backup.scriptLoaded(who, script); - CM.Main.ReplaceTooltipGrimoire() - CM.ReplaceNativeGrimoire(); - } - CM.Backup.RebuildUpgrades = Game.RebuildUpgrades; Game.RebuildUpgrades = function() { CM.Backup.RebuildUpgrades(); @@ -4326,6 +4317,8 @@ CM.Main.ReplaceTooltips = function() { Game.LoadMinigames = function() { CM.Backup.LoadMinigames(); CM.Main.ReplaceTooltipGarden(); + CM.Main.ReplaceTooltipGrimoire() + CM.ReplaceNativeGrimoire(); } Game.LoadMinigames(); } diff --git a/src/Main.js b/src/Main.js index 011f8cf..06265b7 100644 --- a/src/Main.js +++ b/src/Main.js @@ -41,15 +41,6 @@ CM.ReplaceNative = function() { l('bigCookie').removeEventListener('click', Game.ClickCookie, false); l('bigCookie').addEventListener('click', function() { CM.Main.FixMouseY(Game.ClickCookie); }, false); - // Probably better to load per minigame - // TODO! - CM.Backup.scriptLoaded = Game.scriptLoaded; - Game.scriptLoaded = function(who, script) { - CM.Backup.scriptLoaded(who, script); - CM.Main.ReplaceTooltipGrimoire() - CM.ReplaceNativeGrimoire(); - } - CM.Backup.RebuildUpgrades = Game.RebuildUpgrades; Game.RebuildUpgrades = function() { CM.Backup.RebuildUpgrades(); @@ -269,13 +260,16 @@ CM.DelayInit = function() { */ CM.Main.ReplaceTooltips = function() { CM.Main.ReplaceTooltipBuild(); - CM.Main.ReplaceTooltipLump(); - CM.Main.ReplaceTooltipGrimoire(); - + CM.Main.ReplaceTooltipLump(); + + // Replace Tooltips of Minigames. Nesting it in LoadMinigames makes sure to replace them even if + // they were not loaded initially CM.Backup.LoadMinigames = Game.LoadMinigames; Game.LoadMinigames = function() { CM.Backup.LoadMinigames(); CM.Main.ReplaceTooltipGarden(); + CM.Main.ReplaceTooltipGrimoire() + CM.ReplaceNativeGrimoire(); } Game.LoadMinigames(); } From 5abdc77e300e0f6e3403ee45bf39d137467d689a Mon Sep 17 00:00:00 2001 From: Daniel van Noord Date: Wed, 27 Jan 2021 21:43:24 +0100 Subject: [PATCH 040/145] Added data on possible effects --- CookieMonster.js | 34 +++++++++++++++++++++++++++++++--- src/Data.js | 27 +++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/CookieMonster.js b/CookieMonster.js index 3048252..d5faf20 100644 --- a/CookieMonster.js +++ b/CookieMonster.js @@ -919,6 +919,33 @@ CM.Data.ChristCookies = ['Christmas tree biscuits', 'Snowflake biscuits', 'Snowm CM.Data.ValCookies = ['Pure heart biscuits', 'Ardent heart biscuits', 'Sour heart biscuits', 'Weeping heart biscuits', 'Golden heart biscuits', 'Eternal heart biscuits', 'Prism heart biscuits']; CM.Data.PlantDrops = ['Elderwort biscuits', 'Bakeberry cookies', 'Duketater cookies', 'Green yeast digestives', 'Wheat slims', 'Fern tea', 'Ichor syrup'] +/******** + * Section: All possible effects plants and other items can have with an explanation */ + +CM.Data.Effects = { + buildingCost: "Building prices", + click: "Cookies per click", + cps: "Total CPS", + cursorCps: "Cursor CPS", + goldenCookieDur: "Golden cookie duration", + goldenCookieEffDur: "Golden cookie effect duration", + goldenCookieFreq: "Golden cookie frequency", + goldenCookieGain: "Golden cookie gains", + grandmaCps: "Grandma CPS", + itemDrops: "Random item drop chance", + milk: "Effect from milk", + reindeerDur: "Reindeer duration", + reindeerFreq: "Reindeer frequency", + reindeerGain: "Reindeer gains", + upgradeCost: "Upgrade prices", + wrathCookieDur: "Wrath cookie duration", + wrathCookieEffDur: "Wrath cookie effect duration", + wrathCookieFreq: "Wrath cookie frequency", + wrathCookieGain: "Wrath cookie gains", + wrinklerEat: "Wrinkler ", + wrinklerSpawn: "Wrinkler spawn frequency" +} + /******** * Section: Data for the various scales used by CookieMonster */ @@ -4310,9 +4337,10 @@ CM.DelayInit = function() { */ CM.Main.ReplaceTooltips = function() { CM.Main.ReplaceTooltipBuild(); - CM.Main.ReplaceTooltipLump(); - CM.Main.ReplaceTooltipGrimoire(); - + CM.Main.ReplaceTooltipLump(); + + // Replace Tooltips of Minigames. Nesting it in LoadMinigames makes sure to replace them even if + // they were not loaded initially CM.Backup.LoadMinigames = Game.LoadMinigames; Game.LoadMinigames = function() { CM.Backup.LoadMinigames(); diff --git a/src/Data.js b/src/Data.js index e481133..050f82b 100644 --- a/src/Data.js +++ b/src/Data.js @@ -35,6 +35,33 @@ CM.Data.ChristCookies = ['Christmas tree biscuits', 'Snowflake biscuits', 'Snowm CM.Data.ValCookies = ['Pure heart biscuits', 'Ardent heart biscuits', 'Sour heart biscuits', 'Weeping heart biscuits', 'Golden heart biscuits', 'Eternal heart biscuits', 'Prism heart biscuits']; CM.Data.PlantDrops = ['Elderwort biscuits', 'Bakeberry cookies', 'Duketater cookies', 'Green yeast digestives', 'Wheat slims', 'Fern tea', 'Ichor syrup'] +/******** + * Section: All possible effects plants and other items can have with an explanation */ + +CM.Data.Effects = { + buildingCost: "Building prices", + click: "Cookies per click", + cps: "Total CPS", + cursorCps: "Cursor CPS", + goldenCookieDur: "Golden cookie duration", + goldenCookieEffDur: "Golden cookie effect duration", + goldenCookieFreq: "Golden cookie frequency", + goldenCookieGain: "Golden cookie gains", + grandmaCps: "Grandma CPS", + itemDrops: "Random item drop chance", + milk: "Effect from milk", + reindeerDur: "Reindeer duration", + reindeerFreq: "Reindeer frequency", + reindeerGain: "Reindeer gains", + upgradeCost: "Upgrade prices", + wrathCookieDur: "Wrath cookie duration", + wrathCookieEffDur: "Wrath cookie effect duration", + wrathCookieFreq: "Wrath cookie frequency", + wrathCookieGain: "Wrath cookie gains", + wrinklerEat: "Wrinkler ", + wrinklerSpawn: "Wrinkler spawn frequency" +} + /******** * Section: Data for the various scales used by CookieMonster */ From 6c852e2c50d992882ac70c4d0e6e10fae4dfbacc Mon Sep 17 00:00:00 2001 From: Daniel van Noord Date: Wed, 27 Jan 2021 22:12:37 +0100 Subject: [PATCH 041/145] Tooltip for harvest all button #227 --- CookieMonster.js | 48 +++++++++++++++++++++++++++++++++++++++++++++++- src/Disp.js | 47 ++++++++++++++++++++++++++++++++++++++++++++++- src/Main.js | 1 + 3 files changed, 94 insertions(+), 2 deletions(-) diff --git a/CookieMonster.js b/CookieMonster.js index d5faf20..cfece1b 100644 --- a/CookieMonster.js +++ b/CookieMonster.js @@ -2446,9 +2446,10 @@ CM.Disp.Tooltip = function(type, name) { else if (type === 's') l('tooltip').innerHTML = Game.lumpTooltip(); // Sugar Lumps else if (type === 'g') l('tooltip').innerHTML = Game.Objects['Wizard tower'].minigame.spellTooltip(name)(); // Grimoire else if (type == 'p') l('tooltip').innerHTML = Game.ObjectsById[2].minigame.tileTooltip(name[0], name[1])(); // Garden plots + else if (type == 'ha') l('tooltip').innerHTML = Game.ObjectsById[2].minigame.toolTooltip(1)(); // Harvest all button in garden // Adds area for extra tooltip-sections - if ((type == 'b' && Game.buyMode == 1) || type == 'u' || type == 's' || type == 'g' || type == 'p') { + if ((type == 'b' && Game.buyMode == 1) || type == 'u' || type == 's' || type == 'g' || type == 'p' || type == 'ha') { var area = document.createElement('div'); area.id = 'CMTooltipArea'; l('tooltip').appendChild(area); @@ -2613,6 +2614,9 @@ CM.Disp.UpdateTooltip = function() { else if (CM.Disp.tooltipType === 'p') { CM.Disp.UpdateTooltipGardenPlots(); } + else if (CM.Disp.tooltipType === 'ha') { + CM.Disp.UpdateTooltipHarvestAll(); + } CM.Disp.UpdateTooltipWarnings(); } else if (l('CMTooltipArea') == null) { // Remove warnings if its a basic tooltip @@ -2844,6 +2848,47 @@ CM.Disp.UpdateTooltipGardenPlots = function() { else l('CMTooltipArea').style.display = "none"; } +/** + * This function adds extra info to the Garden Harvest All tooltip + * It is called when the Harvest All tooltip is created or refreshed by CM.Disp.UpdateTooltip() + * It adds to the additional information to l('CMTooltipArea') + */ +CM.Disp.UpdateTooltipHarvestAll = function() { + var minigame = Game.Objects['Farm'].minigame; + if (CM.Options.TooltipLump) { + l('CMTooltipBorder').appendChild(CM.Disp.TooltipCreateHeader('Cookies gained from harvesting:')); + var totalGain = 0; + if (Game.keys[16] && Game.keys[17]) var mortal = 1; + for (var y=0;y<6;y++) { + for (var x=0;x<6;x++) { + if (minigame.plot[y][x][0]>=1) { + let tile = minigame.plot[y][x]; + let me = minigame.plantsById[tile[0] - 1]; + let plantName = me.name + + let count = true; + if (mortal && me.immortal) count = false; + if (tile[1] < me.matureBase) count = false; + if (count && plantName == "Bakeberry") { + totalGain += Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 30); + } + else if (count && plantName == "Chocoroot" || plantName == "White chocoroot") { + totalGain += Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 3); + } + else if (count && plantName == "Queenbeet") { + totalGain += Math.min(Game.cookies * 0.04, Game.cookiesPs * 60 * 60); + } + else if (count && plantName == "Duketater") { + totalGain += Math.min(Game.cookies * 0.08, Game.cookiesPs * 60 * 120); + } + } + } + } + l('CMTooltipBorder').appendChild(document.createTextNode(CM.Disp.Beautify(totalGain))); + } + else l('CMTooltipArea').style.display = "none"; +} + /** * This function updates the warnings section of the building and upgrade tooltips * It is called by CM.Disp.UpdateTooltip() @@ -4407,6 +4452,7 @@ CM.Main.ReplaceTooltipLump = function() { */ CM.Main.ReplaceTooltipGarden = function() { if (Game.Objects['Farm'].minigameLoaded) { + l('gardenTool-1').onmouseover = function() {Game.tooltip.dynamic=1; Game.tooltip.draw(this, function() {return CM.Disp.Tooltip('ha', 'HarvestAllButton');}, 'this'); Game.tooltip.wobble();} Array.from(l('gardenPlot').children).forEach((child, index) => { var coords = child.id.slice(-3,); child.onmouseover = function() {Game.tooltip.dynamic=1; Game.tooltip.draw(this, function() {return CM.Disp.Tooltip('p', [`${coords[0]}`,`${coords[2]}`]);}, 'this'); Game.tooltip.wobble();}; diff --git a/src/Disp.js b/src/Disp.js index 019439a..2e10ea6 100644 --- a/src/Disp.js +++ b/src/Disp.js @@ -1234,9 +1234,10 @@ CM.Disp.Tooltip = function(type, name) { else if (type === 's') l('tooltip').innerHTML = Game.lumpTooltip(); // Sugar Lumps else if (type === 'g') l('tooltip').innerHTML = Game.Objects['Wizard tower'].minigame.spellTooltip(name)(); // Grimoire else if (type == 'p') l('tooltip').innerHTML = Game.ObjectsById[2].minigame.tileTooltip(name[0], name[1])(); // Garden plots + else if (type == 'ha') l('tooltip').innerHTML = Game.ObjectsById[2].minigame.toolTooltip(1)(); // Harvest all button in garden // Adds area for extra tooltip-sections - if ((type == 'b' && Game.buyMode == 1) || type == 'u' || type == 's' || type == 'g' || type == 'p') { + if ((type == 'b' && Game.buyMode == 1) || type == 'u' || type == 's' || type == 'g' || type == 'p' || type == 'ha') { var area = document.createElement('div'); area.id = 'CMTooltipArea'; l('tooltip').appendChild(area); @@ -1401,6 +1402,9 @@ CM.Disp.UpdateTooltip = function() { else if (CM.Disp.tooltipType === 'p') { CM.Disp.UpdateTooltipGardenPlots(); } + else if (CM.Disp.tooltipType === 'ha') { + CM.Disp.UpdateTooltipHarvestAll(); + } CM.Disp.UpdateTooltipWarnings(); } else if (l('CMTooltipArea') == null) { // Remove warnings if its a basic tooltip @@ -1632,6 +1636,47 @@ CM.Disp.UpdateTooltipGardenPlots = function() { else l('CMTooltipArea').style.display = "none"; } +/** + * This function adds extra info to the Garden Harvest All tooltip + * It is called when the Harvest All tooltip is created or refreshed by CM.Disp.UpdateTooltip() + * It adds to the additional information to l('CMTooltipArea') + */ +CM.Disp.UpdateTooltipHarvestAll = function() { + var minigame = Game.Objects['Farm'].minigame; + if (CM.Options.TooltipLump) { + l('CMTooltipBorder').appendChild(CM.Disp.TooltipCreateHeader('Cookies gained from harvesting:')); + var totalGain = 0; + if (Game.keys[16] && Game.keys[17]) var mortal = 1; + for (var y=0;y<6;y++) { + for (var x=0;x<6;x++) { + if (minigame.plot[y][x][0]>=1) { + let tile = minigame.plot[y][x]; + let me = minigame.plantsById[tile[0] - 1]; + let plantName = me.name + + let count = true; + if (mortal && me.immortal) count = false; + if (tile[1] < me.matureBase) count = false; + if (count && plantName == "Bakeberry") { + totalGain += Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 30); + } + else if (count && plantName == "Chocoroot" || plantName == "White chocoroot") { + totalGain += Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 3); + } + else if (count && plantName == "Queenbeet") { + totalGain += Math.min(Game.cookies * 0.04, Game.cookiesPs * 60 * 60); + } + else if (count && plantName == "Duketater") { + totalGain += Math.min(Game.cookies * 0.08, Game.cookiesPs * 60 * 120); + } + } + } + } + l('CMTooltipBorder').appendChild(document.createTextNode(CM.Disp.Beautify(totalGain))); + } + else l('CMTooltipArea').style.display = "none"; +} + /** * This function updates the warnings section of the building and upgrade tooltips * It is called by CM.Disp.UpdateTooltip() diff --git a/src/Main.js b/src/Main.js index 06265b7..87b3c48 100644 --- a/src/Main.js +++ b/src/Main.js @@ -330,6 +330,7 @@ CM.Main.ReplaceTooltipLump = function() { */ CM.Main.ReplaceTooltipGarden = function() { if (Game.Objects['Farm'].minigameLoaded) { + l('gardenTool-1').onmouseover = function() {Game.tooltip.dynamic=1; Game.tooltip.draw(this, function() {return CM.Disp.Tooltip('ha', 'HarvestAllButton');}, 'this'); Game.tooltip.wobble();} Array.from(l('gardenPlot').children).forEach((child, index) => { var coords = child.id.slice(-3,); child.onmouseover = function() {Game.tooltip.dynamic=1; Game.tooltip.draw(this, function() {return CM.Disp.Tooltip('p', [`${coords[0]}`,`${coords[2]}`]);}, 'this'); Game.tooltip.wobble();}; From d228967fe7cbadbe666e34f5220f4305121ed2e7 Mon Sep 17 00:00:00 2001 From: PneuJai <53138480+Rjlintkh@users.noreply.github.com> Date: Thu, 28 Jan 2021 13:34:19 +0800 Subject: [PATCH 042/145] set Missing Achievements OFF to the first label --- src/Data.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Data.js b/src/Data.js index f1122d3..cc97655 100644 --- a/src/Data.js +++ b/src/Data.js @@ -196,7 +196,7 @@ CM.ConfigData.DragonAuraInfo = {type: 'bool', group: 'Tooltip', label: ['Extra D // Statistics CM.ConfigData.Stats = {type: 'bool', group: 'Statistics', label: ['Statistics OFF', 'Statistics ON'], desc: 'Extra Cookie Monster statistics!', toggle: true}; CM.ConfigData.MissingUpgrades = {type: 'bool', group: 'Statistics', label: ['Missing Upgrades OFF', 'Missing Upgrades ON'], desc: 'Shows Missing upgrades in Stats Menu. This feature can be laggy for users with a low amount of unlocked achievements.', toggle: true}; -CM.ConfigData.MissingAchievements = {type: 'bool', group: 'Statistics', label: ['Missing Normal Achievements ON', 'Missing Shadow Achievements ON', 'All Missing Achievements ON', 'Missing Achievements OFF'], desc: 'Shows Missing normal or shadow achievements in Stats Menu.', toggle: false}; +CM.ConfigData.MissingAchievements = {type: 'bool', group: 'Statistics', label: ['Missing Achievements OFF', 'Missing Normal Achievements ON', 'Missing Shadow Achievements ON', 'All Missing Achievements ON'], desc: 'Shows Missing normal or shadow achievements in Stats Menu.', toggle: false}; CM.ConfigData.UpStats = {type: 'bool', group: 'Statistics', label: ['Statistics Update Rate (Default)', 'Statistics Update Rate (1s)'], desc: 'Default Game rate is once every 5 seconds', toggle: false}; CM.ConfigData.TimeFormat = {type: 'bool', group: 'Statistics', label: ['Time XXd, XXh, XXm, XXs', 'Time XX:XX:XX:XX:XX'], desc: 'Change the time format', toggle: false}; CM.ConfigData.DetailedTime = {type: 'bool', group: 'Statistics', label: ['Detailed Time OFF', 'Detailed Time ON'], desc: 'Change how time is displayed in certain statistics and tooltips', toggle: true, func: function() {CM.Disp.ToggleDetailedTime();}}; @@ -281,7 +281,7 @@ CM.Data.ConfigDefault = { DragonAuraInfo: 1, Stats: 1, MissingUpgrades: 1, - MissingAchievements: 2, + MissingAchievements: 3, UpStats: 1, TimeFormat: 0, DetailedTime: 1, From 5e5e8f5e22bb32c23029e8d2eeed97d7ddadf18c Mon Sep 17 00:00:00 2001 From: PneuJai <53138480+Rjlintkh@users.noreply.github.com> Date: Thu, 28 Jan 2021 13:36:50 +0800 Subject: [PATCH 043/145] set Missing Achievements OFF to the first label the switch statements make the coding much more easy to understand dont they? --- src/Disp.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Disp.js b/src/Disp.js index cde51e6..ea1b330 100644 --- a/src/Disp.js +++ b/src/Disp.js @@ -1259,10 +1259,10 @@ CM.Disp.ReplaceCrateTooltipAchievements = function() { if (me.type === 'achievement') { let options = {normal: false, shadow: false}; switch (CM.Options.MissingAchievements) { - case 0: options.normal = true; options.shadow = false; break; - case 1: options.normal = false; options.shadow = true; break; - case 2: options.normal = true; options.shadow = true; break; - case 3: options.normal = false; options.shadow = false; break; + case 0: options.normal = false; options.shadow = false; break; + case 1: options.normal = true; options.shadow = false; break; + case 2: options.normal = false; options.shadow = true; break; + case 3: options.normal = true; options.shadow = true; break; } let icon = me.icon; if (options.shadow && me.pool === 'shadow') { @@ -1285,10 +1285,10 @@ CM.Disp.ReplaceCrateTooltipAchievements = function() { if (me.type === 'achievement') { let options = {normal: false, shadow: false}; switch (CM.Options.MissingAchievements) { - case 0: options.normal = true; options.shadow = false; break; - case 1: options.normal = false; options.shadow = true; break; - case 2: options.normal = true; options.shadow = true; break; - case 3: options.normal = false; options.shadow = false; break; + case 0: options.normal = false; options.shadow = false; break; + case 1: options.normal = true; options.shadow = false; break; + case 2: options.normal = false; options.shadow = true; break; + case 3: options.normal = true; options.shadow = true; break; } output = CM.Disp.CrateTooltipAchievementsBackup[1](me,context); if (options.normal && me.pool === 'normal') { From 7b8e29e346bd55458626bdbd0d23c82a7ed1f0b9 Mon Sep 17 00:00:00 2001 From: Daniel van Noord Date: Thu, 28 Jan 2021 22:01:01 +0100 Subject: [PATCH 044/145] Notify's don't occur when loading the mod #495 --- CookieMonster.js | 9 ++++++--- src/Disp.js | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/CookieMonster.js b/CookieMonster.js index cfece1b..901161a 100644 --- a/CookieMonster.js +++ b/CookieMonster.js @@ -2178,7 +2178,8 @@ CM.Disp.CreateWhiteScreen = function() { * @param {string} config The setting in CM.Options that is checked before creating the flash */ CM.Disp.Flash = function(mode, config) { - if ((CM.Options[config] == 1 && mode == 3) || mode == 1) { + // The arguments check makes the sound not play upon initialization of the mod + if ((CM.Options[config] == 1 && mode == 3 && arguments.callee.caller.caller.caller.caller == null) || mode == 1) { CM.Disp.WhiteScreen.style.opacity = '0.5'; if (mode == 3) { CM.Disp.WhiteScreen.style.display = 'inline'; @@ -2203,7 +2204,8 @@ CM.Disp.Flash = function(mode, config) { * @param {string} volConfig The setting in CM.Options that is checked to determine volume */ CM.Disp.PlaySound = function(url, sndConfig, volConfig) { - if (CM.Options[sndConfig] == 1) { + // The arguments check makes the sound not play upon initialization of the mod + if (CM.Options[sndConfig] == 1 && arguments.callee.caller.caller.caller.caller == null) { var sound = new realAudio(url); sound.volume = (CM.Options[volConfig] / 100) * (Game.volume / 100); sound.play(); @@ -2218,7 +2220,8 @@ CM.Disp.PlaySound = function(url, sndConfig, volConfig) { * @param {string} message The text of the to-be created notifications */ CM.Disp.Notification = function(notifyConfig, title, message) { - if (CM.Options[notifyConfig] == 1 && document.visibilityState == 'hidden') { + // The arguments check makes the sound not play upon initialization of the mod + if (CM.Options[notifyConfig] == 1 && document.visibilityState == 'hidden' && arguments.callee.caller.caller.caller.caller == null) { var CookieIcon = 'https://orteil.dashnet.org/cookieclicker/favicon.ico' notification = new Notification(title, {body: message, badge: CookieIcon}); } diff --git a/src/Disp.js b/src/Disp.js index 2e10ea6..23e689f 100644 --- a/src/Disp.js +++ b/src/Disp.js @@ -966,7 +966,8 @@ CM.Disp.CreateWhiteScreen = function() { * @param {string} config The setting in CM.Options that is checked before creating the flash */ CM.Disp.Flash = function(mode, config) { - if ((CM.Options[config] == 1 && mode == 3) || mode == 1) { + // The arguments check makes the sound not play upon initialization of the mod + if ((CM.Options[config] == 1 && mode == 3 && arguments.callee.caller.caller.caller.caller == null) || mode == 1) { CM.Disp.WhiteScreen.style.opacity = '0.5'; if (mode == 3) { CM.Disp.WhiteScreen.style.display = 'inline'; @@ -991,7 +992,8 @@ CM.Disp.Flash = function(mode, config) { * @param {string} volConfig The setting in CM.Options that is checked to determine volume */ CM.Disp.PlaySound = function(url, sndConfig, volConfig) { - if (CM.Options[sndConfig] == 1) { + // The arguments check makes the sound not play upon initialization of the mod + if (CM.Options[sndConfig] == 1 && arguments.callee.caller.caller.caller.caller == null) { var sound = new realAudio(url); sound.volume = (CM.Options[volConfig] / 100) * (Game.volume / 100); sound.play(); @@ -1006,7 +1008,8 @@ CM.Disp.PlaySound = function(url, sndConfig, volConfig) { * @param {string} message The text of the to-be created notifications */ CM.Disp.Notification = function(notifyConfig, title, message) { - if (CM.Options[notifyConfig] == 1 && document.visibilityState == 'hidden') { + // The arguments check makes the sound not play upon initialization of the mod + if (CM.Options[notifyConfig] == 1 && document.visibilityState == 'hidden' && arguments.callee.caller.caller.caller.caller == null) { var CookieIcon = 'https://orteil.dashnet.org/cookieclicker/favicon.ico' notification = new Notification(title, {body: message, badge: CookieIcon}); } From 16ad8f78dc8cfd05ad8191e213d2aa9cd1536045 Mon Sep 17 00:00:00 2001 From: Daniel van Noord Date: Fri, 29 Jan 2021 18:22:57 +0100 Subject: [PATCH 045/145] Update JSColor to 2.4.5 --- jscolor/jscolor.js | 4213 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 3370 insertions(+), 843 deletions(-) diff --git a/jscolor/jscolor.js b/jscolor/jscolor.js index ef3bce5..df9d094 100644 --- a/jscolor/jscolor.js +++ b/jscolor/jscolor.js @@ -1,997 +1,3524 @@ /** - * jscolor, JavaScript Color Picker + * jscolor - JavaScript Color Picker * - * @version 1.4.3 - * @license GNU Lesser General Public License, http://www.gnu.org/copyleft/lesser.html - * @author Jan Odvarko, http://odvarko.cz - * @created 2008-06-15 - * @updated 2014-07-16 * @link http://jscolor.com + * @license For open source use: GPLv3 + * For commercial use: JSColor Commercial License + * @author Jan Odvarko - East Desire + * @version 2.4.5 + * + * See usage examples at http://jscolor.com/examples/ */ -var jscolor = { +(function (global, factory) { + + 'use strict'; + + if (typeof module === 'object' && typeof module.exports === 'object') { + // Export jscolor as a module + module.exports = global.document ? + factory (global) : + function (win) { + if (!win.document) { + throw new Error('jscolor needs a window with document'); + } + return factory(win); + } + return; + } + + // Default use (no module export) + factory(global); + +})(typeof window !== 'undefined' ? window : this, function (window) { // BEGIN factory + +// BEGIN jscolor code - dir : '', // location of jscolor directory (leave empty to autodetect) - bindClass : 'color', // class name - binding : true, // automatic binding via - preloading : true, // use image preloading? +'use strict'; - install : function() { - jscolor.addEvent(window, 'load', jscolor.init); - }, +var jscolor = (function () { // BEGIN jscolor + +var jsc = { - init : function() { - if(jscolor.binding) { - jscolor.bind(); - } - if(jscolor.preloading) { - jscolor.preload(); + initialized : false, + + instances : [], // created instances of jscolor + + readyQueue : [], // functions waiting to be called after init + + + register : function () { + if (typeof window !== 'undefined' && window.document) { + window.document.addEventListener('DOMContentLoaded', jsc.pub.init, false); } }, - getDir : function() { - if(!jscolor.dir) { - var detected = jscolor.detectDir(); - jscolor.dir = detected!==false ? detected : 'jscolor/'; + installBySelector : function (selector, rootNode) { + rootNode = rootNode ? jsc.node(rootNode) : window.document; + if (!rootNode) { + throw new Error('Missing root node'); + } + + var elms = rootNode.querySelectorAll(selector); + + // for backward compatibility with DEPRECATED installation/configuration using className + var matchClass = new RegExp('(^|\\s)(' + jsc.pub.lookupClass + ')(\\s*(\\{[^}]*\\})|\\s|$)', 'i'); + + for (var i = 0; i < elms.length; i += 1) { + + if (elms[i].jscolor && elms[i].jscolor instanceof jsc.pub) { + continue; // jscolor already installed on this element + } + + if (elms[i].type !== undefined && elms[i].type.toLowerCase() == 'color' && jsc.isColorAttrSupported) { + continue; // skips inputs of type 'color' if supported by the browser + } + + var dataOpts, m; + + if ( + (dataOpts = jsc.getDataAttr(elms[i], 'jscolor')) !== null || + (elms[i].className && (m = elms[i].className.match(matchClass))) // installation using className (DEPRECATED) + ) { + var targetElm = elms[i]; + + var optsStr = ''; + if (dataOpts !== null) { + optsStr = dataOpts; + + } else if (m) { // installation using className (DEPRECATED) + console.warn('Installation using class name is DEPRECATED. Use data-jscolor="" attribute instead.' + jsc.docsRef); + if (m[4]) { + optsStr = m[4]; + } + } + + var opts = null; + if (optsStr.trim()) { + try { + opts = jsc.parseOptionsStr(optsStr); + } catch (e) { + console.warn(e + '\n' + optsStr); + } + } + + try { + new jsc.pub(targetElm, opts); + } catch (e) { + console.warn(e); + } + } } - return jscolor.dir; }, - detectDir : function() { - var base = location.href; + parseOptionsStr : function (str) { + var opts = null; - var e = document.getElementsByTagName('base'); - for(var i=0; i try to evaluate the options string as JavaScript object + try { + opts = (new Function ('var opts = (' + str + '); return typeof opts === "object" ? opts : {};'))(); + } catch (eEval) { + throw new Error('Could not evaluate jscolor options: ' + eEval); + } + } + } + return opts; + }, + + + getInstances : function () { + var inst = []; + for (var i = 0; i < jsc.instances.length; i += 1) { + // if the targetElement still exists, the instance is considered "alive" + if (jsc.instances[i] && jsc.instances[i].targetElement) { + inst.push(jsc.instances[i]); + } + } + return inst; + }, + + + createEl : function (tagName) { + var el = window.document.createElement(tagName); + jsc.setData(el, 'gui', true); + return el; + }, + + + node : function (nodeOrSelector) { + if (!nodeOrSelector) { + return null; } - var e = document.getElementsByTagName('script'); - for(var i=0; i -1) + ); + }, + + + isButtonEmpty : function (el) { + switch (jsc.nodeName(el)) { + case 'input': return (!el.value || el.value.trim() === ''); + case 'button': return (el.textContent.trim() === ''); + } + return null; // could not determine element's text + }, + + + // See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md + isPassiveEventSupported : (function () { + var supported = false; + + try { + var opts = Object.defineProperty({}, 'passive', { + get: function () { supported = true; } + }); + window.addEventListener('testPassive', null, opts); + window.removeEventListener('testPassive', null, opts); + } catch (e) {} + + return supported; + })(), + + + isColorAttrSupported : (function () { + var elm = window.document.createElement('input'); + if (elm.setAttribute) { + elm.setAttribute('type', 'color'); + if (elm.type.toLowerCase() == 'color') { + return true; + } + } + return false; + })(), + + + dataProp : '_data_jscolor', + + + // usage: + // setData(obj, prop, value) + // setData(obj, {prop:value, ...}) + // + setData : function () { + var obj = arguments[0]; + + if (arguments.length === 3) { + // setting a single property + var data = obj.hasOwnProperty(jsc.dataProp) ? obj[jsc.dataProp] : (obj[jsc.dataProp] = {}); + var prop = arguments[1]; + var value = arguments[2]; + + data[prop] = value; + return true; + + } else if (arguments.length === 2 && typeof arguments[1] === 'object') { + // setting multiple properties + var data = obj.hasOwnProperty(jsc.dataProp) ? obj[jsc.dataProp] : (obj[jsc.dataProp] = {}); + var map = arguments[1]; + + for (var prop in map) { + if (map.hasOwnProperty(prop)) { + data[prop] = map[prop]; + } + } + return true; + } + + throw new Error('Invalid arguments'); + }, + + + // usage: + // removeData(obj, prop, [prop...]) + // + removeData : function () { + var obj = arguments[0]; + if (!obj.hasOwnProperty(jsc.dataProp)) { + return true; // data object does not exist + } + for (var i = 1; i < arguments.length; i += 1) { + var prop = arguments[i]; + delete obj[jsc.dataProp][prop]; + } + return true; + }, + + + getData : function (obj, prop, setDefault) { + if (!obj.hasOwnProperty(jsc.dataProp)) { + // data object does not exist + if (setDefault !== undefined) { + obj[jsc.dataProp] = {}; // create data object + } else { + return undefined; // no value to return + } + } + var data = obj[jsc.dataProp]; + + if (!data.hasOwnProperty(prop) && setDefault !== undefined) { + data[prop] = setDefault; + } + return data[prop]; + }, + + + getDataAttr : function (el, name) { + var attrName = 'data-' + name; + var attrValue = el.getAttribute(attrName); + return attrValue; + }, + + + setDataAttr : function (el, name, value) { + var attrName = 'data-' + name; + el.setAttribute(attrName, value); + }, + + + _attachedGroupEvents : {}, + + + attachGroupEvent : function (groupName, el, evnt, func) { + if (!jsc._attachedGroupEvents.hasOwnProperty(groupName)) { + jsc._attachedGroupEvents[groupName] = []; + } + jsc._attachedGroupEvents[groupName].push([el, evnt, func]); + el.addEventListener(evnt, func, false); + }, + + + detachGroupEvents : function (groupName) { + if (jsc._attachedGroupEvents.hasOwnProperty(groupName)) { + for (var i = 0; i < jsc._attachedGroupEvents[groupName].length; i += 1) { + var evt = jsc._attachedGroupEvents[groupName][i]; + evt[0].removeEventListener(evt[1], evt[2], false); + } + delete jsc._attachedGroupEvents[groupName]; + } + }, + + + preventDefault : function (e) { + if (e.preventDefault) { e.preventDefault(); } + e.returnValue = false; + }, + + + captureTarget : function (target) { + // IE + if (target.setCapture) { + jsc._capturedTarget = target; + jsc._capturedTarget.setCapture(); + } + }, + + + releaseTarget : function () { + // IE + if (jsc._capturedTarget) { + jsc._capturedTarget.releaseCapture(); + jsc._capturedTarget = null; + } + }, + + + triggerEvent : function (el, eventName, bubbles, cancelable) { + if (!el) { + return; + } + + var ev = null; + + if (typeof Event === 'function') { + ev = new Event(eventName, { + bubbles: bubbles, + cancelable: cancelable + }); + } else { + // IE + ev = window.document.createEvent('Event'); + ev.initEvent(eventName, bubbles, cancelable); + } + + if (!ev) { + return false; + } + + // so that we know that the event was triggered internally + jsc.setData(ev, 'internal', true); + + el.dispatchEvent(ev); + return true; + }, + + + triggerInputEvent : function (el, eventName, bubbles, cancelable) { + if (!el) { + return; + } + if (jsc.isTextInput(el)) { + jsc.triggerEvent(el, eventName, bubbles, cancelable); + } + }, + + + eventKey : function (ev) { + var keys = { + 9: 'Tab', + 13: 'Enter', + 27: 'Escape', + }; + if (typeof ev.code === 'string') { + return ev.code; + } else if (ev.keyCode !== undefined && keys.hasOwnProperty(ev.keyCode)) { + return keys[ev.keyCode]; + } + return null; + }, + + + strList : function (str) { + if (!str) { + return []; + } + return str.replace(/^\s+|\s+$/g, '').split(/\s+/); + }, + + + // The className parameter (str) can only contain a single class name + hasClass : function (elm, className) { + if (!className) { + return false; + } + if (elm.classList !== undefined) { + return elm.classList.contains(className); + } + // polyfill + return -1 != (' ' + elm.className.replace(/\s+/g, ' ') + ' ').indexOf(' ' + className + ' '); + }, + + + // The className parameter (str) can contain multiple class names separated by whitespace + addClass : function (elm, className) { + var classNames = jsc.strList(className); + + if (elm.classList !== undefined) { + for (var i = 0; i < classNames.length; i += 1) { + elm.classList.add(classNames[i]); + } + return; + } + // polyfill + for (var i = 0; i < classNames.length; i += 1) { + if (!jsc.hasClass(elm, classNames[i])) { + elm.className += (elm.className ? ' ' : '') + classNames[i]; + } + } + }, + + + // The className parameter (str) can contain multiple class names separated by whitespace + removeClass : function (elm, className) { + var classNames = jsc.strList(className); + + if (elm.classList !== undefined) { + for (var i = 0; i < classNames.length; i += 1) { + elm.classList.remove(classNames[i]); + } + return; + } + // polyfill + for (var i = 0; i < classNames.length; i += 1) { + var repl = new RegExp( + '^\\s*' + classNames[i] + '\\s*|' + + '\\s*' + classNames[i] + '\\s*$|' + + '\\s+' + classNames[i] + '(\\s+)', + 'g' + ); + elm.className = elm.className.replace(repl, '$1'); + } + }, + + + getCompStyle : function (elm) { + var compStyle = window.getComputedStyle ? window.getComputedStyle(elm) : elm.currentStyle; + + // Note: In Firefox, getComputedStyle returns null in a hidden iframe, + // that's why we need to check if the returned value is non-empty + if (!compStyle) { + return {}; + } + return compStyle; + }, + + + // Note: + // Setting a property to NULL reverts it to the state before it was first set + // with the 'reversible' flag enabled + // + setStyle : function (elm, styles, important, reversible) { + // using '' for standard priority (IE10 apparently doesn't like value undefined) + var priority = important ? 'important' : ''; + var origStyle = null; + + for (var prop in styles) { + if (styles.hasOwnProperty(prop)) { + var setVal = null; + + if (styles[prop] === null) { + // reverting a property value + + if (!origStyle) { + // get the original style object, but dont't try to create it if it doesn't exist + origStyle = jsc.getData(elm, 'origStyle'); + } + if (origStyle && origStyle.hasOwnProperty(prop)) { + // we have property's original value -> use it + setVal = origStyle[prop]; + } + + } else { + // setting a property value + + if (reversible) { + if (!origStyle) { + // get the original style object and if it doesn't exist, create it + origStyle = jsc.getData(elm, 'origStyle', {}); + } + if (!origStyle.hasOwnProperty(prop)) { + // original property value not yet stored -> store it + origStyle[prop] = elm.style[prop]; + } + } + setVal = styles[prop]; + } + + if (setVal !== null) { + elm.style.setProperty(prop, setVal, priority); + } + } + } + }, + + + hexColor : function (r, g, b) { + return '#' + ( + ('0' + Math.round(r).toString(16)).substr(-2) + + ('0' + Math.round(g).toString(16)).substr(-2) + + ('0' + Math.round(b).toString(16)).substr(-2) + ).toUpperCase(); + }, + + + hexaColor : function (r, g, b, a) { + return '#' + ( + ('0' + Math.round(r).toString(16)).substr(-2) + + ('0' + Math.round(g).toString(16)).substr(-2) + + ('0' + Math.round(b).toString(16)).substr(-2) + + ('0' + Math.round(a * 255).toString(16)).substr(-2) + ).toUpperCase(); + }, + + + rgbColor : function (r, g, b) { + return 'rgb(' + + Math.round(r) + ',' + + Math.round(g) + ',' + + Math.round(b) + + ')'; + }, + + + rgbaColor : function (r, g, b, a) { + return 'rgba(' + + Math.round(r) + ',' + + Math.round(g) + ',' + + Math.round(b) + ',' + + (Math.round((a===undefined || a===null ? 1 : a) * 100) / 100) + + ')'; + }, + + + linearGradient : (function () { + + function getFuncName () { + var stdName = 'linear-gradient'; + var prefixes = ['', '-webkit-', '-moz-', '-o-', '-ms-']; + var helper = window.document.createElement('div'); + + for (var i = 0; i < prefixes.length; i += 1) { + var tryFunc = prefixes[i] + stdName; + var tryVal = tryFunc + '(to right, rgba(0,0,0,0), rgba(0,0,0,0))'; + + helper.style.background = tryVal; + if (helper.style.background) { // CSS background successfully set -> function name is supported + return tryFunc; + } + } + return stdName; // fallback to standard 'linear-gradient' without vendor prefix + } + + var funcName = getFuncName(); + + return function () { + return funcName + '(' + Array.prototype.join.call(arguments, ', ') + ')'; + }; + + })(), + + + setBorderRadius : function (elm, value) { + jsc.setStyle(elm, {'border-radius' : value || '0'}); + }, + + + setBoxShadow : function (elm, value) { + jsc.setStyle(elm, {'box-shadow': value || 'none'}); + }, + + + getElementPos : function (e, relativeToViewport) { + var x=0, y=0; + var rect = e.getBoundingClientRect(); + x = rect.left; + y = rect.top; + if (!relativeToViewport) { + var viewPos = jsc.getViewPos(); + x += viewPos[0]; + y += viewPos[1]; + } + return [x, y]; + }, + + + getElementSize : function (e) { + return [e.offsetWidth, e.offsetHeight]; + }, + + + // get pointer's X/Y coordinates relative to viewport + getAbsPointerPos : function (e) { + var x = 0, y = 0; + if (typeof e.changedTouches !== 'undefined' && e.changedTouches.length) { + // touch devices + x = e.changedTouches[0].clientX; + y = e.changedTouches[0].clientY; + } else if (typeof e.clientX === 'number') { + x = e.clientX; + y = e.clientY; + } + return { x: x, y: y }; + }, + + + // get pointer's X/Y coordinates relative to target element + getRelPointerPos : function (e) { + var target = e.target || e.srcElement; + var targetRect = target.getBoundingClientRect(); + + var x = 0, y = 0; + + var clientX = 0, clientY = 0; + if (typeof e.changedTouches !== 'undefined' && e.changedTouches.length) { + // touch devices + clientX = e.changedTouches[0].clientX; + clientY = e.changedTouches[0].clientY; + } else if (typeof e.clientX === 'number') { + clientX = e.clientX; + clientY = e.clientY; + } + + x = clientX - targetRect.left; + y = clientY - targetRect.top; + return { x: x, y: y }; + }, + + + getViewPos : function () { + var doc = window.document.documentElement; + return [ + (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0), + (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0) + ]; + }, + + + getViewSize : function () { + var doc = window.document.documentElement; + return [ + (window.innerWidth || doc.clientWidth), + (window.innerHeight || doc.clientHeight), + ]; + }, + + + // r: 0-255 + // g: 0-255 + // b: 0-255 + // + // returns: [ 0-360, 0-100, 0-100 ] + // + RGB_HSV : function (r, g, b) { + r /= 255; + g /= 255; + b /= 255; + var n = Math.min(Math.min(r,g),b); + var v = Math.max(Math.max(r,g),b); + var m = v - n; + if (m === 0) { return [ null, 0, 100 * v ]; } + var h = r===n ? 3+(b-g)/m : (g===n ? 5+(r-b)/m : 1+(g-r)/m); + return [ + 60 * (h===6?0:h), + 100 * (m/v), + 100 * v + ]; + }, + + + // h: 0-360 + // s: 0-100 + // v: 0-100 + // + // returns: [ 0-255, 0-255, 0-255 ] + // + HSV_RGB : function (h, s, v) { + var u = 255 * (v / 100); + + if (h === null) { + return [ u, u, u ]; + } + + h /= 60; + s /= 100; + + var i = Math.floor(h); + var f = i%2 ? h-i : 1-(h-i); + var m = u * (1 - s); + var n = u * (1 - s * f); + switch (i) { + case 6: + case 0: return [u,n,m]; + case 1: return [n,u,m]; + case 2: return [m,u,n]; + case 3: return [m,n,u]; + case 4: return [n,m,u]; + case 5: return [u,m,n]; + } + }, + + + parseColorString : function (str) { + var ret = { + rgba: null, + format: null // 'hex' | 'hexa' | 'rgb' | 'rgba' + }; + + var m; + + if (m = str.match(/^\W*([0-9A-F]{3,8})\W*$/i)) { + // HEX notation + + if (m[1].length === 8) { + // 8-char notation (= with alpha) + ret.format = 'hexa'; + ret.rgba = [ + parseInt(m[1].substr(0,2),16), + parseInt(m[1].substr(2,2),16), + parseInt(m[1].substr(4,2),16), + parseInt(m[1].substr(6,2),16) / 255 + ]; + + } else if (m[1].length === 6) { + // 6-char notation + ret.format = 'hex'; + ret.rgba = [ + parseInt(m[1].substr(0,2),16), + parseInt(m[1].substr(2,2),16), + parseInt(m[1].substr(4,2),16), + null + ]; + + } else if (m[1].length === 3) { + // 3-char notation + ret.format = 'hex'; + ret.rgba = [ + parseInt(m[1].charAt(0) + m[1].charAt(0),16), + parseInt(m[1].charAt(1) + m[1].charAt(1),16), + parseInt(m[1].charAt(2) + m[1].charAt(2),16), + null + ]; + + } else { + return false; + } + + return ret; + } + + if (m = str.match(/^\W*rgba?\(([^)]*)\)\W*$/i)) { + // rgb(...) or rgba(...) notation + + var par = m[1].split(','); + var re = /^\s*(\d+|\d*\.\d+|\d+\.\d*)\s*$/; + var mR, mG, mB, mA; + if ( + par.length >= 3 && + (mR = par[0].match(re)) && + (mG = par[1].match(re)) && + (mB = par[2].match(re)) + ) { + ret.format = 'rgb'; + ret.rgba = [ + parseFloat(mR[1]) || 0, + parseFloat(mG[1]) || 0, + parseFloat(mB[1]) || 0, + null + ]; + + if ( + par.length >= 4 && + (mA = par[3].match(re)) + ) { + ret.format = 'rgba'; + ret.rgba[3] = parseFloat(mA[1]) || 0; + } + return ret; + } + } + + return false; + }, + + + parsePaletteValue : function (mixed) { + var vals = []; + + if (typeof mixed === 'string') { // input is a string of space separated color values + // rgb() and rgba() may contain spaces too, so let's find all color values by regex + mixed.replace(/#[0-9A-F]{3}([0-9A-F]{3})?|rgba?\(([^)]*)\)/ig, function (val) { + vals.push(val); + }); + } else if (Array.isArray(mixed)) { // input is an array of color values + vals = mixed; + } + + // convert all values into uniform color format + + var colors = []; + + for (var i = 0; i < vals.length; i++) { + var color = jsc.parseColorString(vals[i]); + if (color) { + colors.push(color); + } + } + + return colors; + }, + + + containsTranparentColor : function (colors) { + for (var i = 0; i < colors.length; i++) { + var a = colors[i].rgba[3]; + if (a !== null && a < 1.0) { + return true; } } return false; }, - bind : function() { - var matchClass = new RegExp('(^|\\s)('+jscolor.bindClass+')(\\s*(\\{[^}]*\\})|\\s|$)', 'i'); - var e = document.getElementsByTagName('input'); - for(var i=0; i fill the entire element (0%-100%) + genColorPreviewGradient : function (color, position, width) { + var params = []; + + if (position && width) { + params = [ + 'to ' + {'left':'right', 'right':'left'}[position], + color + ' 0%', + color + ' ' + width + 'px', + 'rgba(0,0,0,0) ' + (width + 1) + 'px', + 'rgba(0,0,0,0) 100%', + ]; + } else { + params = [ + 'to right', + color + ' 0%', + color + ' 100%', + ]; + } + + return jsc.linearGradient.apply(this, params); + }, + + + redrawPosition : function () { + + if (!jsc.picker || !jsc.picker.owner) { + return; // picker is not shown + } + + var thisObj = jsc.picker.owner; + + var tp, vp; + + if (thisObj.fixed) { + // Fixed elements are positioned relative to viewport, + // therefore we can ignore the scroll offset + tp = jsc.getElementPos(thisObj.targetElement, true); // target pos + vp = [0, 0]; // view pos + } else { + tp = jsc.getElementPos(thisObj.targetElement); // target pos + vp = jsc.getViewPos(); // view pos + } + + var ts = jsc.getElementSize(thisObj.targetElement); // target size + var vs = jsc.getViewSize(); // view size + var pd = jsc.getPickerDims(thisObj); + var ps = [pd.borderW, pd.borderH]; // picker outer size + var a, b, c; + switch (thisObj.position.toLowerCase()) { + case 'left': a=1; b=0; c=-1; break; + case 'right':a=1; b=0; c=1; break; + case 'top': a=0; b=1; c=-1; break; + default: a=0; b=1; c=1; break; + } + var l = (ts[b]+ps[b])/2; + + // compute picker position + if (!thisObj.smartPosition) { + var pp = [ + tp[a], + tp[b]+ts[b]-l+l*c + ]; + } else { + var pp = [ + -vp[a]+tp[a]+ps[a] > vs[a] ? + (-vp[a]+tp[a]+ts[a]/2 > vs[a]/2 && tp[a]+ts[a]-ps[a] >= 0 ? tp[a]+ts[a]-ps[a] : tp[a]) : + tp[a], + -vp[b]+tp[b]+ts[b]+ps[b]-l+l*c > vs[b] ? + (-vp[b]+tp[b]+ts[b]/2 > vs[b]/2 && tp[b]+ts[b]-l-l*c >= 0 ? tp[b]+ts[b]-l-l*c : tp[b]+ts[b]-l+l*c) : + (tp[b]+ts[b]-l+l*c >= 0 ? tp[b]+ts[b]-l+l*c : tp[b]+ts[b]-l-l*c) + ]; + } + + var x = pp[a]; + var y = pp[b]; + var positionValue = thisObj.fixed ? 'fixed' : 'absolute'; + var contractShadow = + (pp[0] + ps[0] > tp[0] || pp[0] < tp[0] + ts[0]) && + (pp[1] + ps[1] < tp[1] + ts[1]); + + jsc._drawPosition(thisObj, x, y, positionValue, contractShadow); + }, + + + _drawPosition : function (thisObj, x, y, positionValue, contractShadow) { + var vShadow = contractShadow ? 0 : thisObj.shadowBlur; // px + + jsc.picker.wrap.style.position = positionValue; + jsc.picker.wrap.style.left = x + 'px'; + jsc.picker.wrap.style.top = y + 'px'; + + jsc.setBoxShadow( + jsc.picker.boxS, + thisObj.shadow ? + new jsc.BoxShadow(0, vShadow, thisObj.shadowBlur, 0, thisObj.shadowColor) : + null); + }, + + + getPickerDims : function (thisObj) { + var w = 2 * thisObj.controlBorderWidth + thisObj.width; + var h = 2 * thisObj.controlBorderWidth + thisObj.height; + + var sliderSpace = 2 * thisObj.controlBorderWidth + 2 * jsc.getControlPadding(thisObj) + thisObj.sliderSize; + + if (jsc.getSliderChannel(thisObj)) { + w += sliderSpace; + } + if (thisObj.hasAlphaChannel()) { + w += sliderSpace; + } + + var pal = jsc.getPaletteDims(thisObj, w); + + if (pal.height) { + h += pal.height + thisObj.padding; + } + if (thisObj.closeButton) { + h += 2 * thisObj.controlBorderWidth + thisObj.padding + thisObj.buttonHeight; + } + + var pW = w + (2 * thisObj.padding); + var pH = h + (2 * thisObj.padding); + + return { + contentW: w, + contentH: h, + paddedW: pW, + paddedH: pH, + borderW: pW + (2 * thisObj.borderWidth), + borderH: pH + (2 * thisObj.borderWidth), + palette: pal, + }; + }, + + + getPaletteDims : function (thisObj, width) { + var cols = 0, rows = 0, cellW = 0, cellH = 0, height = 0; + var sampleCount = thisObj._palette ? thisObj._palette.length : 0; + + if (sampleCount) { + cols = thisObj.paletteCols; + rows = cols > 0 ? Math.ceil(sampleCount / cols) : 0; + + // color sample's dimensions (includes border) + cellW = Math.max(1, Math.floor((width - ((cols - 1) * thisObj.paletteSpacing)) / cols)); + cellH = thisObj.paletteHeight ? Math.min(thisObj.paletteHeight, cellW) : cellW; + } + + if (rows) { + height = + rows * cellH + + (rows - 1) * thisObj.paletteSpacing; + } + + return { + cols: cols, + rows: rows, + cellW: cellW, + cellH: cellH, + width: width, + height: height, + }; + }, + + + getControlPadding : function (thisObj) { + return Math.max( + thisObj.padding / 2, + (2 * thisObj.pointerBorderWidth + thisObj.pointerThickness) - thisObj.controlBorderWidth + ); + }, + + + getPadYChannel : function (thisObj) { + switch (thisObj.mode.charAt(1).toLowerCase()) { + case 'v': return 'v'; break; + } + return 's'; + }, + + + getSliderChannel : function (thisObj) { + if (thisObj.mode.length > 2) { + switch (thisObj.mode.charAt(2).toLowerCase()) { + case 's': return 's'; break; + case 'v': return 'v'; break; + } + } + return null; + }, + + + // calls function specified in picker's property + triggerCallback : function (thisObj, prop) { + if (!thisObj[prop]) { + return; // callback func not specified + } + var callback = null; + + if (typeof thisObj[prop] === 'string') { + // string with code + try { + callback = new Function (thisObj[prop]); + } catch (e) { + console.error(e); + } + } else { + // function + callback = thisObj[prop]; + } + + if (callback) { + callback.call(thisObj); + } + }, + + + // Triggers a color change related event(s) on all picker instances. + // It is possible to specify multiple events separated with a space. + triggerGlobal : function (eventNames) { + var inst = jsc.getInstances(); + for (var i = 0; i < inst.length; i += 1) { + inst[i].trigger(eventNames); + } + }, + + + _pointerMoveEvent : { + mouse: 'mousemove', + touch: 'touchmove' + }, + _pointerEndEvent : { + mouse: 'mouseup', + touch: 'touchend' + }, + + + _pointerOrigin : null, + _capturedTarget : null, + + + onDocumentKeyUp : function (e) { + if (['Tab', 'Escape'].indexOf(jsc.eventKey(e)) !== -1) { + if (jsc.picker && jsc.picker.owner) { + jsc.picker.owner.tryHide(); + } + } + }, + + + onWindowResize : function (e) { + jsc.redrawPosition(); + }, + + + onWindowScroll : function (e) { + jsc.redrawPosition(); + }, + + + onParentScroll : function (e) { + // hide the picker when one of the parent elements is scrolled + if (jsc.picker && jsc.picker.owner) { + jsc.picker.owner.tryHide(); + } + }, + + + onDocumentMouseDown : function (e) { + var target = e.target || e.srcElement; + + if (target.jscolor && target.jscolor instanceof jsc.pub) { // clicked targetElement -> show picker + if (target.jscolor.showOnClick && !target.disabled) { + target.jscolor.show(); + } + } else if (jsc.getData(target, 'gui')) { // clicked jscolor's GUI element + var control = jsc.getData(target, 'control'); + if (control) { + // jscolor's control + jsc.onControlPointerStart(e, target, jsc.getData(target, 'control'), 'mouse'); + } + } else { + // mouse is outside the picker's controls -> hide the color picker! + if (jsc.picker && jsc.picker.owner) { + jsc.picker.owner.tryHide(); + } + } + }, + + + onPickerTouchStart : function (e) { + var target = e.target || e.srcElement; + + if (jsc.getData(target, 'control')) { + jsc.onControlPointerStart(e, target, jsc.getData(target, 'control'), 'touch'); + } + }, + + + onControlPointerStart : function (e, target, controlName, pointerType) { + var thisObj = jsc.getData(target, 'instance'); + + jsc.preventDefault(e); + jsc.captureTarget(target); + + var registerDragEvents = function (doc, offset) { + jsc.attachGroupEvent('drag', doc, jsc._pointerMoveEvent[pointerType], + jsc.onDocumentPointerMove(e, target, controlName, pointerType, offset)); + jsc.attachGroupEvent('drag', doc, jsc._pointerEndEvent[pointerType], + jsc.onDocumentPointerEnd(e, target, controlName, pointerType)); + }; + + registerDragEvents(window.document, [0, 0]); + + if (window.parent && window.frameElement) { + var rect = window.frameElement.getBoundingClientRect(); + var ofs = [-rect.left, -rect.top]; + registerDragEvents(window.parent.window.document, ofs); + } + + var abs = jsc.getAbsPointerPos(e); + var rel = jsc.getRelPointerPos(e); + jsc._pointerOrigin = { + x: abs.x - rel.x, + y: abs.y - rel.y + }; + + switch (controlName) { + case 'pad': + // if the value slider is at the bottom, move it up + if (jsc.getSliderChannel(thisObj) === 'v' && thisObj.channels.v === 0) { + thisObj.fromHSVA(null, null, 100, null); + } + jsc.setPad(thisObj, e, 0, 0); + break; + + case 'sld': + jsc.setSld(thisObj, e, 0); + break; + + case 'asld': + jsc.setASld(thisObj, e, 0); + break; + } + thisObj.trigger('input'); + }, + + + onDocumentPointerMove : function (e, target, controlName, pointerType, offset) { + return function (e) { + var thisObj = jsc.getData(target, 'instance'); + switch (controlName) { + case 'pad': + jsc.setPad(thisObj, e, offset[0], offset[1]); + break; + + case 'sld': + jsc.setSld(thisObj, e, offset[1]); + break; + + case 'asld': + jsc.setASld(thisObj, e, offset[1]); + break; + } + thisObj.trigger('input'); + } + }, + + + onDocumentPointerEnd : function (e, target, controlName, pointerType) { + return function (e) { + var thisObj = jsc.getData(target, 'instance'); + jsc.detachGroupEvents('drag'); + jsc.releaseTarget(); + + // Always trigger changes AFTER detaching outstanding mouse handlers, + // in case some color change that occured in user-defined onChange/onInput handler + // intruded into current mouse events + thisObj.trigger('input'); + thisObj.trigger('change'); + }; + }, + + + onPaletteSampleClick : function (e) { + var target = e.currentTarget; + var thisObj = jsc.getData(target, 'instance'); + var color = jsc.getData(target, 'color'); + + // when format is flexible, use the original format of this color sample + if (thisObj.format.toLowerCase() === 'any') { + thisObj._setFormat(color.format); // adapt format + if (!jsc.isAlphaFormat(thisObj.getFormat())) { + color.rgba[3] = 1.0; // when switching to a format that doesn't support alpha, set full opacity + } + } + + // if this color doesn't specify alpha, use alpha of 1.0 (if applicable) + if (color.rgba[3] === null) { + if (thisObj.paletteSetsAlpha === true || (thisObj.paletteSetsAlpha === 'auto' && thisObj._paletteHasTransparency)) { + color.rgba[3] = 1.0; + } + } + + thisObj.fromRGBA.apply(thisObj, color.rgba); + + thisObj.trigger('input'); + thisObj.trigger('change'); + + if (thisObj.hideOnPaletteClick) { + thisObj.hide(); + } + }, + + + setPad : function (thisObj, e, ofsX, ofsY) { + var pointerAbs = jsc.getAbsPointerPos(e); + var x = ofsX + pointerAbs.x - jsc._pointerOrigin.x - thisObj.padding - thisObj.controlBorderWidth; + var y = ofsY + pointerAbs.y - jsc._pointerOrigin.y - thisObj.padding - thisObj.controlBorderWidth; + + var xVal = x * (360 / (thisObj.width - 1)); + var yVal = 100 - (y * (100 / (thisObj.height - 1))); + + switch (jsc.getPadYChannel(thisObj)) { + case 's': thisObj.fromHSVA(xVal, yVal, null, null); break; + case 'v': thisObj.fromHSVA(xVal, null, yVal, null); break; + } + }, + + + setSld : function (thisObj, e, ofsY) { + var pointerAbs = jsc.getAbsPointerPos(e); + var y = ofsY + pointerAbs.y - jsc._pointerOrigin.y - thisObj.padding - thisObj.controlBorderWidth; + var yVal = 100 - (y * (100 / (thisObj.height - 1))); + + switch (jsc.getSliderChannel(thisObj)) { + case 's': thisObj.fromHSVA(null, yVal, null, null); break; + case 'v': thisObj.fromHSVA(null, null, yVal, null); break; + } + }, + + + setASld : function (thisObj, e, ofsY) { + var pointerAbs = jsc.getAbsPointerPos(e); + var y = ofsY + pointerAbs.y - jsc._pointerOrigin.y - thisObj.padding - thisObj.controlBorderWidth; + var yVal = 1.0 - (y * (1.0 / (thisObj.height - 1))); + + if (yVal < 1.0) { + // if format is flexible and the current format doesn't support alpha, switch to a suitable one + var fmt = thisObj.getFormat(); + if (thisObj.format.toLowerCase() === 'any' && !jsc.isAlphaFormat(fmt)) { + thisObj._setFormat(fmt === 'hex' ? 'hexa' : 'rgba'); + } + } + + thisObj.fromHSVA(null, null, null, yVal); + }, + + + createPadCanvas : function () { + + var ret = { + elm: null, + draw: null + }; + + var canvas = jsc.createEl('canvas'); + var ctx = canvas.getContext('2d'); + + var drawFunc = function (width, height, type) { + canvas.width = width; + canvas.height = height; + + ctx.clearRect(0, 0, canvas.width, canvas.height); + + var hGrad = ctx.createLinearGradient(0, 0, canvas.width, 0); + hGrad.addColorStop(0 / 6, '#F00'); + hGrad.addColorStop(1 / 6, '#FF0'); + hGrad.addColorStop(2 / 6, '#0F0'); + hGrad.addColorStop(3 / 6, '#0FF'); + hGrad.addColorStop(4 / 6, '#00F'); + hGrad.addColorStop(5 / 6, '#F0F'); + hGrad.addColorStop(6 / 6, '#F00'); + + ctx.fillStyle = hGrad; + ctx.fillRect(0, 0, canvas.width, canvas.height); + + var vGrad = ctx.createLinearGradient(0, 0, 0, canvas.height); + switch (type.toLowerCase()) { + case 's': + vGrad.addColorStop(0, 'rgba(255,255,255,0)'); + vGrad.addColorStop(1, 'rgba(255,255,255,1)'); + break; + case 'v': + vGrad.addColorStop(0, 'rgba(0,0,0,0)'); + vGrad.addColorStop(1, 'rgba(0,0,0,1)'); + break; + } + ctx.fillStyle = vGrad; + ctx.fillRect(0, 0, canvas.width, canvas.height); + }; + + ret.elm = canvas; + ret.draw = drawFunc; + + return ret; + }, + + + createSliderGradient : function () { + + var ret = { + elm: null, + draw: null + }; + + var canvas = jsc.createEl('canvas'); + var ctx = canvas.getContext('2d'); + + var drawFunc = function (width, height, color1, color2) { + canvas.width = width; + canvas.height = height; + + ctx.clearRect(0, 0, canvas.width, canvas.height); + + var grad = ctx.createLinearGradient(0, 0, 0, canvas.height); + grad.addColorStop(0, color1); + grad.addColorStop(1, color2); + + ctx.fillStyle = grad; + ctx.fillRect(0, 0, canvas.width, canvas.height); + }; + + ret.elm = canvas; + ret.draw = drawFunc; + + return ret; + }, + + + createASliderGradient : function () { + + var ret = { + elm: null, + draw: null + }; + + var canvas = jsc.createEl('canvas'); + var ctx = canvas.getContext('2d'); + + var drawFunc = function (width, height, color) { + canvas.width = width; + canvas.height = height; + + ctx.clearRect(0, 0, canvas.width, canvas.height); + + var sqSize = canvas.width / 2; + var sqColor1 = jsc.pub.chessboardColor1; + var sqColor2 = jsc.pub.chessboardColor2; + + // dark gray background + ctx.fillStyle = sqColor1; + ctx.fillRect(0, 0, canvas.width, canvas.height); + + if (sqSize > 0) { // to avoid infinite loop + for (var y = 0; y < canvas.height; y += sqSize * 2) { + // light gray squares + ctx.fillStyle = sqColor2; + ctx.fillRect(0, y, sqSize, sqSize); + ctx.fillRect(sqSize, y + sqSize, sqSize, sqSize); } - e[i].color = new jscolor.color(e[i], prop); } - } - }, + var grad = ctx.createLinearGradient(0, 0, 0, canvas.height); + grad.addColorStop(0, color); + grad.addColorStop(1, 'rgba(0,0,0,0)'); - preload : function() { - for(var fn in jscolor.imgRequire) { - if(jscolor.imgRequire.hasOwnProperty(fn)) { - jscolor.loadImage(fn); - } - } - }, - - - images : { - pad : [ 181, 101 ], - sld : [ 16, 101 ], - cross : [ 15, 15 ], - arrow : [ 7, 11 ] - }, - - - imgRequire : {}, - imgLoaded : {}, - - - requireImage : function(filename) { - jscolor.imgRequire[filename] = true; - }, - - - loadImage : function(filename) { - if(!jscolor.imgLoaded[filename]) { - jscolor.imgLoaded[filename] = new Image(); - jscolor.imgLoaded[filename].src = jscolor.getDir()+filename; - } - }, - - - fetchElement : function(mixed) { - return typeof mixed === 'string' ? document.getElementById(mixed) : mixed; - }, - - - addEvent : function(el, evnt, func) { - if(el.addEventListener) { - el.addEventListener(evnt, func, false); - } else if(el.attachEvent) { - el.attachEvent('on'+evnt, func); - } - }, - - - fireEvent : function(el, evnt) { - if(!el) { - return; - } - if(document.createEvent) { - var ev = document.createEvent('HTMLEvents'); - ev.initEvent(evnt, true, true); - el.dispatchEvent(ev); - } else if(document.createEventObject) { - var ev = document.createEventObject(); - el.fireEvent('on'+evnt, ev); - } else if(el['on'+evnt]) { // alternatively use the traditional event model (IE5) - el['on'+evnt](); - } - }, - - - getElementPos : function(e) { - var e1=e, e2=e; - var x=0, y=0; - if(e1.offsetParent) { - do { - x += e1.offsetLeft; - y += e1.offsetTop; - } while(e1 = e1.offsetParent); - } - while((e2 = e2.parentNode) && e2.nodeName.toUpperCase() !== 'BODY') { - x -= e2.scrollLeft; - y -= e2.scrollTop; - } - return [x, y]; - }, - - - getElementSize : function(e) { - return [e.offsetWidth, e.offsetHeight]; - }, - - - getRelMousePos : function(e) { - var x = 0, y = 0; - if (!e) { e = window.event; } - if (typeof e.offsetX === 'number') { - x = e.offsetX; - y = e.offsetY; - } else if (typeof e.layerX === 'number') { - x = e.layerX; - y = e.layerY; - } - return { x: x, y: y }; - }, - - - getViewPos : function() { - if(typeof window.pageYOffset === 'number') { - return [window.pageXOffset, window.pageYOffset]; - } else if(document.body && (document.body.scrollLeft || document.body.scrollTop)) { - return [document.body.scrollLeft, document.body.scrollTop]; - } else if(document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) { - return [document.documentElement.scrollLeft, document.documentElement.scrollTop]; - } else { - return [0, 0]; - } - }, - - - getViewSize : function() { - if(typeof window.innerWidth === 'number') { - return [window.innerWidth, window.innerHeight]; - } else if(document.body && (document.body.clientWidth || document.body.clientHeight)) { - return [document.body.clientWidth, document.body.clientHeight]; - } else if(document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) { - return [document.documentElement.clientWidth, document.documentElement.clientHeight]; - } else { - return [0, 0]; - } - }, - - - URI : function(uri) { // See RFC3986 - - this.scheme = null; - this.authority = null; - this.path = ''; - this.query = null; - this.fragment = null; - - this.parse = function(uri) { - var m = uri.match(/^(([A-Za-z][0-9A-Za-z+.-]*)(:))?((\/\/)([^\/?#]*))?([^?#]*)((\?)([^#]*))?((#)(.*))?/); - this.scheme = m[3] ? m[2] : null; - this.authority = m[5] ? m[6] : null; - this.path = m[7]; - this.query = m[9] ? m[10] : null; - this.fragment = m[12] ? m[13] : null; - return this; + ctx.fillStyle = grad; + ctx.fillRect(0, 0, canvas.width, canvas.height); }; - this.toString = function() { - var result = ''; - if(this.scheme !== null) { result = result + this.scheme + ':'; } - if(this.authority !== null) { result = result + '//' + this.authority; } - if(this.path !== null) { result = result + this.path; } - if(this.query !== null) { result = result + '?' + this.query; } - if(this.fragment !== null) { result = result + '#' + this.fragment; } - return result; + ret.elm = canvas; + ret.draw = drawFunc; + + return ret; + }, + + + BoxShadow : (function () { + var BoxShadow = function (hShadow, vShadow, blur, spread, color, inset) { + this.hShadow = hShadow; + this.vShadow = vShadow; + this.blur = blur; + this.spread = spread; + this.color = color; + this.inset = !!inset; }; - this.toAbsolute = function(base) { - var base = new jscolor.URI(base); - var r = this; - var t = new jscolor.URI; + BoxShadow.prototype.toString = function () { + var vals = [ + Math.round(this.hShadow) + 'px', + Math.round(this.vShadow) + 'px', + Math.round(this.blur) + 'px', + Math.round(this.spread) + 'px', + this.color + ]; + if (this.inset) { + vals.push('inset'); + } + return vals.join(' '); + }; - if(base.scheme === null) { return false; } + return BoxShadow; + })(), - if(r.scheme !== null && r.scheme.toLowerCase() === base.scheme.toLowerCase()) { - r.scheme = null; + + flags : { + leaveValue : 1 << 0, + leaveAlpha : 1 << 1, + leavePreview : 1 << 2, + }, + + + enumOpts : { + format: ['auto', 'any', 'hex', 'hexa', 'rgb', 'rgba'], + previewPosition: ['left', 'right'], + mode: ['hsv', 'hvs', 'hs', 'hv'], + position: ['left', 'right', 'top', 'bottom'], + alphaChannel: ['auto', true, false], + paletteSetsAlpha: ['auto', true, false], + }, + + + deprecatedOpts : { + // : ( can be null) + 'styleElement': 'previewElement', + 'onFineChange': 'onInput', + 'overwriteImportant': 'forceStyle', + 'closable': 'closeButton', + 'insetWidth': 'controlBorderWidth', + 'insetColor': 'controlBorderColor', + 'refine': null, + }, + + + docsRef : ' ' + 'See https://jscolor.com/docs/', + + + // + // Usage: + // var myPicker = new JSColor( [, ]) + // + // (constructor is accessible via both 'jscolor' and 'JSColor' name) + // + + pub : function (targetElement, opts) { + + var THIS = this; + + if (!opts) { + opts = {}; + } + + this.channels = { + r: 255, // red [0-255] + g: 255, // green [0-255] + b: 255, // blue [0-255] + h: 0, // hue [0-360] + s: 0, // saturation [0-100] + v: 100, // value (brightness) [0-100] + a: 1.0, // alpha (opacity) [0.0 - 1.0] + }; + + // General options + // + this.format = 'auto'; // 'auto' | 'any' | 'hex' | 'hexa' | 'rgb' | 'rgba' - Format of the input/output value + this.value = undefined; // INITIAL color value in any supported format. To change it later, use method fromString(), fromHSVA(), fromRGBA() or channel() + this.alpha = undefined; // INITIAL alpha value. To change it later, call method channel('A', ) + this.onChange = undefined; // called when color changes. Value can be either a function or a string with JS code. + this.onInput = undefined; // called repeatedly as the color is being changed, e.g. while dragging a slider. Value can be either a function or a string with JS code. + this.valueElement = undefined; // element that will be used to display and input the color value + this.alphaElement = undefined; // element that will be used to display and input the alpha (opacity) value + this.previewElement = undefined; // element that will preview the picked color using CSS background + this.previewPosition = 'left'; // 'left' | 'right' - position of the color preview in previewElement + this.previewSize = 32; // (px) width of the color preview displayed in previewElement + this.previewPadding = 8; // (px) space between color preview and content of the previewElement + this.required = true; // whether the associated text input must always contain a color value. If false, the input can be left empty. + this.hash = true; // whether to prefix the HEX color code with # symbol (only applicable for HEX format) + this.uppercase = true; // whether to show the HEX color code in upper case (only applicable for HEX format) + this.forceStyle = true; // whether to overwrite CSS style of the previewElement using !important flag + + // Color Picker options + // + this.width = 181; // width of the color spectrum (in px) + this.height = 101; // height of the color spectrum (in px) + this.mode = 'HSV'; // 'HSV' | 'HVS' | 'HS' | 'HV' - layout of the color picker controls + this.alphaChannel = 'auto'; // 'auto' | true | false - if alpha channel is enabled, the alpha slider will be visible. If 'auto', it will be determined according to color format + this.position = 'bottom'; // 'left' | 'right' | 'top' | 'bottom' - position relative to the target element + this.smartPosition = true; // automatically change picker position when there is not enough space for it + this.showOnClick = true; // whether to show the picker when user clicks its target element + this.hideOnLeave = true; // whether to automatically hide the picker when user leaves its target element (e.g. upon clicking the document) + this.palette = []; // colors to be displayed in the palette, specified as an array or a string of space separated color values (in any supported format) + this.paletteCols = 10; // number of columns in the palette + this.paletteSetsAlpha = 'auto'; // 'auto' | true | false - if true, palette colors that don't specify alpha will set alpha to 1.0 + this.paletteHeight = 16; // maximum height (px) of a row in the palette + this.paletteSpacing = 4; // distance (px) between color samples in the palette + this.hideOnPaletteClick = false; // when set to true, clicking the palette will also hide the color picker + this.sliderSize = 16; // px + this.crossSize = 8; // px + this.closeButton = false; // whether to display the Close button + this.closeText = 'Close'; + this.buttonColor = 'rgba(0,0,0,1)'; // CSS color + this.buttonHeight = 18; // px + this.padding = 12; // px + this.backgroundColor = 'rgba(255,255,255,1)'; // CSS color + this.borderWidth = 1; // px + this.borderColor = 'rgba(187,187,187,1)'; // CSS color + this.borderRadius = 8; // px + this.controlBorderWidth = 1; // px + this.controlBorderColor = 'rgba(187,187,187,1)'; // CSS color + this.shadow = true; // whether to display a shadow + this.shadowBlur = 15; // px + this.shadowColor = 'rgba(0,0,0,0.2)'; // CSS color + this.pointerColor = 'rgba(76,76,76,1)'; // CSS color + this.pointerBorderWidth = 1; // px + this.pointerBorderColor = 'rgba(255,255,255,1)'; // CSS color + this.pointerThickness = 2; // px + this.zIndex = 5000; + this.container = undefined; // where to append the color picker (BODY element by default) + + // Experimental + // + this.minS = 0; // min allowed saturation (0 - 100) + this.maxS = 100; // max allowed saturation (0 - 100) + this.minV = 0; // min allowed value (brightness) (0 - 100) + this.maxV = 100; // max allowed value (brightness) (0 - 100) + this.minA = 0.0; // min allowed alpha (opacity) (0.0 - 1.0) + this.maxA = 1.0; // max allowed alpha (opacity) (0.0 - 1.0) + + + // Getter: option(name) + // Setter: option(name, value) + // option({name:value, ...}) + // + this.option = function () { + if (!arguments.length) { + throw new Error('No option specified'); } - if(r.scheme !== null) { - t.scheme = r.scheme; - t.authority = r.authority; - t.path = removeDotSegments(r.path); - t.query = r.query; - } else { - if(r.authority !== null) { - t.authority = r.authority; - t.path = removeDotSegments(r.path); - t.query = r.query; - } else { - if(r.path === '') { - t.path = base.path; - if(r.query !== null) { - t.query = r.query; - } else { - t.query = base.query; - } - } else { - if(r.path.substr(0,1) === '/') { - t.path = removeDotSegments(r.path); - } else { - if(base.authority !== null && base.path === '') { - t.path = '/'+r.path; - } else { - t.path = base.path.replace(/[^\/]+$/,'')+r.path; + if (arguments.length === 1 && typeof arguments[0] === 'string') { + // getting a single option + try { + return getOption(arguments[0]); + } catch (e) { + console.warn(e); + } + return false; + + } else if (arguments.length >= 2 && typeof arguments[0] === 'string') { + // setting a single option + try { + if (!setOption(arguments[0], arguments[1])) { + return false; + } + } catch (e) { + console.warn(e); + return false; + } + this.redraw(); // immediately redraws the picker, if it's displayed + this.exposeColor(); // in case some preview-related or format-related option was changed + return true; + + } else if (arguments.length === 1 && typeof arguments[0] === 'object') { + // setting multiple options + var opts = arguments[0]; + var success = true; + for (var opt in opts) { + if (opts.hasOwnProperty(opt)) { + try { + if (!setOption(opt, opts[opt])) { + success = false; } - t.path = removeDotSegments(t.path); + } catch (e) { + console.warn(e); + success = false; } - t.query = r.query; } - t.authority = base.authority; } - t.scheme = base.scheme; + this.redraw(); // immediately redraws the picker, if it's displayed + this.exposeColor(); // in case some preview-related or format-related option was changed + return success; } - t.fragment = r.fragment; - return t; - }; - - function removeDotSegments(path) { - var out = ''; - while(path) { - if(path.substr(0,3)==='../' || path.substr(0,2)==='./') { - path = path.replace(/^\.+/,'').substr(1); - } else if(path.substr(0,3)==='/./' || path==='/.') { - path = '/'+path.substr(3); - } else if(path.substr(0,4)==='/../' || path==='/..') { - path = '/'+path.substr(4); - out = out.replace(/\/?[^\/]*$/, ''); - } else if(path==='.' || path==='..') { - path = ''; - } else { - var rm = path.match(/^\/?[^\/]*/)[0]; - path = path.substr(rm.length); - out = out + rm; - } - } - return out; - } - - if(uri) { - this.parse(uri); - } - - }, - - - // - // Usage example: - // var myColor = new jscolor.color(myInputElement) - // - - color : function(target, prop) { - - - this.required = true; // refuse empty values? - this.adjust = true; // adjust value to uniform notation? - this.hash = false; // prefix color with # symbol? - this.caps = true; // uppercase? - this.slider = true; // show the value/saturation slider? - this.valueElement = target; // value holder - this.styleElement = target; // where to reflect current color - this.onImmediateChange = null; // onchange callback (can be either string or function) - this.hsv = [0, 0, 1]; // read-only 0-6, 0-1, 0-1 - this.rgb = [1, 1, 1]; // read-only 0-1, 0-1, 0-1 - this.minH = 0; // read-only 0-6 - this.maxH = 6; // read-only 0-6 - this.minS = 0; // read-only 0-1 - this.maxS = 1; // read-only 0-1 - this.minV = 0; // read-only 0-1 - this.maxV = 1; // read-only 0-1 - - this.pickerOnfocus = true; // display picker on focus? - this.pickerMode = 'HSV'; // HSV | HVS - this.pickerPosition = 'bottom'; // left | right | top | bottom - this.pickerSmartPosition = true; // automatically adjust picker position when necessary - this.pickerButtonHeight = 20; // px - this.pickerClosable = false; - this.pickerCloseText = 'Close'; - this.pickerButtonColor = 'ButtonText'; // px - this.pickerFace = 10; // px - this.pickerFaceColor = 'ThreeDFace'; // CSS color - this.pickerBorder = 1; // px - this.pickerBorderColor = 'ThreeDHighlight ThreeDShadow ThreeDShadow ThreeDHighlight'; // CSS color - this.pickerInset = 1; // px - this.pickerInsetColor = 'ThreeDShadow ThreeDHighlight ThreeDHighlight ThreeDShadow'; // CSS color - this.pickerZIndex = 10000; - - - for(var p in prop) { - if(prop.hasOwnProperty(p)) { - this[p] = prop[p]; - } + throw new Error('Invalid arguments'); } - this.hidePicker = function() { - if(isPickerOwner()) { - removePicker(); + // Getter: channel(name) + // Setter: channel(name, value) + // + this.channel = function (name, value) { + if (typeof name !== 'string') { + throw new Error('Invalid value for channel name: ' + name); } - }; - - this.showPicker = function() { - if(!isPickerOwner()) { - var tp = jscolor.getElementPos(target); // target pos - var ts = jscolor.getElementSize(target); // target size - var vp = jscolor.getViewPos(); // view pos - var vs = jscolor.getViewSize(); // view size - var ps = getPickerDims(this); // picker size - var a, b, c; - switch(this.pickerPosition.toLowerCase()) { - case 'left': a=1; b=0; c=-1; break; - case 'right':a=1; b=0; c=1; break; - case 'top': a=0; b=1; c=-1; break; - default: a=0; b=1; c=1; break; + if (value === undefined) { + // getting channel value + if (!this.channels.hasOwnProperty(name.toLowerCase())) { + console.warn('Getting unknown channel: ' + name); + return false; } - var l = (ts[b]+ps[b])/2; + return this.channels[name.toLowerCase()]; - // picker pos - if (!this.pickerSmartPosition) { - var pp = [ - tp[a], - tp[b]+ts[b]-l+l*c - ]; - } else { - var pp = [ - -vp[a]+tp[a]+ps[a] > vs[a] ? - (-vp[a]+tp[a]+ts[a]/2 > vs[a]/2 && tp[a]+ts[a]-ps[a] >= 0 ? tp[a]+ts[a]-ps[a] : tp[a]) : - tp[a], - -vp[b]+tp[b]+ts[b]+ps[b]-l+l*c > vs[b] ? - (-vp[b]+tp[b]+ts[b]/2 > vs[b]/2 && tp[b]+ts[b]-l-l*c >= 0 ? tp[b]+ts[b]-l-l*c : tp[b]+ts[b]-l+l*c) : - (tp[b]+ts[b]-l+l*c >= 0 ? tp[b]+ts[b]-l+l*c : tp[b]+ts[b]-l-l*c) - ]; - } - drawPicker(pp[a], pp[b]); - } - }; - - - this.importColor = function() { - if(!valueElement) { - this.exportColor(); } else { - if(!this.adjust) { - if(!this.fromString(valueElement.value, leaveValue)) { - styleElement.style.backgroundImage = styleElement.jscStyle.backgroundImage; - styleElement.style.backgroundColor = styleElement.jscStyle.backgroundColor; - styleElement.style.color = styleElement.jscStyle.color; - this.exportColor(leaveValue | leaveStyle); - } - } else if(!this.required && /^\s*$/.test(valueElement.value)) { - valueElement.value = ''; - styleElement.style.backgroundImage = styleElement.jscStyle.backgroundImage; - styleElement.style.backgroundColor = styleElement.jscStyle.backgroundColor; - styleElement.style.color = styleElement.jscStyle.color; - this.exportColor(leaveValue | leaveStyle); - - } else if(this.fromString(valueElement.value)) { - // OK - } else { - this.exportColor(); + // setting channel value + var res = false; + switch (name.toLowerCase()) { + case 'r': res = this.fromRGBA(value, null, null, null); break; + case 'g': res = this.fromRGBA(null, value, null, null); break; + case 'b': res = this.fromRGBA(null, null, value, null); break; + case 'h': res = this.fromHSVA(value, null, null, null); break; + case 's': res = this.fromHSVA(null, value, null, null); break; + case 'v': res = this.fromHSVA(null, null, value, null); break; + case 'a': res = this.fromHSVA(null, null, null, value); break; + default: + console.warn('Setting unknown channel: ' + name); + return false; + } + if (res) { + this.redraw(); // immediately redraws the picker, if it's displayed + return true; } } - }; + + return false; + } - this.exportColor = function(flags) { - if(!(flags & leaveValue) && valueElement) { - var value = this.toString(); - if(this.caps) { value = value.toUpperCase(); } - if(this.hash) { value = '#'+value; } - valueElement.value = value; - } - if(!(flags & leaveStyle) && styleElement) { - styleElement.style.backgroundImage = "none"; - styleElement.style.backgroundColor = - '#'+this.toString(); - styleElement.style.color = - 0.213 * this.rgb[0] + - 0.715 * this.rgb[1] + - 0.072 * this.rgb[2] - < 0.5 ? '#FFF' : '#000'; - } - if(!(flags & leavePad) && isPickerOwner()) { - redrawPad(); - } - if(!(flags & leaveSld) && isPickerOwner()) { - redrawSld(); + // Triggers given input event(s) by: + // - executing on callback specified as picker's option + // - triggering standard DOM event listeners attached to the value element + // + // It is possible to specify multiple events separated with a space. + // + this.trigger = function (eventNames) { + var evs = jsc.strList(eventNames); + for (var i = 0; i < evs.length; i += 1) { + var ev = evs[i].toLowerCase(); + + // trigger a callback + var callbackProp = null; + switch (ev) { + case 'input': callbackProp = 'onInput'; break; + case 'change': callbackProp = 'onChange'; break; + } + if (callbackProp) { + jsc.triggerCallback(this, callbackProp); + } + + // trigger standard DOM event listeners on the value element + jsc.triggerInputEvent(this.valueElement, ev, true, true); } }; - this.fromHSV = function(h, s, v, flags) { // null = don't change - if(h !== null) { h = Math.max(0.0, this.minH, Math.min(6.0, this.maxH, h)); } - if(s !== null) { s = Math.max(0.0, this.minS, Math.min(1.0, this.maxS, s)); } - if(v !== null) { v = Math.max(0.0, this.minV, Math.min(1.0, this.maxV, v)); } + // h: 0-360 + // s: 0-100 + // v: 0-100 + // a: 0.0-1.0 + // + this.fromHSVA = function (h, s, v, a, flags) { // null = don't change + if (h === undefined) { h = null; } + if (s === undefined) { s = null; } + if (v === undefined) { v = null; } + if (a === undefined) { a = null; } - this.rgb = HSV_RGB( - h===null ? this.hsv[0] : (this.hsv[0]=h), - s===null ? this.hsv[1] : (this.hsv[1]=s), - v===null ? this.hsv[2] : (this.hsv[2]=v) + if (h !== null) { + if (isNaN(h)) { return false; } + this.channels.h = Math.max(0, Math.min(360, h)); + } + if (s !== null) { + if (isNaN(s)) { return false; } + this.channels.s = Math.max(0, Math.min(100, this.maxS, s), this.minS); + } + if (v !== null) { + if (isNaN(v)) { return false; } + this.channels.v = Math.max(0, Math.min(100, this.maxV, v), this.minV); + } + if (a !== null) { + if (isNaN(a)) { return false; } + this.channels.a = this.hasAlphaChannel() ? + Math.max(0, Math.min(1, this.maxA, a), this.minA) : + 1.0; // if alpha channel is disabled, the color should stay 100% opaque + } + + var rgb = jsc.HSV_RGB( + this.channels.h, + this.channels.s, + this.channels.v ); + this.channels.r = rgb[0]; + this.channels.g = rgb[1]; + this.channels.b = rgb[2]; - this.exportColor(flags); + this.exposeColor(flags); + return true; }; - this.fromRGB = function(r, g, b, flags) { // null = don't change - if(r !== null) { r = Math.max(0.0, Math.min(1.0, r)); } - if(g !== null) { g = Math.max(0.0, Math.min(1.0, g)); } - if(b !== null) { b = Math.max(0.0, Math.min(1.0, b)); } + // r: 0-255 + // g: 0-255 + // b: 0-255 + // a: 0.0-1.0 + // + this.fromRGBA = function (r, g, b, a, flags) { // null = don't change + if (r === undefined) { r = null; } + if (g === undefined) { g = null; } + if (b === undefined) { b = null; } + if (a === undefined) { a = null; } - var hsv = RGB_HSV( - r===null ? this.rgb[0] : r, - g===null ? this.rgb[1] : g, - b===null ? this.rgb[2] : b + if (r !== null) { + if (isNaN(r)) { return false; } + r = Math.max(0, Math.min(255, r)); + } + if (g !== null) { + if (isNaN(g)) { return false; } + g = Math.max(0, Math.min(255, g)); + } + if (b !== null) { + if (isNaN(b)) { return false; } + b = Math.max(0, Math.min(255, b)); + } + if (a !== null) { + if (isNaN(a)) { return false; } + this.channels.a = this.hasAlphaChannel() ? + Math.max(0, Math.min(1, this.maxA, a), this.minA) : + 1.0; // if alpha channel is disabled, the color should stay 100% opaque + } + + var hsv = jsc.RGB_HSV( + r===null ? this.channels.r : r, + g===null ? this.channels.g : g, + b===null ? this.channels.b : b ); - if(hsv[0] !== null) { - this.hsv[0] = Math.max(0.0, this.minH, Math.min(6.0, this.maxH, hsv[0])); + if (hsv[0] !== null) { + this.channels.h = Math.max(0, Math.min(360, hsv[0])); } - if(hsv[2] !== 0) { - this.hsv[1] = hsv[1]===null ? null : Math.max(0.0, this.minS, Math.min(1.0, this.maxS, hsv[1])); + if (hsv[2] !== 0) { // fully black color stays black through entire saturation range, so let's not change saturation + this.channels.s = Math.max(0, this.minS, Math.min(100, this.maxS, hsv[1])); } - this.hsv[2] = hsv[2]===null ? null : Math.max(0.0, this.minV, Math.min(1.0, this.maxV, hsv[2])); + this.channels.v = Math.max(0, this.minV, Math.min(100, this.maxV, hsv[2])); // update RGB according to final HSV, as some values might be trimmed - var rgb = HSV_RGB(this.hsv[0], this.hsv[1], this.hsv[2]); - this.rgb[0] = rgb[0]; - this.rgb[1] = rgb[1]; - this.rgb[2] = rgb[2]; + var rgb = jsc.HSV_RGB(this.channels.h, this.channels.s, this.channels.v); + this.channels.r = rgb[0]; + this.channels.g = rgb[1]; + this.channels.b = rgb[2]; - this.exportColor(flags); + this.exposeColor(flags); + return true; }; - this.fromString = function(hex, flags) { - var m = hex.match(/^\W*([0-9A-F]{3}([0-9A-F]{3})?)\W*$/i); - if(!m) { - return false; - } else { - if(m[1].length === 6) { // 6-char notation - this.fromRGB( - parseInt(m[1].substr(0,2),16) / 255, - parseInt(m[1].substr(2,2),16) / 255, - parseInt(m[1].substr(4,2),16) / 255, - flags - ); - } else { // 3-char notation - this.fromRGB( - parseInt(m[1].charAt(0)+m[1].charAt(0),16) / 255, - parseInt(m[1].charAt(1)+m[1].charAt(1),16) / 255, - parseInt(m[1].charAt(2)+m[1].charAt(2),16) / 255, - flags - ); - } + // DEPRECATED. Use .fromHSVA() instead + // + this.fromHSV = function (h, s, v, flags) { + console.warn('fromHSV() method is DEPRECATED. Using fromHSVA() instead.' + jsc.docsRef); + return this.fromHSVA(h, s, v, null, flags); + }; + + + // DEPRECATED. Use .fromRGBA() instead + // + this.fromRGB = function (r, g, b, flags) { + console.warn('fromRGB() method is DEPRECATED. Using fromRGBA() instead.' + jsc.docsRef); + return this.fromRGBA(r, g, b, null, flags); + }; + + + this.fromString = function (str, flags) { + if (!this.required && str.trim() === '') { + // setting empty string to an optional color input + this.setPreviewElementBg(null); + this.setValueElementValue(''); return true; } + + var color = jsc.parseColorString(str); + if (!color) { + return false; // could not parse + } + if (this.format.toLowerCase() === 'any') { + this._setFormat(color.format); // adapt format + if (!jsc.isAlphaFormat(this.getFormat())) { + color.rgba[3] = 1.0; // when switching to a format that doesn't support alpha, set full opacity + } + } + this.fromRGBA( + color.rgba[0], + color.rgba[1], + color.rgba[2], + color.rgba[3], + flags + ); + return true; }; - this.toString = function() { - return ( - (0x100 | Math.round(255*this.rgb[0])).toString(16).substr(1) + - (0x100 | Math.round(255*this.rgb[1])).toString(16).substr(1) + - (0x100 | Math.round(255*this.rgb[2])).toString(16).substr(1) + this.toString = function (format) { + if (format === undefined) { + format = this.getFormat(); // format not specified -> use the current format + } + switch (format.toLowerCase()) { + case 'hex': return this.toHEXString(); break; + case 'hexa': return this.toHEXAString(); break; + case 'rgb': return this.toRGBString(); break; + case 'rgba': return this.toRGBAString(); break; + } + return false; + }; + + + this.toHEXString = function () { + return jsc.hexColor( + this.channels.r, + this.channels.g, + this.channels.b ); }; - function RGB_HSV(r, g, b) { - var n = Math.min(Math.min(r,g),b); - var v = Math.max(Math.max(r,g),b); - var m = v - n; - if(m === 0) { return [ null, 0, v ]; } - var h = r===n ? 3+(b-g)/m : (g===n ? 5+(r-b)/m : 1+(g-r)/m); - return [ h===6?0:h, m/v, v ]; - } + this.toHEXAString = function () { + return jsc.hexaColor( + this.channels.r, + this.channels.g, + this.channels.b, + this.channels.a + ); + }; - function HSV_RGB(h, s, v) { - if(h === null) { return [ v, v, v ]; } - var i = Math.floor(h); - var f = i%2 ? h-i : 1-(h-i); - var m = v * (1 - s); - var n = v * (1 - s*f); - switch(i) { - case 6: - case 0: return [v,n,m]; - case 1: return [n,v,m]; - case 2: return [m,v,n]; - case 3: return [m,n,v]; - case 4: return [n,m,v]; - case 5: return [v,m,n]; + this.toRGBString = function () { + return jsc.rgbColor( + this.channels.r, + this.channels.g, + this.channels.b + ); + }; + + + this.toRGBAString = function () { + return jsc.rgbaColor( + this.channels.r, + this.channels.g, + this.channels.b, + this.channels.a + ); + }; + + + this.toGrayscale = function () { + return ( + 0.213 * this.channels.r + + 0.715 * this.channels.g + + 0.072 * this.channels.b + ); + }; + + + this.toCanvas = function () { + return jsc.genColorPreviewCanvas(this.toRGBAString()).canvas; + }; + + + this.toDataURL = function () { + return this.toCanvas().toDataURL(); + }; + + + this.toBackground = function () { + return jsc.pub.background(this.toRGBAString()); + }; + + + this.isLight = function () { + return this.toGrayscale() > 255 / 2; + }; + + + this.hide = function () { + if (isPickerOwner()) { + detachPicker(); } - } + }; - function removePicker() { - delete jscolor.picker.owner; - document.getElementsByTagName('body')[0].removeChild(jscolor.picker.boxB); - } + this.show = function () { + drawPicker(); + }; - function drawPicker(x, y) { - if(!jscolor.picker) { - jscolor.picker = { - box : document.createElement('div'), - boxB : document.createElement('div'), - pad : document.createElement('div'), - padB : document.createElement('div'), - padM : document.createElement('div'), - sld : document.createElement('div'), - sldB : document.createElement('div'), - sldM : document.createElement('div'), - btn : document.createElement('div'), - btnS : document.createElement('span'), - btnT : document.createTextNode(THIS.pickerCloseText) - }; - for(var i=0,segSize=4; i fill the entire element) + + if ( + jsc.isTextInput(this.previewElement) || // text input + (jsc.isButton(this.previewElement) && !jsc.isButtonEmpty(this.previewElement)) // button with text + ) { + previewPos = this.previewPosition; + } + + this.setPreviewElementBg(this.toRGBAString()); + } + + if (isPickerOwner()) { + redrawPad(); + redrawSld(); + redrawASld(); + } + }; + + + this.setPreviewElementBg = function (color) { + if (!this.previewElement) { + return; + } + + var position = null; // color preview position: null | 'left' | 'right' + var width = null; // color preview width: px | null = fill the entire element + if ( + jsc.isTextInput(this.previewElement) || // text input + (jsc.isButton(this.previewElement) && !jsc.isButtonEmpty(this.previewElement)) // button with text + ) { + position = this.previewPosition; + width = this.previewSize; + } + + var backgrounds = []; + + if (!color) { + // there is no color preview to display -> let's remove any previous background image + backgrounds.push({ + image: 'none', + position: 'left top', + size: 'auto', + repeat: 'no-repeat', + origin: 'padding-box', + }); + } else { + // CSS gradient for background color preview + backgrounds.push({ + image: jsc.genColorPreviewGradient( + color, + position, + width ? width - jsc.pub.previewSeparator.length : null + ), + position: 'left top', + size: 'auto', + repeat: position ? 'repeat-y' : 'repeat', + origin: 'padding-box', + }); + + // data URL of generated PNG image with a gray transparency chessboard + var preview = jsc.genColorPreviewCanvas( + 'rgba(0,0,0,0)', + position ? {'left':'right', 'right':'left'}[position] : null, + width, + true + ); + backgrounds.push({ + image: 'url(\'' + preview.canvas.toDataURL() + '\')', + position: (position || 'left') + ' top', + size: preview.width + 'px ' + preview.height + 'px', + repeat: position ? 'repeat-y' : 'repeat', + origin: 'padding-box', }); } - p.sldM.onmouseup = - p.sldM.onmouseout = function() { if(holdSld) { holdSld=false; jscolor.fireEvent(valueElement,'change'); } }; - p.sldM.onmousedown = function(e) { - holdPad=false; - holdSld=true; - setSld(e); - dispatchImmediateChange(); + + var bg = { + image: [], + position: [], + size: [], + repeat: [], + origin: [], }; - if('ontouchstart' in window) { - p.sldM.addEventListener('touchstart', function(e) { - touchOffset={ - 'X': e.target.offsetParent.offsetLeft, - 'Y': e.target.offsetParent.offsetTop - }; - this.onmousedown({ - 'offsetX':e.touches[0].pageX-touchOffset.X, - 'offsetY':e.touches[0].pageY-touchOffset.Y - }); - }); + for (var i = 0; i < backgrounds.length; i += 1) { + bg.image.push(backgrounds[i].image); + bg.position.push(backgrounds[i].position); + bg.size.push(backgrounds[i].size); + bg.repeat.push(backgrounds[i].repeat); + bg.origin.push(backgrounds[i].origin); } + // set previewElement's background-images + var sty = { + 'background-image': bg.image.join(', '), + 'background-position': bg.position.join(', '), + 'background-size': bg.size.join(', '), + 'background-repeat': bg.repeat.join(', '), + 'background-origin': bg.origin.join(', '), + }; + jsc.setStyle(this.previewElement, sty, this.forceStyle); + + + // set/restore previewElement's padding + var padding = { + left: null, + right: null, + }; + if (position) { + padding[position] = (this.previewSize + this.previewPadding) + 'px'; + } + + var sty = { + 'padding-left': padding.left, + 'padding-right': padding.right, + }; + jsc.setStyle(this.previewElement, sty, this.forceStyle, true); + }; + + + this.setValueElementValue = function (str) { + if (this.valueElement) { + if (jsc.nodeName(this.valueElement) === 'input') { + this.valueElement.value = str; + } else { + this.valueElement.innerHTML = str; + } + } + }; + + + this.setAlphaElementValue = function (str) { + if (this.alphaElement) { + if (jsc.nodeName(this.alphaElement) === 'input') { + this.alphaElement.value = str; + } else { + this.alphaElement.innerHTML = str; + } + } + }; + + + this._processParentElementsInDOM = function () { + if (this._parentElementsProcessed) { return; } + this._parentElementsProcessed = true; + + var elm = this.targetElement; + do { + // If the target element or one of its parent nodes has fixed position, + // then use fixed positioning instead + var compStyle = jsc.getCompStyle(elm); + if (compStyle.position && compStyle.position.toLowerCase() === 'fixed') { + this.fixed = true; + } + + if (elm !== this.targetElement) { + // Ensure to attach onParentScroll only once to each parent element + // (multiple targetElements can share the same parent nodes) + // + // Note: It's not just offsetParents that can be scrollable, + // that's why we loop through all parent nodes + if (!jsc.getData(elm, 'hasScrollListener')) { + elm.addEventListener('scroll', jsc.onParentScroll, false); + jsc.setData(elm, 'hasScrollListener', true); + } + } + } while ((elm = elm.parentNode) && jsc.nodeName(elm) !== 'body'); + }; + + + this.tryHide = function () { + if (this.hideOnLeave) { + this.hide(); + } + }; + + + this.set__palette = function (val) { + this.palette = val; + this._palette = jsc.parsePaletteValue(val); + this._paletteHasTransparency = jsc.containsTranparentColor(this._palette); + }; + + + function setOption (option, value) { + if (typeof option !== 'string') { + throw new Error('Invalid value for option name: ' + option); + } + + // enum option + if (jsc.enumOpts.hasOwnProperty(option)) { + if (typeof value === 'string') { // enum string values are case insensitive + value = value.toLowerCase(); + } + if (jsc.enumOpts[option].indexOf(value) === -1) { + throw new Error('Option \'' + option + '\' has invalid value: ' + value); + } + } + + // deprecated option + if (jsc.deprecatedOpts.hasOwnProperty(option)) { + var oldOpt = option; + var newOpt = jsc.deprecatedOpts[option]; + if (newOpt) { + // if we have a new name for this option, let's log a warning and use the new name + console.warn('Option \'%s\' is DEPRECATED, using \'%s\' instead.' + jsc.docsRef, oldOpt, newOpt); + option = newOpt; + } else { + // new name not available for the option + throw new Error('Option \'' + option + '\' is DEPRECATED'); + } + } + + var setter = 'set__' + option; + + if (typeof THIS[setter] === 'function') { // a setter exists for this option + THIS[setter](value); + return true; + + } else if (option in THIS) { // option exists as a property + THIS[option] = value; + return true; + } + + throw new Error('Unrecognized configuration option: ' + option); + } + + + function getOption (option) { + if (typeof option !== 'string') { + throw new Error('Invalid value for option name: ' + option); + } + + // deprecated option + if (jsc.deprecatedOpts.hasOwnProperty(option)) { + var oldOpt = option; + var newOpt = jsc.deprecatedOpts[option]; + if (newOpt) { + // if we have a new name for this option, let's log a warning and use the new name + console.warn('Option \'%s\' is DEPRECATED, using \'%s\' instead.' + jsc.docsRef, oldOpt, newOpt); + option = newOpt; + } else { + // new name not available for the option + throw new Error('Option \'' + option + '\' is DEPRECATED'); + } + } + + var getter = 'get__' + option; + + if (typeof THIS[getter] === 'function') { // a getter exists for this option + return THIS[getter](value); + + } else if (option in THIS) { // option exists as a property + return THIS[option]; + } + + throw new Error('Unrecognized configuration option: ' + option); + } + + + function detachPicker () { + jsc.removeClass(THIS.targetElement, jsc.pub.activeClassName); + jsc.picker.wrap.parentNode.removeChild(jsc.picker.wrap); + delete jsc.picker.owner; + } + + + function drawPicker () { + + // At this point, when drawing the picker, we know what the parent elements are + // and we can do all related DOM operations, such as registering events on them + // or checking their positioning + THIS._processParentElementsInDOM(); + + if (!jsc.picker) { + jsc.picker = { + owner: null, // owner picker instance + wrap : jsc.createEl('div'), + box : jsc.createEl('div'), + boxS : jsc.createEl('div'), // shadow area + boxB : jsc.createEl('div'), // border + pad : jsc.createEl('div'), + padB : jsc.createEl('div'), // border + padM : jsc.createEl('div'), // mouse/touch area + padCanvas : jsc.createPadCanvas(), + cross : jsc.createEl('div'), + crossBY : jsc.createEl('div'), // border Y + crossBX : jsc.createEl('div'), // border X + crossLY : jsc.createEl('div'), // line Y + crossLX : jsc.createEl('div'), // line X + sld : jsc.createEl('div'), // slider + sldB : jsc.createEl('div'), // border + sldM : jsc.createEl('div'), // mouse/touch area + sldGrad : jsc.createSliderGradient(), + sldPtrS : jsc.createEl('div'), // slider pointer spacer + sldPtrIB : jsc.createEl('div'), // slider pointer inner border + sldPtrMB : jsc.createEl('div'), // slider pointer middle border + sldPtrOB : jsc.createEl('div'), // slider pointer outer border + asld : jsc.createEl('div'), // alpha slider + asldB : jsc.createEl('div'), // border + asldM : jsc.createEl('div'), // mouse/touch area + asldGrad : jsc.createASliderGradient(), + asldPtrS : jsc.createEl('div'), // slider pointer spacer + asldPtrIB : jsc.createEl('div'), // slider pointer inner border + asldPtrMB : jsc.createEl('div'), // slider pointer middle border + asldPtrOB : jsc.createEl('div'), // slider pointer outer border + pal : jsc.createEl('div'), // palette + btn : jsc.createEl('div'), + btnT : jsc.createEl('span'), // text + }; + + jsc.picker.pad.appendChild(jsc.picker.padCanvas.elm); + jsc.picker.padB.appendChild(jsc.picker.pad); + jsc.picker.cross.appendChild(jsc.picker.crossBY); + jsc.picker.cross.appendChild(jsc.picker.crossBX); + jsc.picker.cross.appendChild(jsc.picker.crossLY); + jsc.picker.cross.appendChild(jsc.picker.crossLX); + jsc.picker.padB.appendChild(jsc.picker.cross); + jsc.picker.box.appendChild(jsc.picker.padB); + jsc.picker.box.appendChild(jsc.picker.padM); + + jsc.picker.sld.appendChild(jsc.picker.sldGrad.elm); + jsc.picker.sldB.appendChild(jsc.picker.sld); + jsc.picker.sldB.appendChild(jsc.picker.sldPtrOB); + jsc.picker.sldPtrOB.appendChild(jsc.picker.sldPtrMB); + jsc.picker.sldPtrMB.appendChild(jsc.picker.sldPtrIB); + jsc.picker.sldPtrIB.appendChild(jsc.picker.sldPtrS); + jsc.picker.box.appendChild(jsc.picker.sldB); + jsc.picker.box.appendChild(jsc.picker.sldM); + + jsc.picker.asld.appendChild(jsc.picker.asldGrad.elm); + jsc.picker.asldB.appendChild(jsc.picker.asld); + jsc.picker.asldB.appendChild(jsc.picker.asldPtrOB); + jsc.picker.asldPtrOB.appendChild(jsc.picker.asldPtrMB); + jsc.picker.asldPtrMB.appendChild(jsc.picker.asldPtrIB); + jsc.picker.asldPtrIB.appendChild(jsc.picker.asldPtrS); + jsc.picker.box.appendChild(jsc.picker.asldB); + jsc.picker.box.appendChild(jsc.picker.asldM); + + jsc.picker.box.appendChild(jsc.picker.pal); + + jsc.picker.btn.appendChild(jsc.picker.btnT); + jsc.picker.box.appendChild(jsc.picker.btn); + + jsc.picker.boxB.appendChild(jsc.picker.box); + jsc.picker.wrap.appendChild(jsc.picker.boxS); + jsc.picker.wrap.appendChild(jsc.picker.boxB); + + jsc.picker.wrap.addEventListener('touchstart', jsc.onPickerTouchStart, + jsc.isPassiveEventSupported ? {passive: false} : false); + } + + var p = jsc.picker; + + var displaySlider = !!jsc.getSliderChannel(THIS); + var displayAlphaSlider = THIS.hasAlphaChannel(); + var pickerDims = jsc.getPickerDims(THIS); + var crossOuterSize = (2 * THIS.pointerBorderWidth + THIS.pointerThickness + 2 * THIS.crossSize); + var controlPadding = jsc.getControlPadding(THIS); + var borderRadius = Math.min( + THIS.borderRadius, + Math.round(THIS.padding * Math.PI)); // px + var padCursor = 'crosshair'; + + // wrap + p.wrap.className = 'jscolor-picker-wrap'; + p.wrap.style.clear = 'both'; + p.wrap.style.width = pickerDims.borderW + 'px'; + p.wrap.style.height = pickerDims.borderH + 'px'; + p.wrap.style.zIndex = THIS.zIndex; + // picker - var dims = getPickerDims(THIS); - p.box.style.width = dims[0] + 'px'; - p.box.style.height = dims[1] + 'px'; + p.box.className = 'jscolor-picker'; + p.box.style.width = pickerDims.paddedW + 'px'; + p.box.style.height = pickerDims.paddedH + 'px'; + p.box.style.position = 'relative'; + + // picker shadow + p.boxS.className = 'jscolor-picker-shadow'; + p.boxS.style.position = 'absolute'; + p.boxS.style.left = '0'; + p.boxS.style.top = '0'; + p.boxS.style.width = '100%'; + p.boxS.style.height = '100%'; + jsc.setBorderRadius(p.boxS, borderRadius + 'px'); // picker border - p.boxB.style.position = 'absolute'; - p.boxB.style.clear = 'both'; - p.boxB.style.left = x+'px'; - p.boxB.style.top = y+'px'; - p.boxB.style.zIndex = THIS.pickerZIndex; - p.boxB.style.border = THIS.pickerBorder+'px solid'; - p.boxB.style.borderColor = THIS.pickerBorderColor; - p.boxB.style.background = THIS.pickerFaceColor; + p.boxB.className = 'jscolor-picker-border'; + p.boxB.style.position = 'relative'; + p.boxB.style.border = THIS.borderWidth + 'px solid'; + p.boxB.style.borderColor = THIS.borderColor; + p.boxB.style.background = THIS.backgroundColor; + jsc.setBorderRadius(p.boxB, borderRadius + 'px'); - // pad image - p.pad.style.width = jscolor.images.pad[0]+'px'; - p.pad.style.height = jscolor.images.pad[1]+'px'; + // IE hack: + // If the element is transparent, IE will trigger the event on the elements under it, + // e.g. on Canvas or on elements with border + p.padM.style.background = 'rgba(255,0,0,.2)'; + p.sldM.style.background = 'rgba(0,255,0,.2)'; + p.asldM.style.background = 'rgba(0,0,255,.2)'; + + p.padM.style.opacity = + p.sldM.style.opacity = + p.asldM.style.opacity = + '0'; + + // pad + p.pad.style.position = 'relative'; + p.pad.style.width = THIS.width + 'px'; + p.pad.style.height = THIS.height + 'px'; + + // pad - color spectrum (HSV and HVS) + p.padCanvas.draw(THIS.width, THIS.height, jsc.getPadYChannel(THIS)); // pad border p.padB.style.position = 'absolute'; - p.padB.style.left = THIS.pickerFace+'px'; - p.padB.style.top = THIS.pickerFace+'px'; - p.padB.style.border = THIS.pickerInset+'px solid'; - p.padB.style.borderColor = THIS.pickerInsetColor; + p.padB.style.left = THIS.padding + 'px'; + p.padB.style.top = THIS.padding + 'px'; + p.padB.style.border = THIS.controlBorderWidth + 'px solid'; + p.padB.style.borderColor = THIS.controlBorderColor; // pad mouse area p.padM.style.position = 'absolute'; - p.padM.style.left = '0'; - p.padM.style.top = '0'; - p.padM.style.width = THIS.pickerFace + 2*THIS.pickerInset + jscolor.images.pad[0] + jscolor.images.arrow[0] + 'px'; - p.padM.style.height = p.box.style.height; - p.padM.style.cursor = 'crosshair'; + p.padM.style.left = 0 + 'px'; + p.padM.style.top = 0 + 'px'; + p.padM.style.width = (THIS.padding + 2 * THIS.controlBorderWidth + THIS.width + controlPadding) + 'px'; + p.padM.style.height = (2 * THIS.controlBorderWidth + 2 * THIS.padding + THIS.height) + 'px'; + p.padM.style.cursor = padCursor; + jsc.setData(p.padM, { + instance: THIS, + control: 'pad', + }) - // slider image + // pad cross + p.cross.style.position = 'absolute'; + p.cross.style.left = + p.cross.style.top = + '0'; + p.cross.style.width = + p.cross.style.height = + crossOuterSize + 'px'; + + // pad cross border Y and X + p.crossBY.style.position = + p.crossBX.style.position = + 'absolute'; + p.crossBY.style.background = + p.crossBX.style.background = + THIS.pointerBorderColor; + p.crossBY.style.width = + p.crossBX.style.height = + (2 * THIS.pointerBorderWidth + THIS.pointerThickness) + 'px'; + p.crossBY.style.height = + p.crossBX.style.width = + crossOuterSize + 'px'; + p.crossBY.style.left = + p.crossBX.style.top = + (Math.floor(crossOuterSize / 2) - Math.floor(THIS.pointerThickness / 2) - THIS.pointerBorderWidth) + 'px'; + p.crossBY.style.top = + p.crossBX.style.left = + '0'; + + // pad cross line Y and X + p.crossLY.style.position = + p.crossLX.style.position = + 'absolute'; + p.crossLY.style.background = + p.crossLX.style.background = + THIS.pointerColor; + p.crossLY.style.height = + p.crossLX.style.width = + (crossOuterSize - 2 * THIS.pointerBorderWidth) + 'px'; + p.crossLY.style.width = + p.crossLX.style.height = + THIS.pointerThickness + 'px'; + p.crossLY.style.left = + p.crossLX.style.top = + (Math.floor(crossOuterSize / 2) - Math.floor(THIS.pointerThickness / 2)) + 'px'; + p.crossLY.style.top = + p.crossLX.style.left = + THIS.pointerBorderWidth + 'px'; + + + // slider p.sld.style.overflow = 'hidden'; - p.sld.style.width = jscolor.images.sld[0]+'px'; - p.sld.style.height = jscolor.images.sld[1]+'px'; + p.sld.style.width = THIS.sliderSize + 'px'; + p.sld.style.height = THIS.height + 'px'; + + // slider gradient + p.sldGrad.draw(THIS.sliderSize, THIS.height, '#000', '#000'); // slider border - p.sldB.style.display = THIS.slider ? 'block' : 'none'; + p.sldB.style.display = displaySlider ? 'block' : 'none'; p.sldB.style.position = 'absolute'; - p.sldB.style.right = THIS.pickerFace+'px'; - p.sldB.style.top = THIS.pickerFace+'px'; - p.sldB.style.border = THIS.pickerInset+'px solid'; - p.sldB.style.borderColor = THIS.pickerInsetColor; + p.sldB.style.left = (THIS.padding + THIS.width + 2 * THIS.controlBorderWidth + 2 * controlPadding) + 'px'; + p.sldB.style.top = THIS.padding + 'px'; + p.sldB.style.border = THIS.controlBorderWidth + 'px solid'; + p.sldB.style.borderColor = THIS.controlBorderColor; // slider mouse area - p.sldM.style.display = THIS.slider ? 'block' : 'none'; + p.sldM.style.display = displaySlider ? 'block' : 'none'; p.sldM.style.position = 'absolute'; - p.sldM.style.right = '0'; - p.sldM.style.top = '0'; - p.sldM.style.width = jscolor.images.sld[0] + jscolor.images.arrow[0] + THIS.pickerFace + 2*THIS.pickerInset + 'px'; - p.sldM.style.height = p.box.style.height; - try { - p.sldM.style.cursor = 'pointer'; - } catch(eOldIE) { - p.sldM.style.cursor = 'hand'; + p.sldM.style.left = (THIS.padding + THIS.width + 2 * THIS.controlBorderWidth + controlPadding) + 'px'; + p.sldM.style.top = 0 + 'px'; + p.sldM.style.width = ( + (THIS.sliderSize + 2 * controlPadding + 2 * THIS.controlBorderWidth) + + (displayAlphaSlider ? 0 : Math.max(0, THIS.padding - controlPadding)) // remaining padding to the right edge + ) + 'px'; + p.sldM.style.height = (2 * THIS.controlBorderWidth + 2 * THIS.padding + THIS.height) + 'px'; + p.sldM.style.cursor = 'default'; + jsc.setData(p.sldM, { + instance: THIS, + control: 'sld', + }); + + // slider pointer inner and outer border + p.sldPtrIB.style.border = + p.sldPtrOB.style.border = + THIS.pointerBorderWidth + 'px solid ' + THIS.pointerBorderColor; + + // slider pointer outer border + p.sldPtrOB.style.position = 'absolute'; + p.sldPtrOB.style.left = -(2 * THIS.pointerBorderWidth + THIS.pointerThickness) + 'px'; + p.sldPtrOB.style.top = '0'; + + // slider pointer middle border + p.sldPtrMB.style.border = THIS.pointerThickness + 'px solid ' + THIS.pointerColor; + + // slider pointer spacer + p.sldPtrS.style.width = THIS.sliderSize + 'px'; + p.sldPtrS.style.height = jsc.pub.sliderInnerSpace + 'px'; + + + // alpha slider + p.asld.style.overflow = 'hidden'; + p.asld.style.width = THIS.sliderSize + 'px'; + p.asld.style.height = THIS.height + 'px'; + + // alpha slider gradient + p.asldGrad.draw(THIS.sliderSize, THIS.height, '#000'); + + // alpha slider border + p.asldB.style.display = displayAlphaSlider ? 'block' : 'none'; + p.asldB.style.position = 'absolute'; + p.asldB.style.left = ( + (THIS.padding + THIS.width + 2 * THIS.controlBorderWidth + controlPadding) + + (displaySlider ? (THIS.sliderSize + 3 * controlPadding + 2 * THIS.controlBorderWidth) : 0) + ) + 'px'; + p.asldB.style.top = THIS.padding + 'px'; + p.asldB.style.border = THIS.controlBorderWidth + 'px solid'; + p.asldB.style.borderColor = THIS.controlBorderColor; + + // alpha slider mouse area + p.asldM.style.display = displayAlphaSlider ? 'block' : 'none'; + p.asldM.style.position = 'absolute'; + p.asldM.style.left = ( + (THIS.padding + THIS.width + 2 * THIS.controlBorderWidth + controlPadding) + + (displaySlider ? (THIS.sliderSize + 2 * controlPadding + 2 * THIS.controlBorderWidth) : 0) + ) + 'px'; + p.asldM.style.top = 0 + 'px'; + p.asldM.style.width = ( + (THIS.sliderSize + 2 * controlPadding + 2 * THIS.controlBorderWidth) + + Math.max(0, THIS.padding - controlPadding) // remaining padding to the right edge + ) + 'px'; + p.asldM.style.height = (2 * THIS.controlBorderWidth + 2 * THIS.padding + THIS.height) + 'px'; + p.asldM.style.cursor = 'default'; + jsc.setData(p.asldM, { + instance: THIS, + control: 'asld', + }) + + // alpha slider pointer inner and outer border + p.asldPtrIB.style.border = + p.asldPtrOB.style.border = + THIS.pointerBorderWidth + 'px solid ' + THIS.pointerBorderColor; + + // alpha slider pointer outer border + p.asldPtrOB.style.position = 'absolute'; + p.asldPtrOB.style.left = -(2 * THIS.pointerBorderWidth + THIS.pointerThickness) + 'px'; + p.asldPtrOB.style.top = '0'; + + // alpha slider pointer middle border + p.asldPtrMB.style.border = THIS.pointerThickness + 'px solid ' + THIS.pointerColor; + + // alpha slider pointer spacer + p.asldPtrS.style.width = THIS.sliderSize + 'px'; + p.asldPtrS.style.height = jsc.pub.sliderInnerSpace + 'px'; + + + // palette + p.pal.className = 'jscolor-palette'; + p.pal.style.display = pickerDims.palette.rows ? 'block' : 'none'; + p.pal.style.position = 'absolute'; + p.pal.style.left = THIS.padding + 'px'; + p.pal.style.top = (2 * THIS.controlBorderWidth + 2 * THIS.padding + THIS.height) + 'px'; + + // palette's color samples + + p.pal.innerHTML = ''; + + var chessboard = jsc.genColorPreviewCanvas('rgba(0,0,0,0)'); + + var si = 0; // color sample's index + for (var r = 0; r < pickerDims.palette.rows; r++) { + for (var c = 0; c < pickerDims.palette.cols && si < THIS._palette.length; c++, si++) { + var sampleColor = THIS._palette[si]; + var sampleCssColor = jsc.rgbaColor.apply(null, sampleColor.rgba); + + var sc = jsc.createEl('div'); // color sample's color + sc.style.width = (pickerDims.palette.cellW - 2 * THIS.controlBorderWidth) + 'px'; + sc.style.height = (pickerDims.palette.cellH - 2 * THIS.controlBorderWidth) + 'px'; + sc.style.backgroundColor = sampleCssColor; + + var sw = jsc.createEl('div'); // color sample's wrap + sw.className = 'jscolor-palette-sample'; + sw.style.display = 'block'; + sw.style.position = 'absolute'; + sw.style.left = ( + pickerDims.palette.cols <= 1 ? 0 : + Math.round(10 * (c * ((pickerDims.contentW - pickerDims.palette.cellW) / (pickerDims.palette.cols - 1)))) / 10 + ) + 'px'; + sw.style.top = (r * (pickerDims.palette.cellH + THIS.paletteSpacing)) + 'px'; + sw.style.border = THIS.controlBorderWidth + 'px solid'; + sw.style.borderColor = THIS.controlBorderColor; + sw.style.cursor = 'pointer'; + if (sampleColor.rgba[3] !== null && sampleColor.rgba[3] < 1.0) { // only create chessboard background if the sample has transparency + sw.style.backgroundImage = 'url(\'' + chessboard.canvas.toDataURL() + '\')'; + sw.style.backgroundRepeat = 'repeat'; + sw.style.backgroundPosition = 'center center'; + } + jsc.setData(sw, { + instance: THIS, + control: 'palette-sample', + color: sampleColor, + }) + sw.addEventListener('click', jsc.onPaletteSampleClick, false); + sw.appendChild(sc); + p.pal.appendChild(sw); + } } - // "close" button - function setBtnBorder() { - var insetColors = THIS.pickerInsetColor.split(/\s+/); - var pickerOutsetColor = insetColors.length < 2 ? insetColors[0] : insetColors[1] + ' ' + insetColors[0] + ' ' + insetColors[0] + ' ' + insetColors[1]; - p.btn.style.borderColor = pickerOutsetColor; + + // the Close button + function setBtnBorder () { + var insetColors = THIS.controlBorderColor.split(/\s+/); + var outsetColor = insetColors.length < 2 ? insetColors[0] : insetColors[1] + ' ' + insetColors[0] + ' ' + insetColors[0] + ' ' + insetColors[1]; + p.btn.style.borderColor = outsetColor; } - p.btn.style.display = THIS.pickerClosable ? 'block' : 'none'; + var btnPadding = 15; // px + p.btn.className = 'jscolor-btn-close'; + p.btn.style.display = THIS.closeButton ? 'block' : 'none'; p.btn.style.position = 'absolute'; - p.btn.style.left = THIS.pickerFace + 'px'; - p.btn.style.bottom = THIS.pickerFace + 'px'; - p.btn.style.padding = '0 15px'; - p.btn.style.height = '18px'; - p.btn.style.border = THIS.pickerInset + 'px solid'; + p.btn.style.left = THIS.padding + 'px'; + p.btn.style.bottom = THIS.padding + 'px'; + p.btn.style.padding = '0 ' + btnPadding + 'px'; + p.btn.style.maxWidth = (pickerDims.contentW - 2 * THIS.controlBorderWidth - 2 * btnPadding) + 'px'; + p.btn.style.overflow = 'hidden'; + p.btn.style.height = THIS.buttonHeight + 'px'; + p.btn.style.whiteSpace = 'nowrap'; + p.btn.style.border = THIS.controlBorderWidth + 'px solid'; setBtnBorder(); - p.btn.style.color = THIS.pickerButtonColor; + p.btn.style.color = THIS.buttonColor; p.btn.style.font = '12px sans-serif'; p.btn.style.textAlign = 'center'; - try { - p.btn.style.cursor = 'pointer'; - } catch(eOldIE) { - p.btn.style.cursor = 'hand'; - } + p.btn.style.cursor = 'pointer'; p.btn.onmousedown = function () { - THIS.hidePicker(); + THIS.hide(); }; - p.btnS.style.lineHeight = p.btn.style.height; + p.btnT.style.lineHeight = THIS.buttonHeight + 'px'; + p.btnT.innerHTML = ''; + p.btnT.appendChild(window.document.createTextNode(THIS.closeText)); - // load images in optimal order - switch(modeID) { - case 0: var padImg = 'hs.png'; break; - case 1: var padImg = 'hv.png'; break; - } - p.padM.style.backgroundImage = "url('"+jscolor.getDir()+"cross.gif')"; - p.padM.style.backgroundRepeat = "no-repeat"; - p.sldM.style.backgroundImage = "url('"+jscolor.getDir()+"arrow.gif')"; - p.sldM.style.backgroundRepeat = "no-repeat"; - p.pad.style.backgroundImage = "url('"+jscolor.getDir()+padImg+"')"; - p.pad.style.backgroundRepeat = "no-repeat"; - p.pad.style.backgroundPosition = "0 0"; - - // place pointers + // reposition the pointers redrawPad(); redrawSld(); + redrawASld(); - jscolor.picker.owner = THIS; - document.getElementsByTagName('body')[0].appendChild(p.boxB); - } - - - function getPickerDims(o) { - var dims = [ - 2*o.pickerInset + 2*o.pickerFace + jscolor.images.pad[0] + - (o.slider ? 2*o.pickerInset + 2*jscolor.images.arrow[0] + jscolor.images.sld[0] : 0), - o.pickerClosable ? - 4*o.pickerInset + 3*o.pickerFace + jscolor.images.pad[1] + o.pickerButtonHeight : - 2*o.pickerInset + 2*o.pickerFace + jscolor.images.pad[1] - ]; - return dims; - } - - - function redrawPad() { - // redraw the pad pointer - switch(modeID) { - case 0: var yComponent = 1; break; - case 1: var yComponent = 2; break; + // If we are changing the owner without first closing the picker, + // make sure to first deal with the old owner + if (jsc.picker.owner && jsc.picker.owner !== THIS) { + jsc.removeClass(jsc.picker.owner.targetElement, jsc.pub.activeClassName); } - var x = Math.round((THIS.hsv[0]/6) * (jscolor.images.pad[0]-1)); - var y = Math.round((1-THIS.hsv[yComponent]) * (jscolor.images.pad[1]-1)); - jscolor.picker.padM.style.backgroundPosition = - (THIS.pickerFace+THIS.pickerInset+x - Math.floor(jscolor.images.cross[0]/2)) + 'px ' + - (THIS.pickerFace+THIS.pickerInset+y - Math.floor(jscolor.images.cross[1]/2)) + 'px'; - // redraw the slider image - var seg = jscolor.picker.sld.childNodes; + // Set a new picker owner + jsc.picker.owner = THIS; - switch(modeID) { - case 0: - var rgb = HSV_RGB(THIS.hsv[0], THIS.hsv[1], 1); - for(var i=0; i let's trigger the change event again, even though it was natively dispatched + jsc.triggerInputEvent(THIS.valueElement, 'change', true, true); + } + } + + + function onAlphaChange (ev) { + if (jsc.getData(ev, 'internal')) { + return; // skip if the event was internally triggered by jscolor + } + + var oldVal = THIS.alphaElement.value; + + THIS.processAlphaInput(THIS.alphaElement.value); // this might change the value + + jsc.triggerCallback(THIS, 'onChange'); + + // triggering valueElement's onChange (because changing alpha changes the entire color, e.g. with rgba format) + jsc.triggerInputEvent(THIS.valueElement, 'change', true, true); + + if (THIS.alphaElement.value !== oldVal) { + // value was additionally changed -> let's trigger the change event again, even though it was natively dispatched + jsc.triggerInputEvent(THIS.alphaElement, 'change', true, true); + } + } + + + function onValueInput (ev) { + if (jsc.getData(ev, 'internal')) { + return; // skip if the event was internally triggered by jscolor + } + + if (THIS.valueElement) { + THIS.fromString(THIS.valueElement.value, jsc.flags.leaveValue); + } + + jsc.triggerCallback(THIS, 'onInput'); + + // triggering valueElement's onInput + // (not needed, it was dispatched normally by the browser) + } + + + function onAlphaInput (ev) { + if (jsc.getData(ev, 'internal')) { + return; // skip if the event was internally triggered by jscolor + } + + if (THIS.alphaElement) { + THIS.fromHSVA(null, null, null, parseFloat(THIS.alphaElement.value), jsc.flags.leaveAlpha); + } + + jsc.triggerCallback(THIS, 'onInput'); + + // triggering valueElement's onInput (because changing alpha changes the entire color, e.g. with rgba format) + jsc.triggerInputEvent(THIS.valueElement, 'input', true, true); + } + + + // let's process the DEPRECATED 'options' property (this will be later removed) + if (jsc.pub.options) { + // let's set custom default options, if specified + for (var opt in jsc.pub.options) { + if (jsc.pub.options.hasOwnProperty(opt)) { + try { + setOption(opt, jsc.pub.options[opt]); + } catch (e) { + console.warn(e); + } + } + } + } + + + // let's apply configuration presets + // + var presetsArr = []; + + if (opts.preset) { + if (typeof opts.preset === 'string') { + presetsArr = opts.preset.split(/\s+/); + } else if (Array.isArray(opts.preset)) { + presetsArr = opts.preset.slice(); // slice() to clone + } else { + console.warn('Unrecognized preset value'); + } + } + + // always use the 'default' preset. If it's not listed, append it to the end. + if (presetsArr.indexOf('default') === -1) { + presetsArr.push('default'); + } + + // let's apply the presets in reverse order, so that should there be any overlapping options, + // the formerly listed preset will override the latter + for (var i = presetsArr.length - 1; i >= 0; i -= 1) { + var pres = presetsArr[i]; + if (!pres) { + continue; // preset is empty string + } + if (!jsc.pub.presets.hasOwnProperty(pres)) { + console.warn('Unknown preset: %s', pres); + continue; + } + for (var opt in jsc.pub.presets[pres]) { + if (jsc.pub.presets[pres].hasOwnProperty(opt)) { + try { + setOption(opt, jsc.pub.presets[pres][opt]); + } catch (e) { + console.warn(e); + } + } + } + } + + + // let's set specific options for this color picker + var nonProperties = [ + // these options won't be set as instance properties + 'preset', + ]; + for (var opt in opts) { + if (opts.hasOwnProperty(opt)) { + if (nonProperties.indexOf(opt) === -1) { + try { + setOption(opt, opts[opt]); + } catch (e) { + console.warn(e); + } + } + } + } + + + // + // Install the color picker on chosen element(s) + // + + + // Determine picker's container element + if (this.container === undefined) { + this.container = window.document.body; // default container is BODY element + + } else { // explicitly set to custom element + this.container = jsc.node(this.container); + } + + if (!this.container) { + throw new Error('Cannot instantiate color picker without a container element'); + } + + + // Fetch the target element + this.targetElement = jsc.node(targetElement); + + if (!this.targetElement) { + // temporarily customized error message to help with migrating from versions prior to 2.2 + if (typeof targetElement === 'string' && /^[a-zA-Z][\w:.-]*$/.test(targetElement)) { + // targetElement looks like valid ID + var possiblyId = targetElement; + throw new Error('If \'' + possiblyId + '\' is supposed to be an ID, please use \'#' + possiblyId + '\' or any valid CSS selector.'); + } + + throw new Error('Cannot instantiate color picker without a target element'); + } + + if (this.targetElement.jscolor && this.targetElement.jscolor instanceof jsc.pub) { + throw new Error('Color picker already installed on this element'); + } + + + // link this instance with the target element + this.targetElement.jscolor = this; + jsc.addClass(this.targetElement, jsc.pub.className); + + // register this instance + jsc.instances.push(this); + + + // if target is BUTTON + if (jsc.isButton(this.targetElement)) { + + if (this.targetElement.type.toLowerCase() !== 'button') { + // on buttons, always force type to be 'button', e.g. in situations the target