Plugins 2.0.0 - Documentation

Beta

Plugins are currently in beta. We don't anticipate any major changes as we have been working on this for more than half a year but we don't guarantee it won't change. Use this at your own risk.

In SnapEditor, plugins are just a concept. There is no plugin object. Plugins are just a group of features packaged together. Each feature can stand on its own.

If you are looking to just create a custom button, skip down to the Buttons feature.

Actions

Use actions to share functions in SnapEditor.

Add actions to the SnapEditor.actions object.

SnapEditor.actions.say = function(e, text) {
  e.api.insert("<p>" + text + "</p>");
};

Execute actions at any time from the API object. To execute an action, call the api.execAction() function.

function (e) {
  e.api.execAction("say", e, text);
}

The first argument to api.execAction() is the name of the action you want to execute.

The extra arguments are passed through to the action.

To keep things consistent, the first extra argument should always be a SnapEditor event object. This way, the action always has access to the API.

Buttons

Buttons are declared first, then added. Buttons may be added to other buttons. In this case, the button will trigger a menu with the other buttons in it.

Button objects may contain the following keys.

text, html, action, items

text (mandatory)

text is used for the title when hovering over a button. It is also used for the label if the button is included in a menu and does not have an html key.

html (optional)

html is only used when the button is included in a menu. It is used as the label.

action (optional)

This is only optional if items is not specified.

action specifies a function to execute when the button is clicked. The function will receive a SnapEditor event object.

{
  api: <SnapEditor API Object>
}

The action may also be a String which corresponds to the name of a predefined action.

items (optional)

items tells SnapEditor that this button will trigger a menu.

items is an array of Strings that correspond to the names of each button to include in the menu.

When items is specified, action is ignored since the behaviour of the button is to show a menu.

Declaration

Declare buttons by adding the button to the SnapEditor.buttons object.

// Add an action to be used.
SnapEditor.actions.sayBye =  function (e) {
  e.api.insert("<p>Bye</p>");
};

// Declaring a button.
SnapEditor.buttons.sayHi = {
  text: "Say Hi",
  action: function (e) {
    e.api.insert("<p>Hi</p>");
  }
}
// Declaring a button with a predefined action.
SnapEditor.buttons.sayBye = {
  text: "Say Bye",
  action: "sayBye"
}
// Declaring a button with custom HTML for menus.
SnapEditor.buttons.sayWorld = {
  text: "Say World",
  html: '<span class="shout">Say World</span>',
  action: function (e) {
    e.api.insert("<p>World</p>");
  },
}
// Declaring a button that triggers a menu with other buttons.
SnapEditor.buttons.say = {
  text: "Say",
  items: ["sayHi", "sayBye", "sayWorld"]
}

Adding a Button

After declaring a button, you can add the button to the global SnapEditor default config or a particular instance of SnapEditor.

// Add to the global SnapEditor default config.
SnapEditor.config.buttons.push("say");
// Add to a particular instance of SnapEditor by overriding the default.
var editor = new SnapEditor.InPlace("editor", {
  buttons: ["bold", "italic", "say"]
});
// Add to a particular instance of SnapEditor by appending to the default.
var editor = new SnapEditor.InPlace("editor", {
  buttons: SnapEditor.config.buttons.concat(["say"])
});

Styling

The button will have a classname of the following form.

snapeditor_toolbar_icon_<snake case of button name>

Due to CSS selector strength, to override the default icon, an extra classname needs to be used.

.snapeditor_toolbar .snapeditor_toolbar_icon_<snake case of button name>

Icons should be 26px by 26px.

Example.

// JavaScript
SnapEditor.buttons.sayHi = {
  text: "Say Hi",
  action: function (e) {
    e.api.insert("<p>Hi</p>");
  }
}

// CSS
.snapeditor_toolbar .snapeditor_toolbar_icon_say_hi {
  background-image: url("say_hi.png");
}

For a full example that includes shortcuts, go the Custom Buttons example.

Shortcuts

Shortcuts are declared first, then added. Shortcuts are used to execute an action.

Shortcut objects must contain the following keys.

key, action

key

key specifies the keyboard shortcut to be used. When specifying a combination of keys, separate the keys by a '+'.

The following are the available keys for use.

alt, ctrl, shift,
0-9, a-z,
backspace, delete, esc, enter, space, tab,
up, down, left, right,
home, end, pageup, pagedown

action

action refers to the name of the predefined action to execute.

Declaration

Declare shortcuts by adding the shortcut to the SnapEditor.shortcuts object.

// Add an action to be used.
SnapEditor.actions.sayHi =  function (e) {
  e.api.insert("<p>Hi</p>");
};

// Declare the shortcut for the action.
SnapEditor.shortcuts.sayHi = {
  key: "ctrl+h",
  action: "sayHi"
}

Adding a Shortcut

After declaring a shortcut, you can add the shortcut to the global SnapEditor default config or a particular instance of SnapEditor.

// Add to the global SnapEditor default config.
SnapEditor.config.shortcuts.push("sayHi");
// Add to a particular instance of SnapEditor by overriding the default.
// Do this with care as you will lose other shortcuts.
var editor = new SnapEditor.InPlace("editor", {
  shortcut: ["sayHi"]
});
// Add to a particular instance of SnapEditor by appending to the default.
// This is preferred.
var editor = new SnapEditor.InPlace("editor", {
  shortcut: SnapEditor.config.shortcuts.concat(["sayHi"])
});

If there is a button that references the same action as the shortcut, SnapEditor will automatically include the shortcut in the button's title.

Dialogs

SnapEditor provides a way to easily create dialogs that can be used for various purposes, such as being triggered by an action.

Add dialogs to the SnapEditor.dialogs object.

SnapEditor.dialogs.sayHi = {
  html: "Hi"
}

Dialog objects may contain the following keys.

title, html, css, width, height, onSetup, onOpen, onClose

title (optional)

title is used for the title of the dialog box. If title is set to an empty string "", the title bar shows but with no title. If title is not specified or set to null, the title bar is not rendered.

html (mandatory)

html is used for the content of the dialog. It can either be a string or a function that returns a string.

css (optional)

css is used to style the dialog. It can either be a string or a function that returns a string.

width (optional)

width is used to set the width of the content.

height (optional)

height is used to set the height of the content.

onSetup (optional)

onSetup is a function that gets called the first time the dialog is set up. The function gets a Dialog event object that contains a reference to the dialog. Note that there is no reference to the SnapEditor API at this point as the setup is called in a general manner.

{
  onSetup: function (e) {
    e.dialog.setTitle("All set up");
  }
}

onOpen (optional)

onOpen is a function that gets called whenever the dialog is opened. The function gets a Dialog event object that contains a reference to the dialog and the SnapEditor API. It also gets any other arguments that are passed through when opening a dialog.

{
  onOpen: function (e, arg1, arg2) {
    e.dialog.setTitle("Opening");
    e.api.getContents();
  }
}

onClose (optional)

onClose is a function that gets called whenever the dialog is closed. The function gets a Dialog event object that contains a reference to the dialog and the SnapEditor API.

{
  onClose function (e) {
    e.dialog.setTitle("Closing");
    e.api.getContents();
  }
}

Dialog Object

The Dialog object has the following functions.

setTitle(), setHTML(), on(), find(), close()

setTitle()

setTitle([title])

setTitle() sets the title of the dialog. If an empty string "" is given, the title bar shows but with no title. If no title is given or is null, the title bar is not rendered.

setHTML()

setHTML(html)

setHTML() sets the content of the dialog.

on()

on(selector, event, handler)

on() attaches the given handler to the given event on the elements inside the dialog content that match the given selector.

The handler is given a Dialog event object that contains a reference to the dialog, the SnapEditor API, and the original DOM event.

dialog.on("a.cancel", "click", function (e) {
  e.domEvent.preventDefault();
  e.api.getContents();
  e.dialog.close();
});

find()

find(selector)

find() returns an array of all elements inside the dialog content that matches the given selector.

find() returns an array even if there is a single match or no matches.

var inputs = dialog.find("input[type=text]");

close()

close()

close() closes the dialog.

Opening a Dialog

api.openDialog("sayHi", e, arg1, arg2);

The first argument to api.openDialog() is the name of the dialog you want to open.

The extra arguments are passed through to the action.

To keep things consistent, the first extra argument should always be a SnapEditor event object. This way, the dialog always has access to the API.

Closing a Dialog

dialog.close();
api.closeDialog("sayHi");

The first way to close a dialog is to call the close() function of the Dialog object if you have one.

The other way to close a dialog is to call api.closeDialog(). The only argument to api.closeDialog() is the name of the dialog you want to close.

Behaviours

Behaviours affect the way SnapEditor works. They are triggered by attaching themselves to SnapEditor events.

Behaviours are declared first, then added.

Behaviour objects are made up of SnapEditor event names without the snapeditor namespace. "on" is appended to the name to make it clear we're dealing with events. This makes up the key. The values are functions that will receive a SnapEditor event object which will contain a SnapEditor API object as an argument.

// We'll use the "snapeditor.activate" event as an example.
{
  onActivate: function (e) {
    console.log(e.api.getContents());
  }
}

Declaration

Declare behaviours by adding the behaviour to the SnapEditor.behaviours object.

SnapEditor.behaviours.say = {
  onActivate: function (e) {
    console.log("Activated with content: " + e.api.getContents());
  },
  onUpdate: function (e) {
    // Reposition a custom dialog.
  }
}

Adding Behaviour

After declaring a behaviour, you can add the behaviour to the global SnapEditor default config or a particular instance of SnapEditor.

// Add to the global SnapEditor default config.
SnapEditor.config.behaviours.push("say");
// Add to a particular instance of SnapEditor by overriding the default.
// This is never recommended as the default behaviours of SnapEditor will be removed.
var editor = new SnapEditor.InPlace("editor", {
  behaviour: ["say"]
});
// Add to a particular instance of SnapEditor by appending to the default.
// This is the proper way of adding behaviours.
var editor = new SnapEditor.InPlace("editor", {
  behaviour: SnapEditor.config.behaviours.concat(["say"])
});

Custom Buttons

Here is an example of a custom button.

<!DOCTYPE html>
<html>
  <head>
    <style>
      /* Set the icon for the custom button. */
      .snapeditor_toolbar .snapeditor_toolbar_icon_say_hi {
        background-image: url("say_hi.png");
      }
    </style>
  </head>
  <body>
    <div id="editor">
      <p>This is an in-place editor!</p>
    </div>
    <script type="text/javascript" src="/snapeditor/snapeditor.js"></script>
    <script type="text/javascript">
      // Declare all the needed features.
      SnapEditor.actions.sayHi = function (e) { e.api.insert("<p>Hi</p>"); };
      SnapEditor.buttons.sayHi = {
        text: "Say Hi",
        action: "sayHi"
      };
      SnapEditor.shortcuts.sayHi = {
        key: "ctrl+alt+h",
        action: "sayHi"
      };

      var inPlaceEditor = new SnapEditor.InPlace("editor", {
        // Add the button and shortcut.
        buttons: SnapEditor.config.buttons.concat(["sayHi"]),
        shortcuts: SnapEditor.config.shortcuts.concat(["sayHi"])
      });
    </script>
  </body>
</html>

Plugins

As mentioned at the beginning of this doc, plugins are just a concept. There is no plugin object. Plugins are conceptual groupings of the above features.

One way to group the features together for a plugin is to put them into a single JavaScript file.

Because the features are all attached to global objects, we suggest namespacing all features with the name of your plugin as to not collide with other features.

Here is an example of a "Say" plugin in a file called say.js. We will be using "say" as the namespace. Note that this plugin uses all the features. However, you don't have to.

// Declare the actions.
SnapEditor.actions.sayHi = function (e) { e.api.insert("<p>Hi</p>"); };
SnapEditor.actions.sayBye = function (e) { e.api.insert("<p>Bye</p>"); };
SnapEditor.actions.sayWorld = function (e) { e.api.insert("<p>World</p>"); };

// Declare the buttons.
SnapEditor.buttons.sayHi = {
  text: "Say Hi",
  html: '<span class="hi">Say Hi</span>',
  action: "sayHi"
};
SnapEditor.buttons.sayBye = {
  text: "Say Bye",
  html: '<span class="bye">Say Bye</span>',
  action: "sayBye"
};
SnapEditor.buttons.sayWorld = {
  text: "Say World",
  html: '<span class="world">Say World</span>',
  action: "sayWorld"
};
SnapEditor.buttons.say = {
  text: "Say",
  items: ["sayHi", "sayBye", "sayWorld"] // menu of buttons
};

// Declare behaviours.
SnapEditor.behaviours.say {
  onActivate: function (e) {
    console.log("From the Say plugin: Hi!");
  },
  onClean: function (e) {
    console.log("From the Say plugin: I see you're cleaning the content!");
  }
}

Note that shortcuts are not specified. This is recommended as you're not sure what other plugins the developer may decide to add. If you specify shortcuts in your plugin, it may collide with other ones that the developer is already using. We recommend that shortcuts be left to the developer to determine.

Now the developer can include it on the page.

<!DOCTYPE html>
<html>
  <body>
    <div id="editor">
      <p>This is an in-place editor!</p>
    </div>
    <script type="text/javascript" src="/snapeditor/snapeditor.js"></script>
    <script type="text/javascript" src="/snapeditor/plugins/say.js"></script>
    <script type="text/javascript">
      // Declare the shortcuts.
      SnapEditor.shortcuts.sayHi = {
        key: "ctrl+alt+h",
        action: "sayHi"
      };
      SnapEditor.shortcuts.sayBye = {
        key: "ctrl+alt+b",
        action: "sayBye"
      };
      SnapEditor.shortcuts.sayWorld = {
        key: "ctrl+alt+w",
        action: "sayWorld"
      };

      // In this example, we've decided to add the features directly to the global SnapEditor default config.
      SnapEditor.config.buttons.push("say");
      SnapEditor.config.behaviours.push("say");
      SnapEditor.config.shortcuts.push("sayHi");
      SnapEditor.config.shortcuts.push("sayBye");
      SnapEditor.config.shortcuts.push("sayWorld");

      var inPlaceEditor = new SnapEditor.InPlace("editor");
    </script>
  </body>
</html>