1. Spotlight: Advancing IT Leadership
  2. Videos
  3. Newsletters
  4. Resources

About

  • About Us
  • Advertise
  • Contact Us
  • Foundry Careers
  • Newsletters
  • Contribute to InfoWorld
  • Reprints

Policies

  • Terms of Service
  • Privacy Policy
  • Cookie Policy
  • Copyright Notice
  • Member Preferences
  • About AdChoices
  • E-commerce Affiliate Relationships
  • Your California Privacy Rights

Our Network

  • CIO
  • Computerworld
  • CSO
  • Network World

More

  • News
  • Features
  • Blogs
  • BrandPosts
  • Events
  • Videos
  • Enterprise Buyer’s Guides
  • Analytics
  • Artificial Intelligence
  • Generative AI
  • Careers
  • Cloud Computing
  • Data Management
  • Databases
  • Emerging Technology
  • Technology Industry
  • Security
  • Software Development
  • Microsoft .NET
  • Development Tools
  • Devops
  • Open Source
  • Programming Languages
  • Java
  • JavaScript
  • Python
  • IT Leadership
  • Enterprise Buyer’s Guides
Popular Topics
  • Artificial Intelligence
  • Cloud Computing
  • Data Management
  • Software Development
  • Spotlight: Advancing IT Leadership
  • Videos
  • Newsletters
  • Resources

Topics

  • Analytics
  • Artificial Intelligence
  • Generative AI
  • Careers
  • Cloud Computing
  • Data Management
  • Databases
  • Emerging Technology
  • Technology Industry
  • Security
  • Software Development
  • Microsoft .NET
  • Development Tools
  • Devops
  • Open Source
  • Programming Languages
  • Java
  • JavaScript
  • Python
  • IT Leadership
  • Enterprise Buyer’s Guides

About

  • About Us
  • Advertise
  • Contact Us
  • Foundry Careers
  • Newsletters
  • Contribute to InfoWorld
  • Reprints

Policies

  • Terms of Service
  • Privacy Policy
  • Cookie Policy
  • Copyright Notice
  • Member Preferences
  • About AdChoices
  • E-commerce Affiliate Relationships
  • Your California Privacy Rights

Our Network

  • CIO
  • Computerworld
  • CSO
  • Network World

More

  • News
  • Features
  • Blogs
  • BrandPosts
  • Events
  • Videos
  • Enterprise Buyer’s Guides
    1. Home
    2. Software Development
    3. Strategy for success
    by David Geary

    Strategy for success

    how-to
    Apr 26, 200215 mins
    Design PatternsJakarta EEJava

    The powerful Strategy design pattern aids object-oriented design

    See More

    Back in 1984, I graduated from college with a mechanical engineering degree and went to work as a software engineer. After teaching myself C programming, by 1985 I was busily developing a 50,000-line graphical user interface (GUI) for Unix. That was fun.

    By the end of 1985, my program complete, I was ready to move to other projects—or so I thought. I soon received a slew of bug reports and enhancement requests, so I started wading through my 50,000 lines to make fixes. That was hard.

    I had created a veritable house of cards that came tumbling down almost daily. And that house of cards fell easily; even the most innocuous changes often left me debugging for hours just to restore the program’s stability.

    I thought I had stumbled upon an important software development tenet: have fun during development, then look for a new job after deployment. In fact, however, my difficulties stemmed from my ignorance of the most fundamental tenet of object-oriented (OO) software development: encapsulation. My program was a huge switch-statement collection that invoked different functions under different circumstances—resulting in tightly coupled and difficult-to-change software.

    In this Java Design Patterns installment, I discuss perhaps the most fundamental design pattern: Strategy. If I had known about the Strategy pattern in 1984, I would have avoided a great deal of work.

    The Strategy pattern

    In Chapter 1 of the Gang of Four’s (GOF) Design Patterns, the authors discuss several OO design principles comprising the core of many patterns. The Strategy pattern embodies two such principles—encapsulate the concept that varies and program to an interface, not an implementation. The Design Patterns authors define the Strategy pattern as:

    Define a family of algorithms, encapsulate each one, and make them interchangeable. [The] Strategy [pattern] lets the algorithm vary independently from clients that use it.

    The Strategy pattern lets you build software as a loosely coupled collection of interchangeable parts, in contrast to a monolithic, tightly coupled system. That loose coupling makes your software much more extensible, maintainable, and reusable.

    To teach the Strategy pattern, I first illustrate how Swing uses the Strategy pattern to draw borders around its components. Then I discuss how Swing benefits by using the Strategy pattern, and finally I explain how you can implement the Strategy pattern in your own software.

    Swing borders

    You can draw borders around almost all Swing components, including panels, buttons, lists, and so on. Swing provides numerous border types for its components: bevel, etched, line, titled, and even compound. Borders for Swing components are drawn by the JComponent class, which acts as the base class for all Swing components by implementing functionality common to all Swing components.

    JComponent implements paintBorder(), a method for painting borders around components. Swing’s creators could have implemented paintBorder() like the method in Example 1:

    Example 1. The wrong way to paint Swing borders

    // A hypothetical JComponent.paintBorder method
    protected void paintBorder(Graphics g) {
       switch(getBorderType()) {
          case LINE_BORDER:   paintLineBorder(g);
                              break;
          case ETCHED_BORDER: paintEtchedBorder(g);
                              break;
          case TITLED_BORDER: paintTitledBorder(g);
                              break;
          ...
       }
    }
    

    Example 1’s hypothetical JComponent.paintBorder() method hard codes border painting in JComponent, which tightly couples that functionality and the JComponent class.

    You can see the consequences if you tried to implement a new border type—you’d have to modify JComponent in at least three places: First, you would have to add a new integer value corresponding to your new border type. Second, you would have to add a case to the switch statement. And third, you would have to implement a paintXXXBorder() method, where XXX designates the border type.

    Obviously, you won’t have much success extending the preceding paintBorder() implementation. Not only would you find it difficult to extend paintBorder() with a new border type, but the JComponent class is not yours to modify in the first place—it’s part of the Swing toolkit, meaning you would have to recompile the class and rebuild the entire toolkit. You would also have to require your users to use your renegade Swing version instead of the standard version, and you’d have work to do with the next Swing release. Also, because you’ve added new border-painting functionality to the JComponent class, every Swing component can now access that functionality whether you like it or not—you cannot restrict your new border to a particular component type.

    Finally, Swing components would not be extensible if the JComponent class implemented its functionality with switch statements, as in Example 1.

    What is the OO alternative? Decouple, using the Strategy pattern, JComponent from the code that paints borders, so you can vary the border painting algorithm without modifying the JComponent class. By employing the Strategy pattern, you encapsulate the concept that varies, in this case painting a border, and program to an interface, not an implementation by providing a Border interface. Let’s see how the JComponent uses the Strategy pattern to paint borders. Example 2 lists the JComponent.paintBorder() method:

    Example 2. The right way to paint Swing borders

    // The actual implementation of the JComponent.paintBorder() method
    protected void paintBorder(Graphics g) {
       Border border = getBorder();
       if (border != null) {
          border.paintBorder(this, g, 0, 0, getWidth(), getHeight());
       }
    }
    

    The preceding paintBorder() method paints a component’s border with a border object. Under this scheme, the border object, not the JComponent class, encapsulates the border painting algorithm.

    Notice that JComponent passes a reference to itself (the this argument) to Border.paintBorder() in case a border must retrieve information about its component, a technique known as delegation. With delegation, one object delegates functionality to another object, passing a reference to itself (see “Take Control with the Proxy Design Pattern” (JavaWorld, February 2002)).

    The JComponent class references a border, which is returned from the JComponent.getBorder() method, shown in Example 3 with its corresponding setter method:

    Example 3. Setter and getter methods for a Swing component’s border

    ...
    private Border border;
    ...
    public void setBorder(Border border) {
       Border oldBorder = this.border;
       this.border = border;
       firePropertyChange("border", oldBorder, border);
       if (border != oldBorder) {
          if (border == null || oldBorder == null || !(border.getBorderInsets(this).
                                        equals(oldBorder.getBorderInsets(this)))) {
             revalidate();
          }       
          repaint();
       }
    }
    ...
    public Border getBorder() {
       return border;
    }
    

    When you set a component’s border with JComponent.setBorder(), the JComponent class fires a property change event, and if the new border differs sufficiently from the old border, the component repaints. The getBorder() method simply returns the Border reference.

    Figure 1’s class diagram illustrates the relationship between borders and the JComponent class.

    The JComponent class maintains a private reference to a Border object. Notice that because Border is an interface, not a class, the Swing components can have any border that implements the Border interface. (That’s what it means to program to an interface, not an implementation.)

    Now that you’ve seen how JComponent implements the Strategy pattern to paint component borders, let’s test the implementation’s extensibility by creating a new border type.

    Create a new border type

    Figure 2 shows a Swing application with three panels. I fitted each panel with a custom border, each a HandleBorder instance. Drawing programs frequently use handle borders to move and resize objects.

    Example 4 lists the HandleBorder class:

    Example 4. The HandleBorder class

    import java.awt.*;
    import javax.swing.*;
    import javax.swing.border.*;
    public class HandleBorder extends AbstractBorder {
       protected Color lineColor;
       protected int thick;
       public HandleBorder() {
          this(Color.black, 6);
       }
       public HandleBorder(Color lineColor, int thick) {
          this.lineColor = lineColor;
          this.thick = thick;
       }
       public void paintBorder(Component component, 
                                      Graphics g, int x, int y, int w, int h) {
          Graphics copy = g.create();
          if(copy != null) {
             try {
                copy.translate(x,y);
                paintRectangle(component,copy,w,h);
                paintHandles(component,copy,w,h);
             }
             finally {
                copy.dispose();
             }
          }
       }
       public Insets getBorderInsets() {
          return new Insets(thick,thick,thick,thick);
       }
       protected void paintRectangle(Component c, Graphics g,
                               int w, int h) {
          g.setColor(lineColor);
          g.drawRect(thick/2,thick/2,w-thick-1,h-thick-1);
       }
       protected void paintHandles(Component c, Graphics g,
                               int w, int h) {
          g.setColor(lineColor);
          g.fillRect(0,0,thick,thick); // upper left
          g.fillRect(w-thick,0,thick,thick); // upper right
          g.fillRect(0,h-thick,thick,thick); // lower left
          g.fillRect(w-thick,h-thick,thick,thick); // lower right
          g.fillRect(w/2-thick/2,0,thick,thick); // mid top
          g.fillRect(0,h/2-thick/2,thick,thick); // mid left
          g.fillRect(w/2-thick/2,h-thick,thick,thick); // mid bottom
          g.fillRect(w-thick,h/2-thick/2,thick,thick); // mid right
       }   
    }
    

    The HandleBorder class extends javax.swing.border.AbstractBorder and overrides paintBorder() and getBorderInsets(). While HandleBorder‘s implementation isn’t important, it is important that we can easily create new borders types because Swing uses the Strategy pattern to draw component borders.

    Example 5 lists the Swing application shown in Figure 2:

    Example 5. Use handle borders

    import javax.swing.*;
    import javax.swing.border.*;
    import java.awt.*;
    import java.awt.event.*;
    public class Test extends JFrame {
       public static void main(String[] args) {
          JFrame frame = new Test();
          frame.setBounds(100, 100, 500, 200);
          frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
          frame.show();
       }
       public Test() {
          super("Creating a New Border Type");
          Container contentPane = getContentPane();
          JPanel[] panels = { new JPanel(), 
                         new JPanel(), new JPanel() };
          Border[] borders = { new HandleBorder(),
                         new HandleBorder(Color.red, 8),
                         new HandleBorder(Color.blue, 10) };
          contentPane.setLayout(
                   new FlowLayout(FlowLayout.CENTER,20,20));
          for(int i=0; i < panels.length; ++i) {
             panels[i].setPreferredSize(new Dimension(100,100));
             panels[i].setBorder(borders[i]);
             contentPane.add(panels[i]);
          }
       }
    }
    

    The preceding application creates three panels (instances of javax.swing.JPanel) and three borders (instances of HandleBorder). Notice how you can easily specify borders for those panels by calling JComponent.setBorder().

    Recall from Example 2 that a reference to a component passed to the component’s border when JComponent calls Border.paintBorder()—a form of delegation. As I mentioned earlier, developers frequently use delegation with the Strategy pattern. The HandleBorder class does not use that component reference, but some borders use that reference to obtain information from their component. For example, Example 6 lists the paintBorder() method for such a border, the javax.swing.border.EtchedBorder:

    Example 6. Some Swing borders retrieve information from their components

    // The following listing is from
    // javax.swing.border.EtchedBorder
    public void paintBorder(Component component, Graphics g, int x, int y, 
                             int width, int height) {
       int w = width;
       int h = height;
       
       g.translate(x, y);
       
       g.setColor(etchType == LOWERED? getShadowColor(component) : getHighlightColor(component));
       g.drawRect(0, 0, w-2, h-2);
       
       g.setColor(etchType == LOWERED? getHighlightColor(component) : getShadowColor(component));
       g.drawLine(1, h-3, 1, 1);
       g.drawLine(1, 1, w-3, 1);
       
       g.drawLine(0, h-1, w-1, h-1);
       g.drawLine(w-1, h-1, w-1, 0);
       
       g.translate(-x, -y);
    }
    

    The javax.swing.border.EtchedBorder.paintBorder() method uses its component reference to find its component’s shadow and highlight colors.

    Implement the Strategy pattern

    The Strategy pattern, as one of the simpler design patterns, proves easy to implement in your own software:

    1. Implement a Strategy interface for your strategy objects
    2. Implement ConcreteStrategy classes that implement the Strategy interface, as appropriate
    3. In your Context class, maintain a private reference to a Strategy object.
    4. In your Context class, implement public setter and getter methods for the Strategy object

    The Strategy interface defines your Strategy objects’ behavior; for example, the Strategy interface for Swing borders is the javax.swing.Border interface.

    The concrete ConcreteStrategy classes implement the Strategy interface; for example, for Swing borders, the LineBorder and EtchedBorder classes are ConcreteStrategy classes.

    The Context class uses Strategy objects; for example, for Swing borders, the JComponent class is a Context class.

    You may also examine your existing classes to see if they have tightly coupled functionality that’s a candidate for Strategy objects. Typically, such candidates include switch statements similar to the one I discussed at the beginning of this article.

    Homework

    Some Swing components have more sophisticated rendering and editing requirements than others. Discuss how Swing uses the Strategy pattern in its list class (javax.swing.JList) to render list cells.

    Homework from last time

    Your last assignment asked you to reimplement the TableBubbleSortDecorator I first discussed in “Decorate Your Java Code” (JavaWorld, December 2001) with the JDK’s built-in Proxy pattern support.

    As a convenience, I created an abstract Decorator class that implements the java.lang.reflect.InvocationHandler interface. The Decorator class also references the decorated object (or in Proxy pattern parlance, the real subject). Example 1H lists the Decorator class:

    Example 1H. An abstract Decorator class

    import java.lang.reflect.InvocationHandler;
    public abstract class Decorator implements InvocationHandler {
       // The InvocationHandler interface defines one method:
       // invoke(Object proxy, Method method, Object[] args). That
       // method must be implemented by concrete (meaning not 
       // abstract) extensions of this class.
       private Object decorated;
       protected Decorator(Object decorated) {
          this.decorated = decorated;
       }
       protected synchronized Object getDecorated() {
          return decorated;
       }
       protected synchronized void setDecorated(Object decorated) {
          this.decorated = decorated;
       }
    }
    

    Although the Decorator class claims to implement the InvocationHandler interface, it does not implement the only method defined by that interface: invoke(Object proxy, Method method, Object[] methodArguments). Because of that omission, the Decorator class is abstract, and Decorator extensions must implement the invoke() method if they wish to be concrete.

    The Decorator class acts as a base class for all decorators. Example 2H lists a Decorator extension specific to table sort decorators. Notice that TableSortDecorator does not implement the invoke() method, and therefore is also an abstract class:

    Example 2H. TableSortDecorator, revised

    import javax.swing.table.TableModel;
    import javax.swing.event.TableModelListener;
    public abstract class TableSortDecorator 
                                     extends Decorator 
                                     implements TableModelListener {
       // Concrete extensions of this class must implement 
       // tableChanged from TableModelListener
       abstract public void sort(int column);
       public TableSortDecorator(TableModel realModel) {
          super(realModel);
       }
    }
    

    Now you can write a TableBubbleSortDecorator that uses the JDK’s built-in Proxy pattern support:

    Example 3H. TableBubbleSortDecorator, revised

    import java.lang.reflect.Method;
    import javax.swing.table.TableModel;
    import javax.swing.event.TableModelEvent;
    public class TableBubbleSortDecorator extends TableSortDecorator {
       private int indexes[];
       private static String GET_VALUE_AT = "getValueAt";
       private static String SET_VALUE_AT = "setValueAt";
       public TableBubbleSortDecorator(TableModel model) {
          super(model);
          allocate();
       }
       // tableChanged is defined in TableModelListener, which
       // is implemented by TableSortDecorator.
       public void tableChanged(TableModelEvent e) {
          allocate();   
       }
       // invoke() is defined by the java.lang.reflect.InvocationHandler
       // interface; that interface is implemented by the 
       // (abstract) Decorator class. Decorator is the superclass
       // of TableSortDecorator.
       public Object invoke(Object proxy, Method method, 
                                             Object[] args) {
          Object result = null;
          TableModel model = (TableModel)getDecorated();
          if(GET_VALUE_AT.equals(method.getName())) {
             Integer row = (Integer)args[0], 
                     col = (Integer)args[1];
             result = model.getValueAt(indexes[row.intValue()], 
                                               col.intValue());
          }
          else if(SET_VALUE_AT.equals(method.getName())) {
             Integer row = (Integer)args[1],
                     col = (Integer)args[2];
             model.setValueAt(args[0], indexes[row.intValue()],
                                       col.intValue());
          }
          else {
             try {
                result = method.invoke(model, args);
             }
             catch(Exception ex) {
                ex.printStackTrace(System.err);
             }
          }
          return result;
       }
       // The following methods perform the bubble sort ...
       public void sort(int column) {
          TableModel model = (TableModel)getDecorated();
          int rowCount = model.getRowCount();
          for(int i=0; i < rowCount; i++) {
             for(int j = i+1; j < rowCount; j++) {
                if(compare(indexes[i], indexes[j], column) < 0) {
                   swap(i,j);
                }
             }
          }
       }
       private void swap(int i, int j) {
          int tmp = indexes[i];
          indexes[i] = indexes[j];
          indexes[j] = tmp;
       }
       private int compare(int i, int j, int column) {
          TableModel realModel = (TableModel)getDecorated();
          Object io = realModel.getValueAt(i,column);
          Object jo = realModel.getValueAt(j,column);
          int c = jo.toString().compareTo(io.toString());
          return (c < 0) ? -1 : ((c > 0) ? 1 : 0);
       }
       private void allocate() {
          indexes = new int[((TableModel)getDecorated()).
                              getRowCount()];
          for(int i=0; i < indexes.length; ++i) {
             indexes[i] = i;         
          }
       }
    }
    

    With the JDK’s built-in Proxy pattern support and a well-designed base class, you can easily implement decorators by extending Decorator and implementing invoke().

    Email

    In an email to me, Ken Ballard wrote:

    A toolbar shows certain buttons depending on what node I select in a tree. I created a toolbar decorator that takes a toolbar (JToolBar) in its constructor. The decorator has a showButtonForNode() method that changes the toolbar’s buttons depending upon the node. I invoke the showButtonForNode() method in the valueChanged() method of a tree selection listener.

    Is this a good use of the Decorator pattern?

    Numerous design patterns let you extend functionality; for example, in Java Design Patterns you’ve seen how to extend functionality with the Proxy, Decorator, and Strategy patterns. You can have difficulty knowing which pattern to use in a specific situation because groups of patterns achieve the same goal (for example, Proxy, Decorator, and Strategy all extend functionality). Closely related patterns’ subtle differences determine which represents the best choice for a specific situation. Sometimes, more than one design pattern can be appropriate.

    The Decorator pattern’s major selling point: it can combine multiple behaviors at runtime; for example, in the “Homework from Last Time” section from “Take Control with the Proxy Design Pattern,” I showed how to combine sorting and filtering for a Swing table:

    TableSortDecorator sortDecorator = new TableBubbleSortDecorator(table.getModel());
    TableFilterDecorator filterDecorator = new TableHighPriceFilter(sortDecorator);
    table.setModel(filterDecorator);
    

    In the preceding code, a filter decorator decorates a sort decorator, which in turn decorates a table’s model; as a result, the table model in question sorts and filters its data.

    Ken would not likely combine switching toolbar buttons with other behavior, as is the case for sorting and filtering, so the Decorator pattern may prove overkill. In this case, the Proxy pattern seems more appropriate, as it also extends functionality by fixing the relationship between the proxy and the real subject at compile time, but does not compose behaviors at runtime.

    David Geary is the author of Advanced JavaServer Pages (Prentice Hall, 2001; ISBN: 0130307041) and the Graphic Java series (Sun Microsystems Press). David has been developing object-oriented software with numerous object-oriented languages for 18 years. Since the GOF Design Patterns book was published in 1994, David has been an active proponent of design patterns, and has used and implemented design patterns in Smalltalk, C++, and Java. In 1997, David began working full-time as an author and occasional speaker and consultant. David is a member of the expert groups defining the JSP standard custom tag library and JavaServer Faces, and is a contributor to the Apache Struts JSP framework.

    Related content

    news

    Java turns 30, and there’s no stopping it now

    By Paul Krill
    May 23, 2025 4 mins
    Java Python Rust
    how-to

    How to use method references in Java

    By Rafael del Nero
    May 22, 2025 17 mins
    Java Programming Languages Software Development
    news

    JDK 25: The new features in Java 25

    By Paul Krill
    May 19, 2025 10 mins
    Java Programming Languages Software Development
    feature

    The best Java certifications for software developers

    By Bob Violino
    May 19, 2025 10 mins
    Certifications Developer Java

    Other Sections

    • Resources
    • Videos
    • Spotlight: Advancing IT Leadership

    Show me more

    news

    Salesforce to buy Informatica in $8 billion deal

    By Evan Schuman
    May 27, 20251 min
    Data ManagementMaster Data Management
    Image
    news

    AWS adds observability support to Aurora PostgreSQL Limitless

    By Anirban Ghoshal
    May 27, 20253 mins
    Amazon Web ServicesDatabases
    Image
    feature

    Lessons from building retrieval systems for AI assistants

    By Shaurya Pednekar
    May 27, 202510 mins
    Artificial IntelligenceGenerative AISoftware Development
    Image
    video

    How to use the new Python Installation Manager tool for Python 3.14

    May 27, 20254 mins
    Python
    Image
    video

    How to use Marimo | A better Jupyter-like notebook system for Python

    May 13, 20254 mins
    Python
    Image
    video

    How to prettify command line output in Python with Rich

    May 7, 20254 mins
    Python
    Image

    Sponsored Links

    • Empower your cybersecurity team with expert insights from Palo Alto Networks.
    • Secure AI by Design: Unleash the power of AI and keep applications, usage and data secure.
    About
    • About Us
    • Advertise
    • Contact Us
    • Foundry Careers
    • Reprints
    • Newsletters
    • BrandPosts
    Policies
    • Terms of Service
    • Privacy Policy
    • Cookie Policy
    • Copyright Notice
    • Member Preferences
    • About AdChoices
    • E-commerce Affiliate Relationships
    • Your California Privacy Rights
    • Privacy Settings
    Our Network
    • CIO
    • Computerworld
    • CSO
    • Network World
    • Facebook
    • X
    • YouTube
    • Google News
    • LinkedIn
    © 2025 IDG Communications, Inc. All Rights Reserved.
`, cio: `

🚀 The new CIO.com hybrid search: 🔍 Explore CIO content smarter, faster and AI powered. ✨

`, nww: `

🚀 The new NetworkWorld.com hybrid search: 🔍 Explore NetworkWorld content smarter, faster and AI powered. ✨

`, cw: `

🚀 The new Computerworld.com hybrid search: 🔍 Explore Computerworld content smarter, faster and AI powered. ✨

` }; const sharedStyles = ` `; const publisher = foundry_get_publisher(); const htmlContent = contentSwitch[publisher]; if (!htmlContent || !document.body) return; document.body.insertAdjacentHTML("afterbegin", htmlContent + sharedStyles); const bar = document.querySelector(".section-block--announcementbar"); if (bar) { requestAnimationFrame(() => { bar.classList.add("section-block--announcementbar--visible"); }); } const btn = document.querySelector(".section-block--announcementbar .reset-button"); const searchIcon = document.querySelector('.header__icon-button[data-menu-trigger="search"] svg'); const searchTrigger = document.querySelector('[data-menu-trigger="search"]'); if (searchIcon) { searchIcon.innerHTML = ''; } if (btn && searchTrigger) { btn.addEventListener("click", () => searchTrigger.click()); } console.log("[MISO SCRIPT] Conditions met, initializing Miso search announcements."); }; initMisoSearchAnnouncements(); }); document.addEventListener('consentManagerReady', () => { const hasConsentYouTube = consentManager.checkConsentByVendors([ 'YouTube', 'YT' ]); if (hasConsentYouTube.some(vendor => vendor['Has Consent'] === false)) { console.log('[YOUTUBE SCRIPT] Consent not given for YouTube.'); } else { console.log('[YOUTUBE SCRIPT] Consent given for YouTube. Loading script...'); } }); document.addEventListener('consentManagerReady', () => { const hasConsentGAM = consentManager.checkConsentByVendors([ 'Google Ad Manager', 'GAM' ]); if (hasConsentGAM.some(vendor => vendor['Has Consent'] === false)) { console.log('[GAM SCRIPT] Consent not given for GAM.'); } else { console.log('[GAM SCRIPT] Consent given for GAM. Loading script...'); } }); document.addEventListener('consentManagerReady', () => { const hasConsentGoogleFonts = consentManager.checkConsentByVendors([ 'Google Fonts', 'Google Web Fonts' ]); if (hasConsentGoogleFonts.some(vendor => vendor['Has Consent'] === false)) { console.log('[GOOGLE FONTS SCRIPT] Consent not given for Google Fonts.'); } else { console.log('[GOOGLE FONTS SCRIPT] Consent given for Google Fonts. Loading script...'); } }); document.addEventListener('consentManagerReady', () => { const hasConsentAdobeTypekit = consentManager.checkConsentByVendors([ 'Adobe Typekit' ]); if (hasConsentAdobeTypekit.every(vendor => vendor['Has Consent'] === true)) { if (foundry_is_edition('kr')) { const link = document.createElement('link'); link.rel = 'stylesheet'; link.href = 'https://use.typekit.net/ysx4dcu.css'; document.head.appendChild(link); } } }); document.addEventListener('consentManagerReady', () => { const vendors = ['Subscribers']; const hasConsentSubscribers = consentManager.checkConsentByVendors(vendors); if (hasConsentSubscribers.some(vendor => vendor['Has Consent'] === false)) { return; } else { if (foundry_is_language('en')) { console.log('Language is English'); // subscribers english .. } if (foundry_is_edition('kr')) { console.log('Edition is Korean'); // subscribers in korean .. } if (foundry_is_edition('ja')) { console.log('Edition is Japanese'); // subscribers in japanese .. } } });