Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,16 @@ To add dynamic web content, insert this shortcode:
`[mautic type="content" slot="slot_name"] <your default content> [/mautic]`

where `slot_name` is the dynamic content slot token name you gave in the campaign.

To add Focus Item, insert this shortcode

`[mauticfocusitem id=ID]`

ID is the identifier of the Focus item you want to embed.

To control Focus Item visibility, use Blocks to render your Focus item on specific paths.

### Prefill Mautic forms

You can prefill an embedded Mautic form in Drupal page by passing form keys as Hash params in the URL.
e.g. /your-form-url#p:email=email@somedomain.com&firstname=John&lastname=Doe
263 changes: 263 additions & 0 deletions js/mauticform-prefill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
/*
* Credit to
* Original JS work forked from drupal.org/webform_prefill module to mautic use case
*/

(function ($) {

var SessionStorage = function (pfx) {
this.pfx = pfx;
};

SessionStorage.prototype.browserSupport = function () {
// this is taken from modernizr.
var mod = 'modernizr';
try {
localStorage.setItem(mod, mod);
localStorage.removeItem(mod);
return true;
} catch (e) {
return false;
}
};

SessionStorage.prototype.setItem = function (key, value) {
return sessionStorage.setItem(this.pfx + ':' + key, JSON.stringify(value));
};

SessionStorage.prototype.getItem = function (key) {
try {
var v = sessionStorage.getItem(this.pfx + ':' + key);
if (v !== null) {
v = JSON.parse(v);
}
return v;
}
catch (e) {
return null;
}
};

SessionStorage.prototype.getFirst = function (keys) {
// Get value from all possible keys.
var value = null;
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
value = prefillStore.getItem(key);
if (value) {
return value;
}
}
return null;
};

var prefillStore = new SessionStorage('mauticform_prefill')


var FormValList = function ($e, name_attr) {
this.$e = $e;
this.name_attr = name_attr || 'name';
this.name = $e.attr(this.name_attr);
this.cache_key = this.pfxMap(this.name);
};

FormValList.prototype.getVal = function () {
var $e = this.$e;
var type = $e.attr('type');
if (type == 'checkbox' || type == 'radio') {
$e = $e.closest('form').find('input:' + type + '[' + this.name_attr + '="' + this.name + '"]:checked');
}
var val = $e.val() || [];
return (val.constructor === Array) ? val : [val];
};

FormValList.prototype.getAllByName = function () {
return this.$e.closest('form')
.find('[' + this.name_attr + '="' + this.name + '"]')
.filter('input:checkbox, input:radio, select[multiple]');
};

FormValList.prototype.pfxMap = function (x) {
return 'l:' + x;
}

var FormValSingle = function ($e, name_attr) {
this.$e = $e;
this.name_attr = name_attr || 'name';
this.name = $e.attr(this.name_attr);
this.cache_key = this.pfxMap(this.name);
};

FormValSingle.prototype.getVal = function () {
return this.$e.val();
};

FormValSingle.prototype.getAllByName = function () {
return this.$e.closest('form')
.find('[' + this.name_attr + '="' + this.name + '"]')
.not('input:checkbox, input:radio, select[multiple]');
};

FormValSingle.prototype.pfxMap = function (x) {
return 's:' + x;
}

Drupal.behaviors.mautic = {};

Drupal.behaviors.mautic.elementFactory = function ($e, name_attr) {
name_attr = name_attr || 'data-form-key';
var type = $e.attr('type');
if (type === 'checkbox' || type === 'radio' || $e.is('select[multiple]')) {
return new FormValList($e, name_attr);
}
return new FormValSingle($e, name_attr);
};

Drupal.behaviors.mautic.formKey = function ($e) {
var name = $e.attr('name');
if (!name) {
return;
}
if ($e.attr('type') === 'checkbox') {
name = name.slice(0, -(2 + $e.attr('value').length));
}
return name.slice(name.lastIndexOf('[') + 1, -1);
};

Drupal.behaviors.mautic._keys = function (name) {
if (name in this.settings.map) {
return this.settings.map[name];
}
return [name];
};

Drupal.behaviors.mautic.keys = function (val) {
return $.map(this._keys(val.name), val.pfxMap);
};

Drupal.behaviors.mautic.attachToInputs = function ($wrapper) {
var self = this;
var $inputs = $wrapper.find('input, select, textarea').not(function (i, element) {
// Exclude file elements. We can't prefill those.
if ($(element).attr('type') === 'file') {
return true;
}
// Check nearest include and exclude-wrapper.
var $exclude = $(element).closest('.mauticform-prefill-exclude');
var $include = $(element).closest('.mauticform-prefill-include');
if ($exclude.length > 0) {
// Exclude unless there is an include-wrapper inside the exclude wrapper.
return $include.length <= 0 || $.contains($include.get(), $exclude.get());
}
return false;
});

$inputs.not('[data-form-key]').each(function () {
var $e = $(this);
var fk = self.formKey($e);
if (fk) {
$e.attr('data-form-key', fk);
}
});

var done = {};
$inputs.each(function () {
var e = self.elementFactory($(this));
if (!(e.cache_key in done)) {
done[e.cache_key] = true;

// Get value from all possible keys.
var value = prefillStore.getFirst(self.keys(e));
if (value !== null) {
e.getAllByName().val(value);
}
}
});

$inputs.on('change', function () {
var e = self.elementFactory($(this));
if (!e.name) {
return;
}
prefillStore.setItem(e.cache_key, e.getVal());
});
};

Drupal.behaviors.mautic.attach = function (context, settings) {
if (!prefillStore.browserSupport()) {
return;
}

if (typeof this.settings === 'undefined') {
var hash = window.location.hash.substr(1);
if (hash) {
var new_hash = this.readUrlVars(hash);
if (new_hash !== hash) {
window.location.hash = '#' + new_hash;
}
}
if ('mauticform_prefill' in Drupal.settings) {
this.settings = Drupal.settings.mautic;
}
else {
this.settings = {map: {}};
}
}

this.attachToInputs($('.mauticform_wrapper', context));
};

/**
* Parse the hash from the hash string and clean them from the string.
*
* The hash string is first split into parts using a semi-colon";" as a
* separator. Each part that contains prefill variables (with the "p:"-prefix)
* is then removed.
*
* All prefill-values are stored into the session store.
*/
Drupal.behaviors.mautic.readUrlVars = function (hash, store) {
hash = hash || window.location.hash.substr(1);
if (!hash) {
return '';
}
store = store || prefillStore;
var vars = {}, key, value, p, parts, new_parts = [];
parts = hash.split(';');
for (var j = 0; j < parts.length; j++) {
var part_has_prefill_vars = false;
var part = parts[j];
// Parts starting with p: are used for pre-filling.
if (part.substr(0, 2) === 'p:') {
var hashes = part.substr(2).split('&');
for (var i = 0; i < hashes.length; i++) {
p = hashes[i].indexOf('=');
key = hashes[i].substring(0, p);
// Backwards compatibility strip p: prefixes from keys.
if (key.substr(0, 2) === 'p:') {
key = key.substr(2);
}
value = hashes[i].substring(p + 1);
// Prepare values to be set as list values.
if (!(key in vars)) {
vars[key] = [];
}
vars[key].push(value);
// Set string values directly.
store.setItem('s:' + key, value);
}
}
else {
new_parts.push(part);
}
}

// Finally set all list values.
$.each(vars, function (key, value) {
store.setItem('l:' + key, value);
});

return new_parts.join(';');
};

}(jQuery));
3 changes: 2 additions & 1 deletion mautic.info
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ package = Mautic
version = 7.x-1.0
core = 7.x
files[] = mautic.module
configure = admin/config/mautic
dependencies[] = jquery_update
configure = admin/config/system/mautic
32 changes: 23 additions & 9 deletions mautic.module
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ function mautic_help($path, $arg) {
$output .= '<h3>' . t('Features') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Mautic Tracking') . '</dt>';
$output .= '<dd>' . t('Tracking image works right after you enable the module, insert Base URL and save the plugin. That means it will insert 1 px gif image loaded from your Mautic instance. You can check HTML source code (CTRL + U) of your Drupal website to make sure the plugin works. You should be able to find something like this:<br><code>&lt;img src="http://yourmautic.com/mtracking.gif" /&gt;</code><br>There will be probably longer URL query string at the end of the tracking image URL. It is encoded additional data about the page (title, url, referrer, language).') . '</dd>';
$output .= '<dd>' . t('Tracking script works right after you enable the module, insert Base URL and save the plugin. That means it will insert a Javascript tracking script from your Mautic instance. You can check HTML source code (CTRL + U) of your Drupal website to make sure the plugin works. You should be able to find the script by searching for:<br><code>"http://yourmautic.com/mtc.js"</code><br>There will be probably longer URL query string at the end of the tracking script URL. It is encoded additional data about the page (title, url, referrer, language).') . '</dd>';
$output .= '<dt>' . t('Form embed') . '</dt>';
$output .= '<dd>' . t("To embed a Mautic form into Drupal content, insert this code snippet:<br><code>{mauticform id=ID width=300px height=300px}</code><br>ID is the identifier of the Mautic form you want to embed. You can see the ID of the form in the URL of the form detail. For example for www.yourmautic.com/forms/view/1, ID = 1.") . '</dd>';
$output .= '<dd>' . t("To embed a Mautic form into Drupal content, insert this code snippet:<br><code>[mauticform id=ID]</code><br>ID is the identifier of the Mautic form you want to embed. You can see the ID of the form in the URL of the form detail. For example for www.yourmautic.com/forms/view/1, ID = 1.") . '</dd>';
$output .= '</dl>';
$output .= '<p>' . t('Mautic-Drupal module <a href="@doc">documentation</a>, <a href="@issues">issue reporting</a>', array('@doc' => 'https://github.com/mautic/mautic-drupal/tree/7.x#readme', '@issues' => 'https://github.com/mautic/mautic-drupal/issues')) . '</p>';

Expand All @@ -46,13 +46,16 @@ function mautic_help($path, $arg) {
*/
function mautic_page_alter(&$page) {
if( _mautic_visibility_pages()) {
$mautic_base_url = variable_get('mautic_base_url', '');
$mautic_base_url = trim(variable_get('mautic_base_url', ''), " \t\n\r\0\x0B/");
$script = '(function(w,d,t,u,n,a,m){w["MauticTrackingObject"]=n;';
$script .= 'w[n]=w[n]||function(){(w[n].q=w[n].q||[]).push(arguments)},a=d.createElement(t),';
$script .= 'm=d.getElementsByTagName(t)[0];a.async=1;a.src=u;m.parentNode.insertBefore(a,m)';
$script .= '})(window,document,"script","' . $mautic_base_url . '/mtc.js","mt");';
$script .= 'mt("send", "pageview");';
drupal_add_js($script, array('scope' => 'header', 'type' => 'inline', 'requires_jquery' => FALSE));

// Prefill Helper
drupal_add_js(drupal_get_path('module', 'mautic') . '/js/mauticform-prefill.js', array('scope' => 'footer', 'requires_jquery' => FALSE));
}
}

Expand All @@ -73,16 +76,19 @@ function mautic_filter_info() {
function mautic_filter_shortcodes_process($text, $filter, $format, $langcode, $cache, $cache_id) {
$text = preg_replace_callback('/\[mauticform id=(.*)\]/', '_mautic_form_replace', $text);
$text = preg_replace_callback('/\[mautic type="content" slot="(.*)"\](.*)\[\/mautic\]/', '_mautic_dynamic_content_replace', $text);
$text = preg_replace_callback('/\[mauticfocusitem id=(.*)\]/', '_mautic_focus_item_replace', $text);
return $text;
}

function mautic_filter_shortcodes_tips($filter, $format, $long) {
return t('[mauticform id=1] - Insert a Mautic form with given ID.\n[mautic type="content" slot="slot_name"]Default Content[/mautic] - Insert dynamic web content.');
return t("[mauticform id=1] - Insert a Mautic form with given ID.<br>
[mautic type=\"content\" slot=\"slot_name\"]Default Content[/mautic] - Insert dynamic web content.<br>
[mauticfocusitem id=1] - Insert Mautic Focus Item with given ID.");
}

function _mautic_form_replace($matches) {
$form_id = $matches[1];
$mautic_base_url = variable_get('mautic_base_url', '');
$mautic_base_url = trim(variable_get('mautic_base_url', ''), " \t\n\r\0\x0B/");
$args = array('@mautic_base_url' => $mautic_base_url, '@form_id' => $form_id);
$script = format_string('<script src="@mautic_base_url/form/generate.js?id=@form_id"></script>', $args);
return $script;
Expand All @@ -92,18 +98,26 @@ function _mautic_dynamic_content_replace($matches) {
$dc_slot_name = $matches[1];
$internal_dom = $matches[2];
$args = array('@slot_name' => $dc_slot_name, '@dom' => $internal_dom);
$dynamic_web_content = format_string(' <div data-slot-container=""><div class="mautic-slot" data-slot-name="@slot_name">@dom</div></div>', $args);
$dynamic_web_content = format_string('<div data-slot-container=""><div class="mautic-slot" data-slot-name="@slot_name">@dom</div></div>', $args);
return $dynamic_web_content;
}

function _mautic_focus_item_replace($matches) {
$focus_id = $matches[1];
$mautic_base_url = variable_get('mautic_base_url', '');
$args = array('@mautic_base_url' => $mautic_base_url, '@focus_id' => $focus_id);
$script = format_string('<script src="@mautic_base_url/focus/@focus_id.js" charset="utf8" async="async"></script>', $args);
return $script;
}

/**
* Implements hook_menu().
*/
function mautic_menu() {
$items = array();

$items['admin/config/mautic'] = array(
'title' => 'Mautic URL',
$items['admin/config/system/mautic'] = array(
'title' => 'Mautic',
'description' => 'Configuration for Current posts module',
'page callback' => 'drupal_get_form',
'page arguments' => array('mautic_form'),
Expand All @@ -122,7 +136,7 @@ function mautic_form() {
'#title' => t('Mautic URL'),
'#default_value' => variable_get('mautic_base_url', ''),
'#size' => 60,
'#description' => t("Your mautic base url."),
'#description' => t("Your mautic base url, e.g. https://mydomain.com. No trailing slash required."),
'#required' => TRUE,
);

Expand Down