Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Using a Notification Plugin

Hi,

I'm using Twine 2.1 with SugarCube 2.x, and I'm trying to use this Notification plugin. I try adding the minified js to the Story JavaScript, but I keep getting "Unexpected eval or arguments in strict mode."

I also want to make a custom macro to use it easily. Something like:
Without parameters, defaults are type ("info") and duration (3). The message is the macro's payload.
<<notify>>This is a notification message<</notify>>
Result:
$("body").overHang({
  type: "info",
  message : "This is a notification message",
  duration : 3
})

First parameter is for type. It is a string.
<<notify "warn">>Default warning<</notify>>
Result:
$("body").overHang({
  type : "warn",
  message : "Default warning",
  duration : 3
})

Second parameter is for duration. It is a number.
<<notify "error" 5>>Some error<</notify>>
Result:
$("body").overHang({
  type : "error",
  message : "Some error",
  duration : 5
})

The plugin page seems to allow $("#SELECTOR").overHang(...) so I'm wondering if it should be $("#tw-story") instead, but I'm rather uninformed about Twine DOM to be certain.

How do I actually plug this plugin into my story? Also, how should I define the notify macro to fulfill my use cases?

Comments

  • I'm using Twine 2.1 with SugarCube 2.x, and I'm trying to use this Notification plugin. I try adding the minified js to the Story JavaScript, but I keep getting "Unexpected eval or arguments in strict mode."
    That would be because the plugin author is doing very unwise things. They're overriding the arguments special function variable, which you should never do under any circumstances and is actually illegal to do within strict mode. SugarCube runs in strict mode, so the plugin's attempt to do so predictably throws an error.

    The plugin page seems to allow $("#SELECTOR").overHang(...) so I'm wondering if it should be $("#tw-story") instead, but I'm rather uninformed about Twine DOM to be certain.
    You're misspelling the method's name, it's .overhang()—lowercase h.

    There is no Twine DOM. Twine is only an IDE/compiler, full stop. Each story format defines its own markup, features, HTML, and CSS.

    SugarCube v2's HTML structure does not contain an element with the ID tw-story. Beyond that, the plugin should really be injecting its core element into the document's body element anyway.

    How do I actually plug this plugin into my story? Also, how should I define the notify macro to fulfill my use cases?
    Here is a fixed version of the plugin, along with the macro you wanted. Just copy/paste that into your Story JavaScript—I assume that's how you had attempted to install it originally. If you have not yet done so, you will also need to paste overhang.js' CSS—not included here—into your Story Stylesheet.

    NOTE: If you decide to tinker with the macro, unless you also install jQuery UI, do not change the easing method set within the macro to anything other than the listed options or overhang.js will crash.
    Macro.add('notify', {
    	tags    : null,
    	handler : function () {
    		$(document.body).overhang({
    			type     : this.args[0] || 'info',
    			duration : Number.parseInt(this.args[1]) || 3,
    			easing   : 'swing', // jQuery only includes: 'swing', 'linear'
    			message  : this.payload[0].contents
    		});
    	}
    });
    
    (function ($) {
    /**
     * overhang.js
     * Paul Krishnamurthy 2016
     * Fix by Thomas M. Edwards 2017
     */
    $.fn.overhang = function (options) {
    
      var $element = $(this);
      var $overhang = $("<div class='overhang'></div>");
    
      $(".overhang").remove();
    
      // Flat UI color themes
      var themes = {
        "success" : ["#2ECC71", "#27AE60"],
        "error"   : ["#E74C3C", "#C0392B"],
        "warn"    : ["#E67E22", "#D35400"],
        "info"    : ["#3498DB", "#2980B9"],
        "prompt"  : ["#9B59B6", "#8E44AD"],
        "confirm" : ["#1ABC9C", "#16A085"],
        "blank"   : ["#34495E", "#2C3E50"]
      };
    
      // Default attributes
      var defaults = {
        type         : "success",
        message      : "This is an overhang.js message!",
        textColor    : "#FFFFFF",
        yesMessage   : "Yes",
        noMessage    : "No",
        yesColor     : "#2ECC71",
        noColor      : "#E74C3C",
        duration     : 1.5,
        speed        : 500,
        closeConfirm : false,
        upper        : false,
        easing       : "easeOutBounce",
        html         : false,
        callback     : function () {}
      };
    
      var attributes = $.extend(defaults, options);
    
      // Raise the overhang alert
      function raise (runCallback, identifier) {
        $overhang.slideUp(attributes.speed, function () {
          if (runCallback) {
            attributes.callback(identifier !== null ? $element.data(identifier) : "");
          }
        });
      }
    
      // Handle invalid type name
      var validTypes = ["success", "error", "warn", "info", "prompt", "confirm"];
      if ($.inArray(attributes.type, validTypes) === -1) {
        attributes.type = "blank";
    
        // Notify the user
        console.log("You have entered invalid type name for an overhang message.");
      }
    
      // Set attribut primary and accent colors
      if (options.custom) {
        attributes.primary = options.primary;
        attributes.accent  = options.accent;
      } else {
        attributes.primary = themes[attributes.type][0] || "#ECF0F1";
        attributes.accent  = themes[attributes.type][1] || "#BDC3C7";
      }
    
      if (attributes.type === "prompt" || attributes.type === "confirm") {
        attributes.primary      = options.primary || themes[attributes.type][0];
        attributes.accent       = options.accent  || themes[attributes.type][1];
        attributes.closeConfirm = true;
      }
    
      // Style colors
      $overhang.css("background-color", attributes.primary);
      $overhang.css("border-bottom", "6px solid " + attributes.accent);
    
      // Message
      var $message = $("<span class='overhang-message'></span>");
      $message.css("color", attributes.textColor);
    
      // Assign html or text
      if (attributes.html) {
        $message.html(attributes.message);
      } else {
        $message.text(attributes.upper ? attributes.message.toUpperCase() : attributes.message);
      }
    
      $overhang.append($message);
    
      // Additional overhang elements
      var $inputField = $("<input class='overhang-prompt-field' />");
      var $yesButton = $("<button class='overhang-yes-option'>" + attributes.yesMessage + "</button>");
      var $noButton = $("<button class='overhang-no-option'>" + attributes.noMessage + "</button>");
    
      $yesButton.css("background-color", attributes.yesColor);
      $noButton.css("background-color", attributes.noColor);
    
      // Close button
      if (attributes.closeConfirm) {
        var $close = $("<span class='overhang-close'></span>");
        $close.css("color", attributes.accent);
    
        if (attributes.type !== "confirm") {
          $overhang.append($close);
        }
      }
    
      if (attributes.type === "prompt") {
        $overhang.append($inputField);
        $element.data("overhangPrompt", null);
    
        // Submit action
        $inputField.keydown(function (e) {
          if (e.keyCode == 13) {
    
            // Append the data to the DOM element
            $element.data("overhangPrompt", $inputField.val());
            raise(true, "overhangPrompt");
          }
        });
    
      } else if (attributes.type === "confirm") {
    
        $overhang.append($yesButton);
        $overhang.append($noButton);
    
        $overhang.append($close);
    
        $element.data("overhangConfirm", null);
    
        // Append selection to DOM element
        $yesButton.click(function () {
          $element.data("overhangConfirm", true);
          raise(true, "overhangConfirm");
        });
    
        $noButton.click(function () {
          $element.data("overhangConfirm", false);
          raise(true, "overhangConfirm");
        });
    
      }
    
      // Attack overhang to element
      $element.append($overhang);
    
      // Animate drop down and up
      if (attributes.closeConfirm) {
        $overhang.slideDown(attributes.speed, attributes.easing);
    
        $close.click(function () {
          if (attributes.type !== "prompt" && attributes.type !== "confirm") {
            raise(true, null);
          } else {
            raise(false, null);
          }
        });
      } else {
        $overhang
          .slideDown(attributes.speed, attributes.easing)
          .delay(attributes.duration * 1000)
          .slideUp(attributes.speed, function () {
            raise(true, null);
          });
      }
    };
    
    /* end overhang.js */
    })(jQuery);
    
  • About the DOM, I thought I knew that Twine has a certain DOM, but I guess I got mixed up slightly. So inject to body anyway, yeah? Will do.

    I have the CSS in my Story Stylesheet, so that's done.

    By easing method, I assume you meant this:
    easing   : 'swing', // jQuery only includes: 'swing', 'linear'
    
    What is it, anyway? So I should just not tinker with that one? I presume there are other options, but I have to include jQuery UI?
  • The easing function determines how the animation proceeds. jQuery only includes two, swing and linearswing ramps, while linear proceeds, well, linearly. jQuery UI defines others, though I probably wouldn't advise loading it simply to get them—unless you're really attached to one or something.
  • As an addition, if I want to have the payload contain variables, how should I change the macro? Something about using jQuery().wiki, perhaps?
  • Currently, overhang.js doesn't support chaining, which I'd rather not do this without, so a minor modification to it will be required in addition to the requisite changes to the macro. And yes, as far as the macro goes, jQuery().wiki() will be part of the solution.

    Here's an updated version of both which supports all SugarCube markup within the macro body:
    Macro.add('notify', {
    	tags    : null,
    	handler : function () {
    		$(document.body)
    			.overhang({
    				type     : this.args[0] || 'info',
    				duration : Number.parseInt(this.args[1]) || 3,
    				easing   : 'swing', // jQuery only includes: 'swing', 'linear'
    				message  : '' // Leave this empty
    			})
    			.find('.overhang .overhang-message')
    				.empty()
    				.wiki(this.payload[0].contents);
    	}
    });
    
    (function ($) {
    /**
     * overhang.js
     * Paul Krishnamurthy 2016
     * Fixes & additions by Thomas M. Edwards 2017
     */
    $.fn.overhang = function (options) {
    
      var $element = $(this);
      var $overhang = $("<div class='overhang'></div>");
    
      $(".overhang").remove();
    
      // Flat UI color themes
      var themes = {
        "success" : ["#2ECC71", "#27AE60"],
        "error"   : ["#E74C3C", "#C0392B"],
        "warn"    : ["#E67E22", "#D35400"],
        "info"    : ["#3498DB", "#2980B9"],
        "prompt"  : ["#9B59B6", "#8E44AD"],
        "confirm" : ["#1ABC9C", "#16A085"],
        "blank"   : ["#34495E", "#2C3E50"]
      };
    
      // Default attributes
      var defaults = {
        type         : "success",
        message      : "This is an overhang.js message!",
        textColor    : "#FFFFFF",
        yesMessage   : "Yes",
        noMessage    : "No",
        yesColor     : "#2ECC71",
        noColor      : "#E74C3C",
        duration     : 1.5,
        speed        : 500,
        closeConfirm : false,
        upper        : false,
        easing       : "easeOutBounce",
        html         : false,
        callback     : function () {}
      };
    
      var attributes = $.extend(defaults, options);
    
      // Raise the overhang alert
      function raise(runCallback, identifier) {
        $overhang.slideUp(attributes.speed, function () {
          if (runCallback) {
            attributes.callback(identifier !== null ? $element.data(identifier) : "");
          }
        });
      }
    
      // Handle invalid type name
      var validTypes = ["success", "error", "warn", "info", "prompt", "confirm"];
      if ($.inArray(attributes.type, validTypes) === -1) {
        attributes.type = "blank";
    
        // Notify the user
        console.log("You have entered invalid type name for an overhang message.");
      }
    
      // Set attribut primary and accent colors
      if (options.custom) {
        attributes.primary = options.primary;
        attributes.accent  = options.accent;
      } else {
        attributes.primary = themes[attributes.type][0] || "#ECF0F1";
        attributes.accent  = themes[attributes.type][1] || "#BDC3C7";
      }
    
      if (attributes.type === "prompt" || attributes.type === "confirm") {
        attributes.primary      = options.primary || themes[attributes.type][0];
        attributes.accent       = options.accent  || themes[attributes.type][1];
        attributes.closeConfirm = true;
      }
    
      // Style colors
      $overhang.css("background-color", attributes.primary);
      $overhang.css("border-bottom", "6px solid " + attributes.accent);
    
      // Message
      var $message = $("<span class='overhang-message'></span>");
      $message.css("color", attributes.textColor);
    
      // Assign html or text
      if (attributes.html) {
        $message.html(attributes.message);
      } else {
        $message.text(attributes.upper ? attributes.message.toUpperCase() : attributes.message);
      }
    
      $overhang.append($message);
    
      // Additional overhang elements
      var $inputField = $("<input class='overhang-prompt-field' />");
      var $yesButton = $("<button class='overhang-yes-option'>" + attributes.yesMessage + "</button>");
      var $noButton = $("<button class='overhang-no-option'>" + attributes.noMessage + "</button>");
    
      $yesButton.css("background-color", attributes.yesColor);
      $noButton.css("background-color", attributes.noColor);
    
      // Close button
      if (attributes.closeConfirm) {
        var $close = $("<span class='overhang-close'></span>");
        $close.css("color", attributes.accent);
    
        if (attributes.type !== "confirm") {
          $overhang.append($close);
        }
      }
    
      if (attributes.type === "prompt") {
        $overhang.append($inputField);
        $element.data("overhangPrompt", null);
    
        // Submit action
        $inputField.keydown(function (e) {
          if (e.keyCode == 13) {
    
            // Append the data to the DOM element
            $element.data("overhangPrompt", $inputField.val());
            raise(true, "overhangPrompt");
          }
        });
    
      } else if (attributes.type === "confirm") {
    
        $overhang.append($yesButton);
        $overhang.append($noButton);
    
        $overhang.append($close);
    
        $element.data("overhangConfirm", null);
    
        // Append selection to DOM element
        $yesButton.click(function () {
          $element.data("overhangConfirm", true);
          raise(true, "overhangConfirm");
        });
    
        $noButton.click(function () {
          $element.data("overhangConfirm", false);
          raise(true, "overhangConfirm");
        });
    
      }
    
      // Attack overhang to element
      $element.append($overhang);
    
      // Animate drop down and up
      if (attributes.closeConfirm) {
        $overhang.slideDown(attributes.speed, attributes.easing);
    
        $close.click(function () {
          if (attributes.type !== "prompt" && attributes.type !== "confirm") {
            raise(true, null);
          } else {
            raise(false, null);
          }
        });
      } else {
        $overhang
          .slideDown(attributes.speed, attributes.easing)
          .delay(attributes.duration * 1000)
          .slideUp(attributes.speed, function () {
            raise(true, null);
          });
      }
    
      // Return `this` for further chaining.
      return this;
    };
    
    /* end overhang.js */
    })(jQuery);
    
Sign In or Register to comment.